[automerger] Move R reference to own package am: 7d6b8bfbb4

Change-Id: Ia6ce1da5fa8571b429e51ea4425e0064b2c52f64
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 7b2174e..7dc4050 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -46,6 +46,8 @@
 
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android-support-v*)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/support.aidl)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android-support-customtabs_intermediates/src/)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android-support-annotations_intermediates)
 
 # ************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/OWNERS b/OWNERS
index 0de3634..3126105 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,6 +1,7 @@
 adamp@google.com
 alanv@google.com
 aurimas@google.com
+chet@google.com
 ccraik@google.com
 clarabayarri@google.com
 ilake@google.com
diff --git a/README.md b/README.md
index d34ea7e..f6cdb65 100644
--- a/README.md
+++ b/README.md
@@ -29,12 +29,19 @@
 
 If you see any warnings (red underlines) run `Build > Clean Project`.
 
-## Optional - Full Build
+## Builds
+### Full Build (Optional)
 You can do most of your work from Android Studio, however you can also build the full support library from command line:
 
     cd path/to/checkout/frameworks/support/
     ./gradlew createArchive
 
+### Building Support Library as part of your App build
+If you intend to repeatedly make changes to Support Library and to wish to see
+the results in your app, and you don't want to have to repeatedly build them as
+separate Gradle projects, you can
+[configure your app build to build Support Library too](adding-support-library-as-included-build.md)
+
 ## Running Tests
 
 ### Single Test Class or Method
diff --git a/adding-support-library-as-included-build.md b/adding-support-library-as-included-build.md
new file mode 100644
index 0000000..136929f
--- /dev/null
+++ b/adding-support-library-as-included-build.md
@@ -0,0 +1,32 @@
+# Adding the Support Library Build Within Another Build
+
+Would you like to make a change in Support Library and have it be propagated to
+your downstream Gradle build (generally an app) without having to separately
+build Support Library and then build your application?
+
+## To build Support Library as part of your existing Gradle build
+*   To add the Support Library build
+    *   Add `apply(from: '<support-lib-repo-root>/frameworks/support/include-support-library.gradle')`
+        to your settings.gradle
+        *   See [include-support-library.gradle](include-support-library.gradle)
+            for more information
+*   If your project is an Android app, also update some dependencies:
+    *   Open your local.properties file and update the value of `sdk.dir` .
+        *   It should point to `<support-lib-repo-root>/prebuilts/fullsdk-<platform>` .
+        *   For example, `~/support-library/prebuilts/fullsdk-linux` .
+    *   In your build.gradle, update any versions that refer to previous versions of
+        Support Library.
+        *   To determine the correct version, find the SDK with the highest
+            number among SDKs in the Support Library repo.
+
+                echo <support-lib-repo-root>/prebuilts/fullsdk-linux/platforms/android* | xargs -n 1 echo | sed 's/.*android-//' | tail -n 1
+
+            This should output, for example, "28"
+
+        *   Update dependency versions
+            *   For example, you may want to replace
+                `com.android.support:app-compat-v7:26.0.2` with
+                `com.android.support:app-compat-v7:28.0.2`
+        *   Update configuration given to the Android Gradle plugin
+            *   Check `compileSdkVersion` and make sure its version is correct
+
diff --git a/annotations/Android.mk b/annotations/Android.mk
deleted file mode 100644
index 684a77a..0000000
--- a/annotations/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := android-support-annotations
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/app-toolkit/settings.gradle b/app-toolkit/settings.gradle
index a9aa472..26bf742 100644
--- a/app-toolkit/settings.gradle
+++ b/app-toolkit/settings.gradle
@@ -116,10 +116,5 @@
 // External
 //
 /////////////////////////////
-if (inAppToolkitProject) {
-    File externalRoot = new File(supportRoot, '../../external')
 
-    includeBuild new File(externalRoot, 'doclava')
-
-    includeBuild new File(externalRoot, 'jdiff')
-}
+apply(from: new File(supportRoot, 'include-composite-deps.gradle'))
diff --git a/asynclayoutinflater/api/current.txt b/asynclayoutinflater/api/current.txt
new file mode 100644
index 0000000..83a85be
--- /dev/null
+++ b/asynclayoutinflater/api/current.txt
@@ -0,0 +1,13 @@
+package android.support.v4.view {
+
+  public final class AsyncLayoutInflater {
+    ctor public AsyncLayoutInflater(android.content.Context);
+    method public void inflate(int, android.view.ViewGroup, android.support.v4.view.AsyncLayoutInflater.OnInflateFinishedListener);
+  }
+
+  public static abstract interface AsyncLayoutInflater.OnInflateFinishedListener {
+    method public abstract void onInflateFinished(android.view.View, int, android.view.ViewGroup);
+  }
+
+}
+
diff --git a/asynclayoutinflater/build.gradle b/asynclayoutinflater/build.gradle
new file mode 100644
index 0000000..597b01d
--- /dev/null
+++ b/asynclayoutinflater/build.gradle
@@ -0,0 +1,20 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+}
+
+supportLibrary {
+    name = "Android Support Library Async Layout Inflater"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/asynclayoutinflater/src/main/AndroidManifest.xml b/asynclayoutinflater/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a98f288
--- /dev/null
+++ b/asynclayoutinflater/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.asynclayoutinflater"/>
diff --git a/core-ui/src/main/java/android/support/v4/view/AsyncLayoutInflater.java b/asynclayoutinflater/src/main/java/android/support/v4/view/AsyncLayoutInflater.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/AsyncLayoutInflater.java
rename to asynclayoutinflater/src/main/java/android/support/v4/view/AsyncLayoutInflater.java
diff --git a/build.gradle b/build.gradle
index 84753dd..0307507 100644
--- a/build.gradle
+++ b/build.gradle
@@ -49,6 +49,8 @@
 
 init.setupRelease()
 
+apply from: 'buildSrc/jetify.gradle'
+
 init.enableDoclavaAndJDiff(this, new DacOptions("android/support", "SUPPORT_DATA"))
 
 ///// FLATFOOT START
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index b89ffba..f028c0d 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -40,7 +40,7 @@
 dependencies {
     compile build_libs.gradle
     compile build_libs.jacoco
-    compile build_libs.error_prone
+    compile build_libs.error_prone_gradle
     compile build_libs.jarjar_gradle
     compile gradleApi()
     testCompile "junit:junit:4.12"
diff --git a/buildSrc/build_dependencies.gradle b/buildSrc/build_dependencies.gradle
index 73cdf37..eb414dd 100644
--- a/buildSrc/build_dependencies.gradle
+++ b/buildSrc/build_dependencies.gradle
@@ -34,7 +34,7 @@
 
 // jarjar plugin
 build_libs.jarjar_gradle = 'org.anarres.jarjar:jarjar-gradle:1.0.0'
-build_libs.error_prone = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.13'
+build_libs.error_prone_gradle = 'net.ltgt.gradle:gradle-errorprone-plugin:0.0.13'
 build_libs.jacoco = 'org.jacoco:org.jacoco.core:0.7.8'
 build_libs.jacoco_ant = 'org.jacoco:org.jacoco.ant:0.7.8'
 build_libs.jetifier = 'androidx.tools.jetifier:gradle-plugin:0.1'
diff --git a/buildSrc/dependencies.gradle b/buildSrc/dependencies.gradle
index fe664e0..baf1ba0 100644
--- a/buildSrc/dependencies.gradle
+++ b/buildSrc/dependencies.gradle
@@ -17,12 +17,7 @@
 def libs = [:]
 
 libs.exclude_annotations_transitive = {
-    exclude module: 'support-annotations'
-    transitive = true
-}
-
-libs.exclude_annotations_transitive = {
-    exclude module: 'support-annotations'
+    exclude group: 'com.android.support'
     transitive = true
 }
 
diff --git a/buildSrc/jetify.gradle b/buildSrc/jetify.gradle
new file mode 100644
index 0000000..6fdc5eb
--- /dev/null
+++ b/buildSrc/jetify.gradle
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+def standaloneProject = project(":jetifier-standalone")
+def jetifierBin = file("${standaloneProject.buildDir}/install/jetifier-standalone/bin/jetifier-standalone")
+
+task jetifyArchive(type: Exec) {
+    description "Produces a zip of jetified artifacts by running Jetifier against top-of-tree*.zip" +
+            " This task only exists to enable dejetifyArchive to have a realistic archive to test " +
+            " with. This task should be deleted once Jetpack exists."
+
+    dependsOn tasks['createArchive']
+    dependsOn ':jetifier-standalone:installDist'
+    inputs.file project.tasks['createArchive'].archivePath
+
+    outputs.file "${buildDir}/top-of-tree-m2-repository-jetified-${project.ext.buildNumber}.zip"
+
+    commandLine ("bash", "-c",
+        "if ${jetifierBin} -s -outputfile ${outputs.files.singleFile} -i ${inputs.files.singleFile}; then\n" +
+        "  echo success;\n" +
+        "else\n" +
+        "  echo jetifyArchive was not expected to work anyway. Ask jeffrygaston@ or pavlis@ to make it work.\n" +
+        "  exit 1\n" +
+        "fi")
+}
+
+task dejetifyArchive(type: Exec) {
+    description "Produces a zip of dejetified artifacts by running Dejetifier against jetified" +
+            " artifacts, for temporary usage by external clients that haven't upgraded to Jetpack" +
+            " yet."
+
+    dependsOn tasks['jetifyArchive']
+    inputs.file project.tasks['jetifyArchive'].outputs.files.singleFile
+
+    outputs.file "${buildDir}/top-of-tree-m2-repository-dejetified-${project.ext.buildNumber}.zip"
+
+
+    commandLine ("${jetifierBin}", "-s", "-outputfile", "${outputs.files.singleFile}",  "-i", "${inputs.files.singleFile}")
+}
+
diff --git a/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt b/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
index 55f010f..74f0505 100644
--- a/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
+++ b/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
@@ -19,6 +19,8 @@
 import net.ltgt.gradle.errorprone.ErrorProneToolChain
 import org.gradle.api.tasks.compile.JavaCompile
 
+const val ERROR_PRONE_VERSION = "com.google.errorprone:error_prone_core:2.2.0"
+
 fun JavaCompile.configureWithErrorProne(toolChain: ErrorProneToolChain) {
     this.toolChain = toolChain
 
diff --git a/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt b/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
index 9c983bb..170462d 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
@@ -27,4 +27,6 @@
     const val ARCH_CORE = "android.arch.core"
     const val PAGING = "android.arch.paging"
     const val NAVIGATION = "android.arch.navigation"
+    const val SLICES = "androidx.app.slice"
+    const val JETIFIER = "com.android.support.jetifier"
 }
diff --git a/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt b/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
index 145e892..ac74c0d 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
@@ -23,7 +23,7 @@
     /**
      * Version code of the support library components.
      */
-    val SUPPORT_LIBRARY = Version("27.1.0")
+    val SUPPORT_LIBRARY = Version("28.0.0-SNAPSHOT")
 
     /**
      * Version code for Room
@@ -76,4 +76,9 @@
      * Version code for shared testing code of flatfoot
      */
     val ARCH_CORE_TESTING = ARCH_CORE
+
+    /**
+     * Version code for Jetifier
+     */
+    val JETIFIER = Version("0.2.0")
 }
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
index 68d2e61..69419d4 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
@@ -47,18 +47,6 @@
 
             library.defaultConfig.minSdkVersion(supportLibraryExtension.minSdkVersion)
 
-            if (supportLibraryExtension.legacySourceLocation) {
-                // We use a non-standard manifest path.
-                library.sourceSets.getByName("main").manifest.srcFile("AndroidManifest.xml")
-
-                // We use a non-standard test directory structure.
-                val androidTest = library.sourceSets.getByName("androidTest")
-                androidTest.setRoot("tests")
-                androidTest.java.srcDir("tests/src")
-                androidTest.res.srcDir("tests/res")
-                androidTest.manifest.srcFile("tests/AndroidManifest.xml")
-            }
-
             // Java 8 is only fully supported on API 24+ and not all Java 8 features are binary
             // compatible with API < 24, so use Java 7 for both source AND target.
             val javaVersion: JavaVersion
@@ -140,6 +128,7 @@
         setUpSoureJarTaskForAndroidProject(project, library)
 
         val toolChain = ErrorProneToolChain.create(project)
+        project.dependencies.add("errorprone", ERROR_PRONE_VERSION)
         library.buildTypes.create("errorProne")
         library.libraryVariants.all { libraryVariant ->
             if (libraryVariant.getBuildType().getName().equals("errorProne")) {
@@ -177,10 +166,6 @@
         lintOptions.fatal("MissingTranslation")
     }
 
-    if (System.getenv("GRADLE_PLUGIN_VERSION") != null) {
-        lintOptions.check("NewApi")
-    }
-
     // Set baseline file for all legacy lint warnings.
     if (baseline.exists()) {
         lintOptions.baseline(baseline)
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
index cec3629..1604bbe 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
@@ -72,6 +72,7 @@
         }
 
         val toolChain = ErrorProneToolChain.create(project)
+        project.dependencies.add("errorprone", ERROR_PRONE_VERSION)
 
         project.afterEvaluate {
             if (testAppExtension.enableErrorProne) {
diff --git a/buildSrc/src/main/kotlin/android/support/SupportConfig.kt b/buildSrc/src/main/kotlin/android/support/SupportConfig.kt
index b3f0bb0..42b298c 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportConfig.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportConfig.kt
@@ -24,7 +24,7 @@
     const val DEFAULT_MIN_SDK_VERSION = 14
     const val INSTRUMENTATION_RUNNER = "android.support.test.runner.AndroidJUnitRunner"
     const val BUILD_TOOLS_VERSION = "27.0.3"
-    const val CURRENT_SDK_VERSION = 27
+    const val CURRENT_SDK_VERSION = 28
 
     fun getKeystore(project: Project): File {
         val supportRoot = (project.rootProject.property("ext") as ExtraPropertiesExtension)
diff --git a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt b/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
index f37bf03..f3651ab 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
@@ -50,6 +50,7 @@
 
         project.apply(mapOf("plugin" to ErrorProneBasePlugin::class.java))
         val toolChain = ErrorProneToolChain.create(project)
+        project.dependencies.add("errorprone", ERROR_PRONE_VERSION)
         val compileTasks = project.tasks.withType(JavaCompile::class.java)
         compileTasks.all { it.configureWithErrorProne(toolChain) }
 
diff --git a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt b/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
index c6b5fa5..fb2f3b5 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
+++ b/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
@@ -33,7 +33,6 @@
     var url = SUPPORT_URL
     private var licenses: MutableCollection<License> = ArrayList()
     var java8Library = false
-    var legacySourceLocation = false
     var publish = false
     /**
      * This flag works only if publish flag is "true".
diff --git a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaJavadocOptionFileOption.kt b/buildSrc/src/main/kotlin/android/support/doclava/DoclavaJavadocOptionFileOption.kt
deleted file mode 100644
index 828fb25..0000000
--- a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaJavadocOptionFileOption.kt
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.doclava
-
-import org.gradle.external.javadoc.internal.AbstractJavadocOptionFileOption
-import org.gradle.external.javadoc.internal.JavadocOptionFileWriterContext
-import java.io.IOException
-import java.util.ArrayList
-
-//TODO: remove this once https://github.com/gradle/gradle/issues/2354 is fixed
-class DoclavaJavadocOptionFileOption : AbstractJavadocOptionFileOption<Iterable<String>> {
-
-    constructor(option: String) : super(option, null)
-
-    constructor(option: String, value: Iterable<String>?) : super(option, value)
-
-    @Throws(IOException::class)
-    override fun write(writerContext: JavadocOptionFileWriterContext) {
-        writerContext.writeOptionHeader(getOption())
-        val args = getValue()
-        if (args != null) {
-            val iter = args.iterator()
-            while (true) {
-                writerContext.writeValue(iter.next())
-                if (!iter.hasNext()) {
-                    break
-                }
-                writerContext.write(" ")
-            }
-        }
-        writerContext.newLine()
-    }
-    /**
-     * @return a deep copy of the option
-     */
-    override fun duplicate(): DoclavaJavadocOptionFileOption {
-        val value = getValue()
-        val valueCopy: ArrayList<String>?
-        if (value != null) {
-            valueCopy = ArrayList()
-            valueCopy += value
-        } else {
-            valueCopy = null
-        }
-        return DoclavaJavadocOptionFileOption(getOption(), valueCopy)
-    }
-}
diff --git a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt b/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
index 48a98f9..b30611d 100644
--- a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
+++ b/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
@@ -126,7 +126,8 @@
 
     /**
      * The doclet path which has the {@code com.gogole.doclava.Doclava} class.
-     * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
+     * This option will override any doclet path set in this instance's
+     * {@link #options JavadocOptions}.
      * @see MinimalJavadocOptions#getDocletpath()
      */
     @InputFiles
@@ -136,7 +137,8 @@
 
     /**
      * Sets the doclet path which has the {@code com.gogole.doclava.Doclava} class.
-     * This option will override any doclet path set in this instance's {@link #options JavadocOptions}.
+     * This option will override any doclet path set in this instance's
+     * {@link #options JavadocOptions}.
      * @see MinimalJavadocOptions#setDocletpath(java.util.List)
      */
     fun setDocletpath(docletpath: Collection<File>) {
@@ -178,7 +180,7 @@
         }
 
         if (!generateDocs) {
-            addOption(DoclavaJavadocOptionFileOption("nodocs"))
+            addBooleanOption("nodocs", true)
         }
 
         // If requested, generate the API files.
@@ -199,7 +201,7 @@
             }
         }
         // Always treat this as an Android docs task.
-        addOption(DoclavaJavadocOptionFileOption("android"))
+        addBooleanOption("android", true)
     }
 
     fun coreJavadocOptions(configure: CoreJavadocOptions.() -> Unit) =
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
new file mode 100644
index 0000000..d93c20a
--- /dev/null
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
@@ -0,0 +1 @@
+implementation-class=android.support.SupportKotlinLibraryPlugin
diff --git a/car/Android.mk b/car/Android.mk
index 7ceb2ec..b15732f 100644
--- a/car/Android.mk
+++ b/car/Android.mk
@@ -18,12 +18,7 @@
 # Applications that use this library must specify
 #
 #   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-car\
-#       android-support-design \
-#       android-support-v4 \
-#       android-support-v7-appcompat \
-#       android-support-v7-cardview \
-#       android-support-v7-recyclerview
+#       $(ANDROID_SUPPORT_CAR_TARGETS)
 #
 # in their makefiles to include the resources and their dependencies in their package.
 
@@ -44,13 +39,11 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     prebuilt-android.car-stubs
 LOCAL_JAVA_LIBRARIES := \
-        android-support-annotations
+    android-support-annotations
 LOCAL_SHARED_ANDROID_LIBRARIES := \
-        android-support-design \
-        android-support-v4 \
-        android-support-v7-appcompat \
-        android-support-v7-cardview \
-        android-support-v7-recyclerview
+    $(ANDROID_SUPPORT_DESIGN_TARGETS) \
+    android-support-media-compat \
+    android-support-v7-cardview
 LOCAL_JAR_EXCLUDE_FILES := none
 LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
diff --git a/car/build.gradle b/car/build.gradle
index f15ff02..819f0ad 100644
--- a/car/build.gradle
+++ b/car/build.gradle
@@ -9,7 +9,7 @@
 dependencies {
     api project(':appcompat-v7')
     api project(':cardview-v7')
-    api project(':design')
+    api("com.android.support:design:28.0.0-SNAPSHOT", { transitive = false })
     api project(':support-annotations')
     api project(':support-v4')
     api project(':recyclerview-v7')
diff --git a/car/src/androidTest/NO_DOCS b/car/src/androidTest/NO_DOCS
deleted file mode 100644
index bd77b1a..0000000
--- a/car/src/androidTest/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
\ No newline at end of file
diff --git a/car/src/main/AndroidManifest.xml b/car/src/main/AndroidManifest.xml
index 854e097..97f4b50 100644
--- a/car/src/main/AndroidManifest.xml
+++ b/car/src/main/AndroidManifest.xml
@@ -13,6 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="androidx.car">
-</manifest>
+<manifest package="androidx.car"/>
diff --git a/collections/build.gradle b/collections/build.gradle
new file mode 100644
index 0000000..3145c4a
--- /dev/null
+++ b/collections/build.gradle
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportJavaLibraryPlugin")
+}
+
+dependencies {
+    compile(project(":support-annotations"))
+    testCompile(JUNIT)
+}
+
+supportLibrary {
+    name = "Android Support Library collections"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "Standalone efficient collections."
+}
diff --git a/collections/src/main/java/android/support/v4/util/ArrayMap.java b/collections/src/main/java/android/support/v4/util/ArrayMap.java
new file mode 100644
index 0000000..1948093
--- /dev/null
+++ b/collections/src/main/java/android/support/v4/util/ArrayMap.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ArrayMap is a generic key->value mapping data structure that is
+ * designed to be more memory efficient than a traditional {@link java.util.HashMap},
+ * this implementation is a version of the platform's
+ * {@code android.util.ArrayMap} that can be used on older versions of the platform.
+ * It keeps its mappings in an array data structure -- an integer array of hash
+ * codes for each item, and an Object array of the key/value pairs.  This allows it to
+ * avoid having to create an extra object for every entry put in to the map, and it
+ * also tries to control the growth of the size of these arrays more aggressively
+ * (since growing them only requires copying the entries in the array, not rebuilding
+ * a hash map).
+ *
+ * <p>If you don't need the standard Java container APIs provided here (iterators etc),
+ * consider using {@link SimpleArrayMap} instead.</p>
+ *
+ * <p>Note that this implementation is not intended to be appropriate for data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>Because this container is intended to better balance memory use, unlike most other
+ * standard Java containers it will shrink its array as items are removed from it.  Currently
+ * you have no control over this shrinking -- if you set a capacity and then remove an
+ * item, it may reduce the capacity to better match the current size.  In the future an
+ * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
+ */
+public class ArrayMap<K, V> extends SimpleArrayMap<K, V> implements Map<K, V> {
+    MapCollections<K, V> mCollections;
+
+    public ArrayMap() {
+        super();
+    }
+
+    /**
+     * Create a new ArrayMap with a given initial capacity.
+     */
+    public ArrayMap(int capacity) {
+        super(capacity);
+    }
+
+    /**
+     * Create a new ArrayMap with the mappings from the given ArrayMap.
+     */
+    public ArrayMap(SimpleArrayMap map) {
+        super(map);
+    }
+
+    private MapCollections<K, V> getCollection() {
+        if (mCollections == null) {
+            mCollections = new MapCollections<K, V>() {
+                @Override
+                protected int colGetSize() {
+                    return mSize;
+                }
+
+                @Override
+                protected Object colGetEntry(int index, int offset) {
+                    return mArray[(index<<1) + offset];
+                }
+
+                @Override
+                protected int colIndexOfKey(Object key) {
+                    return indexOfKey(key);
+                }
+
+                @Override
+                protected int colIndexOfValue(Object value) {
+                    return indexOfValue(value);
+                }
+
+                @Override
+                protected Map<K, V> colGetMap() {
+                    return ArrayMap.this;
+                }
+
+                @Override
+                protected void colPut(K key, V value) {
+                    put(key, value);
+                }
+
+                @Override
+                protected V colSetValue(int index, V value) {
+                    return setValueAt(index, value);
+                }
+
+                @Override
+                protected void colRemoveAt(int index) {
+                    removeAt(index);
+                }
+
+                @Override
+                protected void colClear() {
+                    clear();
+                }
+            };
+        }
+        return mCollections;
+    }
+
+    /**
+     * Determine if the array map contains all of the keys in the given collection.
+     * @param collection The collection whose contents are to be checked against.
+     * @return Returns true if this array map contains a key for every entry
+     * in <var>collection</var>, else returns false.
+     */
+    public boolean containsAll(Collection<?> collection) {
+        return MapCollections.containsAllHelper(this, collection);
+    }
+
+    /**
+     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>map</var>
+     * @param map The map whose contents are to be retrieved.
+     */
+    @Override
+    public void putAll(Map<? extends K, ? extends V> map) {
+        ensureCapacity(mSize + map.size());
+        for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Remove all keys in the array map that exist in the given collection.
+     * @param collection The collection whose contents are to be used to remove keys.
+     * @return Returns true if any keys were removed from the array map, else false.
+     */
+    public boolean removeAll(Collection<?> collection) {
+        return MapCollections.removeAllHelper(this, collection);
+    }
+
+    /**
+     * Remove all keys in the array map that do <b>not</b> exist in the given collection.
+     * @param collection The collection whose contents are to be used to determine which
+     * keys to keep.
+     * @return Returns true if any keys were removed from the array map, else false.
+     */
+    public boolean retainAll(Collection<?> collection) {
+        return MapCollections.retainAllHelper(this, collection);
+    }
+
+    /**
+     * Return a {@link java.util.Set} for iterating over and interacting with all mappings
+     * in the array map.
+     *
+     * <p><b>Note:</b> this is a very inefficient way to access the array contents, it
+     * requires generating a number of temporary objects.</p>
+     *
+     * <p><b>Note:</b></p> the semantics of this
+     * Set are subtly different than that of a {@link java.util.HashMap}: most important,
+     * the {@link java.util.Map.Entry Map.Entry} object returned by its iterator is a single
+     * object that exists for the entire iterator, so you can <b>not</b> hold on to it
+     * after calling {@link java.util.Iterator#next() Iterator.next}.</p>
+     */
+    @Override
+    public Set<Entry<K, V>> entrySet() {
+        return getCollection().getEntrySet();
+    }
+
+    /**
+     * Return a {@link java.util.Set} for iterating over and interacting with all keys
+     * in the array map.
+     *
+     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
+     * requires generating a number of temporary objects.</p>
+     */
+    @Override
+    public Set<K> keySet() {
+        return getCollection().getKeySet();
+    }
+
+    /**
+     * Return a {@link java.util.Collection} for iterating over and interacting with all values
+     * in the array map.
+     *
+     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
+     * requires generating a number of temporary objects.</p>
+     */
+    @Override
+    public Collection<V> values() {
+        return getCollection().getValues();
+    }
+}
diff --git a/collections/src/main/java/android/support/v4/util/ArraySet.java b/collections/src/main/java/android/support/v4/util/ArraySet.java
new file mode 100644
index 0000000..84073f0
--- /dev/null
+++ b/collections/src/main/java/android/support/v4/util/ArraySet.java
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ArraySet is a generic set data structure that is designed to be more memory efficient than a
+ * traditional {@link java.util.HashSet}.  The design is very similar to
+ * {@link ArrayMap}, with all of the caveats described there.  This implementation is
+ * separate from ArrayMap, however, so the Object array contains only one item for each
+ * entry in the set (instead of a pair for a mapping).
+ *
+ * <p>Note that this implementation is not intended to be appropriate for data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashSet, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>Because this container is intended to better balance memory use, unlike most other
+ * standard Java containers it will shrink its array as items are removed from it.  Currently
+ * you have no control over this shrinking -- if you set a capacity and then remove an
+ * item, it may reduce the capacity to better match the current size.  In the future an
+ * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
+ */
+public final class ArraySet<E> implements Collection<E>, Set<E> {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "ArraySet";
+    private static final int[] INT = new int[0];
+    private static final Object[] OBJECT = new Object[0];
+
+    /**
+     * The minimum amount by which the capacity of a ArraySet will increase.
+     * This is tuned to be relatively space-efficient.
+     */
+    private static final int BASE_SIZE = 4;
+
+    /**
+     * Maximum number of entries to have in array caches.
+     */
+    private static final int CACHE_SIZE = 10;
+
+    /**
+     * Caches of small array objects to avoid spamming garbage.  The cache
+     * Object[] variable is a pointer to a linked list of array objects.
+     * The first entry in the array is a pointer to the next array in the
+     * list; the second entry is a pointer to the int[] hash code array for it.
+     */
+    private static Object[] sBaseCache;
+    private static int sBaseCacheSize;
+    private static Object[] sTwiceBaseCache;
+    private static int sTwiceBaseCacheSize;
+
+    private int[] mHashes;
+    private Object[] mArray;
+    private int mSize;
+    private MapCollections<E, E> mCollections;
+
+    private int indexOf(Object key, int hash) {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, hash);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (key.equals(mArray[index])) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == hash; end++) {
+            if (key.equals(mArray[end])) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
+            if (key.equals(mArray[i])) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    private int indexOfNull() {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = ContainerHelpers.binarySearch(mHashes, N, 0);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (null == mArray[index]) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == 0; end++) {
+            if (null == mArray[end]) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {
+            if (null == mArray[i]) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    @SuppressWarnings("ArrayToString")
+    private void allocArrays(final int size) {
+        if (size == (BASE_SIZE * 2)) {
+            synchronized (ArraySet.class) {
+                if (sTwiceBaseCache != null) {
+                    final Object[] array = sTwiceBaseCache;
+                    mArray = array;
+                    sTwiceBaseCache = (Object[]) array[0];
+                    mHashes = (int[]) array[1];
+                    array[0] = array[1] = null;
+                    sTwiceBaseCacheSize--;
+                    if (DEBUG) {
+                        System.out.println(TAG + " Retrieving 2x cache " + mHashes + " now have "
+                                + sTwiceBaseCacheSize + " entries");
+                    }
+                    return;
+                }
+            }
+        } else if (size == BASE_SIZE) {
+            synchronized (ArraySet.class) {
+                if (sBaseCache != null) {
+                    final Object[] array = sBaseCache;
+                    mArray = array;
+                    sBaseCache = (Object[]) array[0];
+                    mHashes = (int[]) array[1];
+                    array[0] = array[1] = null;
+                    sBaseCacheSize--;
+                    if (DEBUG) {
+                        System.out.println(TAG + " Retrieving 1x cache " + mHashes + " now have "
+                                + sBaseCacheSize + " entries");
+                    }
+                    return;
+                }
+            }
+        }
+
+        mHashes = new int[size];
+        mArray = new Object[size];
+    }
+
+    @SuppressWarnings("ArrayToString")
+    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
+        if (hashes.length == (BASE_SIZE * 2)) {
+            synchronized (ArraySet.class) {
+                if (sTwiceBaseCacheSize < CACHE_SIZE) {
+                    array[0] = sTwiceBaseCache;
+                    array[1] = hashes;
+                    for (int i = size - 1; i >= 2; i--) {
+                        array[i] = null;
+                    }
+                    sTwiceBaseCache = array;
+                    sTwiceBaseCacheSize++;
+                    if (DEBUG) {
+                        System.out.println(TAG + " Storing 2x cache " + array + " now have "
+                                + sTwiceBaseCacheSize + " entries");
+                    }
+                }
+            }
+        } else if (hashes.length == BASE_SIZE) {
+            synchronized (ArraySet.class) {
+                if (sBaseCacheSize < CACHE_SIZE) {
+                    array[0] = sBaseCache;
+                    array[1] = hashes;
+                    for (int i = size - 1; i >= 2; i--) {
+                        array[i] = null;
+                    }
+                    sBaseCache = array;
+                    sBaseCacheSize++;
+                    if (DEBUG) {
+                        System.out.println(TAG + " Storing 1x cache " + array + " now have "
+                                + sBaseCacheSize + " entries");
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a new empty ArraySet.  The default capacity of an array map is 0, and
+     * will grow once items are added to it.
+     */
+    public ArraySet() {
+        this(0);
+    }
+
+    /**
+     * Create a new ArraySet with a given initial capacity.
+     */
+    public ArraySet(int capacity) {
+        if (capacity == 0) {
+            mHashes = INT;
+            mArray = OBJECT;
+        } else {
+            allocArrays(capacity);
+        }
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArraySet with the mappings from the given ArraySet.
+     */
+    public ArraySet(@Nullable ArraySet<E> set) {
+        this();
+        if (set != null) {
+            addAll(set);
+        }
+    }
+
+    /**
+     * Create a new ArraySet with the mappings from the given {@link Collection}.
+     */
+    public ArraySet(@Nullable Collection<E> set) {
+        this();
+        if (set != null) {
+            addAll(set);
+        }
+    }
+
+    /**
+     * Make the array map empty.  All storage is released.
+     */
+    @Override
+    public void clear() {
+        if (mSize != 0) {
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = INT;
+            mArray = OBJECT;
+            mSize = 0;
+        }
+    }
+
+    /**
+     * Ensure the array map can hold at least <var>minimumCapacity</var>
+     * items.
+     */
+    public void ensureCapacity(int minimumCapacity) {
+        if (mHashes.length < minimumCapacity) {
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(minimumCapacity);
+            if (mSize > 0) {
+                System.arraycopy(ohashes, 0, mHashes, 0, mSize);
+                System.arraycopy(oarray, 0, mArray, 0, mSize);
+            }
+            freeArrays(ohashes, oarray, mSize);
+        }
+    }
+
+    /**
+     * Check whether a value exists in the set.
+     *
+     * @param key The value to search for.
+     * @return Returns true if the value exists, else false.
+     */
+    @Override
+    public boolean contains(Object key) {
+        return indexOf(key) >= 0;
+    }
+
+    /**
+     * Returns the index of a value in the set.
+     *
+     * @param key The value to search for.
+     * @return Returns the index of the value if it exists, else a negative integer.
+     */
+    public int indexOf(Object key) {
+        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+    }
+
+    /**
+     * Return the value at the given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value stored at the given index.
+     */
+    @Nullable
+    public E valueAt(int index) {
+        return (E) mArray[index];
+    }
+
+    /**
+     * Return true if the array map contains no items.
+     */
+    @Override
+    public boolean isEmpty() {
+        return mSize <= 0;
+    }
+
+    /**
+     * Adds the specified object to this set. The set is not modified if it
+     * already contains the object.
+     *
+     * @param value the object to add.
+     * @return {@code true} if this set is modified, {@code false} otherwise.
+     * @throws ClassCastException
+     *             when the class of the object is inappropriate for this set.
+     */
+    @Override
+    public boolean add(@Nullable E value) {
+        final int hash;
+        int index;
+        if (value == null) {
+            hash = 0;
+            index = indexOfNull();
+        } else {
+            hash = value.hashCode();
+            index = indexOf(value, hash);
+        }
+        if (index >= 0) {
+            return false;
+        }
+
+        index = ~index;
+        if (mSize >= mHashes.length) {
+            final int n = mSize >= (BASE_SIZE * 2) ? (mSize + (mSize >> 1))
+                    : (mSize >= BASE_SIZE ? (BASE_SIZE * 2) : BASE_SIZE);
+
+            if (DEBUG) System.out.println(TAG + " add: grow from " + mHashes.length + " to " + n);
+
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(n);
+
+            if (mHashes.length > 0) {
+                if (DEBUG) System.out.println(TAG + " add: copy 0-" + mSize + " to 0");
+                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
+                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
+            }
+
+            freeArrays(ohashes, oarray, mSize);
+        }
+
+        if (index < mSize) {
+            if (DEBUG) {
+                System.out.println(TAG + " add: move " + index + "-" + (mSize - index) + " to "
+                        + (index + 1));
+            }
+            System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);
+            System.arraycopy(mArray, index, mArray, index + 1, mSize - index);
+        }
+
+        mHashes[index] = hash;
+        mArray[index] = value;
+        mSize++;
+        return true;
+    }
+
+    /**
+     * Special fast path for appending items to the end of the array without validation.
+     * The array must already be large enough to contain the item.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void append(E value) {
+        final int index = mSize;
+        final int hash = value == null ? 0 : value.hashCode();
+        if (index >= mHashes.length) {
+            throw new IllegalStateException("Array is full");
+        }
+        if (index > 0 && mHashes[index - 1] > hash) {
+            // Cannot optimize since it would break the sorted order - fallback to add()
+            if (DEBUG) {
+                RuntimeException e = new RuntimeException("here");
+                System.err.println(TAG + " New hash " + hash
+                        + " is before end of array hash " + mHashes[index - 1]
+                        + " at index " + index);
+                e.printStackTrace();
+            }
+            add(value);
+            return;
+        }
+        mSize = index + 1;
+        mHashes[index] = hash;
+        mArray[index] = value;
+    }
+
+    /**
+     * Perform a {@link #add(Object)} of all values in <var>array</var>
+     * @param array The array whose contents are to be retrieved.
+     */
+    public void addAll(@NonNull ArraySet<? extends E> array) {
+        final int N = array.mSize;
+        ensureCapacity(mSize + N);
+        if (mSize == 0) {
+            if (N > 0) {
+                System.arraycopy(array.mHashes, 0, mHashes, 0, N);
+                System.arraycopy(array.mArray, 0, mArray, 0, N);
+                mSize = N;
+            }
+        } else {
+            for (int i = 0; i < N; i++) {
+                add(array.valueAt(i));
+            }
+        }
+    }
+
+    /**
+     * Removes the specified object from this set.
+     *
+     * @param object the object to remove.
+     * @return {@code true} if this set was modified, {@code false} otherwise.
+     */
+    @Override
+    public boolean remove(Object object) {
+        final int index = indexOf(object);
+        if (index >= 0) {
+            removeAt(index);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Remove the key/value mapping at the given index.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value that was stored at this index.
+     */
+    public E removeAt(int index) {
+        final Object old = mArray[index];
+        if (mSize <= 1) {
+            // Now empty.
+            if (DEBUG) System.out.println(TAG + " remove: shrink from " + mHashes.length + " to 0");
+            freeArrays(mHashes, mArray, mSize);
+            mHashes = INT;
+            mArray = OBJECT;
+            mSize = 0;
+        } else {
+            if (mHashes.length > (BASE_SIZE * 2) && mSize < mHashes.length / 3) {
+                // Shrunk enough to reduce size of arrays.  We don't allow it to
+                // shrink smaller than (BASE_SIZE*2) to avoid flapping between
+                // that and BASE_SIZE.
+                final int n = mSize > (BASE_SIZE * 2) ? (mSize + (mSize >> 1)) : (BASE_SIZE * 2);
+
+                if (DEBUG) System.out.println(TAG + " remove: shrink from " + mHashes.length + " to " + n);
+
+                final int[] ohashes = mHashes;
+                final Object[] oarray = mArray;
+                allocArrays(n);
+
+                mSize--;
+                if (index > 0) {
+                    if (DEBUG) System.out.println(TAG + " remove: copy from 0-" + index + " to 0");
+                    System.arraycopy(ohashes, 0, mHashes, 0, index);
+                    System.arraycopy(oarray, 0, mArray, 0, index);
+                }
+                if (index < mSize) {
+                    if (DEBUG) {
+                        System.out.println(TAG + " remove: copy from " + (index + 1) + "-" + mSize
+                                + " to " + index);
+                    }
+                    System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(oarray, index + 1, mArray, index, mSize - index);
+                }
+            } else {
+                mSize--;
+                if (index < mSize) {
+                    if (DEBUG) {
+                        System.out.println(TAG + " remove: move " + (index + 1) + "-" + mSize + " to " + index);
+                    }
+                    System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);
+                    System.arraycopy(mArray, index + 1, mArray, index, mSize - index);
+                }
+                mArray[mSize] = null;
+            }
+        }
+        return (E) old;
+    }
+
+    /**
+     * Perform a {@link #remove(Object)} of all values in <var>array</var>
+     * @param array The array whose contents are to be removed.
+     */
+    public boolean removeAll(ArraySet<? extends E> array) {
+        // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first
+        //       pass, use the property that the sets are sorted by hash to make this linear passes
+        //       (except for hash collisions, which means worst case still n*m), then do one
+        //       collection pass into a new array. This avoids binary searches and excessive memcpy.
+        final int N = array.mSize;
+
+        // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all
+        //       the single results, compare size before and after.
+        final int originalSize = mSize;
+        for (int i = 0; i < N; i++) {
+            remove(array.valueAt(i));
+        }
+        return originalSize != mSize;
+    }
+
+    /**
+     * Return the number of items in this array map.
+     */
+    @Override
+    public int size() {
+        return mSize;
+    }
+
+    @NonNull
+    @Override
+    public Object[] toArray() {
+        Object[] result = new Object[mSize];
+        System.arraycopy(mArray, 0, result, 0, mSize);
+        return result;
+    }
+
+    @NonNull
+    @Override
+    public <T> T[] toArray(@NonNull T[] array) {
+        if (array.length < mSize) {
+            @SuppressWarnings("unchecked") T[] newArray =
+                    (T[]) Array.newInstance(array.getClass().getComponentType(), mSize);
+            array = newArray;
+        }
+        System.arraycopy(mArray, 0, array, 0, mSize);
+        if (array.length > mSize) {
+            array[mSize] = null;
+        }
+        return array;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns false if the object is not a set, or
+     * if the sets have different sizes.  Otherwise, for each value in this
+     * set, it checks to make sure the value also exists in the other set.
+     * If any value doesn't exist, the method returns false; otherwise, it
+     * returns true.
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object instanceof Set) {
+            Set<?> set = (Set<?>) object;
+            if (size() != set.size()) {
+                return false;
+            }
+
+            try {
+                for (int i = 0; i < mSize; i++) {
+                    E mine = valueAt(i);
+                    if (!set.contains(mine)) {
+                        return false;
+                    }
+                }
+            } catch (NullPointerException ignored) {
+                return false;
+            } catch (ClassCastException ignored) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        final int[] hashes = mHashes;
+        int result = 0;
+        for (int i = 0, s = mSize; i < s; i++) {
+            result += hashes[i];
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its values. If
+     * this set contains itself as a value, the string "(this Set)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (isEmpty()) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 14);
+        buffer.append('{');
+        for (int i = 0; i < mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Set)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+
+    // ------------------------------------------------------------------------
+    // Interop with traditional Java containers.  Not as efficient as using
+    // specialized collection APIs.
+    // ------------------------------------------------------------------------
+
+    private MapCollections<E, E> getCollection() {
+        if (mCollections == null) {
+            mCollections = new MapCollections<E, E>() {
+                @Override
+                protected int colGetSize() {
+                    return mSize;
+                }
+
+                @Override
+                protected Object colGetEntry(int index, int offset) {
+                    return mArray[index];
+                }
+
+                @Override
+                protected int colIndexOfKey(Object key) {
+                    return indexOf(key);
+                }
+
+                @Override
+                protected int colIndexOfValue(Object value) {
+                    return indexOf(value);
+                }
+
+                @Override
+                protected Map<E, E> colGetMap() {
+                    throw new UnsupportedOperationException("not a map");
+                }
+
+                @Override
+                protected void colPut(E key, E value) {
+                    add(key);
+                }
+
+                @Override
+                protected E colSetValue(int index, E value) {
+                    throw new UnsupportedOperationException("not a map");
+                }
+
+                @Override
+                protected void colRemoveAt(int index) {
+                    removeAt(index);
+                }
+
+                @Override
+                protected void colClear() {
+                    clear();
+                }
+            };
+        }
+        return mCollections;
+    }
+
+    /**
+     * Return an {@link java.util.Iterator} over all values in the set.
+     *
+     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
+     * requires generating a number of temporary objects and allocates additional state
+     * information associated with the container that will remain for the life of the container.</p>
+     */
+    @Override
+    public Iterator<E> iterator() {
+        return getCollection().getKeySet().iterator();
+    }
+
+    /**
+     * Determine if the array set contains all of the values in the given collection.
+     * @param collection The collection whose contents are to be checked against.
+     * @return Returns true if this array set contains a value for every entry
+     * in <var>collection</var>, else returns false.
+     */
+    @Override
+    public boolean containsAll(@NonNull Collection<?> collection) {
+        Iterator<?> it = collection.iterator();
+        while (it.hasNext()) {
+            if (!contains(it.next())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Perform an {@link #add(Object)} of all values in <var>collection</var>
+     * @param collection The collection whose contents are to be retrieved.
+     */
+    @Override
+    public boolean addAll(@NonNull Collection<? extends E> collection) {
+        ensureCapacity(mSize + collection.size());
+        boolean added = false;
+        for (E value : collection) {
+            added |= add(value);
+        }
+        return added;
+    }
+
+    /**
+     * Remove all values in the array set that exist in the given collection.
+     * @param collection The collection whose contents are to be used to remove values.
+     * @return Returns true if any values were removed from the array set, else false.
+     */
+    @Override
+    public boolean removeAll(@NonNull Collection<?> collection) {
+        boolean removed = false;
+        for (Object value : collection) {
+            removed |= remove(value);
+        }
+        return removed;
+    }
+
+    /**
+     * Remove all values in the array set that do <b>not</b> exist in the given collection.
+     * @param collection The collection whose contents are to be used to determine which
+     * values to keep.
+     * @return Returns true if any values were removed from the array set, else false.
+     */
+    @Override
+    public boolean retainAll(@NonNull Collection<?> collection) {
+        boolean removed = false;
+        for (int i = mSize - 1; i >= 0; i--) {
+            if (!collection.contains(mArray[i])) {
+                removeAt(i);
+                removed = true;
+            }
+        }
+        return removed;
+    }
+}
diff --git a/compat/src/main/java/android/support/v4/util/CircularArray.java b/collections/src/main/java/android/support/v4/util/CircularArray.java
similarity index 100%
rename from compat/src/main/java/android/support/v4/util/CircularArray.java
rename to collections/src/main/java/android/support/v4/util/CircularArray.java
diff --git a/compat/src/main/java/android/support/v4/util/CircularIntArray.java b/collections/src/main/java/android/support/v4/util/CircularIntArray.java
similarity index 100%
rename from compat/src/main/java/android/support/v4/util/CircularIntArray.java
rename to collections/src/main/java/android/support/v4/util/CircularIntArray.java
diff --git a/compat/src/main/java/android/support/v4/util/ContainerHelpers.java b/collections/src/main/java/android/support/v4/util/ContainerHelpers.java
similarity index 100%
rename from compat/src/main/java/android/support/v4/util/ContainerHelpers.java
rename to collections/src/main/java/android/support/v4/util/ContainerHelpers.java
diff --git a/collections/src/main/java/android/support/v4/util/LongSparseArray.java b/collections/src/main/java/android/support/v4/util/LongSparseArray.java
new file mode 100644
index 0000000..9285619
--- /dev/null
+++ b/collections/src/main/java/android/support/v4/util/LongSparseArray.java
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+/**
+ * SparseArray mapping longs to Objects, a version of the platform's
+ * {@code android.util.LongSparseArray} that can be used on older versions of the
+ * platform.  Unlike a normal array of Objects,
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Longs to Objects, both because it avoids
+  * auto-boxing keys and its data structure doesn't rely on an extra entry object
+  * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>To help with performance, the container includes an optimization when removing
+ * keys: instead of compacting its array immediately, it leaves the removed entry marked
+ * as deleted.  The entry can then be re-used for the same key, or compacted later in
+ * a single garbage collection step of all removed entries.  This garbage collection will
+ * need to be performed at any time the array needs to be grown or the the map size or
+ * entry values are retrieved.</p>
+ */
+public class LongSparseArray<E> implements Cloneable {
+    private static final Object DELETED = new Object();
+    private boolean mGarbage = false;
+
+    private long[] mKeys;
+    private Object[] mValues;
+    private int mSize;
+
+    /**
+     * Creates a new LongSparseArray containing no mappings.
+     */
+    public LongSparseArray() {
+        this(10);
+    }
+
+    /**
+     * Creates a new LongSparseArray containing no mappings that will not
+     * require any additional memory allocation to store the specified
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
+     */
+    public LongSparseArray(int initialCapacity) {
+        if (initialCapacity == 0) {
+            mKeys = ContainerHelpers.EMPTY_LONGS;
+            mValues = ContainerHelpers.EMPTY_OBJECTS;
+        } else {
+            initialCapacity = ContainerHelpers.idealLongArraySize(initialCapacity);
+            mKeys = new long[initialCapacity];
+            mValues = new Object[initialCapacity];
+        }
+        mSize = 0;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public LongSparseArray<E> clone() {
+        LongSparseArray<E> clone = null;
+        try {
+            clone = (LongSparseArray<E>) super.clone();
+            clone.mKeys = mKeys.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or <code>null</code>
+     * if no such mapping has been made.
+     */
+    public E get(long key) {
+        return get(key, null);
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or the specified Object
+     * if no such mapping has been made.
+     */
+    @SuppressWarnings("unchecked")
+    public E get(long key, E valueIfKeyNotFound) {
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i < 0 || mValues[i] == DELETED) {
+            return valueIfKeyNotFound;
+        } else {
+            return (E) mValues[i];
+        }
+    }
+
+    /**
+     * Removes the mapping from the specified key, if there was any.
+     */
+    public void delete(long key) {
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i >= 0) {
+            if (mValues[i] != DELETED) {
+                mValues[i] = DELETED;
+                mGarbage = true;
+            }
+        }
+    }
+
+    /**
+     * Alias for {@link #delete(long)}.
+     */
+    public void remove(long key) {
+        delete(key);
+    }
+
+    /**
+     * Removes the mapping at the specified index.
+     */
+    public void removeAt(int index) {
+        if (mValues[index] != DELETED) {
+            mValues[index] = DELETED;
+            mGarbage = true;
+        }
+    }
+
+    private void gc() {
+        // Log.e("SparseArray", "gc start with " + mSize);
+
+        int n = mSize;
+        int o = 0;
+        long[] keys = mKeys;
+        Object[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            Object val = values[i];
+
+            if (val != DELETED) {
+                if (i != o) {
+                    keys[o] = keys[i];
+                    values[o] = val;
+                    values[i] = null;
+                }
+
+                o++;
+            }
+        }
+
+        mGarbage = false;
+        mSize = o;
+
+        // Log.e("SparseArray", "gc end with " + mSize);
+    }
+
+    /**
+     * Adds a mapping from the specified key to the specified value,
+     * replacing the previous mapping from the specified key if there
+     * was one.
+     */
+    public void put(long key, E value) {
+        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i >= 0) {
+            mValues[i] = value;
+        } else {
+            i = ~i;
+
+            if (i < mSize && mValues[i] == DELETED) {
+                mKeys[i] = key;
+                mValues[i] = value;
+                return;
+            }
+
+            if (mGarbage && mSize >= mKeys.length) {
+                gc();
+
+                // Search again because indices may have changed.
+                i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
+            }
+
+            if (mSize >= mKeys.length) {
+                int n = ContainerHelpers.idealLongArraySize(mSize + 1);
+
+                long[] nkeys = new long[n];
+                Object[] nvalues = new Object[n];
+
+                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+                mKeys = nkeys;
+                mValues = nvalues;
+            }
+
+            if (mSize - i != 0) {
+                // Log.e("SparseArray", "move " + (mSize - i));
+                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+            }
+
+            mKeys[i] = key;
+            mValues[i] = value;
+            mSize++;
+        }
+    }
+
+    /**
+     * Returns the number of key-value mappings that this LongSparseArray
+     * currently stores.
+     */
+    public int size() {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mSize;
+    }
+
+    /**
+     * Return true if size() is 0.
+     * @return true if size() is 0.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the key from the <code>index</code>th key-value mapping that this
+     * LongSparseArray stores.
+     */
+    public long keyAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mKeys[index];
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the value from the <code>index</code>th key-value mapping that this
+     * LongSparseArray stores.
+     */
+    @SuppressWarnings("unchecked")
+    public E valueAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return (E) mValues[index];
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, sets a new
+     * value for the <code>index</code>th key-value mapping that this
+     * LongSparseArray stores.
+     */
+    public void setValueAt(int index, E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        mValues[index] = value;
+    }
+
+    /**
+     * Returns the index for which {@link #keyAt} would return the
+     * specified key, or a negative number if the specified
+     * key is not mapped.
+     */
+    public int indexOfKey(long key) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return ContainerHelpers.binarySearch(mKeys, mSize, key);
+    }
+
+    /**
+     * Returns an index for which {@link #valueAt} would return the
+     * specified key, or a negative number if no keys map to the
+     * specified value.
+     * Beware that this is a linear search, unlike lookups by key,
+     * and that multiple keys can map to the same value and this will
+     * find only one of them.
+     */
+    public int indexOfValue(E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        for (int i = 0; i < mSize; i++)
+            if (mValues[i] == value)
+                return i;
+
+        return -1;
+    }
+
+    /**
+     * Removes all key-value mappings from this LongSparseArray.
+     */
+    public void clear() {
+        int n = mSize;
+        Object[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            values[i] = null;
+        }
+
+        mSize = 0;
+        mGarbage = false;
+    }
+
+    /**
+     * Puts a key/value pair into the array, optimizing for the case where
+     * the key is greater than all existing keys in the array.
+     */
+    public void append(long key, E value) {
+        if (mSize != 0 && key <= mKeys[mSize - 1]) {
+            put(key, value);
+            return;
+        }
+
+        if (mGarbage && mSize >= mKeys.length) {
+            gc();
+        }
+
+        int pos = mSize;
+        if (pos >= mKeys.length) {
+            int n = ContainerHelpers.idealLongArraySize(pos + 1);
+
+            long[] nkeys = new long[n];
+            Object[] nvalues = new Object[n];
+
+            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+            mKeys = nkeys;
+            mValues = nvalues;
+        }
+
+        mKeys[pos] = key;
+        mValues[pos] = value;
+        mSize = pos + 1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings. If
+     * this map contains itself as a value, the string "(this Map)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            long key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Map)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+}
diff --git a/collections/src/main/java/android/support/v4/util/LruCache.java b/collections/src/main/java/android/support/v4/util/LruCache.java
new file mode 100644
index 0000000..d41f4fb
--- /dev/null
+++ b/collections/src/main/java/android/support/v4/util/LruCache.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Static library version of {@code android.util.LruCache}. Used to write apps
+ * that run on API levels prior to 12. When running on API level 12 or above,
+ * this implementation is still used; it does not try to switch to the
+ * framework's implementation. See the framework SDK documentation for a class
+ * overview.
+ */
+public class LruCache<K, V> {
+    private final LinkedHashMap<K, V> map;
+
+    /** Size of this cache in units. Not necessarily the number of elements. */
+    private int size;
+    private int maxSize;
+
+    private int putCount;
+    private int createCount;
+    private int evictionCount;
+    private int hitCount;
+    private int missCount;
+
+    /**
+     * @param maxSize for caches that do not override {@link #sizeOf}, this is
+     *     the maximum number of entries in the cache. For all other caches,
+     *     this is the maximum sum of the sizes of the entries in this cache.
+     */
+    public LruCache(int maxSize) {
+        if (maxSize <= 0) {
+            throw new IllegalArgumentException("maxSize <= 0");
+        }
+        this.maxSize = maxSize;
+        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
+    }
+
+    /**
+     * Sets the size of the cache.
+     *
+     * @param maxSize The new maximum size.
+     */
+    public void resize(int maxSize) {
+        if (maxSize <= 0) {
+            throw new IllegalArgumentException("maxSize <= 0");
+        }
+
+        synchronized (this) {
+            this.maxSize = maxSize;
+        }
+        trimToSize(maxSize);
+    }
+
+    /**
+     * Returns the value for {@code key} if it exists in the cache or can be
+     * created by {@code #create}. If a value was returned, it is moved to the
+     * head of the queue. This returns null if a value is not cached and cannot
+     * be created.
+     */
+    public final V get(K key) {
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        }
+
+        V mapValue;
+        synchronized (this) {
+            mapValue = map.get(key);
+            if (mapValue != null) {
+                hitCount++;
+                return mapValue;
+            }
+            missCount++;
+        }
+
+        /*
+         * Attempt to create a value. This may take a long time, and the map
+         * may be different when create() returns. If a conflicting value was
+         * added to the map while create() was working, we leave that value in
+         * the map and release the created value.
+         */
+
+        V createdValue = create(key);
+        if (createdValue == null) {
+            return null;
+        }
+
+        synchronized (this) {
+            createCount++;
+            mapValue = map.put(key, createdValue);
+
+            if (mapValue != null) {
+                // There was a conflict so undo that last put
+                map.put(key, mapValue);
+            } else {
+                size += safeSizeOf(key, createdValue);
+            }
+        }
+
+        if (mapValue != null) {
+            entryRemoved(false, key, createdValue, mapValue);
+            return mapValue;
+        } else {
+            trimToSize(maxSize);
+            return createdValue;
+        }
+    }
+
+    /**
+     * Caches {@code value} for {@code key}. The value is moved to the head of
+     * the queue.
+     *
+     * @return the previous value mapped by {@code key}.
+     */
+    public final V put(K key, V value) {
+        if (key == null || value == null) {
+            throw new NullPointerException("key == null || value == null");
+        }
+
+        V previous;
+        synchronized (this) {
+            putCount++;
+            size += safeSizeOf(key, value);
+            previous = map.put(key, value);
+            if (previous != null) {
+                size -= safeSizeOf(key, previous);
+            }
+        }
+
+        if (previous != null) {
+            entryRemoved(false, key, previous, value);
+        }
+
+        trimToSize(maxSize);
+        return previous;
+    }
+
+    /**
+     * Remove the eldest entries until the total of remaining entries is at or
+     * below the requested size.
+     *
+     * @param maxSize the maximum size of the cache before returning. May be -1
+     *            to evict even 0-sized elements.
+     */
+    public void trimToSize(int maxSize) {
+        while (true) {
+            K key;
+            V value;
+            synchronized (this) {
+                if (size < 0 || (map.isEmpty() && size != 0)) {
+                    throw new IllegalStateException(getClass().getName()
+                            + ".sizeOf() is reporting inconsistent results!");
+                }
+
+                if (size <= maxSize || map.isEmpty()) {
+                    break;
+                }
+
+                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
+                key = toEvict.getKey();
+                value = toEvict.getValue();
+                map.remove(key);
+                size -= safeSizeOf(key, value);
+                evictionCount++;
+            }
+
+            entryRemoved(true, key, value, null);
+        }
+    }
+
+    /**
+     * Removes the entry for {@code key} if it exists.
+     *
+     * @return the previous value mapped by {@code key}.
+     */
+    public final V remove(K key) {
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        }
+
+        V previous;
+        synchronized (this) {
+            previous = map.remove(key);
+            if (previous != null) {
+                size -= safeSizeOf(key, previous);
+            }
+        }
+
+        if (previous != null) {
+            entryRemoved(false, key, previous, null);
+        }
+
+        return previous;
+    }
+
+    /**
+     * Called for entries that have been evicted or removed. This method is
+     * invoked when a value is evicted to make space, removed by a call to
+     * {@link #remove}, or replaced by a call to {@link #put}. The default
+     * implementation does nothing.
+     *
+     * <p>The method is called without synchronization: other threads may
+     * access the cache while this method is executing.
+     *
+     * @param evicted true if the entry is being removed to make space, false
+     *     if the removal was caused by a {@link #put} or {@link #remove}.
+     * @param newValue the new value for {@code key}, if it exists. If non-null,
+     *     this removal was caused by a {@link #put}. Otherwise it was caused by
+     *     an eviction or a {@link #remove}.
+     */
+    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
+
+    /**
+     * Called after a cache miss to compute a value for the corresponding key.
+     * Returns the computed value or null if no value can be computed. The
+     * default implementation returns null.
+     *
+     * <p>The method is called without synchronization: other threads may
+     * access the cache while this method is executing.
+     *
+     * <p>If a value for {@code key} exists in the cache when this method
+     * returns, the created value will be released with {@link #entryRemoved}
+     * and discarded. This can occur when multiple threads request the same key
+     * at the same time (causing multiple values to be created), or when one
+     * thread calls {@link #put} while another is creating a value for the same
+     * key.
+     */
+    protected V create(K key) {
+        return null;
+    }
+
+    private int safeSizeOf(K key, V value) {
+        int result = sizeOf(key, value);
+        if (result < 0) {
+            throw new IllegalStateException("Negative size: " + key + "=" + value);
+        }
+        return result;
+    }
+
+    /**
+     * Returns the size of the entry for {@code key} and {@code value} in
+     * user-defined units.  The default implementation returns 1 so that size
+     * is the number of entries and max size is the maximum number of entries.
+     *
+     * <p>An entry's size must not change while it is in the cache.
+     */
+    protected int sizeOf(K key, V value) {
+        return 1;
+    }
+
+    /**
+     * Clear the cache, calling {@link #entryRemoved} on each removed entry.
+     */
+    public final void evictAll() {
+        trimToSize(-1); // -1 will evict 0-sized elements
+    }
+
+    /**
+     * For caches that do not override {@link #sizeOf}, this returns the number
+     * of entries in the cache. For all other caches, this returns the sum of
+     * the sizes of the entries in this cache.
+     */
+    public synchronized final int size() {
+        return size;
+    }
+
+    /**
+     * For caches that do not override {@link #sizeOf}, this returns the maximum
+     * number of entries in the cache. For all other caches, this returns the
+     * maximum sum of the sizes of the entries in this cache.
+     */
+    public synchronized final int maxSize() {
+        return maxSize;
+    }
+
+    /**
+     * Returns the number of times {@link #get} returned a value that was
+     * already present in the cache.
+     */
+    public synchronized final int hitCount() {
+        return hitCount;
+    }
+
+    /**
+     * Returns the number of times {@link #get} returned null or required a new
+     * value to be created.
+     */
+    public synchronized final int missCount() {
+        return missCount;
+    }
+
+    /**
+     * Returns the number of times {@link #create(Object)} returned a value.
+     */
+    public synchronized final int createCount() {
+        return createCount;
+    }
+
+    /**
+     * Returns the number of times {@link #put} was called.
+     */
+    public synchronized final int putCount() {
+        return putCount;
+    }
+
+    /**
+     * Returns the number of values that have been evicted.
+     */
+    public synchronized final int evictionCount() {
+        return evictionCount;
+    }
+
+    /**
+     * Returns a copy of the current contents of the cache, ordered from least
+     * recently accessed to most recently accessed.
+     */
+    public synchronized final Map<K, V> snapshot() {
+        return new LinkedHashMap<K, V>(map);
+    }
+
+    @Override public synchronized final String toString() {
+        int accesses = hitCount + missCount;
+        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
+        return String.format(Locale.US, "LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
+                maxSize, hitCount, missCount, hitPercent);
+    }
+}
diff --git a/compat/src/main/java/android/support/v4/util/MapCollections.java b/collections/src/main/java/android/support/v4/util/MapCollections.java
similarity index 100%
rename from compat/src/main/java/android/support/v4/util/MapCollections.java
rename to collections/src/main/java/android/support/v4/util/MapCollections.java
diff --git a/collections/src/main/java/android/support/v4/util/SimpleArrayMap.java b/collections/src/main/java/android/support/v4/util/SimpleArrayMap.java
new file mode 100644
index 0000000..247451f
--- /dev/null
+++ b/collections/src/main/java/android/support/v4/util/SimpleArrayMap.java
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+import java.util.ConcurrentModificationException;
+import java.util.Map;
+
+/**
+ * Base implementation of {@link ArrayMap} that doesn't include any standard Java
+ * container API interoperability.  These features are generally heavier-weight ways
+ * to interact with the container, so discouraged, but they can be useful to make it
+ * easier to use as a drop-in replacement for HashMap.  If you don't need them, this
+ * class can be preferrable since it doesn't bring in any of the implementation of those
+ * APIs, allowing that code to be stripped by ProGuard.
+ */
+public class SimpleArrayMap<K, V> {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "ArrayMap";
+
+    /**
+     * Attempt to spot concurrent modifications to this data structure.
+     *
+     * It's best-effort, but any time we can throw something more diagnostic than an
+     * ArrayIndexOutOfBoundsException deep in the ArrayMap internals it's going to
+     * save a lot of development time.
+     *
+     * Good times to look for CME include after any allocArrays() call and at the end of
+     * functions that change mSize (put/remove/clear).
+     */
+    private static final boolean CONCURRENT_MODIFICATION_EXCEPTIONS = true;
+
+    /**
+     * The minimum amount by which the capacity of a ArrayMap will increase.
+     * This is tuned to be relatively space-efficient.
+     */
+    private static final int BASE_SIZE = 4;
+
+    /**
+     * Maximum number of entries to have in array caches.
+     */
+    private static final int CACHE_SIZE = 10;
+
+    /**
+     * Caches of small array objects to avoid spamming garbage.  The cache
+     * Object[] variable is a pointer to a linked list of array objects.
+     * The first entry in the array is a pointer to the next array in the
+     * list; the second entry is a pointer to the int[] hash code array for it.
+     */
+    static Object[] mBaseCache;
+    static int mBaseCacheSize;
+    static Object[] mTwiceBaseCache;
+    static int mTwiceBaseCacheSize;
+
+    int[] mHashes;
+    Object[] mArray;
+    int mSize;
+
+    private static int binarySearchHashes(int[] hashes, int N, int hash) {
+        try {
+            return ContainerHelpers.binarySearch(hashes, N, hash);
+        } catch (ArrayIndexOutOfBoundsException e) {
+            if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
+                throw new ConcurrentModificationException();
+            } else {
+                throw e; // the cache is poisoned at this point, there's not much we can do
+            }
+        }
+    }
+
+    int indexOf(Object key, int hash) {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = binarySearchHashes(mHashes, N, hash);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (key.equals(mArray[index<<1])) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == hash; end++) {
+            if (key.equals(mArray[end << 1])) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
+            if (key.equals(mArray[i << 1])) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    int indexOfNull() {
+        final int N = mSize;
+
+        // Important fast case: if nothing is in here, nothing to look for.
+        if (N == 0) {
+            return ~0;
+        }
+
+        int index = binarySearchHashes(mHashes, N, 0);
+
+        // If the hash code wasn't found, then we have no entry for this key.
+        if (index < 0) {
+            return index;
+        }
+
+        // If the key at the returned index matches, that's what we want.
+        if (null == mArray[index<<1]) {
+            return index;
+        }
+
+        // Search for a matching key after the index.
+        int end;
+        for (end = index + 1; end < N && mHashes[end] == 0; end++) {
+            if (null == mArray[end << 1]) return end;
+        }
+
+        // Search for a matching key before the index.
+        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {
+            if (null == mArray[i << 1]) return i;
+        }
+
+        // Key not found -- return negative value indicating where a
+        // new entry for this key should go.  We use the end of the
+        // hash chain to reduce the number of array entries that will
+        // need to be copied when inserting.
+        return ~end;
+    }
+
+    @SuppressWarnings("ArrayToString")
+    private void allocArrays(final int size) {
+        if (size == (BASE_SIZE*2)) {
+            synchronized (ArrayMap.class) {
+                if (mTwiceBaseCache != null) {
+                    final Object[] array = mTwiceBaseCache;
+                    mArray = array;
+                    mTwiceBaseCache = (Object[])array[0];
+                    mHashes = (int[])array[1];
+                    array[0] = array[1] = null;
+                    mTwiceBaseCacheSize--;
+                    if (DEBUG) System.out.println(TAG + " Retrieving 2x cache " + mHashes
+                            + " now have " + mTwiceBaseCacheSize + " entries");
+                    return;
+                }
+            }
+        } else if (size == BASE_SIZE) {
+            synchronized (ArrayMap.class) {
+                if (mBaseCache != null) {
+                    final Object[] array = mBaseCache;
+                    mArray = array;
+                    mBaseCache = (Object[])array[0];
+                    mHashes = (int[])array[1];
+                    array[0] = array[1] = null;
+                    mBaseCacheSize--;
+                    if (DEBUG) System.out.println(TAG + " Retrieving 1x cache " + mHashes
+                            + " now have " + mBaseCacheSize + " entries");
+                    return;
+                }
+            }
+        }
+
+        mHashes = new int[size];
+        mArray = new Object[size<<1];
+    }
+
+    @SuppressWarnings("ArrayToString")
+    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
+        if (hashes.length == (BASE_SIZE*2)) {
+            synchronized (ArrayMap.class) {
+                if (mTwiceBaseCacheSize < CACHE_SIZE) {
+                    array[0] = mTwiceBaseCache;
+                    array[1] = hashes;
+                    for (int i=(size<<1)-1; i>=2; i--) {
+                        array[i] = null;
+                    }
+                    mTwiceBaseCache = array;
+                    mTwiceBaseCacheSize++;
+                    if (DEBUG) System.out.println(TAG + " Storing 2x cache " + array
+                            + " now have " + mTwiceBaseCacheSize + " entries");
+                }
+            }
+        } else if (hashes.length == BASE_SIZE) {
+            synchronized (ArrayMap.class) {
+                if (mBaseCacheSize < CACHE_SIZE) {
+                    array[0] = mBaseCache;
+                    array[1] = hashes;
+                    for (int i=(size<<1)-1; i>=2; i--) {
+                        array[i] = null;
+                    }
+                    mBaseCache = array;
+                    mBaseCacheSize++;
+                    if (DEBUG) System.out.println(TAG + " Storing 1x cache " + array
+                            + " now have " + mBaseCacheSize + " entries");
+                }
+            }
+        }
+    }
+
+    /**
+     * Create a new empty ArrayMap.  The default capacity of an array map is 0, and
+     * will grow once items are added to it.
+     */
+    public SimpleArrayMap() {
+        mHashes = ContainerHelpers.EMPTY_INTS;
+        mArray = ContainerHelpers.EMPTY_OBJECTS;
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArrayMap with a given initial capacity.
+     */
+    public SimpleArrayMap(int capacity) {
+        if (capacity == 0) {
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+        } else {
+            allocArrays(capacity);
+        }
+        mSize = 0;
+    }
+
+    /**
+     * Create a new ArrayMap with the mappings from the given ArrayMap.
+     */
+    public SimpleArrayMap(SimpleArrayMap<K, V> map) {
+        this();
+        if (map != null) {
+            putAll(map);
+        }
+    }
+
+    /**
+     * Make the array map empty.  All storage is released.
+     */
+    public void clear() {
+        if (mSize > 0) {
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            final int osize = mSize;
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            mSize = 0;
+            freeArrays(ohashes, oarray, osize);
+        }
+        if (CONCURRENT_MODIFICATION_EXCEPTIONS && mSize > 0) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Ensure the array map can hold at least <var>minimumCapacity</var>
+     * items.
+     */
+    public void ensureCapacity(int minimumCapacity) {
+        final int osize = mSize;
+        if (mHashes.length < minimumCapacity) {
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(minimumCapacity);
+            if (mSize > 0) {
+                System.arraycopy(ohashes, 0, mHashes, 0, osize);
+                System.arraycopy(oarray, 0, mArray, 0, osize<<1);
+            }
+            freeArrays(ohashes, oarray, osize);
+        }
+        if (CONCURRENT_MODIFICATION_EXCEPTIONS && mSize != osize) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Check whether a key exists in the array.
+     *
+     * @param key The key to search for.
+     * @return Returns true if the key exists, else false.
+     */
+    public boolean containsKey(Object key) {
+        return indexOfKey(key) >= 0;
+    }
+
+    /**
+     * Returns the index of a key in the set.
+     *
+     * @param key The key to search for.
+     * @return Returns the index of the key if it exists, else a negative integer.
+     */
+    public int indexOfKey(Object key) {
+        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+    }
+
+    int indexOfValue(Object value) {
+        final int N = mSize*2;
+        final Object[] array = mArray;
+        if (value == null) {
+            for (int i=1; i<N; i+=2) {
+                if (array[i] == null) {
+                    return i>>1;
+                }
+            }
+        } else {
+            for (int i=1; i<N; i+=2) {
+                if (value.equals(array[i])) {
+                    return i>>1;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Check whether a value exists in the array.  This requires a linear search
+     * through the entire array.
+     *
+     * @param value The value to search for.
+     * @return Returns true if the value exists, else false.
+     */
+    public boolean containsValue(Object value) {
+        return indexOfValue(value) >= 0;
+    }
+
+    /**
+     * Retrieve a value from the array.
+     * @param key The key of the value to retrieve.
+     * @return Returns the value associated with the given key,
+     * or null if there is no such key.
+     */
+    public V get(Object key) {
+        final int index = indexOfKey(key);
+        return index >= 0 ? (V)mArray[(index<<1)+1] : null;
+    }
+
+    /**
+     * Return the key at the given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the key stored at the given index.
+     */
+    public K keyAt(int index) {
+        return (K)mArray[index << 1];
+    }
+
+    /**
+     * Return the value at the given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value stored at the given index.
+     */
+    public V valueAt(int index) {
+        return (V)mArray[(index << 1) + 1];
+    }
+
+    /**
+     * Set the value at a given index in the array.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @param value The new value to store at this index.
+     * @return Returns the previous value at the given index.
+     */
+    public V setValueAt(int index, V value) {
+        index = (index << 1) + 1;
+        V old = (V)mArray[index];
+        mArray[index] = value;
+        return old;
+    }
+
+    /**
+     * Return true if the array map contains no items.
+     */
+    public boolean isEmpty() {
+        return mSize <= 0;
+    }
+
+    /**
+     * Add a new value to the array map.
+     * @param key The key under which to store the value.  <b>Must not be null.</b>  If
+     * this key already exists in the array, its value will be replaced.
+     * @param value The value to store for the given key.
+     * @return Returns the old value that was stored for the given key, or null if there
+     * was no such key.
+     */
+    public V put(K key, V value) {
+        final int osize = mSize;
+        final int hash;
+        int index;
+        if (key == null) {
+            hash = 0;
+            index = indexOfNull();
+        } else {
+            hash = key.hashCode();
+            index = indexOf(key, hash);
+        }
+        if (index >= 0) {
+            index = (index<<1) + 1;
+            final V old = (V)mArray[index];
+            mArray[index] = value;
+            return old;
+        }
+
+        index = ~index;
+        if (osize >= mHashes.length) {
+            final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
+                    : (osize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
+
+            if (DEBUG) System.out.println(TAG + " put: grow from " + mHashes.length + " to " + n);
+
+            final int[] ohashes = mHashes;
+            final Object[] oarray = mArray;
+            allocArrays(n);
+
+            if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
+                throw new ConcurrentModificationException();
+            }
+
+            if (mHashes.length > 0) {
+                if (DEBUG) System.out.println(TAG + " put: copy 0-" + osize + " to 0");
+                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
+                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
+            }
+
+            freeArrays(ohashes, oarray, osize);
+        }
+
+        if (index < osize) {
+            if (DEBUG) System.out.println(TAG + " put: move " + index + "-" + (osize-index)
+                    + " to " + (index+1));
+            System.arraycopy(mHashes, index, mHashes, index + 1, osize - index);
+            System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);
+        }
+
+        if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
+            if (osize != mSize || index >= mHashes.length) {
+                throw new ConcurrentModificationException();
+            }
+        }
+
+        mHashes[index] = hash;
+        mArray[index<<1] = key;
+        mArray[(index<<1)+1] = value;
+        mSize++;
+        return null;
+    }
+
+    /**
+     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>array</var>
+     * @param array The array whose contents are to be retrieved.
+     */
+    public void putAll(SimpleArrayMap<? extends K, ? extends V> array) {
+        final int N = array.mSize;
+        ensureCapacity(mSize + N);
+        if (mSize == 0) {
+            if (N > 0) {
+                System.arraycopy(array.mHashes, 0, mHashes, 0, N);
+                System.arraycopy(array.mArray, 0, mArray, 0, N<<1);
+                mSize = N;
+            }
+        } else {
+            for (int i=0; i<N; i++) {
+                put(array.keyAt(i), array.valueAt(i));
+            }
+        }
+    }
+
+    /**
+     * Remove an existing key from the array map.
+     * @param key The key of the mapping to remove.
+     * @return Returns the value that was stored under the key, or null if there
+     * was no such key.
+     */
+    public V remove(Object key) {
+        final int index = indexOfKey(key);
+        if (index >= 0) {
+            return removeAt(index);
+        }
+
+        return null;
+    }
+
+    /**
+     * Remove the key/value mapping at the given index.
+     * @param index The desired index, must be between 0 and {@link #size()}-1.
+     * @return Returns the value that was stored at this index.
+     */
+    public V removeAt(int index) {
+        final Object old = mArray[(index << 1) + 1];
+        final int osize = mSize;
+        final int nsize;
+        if (osize <= 1) {
+            // Now empty.
+            if (DEBUG) System.out.println(TAG + " remove: shrink from " + mHashes.length + " to 0");
+            freeArrays(mHashes, mArray, osize);
+            mHashes = ContainerHelpers.EMPTY_INTS;
+            mArray = ContainerHelpers.EMPTY_OBJECTS;
+            nsize = 0;
+        } else {
+            nsize = osize - 1;
+            if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
+                // Shrunk enough to reduce size of arrays.  We don't allow it to
+                // shrink smaller than (BASE_SIZE*2) to avoid flapping between
+                // that and BASE_SIZE.
+                final int n = osize > (BASE_SIZE*2) ? (osize + (osize>>1)) : (BASE_SIZE*2);
+
+                if (DEBUG) System.out.println(TAG + " remove: shrink from " + mHashes.length + " to " + n);
+
+                final int[] ohashes = mHashes;
+                final Object[] oarray = mArray;
+                allocArrays(n);
+
+                if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
+                    throw new ConcurrentModificationException();
+                }
+
+                if (index > 0) {
+                    if (DEBUG) System.out.println(TAG + " remove: copy from 0-" + index + " to 0");
+                    System.arraycopy(ohashes, 0, mHashes, 0, index);
+                    System.arraycopy(oarray, 0, mArray, 0, index << 1);
+                }
+                if (index < nsize) {
+                    if (DEBUG) System.out.println(TAG + " remove: copy from " + (index+1) + "-" + nsize
+                            + " to " + index);
+                    System.arraycopy(ohashes, index + 1, mHashes, index, nsize - index);
+                    System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1,
+                            (nsize - index) << 1);
+                }
+            } else {
+                if (index < nsize) {
+                    if (DEBUG) System.out.println(TAG + " remove: move " + (index+1) + "-" + nsize
+                            + " to " + index);
+                    System.arraycopy(mHashes, index + 1, mHashes, index, nsize - index);
+                    System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1,
+                            (nsize - index) << 1);
+                }
+                mArray[nsize << 1] = null;
+                mArray[(nsize << 1) + 1] = null;
+            }
+        }
+        if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
+            throw new ConcurrentModificationException();
+        }
+        mSize = nsize;
+        return (V)old;
+    }
+
+    /**
+     * Return the number of items in this array map.
+     */
+    public int size() {
+        return mSize;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation returns false if the object is not a Map or
+     * SimpleArrayMap, or if the maps have different sizes. Otherwise, for each
+     * key in this map, values of both maps are compared. If the values for any
+     * key are not equal, the method returns false, otherwise it returns true.
+     */
+    @Override
+    public boolean equals(Object object) {
+        if (this == object) {
+            return true;
+        }
+        if (object instanceof SimpleArrayMap) {
+            SimpleArrayMap<?, ?> map = (SimpleArrayMap<?, ?>) object;
+            if (size() != map.size()) {
+                return false;
+            }
+
+            try {
+                for (int i=0; i<mSize; i++) {
+                    K key = keyAt(i);
+                    V mine = valueAt(i);
+                    Object theirs = map.get(key);
+                    if (mine == null) {
+                        if (theirs != null || !map.containsKey(key)) {
+                            return false;
+                        }
+                    } else if (!mine.equals(theirs)) {
+                        return false;
+                    }
+                }
+            } catch (NullPointerException ignored) {
+                return false;
+            } catch (ClassCastException ignored) {
+                return false;
+            }
+            return true;
+        } else if (object instanceof Map) {
+            Map<?, ?> map = (Map<?, ?>) object;
+            if (size() != map.size()) {
+                return false;
+            }
+
+            try {
+                for (int i=0; i<mSize; i++) {
+                    K key = keyAt(i);
+                    V mine = valueAt(i);
+                    Object theirs = map.get(key);
+                    if (mine == null) {
+                        if (theirs != null || !map.containsKey(key)) {
+                            return false;
+                        }
+                    } else if (!mine.equals(theirs)) {
+                        return false;
+                    }
+                }
+            } catch (NullPointerException ignored) {
+                return false;
+            } catch (ClassCastException ignored) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        final int[] hashes = mHashes;
+        final Object[] array = mArray;
+        int result = 0;
+        for (int i = 0, v = 1, s = mSize; i < s; i++, v+=2) {
+            Object value = array[v];
+            result += hashes[i] ^ (value == null ? 0 : value.hashCode());
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings. If
+     * this map contains itself as a key or a value, the string "(this Map)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (isEmpty()) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            Object key = keyAt(i);
+            if (key != this) {
+                buffer.append(key);
+            } else {
+                buffer.append("(this Map)");
+            }
+            buffer.append('=');
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Map)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+}
diff --git a/collections/src/main/java/android/support/v4/util/SparseArrayCompat.java b/collections/src/main/java/android/support/v4/util/SparseArrayCompat.java
new file mode 100644
index 0000000..eece9b5
--- /dev/null
+++ b/collections/src/main/java/android/support/v4/util/SparseArrayCompat.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+/**
+ * SparseArrays map integers to Objects.  Unlike a normal array of Objects,
+ * there can be gaps in the indices.  It is intended to be more memory efficient
+ * than using a HashMap to map Integers to Objects, both because it avoids
+ * auto-boxing keys and its data structure doesn't rely on an extra entry object
+ * for each mapping.
+ *
+ * <p>Note that this container keeps its mappings in an array data structure,
+ * using a binary search to find keys.  The implementation is not intended to be appropriate for
+ * data structures
+ * that may contain large numbers of items.  It is generally slower than a traditional
+ * HashMap, since lookups require a binary search and adds and removes require inserting
+ * and deleting entries in the array.  For containers holding up to hundreds of items,
+ * the performance difference is not significant, less than 50%.</p>
+ *
+ * <p>To help with performance, the container includes an optimization when removing
+ * keys: instead of compacting its array immediately, it leaves the removed entry marked
+ * as deleted.  The entry can then be re-used for the same key, or compacted later in
+ * a single garbage collection step of all removed entries.  This garbage collection will
+ * need to be performed at any time the array needs to be grown or the the map size or
+ * entry values are retrieved.</p>
+ *
+ * <p>It is possible to iterate over the items in this container using
+ * {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
+ * <code>keyAt(int)</code> with ascending values of the index will return the
+ * keys in ascending order, or the values corresponding to the keys in ascending
+ * order in the case of <code>valueAt(int)</code>.</p>
+ */
+public class SparseArrayCompat<E> implements Cloneable {
+    private static final Object DELETED = new Object();
+    private boolean mGarbage = false;
+
+    private int[] mKeys;
+    private Object[] mValues;
+    private int mSize;
+
+    /**
+     * Creates a new SparseArray containing no mappings.
+     */
+    public SparseArrayCompat() {
+        this(10);
+    }
+
+    /**
+     * Creates a new SparseArray containing no mappings that will not
+     * require any additional memory allocation to store the specified
+     * number of mappings.  If you supply an initial capacity of 0, the
+     * sparse array will be initialized with a light-weight representation
+     * not requiring any additional array allocations.
+     */
+    public SparseArrayCompat(int initialCapacity) {
+        if (initialCapacity == 0) {
+            mKeys =  ContainerHelpers.EMPTY_INTS;
+            mValues =  ContainerHelpers.EMPTY_OBJECTS;
+        } else {
+            initialCapacity =  ContainerHelpers.idealIntArraySize(initialCapacity);
+            mKeys = new int[initialCapacity];
+            mValues = new Object[initialCapacity];
+        }
+        mSize = 0;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public SparseArrayCompat<E> clone() {
+        SparseArrayCompat<E> clone = null;
+        try {
+            clone = (SparseArrayCompat<E>) super.clone();
+            clone.mKeys = mKeys.clone();
+            clone.mValues = mValues.clone();
+        } catch (CloneNotSupportedException cnse) {
+            /* ignore */
+        }
+        return clone;
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or <code>null</code>
+     * if no such mapping has been made.
+     */
+    public E get(int key) {
+        return get(key, null);
+    }
+
+    /**
+     * Gets the Object mapped from the specified key, or the specified Object
+     * if no such mapping has been made.
+     */
+    @SuppressWarnings("unchecked")
+    public E get(int key, E valueIfKeyNotFound) {
+        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i < 0 || mValues[i] == DELETED) {
+            return valueIfKeyNotFound;
+        } else {
+            return (E) mValues[i];
+        }
+    }
+
+    /**
+     * Removes the mapping from the specified key, if there was any.
+     */
+    public void delete(int key) {
+        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i >= 0) {
+            if (mValues[i] != DELETED) {
+                mValues[i] = DELETED;
+                mGarbage = true;
+            }
+        }
+    }
+
+    /**
+     * Alias for {@link #delete(int)}.
+     */
+    public void remove(int key) {
+        delete(key);
+    }
+
+    /**
+     * Removes the mapping at the specified index.
+     */
+    public void removeAt(int index) {
+        if (mValues[index] != DELETED) {
+            mValues[index] = DELETED;
+            mGarbage = true;
+        }
+    }
+
+    /**
+     * Remove a range of mappings as a batch.
+     *
+     * @param index Index to begin at
+     * @param size Number of mappings to remove
+     */
+    public void removeAtRange(int index, int size) {
+        final int end = Math.min(mSize, index + size);
+        for (int i = index; i < end; i++) {
+            removeAt(i);
+        }
+    }
+
+    private void gc() {
+        // Log.e("SparseArray", "gc start with " + mSize);
+
+        int n = mSize;
+        int o = 0;
+        int[] keys = mKeys;
+        Object[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            Object val = values[i];
+
+            if (val != DELETED) {
+                if (i != o) {
+                    keys[o] = keys[i];
+                    values[o] = val;
+                    values[i] = null;
+                }
+
+                o++;
+            }
+        }
+
+        mGarbage = false;
+        mSize = o;
+
+        // Log.e("SparseArray", "gc end with " + mSize);
+    }
+
+    /**
+     * Adds a mapping from the specified key to the specified value,
+     * replacing the previous mapping from the specified key if there
+     * was one.
+     */
+    public void put(int key, E value) {
+        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);
+
+        if (i >= 0) {
+            mValues[i] = value;
+        } else {
+            i = ~i;
+
+            if (i < mSize && mValues[i] == DELETED) {
+                mKeys[i] = key;
+                mValues[i] = value;
+                return;
+            }
+
+            if (mGarbage && mSize >= mKeys.length) {
+                gc();
+
+                // Search again because indices may have changed.
+                i = ~ ContainerHelpers.binarySearch(mKeys, mSize, key);
+            }
+
+            if (mSize >= mKeys.length) {
+                int n =  ContainerHelpers.idealIntArraySize(mSize + 1);
+
+                int[] nkeys = new int[n];
+                Object[] nvalues = new Object[n];
+
+                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+                mKeys = nkeys;
+                mValues = nvalues;
+            }
+
+            if (mSize - i != 0) {
+                // Log.e("SparseArray", "move " + (mSize - i));
+                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+            }
+
+            mKeys[i] = key;
+            mValues[i] = value;
+            mSize++;
+        }
+    }
+
+    /**
+     * Returns the number of key-value mappings that this SparseArray
+     * currently stores.
+     */
+    public int size() {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mSize;
+    }
+
+    /**
+     * Return true if size() is 0.
+     * @return true if size() is 0.
+     */
+    public boolean isEmpty() {
+        return size() == 0;
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the key from the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public int keyAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return mKeys[index];
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns
+     * the value from the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    @SuppressWarnings("unchecked")
+    public E valueAt(int index) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return (E) mValues[index];
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, sets a new
+     * value for the <code>index</code>th key-value mapping that this
+     * SparseArray stores.
+     */
+    public void setValueAt(int index, E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        mValues[index] = value;
+    }
+
+    /**
+     * Returns the index for which {@link #keyAt} would return the
+     * specified key, or a negative number if the specified
+     * key is not mapped.
+     */
+    public int indexOfKey(int key) {
+        if (mGarbage) {
+            gc();
+        }
+
+        return  ContainerHelpers.binarySearch(mKeys, mSize, key);
+    }
+
+    /**
+     * Returns an index for which {@link #valueAt} would return the
+     * specified key, or a negative number if no keys map to the
+     * specified value.
+     * <p>Beware that this is a linear search, unlike lookups by key,
+     * and that multiple keys can map to the same value and this will
+     * find only one of them.
+     * <p>Note also that unlike most collections' {@code indexOf} methods,
+     * this method compares values using {@code ==} rather than {@code equals}.
+     */
+    public int indexOfValue(E value) {
+        if (mGarbage) {
+            gc();
+        }
+
+        for (int i = 0; i < mSize; i++)
+            if (mValues[i] == value)
+                return i;
+
+        return -1;
+    }
+
+    /**
+     * Removes all key-value mappings from this SparseArray.
+     */
+    public void clear() {
+        int n = mSize;
+        Object[] values = mValues;
+
+        for (int i = 0; i < n; i++) {
+            values[i] = null;
+        }
+
+        mSize = 0;
+        mGarbage = false;
+    }
+
+    /**
+     * Puts a key/value pair into the array, optimizing for the case where
+     * the key is greater than all existing keys in the array.
+     */
+    public void append(int key, E value) {
+        if (mSize != 0 && key <= mKeys[mSize - 1]) {
+            put(key, value);
+            return;
+        }
+
+        if (mGarbage && mSize >= mKeys.length) {
+            gc();
+        }
+
+        int pos = mSize;
+        if (pos >= mKeys.length) {
+            int n =  ContainerHelpers.idealIntArraySize(pos + 1);
+
+            int[] nkeys = new int[n];
+            Object[] nvalues = new Object[n];
+
+            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+            mKeys = nkeys;
+            mValues = nvalues;
+        }
+
+        mKeys[pos] = key;
+        mValues[pos] = value;
+        mSize = pos + 1;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation composes a string by iterating over its mappings. If
+     * this map contains itself as a value, the string "(this Map)"
+     * will appear in its place.
+     */
+    @Override
+    public String toString() {
+        if (size() <= 0) {
+            return "{}";
+        }
+
+        StringBuilder buffer = new StringBuilder(mSize * 28);
+        buffer.append('{');
+        for (int i=0; i<mSize; i++) {
+            if (i > 0) {
+                buffer.append(", ");
+            }
+            int key = keyAt(i);
+            buffer.append(key);
+            buffer.append('=');
+            Object value = valueAt(i);
+            if (value != this) {
+                buffer.append(value);
+            } else {
+                buffer.append("(this Map)");
+            }
+        }
+        buffer.append('}');
+        return buffer.toString();
+    }
+}
diff --git a/collections/src/test/java/android/support/v4/util/ArrayMapCompatTest.java b/collections/src/test/java/android/support/v4/util/ArrayMapCompatTest.java
new file mode 100644
index 0000000..add6ba5
--- /dev/null
+++ b/collections/src/test/java/android/support/v4/util/ArrayMapCompatTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+public class ArrayMapCompatTest {
+
+    @Test
+    public void testCanNotIteratePastEnd_entrySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<Map.Entry<String, String>> expectedEntriesToIterate = new HashSet<>(Arrays.asList(
+                entryOf("key 1", "value 1"),
+                entryOf("key 2", "value 2")
+        ));
+        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
+
+        // Assert iteration over the expected two entries in any order
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> firstEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(firstEntry));
+
+        assertTrue(iterator.hasNext());
+        Map.Entry<String, String> secondEntry = copyOf(iterator.next());
+        assertTrue(expectedEntriesToIterate.remove(secondEntry));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    private static <K, V> Map.Entry<K, V> entryOf(K key, V value) {
+        return new AbstractMap.SimpleEntry<>(key, value);
+    }
+
+    private static <K, V> Map.Entry<K, V> copyOf(Map.Entry<K, V> entry) {
+        return entryOf(entry.getKey(), entry.getValue());
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_keySetIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedKeysToIterate = new HashSet<>(Arrays.asList("key 1", "key 2"));
+        Iterator<String> iterator = map.keySet().iterator();
+
+        // Assert iteration over the expected two keys in any order
+        assertTrue(iterator.hasNext());
+        String firstKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(firstKey));
+
+        assertTrue(iterator.hasNext());
+        String secondKey = iterator.next();
+        assertTrue(expectedKeysToIterate.remove(secondKey));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+
+    @Test
+    public void testCanNotIteratePastEnd_valuesIterator() {
+        Map<String, String> map = new ArrayMap<>();
+        map.put("key 1", "value 1");
+        map.put("key 2", "value 2");
+        Set<String> expectedValuesToIterate = new HashSet<>(Arrays.asList("value 1", "value 2"));
+        Iterator<String> iterator = map.values().iterator();
+
+        // Assert iteration over the expected two values in any order
+        assertTrue(iterator.hasNext());
+        String firstValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(firstValue));
+
+        assertTrue(iterator.hasNext());
+        String secondValue = iterator.next();
+        assertTrue(expectedValuesToIterate.remove(secondValue));
+
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+}
diff --git a/collections/src/test/java/android/support/v4/util/ArraySetCompatTest.java b/collections/src/test/java/android/support/v4/util/ArraySetCompatTest.java
new file mode 100644
index 0000000..a0e74e9
--- /dev/null
+++ b/collections/src/test/java/android/support/v4/util/ArraySetCompatTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public class ArraySetCompatTest {
+    @Test
+    public void testCanNotIteratePastEnd() {
+        ArraySet<String> set = new ArraySet<>();
+        set.add("value");
+        Iterator<String> iterator = set.iterator();
+
+        assertTrue(iterator.hasNext());
+        assertEquals("value", iterator.next());
+        assertFalse(iterator.hasNext());
+
+        try {
+            iterator.next();
+            fail();
+        } catch (NoSuchElementException expected) {
+        }
+    }
+}
diff --git a/collections/src/test/java/android/support/v4/util/LongSparseArrayTest.java b/collections/src/test/java/android/support/v4/util/LongSparseArrayTest.java
new file mode 100644
index 0000000..0276e14
--- /dev/null
+++ b/collections/src/test/java/android/support/v4/util/LongSparseArrayTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class LongSparseArrayTest {
+    @Test
+    public void isEmpty() throws Exception {
+        LongSparseArray<String> LongSparseArray = new LongSparseArray<>();
+        assertTrue(LongSparseArray.isEmpty()); // Newly created LongSparseArray should be empty
+
+        // Adding elements should change state from empty to not empty.
+        for (long i = 0L; i < 5L; i++) {
+            LongSparseArray.put(i, Long.toString(i));
+            assertFalse(LongSparseArray.isEmpty());
+        }
+        LongSparseArray.clear();
+        assertTrue(LongSparseArray.isEmpty()); // A cleared LongSparseArray should be empty.
+
+
+        long key1 = 1L, key2 = 2L;
+        String value1 = "some value", value2 = "some other value";
+        LongSparseArray.append(key1, value1);
+        assertFalse(LongSparseArray.isEmpty()); // has 1 element.
+        LongSparseArray.append(key2, value2);
+        assertFalse(LongSparseArray.isEmpty());  // has 2 elements.
+        assertFalse(LongSparseArray.isEmpty());  // consecutive calls should be OK.
+
+        LongSparseArray.remove(key1);
+        assertFalse(LongSparseArray.isEmpty()); // has 1 element.
+        LongSparseArray.remove(key2);
+        assertTrue(LongSparseArray.isEmpty());
+    }
+
+}
diff --git a/collections/src/test/java/android/support/v4/util/SimpleArrayMapTest.java b/collections/src/test/java/android/support/v4/util/SimpleArrayMapTest.java
new file mode 100644
index 0000000..3c2bea1
--- /dev/null
+++ b/collections/src/test/java/android/support/v4/util/SimpleArrayMapTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package android.support.v4.util;
+
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+import java.util.ConcurrentModificationException;
+import java.util.Locale;
+
+/**
+ * Unit tests for SimpleArrayMap
+ */
+public class SimpleArrayMapTest {
+    SimpleArrayMap<String, String> map = new SimpleArrayMap<>();
+    private boolean mDone;
+
+    /**
+     * Attempt to generate a ConcurrentModificationException in ArrayMap.
+     */
+    @Test
+    public void testConcurrentModificationException() throws Exception {
+        final int TEST_LEN_MS = 5000;
+        System.out.println("Starting SimpleArrayMap concurrency test");
+        mDone = false;
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                int i = 0;
+                while (!mDone) {
+                    try {
+                        map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT");
+                    } catch (ArrayIndexOutOfBoundsException e) {
+                        // SimpleArrayMap is not thread safe, so lots of concurrent modifications
+                        // can still cause data corruption
+                        System.err.println("concurrent modification uncaught, causing indexing failure");
+                        e.printStackTrace();
+                    } catch (ClassCastException e) {
+                        // cache corruption should not occur as it is hard to trace and one thread
+                        // may corrupt the pool for all threads in the same process.
+                        System.err.println("concurrent modification uncaught, causing cache corruption");
+                        e.printStackTrace();
+                        fail();
+                    } catch (ConcurrentModificationException e) {
+                    }
+                }
+            }
+        }).start();
+        for (int i = 0; i < (TEST_LEN_MS / 100); i++) {
+            try {
+                Thread.sleep(100);
+                map.clear();
+            } catch (InterruptedException e) {
+            } catch (ArrayIndexOutOfBoundsException e) {
+                System.err.println("concurrent modification uncaught, causing indexing failure");
+            } catch (ClassCastException e) {
+                System.err.println("concurrent modification uncaught, causing cache corruption");
+                fail();
+            } catch (ConcurrentModificationException e) {
+            }
+        }
+        mDone = true;
+    }
+
+    /**
+     * Check to make sure the same operations behave as expected in a single thread.
+     */
+    @Test
+    public void testNonConcurrentAccesses() throws Exception {
+        for (int i = 0; i < 100000; i++) {
+            try {
+                map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT");
+                if (i % 500 == 0) {
+                    map.clear();
+                }
+            } catch (ConcurrentModificationException e) {
+                System.err.println("Concurrent modification caught on single thread");
+                e.printStackTrace();
+                fail();
+            }
+        }
+    }
+}
diff --git a/collections/src/test/java/android/support/v4/util/SparseArrayCompatTest.java b/collections/src/test/java/android/support/v4/util/SparseArrayCompatTest.java
new file mode 100644
index 0000000..afe58ae
--- /dev/null
+++ b/collections/src/test/java/android/support/v4/util/SparseArrayCompatTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.util;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class SparseArrayCompatTest {
+    @Test
+    public void isEmpty() throws Exception {
+        SparseArrayCompat<String> sparseArrayCompat = new SparseArrayCompat<>();
+        assertTrue(sparseArrayCompat.isEmpty()); // Newly created SparseArrayCompat should be empty
+
+        // Adding elements should change state from empty to not empty.
+        for (int i = 0; i < 5; i++) {
+            sparseArrayCompat.put(i, Integer.toString(i));
+            assertFalse(sparseArrayCompat.isEmpty());
+        }
+        sparseArrayCompat.clear();
+        assertTrue(sparseArrayCompat.isEmpty()); // A cleared SparseArrayCompat should be empty.
+
+
+        int key1 = 1, key2 = 2;
+        String value1 = "some value", value2 = "some other value";
+        sparseArrayCompat.append(key1, value1);
+        assertFalse(sparseArrayCompat.isEmpty()); // has 1 element.
+        sparseArrayCompat.append(key2, value2);
+        assertFalse(sparseArrayCompat.isEmpty());  // has 2 elements.
+        assertFalse(sparseArrayCompat.isEmpty());  // consecutive calls should be OK.
+
+        sparseArrayCompat.remove(key1);
+        assertFalse(sparseArrayCompat.isEmpty()); // has 1 element.
+        sparseArrayCompat.remove(key2);
+        assertTrue(sparseArrayCompat.isEmpty());
+    }
+}
diff --git a/compat/Android.mk b/compat/Android.mk
deleted file mode 100644
index 720a1eb..0000000
--- a/compat/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-compat
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-compat
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src/main/java
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,src/main/java) \
-    $(call all-Iaidl-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    apptoolkit-arch-core-common \
-    apptoolkit-lifecycle-common \
-    apptoolkit-lifecycle-runtime
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/compat/AndroidManifest.xml b/compat/AndroidManifest.xml
deleted file mode 100644
index 5525c41..0000000
--- a/compat/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.compat">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/compat/api/27.1.0.ignore b/compat/api/27.1.0.ignore
new file mode 100644
index 0000000..e8c272c
--- /dev/null
+++ b/compat/api/27.1.0.ignore
@@ -0,0 +1,10 @@
+44c2c3c
+fbe2c76
+e51f961
+c851773
+34f4ba1
+9fad272
+43b0030
+81879f6
+343d890
+483ac6a
diff --git a/compat/api/current.txt b/compat/api/current.txt
index 81a85b8..006316b 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -33,7 +33,7 @@
     ctor public InputConnectionCompat();
     method public static boolean commitContent(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputContentInfoCompat, int, android.os.Bundle);
     method public static android.view.inputmethod.InputConnection createWrapper(android.view.inputmethod.InputConnection, android.view.inputmethod.EditorInfo, android.support.v13.view.inputmethod.InputConnectionCompat.OnCommitContentListener);
-    field public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
+    field public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 1; // 0x1
   }
 
   public static abstract interface InputConnectionCompat.OnCommitContentListener {
@@ -136,6 +136,12 @@
     method public static void setExactAndAllowWhileIdle(android.app.AlarmManager, int, long, android.app.PendingIntent);
   }
 
+  public class AppLaunchChecker {
+    ctor public AppLaunchChecker();
+    method public static boolean hasStartedFromLauncher(android.content.Context);
+    method public static void onActivityCreate(android.app.Activity);
+  }
+
   public final class AppOpsManagerCompat {
     method public static int noteOp(android.content.Context, java.lang.String, int, java.lang.String);
     method public static int noteOpNoThrow(android.content.Context, java.lang.String, int, java.lang.String);
@@ -153,6 +159,35 @@
     method public static void putBinder(android.os.Bundle, java.lang.String, android.os.IBinder);
   }
 
+  public class FrameMetricsAggregator {
+    ctor public FrameMetricsAggregator();
+    ctor public FrameMetricsAggregator(int);
+    method public void add(android.app.Activity);
+    method public android.util.SparseIntArray[] getMetrics();
+    method public android.util.SparseIntArray[] remove(android.app.Activity);
+    method public android.util.SparseIntArray[] reset();
+    method public android.util.SparseIntArray[] stop();
+    field public static final int ANIMATION_DURATION = 256; // 0x100
+    field public static final int ANIMATION_INDEX = 8; // 0x8
+    field public static final int COMMAND_DURATION = 32; // 0x20
+    field public static final int COMMAND_INDEX = 5; // 0x5
+    field public static final int DELAY_DURATION = 128; // 0x80
+    field public static final int DELAY_INDEX = 7; // 0x7
+    field public static final int DRAW_DURATION = 8; // 0x8
+    field public static final int DRAW_INDEX = 3; // 0x3
+    field public static final int EVERY_DURATION = 511; // 0x1ff
+    field public static final int INPUT_DURATION = 2; // 0x2
+    field public static final int INPUT_INDEX = 1; // 0x1
+    field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
+    field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
+    field public static final int SWAP_DURATION = 64; // 0x40
+    field public static final int SWAP_INDEX = 6; // 0x6
+    field public static final int SYNC_DURATION = 16; // 0x10
+    field public static final int SYNC_INDEX = 4; // 0x4
+    field public static final int TOTAL_DURATION = 1; // 0x1
+    field public static final int TOTAL_INDEX = 0; // 0x0
+  }
+
   public abstract class JobIntentService extends android.app.Service {
     ctor public JobIntentService();
     method public static void enqueueWork(android.content.Context, java.lang.Class, int, android.content.Intent);
@@ -164,6 +199,18 @@
     method public void setInterruptIfStopped(boolean);
   }
 
+  public final class NavUtils {
+    method public static android.content.Intent getParentActivityIntent(android.app.Activity);
+    method public static android.content.Intent getParentActivityIntent(android.content.Context, java.lang.Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static android.content.Intent getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static java.lang.String getParentActivityName(android.app.Activity);
+    method public static java.lang.String getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public static void navigateUpFromSameTask(android.app.Activity);
+    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
+    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
+    field public static final java.lang.String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
+  }
+
   public class NotificationCompat {
     ctor public NotificationCompat();
     method public static android.support.v4.app.NotificationCompat.Action getAction(android.app.Notification, int);
@@ -174,6 +221,7 @@
     method public static android.os.Bundle getExtras(android.app.Notification);
     method public static java.lang.String getGroup(android.app.Notification);
     method public static int getGroupAlertBehavior(android.app.Notification);
+    method public static java.util.List<android.support.v4.app.NotificationCompat.Action> getInvisibleActions(android.app.Notification);
     method public static boolean getLocalOnly(android.app.Notification);
     method public static java.lang.String getShortcutId(android.app.Notification);
     method public static java.lang.String getSortKey(android.app.Notification);
@@ -208,6 +256,7 @@
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
     field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
     field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
+    field public static final java.lang.String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
     field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
     field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
     field public static final java.lang.String EXTRA_MEDIA_SESSION = "android.mediaSession";
@@ -261,7 +310,20 @@
     method public android.os.Bundle getExtras();
     method public int getIcon();
     method public android.support.v4.app.RemoteInput[] getRemoteInputs();
+    method public int getSemanticAction();
+    method public boolean getShowsUserInterface();
     method public java.lang.CharSequence getTitle();
+    field public static final int SEMANTIC_ACTION_ARCHIVE = 5; // 0x5
+    field public static final int SEMANTIC_ACTION_CALL = 10; // 0xa
+    field public static final int SEMANTIC_ACTION_DELETE = 4; // 0x4
+    field public static final int SEMANTIC_ACTION_MARK_AS_READ = 2; // 0x2
+    field public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3; // 0x3
+    field public static final int SEMANTIC_ACTION_MUTE = 6; // 0x6
+    field public static final int SEMANTIC_ACTION_NONE = 0; // 0x0
+    field public static final int SEMANTIC_ACTION_REPLY = 1; // 0x1
+    field public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9; // 0x9
+    field public static final int SEMANTIC_ACTION_THUMBS_UP = 8; // 0x8
+    field public static final int SEMANTIC_ACTION_UNMUTE = 7; // 0x7
     field public android.app.PendingIntent actionIntent;
     field public int icon;
     field public java.lang.CharSequence title;
@@ -276,12 +338,17 @@
     method public android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Extender);
     method public android.os.Bundle getExtras();
     method public android.support.v4.app.NotificationCompat.Action.Builder setAllowGeneratedReplies(boolean);
+    method public android.support.v4.app.NotificationCompat.Action.Builder setSemanticAction(int);
+    method public android.support.v4.app.NotificationCompat.Action.Builder setShowsUserInterface(boolean);
   }
 
   public static abstract interface NotificationCompat.Action.Extender {
     method public abstract android.support.v4.app.NotificationCompat.Action.Builder extend(android.support.v4.app.NotificationCompat.Action.Builder);
   }
 
+  public static abstract class NotificationCompat.Action.SemanticAction implements java.lang.annotation.Annotation {
+  }
+
   public static final class NotificationCompat.Action.WearableExtender implements android.support.v4.app.NotificationCompat.Action.Extender {
     ctor public NotificationCompat.Action.WearableExtender();
     ctor public NotificationCompat.Action.WearableExtender(android.support.v4.app.NotificationCompat.Action);
@@ -324,6 +391,8 @@
     method public android.support.v4.app.NotificationCompat.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
     method public android.support.v4.app.NotificationCompat.Builder addAction(android.support.v4.app.NotificationCompat.Action);
     method public android.support.v4.app.NotificationCompat.Builder addExtras(android.os.Bundle);
+    method public android.support.v4.app.NotificationCompat.Builder addInvisibleAction(int, java.lang.CharSequence, android.app.PendingIntent);
+    method public android.support.v4.app.NotificationCompat.Builder addInvisibleAction(android.support.v4.app.NotificationCompat.Action);
     method public android.support.v4.app.NotificationCompat.Builder addPerson(java.lang.String);
     method public android.app.Notification build();
     method public android.support.v4.app.NotificationCompat.Builder extend(android.support.v4.app.NotificationCompat.Extender);
@@ -436,7 +505,9 @@
     method public java.lang.CharSequence getConversationTitle();
     method public java.util.List<android.support.v4.app.NotificationCompat.MessagingStyle.Message> getMessages();
     method public java.lang.CharSequence getUserDisplayName();
+    method public boolean isGroupConversation();
     method public android.support.v4.app.NotificationCompat.MessagingStyle setConversationTitle(java.lang.CharSequence);
+    method public android.support.v4.app.NotificationCompat.MessagingStyle setGroupConversation(boolean);
     field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
   }
 
@@ -659,6 +730,29 @@
     method public abstract void onSharedElementsReady();
   }
 
+  public final class TaskStackBuilder implements java.lang.Iterable {
+    method public android.support.v4.app.TaskStackBuilder addNextIntent(android.content.Intent);
+    method public android.support.v4.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(android.app.Activity);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(java.lang.Class<?>);
+    method public android.support.v4.app.TaskStackBuilder addParentStack(android.content.ComponentName);
+    method public static android.support.v4.app.TaskStackBuilder create(android.content.Context);
+    method public android.content.Intent editIntentAt(int);
+    method public static deprecated android.support.v4.app.TaskStackBuilder from(android.content.Context);
+    method public deprecated android.content.Intent getIntent(int);
+    method public int getIntentCount();
+    method public android.content.Intent[] getIntents();
+    method public android.app.PendingIntent getPendingIntent(int, int);
+    method public android.app.PendingIntent getPendingIntent(int, int, android.os.Bundle);
+    method public deprecated java.util.Iterator<android.content.Intent> iterator();
+    method public void startActivities();
+    method public void startActivities(android.os.Bundle);
+  }
+
+  public static abstract interface TaskStackBuilder.SupportParentable {
+    method public abstract android.content.Intent getSupportParentActivityIntent();
+  }
+
 }
 
 package android.support.v4.content {
@@ -687,6 +781,17 @@
     method public static void startForegroundService(android.content.Context, android.content.Intent);
   }
 
+  public class FileProvider extends android.content.ContentProvider {
+    ctor public FileProvider();
+    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
+    method public java.lang.String getType(android.net.Uri);
+    method public static android.net.Uri getUriForFile(android.content.Context, java.lang.String, java.io.File);
+    method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
+    method public boolean onCreate();
+    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
+  }
+
   public final class IntentCompat {
     method public static android.content.Intent makeMainSelectorActivity(java.lang.String, java.lang.String);
     field public static final java.lang.String CATEGORY_LEANBACK_LAUNCHER = "android.intent.category.LEANBACK_LAUNCHER";
@@ -694,6 +799,23 @@
     field public static final java.lang.String EXTRA_START_PLAYBACK = "android.intent.extra.START_PLAYBACK";
   }
 
+  public final class MimeTypeFilter {
+    method public static boolean matches(java.lang.String, java.lang.String);
+    method public static java.lang.String matches(java.lang.String, java.lang.String[]);
+    method public static java.lang.String matches(java.lang.String[], java.lang.String);
+    method public static java.lang.String[] matchesMany(java.lang.String[], java.lang.String);
+  }
+
+  public final class PermissionChecker {
+    method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
+    method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
+    method public static int checkPermission(android.content.Context, java.lang.String, int, int, java.lang.String);
+    method public static int checkSelfPermission(android.content.Context, java.lang.String);
+    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
+    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
+    field public static final int PERMISSION_GRANTED = 0; // 0x0
+  }
+
   public final deprecated class SharedPreferencesCompat {
   }
 
@@ -782,6 +904,29 @@
     method public static void setHasMipMap(android.graphics.Bitmap, boolean);
   }
 
+  public final class ColorUtils {
+    method public static int HSLToColor(float[]);
+    method public static int LABToColor(double, double, double);
+    method public static void LABToXYZ(double, double, double, double[]);
+    method public static void RGBToHSL(int, int, int, float[]);
+    method public static void RGBToLAB(int, int, int, double[]);
+    method public static void RGBToXYZ(int, int, int, double[]);
+    method public static int XYZToColor(double, double, double);
+    method public static void XYZToLAB(double, double, double, double[]);
+    method public static int blendARGB(int, int, float);
+    method public static void blendHSL(float[], float[], float, float[]);
+    method public static void blendLAB(double[], double[], double, double[]);
+    method public static double calculateContrast(int, int);
+    method public static double calculateLuminance(int);
+    method public static int calculateMinimumAlpha(int, int, float);
+    method public static void colorToHSL(int, float[]);
+    method public static void colorToLAB(int, double[]);
+    method public static void colorToXYZ(int, double[]);
+    method public static int compositeColors(int, int);
+    method public static double distanceEuclidean(double[], double[]);
+    method public static int setAlphaComponent(int, int);
+  }
+
   public final class PaintCompat {
     method public static boolean hasGlyph(android.graphics.Paint, java.lang.String);
   }
@@ -821,6 +966,35 @@
     method public android.graphics.drawable.Icon toIcon();
   }
 
+  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
+    method public void draw(android.graphics.Canvas);
+    method public final android.graphics.Bitmap getBitmap();
+    method public float getCornerRadius();
+    method public int getGravity();
+    method public int getOpacity();
+    method public final android.graphics.Paint getPaint();
+    method public boolean hasAntiAlias();
+    method public boolean hasMipMap();
+    method public boolean isCircular();
+    method public void setAlpha(int);
+    method public void setAntiAlias(boolean);
+    method public void setCircular(boolean);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setCornerRadius(float);
+    method public void setDither(boolean);
+    method public void setGravity(int);
+    method public void setMipMap(boolean);
+    method public void setTargetDensity(android.graphics.Canvas);
+    method public void setTargetDensity(android.util.DisplayMetrics);
+    method public void setTargetDensity(int);
+  }
+
+  public final class RoundedBitmapDrawableFactory {
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap);
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.lang.String);
+    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
+  }
+
 }
 
 package android.support.v4.hardware.display {
@@ -868,6 +1042,16 @@
 
 }
 
+package android.support.v4.math {
+
+  public class MathUtils {
+    method public static float clamp(float, float, float);
+    method public static double clamp(double, double, double);
+    method public static int clamp(int, int, int);
+  }
+
+}
+
 package android.support.v4.net {
 
   public final class ConnectivityManagerCompat {
@@ -1100,45 +1284,6 @@
 
 package android.support.v4.util {
 
-  public class ArrayMap<K, V> extends android.support.v4.util.SimpleArrayMap implements java.util.Map {
-    ctor public ArrayMap();
-    ctor public ArrayMap(int);
-    ctor public ArrayMap(android.support.v4.util.SimpleArrayMap);
-    method public boolean containsAll(java.util.Collection<?>);
-    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
-    method public java.util.Set<K> keySet();
-    method public void putAll(java.util.Map<? extends K, ? extends V>);
-    method public boolean removeAll(java.util.Collection<?>);
-    method public boolean retainAll(java.util.Collection<?>);
-    method public java.util.Collection<V> values();
-  }
-
-  public final class ArraySet<E> implements java.util.Collection java.util.Set {
-    ctor public ArraySet();
-    ctor public ArraySet(int);
-    ctor public ArraySet(android.support.v4.util.ArraySet<E>);
-    ctor public ArraySet(java.util.Collection<E>);
-    method public boolean add(E);
-    method public void addAll(android.support.v4.util.ArraySet<? extends E>);
-    method public boolean addAll(java.util.Collection<? extends E>);
-    method public void clear();
-    method public boolean contains(java.lang.Object);
-    method public boolean containsAll(java.util.Collection<?>);
-    method public void ensureCapacity(int);
-    method public int indexOf(java.lang.Object);
-    method public boolean isEmpty();
-    method public java.util.Iterator<E> iterator();
-    method public boolean remove(java.lang.Object);
-    method public boolean removeAll(android.support.v4.util.ArraySet<? extends E>);
-    method public boolean removeAll(java.util.Collection<?>);
-    method public E removeAt(int);
-    method public boolean retainAll(java.util.Collection<?>);
-    method public int size();
-    method public java.lang.Object[] toArray();
-    method public <T> T[] toArray(T[]);
-    method public E valueAt(int);
-  }
-
   public class AtomicFile {
     ctor public AtomicFile(java.io.File);
     method public void delete();
@@ -1150,82 +1295,6 @@
     method public java.io.FileOutputStream startWrite() throws java.io.IOException;
   }
 
-  public final class CircularArray<E> {
-    ctor public CircularArray();
-    ctor public CircularArray(int);
-    method public void addFirst(E);
-    method public void addLast(E);
-    method public void clear();
-    method public E get(int);
-    method public E getFirst();
-    method public E getLast();
-    method public boolean isEmpty();
-    method public E popFirst();
-    method public E popLast();
-    method public void removeFromEnd(int);
-    method public void removeFromStart(int);
-    method public int size();
-  }
-
-  public final class CircularIntArray {
-    ctor public CircularIntArray();
-    ctor public CircularIntArray(int);
-    method public void addFirst(int);
-    method public void addLast(int);
-    method public void clear();
-    method public int get(int);
-    method public int getFirst();
-    method public int getLast();
-    method public boolean isEmpty();
-    method public int popFirst();
-    method public int popLast();
-    method public void removeFromEnd(int);
-    method public void removeFromStart(int);
-    method public int size();
-  }
-
-  public class LongSparseArray<E> implements java.lang.Cloneable {
-    ctor public LongSparseArray();
-    ctor public LongSparseArray(int);
-    method public void append(long, E);
-    method public void clear();
-    method public android.support.v4.util.LongSparseArray<E> clone();
-    method public void delete(long);
-    method public E get(long);
-    method public E get(long, E);
-    method public int indexOfKey(long);
-    method public int indexOfValue(E);
-    method public long keyAt(int);
-    method public void put(long, E);
-    method public void remove(long);
-    method public void removeAt(int);
-    method public void setValueAt(int, E);
-    method public int size();
-    method public E valueAt(int);
-  }
-
-  public class LruCache<K, V> {
-    ctor public LruCache(int);
-    method protected V create(K);
-    method public final synchronized int createCount();
-    method protected void entryRemoved(boolean, K, V, V);
-    method public final void evictAll();
-    method public final synchronized int evictionCount();
-    method public final V get(K);
-    method public final synchronized int hitCount();
-    method public final synchronized int maxSize();
-    method public final synchronized int missCount();
-    method public final V put(K, V);
-    method public final synchronized int putCount();
-    method public final V remove(K);
-    method public void resize(int);
-    method public final synchronized int size();
-    method protected int sizeOf(K, V);
-    method public final synchronized java.util.Map<K, V> snapshot();
-    method public final synchronized java.lang.String toString();
-    method public void trimToSize(int);
-  }
-
   public class ObjectsCompat {
     method public static boolean equals(java.lang.Object, java.lang.Object);
     method public static int hash(java.lang.Object...);
@@ -1264,48 +1333,6 @@
     ctor public Pools.SynchronizedPool(int);
   }
 
-  public class SimpleArrayMap<K, V> {
-    ctor public SimpleArrayMap();
-    ctor public SimpleArrayMap(int);
-    ctor public SimpleArrayMap(android.support.v4.util.SimpleArrayMap<K, V>);
-    method public void clear();
-    method public boolean containsKey(java.lang.Object);
-    method public boolean containsValue(java.lang.Object);
-    method public void ensureCapacity(int);
-    method public V get(java.lang.Object);
-    method public int indexOfKey(java.lang.Object);
-    method public boolean isEmpty();
-    method public K keyAt(int);
-    method public V put(K, V);
-    method public void putAll(android.support.v4.util.SimpleArrayMap<? extends K, ? extends V>);
-    method public V remove(java.lang.Object);
-    method public V removeAt(int);
-    method public V setValueAt(int, V);
-    method public int size();
-    method public V valueAt(int);
-  }
-
-  public class SparseArrayCompat<E> implements java.lang.Cloneable {
-    ctor public SparseArrayCompat();
-    ctor public SparseArrayCompat(int);
-    method public void append(int, E);
-    method public void clear();
-    method public android.support.v4.util.SparseArrayCompat<E> clone();
-    method public void delete(int);
-    method public E get(int);
-    method public E get(int, E);
-    method public int indexOfKey(int);
-    method public int indexOfValue(E);
-    method public int keyAt(int);
-    method public void put(int, E);
-    method public void remove(int);
-    method public void removeAt(int);
-    method public void removeAtRange(int, int);
-    method public void setValueAt(int, E);
-    method public int size();
-    method public E valueAt(int);
-  }
-
 }
 
 package android.support.v4.view {
@@ -1407,6 +1434,7 @@
   }
 
   public final class MenuCompat {
+    method public static void setGroupDividerEnabled(android.view.Menu, boolean);
     method public static deprecated void setShowAsAction(android.view.MenuItem, int);
   }
 
@@ -1536,6 +1564,26 @@
     method public abstract void stopNestedScroll(int);
   }
 
+  public class NestedScrollingChildHelper {
+    ctor public NestedScrollingChildHelper(android.view.View);
+    method public boolean dispatchNestedFling(float, float, boolean);
+    method public boolean dispatchNestedPreFling(float, float);
+    method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
+    method public boolean dispatchNestedPreScroll(int, int, int[], int[], int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[]);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[], int);
+    method public boolean hasNestedScrollingParent();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean isNestedScrollingEnabled();
+    method public void onDetachedFromWindow();
+    method public void onStopNestedScroll(android.view.View);
+    method public void setNestedScrollingEnabled(boolean);
+    method public boolean startNestedScroll(int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll();
+    method public void stopNestedScroll(int);
+  }
+
   public abstract interface NestedScrollingParent {
     method public abstract int getNestedScrollAxes();
     method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
@@ -1555,6 +1603,15 @@
     method public abstract void onStopNestedScroll(android.view.View, int);
   }
 
+  public class NestedScrollingParentHelper {
+    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
+    method public int getNestedScrollAxes();
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View);
+    method public void onStopNestedScroll(android.view.View, int);
+  }
+
   public abstract interface OnApplyWindowInsetsListener {
     method public abstract android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.view.View, android.support.v4.view.WindowInsetsCompat);
   }
@@ -1797,6 +1854,7 @@
 
   public final class ViewConfigurationCompat {
     method public static float getScaledHorizontalScrollFactor(android.view.ViewConfiguration, android.content.Context);
+    method public static int getScaledHoverSlop(android.view.ViewConfiguration);
     method public static deprecated int getScaledPagingTouchSlop(android.view.ViewConfiguration);
     method public static float getScaledVerticalScrollFactor(android.view.ViewConfiguration, android.content.Context);
     method public static deprecated boolean hasPermanentMenuKey(android.view.ViewConfiguration);
@@ -2318,6 +2376,33 @@
 
 package android.support.v4.widget {
 
+  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
+    ctor public AutoScrollHelper(android.view.View);
+    method public abstract boolean canTargetScrollHorizontally(int);
+    method public abstract boolean canTargetScrollVertically(int);
+    method public boolean isEnabled();
+    method public boolean isExclusive();
+    method public boolean onTouch(android.view.View, android.view.MotionEvent);
+    method public abstract void scrollTargetBy(int, int);
+    method public android.support.v4.widget.AutoScrollHelper setActivationDelay(int);
+    method public android.support.v4.widget.AutoScrollHelper setEdgeType(int);
+    method public android.support.v4.widget.AutoScrollHelper setEnabled(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setExclusive(boolean);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMaximumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setMinimumVelocity(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRampDownDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRampUpDuration(int);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeEdges(float, float);
+    method public android.support.v4.widget.AutoScrollHelper setRelativeVelocity(float, float);
+    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
+    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
+    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
+    field public static final float NO_MAX = 3.4028235E38f;
+    field public static final float NO_MIN = 0.0f;
+    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
+  }
+
   public final class CompoundButtonCompat {
     method public static android.graphics.drawable.Drawable getButtonDrawable(android.widget.CompoundButton);
     method public static android.content.res.ColorStateList getButtonTintList(android.widget.CompoundButton);
@@ -2326,6 +2411,15 @@
     method public static void setButtonTintMode(android.widget.CompoundButton, android.graphics.PorterDuff.Mode);
   }
 
+  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
+    ctor public ContentLoadingProgressBar(android.content.Context);
+    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
+    method public synchronized void hide();
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public synchronized void show();
+  }
+
   public final class EdgeEffectCompat {
     ctor public deprecated EdgeEffectCompat(android.content.Context);
     method public deprecated boolean draw(android.graphics.Canvas);
@@ -2351,11 +2445,54 @@
     method public static android.view.View.OnTouchListener createDragToOpenListener(android.widget.ListPopupWindow, android.view.View);
   }
 
+  public class ListViewAutoScrollHelper extends android.support.v4.widget.AutoScrollHelper {
+    ctor public ListViewAutoScrollHelper(android.widget.ListView);
+    method public boolean canTargetScrollHorizontally(int);
+    method public boolean canTargetScrollVertically(int);
+    method public void scrollTargetBy(int, int);
+  }
+
   public final class ListViewCompat {
     method public static boolean canScrollList(android.widget.ListView, int);
     method public static void scrollListBy(android.widget.ListView, int);
   }
 
+  public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild2 android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
+    ctor public NestedScrollView(android.content.Context);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
+    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
+    method public boolean arrowScroll(int);
+    method public int computeHorizontalScrollExtent();
+    method public int computeHorizontalScrollOffset();
+    method public int computeHorizontalScrollRange();
+    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect);
+    method public int computeVerticalScrollExtent();
+    method public int computeVerticalScrollOffset();
+    method public int computeVerticalScrollRange();
+    method public boolean dispatchNestedPreScroll(int, int, int[], int[], int);
+    method public boolean dispatchNestedScroll(int, int, int, int, int[], int);
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fling(int);
+    method public boolean fullScroll(int);
+    method public int getMaxScrollAmount();
+    method public boolean hasNestedScrollingParent(int);
+    method public boolean isFillViewport();
+    method public boolean isSmoothScrollingEnabled();
+    method public void onAttachedToWindow();
+    method public boolean pageScroll(int);
+    method public void setFillViewport(boolean);
+    method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
+    method public void setSmoothScrollingEnabled(boolean);
+    method public final void smoothScrollBy(int, int);
+    method public final void smoothScrollTo(int, int);
+    method public boolean startNestedScroll(int, int);
+    method public void stopNestedScroll(int);
+  }
+
+  public static abstract interface NestedScrollView.OnScrollChangeListener {
+    method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
+  }
+
   public final class PopupMenuCompat {
     method public static android.view.View.OnTouchListener getDragToOpenListener(java.lang.Object);
   }
diff --git a/compat/build.gradle b/compat/build.gradle
index 8f44285..f52c5ff 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -8,6 +8,7 @@
 
 dependencies {
     api(project(":support-annotations"))
+    api(project(":collections"))
     api(ARCH_LIFECYCLE_RUNTIME, libs.exclude_annotations_transitive)
 
     androidTestImplementation(TEST_RUNNER)
@@ -21,7 +22,6 @@
 
 android {
     sourceSets {
-        main.aidl.srcDirs = ['src/main/java']
         main.res.srcDirs 'res', 'res-public'
     }
 
@@ -37,5 +37,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
-    legacySourceLocation = true
 }
diff --git a/compat/res-public/values/public_attrs.xml b/compat/res-public/values/public_attrs.xml
index e45f8c2..38d858e 100644
--- a/compat/res-public/values/public_attrs.xml
+++ b/compat/res-public/values/public_attrs.xml
@@ -26,4 +26,6 @@
      <public type="attr" name="fontStyle"/>
      <public type="attr" name="font"/>
      <public type="attr" name="fontWeight"/>
+     <public type="attr" name="fontVariationSettings"/>
+     <public type="attr" name="ttcIndex"/>
 </resources>
diff --git a/compat/res/values/attrs.xml b/compat/res/values/attrs.xml
index 04d7690..1a721a8 100644
--- a/compat/res/values/attrs.xml
+++ b/compat/res/values/attrs.xml
@@ -79,10 +79,19 @@
          common values are 400 for regular weight and 700 for bold weight. If unspecified, the value
          in the font's header tables will be used. -->
         <attr name="fontWeight" format="integer" />
-
+        <!-- The variation settings to be applied to the font. The string should be in the following
+         format: "'tag1' value1, 'tag2' value2, ...". If the default variation settings should be
+         used, or the font used does not support variation settings, this attribute needs not be
+         specified. -->
+        <attr name="fontVariationSettings" format="string" />
+        <!-- The index of the font in the tcc font file. If the font file referenced is not in the
+        tcc format, this attribute needs not be specified. -->
+        <attr name="ttcIndex" format="integer" />
         <!-- References to the framework attrs -->
         <attr name="android:fontStyle" />
         <attr name="android:font" />
         <attr name="android:fontWeight" />
+        <attr name="android:fontVariationSettings" />
+        <attr name="android:ttcIndex" />
     </declare-styleable>
 </resources>
diff --git a/compat/src/androidTest/AndroidManifest.xml b/compat/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..25ca7ef
--- /dev/null
+++ b/compat/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.compat.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <uses-permission android:name="android.permission.VIBRATE"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
+
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+
+    <application
+        android:supportsRtl="true"
+        android:theme="@style/TestActivityTheme">
+        <activity android:name="android.support.v4.widget.ListViewTestActivity"/>
+
+        <activity android:name="android.support.v4.widget.TextViewTestActivity"/>
+
+        <activity android:name="android.support.v4.view.VpaActivity"/>
+
+        <activity
+            android:name="android.support.v4.ThemedYellowActivity"
+            android:theme="@style/YellowTheme"/>
+
+        <activity android:name="android.support.v4.view.ViewCompatActivity"/>
+
+        <activity android:name="android.support.v4.app.TestSupportActivity"
+                  android:icon="@drawable/test_drawable_blue"/>
+
+        <activity android:name="android.support.v13.view.DragStartHelperTestActivity"/>
+
+        <activity android:name="android.support.v4.widget.ContentLoadingProgressBarActivity"/>
+
+        <activity android:name="android.support.v4.widget.TextViewTestActivity"/>
+        <activity android:name="android.support.v4.app.FrameMetricsActivity"/>
+        <activity android:name="android.support.v4.app.FrameMetricsSubActivity"/>
+
+        <provider
+            android:name="android.support.v4.content.FileProvider"
+            android:authorities="moocow"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/paths"/>
+        </provider>
+
+        <provider android:name="android.support.v4.provider.MockFontProvider"
+                  android:authorities="android.support.provider.fonts.font"
+                  android:exported="false"
+                  android:multiprocess="true"/>
+
+        <service android:name="android.support.v4.app.JobIntentServiceTest$TargetService"
+                 android:permission="android.permission.BIND_JOB_SERVICE"/>
+
+    </application>
+
+</manifest>
diff --git a/compat/tests/assets/fonts/large_a.ttf b/compat/src/androidTest/assets/fonts/large_a.ttf
similarity index 100%
rename from compat/tests/assets/fonts/large_a.ttf
rename to compat/src/androidTest/assets/fonts/large_a.ttf
Binary files differ
diff --git a/compat/tests/assets/fonts/large_a.ttx b/compat/src/androidTest/assets/fonts/large_a.ttx
similarity index 100%
rename from compat/tests/assets/fonts/large_a.ttx
rename to compat/src/androidTest/assets/fonts/large_a.ttx
diff --git a/compat/tests/assets/fonts/large_b.ttf b/compat/src/androidTest/assets/fonts/large_b.ttf
similarity index 100%
rename from compat/tests/assets/fonts/large_b.ttf
rename to compat/src/androidTest/assets/fonts/large_b.ttf
Binary files differ
diff --git a/compat/tests/assets/fonts/large_b.ttx b/compat/src/androidTest/assets/fonts/large_b.ttx
similarity index 100%
rename from compat/tests/assets/fonts/large_b.ttx
rename to compat/src/androidTest/assets/fonts/large_b.ttx
diff --git a/compat/tests/assets/fonts/large_c.ttf b/compat/src/androidTest/assets/fonts/large_c.ttf
similarity index 100%
rename from compat/tests/assets/fonts/large_c.ttf
rename to compat/src/androidTest/assets/fonts/large_c.ttf
Binary files differ
diff --git a/compat/tests/assets/fonts/large_c.ttx b/compat/src/androidTest/assets/fonts/large_c.ttx
similarity index 100%
rename from compat/tests/assets/fonts/large_c.ttx
rename to compat/src/androidTest/assets/fonts/large_c.ttx
diff --git a/compat/tests/assets/fonts/large_d.ttf b/compat/src/androidTest/assets/fonts/large_d.ttf
similarity index 100%
rename from compat/tests/assets/fonts/large_d.ttf
rename to compat/src/androidTest/assets/fonts/large_d.ttf
Binary files differ
diff --git a/compat/tests/assets/fonts/large_d.ttx b/compat/src/androidTest/assets/fonts/large_d.ttx
similarity index 100%
rename from compat/tests/assets/fonts/large_d.ttx
rename to compat/src/androidTest/assets/fonts/large_d.ttx
diff --git a/compat/tests/assets/fonts/samplefont.ttf b/compat/src/androidTest/assets/fonts/samplefont.ttf
similarity index 100%
rename from compat/tests/assets/fonts/samplefont.ttf
rename to compat/src/androidTest/assets/fonts/samplefont.ttf
Binary files differ
diff --git a/compat/tests/assets/fonts/samplefont.ttx b/compat/src/androidTest/assets/fonts/samplefont.ttx
similarity index 100%
rename from compat/tests/assets/fonts/samplefont.ttx
rename to compat/src/androidTest/assets/fonts/samplefont.ttx
diff --git a/compat/tests/fonts_readme.txt b/compat/src/androidTest/fonts_readme.txt
similarity index 100%
rename from compat/tests/fonts_readme.txt
rename to compat/src/androidTest/fonts_readme.txt
diff --git a/compat/tests/java/android/support/v13/view/DragStartHelperTest.java b/compat/src/androidTest/java/android/support/v13/view/DragStartHelperTest.java
similarity index 100%
rename from compat/tests/java/android/support/v13/view/DragStartHelperTest.java
rename to compat/src/androidTest/java/android/support/v13/view/DragStartHelperTest.java
diff --git a/compat/tests/java/android/support/v13/view/DragStartHelperTestActivity.java b/compat/src/androidTest/java/android/support/v13/view/DragStartHelperTestActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v13/view/DragStartHelperTestActivity.java
rename to compat/src/androidTest/java/android/support/v13/view/DragStartHelperTestActivity.java
diff --git a/compat/tests/java/android/support/v4/BaseInstrumentationTestCase.java b/compat/src/androidTest/java/android/support/v4/BaseInstrumentationTestCase.java
similarity index 100%
rename from compat/tests/java/android/support/v4/BaseInstrumentationTestCase.java
rename to compat/src/androidTest/java/android/support/v4/BaseInstrumentationTestCase.java
diff --git a/compat/tests/java/android/support/v4/BaseTestActivity.java b/compat/src/androidTest/java/android/support/v4/BaseTestActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v4/BaseTestActivity.java
rename to compat/src/androidTest/java/android/support/v4/BaseTestActivity.java
diff --git a/compat/tests/java/android/support/v4/ThemedYellowActivity.java b/compat/src/androidTest/java/android/support/v4/ThemedYellowActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v4/ThemedYellowActivity.java
rename to compat/src/androidTest/java/android/support/v4/ThemedYellowActivity.java
diff --git a/compat/tests/java/android/support/v4/app/ActivityCompatTest.java b/compat/src/androidTest/java/android/support/v4/app/ActivityCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/app/ActivityCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/app/ActivityCompatTest.java
diff --git a/core-utils/tests/java/android/support/v4/app/FrameMetricsActivity.java b/compat/src/androidTest/java/android/support/v4/app/FrameMetricsActivity.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/app/FrameMetricsActivity.java
rename to compat/src/androidTest/java/android/support/v4/app/FrameMetricsActivity.java
diff --git a/core-utils/tests/java/android/support/v4/app/FrameMetricsAggregatorTest.java b/compat/src/androidTest/java/android/support/v4/app/FrameMetricsAggregatorTest.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/app/FrameMetricsAggregatorTest.java
rename to compat/src/androidTest/java/android/support/v4/app/FrameMetricsAggregatorTest.java
diff --git a/core-utils/tests/java/android/support/v4/app/FrameMetricsSubActivity.java b/compat/src/androidTest/java/android/support/v4/app/FrameMetricsSubActivity.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/app/FrameMetricsSubActivity.java
rename to compat/src/androidTest/java/android/support/v4/app/FrameMetricsSubActivity.java
diff --git a/compat/tests/java/android/support/v4/app/JobIntentServiceTest.java b/compat/src/androidTest/java/android/support/v4/app/JobIntentServiceTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/app/JobIntentServiceTest.java
rename to compat/src/androidTest/java/android/support/v4/app/JobIntentServiceTest.java
diff --git a/compat/src/androidTest/java/android/support/v4/app/NotificationCompatTest.java b/compat/src/androidTest/java/android/support/v4/app/NotificationCompatTest.java
new file mode 100644
index 0000000..903778f
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/app/NotificationCompatTest.java
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import static android.support.v4.app.NotificationCompat.DEFAULT_ALL;
+import static android.support.v4.app.NotificationCompat.DEFAULT_LIGHTS;
+import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND;
+import static android.support.v4.app.NotificationCompat.DEFAULT_VIBRATE;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_ALL;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_CHILDREN;
+import static android.support.v4.app.NotificationCompat.GROUP_ALERT_SUMMARY;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.Color;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.BaseInstrumentationTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationCompatTest extends BaseInstrumentationTestCase<TestSupportActivity> {
+    private static final String TEXT_RESULT_KEY = "text";
+    private static final String DATA_RESULT_KEY = "data";
+    private static final String EXTRA_COLORIZED = "android.colorized";
+
+    Context mContext;
+
+    public NotificationCompatTest() {
+        super(TestSupportActivity.class);
+    }
+
+    @Before
+    public void setup() {
+        mContext = mActivityTestRule.getActivity();
+    }
+
+    @Test
+    public void testBadgeIcon() throws Throwable {
+        int badgeIcon = NotificationCompat.BADGE_ICON_SMALL;
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setBadgeIconType(badgeIcon)
+                .build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            assertEquals(badgeIcon, NotificationCompat.getBadgeIconType(n));
+        } else {
+            assertEquals(NotificationCompat.BADGE_ICON_NONE,
+                    NotificationCompat.getBadgeIconType(n));
+        }
+    }
+
+    @Test
+    public void testTimeout() throws Throwable {
+        long timeout = 23552;
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setTimeoutAfter(timeout)
+                .build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            assertEquals(timeout, NotificationCompat.getTimeoutAfter(n));
+        } else {
+            assertEquals(0, NotificationCompat.getTimeoutAfter(n));
+        }
+    }
+
+    @Test
+    public void testShortcutId() throws Throwable {
+        String shortcutId = "fgdfg";
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setShortcutId(shortcutId)
+                .build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            assertEquals(shortcutId, NotificationCompat.getShortcutId(n));
+        } else {
+            assertEquals(null, NotificationCompat.getShortcutId(n));
+        }
+    }
+
+    @Test
+    public void testNotificationChannel() throws Throwable {
+        String channelId = "new ID";
+        Notification n  = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setChannelId(channelId)
+                .build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            assertEquals(channelId, NotificationCompat.getChannelId(n));
+        } else {
+            assertNull(NotificationCompat.getChannelId(n));
+        }
+    }
+
+    @Test
+    public void testNotificationChannel_assignedFromBuilder() throws Throwable {
+        String channelId = "new ID";
+        Notification n  = new NotificationCompat.Builder(mActivityTestRule.getActivity(), channelId)
+                .build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            assertEquals(channelId, NotificationCompat.getChannelId(n));
+        } else {
+            assertNull(NotificationCompat.getChannelId(n));
+        }
+    }
+
+    @Test
+    public void testNotificationActionBuilder_assignsColorized() throws Throwable {
+        Notification n = newNotificationBuilder().setColorized(true).build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            Bundle extras = NotificationCompat.getExtras(n);
+            assertTrue(Boolean.TRUE.equals(extras.get(EXTRA_COLORIZED)));
+        }
+    }
+
+    @Test
+    public void testNotificationActionBuilder_unassignesColorized() throws Throwable {
+        Notification n = newNotificationBuilder().setColorized(false).build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            Bundle extras = NotificationCompat.getExtras(n);
+            assertTrue(Boolean.FALSE.equals(extras.get(EXTRA_COLORIZED)));
+        }
+    }
+
+    @Test
+    public void testNotificationActionBuilder_doesntAssignColorized() throws Throwable {
+        Notification n = newNotificationBuilder().build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            Bundle extras = NotificationCompat.getExtras(n);
+            assertFalse(extras.containsKey(EXTRA_COLORIZED));
+        }
+    }
+
+    @Test
+    public void testNotificationActionBuilder_copiesRemoteInputs() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .addRemoteInput(new RemoteInput("a", "b", null, false, null, null)).build();
+
+        NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build();
+
+        assertSame(a.getRemoteInputs()[0], aCopy.getRemoteInputs()[0]);
+    }
+
+    @Test
+    public void testNotificationActionBuilder_copiesAllowGeneratedReplies() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .setAllowGeneratedReplies(true).build();
+
+        NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build();
+
+        assertEquals(a.getAllowGeneratedReplies(), aCopy.getAllowGeneratedReplies());
+    }
+
+    @SdkSuppress(minSdkVersion = 24)
+    @Test
+    public void testFrameworkNotificationActionBuilder_setAllowGeneratedRepliesTrue()
+            throws Throwable {
+        Notification notif = new Notification.Builder(mContext)
+                .addAction(new Notification.Action.Builder(0, "title", null)
+                        .setAllowGeneratedReplies(true).build()).build();
+        NotificationCompat.Action action = NotificationCompat.getAction(notif, 0);
+        assertTrue(action.getAllowGeneratedReplies());
+    }
+
+    @Test
+    public void testNotificationActionBuilder_defaultAllowGeneratedRepliesTrue() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder().build();
+
+        assertTrue(a.getAllowGeneratedReplies());
+    }
+
+    @Test
+    public void testNotificationActionBuilder_defaultShowsUserInterfaceTrue() {
+        NotificationCompat.Action action = newActionBuilder().build();
+
+        assertTrue(action.getShowsUserInterface());
+    }
+
+    @Test
+    public void testNotificationAction_defaultAllowGeneratedRepliesTrue() throws Throwable {
+        NotificationCompat.Action a = new NotificationCompat.Action(0, null, null);
+
+        assertTrue(a.getAllowGeneratedReplies());
+    }
+
+    @Test
+    public void testNotificationAction_defaultShowsUserInterfaceTrue() {
+        NotificationCompat.Action action = new NotificationCompat.Action(0, null, null);
+
+        assertTrue(action.getShowsUserInterface());
+    }
+
+    @Test
+    public void testNotificationActionBuilder_setAllowGeneratedRepliesFalse() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .setAllowGeneratedReplies(false).build();
+
+        assertFalse(a.getAllowGeneratedReplies());
+    }
+
+    @Test
+    public void testNotificationAction_setShowsUserInterfaceFalse() {
+        NotificationCompat.Action action = newActionBuilder()
+                .setShowsUserInterface(false).build();
+
+        assertFalse(action.getShowsUserInterface());
+    }
+
+    @SdkSuppress(minSdkVersion = 20)
+    @Test
+    public void testGetActionCompatFromAction_showsUserInterface() {
+        NotificationCompat.Action action = newActionBuilder()
+                .setShowsUserInterface(false).build();
+        Notification notification = newNotificationBuilder().addAction(action).build();
+        NotificationCompat.Action result =
+                NotificationCompat.getActionCompatFromAction(notification.actions[0]);
+
+        assertFalse(result.getExtras().getBoolean(
+                NotificationCompat.Action.EXTRA_SHOWS_USER_INTERFACE, true));
+        assertFalse(result.getShowsUserInterface());
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @Test
+    public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesTrue()
+            throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .setAllowGeneratedReplies(true).build();
+        NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
+                .addAction(a);
+        Notification notification = newNotificationBuilder().extend(extender).build();
+        assertTrue(new NotificationCompat.WearableExtender(notification).getActions().get(0)
+                .getAllowGeneratedReplies());
+    }
+
+    @SdkSuppress(minSdkVersion = 17)
+    @Test
+    public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesFalse()
+            throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .setAllowGeneratedReplies(false).build();
+        NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
+                .addAction(a);
+        Notification notification = newNotificationBuilder().extend(extender).build();
+        assertFalse(new NotificationCompat.WearableExtender(notification).getActions().get(0)
+                .getAllowGeneratedReplies());
+    }
+
+
+    @SdkSuppress(maxSdkVersion = 16)
+    @SmallTest
+    @Test
+    public void testNotificationWearableExtenderAction_noActions()
+            throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .setAllowGeneratedReplies(true).build();
+        NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
+                .addAction(a);
+        Notification notification = newNotificationBuilder().extend(extender).build();
+        assertTrue(new NotificationCompat.WearableExtender(notification).getActions().size() == 0);
+    }
+
+    @Test
+    public void testNotificationActionBuilder_setDataOnlyRemoteInput() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .addRemoteInput(newDataOnlyRemoteInput()).build();
+        RemoteInput[] textInputs = a.getRemoteInputs();
+        assertTrue(textInputs == null || textInputs.length == 0);
+        verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
+    }
+
+    @Test
+    public void testNotificationActionBuilder_setTextAndDataOnlyRemoteInput() throws Throwable {
+        NotificationCompat.Action a = newActionBuilder()
+                .addRemoteInput(newDataOnlyRemoteInput())
+                .addRemoteInput(newTextRemoteInput())
+                .build();
+
+        verifyRemoteInputArrayHasSingleResult(a.getRemoteInputs(), TEXT_RESULT_KEY);
+        verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
+    }
+
+    @Test
+    public void testMessage_setAndGetExtras() throws Throwable {
+        String extraKey = "extra_key";
+        CharSequence extraValue = "extra_value";
+        NotificationCompat.MessagingStyle.Message m =
+                new NotificationCompat.MessagingStyle.Message("text", 0 /*timestamp */, "sender");
+        m.getExtras().putCharSequence(extraKey, extraValue);
+        assertEquals(extraValue, m.getExtras().getCharSequence(extraKey));
+
+        ArrayList<NotificationCompat.MessagingStyle.Message> messages = new ArrayList<>(1);
+        messages.add(m);
+        Bundle[] bundleArray =
+                NotificationCompat.MessagingStyle.Message.getBundleArrayForMessages(messages);
+        assertEquals(1, bundleArray.length);
+        NotificationCompat.MessagingStyle.Message fromBundle =
+                NotificationCompat.MessagingStyle.Message.getMessageFromBundle(bundleArray[0]);
+        assertEquals(extraValue, fromBundle.getExtras().getCharSequence(extraKey));
+    }
+
+    @Test
+    public void testGetGroupAlertBehavior() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .build();
+        if (Build.VERSION.SDK_INT >= 26) {
+            assertEquals(GROUP_ALERT_CHILDREN, NotificationCompat.getGroupAlertBehavior(n));
+        } else {
+            assertEquals(GROUP_ALERT_ALL, NotificationCompat.getGroupAlertBehavior(n));
+        }
+    }
+
+    @Test
+    public void testGroupAlertBehavior_mutesGroupNotifications() throws Throwable {
+        // valid between api 20, when groups were added, and api 25, the last to use sound
+        // and vibration from the notification itself
+
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(true)
+                .build();
+
+        Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(false)
+                .build();
+
+        if (Build.VERSION.SDK_INT >= 20 && !(Build.VERSION.SDK_INT >= 26)) {
+            assertNull(n.sound);
+            assertNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) == 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) == 0);
+
+            assertNull(n2.sound);
+            assertNull(n2.vibrate);
+            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n2.defaults & DEFAULT_SOUND) == 0);
+            assertTrue((n2.defaults & DEFAULT_VIBRATE) == 0);
+        } else if (Build.VERSION.SDK_INT < 20) {
+            assertNotNull(n.sound);
+            assertNotNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
+
+            assertNotNull(n2.sound);
+            assertNotNull(n2.vibrate);
+            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
+        }
+    }
+
+    @Test
+    public void testGroupAlertBehavior_doesNotMuteIncorrectGroupNotifications() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(true)
+                .build();
+
+        Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(false)
+                .build();
+
+        Notification n3 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup("grouped")
+                .setGroupSummary(false)
+                .build();
+
+        if (Build.VERSION.SDK_INT >= 20 && !(Build.VERSION.SDK_INT >= 26)) {
+            assertNotNull(n.sound);
+            assertNotNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
+
+            assertNotNull(n2.sound);
+            assertNotNull(n2.vibrate);
+            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
+
+            assertNotNull(n3.sound);
+            assertNotNull(n3.vibrate);
+            assertTrue((n3.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n3.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n3.defaults & DEFAULT_VIBRATE) != 0);
+        }
+    }
+
+    @Test
+    public void testGroupAlertBehavior_doesNotMuteNonGroupNotifications() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
+                .setVibrate(new long[] {235})
+                .setSound(Uri.EMPTY)
+                .setDefaults(DEFAULT_ALL)
+                .setGroup(null)
+                .setGroupSummary(false)
+                .build();
+        if (!(Build.VERSION.SDK_INT >= 26)) {
+            assertNotNull(n.sound);
+            assertNotNull(n.vibrate);
+            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
+            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
+            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
+        }
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 21)
+    public void testHasAudioAttributesFrom21() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setSound(Uri.EMPTY)
+                .build();
+        assertNotNull(n.audioAttributes);
+        assertEquals(-1, n.audioStreamType);
+        assertEquals(Uri.EMPTY, n.sound);
+
+        n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setSound(Uri.EMPTY, AudioManager.STREAM_RING)
+                .build();
+        assertNotNull(n.audioAttributes);
+        assertEquals(AudioAttributes.CONTENT_TYPE_SONIFICATION,
+                n.audioAttributes.getContentType());
+        assertEquals(-1, n.audioStreamType);
+        assertEquals(Uri.EMPTY, n.sound);
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 20)
+    public void testHasStreamTypePre21() throws Throwable {
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setSound(Uri.EMPTY, 34)
+                .build();
+        assertEquals(34, n.audioStreamType);
+        assertEquals(Uri.EMPTY, n.sound);
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test
+    public void testClearAlertingFieldsIfUsingChannels() throws Throwable {
+        long[] vibration = new long[]{100};
+
+        // stripped if using channels
+        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity(), "test")
+                .setSound(Uri.EMPTY)
+                .setDefaults(Notification.DEFAULT_ALL)
+                .setVibrate(vibration)
+                .setLights(Color.BLUE, 100, 100)
+                .build();
+        assertNull(n.sound);
+        assertEquals(0, n.defaults);
+        assertNull(n.vibrate);
+        assertEquals(0, n.ledARGB);
+        assertEquals(0, n.ledOnMS);
+        assertEquals(0, n.ledOffMS);
+
+        // left intact if not using channels
+        n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
+                .setSound(Uri.EMPTY)
+                .setDefaults(Notification.DEFAULT_ALL)
+                .setVibrate(vibration)
+                .setLights(Color.BLUE, 100, 100)
+                .build();
+        assertEquals(Uri.EMPTY, n.sound);
+        assertNotNull(n.audioAttributes);
+        assertEquals(Notification.DEFAULT_ALL, n.defaults);
+        assertEquals(vibration, n.vibrate);
+        assertEquals(Color.BLUE, n.ledARGB);
+        assertEquals(100, n.ledOnMS);
+        assertEquals(100, n.ledOffMS);
+    }
+
+    @Test
+    public void messagingStyle_isGroupConversation() {
+        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
+        NotificationCompat.MessagingStyle messagingStyle =
+                new NotificationCompat.MessagingStyle("self name")
+                        .setGroupConversation(true)
+                        .setConversationTitle("test conversation title");
+        new NotificationCompat.Builder(mContext, "test id")
+                .setSmallIcon(1)
+                .setContentTitle("test title")
+                .setStyle(messagingStyle)
+                .build();
+
+        assertTrue(messagingStyle.isGroupConversation());
+    }
+
+    @Test
+    public void messagingStyle_isGroupConversation_noConversationTitle() {
+        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.P;
+        NotificationCompat.MessagingStyle messagingStyle =
+                new NotificationCompat.MessagingStyle("self name")
+                        .setGroupConversation(true)
+                        .setConversationTitle(null);
+        new NotificationCompat.Builder(mContext, "test id")
+                .setSmallIcon(1)
+                .setContentTitle("test title")
+                .setStyle(messagingStyle)
+                .build();
+
+        assertTrue(messagingStyle.isGroupConversation());
+    }
+
+    @Test
+    public void messagingStyle_isGroupConversation_withConversationTitle_legacy() {
+        // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
+        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
+        NotificationCompat.MessagingStyle messagingStyle =
+                new NotificationCompat.MessagingStyle("self name")
+                        .setGroupConversation(false)
+                        .setConversationTitle("test conversation title");
+        new NotificationCompat.Builder(mContext, "test id")
+                .setSmallIcon(1)
+                .setContentTitle("test title")
+                .setStyle(messagingStyle)
+                .build();
+
+        assertTrue(messagingStyle.isGroupConversation());
+    }
+
+    @Test
+    public void messagingStyle_isGroupConversation_withoutConversationTitle_legacy() {
+        // In legacy (version < P), isGroupConversation is controlled by conversationTitle.
+        mContext.getApplicationInfo().targetSdkVersion = Build.VERSION_CODES.O;
+        NotificationCompat.MessagingStyle messagingStyle =
+                new NotificationCompat.MessagingStyle("self name")
+                        .setGroupConversation(true)
+                        .setConversationTitle(null);
+        new NotificationCompat.Builder(mContext, "test id")
+                .setSmallIcon(1)
+                .setContentTitle("test title")
+                .setStyle(messagingStyle)
+                .build();
+
+        assertFalse(messagingStyle.isGroupConversation());
+    }
+
+    @Test
+    public void testMessagingStyle_extras() {
+        NotificationCompat.MessagingStyle messagingStyle =
+                new NotificationCompat.MessagingStyle("test name")
+                        .setGroupConversation(true);
+        Bundle bundle = new Bundle();
+        messagingStyle.addCompatExtras(bundle);
+
+        NotificationCompat.MessagingStyle resultMessagingStyle =
+                new NotificationCompat.MessagingStyle("test name");
+        resultMessagingStyle.restoreFromCompatExtras(bundle);
+
+        assertTrue(resultMessagingStyle.isGroupConversation());
+    }
+
+    @Test
+    public void action_builder_hasDefault() {
+        NotificationCompat.Action action =
+                new NotificationCompat.Action.Builder(0, "Test Title", null).build();
+        assertEquals(NotificationCompat.Action.SEMANTIC_ACTION_NONE, action.getSemanticAction());
+    }
+
+    @Test
+    public void action_builder_setSemanticAction() {
+        NotificationCompat.Action action =
+                new NotificationCompat.Action.Builder(0, "Test Title", null)
+                        .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
+                        .build();
+        assertEquals(NotificationCompat.Action.SEMANTIC_ACTION_REPLY, action.getSemanticAction());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 20)
+    public void action_semanticAction_toAndFromNotification() {
+        NotificationCompat.Action action =
+                new NotificationCompat.Action.Builder(0, "Test Title", null)
+                        .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY)
+                        .build();
+        Notification notification = newNotificationBuilder().addAction(action).build();
+        NotificationCompat.Action result = NotificationCompat.getAction(notification, 0);
+
+        assertEquals(NotificationCompat.Action.SEMANTIC_ACTION_REPLY, result.getSemanticAction());
+    }
+
+    private static final NotificationCompat.Action TEST_INVISIBLE_ACTION =
+            new NotificationCompat.Action.Builder(0, "Test Title", null).build();
+
+    @Test
+    @SdkSuppress(minSdkVersion = 21)
+    public void getInvisibleActions() {
+        Notification notification =
+                newNotificationBuilder().addInvisibleAction(TEST_INVISIBLE_ACTION).build();
+        verifyInvisibleActionExists(notification);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 21)
+    public void getInvisibleActions_withCarExtender() {
+        NotificationCompat.CarExtender carExtender = new NotificationCompat.CarExtender();
+        Notification notification = newNotificationBuilder()
+                .addInvisibleAction(TEST_INVISIBLE_ACTION)
+                .extend(carExtender)
+                .build();
+        verifyInvisibleActionExists(notification);
+    }
+
+    private static void verifyInvisibleActionExists(Notification notification) {
+        List<NotificationCompat.Action> result =
+                NotificationCompat.getInvisibleActions(notification);
+        assertTrue("Expecting 1 result, got " + result.size(), result.size() == 1);
+        NotificationCompat.Action resultAction = result.get(0);
+        assertEquals(resultAction.getIcon(), TEST_INVISIBLE_ACTION.getIcon());
+        assertEquals(resultAction.getTitle(), TEST_INVISIBLE_ACTION.getTitle());
+    }
+
+    private static RemoteInput newDataOnlyRemoteInput() {
+        return new RemoteInput.Builder(DATA_RESULT_KEY)
+            .setAllowFreeFormInput(false)
+            .setAllowDataType("mimeType", true)
+            .build();
+    }
+
+    private static RemoteInput newTextRemoteInput() {
+        return new RemoteInput.Builder(TEXT_RESULT_KEY).build();  // allowFreeForm defaults to true
+    }
+
+    private static void verifyRemoteInputArrayHasSingleResult(
+            RemoteInput[] remoteInputs, String expectedResultKey) {
+        assertTrue(remoteInputs != null && remoteInputs.length == 1);
+        assertEquals(expectedResultKey, remoteInputs[0].getResultKey());
+    }
+
+    private static NotificationCompat.Action.Builder newActionBuilder() {
+        return new NotificationCompat.Action.Builder(0, "title", null);
+    }
+
+    private NotificationCompat.Builder newNotificationBuilder() {
+        return new NotificationCompat.Builder(mContext)
+                .setSmallIcon(0)
+                .setContentTitle("title")
+                .setContentText("text");
+    }
+}
diff --git a/compat/tests/java/android/support/v4/app/RemoteInputTest.java b/compat/src/androidTest/java/android/support/v4/app/RemoteInputTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/app/RemoteInputTest.java
rename to compat/src/androidTest/java/android/support/v4/app/RemoteInputTest.java
diff --git a/compat/tests/java/android/support/v4/app/SupportActivityTest.java b/compat/src/androidTest/java/android/support/v4/app/SupportActivityTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/app/SupportActivityTest.java
rename to compat/src/androidTest/java/android/support/v4/app/SupportActivityTest.java
diff --git a/compat/tests/java/android/support/v4/app/TestSupportActivity.java b/compat/src/androidTest/java/android/support/v4/app/TestSupportActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v4/app/TestSupportActivity.java
rename to compat/src/androidTest/java/android/support/v4/app/TestSupportActivity.java
diff --git a/compat/tests/java/android/support/v4/content/ContextCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/ContextCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/content/ContextCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/content/ContextCompatTest.java
diff --git a/core-utils/tests/java/android/support/v4/content/FileProviderTest.java b/compat/src/androidTest/java/android/support/v4/content/FileProviderTest.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/content/FileProviderTest.java
rename to compat/src/androidTest/java/android/support/v4/content/FileProviderTest.java
diff --git a/core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java b/compat/src/androidTest/java/android/support/v4/content/MimeTypeFilterTest.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/content/MimeTypeFilterTest.java
rename to compat/src/androidTest/java/android/support/v4/content/MimeTypeFilterTest.java
diff --git a/core-utils/tests/java/android/support/v4/content/PermissionCheckerTest.java b/compat/src/androidTest/java/android/support/v4/content/PermissionCheckerTest.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/content/PermissionCheckerTest.java
rename to compat/src/androidTest/java/android/support/v4/content/PermissionCheckerTest.java
diff --git a/compat/tests/java/android/support/v4/content/pm/ShortcutInfoCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/pm/ShortcutInfoCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/content/pm/ShortcutInfoCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/content/pm/ShortcutInfoCompatTest.java
diff --git a/compat/tests/java/android/support/v4/content/pm/ShortcutManagerCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/pm/ShortcutManagerCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/content/pm/ShortcutManagerCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/content/pm/ShortcutManagerCompatTest.java
diff --git a/compat/src/androidTest/java/android/support/v4/content/res/FontResourcesParserCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
new file mode 100644
index 0000000..f503d99
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.content.res;
+
+import static android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
+import static android.support.v4.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry;
+import static android.support.v4.content.res.FontResourcesParserCompat.FontFileResourceEntry;
+import static android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.annotation.SuppressLint;
+import android.app.Instrumentation;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.Build;
+import android.support.compat.test.R;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.provider.FontRequest;
+import android.util.Base64;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Tests for {@link FontResourcesParserCompat}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FontResourcesParserCompatTest {
+
+    private Instrumentation mInstrumentation;
+    private Resources mResources;
+
+    @Before
+    public void setup() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mResources = mInstrumentation.getContext().getResources();
+    }
+
+    @Test
+    public void testParse() throws XmlPullParserException, IOException {
+        @SuppressLint("ResourceType")
+        XmlResourceParser parser = mResources.getXml(R.font.samplexmlfontforparsing);
+
+        FamilyResourceEntry result = FontResourcesParserCompat.parse(parser, mResources);
+
+        assertNotNull(result);
+        FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) result;
+        FontFileResourceEntry[] fileEntries = filesEntry.getEntries();
+        assertEquals(4, fileEntries.length);
+        FontFileResourceEntry font1 = fileEntries[0];
+        assertEquals(400, font1.getWeight());
+        assertEquals(false, font1.isItalic());
+        assertEquals("'wdth' 0.8", font1.getVariationSettings());
+        assertEquals(0, font1.getTtcIndex());
+        assertEquals(R.font.samplefont, font1.getResourceId());
+        FontFileResourceEntry font2 = fileEntries[1];
+        assertEquals(400, font2.getWeight());
+        assertEquals(true, font2.isItalic());
+        assertEquals("'contrast' 0.5", font2.getVariationSettings());
+        assertEquals(1, font2.getTtcIndex());
+        assertEquals(R.font.samplefont2, font2.getResourceId());
+        FontFileResourceEntry font3 = fileEntries[2];
+        assertEquals(700, font3.getWeight());
+        assertEquals(false, font3.isItalic());
+        assertEquals("'wdth' 500.0, 'wght' 300.0", font3.getVariationSettings());
+        assertEquals(2, font3.getTtcIndex());
+        assertEquals(R.font.samplefont3, font3.getResourceId());
+        FontFileResourceEntry font4 = fileEntries[3];
+        assertEquals(700, font4.getWeight());
+        assertEquals(true, font4.isItalic());
+        assertEquals(null, font4.getVariationSettings());
+        assertEquals(0, font4.getTtcIndex());
+        assertEquals(R.font.samplefont4, font4.getResourceId());
+    }
+
+    @Test
+    public void testParseAndroidAttrs() throws XmlPullParserException, IOException {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
+            // The following tests are only expected to pass on v22+ devices. The android
+            // resources are stripped in older versions and hence won't be parsed.
+            return;
+        }
+
+        @SuppressLint("ResourceType")
+        XmlResourceParser parser = mResources.getXml(R.font.samplexmlfontforparsing2);
+
+        FamilyResourceEntry result = FontResourcesParserCompat.parse(parser, mResources);
+
+        assertNotNull(result);
+        FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) result;
+        FontFileResourceEntry[] fileEntries = filesEntry.getEntries();
+        assertEquals(4, fileEntries.length);
+        FontFileResourceEntry font1 = fileEntries[0];
+        assertEquals(400, font1.getWeight());
+        assertEquals(false, font1.isItalic());
+        assertEquals("'wdth' 0.8", font1.getVariationSettings());
+        assertEquals(0, font1.getTtcIndex());
+        assertEquals(R.font.samplefont, font1.getResourceId());
+        FontFileResourceEntry font2 = fileEntries[1];
+        assertEquals(400, font2.getWeight());
+        assertEquals(true, font2.isItalic());
+        assertEquals("'contrast' 0.5", font2.getVariationSettings());
+        assertEquals(1, font2.getTtcIndex());
+        assertEquals(R.font.samplefont2, font2.getResourceId());
+        FontFileResourceEntry font3 = fileEntries[2];
+        assertEquals(700, font3.getWeight());
+        assertEquals(false, font3.isItalic());
+        assertEquals("'wdth' 500.0, 'wght' 300.0", font3.getVariationSettings());
+        assertEquals(2, font3.getTtcIndex());
+        assertEquals(R.font.samplefont3, font3.getResourceId());
+        FontFileResourceEntry font4 = fileEntries[3];
+        assertEquals(700, font4.getWeight());
+        assertEquals(true, font4.isItalic());
+        assertEquals(null, font4.getVariationSettings());
+        assertEquals(0, font4.getTtcIndex());
+        assertEquals(R.font.samplefont4, font4.getResourceId());
+    }
+
+    @Test
+    public void testParseDownloadableFont() throws IOException, XmlPullParserException {
+        @SuppressLint("ResourceType")
+        XmlResourceParser parser = mResources.getXml(R.font.samplexmldownloadedfont);
+
+        FamilyResourceEntry result = FontResourcesParserCompat.parse(parser, mResources);
+
+        assertNotNull(result);
+        ProviderResourceEntry providerEntry = (ProviderResourceEntry) result;
+        FontRequest request = providerEntry.getRequest();
+        assertEquals("android.support.provider.fonts.font",
+                request.getProviderAuthority());
+        assertEquals("android.support.compat.test", request.getProviderPackage());
+        assertEquals("singleFontFamily", request.getQuery());
+    }
+
+    @Test
+    public void testReadCertsSingleArray() {
+        List<List<byte[]>> result = FontResourcesParserCompat.readCerts(mResources, R.array.certs1);
+
+        assertEquals(1, result.size());
+        List<byte[]> firstSet = result.get(0);
+        assertEquals(2, firstSet.size());
+        String firstValue = Base64.encodeToString(firstSet.get(0), Base64.DEFAULT).trim();
+        assertEquals("MIIEqDCCA5CgAwIBAgIJANWFuGx9", firstValue);
+        String secondValue = Base64.encodeToString(firstSet.get(1), Base64.DEFAULT).trim();
+        assertEquals("UEChMHQW5kcm9pZDEQMA4GA=", secondValue);
+    }
+
+    @Test
+    public void testReadCertsMultiArray() {
+        List<List<byte[]>> result =
+                FontResourcesParserCompat.readCerts(mResources, R.array.certarray);
+
+        assertEquals(2, result.size());
+        List<byte[]> firstSet = result.get(0);
+        assertEquals(2, firstSet.size());
+        String firstValue = Base64.encodeToString(firstSet.get(0), Base64.DEFAULT).trim();
+        assertEquals("MIIEqDCCA5CgAwIBAgIJANWFuGx9", firstValue);
+        String secondValue = Base64.encodeToString(firstSet.get(1), Base64.DEFAULT).trim();
+        assertEquals("UEChMHQW5kcm9pZDEQMA4GA=", secondValue);
+        List<byte[]> secondSet = result.get(1);
+        assertEquals(2, secondSet.size());
+        String thirdValue = Base64.encodeToString(secondSet.get(0), Base64.DEFAULT).trim();
+        assertEquals("MDEyMzM2NTZaMIGUMQswCQYD", thirdValue);
+        String fourthValue = Base64.encodeToString(secondSet.get(1), Base64.DEFAULT).trim();
+        assertEquals("DHThvbbR24kT9ixcOd9W+EY=", fourthValue);
+    }
+}
diff --git a/compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java b/compat/src/androidTest/java/android/support/v4/content/res/ResourcesCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/content/res/ResourcesCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/content/res/ResourcesCompatTest.java
diff --git a/compat/src/androidTest/java/android/support/v4/graphics/ColorUtilsTest.java b/compat/src/androidTest/java/android/support/v4/graphics/ColorUtilsTest.java
new file mode 100644
index 0000000..af11e2b
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/graphics/ColorUtilsTest.java
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.graphics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Color;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ColorUtilsTest {
+
+    // 0.5% of the max value
+    private static final float ALLOWED_OFFSET_HUE = 360 * 0.005f;
+    private static final float ALLOWED_OFFSET_SATURATION = 0.005f;
+    private static final float ALLOWED_OFFSET_LIGHTNESS = 0.005f;
+    private static final float ALLOWED_OFFSET_MIN_ALPHA = 0.01f;
+    private static final double ALLOWED_OFFSET_LAB = 0.01;
+    private static final double ALLOWED_OFFSET_XYZ = 0.01;
+
+    private static final int ALLOWED_OFFSET_RGB_COMPONENT = 2;
+
+    private static final ArrayList<TestEntry> sEntryList = new ArrayList<>();
+
+    static {
+        sEntryList.add(new TestEntry(Color.BLACK).setHsl(0f, 0f, 0f)
+                .setLab(0, 0, 0).setXyz(0, 0, 0)
+                .setWhiteMinAlpha30(0.35f).setWhiteMinAlpha45(0.46f));
+
+        sEntryList.add(new TestEntry(Color.WHITE).setHsl(0f, 0f, 1f)
+                .setLab(100, 0.005, -0.01).setXyz(95.05, 100, 108.9)
+                .setBlackMinAlpha30(0.42f).setBlackMinAlpha45(0.54f));
+
+        sEntryList.add(new TestEntry(Color.BLUE).setHsl(240f, 1f, 0.5f)
+                .setLab(32.303, 79.197, -107.864).setXyz(18.05, 7.22, 95.05)
+                .setWhiteMinAlpha30(0.55f).setWhiteMinAlpha45(0.71f));
+
+        sEntryList.add(new TestEntry(Color.GREEN).setHsl(120f, 1f, 0.5f)
+                .setLab(87.737, -86.185, 83.181).setXyz(35.76, 71.520, 11.920)
+                .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
+
+        sEntryList.add(new TestEntry(Color.RED).setHsl(0f, 1f, 0.5f)
+                .setLab(53.233, 80.109, 67.22).setXyz(41.24, 21.26, 1.93)
+                .setWhiteMinAlpha30(0.84f).setBlackMinAlpha30(0.55f).setBlackMinAlpha45(0.78f));
+
+        sEntryList.add(new TestEntry(Color.CYAN).setHsl(180f, 1f, 0.5f)
+                .setLab(91.117, -48.08, -14.138).setXyz(53.81, 78.74, 106.97)
+                .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
+
+        sEntryList.add(new TestEntry(0xFF2196F3).setHsl(207f, 0.9f, 0.54f)
+                .setLab(60.433, 2.091, -55.116).setXyz(27.711, 28.607, 88.855)
+                .setBlackMinAlpha30(0.52f).setWhiteMinAlpha30(0.97f).setBlackMinAlpha45(0.7f));
+
+        sEntryList.add(new TestEntry(0xFFD1C4E9).setHsl(261f, 0.46f, 0.84f)
+                .setLab(81.247, 11.513, -16.677).setXyz(60.742, 58.918, 85.262)
+                .setBlackMinAlpha30(0.45f).setBlackMinAlpha45(0.58f));
+
+        sEntryList.add(new TestEntry(0xFF311B92).setHsl(251.09f, 0.687f, 0.339f)
+                .setLab(21.988, 44.301, -60.942).setXyz(6.847, 3.512, 27.511)
+                .setWhiteMinAlpha30(0.39f).setWhiteMinAlpha45(0.54f));
+    }
+
+    @Test
+    public void testColorToHSL() {
+        for (TestEntry entry : sEntryList) {
+            verifyColorToHSL(entry.rgb, entry.hsl);
+        }
+    }
+
+    @Test
+    public void testHSLToColor() {
+        for (TestEntry entry : sEntryList) {
+            verifyHSLToColor(entry.hsl, entry.rgb);
+        }
+    }
+
+    @Test
+    public void testColorToHslLimits() {
+        final float[] hsl = new float[3];
+
+        for (TestEntry entry : sEntryList) {
+            ColorUtils.colorToHSL(entry.rgb, hsl);
+
+            assertTrue(hsl[0] >= 0f && hsl[0] <= 360f);
+            assertTrue(hsl[1] >= 0f && hsl[1] <= 1f);
+            assertTrue(hsl[2] >= 0f && hsl[2] <= 1f);
+        }
+    }
+
+    @Test
+    public void testColorToXYZ() {
+        for (TestEntry entry : sEntryList) {
+            verifyColorToXYZ(entry.rgb, entry.xyz);
+        }
+    }
+
+    @Test
+    public void testColorToLAB() {
+        for (TestEntry entry : sEntryList) {
+            verifyColorToLAB(entry.rgb, entry.lab);
+        }
+    }
+
+    @Test
+    public void testLABToXYZ() {
+        for (TestEntry entry : sEntryList) {
+            verifyLABToXYZ(entry.lab, entry.xyz);
+        }
+    }
+
+    @Test
+    public void testXYZToColor() {
+        for (TestEntry entry : sEntryList) {
+            verifyXYZToColor(entry.xyz, entry.rgb);
+        }
+    }
+
+    @Test
+    public void testLABToColor() {
+        for (TestEntry entry : sEntryList) {
+            verifyLABToColor(entry.lab, entry.rgb);
+        }
+    }
+
+    @Test
+    public void testMinAlphas() {
+        for (TestEntry entry : sEntryList) {
+            verifyMinAlpha("Black title", entry.rgb, entry.blackMinAlpha30,
+                    ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 3.0f));
+            verifyMinAlpha("Black body", entry.rgb, entry.blackMinAlpha45,
+                    ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 4.5f));
+            verifyMinAlpha("White title", entry.rgb, entry.whiteMinAlpha30,
+                    ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 3.0f));
+            verifyMinAlpha("White body", entry.rgb, entry.whiteMinAlpha45,
+                    ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 4.5f));
+        }
+    }
+
+    @Test
+    public void testCircularInterpolationForwards() {
+        assertEquals(0f, ColorUtils.circularInterpolate(0, 180, 0f), 0f);
+        assertEquals(90f, ColorUtils.circularInterpolate(0, 180, 0.5f), 0f);
+        assertEquals(180f, ColorUtils.circularInterpolate(0, 180, 1f), 0f);
+    }
+
+    @Test
+    public void testCircularInterpolationBackwards() {
+        assertEquals(180f, ColorUtils.circularInterpolate(180, 0, 0f), 0f);
+        assertEquals(90f, ColorUtils.circularInterpolate(180, 0, 0.5f), 0f);
+        assertEquals(0f, ColorUtils.circularInterpolate(180, 0, 1f), 0f);
+    }
+
+    @Test
+    public void testCircularInterpolationCrossZero() {
+        assertEquals(270f, ColorUtils.circularInterpolate(270, 90, 0f), 0f);
+        assertEquals(180f, ColorUtils.circularInterpolate(270, 90, 0.5f), 0f);
+        assertEquals(90f, ColorUtils.circularInterpolate(270, 90, 1f), 0f);
+    }
+
+    private static void verifyMinAlpha(String title, int color, float expected, int actual) {
+        final String message = title + " text within error for #" + Integer.toHexString(color);
+        if (expected < 0) {
+            assertEquals(message, actual, -1);
+        } else {
+            assertEquals(message, expected, actual / 255f, ALLOWED_OFFSET_MIN_ALPHA);
+        }
+    }
+
+    private static void verifyColorToHSL(int color, float[] expected) {
+        float[] actualHSL = new float[3];
+        ColorUtils.colorToHSL(color, actualHSL);
+
+        assertEquals("Hue not within offset", expected[0], actualHSL[0],
+                ALLOWED_OFFSET_HUE);
+        assertEquals("Saturation not within offset", expected[1], actualHSL[1],
+                ALLOWED_OFFSET_SATURATION);
+        assertEquals("Lightness not within offset", expected[2], actualHSL[2],
+                ALLOWED_OFFSET_LIGHTNESS);
+    }
+
+    private static void verifyHSLToColor(float[] hsl, int expected) {
+        final int actualRgb = ColorUtils.HSLToColor(hsl);
+
+        assertEquals("Red not within offset", Color.red(expected), Color.red(actualRgb),
+                ALLOWED_OFFSET_RGB_COMPONENT);
+        assertEquals("Green not within offset", Color.green(expected), Color.green(actualRgb),
+                ALLOWED_OFFSET_RGB_COMPONENT);
+        assertEquals("Blue not within offset", Color.blue(expected), Color.blue(actualRgb),
+                ALLOWED_OFFSET_RGB_COMPONENT);
+    }
+
+    private static void verifyColorToLAB(int color, double[] expected) {
+        double[] result = new double[3];
+        ColorUtils.colorToLAB(color, result);
+
+        assertEquals("L not within offset", expected[0], result[0], ALLOWED_OFFSET_LAB);
+        assertEquals("A not within offset", expected[1], result[1], ALLOWED_OFFSET_LAB);
+        assertEquals("B not within offset", expected[2], result[2], ALLOWED_OFFSET_LAB);
+    }
+
+    private static void verifyColorToXYZ(int color, double[] expected) {
+        double[] result = new double[3];
+        ColorUtils.colorToXYZ(color, result);
+
+        assertEquals("X not within offset", expected[0], result[0], ALLOWED_OFFSET_XYZ);
+        assertEquals("Y not within offset", expected[1], result[1], ALLOWED_OFFSET_XYZ);
+        assertEquals("Z not within offset", expected[2], result[2], ALLOWED_OFFSET_XYZ);
+    }
+
+    private static void verifyLABToXYZ(double[] lab, double[] expected) {
+        double[] result = new double[3];
+        ColorUtils.LABToXYZ(lab[0], lab[1], lab[2], result);
+
+        assertEquals("X not within offset", expected[0], result[0], ALLOWED_OFFSET_XYZ);
+        assertEquals("Y not within offset", expected[1], result[1], ALLOWED_OFFSET_XYZ);
+        assertEquals("Z not within offset", expected[2], result[2], ALLOWED_OFFSET_XYZ);
+    }
+
+    private static void verifyXYZToColor(double[] xyz, int expected) {
+        final int result = ColorUtils.XYZToColor(xyz[0], xyz[1], xyz[2]);
+        verifyRGBComponentsClose(expected, result);
+    }
+
+    private static void verifyLABToColor(double[] lab, int expected) {
+        final int result = ColorUtils.LABToColor(lab[0], lab[1], lab[2]);
+        verifyRGBComponentsClose(expected, result);
+    }
+
+    private static void verifyRGBComponentsClose(int expected, int actual) {
+        final String message = "Expected: #" + Integer.toHexString(expected)
+                + ", Actual: #" + Integer.toHexString(actual);
+        assertEquals("R not equal: " + message, Color.red(expected), Color.red(actual), 1);
+        assertEquals("G not equal: " + message, Color.green(expected), Color.green(actual), 1);
+        assertEquals("B not equal: " + message, Color.blue(expected), Color.blue(actual), 1);
+    }
+
+    private static class TestEntry {
+        final int rgb;
+        final float[] hsl = new float[3];
+        final double[] xyz = new double[3];
+        final double[] lab = new double[3];
+
+        float blackMinAlpha45 = -1;
+        float blackMinAlpha30 = -1;
+        float whiteMinAlpha45 = -1;
+        float whiteMinAlpha30 = -1;
+
+        TestEntry(int rgb) {
+            this.rgb = rgb;
+        }
+
+        TestEntry setHsl(float h, float s, float l) {
+            hsl[0] = h;
+            hsl[1] = s;
+            hsl[2] = l;
+            return this;
+        }
+
+        TestEntry setXyz(double x, double y, double z) {
+            xyz[0] = x;
+            xyz[1] = y;
+            xyz[2] = z;
+            return this;
+        }
+
+        TestEntry setLab(double l, double a, double b) {
+            lab[0] = l;
+            lab[1] = a;
+            lab[2] = b;
+            return this;
+        }
+
+        TestEntry setBlackMinAlpha30(float minAlpha) {
+            blackMinAlpha30 = minAlpha;
+            return this;
+        }
+
+        TestEntry setBlackMinAlpha45(float minAlpha) {
+            blackMinAlpha45 = minAlpha;
+            return this;
+        }
+
+        TestEntry setWhiteMinAlpha30(float minAlpha) {
+            whiteMinAlpha30 = minAlpha;
+            return this;
+        }
+
+        TestEntry setWhiteMinAlpha45(float minAlpha) {
+            whiteMinAlpha45 = minAlpha;
+            return this;
+        }
+    }
+}
diff --git a/compat/tests/java/android/support/v4/graphics/DrawableCompatTest.java b/compat/src/androidTest/java/android/support/v4/graphics/DrawableCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/graphics/DrawableCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/graphics/DrawableCompatTest.java
diff --git a/compat/tests/java/android/support/v4/graphics/PaintCompatHasGlyphTest.java b/compat/src/androidTest/java/android/support/v4/graphics/PaintCompatHasGlyphTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/graphics/PaintCompatHasGlyphTest.java
rename to compat/src/androidTest/java/android/support/v4/graphics/PaintCompatHasGlyphTest.java
diff --git a/compat/tests/java/android/support/v4/graphics/TestTintAwareDrawable.java b/compat/src/androidTest/java/android/support/v4/graphics/TestTintAwareDrawable.java
similarity index 100%
rename from compat/tests/java/android/support/v4/graphics/TestTintAwareDrawable.java
rename to compat/src/androidTest/java/android/support/v4/graphics/TestTintAwareDrawable.java
diff --git a/compat/src/androidTest/java/android/support/v4/graphics/TypefaceCompatTest.java b/compat/src/androidTest/java/android/support/v4/graphics/TypefaceCompatTest.java
new file mode 100644
index 0000000..9c27966
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/graphics/TypefaceCompatTest.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.graphics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.SuppressLint;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.content.res.Resources;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.compat.test.R;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.v4.content.res.FontResourcesParserCompat;
+import android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
+import android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
+import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.provider.FontRequest;
+import android.support.v4.provider.FontsContractCompat;
+import android.support.v4.provider.MockFontProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+public class TypefaceCompatTest {
+
+    public Context mContext;
+    public Resources mResources;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mResources = mContext.getResources();
+        MockFontProvider.prepareFontFiles(mContext);
+    }
+
+    @After
+    public void tearDown() {
+        MockFontProvider.cleanUpFontFiles(mContext);
+    }
+
+    // Signature to be used for authentication to access content provider.
+    // In this test case, the content provider and consumer live in the same package, self package's
+    // signature works.
+    private static final List<List<byte[]>> SIGNATURE;
+    static {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        try {
+            PackageManager manager = context.getPackageManager();
+            PackageInfo info = manager.getPackageInfo(
+                    context.getPackageName(), PackageManager.GET_SIGNATURES);
+            ArrayList<byte[]> out = new ArrayList<>();
+            for (Signature sig : info.signatures) {
+                out.add(sig.toByteArray());
+            }
+            SIGNATURE = new ArrayList<>();
+            SIGNATURE.add(out);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Helper method to get the used font resource id by typeface.
+     *
+     * If the typeface is created from one of the R.font.large_a, R.font.large_b, R.font.large_c or
+     * R.font.large_d resource, this method returns the resource id used by the typeface.
+     */
+    private static int getSelectedFontResourceId(Typeface typeface) {
+        // The glyph for "a" in R.font.large_a font has a 3em width and glyph for "b", "c" and "d"
+        // have 1em width. Similarly, The glyph for "b" in R.font.large_b font, the glyph for "c"
+        // in R.font.large_c font, the glyph for "d" in R.font.large_d font has 3em width and the
+        // glyph for the rest characters have 1em. Thus we can get the resource id of the source
+        // font file by comparing width of "a", "b", "c" and "d".
+        Paint p = new Paint();
+        p.setTypeface(typeface);
+        final int[] ids = { R.font.large_a, R.font.large_b, R.font.large_c, R.font.large_d };
+        final float[] widths = {
+            p.measureText("a"), p.measureText("b"), p.measureText("c"), p.measureText("d")
+        };
+
+        int maxIndex = Integer.MIN_VALUE;
+        float maxValue = Float.MIN_VALUE;
+        for (int i = 0; i < widths.length; ++i) {
+            if (maxValue < widths[i]) {
+                maxIndex = i;
+                maxValue = widths[i];
+            }
+        }
+        return ids[maxIndex];
+    }
+
+    /**
+     * Helper method to obtain ProviderResourceEntry with overwriting correct signatures.
+     */
+    private ProviderResourceEntry getProviderResourceEntry(int id) {
+        final ProviderResourceEntry entry;
+        try {
+            entry = (ProviderResourceEntry) FontResourcesParserCompat.parse(
+                    mResources.getXml(id), mResources);
+        } catch (XmlPullParserException | IOException e) {
+            throw new RuntimeException(e);
+        }
+        final FontRequest parsedRequest = entry.getRequest();
+        final FontRequest request = new FontRequest(parsedRequest.getProviderAuthority(),
+                parsedRequest.getProviderPackage(), parsedRequest.getQuery(), SIGNATURE);
+        return new ProviderResourceEntry(request, entry.getFetchStrategy(), entry.getTimeout());
+    }
+
+    public static class FontCallback extends ResourcesCompat.FontCallback {
+        private final CountDownLatch mLatch;
+        Typeface mTypeface;
+
+        FontCallback(CountDownLatch latch) {
+            mLatch = latch;
+        }
+
+        @Override
+        public void onFontRetrieved(@NonNull Typeface typeface) {
+            mTypeface = typeface;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onFontRetrievalFailed(int reason) {
+            mLatch.countDown();
+        }
+    }
+
+    @Test
+    public void testCreateFromResourcesFamilyXml_resourceFont_asyncloading() throws Exception {
+        final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.NORMAL, callback,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+
+        assertEquals(R.font.large_a, getSelectedFontResourceId(callback.mTypeface));
+
+        latch = new CountDownLatch(1);
+        final FontCallback callback2 = new FontCallback(latch);
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.ITALIC, callback2,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertEquals(R.font.large_b, getSelectedFontResourceId(callback2.mTypeface));
+
+        latch = new CountDownLatch(1);
+        final FontCallback callback3 = new FontCallback(latch);
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.BOLD, callback3,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertEquals(R.font.large_c, getSelectedFontResourceId(callback3.mTypeface));
+
+        latch = new CountDownLatch(1);
+        final FontCallback callback4 = new FontCallback(latch);
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
+                        R.font.styletest_async_providerfont, Typeface.BOLD_ITALIC, callback4,
+                        null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertEquals(R.font.large_d, getSelectedFontResourceId(callback4.mTypeface));
+    }
+
+    @Test
+    public void testProviderFont_xmlRequest() {
+        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                getProviderResourceEntry(R.font.samplexmldownloadedfontblocking), mResources,
+                R.font.samplexmldownloadedfontblocking, Typeface.NORMAL, null,
+                null /* handler */, true /* isXmlRequest */);
+
+        assertNotNull(typeface);
+        assertNotEquals(Typeface.DEFAULT, typeface);
+    }
+
+    @Test
+    public void testProviderFont_nonXmlRequest_noCallback() {
+        // If we don't give a callback, the request should be blocking.
+        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                getProviderResourceEntry(R.font.samplexmldownloadedfontblocking), mResources,
+                R.font.samplexmldownloadedfontblocking, Typeface.NORMAL, null,
+                null /* handler */, false /* isXmlRequest */);
+
+        assertNotNull(typeface);
+        assertNotEquals(Typeface.DEFAULT, typeface);
+    }
+
+    @Test
+    public void testProviderFont_nonXmlRequest_withCallback() throws InterruptedException {
+        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+        FontsContractCompat.resetCache();
+
+        final Typeface[] result = new Typeface[1];
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
+                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
+                        callback, null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertNotNull(callback.mTypeface);
+        assertNull(result[0]);
+    }
+
+    @Test
+    public void testProviderFont_nonXmlRequest_withCallback_cached() throws InterruptedException {
+        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        CountDownLatch latch = new CountDownLatch(1);
+        final FontCallback callback = new FontCallback(latch);
+        FontsContractCompat.resetCache();
+
+        final Typeface[] result = new Typeface[2];
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
+                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
+                        callback, null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertNotNull(callback.mTypeface);
+        assertNull(result[0]);
+
+        latch = new CountDownLatch(1);
+        final FontCallback callback2 = new FontCallback(latch);
+
+        inst.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                result[1] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
+                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
+                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
+                        callback2, null /* handler */, false /* isXmlRequest */);
+            }
+        });
+        assertTrue(latch.await(5L, TimeUnit.SECONDS));
+        assertNotNull(callback2.mTypeface);
+        assertNotNull(result[1]);
+    }
+
+    @Test
+    public void testCreateFromResourcesFamilyXml_resourceFont() throws Exception {
+        @SuppressLint("ResourceType")
+        // We are retrieving the XML font as an XML resource for testing purposes.
+        final FamilyResourceEntry entry = FontResourcesParserCompat.parse(
+                mResources.getXml(R.font.styletestfont), mResources);
+        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
+                R.font.styletestfont, Typeface.NORMAL, null /* callback */, null /* handler */,
+                false /* isXmlRequest */);
+        Typeface cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.NORMAL);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
+        typeface = Typeface.create(typeface, Typeface.NORMAL);
+        // styletestfont has a node of fontStyle="normal" fontWeight="400" font="@font/large_a".
+        assertEquals(R.font.large_a, getSelectedFontResourceId(typeface));
+
+        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
+                R.font.styletestfont, Typeface.ITALIC, null /* callback */, null /* handler */,
+                false /* isXmlRequest */);
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.ITALIC);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
+        typeface = Typeface.create(typeface, Typeface.ITALIC);
+        // styletestfont has a node of fontStyle="italic" fontWeight="400" font="@font/large_b".
+        assertEquals(R.font.large_b, getSelectedFontResourceId(typeface));
+
+        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
+                R.font.styletestfont, Typeface.BOLD, null /* callback */, null /* handler */,
+                false /* isXmlRequest */);
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.BOLD);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
+        typeface = Typeface.create(typeface, Typeface.BOLD);
+        // styletestfont has a node of fontStyle="normal" fontWeight="700" font="@font/large_c".
+        assertEquals(R.font.large_c, getSelectedFontResourceId(typeface));
+
+        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
+                R.font.styletestfont, Typeface.BOLD_ITALIC, null /* callback */,
+                null /* handler */, false /* isXmlRequest */);
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.styletestfont, Typeface.BOLD_ITALIC);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
+        typeface = Typeface.create(typeface, Typeface.BOLD_ITALIC);
+        // styletestfont has a node of fontStyle="italic" fontWeight="700" font="@font/large_d".
+        assertEquals(R.font.large_d, getSelectedFontResourceId(typeface));
+    }
+
+    private Typeface getLargerTypeface(String text, Typeface typeface1, Typeface typeface2) {
+        Paint p1 = new Paint();
+        p1.setTypeface(typeface1);
+        float width1 = p1.measureText(text);
+        Paint p2 = new Paint();
+        p2.setTypeface(typeface2);
+        float width2 = p2.measureText(text);
+
+        if (width1 > width2) {
+            return typeface1;
+        } else if (width1 < width2) {
+            return typeface2;
+        } else {
+            assertTrue(false);
+            return null;
+        }
+    }
+
+    @Test
+    public void testCreateFromResourcesFamilyXml_resourceTtcFont() throws Exception {
+        // Here we test that building typefaces by indexing in font collections works correctly.
+        // We want to ensure that the built typefaces correspond to the fonts with the right index.
+        // sample_font_collection.ttc contains two fonts (with indices 0 and 1). The first one has
+        // glyph "a" of 3em width, and all the other glyphs 1em. The second one has glyph "b" of
+        // 3em width, and all the other glyphs 1em. Hence, we can compare the width of these
+        // glyphs to assert that ttc indexing works.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+            // Creating typefaces with ttc index was only supported in the API starting with N.
+            return;
+        }
+        final FamilyResourceEntry entry1 = FontResourcesParserCompat.parse(
+                mResources.getXml(R.font.ttctestfont1), mResources);
+        Typeface typeface1 = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry1,
+                mResources, R.font.ttctestfont1, Typeface.NORMAL, null /* callback */,
+                null /*handler */, false /* isXmlRequest */);
+        assertNotNull(typeface1);
+        final FamilyResourceEntry entry2 = FontResourcesParserCompat.parse(
+                mResources.getXml(R.font.ttctestfont2), mResources);
+        Typeface typeface2 = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry2,
+                mResources, R.font.ttctestfont2, Typeface.NORMAL, null /* callback */,
+                null /*handler */, false /* isXmlRequest */);
+        assertNotNull(typeface2);
+
+        assertEquals(getLargerTypeface("a", typeface1, typeface2), typeface1);
+        assertEquals(getLargerTypeface("b", typeface1, typeface2), typeface2);
+    }
+
+    @Test
+    public void testCreateFromResourcesFamilyXml_resourceFontWithVariationSettings()
+            throws Exception {
+        // Here we test that specifying variation settings for fonts in XMLs works correctly.
+        // We build typefaces from two families containing one font each, using the same font
+        // resource, but having different values for the 'wdth' tag. Then we measure the painted
+        // text to ensure that the tag affects the text width. The font resource used supports
+        // the 'wdth' axis for the dash (-) character.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
+            // Variation settings are only supported on O and newer.
+            return;
+        }
+        final FamilyResourceEntry entry1 = FontResourcesParserCompat.parse(
+                mResources.getXml(R.font.variationsettingstestfont1), mResources);
+        Typeface typeface1 = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry1,
+                mResources, R.font.variationsettingstestfont1, Typeface.NORMAL, null /* callback */,
+                null /*handler */, false /* isXmlRequest */);
+        assertNotNull(typeface1);
+        final FamilyResourceEntry entry2 = FontResourcesParserCompat.parse(
+                mResources.getXml(R.font.variationsettingstestfont2), mResources);
+        Typeface typeface2 = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry2,
+                mResources, R.font.variationsettingstestfont2, Typeface.NORMAL, null /* callback */,
+                null /*handler */, false /* isXmlRequest */);
+        assertNotNull(typeface2);
+
+        assertEquals(getLargerTypeface("-", typeface1, typeface2), typeface2);
+    }
+
+    @Test
+    public void testCreateFromResourcesFontFile() {
+        Typeface typeface = TypefaceCompat.createFromResourcesFontFile(mContext, mResources,
+                R.font.large_a, "res/font/large_a.ttf", Typeface.NORMAL);
+        assertNotNull(typeface);
+        Typeface cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.large_a, Typeface.NORMAL);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
+        assertEquals(R.font.large_a, getSelectedFontResourceId(typeface));
+
+        typeface = TypefaceCompat.createFromResourcesFontFile(mContext, mResources, R.font.large_b,
+                "res/font/large_b.ttf", Typeface.NORMAL);
+        assertNotNull(typeface);
+        cachedTypeface = TypefaceCompat.findFromCache(
+                mResources, R.font.large_b, Typeface.NORMAL);
+        assertNotNull(cachedTypeface);
+        assertEquals(typeface, cachedTypeface);
+        assertEquals(R.font.large_b, getSelectedFontResourceId(typeface));
+    }
+}
diff --git a/compat/tests/java/android/support/v4/graphics/TypefaceCompatUtilTest.java b/compat/src/androidTest/java/android/support/v4/graphics/TypefaceCompatUtilTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/graphics/TypefaceCompatUtilTest.java
rename to compat/src/androidTest/java/android/support/v4/graphics/TypefaceCompatUtilTest.java
diff --git a/compat/tests/java/android/support/v4/graphics/drawable/IconCompatTest.java b/compat/src/androidTest/java/android/support/v4/graphics/drawable/IconCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/graphics/drawable/IconCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/graphics/drawable/IconCompatTest.java
diff --git a/core-utils/tests/java/android/support/v4/math/MathUtilsTest.java b/compat/src/androidTest/java/android/support/v4/math/MathUtilsTest.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/math/MathUtilsTest.java
rename to compat/src/androidTest/java/android/support/v4/math/MathUtilsTest.java
diff --git a/compat/tests/java/android/support/v4/os/LocaleListCompatTest.java b/compat/src/androidTest/java/android/support/v4/os/LocaleListCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/os/LocaleListCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/os/LocaleListCompatTest.java
diff --git a/compat/tests/java/android/support/v4/provider/FontRequestTest.java b/compat/src/androidTest/java/android/support/v4/provider/FontRequestTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/provider/FontRequestTest.java
rename to compat/src/androidTest/java/android/support/v4/provider/FontRequestTest.java
diff --git a/compat/tests/java/android/support/v4/provider/FontsContractCompatTest.java b/compat/src/androidTest/java/android/support/v4/provider/FontsContractCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/provider/FontsContractCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/provider/FontsContractCompatTest.java
diff --git a/compat/tests/java/android/support/v4/provider/MockFontProvider.java b/compat/src/androidTest/java/android/support/v4/provider/MockFontProvider.java
similarity index 100%
rename from compat/tests/java/android/support/v4/provider/MockFontProvider.java
rename to compat/src/androidTest/java/android/support/v4/provider/MockFontProvider.java
diff --git a/compat/tests/java/android/support/v4/provider/SelfDestructiveThreadTest.java b/compat/src/androidTest/java/android/support/v4/provider/SelfDestructiveThreadTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/provider/SelfDestructiveThreadTest.java
rename to compat/src/androidTest/java/android/support/v4/provider/SelfDestructiveThreadTest.java
diff --git a/compat/tests/java/android/support/v4/testutils/LayoutDirectionActions.java b/compat/src/androidTest/java/android/support/v4/testutils/LayoutDirectionActions.java
similarity index 100%
rename from compat/tests/java/android/support/v4/testutils/LayoutDirectionActions.java
rename to compat/src/androidTest/java/android/support/v4/testutils/LayoutDirectionActions.java
diff --git a/compat/tests/java/android/support/v4/testutils/TestUtils.java b/compat/src/androidTest/java/android/support/v4/testutils/TestUtils.java
similarity index 100%
rename from compat/tests/java/android/support/v4/testutils/TestUtils.java
rename to compat/src/androidTest/java/android/support/v4/testutils/TestUtils.java
diff --git a/compat/tests/java/android/support/v4/testutils/TextViewActions.java b/compat/src/androidTest/java/android/support/v4/testutils/TextViewActions.java
similarity index 100%
rename from compat/tests/java/android/support/v4/testutils/TextViewActions.java
rename to compat/src/androidTest/java/android/support/v4/testutils/TextViewActions.java
diff --git a/compat/tests/java/android/support/v4/text/BidiFormatterTest.java b/compat/src/androidTest/java/android/support/v4/text/BidiFormatterTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/text/BidiFormatterTest.java
rename to compat/src/androidTest/java/android/support/v4/text/BidiFormatterTest.java
diff --git a/compat/tests/java/android/support/v4/text/IcuCompatTest.java b/compat/src/androidTest/java/android/support/v4/text/IcuCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/text/IcuCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/text/IcuCompatTest.java
diff --git a/compat/src/androidTest/java/android/support/v4/text/util/FindAddressTest.java b/compat/src/androidTest/java/android/support/v4/text/util/FindAddressTest.java
new file mode 100644
index 0000000..b4e1635
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/text/util/FindAddressTest.java
@@ -0,0 +1,608 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.text.util;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.regex.MatchResult;
+
+/**
+ * Tests for FindAddress implementation.
+ *
+ * https://cs.chromium.org/chromium/src/android_webview/javatests/src/org/chromium
+ * /android_webview/test/FindAddressTest.java
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FindAddressTest {
+    private void assertExpectedMatch(MatchResult match, String exptectedMatch) {
+        Assert.assertNotNull(match);
+        Assert.assertEquals(match.group(0), exptectedMatch);
+    }
+
+    private void assertIsAddress(String address) {
+        Assert.assertEquals(address, FindAddress.findAddress(address));
+    }
+
+    private boolean containsAddress(String address) {
+        return FindAddress.findAddress(address) != null;
+    }
+
+    private boolean isAddress(String address) {
+        return FindAddress.findAddress(address).equals(address);
+    }
+
+    @Test
+    public void testFullAddress() {
+        // Test US Google corporate addresses. Expects a full string match.
+        assertIsAddress("1600 Amphitheatre Parkway Mountain View, CA 94043");
+        assertIsAddress("201 S. Division St. Suite 500 Ann Arbor, MI 48104");
+        Assert.assertTrue(containsAddress(
+                "Millennium at Midtown 10 10th Street NE Suite 600 Atlanta, GA 30309"));
+        assertIsAddress("9606 North MoPac Expressway Suite 400 Austin, TX 78759");
+        assertIsAddress("2590 Pearl Street Suite 100 Boulder, CO 80302");
+        assertIsAddress("5 Cambridge Center, Floors 3-6 Cambridge, MA 02142");
+        assertIsAddress("410 Market St Suite 415 Chapel Hill, NC 27516");
+        assertIsAddress("20 West Kinzie St. Chicago, IL 60654");
+        assertIsAddress("114 Willits Street Birmingham, MI 48009");
+        assertIsAddress("19540 Jamboree Road 2nd Floor Irvine, CA 92612");
+        assertIsAddress("747 6th Street South, Kirkland, WA 98033");
+        assertIsAddress("301 S. Blount St. Suite 301 Madison, WI 53703");
+        assertIsAddress("76 Ninth Avenue 4th Floor New York, NY 10011");
+        Assert.assertTrue(containsAddress(
+                "Chelsea Markset Space, 75 Ninth Avenue 2nd and 4th Floors New York, NY 10011"));
+        assertIsAddress("6425 Penn Ave. Suite 700 Pittsburgh, PA 15206");
+        assertIsAddress("1818 Library Street Suite 400 Reston, VA 20190");
+        assertIsAddress("345 Spear Street Floors 2-4 San Francisco, CA 94105");
+        assertIsAddress("604 Arizona Avenue Santa Monica, CA 90401");
+        assertIsAddress("651 N. 34th St. Seattle, WA 98103");
+        Assert.assertTrue(
+                isAddress("1101 New York Avenue, N.W. Second Floor Washington, DC 20005"));
+
+        // Other tests.
+        assertIsAddress("57th Street and Lake Shore Drive\nChicago, IL 60637");
+        assertIsAddress("308 Congress Street Boston, MA 02210");
+        Assert.assertTrue(
+                containsAddress("Central Park West at 79th Street, New York, NY, 10024-5192"));
+        Assert.assertTrue(containsAddress(
+                "Lincoln Park | 100 34th Avenue • San Francisco, CA 94121 | 41575036"));
+
+        Assert.assertEquals(
+                FindAddress.findAddress(
+                        "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do "
+                                + "1600 Amphitheatre Parkway Mountain View, CA 94043 eiusmod "
+                                + "tempor incididunt ut labore et dolore magna aliqua."),
+                "1600 Amphitheatre Parkway Mountain View, CA 94043");
+
+        Assert.assertEquals(FindAddress.findAddress("2590 Pearl Street Suite 100 Boulder, CO 80302 "
+                        + "6425 Penn Ave. Suite 700 Pittsburgh, PA 15206"),
+                "2590 Pearl Street Suite 100 Boulder, CO 80302");
+
+        assertIsAddress("5400 Preston Oaks Rd Dallas TX 75254");
+        assertIsAddress("5400 Preston Oaks Road Dallas TX 75254");
+        assertIsAddress("5400 Preston Oaks Ave Dallas TX 75254");
+
+        Assert.assertTrue(
+                containsAddress("住所は 1600 Amphitheatre Parkway Mountain View, CA 94043 です。"));
+
+        Assert.assertFalse(containsAddress("1 st. too-short, CA 90000"));
+        Assert.assertTrue(containsAddress("1 st. long enough, CA 90000"));
+
+        Assert.assertTrue(containsAddress("1 st. some city in al 35000"));
+        Assert.assertFalse(containsAddress("1 book st Aquinas et al 35000"));
+
+        Assert.assertFalse(containsAddress("1 this comes too late: street, CA 90000"));
+        Assert.assertTrue(containsAddress("1 this is ok: street, CA 90000"));
+
+        Assert.assertFalse(
+                containsAddress("1 street I love verbosity, so I'm writing an address with "
+                        + "too many words CA 90000"));
+        Assert.assertTrue(containsAddress("1 street 2 3 4 5 6 7 8 9 10 11 12, CA 90000"));
+
+        assertIsAddress("79th Street 1st Floor New York City, NY 10024-5192");
+
+        assertIsAddress("79th Street 1st Floor New York 10024-5192");
+        assertIsAddress("79th Street 1st Floor New  York 10024-5192");
+        Assert.assertNull(FindAddress.findAddress("79th Street 1st Floor New\nYork 10024-5192"));
+        Assert.assertNull(FindAddress.findAddress("79th Street 1st Floor New, York 10024-5192"));
+
+        Assert.assertFalse(containsAddress("123 Fake Street, Springfield, Springfield"));
+        Assert.assertFalse(containsAddress("999 Street Avenue, City, ZZ 98765"));
+        Assert.assertFalse(containsAddress("76 Here be dragons, CA 94043"));
+        Assert.assertFalse(containsAddress("1 This, has, too* many, lines, to, be* valid"));
+        Assert.assertFalse(
+                containsAddress("1 Supercalifragilisticexpialidocious is too long, CA 90000"));
+        Assert.assertFalse(containsAddress(""));
+    }
+
+    @Test
+    public void testFullAddressWithoutZipCode() {
+        assertIsAddress("1600 Amphitheatre Parkway Mountain View, CA");
+        assertIsAddress("201 S. Division St. Suite 500 Ann Arbor, MI");
+    }
+
+    @Test
+    public void testNumberPrefixCases() {
+        Assert.assertEquals(
+                FindAddress.findAddress("Cafe 21\n750 Fifth Ave. San Diego, California 92101"),
+                "750 Fifth Ave. San Diego, California 92101");
+        Assert.assertEquals(
+                FindAddress.findAddress(
+                        "Century City 15\n 10250 Santa Monica Boulevard Los Angeles, CA 90067"),
+                "10250 Santa Monica Boulevard Los Angeles, CA 90067");
+        Assert.assertEquals(FindAddress.findAddress("123 45\n67 My Street, Somewhere, NY 10000"),
+                "67 My Street, Somewhere, NY 10000");
+        assertIsAddress("123 4th Avenue, Somewhere in NY 10000");
+    }
+
+    @Test
+    public void testLocationName() {
+        Assert.assertFalse(FindAddress.isValidLocationName("str-eet"));
+        Assert.assertFalse(FindAddress.isValidLocationName("somewhere"));
+
+        // Test all supported street names and expected plural cases.
+        Assert.assertTrue(FindAddress.isValidLocationName("alley"));
+        Assert.assertTrue(FindAddress.isValidLocationName("annex"));
+        Assert.assertTrue(FindAddress.isValidLocationName("arcade"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ave."));
+        Assert.assertTrue(FindAddress.isValidLocationName("avenue"));
+        Assert.assertTrue(FindAddress.isValidLocationName("alameda"));
+        Assert.assertTrue(FindAddress.isValidLocationName("bayou"));
+        Assert.assertTrue(FindAddress.isValidLocationName("beach"));
+        Assert.assertTrue(FindAddress.isValidLocationName("bend"));
+        Assert.assertTrue(FindAddress.isValidLocationName("bluff"));
+        Assert.assertTrue(FindAddress.isValidLocationName("bluffs"));
+        Assert.assertTrue(FindAddress.isValidLocationName("bottom"));
+        Assert.assertTrue(FindAddress.isValidLocationName("boulevard"));
+        Assert.assertTrue(FindAddress.isValidLocationName("branch"));
+        Assert.assertTrue(FindAddress.isValidLocationName("bridge"));
+        Assert.assertTrue(FindAddress.isValidLocationName("brook"));
+        Assert.assertTrue(FindAddress.isValidLocationName("brooks"));
+        Assert.assertTrue(FindAddress.isValidLocationName("burg"));
+        Assert.assertTrue(FindAddress.isValidLocationName("burgs"));
+        Assert.assertTrue(FindAddress.isValidLocationName("bypass"));
+        Assert.assertTrue(FindAddress.isValidLocationName("broadway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("camino"));
+        Assert.assertTrue(FindAddress.isValidLocationName("camp"));
+        Assert.assertTrue(FindAddress.isValidLocationName("canyon"));
+        Assert.assertTrue(FindAddress.isValidLocationName("cape"));
+        Assert.assertTrue(FindAddress.isValidLocationName("causeway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("center"));
+        Assert.assertTrue(FindAddress.isValidLocationName("centers"));
+        Assert.assertTrue(FindAddress.isValidLocationName("circle"));
+        Assert.assertTrue(FindAddress.isValidLocationName("circles"));
+        Assert.assertTrue(FindAddress.isValidLocationName("cliff"));
+        Assert.assertTrue(FindAddress.isValidLocationName("cliffs"));
+        Assert.assertTrue(FindAddress.isValidLocationName("club"));
+        Assert.assertTrue(FindAddress.isValidLocationName("common"));
+        Assert.assertTrue(FindAddress.isValidLocationName("corner"));
+        Assert.assertTrue(FindAddress.isValidLocationName("corners"));
+        Assert.assertTrue(FindAddress.isValidLocationName("course"));
+        Assert.assertTrue(FindAddress.isValidLocationName("court"));
+        Assert.assertTrue(FindAddress.isValidLocationName("courts"));
+        Assert.assertTrue(FindAddress.isValidLocationName("cove"));
+        Assert.assertTrue(FindAddress.isValidLocationName("coves"));
+        Assert.assertTrue(FindAddress.isValidLocationName("creek"));
+        Assert.assertTrue(FindAddress.isValidLocationName("crescent"));
+        Assert.assertTrue(FindAddress.isValidLocationName("crest"));
+        Assert.assertTrue(FindAddress.isValidLocationName("crossing"));
+        Assert.assertTrue(FindAddress.isValidLocationName("crossroad"));
+        Assert.assertTrue(FindAddress.isValidLocationName("curve"));
+        Assert.assertTrue(FindAddress.isValidLocationName("circulo"));
+        Assert.assertTrue(FindAddress.isValidLocationName("dale"));
+        Assert.assertTrue(FindAddress.isValidLocationName("dam"));
+        Assert.assertTrue(FindAddress.isValidLocationName("divide"));
+        Assert.assertTrue(FindAddress.isValidLocationName("drive"));
+        Assert.assertTrue(FindAddress.isValidLocationName("drives"));
+        Assert.assertTrue(FindAddress.isValidLocationName("estate"));
+        Assert.assertTrue(FindAddress.isValidLocationName("estates"));
+        Assert.assertTrue(FindAddress.isValidLocationName("expressway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("extension"));
+        Assert.assertTrue(FindAddress.isValidLocationName("extensions"));
+        Assert.assertTrue(FindAddress.isValidLocationName("fall"));
+        Assert.assertTrue(FindAddress.isValidLocationName("falls"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ferry"));
+        Assert.assertTrue(FindAddress.isValidLocationName("field"));
+        Assert.assertTrue(FindAddress.isValidLocationName("fields"));
+        Assert.assertTrue(FindAddress.isValidLocationName("flat"));
+        Assert.assertTrue(FindAddress.isValidLocationName("flats"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ford"));
+        Assert.assertTrue(FindAddress.isValidLocationName("fords"));
+        Assert.assertTrue(FindAddress.isValidLocationName("forest"));
+        Assert.assertTrue(FindAddress.isValidLocationName("forge"));
+        Assert.assertTrue(FindAddress.isValidLocationName("forges"));
+        Assert.assertTrue(FindAddress.isValidLocationName("fork"));
+        Assert.assertTrue(FindAddress.isValidLocationName("forks"));
+        Assert.assertTrue(FindAddress.isValidLocationName("fort"));
+        Assert.assertTrue(FindAddress.isValidLocationName("freeway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("garden"));
+        Assert.assertTrue(FindAddress.isValidLocationName("gardens"));
+        Assert.assertTrue(FindAddress.isValidLocationName("gateway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("glen"));
+        Assert.assertTrue(FindAddress.isValidLocationName("glens"));
+        Assert.assertTrue(FindAddress.isValidLocationName("green"));
+        Assert.assertTrue(FindAddress.isValidLocationName("greens"));
+        Assert.assertTrue(FindAddress.isValidLocationName("grove"));
+        Assert.assertTrue(FindAddress.isValidLocationName("groves"));
+        Assert.assertTrue(FindAddress.isValidLocationName("harbor"));
+        Assert.assertTrue(FindAddress.isValidLocationName("harbors"));
+        Assert.assertTrue(FindAddress.isValidLocationName("haven"));
+        Assert.assertTrue(FindAddress.isValidLocationName("heights"));
+        Assert.assertTrue(FindAddress.isValidLocationName("highway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("hill"));
+        Assert.assertTrue(FindAddress.isValidLocationName("hills"));
+        Assert.assertTrue(FindAddress.isValidLocationName("hollow"));
+        Assert.assertTrue(FindAddress.isValidLocationName("inlet"));
+        Assert.assertTrue(FindAddress.isValidLocationName("island"));
+        Assert.assertTrue(FindAddress.isValidLocationName("islands"));
+        Assert.assertTrue(FindAddress.isValidLocationName("isle"));
+        Assert.assertTrue(FindAddress.isValidLocationName("junction"));
+        Assert.assertTrue(FindAddress.isValidLocationName("junctions"));
+        Assert.assertTrue(FindAddress.isValidLocationName("key"));
+        Assert.assertTrue(FindAddress.isValidLocationName("keys"));
+        Assert.assertTrue(FindAddress.isValidLocationName("knoll"));
+        Assert.assertTrue(FindAddress.isValidLocationName("knolls"));
+        Assert.assertTrue(FindAddress.isValidLocationName("lake"));
+        Assert.assertTrue(FindAddress.isValidLocationName("lakes"));
+        Assert.assertTrue(FindAddress.isValidLocationName("land"));
+        Assert.assertTrue(FindAddress.isValidLocationName("landing"));
+        Assert.assertTrue(FindAddress.isValidLocationName("lane"));
+        Assert.assertTrue(FindAddress.isValidLocationName("light"));
+        Assert.assertTrue(FindAddress.isValidLocationName("lights"));
+        Assert.assertTrue(FindAddress.isValidLocationName("loaf"));
+        Assert.assertTrue(FindAddress.isValidLocationName("lock"));
+        Assert.assertTrue(FindAddress.isValidLocationName("locks"));
+        Assert.assertTrue(FindAddress.isValidLocationName("lodge"));
+        Assert.assertTrue(FindAddress.isValidLocationName("loop"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mall"));
+        Assert.assertTrue(FindAddress.isValidLocationName("manor"));
+        Assert.assertTrue(FindAddress.isValidLocationName("manors"));
+        Assert.assertTrue(FindAddress.isValidLocationName("meadow"));
+        Assert.assertTrue(FindAddress.isValidLocationName("meadows"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mews"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mill"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mills"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mission"));
+        Assert.assertTrue(FindAddress.isValidLocationName("motorway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mount"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mountain"));
+        Assert.assertTrue(FindAddress.isValidLocationName("mountains"));
+        Assert.assertTrue(FindAddress.isValidLocationName("neck"));
+        Assert.assertTrue(FindAddress.isValidLocationName("orchard"));
+        Assert.assertTrue(FindAddress.isValidLocationName("oval"));
+        Assert.assertTrue(FindAddress.isValidLocationName("overpass"));
+        Assert.assertTrue(FindAddress.isValidLocationName("park"));
+        Assert.assertTrue(FindAddress.isValidLocationName("parks"));
+        Assert.assertTrue(FindAddress.isValidLocationName("parkway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("parkways"));
+        Assert.assertTrue(FindAddress.isValidLocationName("pass"));
+        Assert.assertTrue(FindAddress.isValidLocationName("passage"));
+        Assert.assertTrue(FindAddress.isValidLocationName("path"));
+        Assert.assertTrue(FindAddress.isValidLocationName("pike"));
+        Assert.assertTrue(FindAddress.isValidLocationName("pine"));
+        Assert.assertTrue(FindAddress.isValidLocationName("pines"));
+        Assert.assertTrue(FindAddress.isValidLocationName("plain"));
+        Assert.assertTrue(FindAddress.isValidLocationName("plains"));
+        Assert.assertTrue(FindAddress.isValidLocationName("plaza"));
+        Assert.assertTrue(FindAddress.isValidLocationName("point"));
+        Assert.assertTrue(FindAddress.isValidLocationName("points"));
+        Assert.assertTrue(FindAddress.isValidLocationName("port"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ports"));
+        Assert.assertTrue(FindAddress.isValidLocationName("prairie"));
+        Assert.assertTrue(FindAddress.isValidLocationName("privada"));
+        Assert.assertTrue(FindAddress.isValidLocationName("radial"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ramp"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ranch"));
+        Assert.assertTrue(FindAddress.isValidLocationName("rapid"));
+        Assert.assertTrue(FindAddress.isValidLocationName("rapids"));
+        Assert.assertTrue(FindAddress.isValidLocationName("rd"));
+        Assert.assertTrue(FindAddress.isValidLocationName("rd."));
+        Assert.assertTrue(FindAddress.isValidLocationName("rest"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ridge"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ridges"));
+        Assert.assertTrue(FindAddress.isValidLocationName("river"));
+        Assert.assertTrue(FindAddress.isValidLocationName("road"));
+        Assert.assertTrue(FindAddress.isValidLocationName("roads"));
+        Assert.assertTrue(FindAddress.isValidLocationName("route"));
+        Assert.assertTrue(FindAddress.isValidLocationName("row"));
+        Assert.assertTrue(FindAddress.isValidLocationName("rue"));
+        Assert.assertTrue(FindAddress.isValidLocationName("run"));
+        Assert.assertTrue(FindAddress.isValidLocationName("shoal"));
+        Assert.assertTrue(FindAddress.isValidLocationName("shoals"));
+        Assert.assertTrue(FindAddress.isValidLocationName("shore"));
+        Assert.assertTrue(FindAddress.isValidLocationName("shores"));
+        Assert.assertTrue(FindAddress.isValidLocationName("skyway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("spring"));
+        Assert.assertTrue(FindAddress.isValidLocationName("springs"));
+        Assert.assertTrue(FindAddress.isValidLocationName("spur"));
+        Assert.assertTrue(FindAddress.isValidLocationName("spurs"));
+        Assert.assertTrue(FindAddress.isValidLocationName("square"));
+        Assert.assertTrue(FindAddress.isValidLocationName("squares"));
+        Assert.assertTrue(FindAddress.isValidLocationName("station"));
+        Assert.assertTrue(FindAddress.isValidLocationName("stravenue"));
+        Assert.assertTrue(FindAddress.isValidLocationName("stream"));
+        Assert.assertTrue(FindAddress.isValidLocationName("st."));
+        Assert.assertTrue(FindAddress.isValidLocationName("street"));
+        Assert.assertTrue(FindAddress.isValidLocationName("streets"));
+        Assert.assertTrue(FindAddress.isValidLocationName("summit"));
+        Assert.assertTrue(FindAddress.isValidLocationName("speedway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("terrace"));
+        Assert.assertTrue(FindAddress.isValidLocationName("throughway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("trace"));
+        Assert.assertTrue(FindAddress.isValidLocationName("track"));
+        Assert.assertTrue(FindAddress.isValidLocationName("trafficway"));
+        Assert.assertTrue(FindAddress.isValidLocationName("trail"));
+        Assert.assertTrue(FindAddress.isValidLocationName("tunnel"));
+        Assert.assertTrue(FindAddress.isValidLocationName("turnpike"));
+        Assert.assertTrue(FindAddress.isValidLocationName("underpass"));
+        Assert.assertTrue(FindAddress.isValidLocationName("union"));
+        Assert.assertTrue(FindAddress.isValidLocationName("unions"));
+        Assert.assertTrue(FindAddress.isValidLocationName("valley"));
+        Assert.assertTrue(FindAddress.isValidLocationName("valleys"));
+        Assert.assertTrue(FindAddress.isValidLocationName("viaduct"));
+        Assert.assertTrue(FindAddress.isValidLocationName("view"));
+        Assert.assertTrue(FindAddress.isValidLocationName("views"));
+        Assert.assertTrue(FindAddress.isValidLocationName("village"));
+        Assert.assertTrue(FindAddress.isValidLocationName("villages"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ville"));
+        Assert.assertTrue(FindAddress.isValidLocationName("vista"));
+        Assert.assertTrue(FindAddress.isValidLocationName("walk"));
+        Assert.assertTrue(FindAddress.isValidLocationName("walks"));
+        Assert.assertTrue(FindAddress.isValidLocationName("wall"));
+        Assert.assertTrue(FindAddress.isValidLocationName("way"));
+        Assert.assertTrue(FindAddress.isValidLocationName("ways"));
+        Assert.assertTrue(FindAddress.isValidLocationName("well"));
+        Assert.assertTrue(FindAddress.isValidLocationName("wells"));
+        Assert.assertTrue(FindAddress.isValidLocationName("xing"));
+        Assert.assertTrue(FindAddress.isValidLocationName("xrd"));
+    }
+
+    @Test
+    public void testZipCode() {
+        Assert.assertTrue(FindAddress.isValidZipCode("90000"));
+        Assert.assertTrue(FindAddress.isValidZipCode("01234"));
+        Assert.assertTrue(FindAddress.isValidZipCode("99999-9999"));
+
+        Assert.assertFalse(FindAddress.isValidZipCode("999999999"));
+        Assert.assertFalse(FindAddress.isValidZipCode("9999-99999"));
+        Assert.assertFalse(FindAddress.isValidZipCode("999999999-"));
+        Assert.assertFalse(FindAddress.isValidZipCode("99999-999a"));
+        Assert.assertFalse(FindAddress.isValidZipCode("99999--9999"));
+        Assert.assertFalse(FindAddress.isValidZipCode("90000o"));
+        Assert.assertFalse(FindAddress.isValidZipCode("90000-"));
+
+        // Test the state index against the zip range table.
+        Assert.assertTrue(FindAddress.isValidZipCode("99000", "AK"));
+        Assert.assertTrue(FindAddress.isValidZipCode("99000", "Alaska"));
+        Assert.assertTrue(FindAddress.isValidZipCode("35000", "AL"));
+        Assert.assertTrue(FindAddress.isValidZipCode("36000", "Alabama"));
+        Assert.assertTrue(FindAddress.isValidZipCode("71000", "AR"));
+        Assert.assertTrue(FindAddress.isValidZipCode("72000", "Arkansas"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "AS"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "American Samoa"));
+        Assert.assertTrue(FindAddress.isValidZipCode("85000", "AZ"));
+        Assert.assertTrue(FindAddress.isValidZipCode("86000", "Arizona"));
+        Assert.assertTrue(FindAddress.isValidZipCode("90000", "CA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "California"));
+        Assert.assertTrue(FindAddress.isValidZipCode("80000", "CO"));
+        Assert.assertTrue(FindAddress.isValidZipCode("81000", "Colorado"));
+        Assert.assertTrue(FindAddress.isValidZipCode("06000", "CT"));
+        Assert.assertTrue(FindAddress.isValidZipCode("06000", "Connecticut"));
+        Assert.assertTrue(FindAddress.isValidZipCode("20000", "DC"));
+        Assert.assertTrue(FindAddress.isValidZipCode("20000", "District of Columbia"));
+        Assert.assertTrue(FindAddress.isValidZipCode("19000", "DE"));
+        Assert.assertTrue(FindAddress.isValidZipCode("19000", "Delaware"));
+        Assert.assertTrue(FindAddress.isValidZipCode("32000", "FL"));
+        Assert.assertTrue(FindAddress.isValidZipCode("34000", "Florida"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "FM"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "Federated States of Micronesia"));
+        Assert.assertTrue(FindAddress.isValidZipCode("30000", "GA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("31000", "Georgia"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "GU"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "Guam"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "HI"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "Hawaii"));
+        Assert.assertTrue(FindAddress.isValidZipCode("50000", "IA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("52000", "Iowa"));
+        Assert.assertTrue(FindAddress.isValidZipCode("83000", "ID"));
+        Assert.assertTrue(FindAddress.isValidZipCode("83000", "Idaho"));
+        Assert.assertTrue(FindAddress.isValidZipCode("60000", "IL"));
+        Assert.assertTrue(FindAddress.isValidZipCode("62000", "Illinois"));
+        Assert.assertTrue(FindAddress.isValidZipCode("46000", "IN"));
+        Assert.assertTrue(FindAddress.isValidZipCode("47000", "Indiana"));
+        Assert.assertTrue(FindAddress.isValidZipCode("66000", "KS"));
+        Assert.assertTrue(FindAddress.isValidZipCode("67000", "Kansas"));
+        Assert.assertTrue(FindAddress.isValidZipCode("40000", "KY"));
+        Assert.assertTrue(FindAddress.isValidZipCode("42000", "Kentucky"));
+        Assert.assertTrue(FindAddress.isValidZipCode("70000", "LA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("71000", "Louisiana"));
+        Assert.assertTrue(FindAddress.isValidZipCode("01000", "MA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("02000", "Massachusetts"));
+        Assert.assertTrue(FindAddress.isValidZipCode("20000", "MD"));
+        Assert.assertTrue(FindAddress.isValidZipCode("21000", "Maryland"));
+        Assert.assertTrue(FindAddress.isValidZipCode("03000", "ME"));
+        Assert.assertTrue(FindAddress.isValidZipCode("04000", "Maine"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "MH"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "Marshall Islands"));
+        Assert.assertTrue(FindAddress.isValidZipCode("48000", "MI"));
+        Assert.assertTrue(FindAddress.isValidZipCode("49000", "Michigan"));
+        Assert.assertTrue(FindAddress.isValidZipCode("55000", "MN"));
+        Assert.assertTrue(FindAddress.isValidZipCode("56000", "Minnesota"));
+        Assert.assertTrue(FindAddress.isValidZipCode("63000", "MO"));
+        Assert.assertTrue(FindAddress.isValidZipCode("65000", "Missouri"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "MP"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "Northern Mariana Islands"));
+        Assert.assertTrue(FindAddress.isValidZipCode("38000", "MS"));
+        Assert.assertTrue(FindAddress.isValidZipCode("39000", "Mississippi"));
+        Assert.assertTrue(FindAddress.isValidZipCode("55000", "MT"));
+        Assert.assertTrue(FindAddress.isValidZipCode("56000", "Montana"));
+        Assert.assertTrue(FindAddress.isValidZipCode("27000", "NC"));
+        Assert.assertTrue(FindAddress.isValidZipCode("28000", "North Carolina"));
+        Assert.assertTrue(FindAddress.isValidZipCode("58000", "ND"));
+        Assert.assertTrue(FindAddress.isValidZipCode("58000", "North Dakota"));
+        Assert.assertTrue(FindAddress.isValidZipCode("68000", "NE"));
+        Assert.assertTrue(FindAddress.isValidZipCode("69000", "Nebraska"));
+        Assert.assertTrue(FindAddress.isValidZipCode("03000", "NH"));
+        Assert.assertTrue(FindAddress.isValidZipCode("04000", "New Hampshire"));
+        Assert.assertTrue(FindAddress.isValidZipCode("07000", "NJ"));
+        Assert.assertTrue(FindAddress.isValidZipCode("08000", "New Jersey"));
+        Assert.assertTrue(FindAddress.isValidZipCode("87000", "NM"));
+        Assert.assertTrue(FindAddress.isValidZipCode("88000", "New Mexico"));
+        Assert.assertTrue(FindAddress.isValidZipCode("88000", "NV"));
+        Assert.assertTrue(FindAddress.isValidZipCode("89000", "Nevada"));
+        Assert.assertTrue(FindAddress.isValidZipCode("10000", "NY"));
+        Assert.assertTrue(FindAddress.isValidZipCode("14000", "New York"));
+        Assert.assertTrue(FindAddress.isValidZipCode("43000", "OH"));
+        Assert.assertTrue(FindAddress.isValidZipCode("45000", "Ohio"));
+        Assert.assertTrue(FindAddress.isValidZipCode("73000", "OK"));
+        Assert.assertTrue(FindAddress.isValidZipCode("74000", "Oklahoma"));
+        Assert.assertTrue(FindAddress.isValidZipCode("97000", "OR"));
+        Assert.assertTrue(FindAddress.isValidZipCode("97000", "Oregon"));
+        Assert.assertTrue(FindAddress.isValidZipCode("15000", "PA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("19000", "Pennsylvania"));
+        Assert.assertTrue(FindAddress.isValidZipCode("06000", "PR"));
+        Assert.assertTrue(FindAddress.isValidZipCode("06000", "Puerto Rico"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "PW"));
+        Assert.assertTrue(FindAddress.isValidZipCode("96000", "Palau"));
+        Assert.assertTrue(FindAddress.isValidZipCode("02000", "RI"));
+        Assert.assertTrue(FindAddress.isValidZipCode("02000", "Rhode Island"));
+        Assert.assertTrue(FindAddress.isValidZipCode("29000", "SC"));
+        Assert.assertTrue(FindAddress.isValidZipCode("29000", "South Carolina"));
+        Assert.assertTrue(FindAddress.isValidZipCode("57000", "SD"));
+        Assert.assertTrue(FindAddress.isValidZipCode("57000", "South Dakota"));
+        Assert.assertTrue(FindAddress.isValidZipCode("37000", "TN"));
+        Assert.assertTrue(FindAddress.isValidZipCode("38000", "Tennessee"));
+        Assert.assertTrue(FindAddress.isValidZipCode("75000", "TX"));
+        Assert.assertTrue(FindAddress.isValidZipCode("79000", "Texas"));
+        Assert.assertTrue(FindAddress.isValidZipCode("84000", "UT"));
+        Assert.assertTrue(FindAddress.isValidZipCode("84000", "Utah"));
+        Assert.assertTrue(FindAddress.isValidZipCode("22000", "VA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("24000", "Virginia"));
+        Assert.assertTrue(FindAddress.isValidZipCode("06000", "VI"));
+        Assert.assertTrue(FindAddress.isValidZipCode("09000", "Virgin Islands"));
+        Assert.assertTrue(FindAddress.isValidZipCode("05000", "VT"));
+        Assert.assertTrue(FindAddress.isValidZipCode("05000", "Vermont"));
+        Assert.assertTrue(FindAddress.isValidZipCode("98000", "WA"));
+        Assert.assertTrue(FindAddress.isValidZipCode("99000", "Washington"));
+        Assert.assertTrue(FindAddress.isValidZipCode("53000", "WI"));
+        Assert.assertTrue(FindAddress.isValidZipCode("54000", "Wisconsin"));
+        Assert.assertTrue(FindAddress.isValidZipCode("24000", "WV"));
+        Assert.assertTrue(FindAddress.isValidZipCode("26000", "West Virginia"));
+        Assert.assertTrue(FindAddress.isValidZipCode("82000", "WY"));
+        Assert.assertTrue(FindAddress.isValidZipCode("83000", "Wyoming"));
+    }
+
+    @Test
+    public void testMatchState() {
+        // The complete set of state codes and names is tested together
+        // with their returned state indices in the zip code test.
+        assertExpectedMatch(FindAddress.matchState("CALIFORNIA", 0), "CALIFORNIA");
+        assertExpectedMatch(FindAddress.matchState("ca", 0), "ca");
+
+        assertExpectedMatch(FindAddress.matchState(" CALIFORNIA", 1), "CALIFORNIA");
+        assertExpectedMatch(FindAddress.matchState(" ca", 1), "ca");
+
+        Assert.assertNull(FindAddress.matchState("notcalifornia", 3));
+        Assert.assertNull(FindAddress.matchState("californi", 0));
+        Assert.assertNull(FindAddress.matchState("northern mariana", 0));
+        Assert.assertNull(FindAddress.matchState("northern mariana island", 0));
+        Assert.assertNull(FindAddress.matchState("zz", 0));
+    }
+
+    @Test
+    public void testGetHouseNumber() {
+        assertExpectedMatch(FindAddress.matchHouseNumber("4", 0), "4");
+
+        // Matches not at the start of the string should be preceded by a valid delimiter.
+        assertExpectedMatch(FindAddress.matchHouseNumber(" 4", 1), "4");
+        assertExpectedMatch(FindAddress.matchHouseNumber(",4", 1), "4");
+        Assert.assertNull(FindAddress.matchHouseNumber("x4", 1));
+
+        // Matches should be followed by a valid delimiter.
+        assertExpectedMatch(FindAddress.matchHouseNumber("4,5", 0), "4");
+        Assert.assertNull(FindAddress.matchHouseNumber("4?", 0));
+        Assert.assertNull(FindAddress.matchHouseNumber("4:", 0));
+
+        // Quotes are valid delimiters.
+        assertExpectedMatch(FindAddress.matchHouseNumber("\"4\"", 1), "4");
+        assertExpectedMatch(FindAddress.matchHouseNumber("'4'", 1), "4");
+
+        // Matches shouldn't include the delimiter, or anything after it.
+        assertExpectedMatch(FindAddress.matchHouseNumber("4 my house", 0), "4");
+
+        // One is a valid house number.
+        assertExpectedMatch(FindAddress.matchHouseNumber("one", 0), "one");
+
+        // One can't be an ordinal though.
+        Assert.assertNull(FindAddress.matchHouseNumber("oneth", 0));
+
+        // House numbers can be followed by a single letter.
+        assertExpectedMatch(FindAddress.matchHouseNumber("1A", 0), "1A");
+
+        // But not two.
+        Assert.assertNull(FindAddress.matchHouseNumber("1AA", 0));
+
+        // Except if it's a valid ordinal.
+        assertExpectedMatch(FindAddress.matchHouseNumber("1st", 0), "1st");
+        assertExpectedMatch(FindAddress.matchHouseNumber("1ST", 0), "1ST");
+        assertExpectedMatch(FindAddress.matchHouseNumber("11th", 0), "11th");
+        assertExpectedMatch(FindAddress.matchHouseNumber("21st", 0), "21st");
+
+        assertExpectedMatch(FindAddress.matchHouseNumber("2nd", 0), "2nd");
+        assertExpectedMatch(FindAddress.matchHouseNumber("12th", 0), "12th");
+        assertExpectedMatch(FindAddress.matchHouseNumber("22nd", 0), "22nd");
+
+        assertExpectedMatch(FindAddress.matchHouseNumber("3rd", 0), "3rd");
+        assertExpectedMatch(FindAddress.matchHouseNumber("13th", 0), "13th");
+        assertExpectedMatch(FindAddress.matchHouseNumber("23rd", 0), "23rd");
+
+        Assert.assertNull(FindAddress.matchHouseNumber("11st", 0));
+        Assert.assertNull(FindAddress.matchHouseNumber("21th", 0));
+        Assert.assertNull(FindAddress.matchHouseNumber("1nd", 0));
+
+        // These two cases are different from the original C++
+        // implementation (which didn't match numbers in these cases).
+        assertExpectedMatch(FindAddress.matchHouseNumber("111th", 0), "111th");
+        assertExpectedMatch(FindAddress.matchHouseNumber("011th", 0), "011th");
+
+        // This case used to match, but now doesn't.
+        Assert.assertNull(FindAddress.matchHouseNumber("211st", 0));
+
+        // Hypenated numbers are OK.
+        assertExpectedMatch(FindAddress.matchHouseNumber("1-201", 0), "1-201");
+        assertExpectedMatch(FindAddress.matchHouseNumber("1-one", 0), "1-one");
+
+        // But a trailing hypen isn't valid.
+        Assert.assertNull(FindAddress.matchHouseNumber("1- ", 0));
+        Assert.assertNull(FindAddress.matchHouseNumber("1-word", 0));
+
+        // Ordinals can be part of a hyphenated number.
+        assertExpectedMatch(FindAddress.matchHouseNumber("1-1st", 0), "1-1st");
+
+        // Limit of 5 digits at most.
+        assertExpectedMatch(FindAddress.matchHouseNumber("12345", 0), "12345");
+        Assert.assertNull(FindAddress.matchHouseNumber("123456", 0));
+
+        // Limit applies to the whole match, not the components.
+        Assert.assertNull(FindAddress.matchHouseNumber("123-456", 0));
+    }
+}
diff --git a/compat/src/androidTest/java/android/support/v4/text/util/LinkifyCompatTest.java b/compat/src/androidTest/java/android/support/v4/text/util/LinkifyCompatTest.java
new file mode 100644
index 0000000..afaf879
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/text/util/LinkifyCompatTest.java
@@ -0,0 +1,863 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.text.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.util.PatternsCompat;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.URLSpan;
+import android.text.util.Linkify;
+import android.text.util.Linkify.MatchFilter;
+import android.text.util.Linkify.TransformFilter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Test {@link LinkifyCompat}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LinkifyCompatTest {
+    private static final Pattern LINKIFY_TEST_PATTERN = Pattern.compile(
+            "(test:)?[a-zA-Z0-9]+(\\.pattern)?");
+
+    private MatchFilter mMatchFilterStartWithDot = new MatchFilter() {
+        @Override
+        public boolean acceptMatch(final CharSequence s, final int start, final int end) {
+            if (start == 0) {
+                return true;
+            }
+
+            if (s.charAt(start - 1) == '.') {
+                return false;
+            }
+
+            return true;
+        }
+    };
+
+    private TransformFilter mTransformFilterUpperChar = new TransformFilter() {
+        @Override
+        public String transformUrl(final Matcher match, String url) {
+            StringBuilder buffer = new StringBuilder();
+            String matchingRegion = match.group();
+
+            for (int i = 0, size = matchingRegion.length(); i < size; i++) {
+                char character = matchingRegion.charAt(i);
+
+                if (character == '.' || Character.isLowerCase(character)
+                        || Character.isDigit(character)) {
+                    buffer.append(character);
+                }
+            }
+            return buffer.toString();
+        }
+    };
+
+    @Test
+    public void testAddLinksToSpannable() {
+        // Verify URLs including the ones that have new gTLDs, and the
+        // ones that look like gTLDs (and so are accepted by linkify)
+        // and the ones that should not be linkified due to non-compliant
+        // gTLDs
+        final String longGTLD =
+                "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabc";
+        SpannableString spannable = new SpannableString("name@gmail.com, "
+                + "www.google.com, http://www.google.com/language_tools?hl=en, "
+                + "a.bd, "   // a URL with accepted TLD so should be linkified
+                + "d.e, f.1, g.12, "  // not valid, so should not be linkified
+                + "http://h." + longGTLD + " "  // valid, should be linkified
+                + "j." + longGTLD + "a"); // not a valid URL (gtld too long), no linkify
+
+        assertTrue(LinkifyCompat.addLinks(spannable, Linkify.WEB_URLS));
+        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertEquals(4, spans.length);
+        assertEquals("http://www.google.com", spans[0].getURL());
+        assertEquals("http://www.google.com/language_tools?hl=en", spans[1].getURL());
+        assertEquals("http://a.bd", spans[2].getURL());
+        assertEquals("http://h." + longGTLD, spans[3].getURL());
+
+        assertTrue(LinkifyCompat.addLinks(spannable, Linkify.EMAIL_ADDRESSES));
+        spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertEquals(1, spans.length);
+        assertEquals("mailto:name@gmail.com", spans[0].getURL());
+
+        try {
+            LinkifyCompat.addLinks((Spannable) null, Linkify.WEB_URLS);
+            fail("Should throw NullPointerException!");
+        } catch (NullPointerException e) {
+            // expect
+        }
+
+        assertFalse(LinkifyCompat.addLinks((Spannable) null, 0));
+    }
+
+    @Test
+    public void testAddLinksToSpannableWithScheme() {
+        String text = "google.pattern, test:AZ0101.pattern";
+
+        SpannableString spannable = new SpannableString(text);
+        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:");
+        URLSpan[] spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
+        assertEquals(2, spans.length);
+        assertEquals("test:google.pattern", spans[0].getURL());
+        assertEquals("test:AZ0101.pattern", spans[1].getURL());
+
+        try {
+            LinkifyCompat.addLinks((Spannable) null, LINKIFY_TEST_PATTERN, "Test:");
+            fail("Should throw NullPointerException!");
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            LinkifyCompat.addLinks(spannable, null, "Test:");
+            fail("Should throw NullPointerException!");
+        } catch (NullPointerException e) {
+        }
+
+        spannable = new SpannableString(text);
+        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, null);
+        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
+        assertEquals(2, spans.length);
+        assertEquals("google.pattern", spans[0].getURL());
+        assertEquals("test:AZ0101.pattern", spans[1].getURL());
+    }
+
+    @Test
+    public void testAddLinks3() {
+        String text = "FilterUpperCase.pattern, 12.345.pattern";
+
+        SpannableString spannable = new SpannableString(text);
+        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:",
+                mMatchFilterStartWithDot, mTransformFilterUpperChar);
+        URLSpan[] spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
+        assertEquals(2, spans.length);
+        assertEquals("test:ilterpperase.pattern", spans[0].getURL());
+        assertEquals("test:12", spans[1].getURL());
+
+        try {
+            LinkifyCompat.addLinks((Spannable)null, LINKIFY_TEST_PATTERN, "Test:",
+                    mMatchFilterStartWithDot, mTransformFilterUpperChar);
+            fail("Should throw NullPointerException!");
+        } catch (NullPointerException e) {
+            // expect
+        }
+
+        try {
+            LinkifyCompat.addLinks(spannable, null, "Test:", mMatchFilterStartWithDot,
+                    mTransformFilterUpperChar);
+            fail("Should throw NullPointerException!");
+        } catch (NullPointerException e) {
+            // expect
+        }
+
+        spannable = new SpannableString(text);
+        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, null, mMatchFilterStartWithDot,
+                mTransformFilterUpperChar);
+        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
+        assertEquals(2, spans.length);
+        assertEquals("ilterpperase.pattern", spans[0].getURL());
+        assertEquals("12", spans[1].getURL());
+
+        spannable = new SpannableString(text);
+        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:", null, mTransformFilterUpperChar);
+        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
+        assertEquals(3, spans.length);
+        assertEquals("test:ilterpperase.pattern", spans[0].getURL());
+        assertEquals("test:12", spans[1].getURL());
+        assertEquals("test:345.pattern", spans[2].getURL());
+
+        spannable = new SpannableString(text);
+        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:", mMatchFilterStartWithDot, null);
+        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
+        assertEquals(2, spans.length);
+        assertEquals("test:FilterUpperCase.pattern", spans[0].getURL());
+        assertEquals("test:12", spans[1].getURL());
+    }
+
+    @Test
+    public void testAddLinksPhoneNumbers() {
+        String numbersInvalid = "123456789 not a phone number";
+        String numbersUKLocal = "tel:(0812)1234560 (0812)1234561";
+        String numbersUSLocal = "tel:(812)1234562 (812)123.4563 "
+                + " tel:(800)5551210 (800)555-1211 555-1212";
+        String numbersIntl = "tel:+4408121234564 +44-0812-123-4565"
+                + " tel:+18005551213 +1-800-555-1214";
+        SpannableString spannable = new SpannableString(
+                numbersInvalid
+                        + " " + numbersUKLocal
+                        + " " + numbersUSLocal
+                        + " " + numbersIntl);
+
+        // phonenumber linkify is locale-dependent
+        if (Locale.US.equals(Locale.getDefault())) {
+            assertTrue(LinkifyCompat.addLinks(spannable, Linkify.PHONE_NUMBERS));
+            URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+            // We cannot assert the contents of the spans as support library falls back to the
+            // framework libphonenumber which behaves differently for different API levels.
+            assertNotEquals("There should be more than zero phone number spans.", 0, spans.length);
+        }
+
+        try {
+            LinkifyCompat.addLinks((Spannable) null, Linkify.WEB_URLS);
+            fail("Should throw NullPointerException!");
+        } catch (NullPointerException e) {
+            // expect
+        }
+
+        assertFalse(LinkifyCompat.addLinks((Spannable) null, 0));
+    }
+
+    @Test
+    public void testAddLinks_spanOverlapPruning() {
+        SpannableString spannable = new SpannableString("800-555-1211@gmail.com 800-555-1222.com"
+                + " phone +1-800-555-1214");
+
+        // phonenumber linkify is locale-dependent
+        if (Locale.US.equals(Locale.getDefault())) {
+            assertTrue(LinkifyCompat.addLinks(spannable, Linkify.ALL));
+            URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+            assertEquals(3, spans.length);
+            assertTrue(containsUrl(spans, "tel:+18005551214"));
+            assertTrue(containsUrl(spans, "mailto:800-555-1211@gmail.com"));
+            assertTrue(containsUrl(spans, "http://800-555-1222.com"));
+        }
+    }
+
+    private boolean containsUrl(URLSpan[] spans, String expectedValue) {
+        for (URLSpan span : spans) {
+            if (span.getURL().equals(expectedValue)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Test
+    public void testAddLinks_addsLinksWhenDefaultSchemeIsNull() {
+        Spannable spannable = new SpannableString("any https://android.com any android.com any");
+        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, null, null, null);
+
+        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
+        assertEquals("https://android.com", spans[0].getURL());
+        assertEquals("android.com", spans[1].getURL());
+    }
+
+    @Test
+    public void testAddLinks_addsLinksWhenSchemesArrayIsNull() {
+        Spannable spannable = new SpannableString("any https://android.com any android.com any");
+        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, "http://", null, null);
+
+        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
+        // expected behavior, passing null schemes array means: prepend defaultScheme to all links.
+        assertEquals("http://https://android.com", spans[0].getURL());
+        assertEquals("http://android.com", spans[1].getURL());
+    }
+
+    @Test
+    public void testAddLinks_prependsDefaultSchemeToBeginingOfLink() {
+        Spannable spannable = new SpannableString("any android.com any");
+        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, "http://",
+                new String[] { "http://", "https://"}, null, null);
+
+        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertEquals("android.com should be linkified", 1, spans.length);
+        assertEquals("http://android.com", spans[0].getURL());
+    }
+
+    @Test
+    public void testAddLinks_doesNotPrependSchemeIfSchemeExists() {
+        Spannable spannable = new SpannableString("any https://android.com any");
+        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, "http://",
+                new String[] { "http://", "https://"}, null, null);
+
+        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertEquals("android.com should be linkified", 1, spans.length);
+        assertEquals("https://android.com", spans[0].getURL());
+    }
+
+    // WEB_URLS Related Tests
+
+    @Test
+    public void testAddLinks_doesNotAddLinksForUrlWithoutProtocolAndWithoutKnownTld() {
+        Spannable spannable = new SpannableString("hey man.its me");
+        boolean linksAdded = LinkifyCompat.addLinks(spannable, Linkify.ALL);
+        assertFalse("Should not add link with unknown TLD", linksAdded);
+    }
+
+    @Test
+    public void testAddLinks_shouldNotAddEmailAddressAsUrl() {
+        String url = "name@gmail.com";
+        verifyAddLinksWithWebUrlFails("Should not recognize email address as URL", url);
+    }
+
+    @Test
+    public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() {
+        String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
+        verifyAddLinksWithWebUrlSucceeds("Should accept commas", url);
+    }
+
+    @Test
+    public void testAddLinks_addsLinksForUrlWithProtocolWithoutTld() {
+        String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
+        verifyAddLinksWithWebUrlSucceeds("Should accept URL starting with protocol but does not"
+                + " have TLD", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesProtocolCaseInsensitive() {
+        String url = "hTtP://android.com";
+        verifyAddLinksWithWebUrlSucceeds("Protocol matching should be case insensitive", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesValidUrlWithSchemeAndHostname() {
+        String url = "http://www.android.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme and hostname", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesValidUrlWithSchemeHostnameAndNewTld() {
+        String url = "http://www.android.me";
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme hostname and new TLD",
+                url);
+    }
+
+    @Test
+    public void testAddLinks_matchesValidUrlWithHostnameAndNewTld() {
+        String url = "android.camera";
+        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with hostname and new TLD", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesPunycodeUrl() {
+        String url = "http://xn--fsqu00a.xn--unup4y";
+        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesPunycodeUrlWithoutProtocol() {
+        String url = "xn--fsqu00a.xn--unup4y";
+        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL without protocol", url);
+    }
+
+    @Test
+    public void testAddLinks_doesNotMatchPunycodeTldThatStartsWithDash() {
+        String url = "xn--fsqu00a.-xn--unup4y";
+        verifyAddLinksWithWebUrlFails("Should not match Punycode TLD that starts with dash", url);
+    }
+
+    @Test
+    public void testAddLinks_partiallyMatchesPunycodeTldThatEndsWithDash() {
+        String url = "http://xn--fsqu00a.xn--unup4y-";
+        verifyAddLinksWithWebUrlPartiallyMatches("Should partially match Punycode TLD that ends "
+                + "with dash", "http://xn--fsqu00a.xn--unup4y", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodeDomainName() {
+        String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodeDomainNameWithoutProtocol() {
+        String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL without protocol and with Unicode "
+                + "domain name", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodeDomainNameAndTld() {
+        String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name and TLD", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesUrlWithUnicodePath() {
+        String url = "http://android.com/\u2019/a";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode path", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesValidUrlWithPort() {
+        String url = "http://www.example.com:8080";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with port", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesUrlWithPortAndQuery() {
+        String url = "http://www.example.com:8080/?foo=bar";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with port and query", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesUrlWithTilde() {
+        String url = "http://www.example.com:8080/~user/?foo=bar";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with tilde", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesUrlStartingWithHttpAndDoesNotHaveTld() {
+        String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL without a TLD and starting with http",
+                url);
+    }
+
+    @Test
+    public void testAddLinks_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() {
+        String url = "thank.you";
+        verifyAddLinksWithWebUrlFails("Should not match URL that does not start with a protocol "
+                + "and does not contain a known TLD", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesValidUrlWithEmoji() {
+        String url = "Thank\u263A.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
+    }
+
+    @Test
+    public void testAddLinks_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld() {
+        String url = "Thank\u263A.you";
+        verifyAddLinksWithWebUrlFails("Should not match URLs containing emoji and with unknown "
+                + "TLD", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesDomainNameWithSurrogatePairs() {
+        String url = "android\uD83C\uDF38.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with Unicode surrogate pairs",
+                url);
+    }
+
+    @Test
+    public void testAddLinks_matchesTldWithSurrogatePairs() {
+        String url = "http://android.\uD83C\uDF38com";
+        verifyAddLinksWithWebUrlSucceeds("Should match TLD with Unicode surrogate pairs", url);
+    }
+
+    @Test
+    public void testAddLinks_doesNotMatchUrlWithExcludedSurrogate() {
+        String url = "android\uD83F\uDFFE.com";
+        verifyAddLinksWithWebUrlFails("Should not match URL with excluded Unicode surrogate"
+                + " pair",  url);
+    }
+
+    @Test
+    public void testAddLinks_matchesPathWithSurrogatePairs() {
+        String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38f";
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with Unicode surrogate pairs",
+                url);
+    }
+
+    @Test
+    public void testAddLinks__doesNotMatchUnicodeSpaces() {
+        String part1 = "http://and";
+        String part2 = "roid.com";
+        String[] emptySpaces = new String[]{
+                "\u00A0", // no-break space
+                "\u2000", // en quad
+                "\u2001", // em quad
+                "\u2002", // en space
+                "\u2003", // em space
+                "\u2004", // three-per-em space
+                "\u2005", // four-per-em space
+                "\u2006", // six-per-em space
+                "\u2007", // figure space
+                "\u2008", // punctuation space
+                "\u2009", // thin space
+                "\u200A", // hair space
+                "\u2028", // line separator
+                "\u2029", // paragraph separator
+                "\u202F", // narrow no-break space
+                "\u3000"  // ideographic space
+        };
+
+        for (String emptySpace : emptySpaces) {
+            String url = part1 + emptySpace + part2;
+            verifyAddLinksWithWebUrlPartiallyMatches("Should not include empty space with code: "
+                    + emptySpace.codePointAt(0), part1, url);
+        }
+    }
+
+    @Test
+    public void testAddLinks_matchesDomainNameWithDash() {
+        String url = "http://a-nd.r-oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+
+        url = "a-nd.r-oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesDomainNameWithUnderscore() {
+        String url = "http://a_nd.r_oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+
+        url = "a_nd.r_oid.com";
+        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesPathAndQueryWithDollarSign() {
+        String url = "http://android.com/path$?v=$val";
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+
+        url = "android.com/path$?v=$val";
+        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
+    }
+
+    @Test
+    public void testAddLinks_matchesEmptyPathWithQueryParams() {
+        String url = "http://android.com?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "android.com?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "http://android.com/?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+
+        url = "android.com/?q=v";
+        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
+    }
+
+    // EMAIL_ADDRESSES Related Tests
+
+    @Test
+    public void testAddLinks_email_matchesShortValidEmail() {
+        String email = "a@a.co";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+
+        email = "ab@a.co";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesRegularEmail() {
+        String email = "email@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesEmailWithMultipleSubdomains() {
+        String email = "email@e.somelongdomainnameforandroid.abc.uk";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithDot() {
+        String email = "e.mail@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithPlus() {
+        String email = "e+mail@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithUnderscore() {
+        String email = "e_mail@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithDash() {
+        String email = "e-mail@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithApostrophe() {
+        String email = "e'mail@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithDigits() {
+        String email = "123@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesUnicodeLocalPart() {
+        String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithEmoji() {
+        String email = "smiley\u263A@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartWithSurrogatePairs() {
+        String email = "a\uD83C\uDF38a@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesDomainWithDash() {
+        String email = "email@an-droid.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesUnicodeDomain() {
+        String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesUnicodeLocalPartAndDomain() {
+        String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesDomainWithEmoji() {
+        String email = "smiley@\u263Aandroid.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesDomainWithSurrogatePairs() {
+        String email = "email@\uD83C\uDF38android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartAndDomainWithSurrogatePairs() {
+        String email = "a\uD83C\uDF38a@\uD83C\uDF38android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_partiallyMatchesEmailEndingWithDot() {
+        String email = "email@android.co.uk.";
+        verifyAddLinksWithEmailPartiallyMatches("Should partially match email ending with dot",
+                "mailto:email@android.co.uk", email);
+    }
+
+    @Test
+    public void testAddLinks_email_partiallyMatchesLocalPartStartingWithDot() {
+        String email = ".email@android.com";
+        verifyAddLinksWithEmailPartiallyMatches("Should partially match email starting "
+                + "with dot", "mailto:email@android.com", email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchStringWithoutAtSign() {
+        String email = "android.com";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchPlainString() {
+        String email = "email";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchEmailWithoutTld() {
+        String email = "email@android";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchLocalPartEndingWithDot() {
+        String email = "email.@android.com";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchDomainStartingWithDash() {
+        String email = "email@-android.com";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchDomainWithConsecutiveDots() {
+        String email = "email@android..com";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchEmailWithIp() {
+        String email = "email@127.0.0.1";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_doesNotMatchEmailWithInvalidTld() {
+        String email = "email@android.c";
+        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesLocalPartUpTo64Chars() {
+        String localPart = "";
+        for (int i = 0; i < 64; i++) {
+            localPart += "a";
+        }
+        String email = localPart + "@android.com";
+        verifyAddLinksWithEmailSucceeds("Should match email local part of length: "
+                + localPart.length(), email);
+
+        email = localPart + "a@android.com";
+        verifyAddLinksWithEmailFails("Should not match email local part of length:"
+                + localPart.length(), email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesSubdomainUpTo63Chars() {
+        String subdomain = "";
+        for (int i = 0; i < 63; i++) {
+            subdomain += "a";
+        }
+        String email = "email@" + subdomain + ".com";
+
+        verifyAddLinksWithEmailSucceeds("Should match email subdomain of length: "
+                + subdomain.length(), email);
+
+        subdomain += "a";
+        email = "email@" + subdomain + ".com";
+
+        verifyAddLinksWithEmailFails("Should not match email subdomain of length:"
+                + subdomain.length(), email);
+    }
+
+    @Test
+    public void testAddLinks_email_matchesDomainUpTo255Chars() {
+        String domain = "";
+        while (domain.length() <= 250) {
+            domain += "d.";
+        }
+        domain += "com";
+        assertEquals(255, domain.length());
+        String email = "a@" + domain;
+        verifyAddLinksWithEmailSucceeds("Should match email domain of length: "
+                + domain.length(), email);
+
+        email = email + "m";
+        verifyAddLinksWithEmailFails("Should not match email domain of length:"
+                + domain.length(), email);
+    }
+
+    // ADDRESS RELATED TESTS
+
+    @Test
+    public void testFindAddress_withoutZipcode() {
+        final String address = "455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA";
+        verifyAddLinksWithMapAddressSucceeds("Should match map address: " + address, address);
+    }
+
+    @Test
+    public void testFindAddress_withZipcode() {
+        final String address = "455 LARKSPUR DRIVE CALIFORNIA SPRINGS CALIFORNIA 92826";
+        verifyAddLinksWithMapAddressSucceeds("Should match map address: " + address, address);
+    }
+
+    @Test
+    public void testFindAddress_invalidAddress() {
+        final String address = "This is not an address: no town, no state, no zip.";
+        verifyAddLinksWithMapAddressFails("Should not match map address: " + address, address);
+    }
+
+    // Utility functions
+    private static void verifyAddLinksWithWebUrlSucceeds(String msg, String url) {
+        verifyAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
+    }
+
+    private static void verifyAddLinksWithWebUrlFails(String msg, String url) {
+        verifyAddLinksFails(msg, url, Linkify.WEB_URLS);
+    }
+
+    private static void verifyAddLinksWithWebUrlPartiallyMatches(String msg, String expected,
+            String url) {
+        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.WEB_URLS);
+    }
+
+    private static void verifyAddLinksWithEmailSucceeds(String msg, String url) {
+        verifyAddLinksSucceeds(msg, url, Linkify.EMAIL_ADDRESSES);
+    }
+
+    private static void verifyAddLinksWithEmailFails(String msg, String url) {
+        verifyAddLinksFails(msg, url, Linkify.EMAIL_ADDRESSES);
+    }
+
+    private static void verifyAddLinksWithEmailPartiallyMatches(String msg, String expected,
+            String url) {
+        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.EMAIL_ADDRESSES);
+    }
+
+    private static void verifyAddLinksWithMapAddressSucceeds(String msg, String url) {
+        verifyAddLinksSucceeds(msg, url, Linkify.MAP_ADDRESSES);
+    }
+
+    private static void verifyAddLinksWithMapAddressFails(String msg, String url) {
+        verifyAddLinksFails(msg, url, Linkify.MAP_ADDRESSES);
+    }
+
+    private static void verifyAddLinksSucceeds(String msg, String string, int type) {
+        String str = "start " + string + " end";
+        Spannable spannable = new SpannableString(str);
+
+        boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
+        URLSpan[] spans = spannable.getSpans(0, str.length(), URLSpan.class);
+
+        assertTrue(msg, linksAdded);
+        assertEquals("Span should start from the beginning of: " + string,
+                "start ".length(), spannable.getSpanStart(spans[0]));
+        assertEquals("Span should end at the end of: " + string,
+                str.length() - " end".length(), spannable.getSpanEnd(spans[0]));
+    }
+
+    private static void verifyAddLinksFails(String msg, String string, int type) {
+        Spannable spannable = new SpannableString("start " + string + " end");
+        boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
+        assertFalse(msg, linksAdded);
+    }
+
+    private static void verifyAddLinksPartiallyMatches(String msg, String expected,
+            String string, int type) {
+        Spannable spannable = new SpannableString("start " + string + " end");
+        boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
+        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+        assertTrue(msg, linksAdded);
+        assertEquals(msg, expected, spans[0].getURL().toString());
+    }
+}
diff --git a/compat/tests/java/android/support/v4/util/ObjectsCompatTest.java b/compat/src/androidTest/java/android/support/v4/util/ObjectsCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/util/ObjectsCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/util/ObjectsCompatTest.java
diff --git a/compat/tests/java/android/support/v4/util/PatternsCompatTest.java b/compat/src/androidTest/java/android/support/v4/util/PatternsCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/util/PatternsCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/util/PatternsCompatTest.java
diff --git a/compat/tests/java/android/support/v4/view/GravityCompatTest.java b/compat/src/androidTest/java/android/support/v4/view/GravityCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/GravityCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/view/GravityCompatTest.java
diff --git a/compat/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java b/compat/src/androidTest/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/view/MarginLayoutParamsCompatTest.java
diff --git a/compat/tests/java/android/support/v4/view/PointerIconCompatTest.java b/compat/src/androidTest/java/android/support/v4/view/PointerIconCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/PointerIconCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/view/PointerIconCompatTest.java
diff --git a/compat/tests/java/android/support/v4/view/ViewCompatActivity.java b/compat/src/androidTest/java/android/support/v4/view/ViewCompatActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/ViewCompatActivity.java
rename to compat/src/androidTest/java/android/support/v4/view/ViewCompatActivity.java
diff --git a/compat/tests/java/android/support/v4/view/ViewCompatTest.java b/compat/src/androidTest/java/android/support/v4/view/ViewCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/ViewCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/view/ViewCompatTest.java
diff --git a/compat/tests/java/android/support/v4/view/ViewGroupCompatTest.java b/compat/src/androidTest/java/android/support/v4/view/ViewGroupCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/ViewGroupCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/view/ViewGroupCompatTest.java
diff --git a/compat/tests/java/android/support/v4/view/ViewPropertyAnimatorCompatTest.java b/compat/src/androidTest/java/android/support/v4/view/ViewPropertyAnimatorCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/ViewPropertyAnimatorCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/view/ViewPropertyAnimatorCompatTest.java
diff --git a/compat/tests/java/android/support/v4/view/VpaActivity.java b/compat/src/androidTest/java/android/support/v4/view/VpaActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v4/view/VpaActivity.java
rename to compat/src/androidTest/java/android/support/v4/view/VpaActivity.java
diff --git a/compat/src/androidTest/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatTest.java b/compat/src/androidTest/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatTest.java
new file mode 100644
index 0000000..34a0f99
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompatTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.view.accessibility;
+
+import static org.junit.Assert.*;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityNodeInfoCompatTest {
+    @Test
+    public void testSetCollectionInfoIsNullable() throws Exception {
+        AccessibilityNodeInfo accessibilityNodeInfo = AccessibilityNodeInfo.obtain();
+        AccessibilityNodeInfoCompat accessibilityNodeInfoCompat = AccessibilityNodeInfoCompat.wrap(
+                accessibilityNodeInfo);
+        accessibilityNodeInfoCompat.setCollectionInfo(null);
+    }
+
+    @Test
+    public void testSetCollectionItemInfoIsNullable() throws Exception {
+        AccessibilityNodeInfo accessibilityNodeInfo = AccessibilityNodeInfo.obtain();
+        AccessibilityNodeInfoCompat accessibilityNodeInfoCompat = AccessibilityNodeInfoCompat.wrap(
+                accessibilityNodeInfo);
+        accessibilityNodeInfoCompat.setCollectionItemInfo(null);
+    }
+}
diff --git a/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarActivity.java b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarActivity.java
new file mode 100644
index 0000000..d9bf4e2
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.compat.test.R;
+
+public class ContentLoadingProgressBarActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.content_loading_progress_bar_activity);
+    }
+}
diff --git a/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
new file mode 100644
index 0000000..c8bc229
--- /dev/null
+++ b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.compat.test.R;
+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.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link ContentLoadingProgressBar}
+ */
+@RunWith(AndroidJUnit4.class)
+public class ContentLoadingProgressBarTest {
+    @Rule
+    public final ActivityTestRule<ContentLoadingProgressBarActivity> mActivityTestRule;
+
+    public ContentLoadingProgressBarTest() {
+        mActivityTestRule = new ActivityTestRule<>(ContentLoadingProgressBarActivity.class);
+    }
+
+    private ContentLoadingProgressBar mContentLoadingProgressBar;
+
+    @Before
+    public void setUp() {
+        mContentLoadingProgressBar = mActivityTestRule.getActivity().findViewById(R.id.progressBar);
+    }
+
+    @Test
+    @LargeTest
+    public void showAndThenLaterHide() {
+        mContentLoadingProgressBar.show();
+
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mContentLoadingProgressBar.getVisibility() == View.VISIBLE;
+            }
+        });
+
+        mContentLoadingProgressBar.hide();
+
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mContentLoadingProgressBar.getVisibility() == View.GONE;
+            }
+        });
+    }
+
+    @Test
+    @LargeTest
+    public void showAndImmediatelyHide() {
+        mContentLoadingProgressBar.show();
+        mContentLoadingProgressBar.hide();
+
+        // show() followed immediately by hide() should leave the progress bar in GONE state
+        assertEquals(mContentLoadingProgressBar.getVisibility(), View.GONE);
+
+        // The next show() should eventually show the progress bar
+        mContentLoadingProgressBar.show();
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mContentLoadingProgressBar.getVisibility() == View.VISIBLE;
+            }
+        });
+
+
+        // The next hide() should eventually hide the progress bar
+        mContentLoadingProgressBar.hide();
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mContentLoadingProgressBar.getVisibility() == View.GONE;
+            }
+        });
+    }
+}
diff --git a/compat/tests/java/android/support/v4/widget/ListViewCompatTest.java b/compat/src/androidTest/java/android/support/v4/widget/ListViewCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/widget/ListViewCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/widget/ListViewCompatTest.java
diff --git a/compat/tests/java/android/support/v4/widget/ListViewTestActivity.java b/compat/src/androidTest/java/android/support/v4/widget/ListViewTestActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v4/widget/ListViewTestActivity.java
rename to compat/src/androidTest/java/android/support/v4/widget/ListViewTestActivity.java
diff --git a/compat/tests/java/android/support/v4/widget/ScrollerCompatTestBase.java b/compat/src/androidTest/java/android/support/v4/widget/ScrollerCompatTestBase.java
similarity index 100%
rename from compat/tests/java/android/support/v4/widget/ScrollerCompatTestBase.java
rename to compat/src/androidTest/java/android/support/v4/widget/ScrollerCompatTestBase.java
diff --git a/compat/tests/java/android/support/v4/widget/TextViewCompatTest.java b/compat/src/androidTest/java/android/support/v4/widget/TextViewCompatTest.java
similarity index 100%
rename from compat/tests/java/android/support/v4/widget/TextViewCompatTest.java
rename to compat/src/androidTest/java/android/support/v4/widget/TextViewCompatTest.java
diff --git a/compat/tests/java/android/support/v4/widget/TextViewTestActivity.java b/compat/src/androidTest/java/android/support/v4/widget/TextViewTestActivity.java
similarity index 100%
rename from compat/tests/java/android/support/v4/widget/TextViewTestActivity.java
rename to compat/src/androidTest/java/android/support/v4/widget/TextViewTestActivity.java
diff --git a/compat/tests/res/color/complex_themed_selector.xml b/compat/src/androidTest/res/color/complex_themed_selector.xml
similarity index 100%
rename from compat/tests/res/color/complex_themed_selector.xml
rename to compat/src/androidTest/res/color/complex_themed_selector.xml
diff --git a/compat/tests/res/color/complex_unthemed_selector.xml b/compat/src/androidTest/res/color/complex_unthemed_selector.xml
similarity index 100%
rename from compat/tests/res/color/complex_unthemed_selector.xml
rename to compat/src/androidTest/res/color/complex_unthemed_selector.xml
diff --git a/compat/tests/res/color/simple_themed_selector.xml b/compat/src/androidTest/res/color/simple_themed_selector.xml
similarity index 100%
rename from compat/tests/res/color/simple_themed_selector.xml
rename to compat/src/androidTest/res/color/simple_themed_selector.xml
diff --git a/compat/tests/res/drawable-hdpi/density_aware_drawable.png b/compat/src/androidTest/res/drawable-hdpi/density_aware_drawable.png
similarity index 100%
rename from compat/tests/res/drawable-hdpi/density_aware_drawable.png
rename to compat/src/androidTest/res/drawable-hdpi/density_aware_drawable.png
Binary files differ
diff --git a/compat/tests/res/drawable-ldpi/aliased_drawable_alternate.png b/compat/src/androidTest/res/drawable-ldpi/aliased_drawable_alternate.png
similarity index 100%
rename from compat/tests/res/drawable-ldpi/aliased_drawable_alternate.png
rename to compat/src/androidTest/res/drawable-ldpi/aliased_drawable_alternate.png
Binary files differ
diff --git a/compat/tests/res/drawable-mdpi/density_aware_drawable.png b/compat/src/androidTest/res/drawable-mdpi/density_aware_drawable.png
similarity index 100%
rename from compat/tests/res/drawable-mdpi/density_aware_drawable.png
rename to compat/src/androidTest/res/drawable-mdpi/density_aware_drawable.png
Binary files differ
diff --git a/compat/tests/res/drawable-mdpi/test_drawable.png b/compat/src/androidTest/res/drawable-mdpi/test_drawable.png
similarity index 100%
rename from compat/tests/res/drawable-mdpi/test_drawable.png
rename to compat/src/androidTest/res/drawable-mdpi/test_drawable.png
Binary files differ
diff --git a/compat/tests/res/drawable-xhdpi/density_aware_drawable.png b/compat/src/androidTest/res/drawable-xhdpi/density_aware_drawable.png
similarity index 100%
rename from compat/tests/res/drawable-xhdpi/density_aware_drawable.png
rename to compat/src/androidTest/res/drawable-xhdpi/density_aware_drawable.png
Binary files differ
diff --git a/compat/tests/res/drawable-xxhdpi/density_aware_drawable.png b/compat/src/androidTest/res/drawable-xxhdpi/density_aware_drawable.png
similarity index 100%
rename from compat/tests/res/drawable-xxhdpi/density_aware_drawable.png
rename to compat/src/androidTest/res/drawable-xxhdpi/density_aware_drawable.png
Binary files differ
diff --git a/compat/tests/res/drawable/action_icon.xml b/compat/src/androidTest/res/drawable/action_icon.xml
similarity index 100%
rename from compat/tests/res/drawable/action_icon.xml
rename to compat/src/androidTest/res/drawable/action_icon.xml
diff --git a/compat/tests/res/drawable/action_icon2.xml b/compat/src/androidTest/res/drawable/action_icon2.xml
similarity index 100%
rename from compat/tests/res/drawable/action_icon2.xml
rename to compat/src/androidTest/res/drawable/action_icon2.xml
diff --git a/compat/tests/res/drawable/content_icon.xml b/compat/src/androidTest/res/drawable/content_icon.xml
similarity index 100%
rename from compat/tests/res/drawable/content_icon.xml
rename to compat/src/androidTest/res/drawable/content_icon.xml
diff --git a/compat/tests/res/drawable/content_icon2.xml b/compat/src/androidTest/res/drawable/content_icon2.xml
similarity index 100%
rename from compat/tests/res/drawable/content_icon2.xml
rename to compat/src/androidTest/res/drawable/content_icon2.xml
diff --git a/compat/tests/res/drawable/pointer_icon.xml b/compat/src/androidTest/res/drawable/pointer_icon.xml
similarity index 100%
rename from compat/tests/res/drawable/pointer_icon.xml
rename to compat/src/androidTest/res/drawable/pointer_icon.xml
diff --git a/compat/tests/res/drawable/test_drawable_blue.xml b/compat/src/androidTest/res/drawable/test_drawable_blue.xml
similarity index 100%
rename from compat/tests/res/drawable/test_drawable_blue.xml
rename to compat/src/androidTest/res/drawable/test_drawable_blue.xml
diff --git a/compat/tests/res/drawable/test_drawable_green.xml b/compat/src/androidTest/res/drawable/test_drawable_green.xml
similarity index 100%
rename from compat/tests/res/drawable/test_drawable_green.xml
rename to compat/src/androidTest/res/drawable/test_drawable_green.xml
diff --git a/compat/tests/res/drawable/test_drawable_red.xml b/compat/src/androidTest/res/drawable/test_drawable_red.xml
similarity index 100%
rename from compat/tests/res/drawable/test_drawable_red.xml
rename to compat/src/androidTest/res/drawable/test_drawable_red.xml
diff --git a/compat/tests/res/drawable/themed_bitmap.xml b/compat/src/androidTest/res/drawable/themed_bitmap.xml
similarity index 100%
rename from compat/tests/res/drawable/themed_bitmap.xml
rename to compat/src/androidTest/res/drawable/themed_bitmap.xml
diff --git a/compat/tests/res/drawable/themed_drawable.xml b/compat/src/androidTest/res/drawable/themed_drawable.xml
similarity index 100%
rename from compat/tests/res/drawable/themed_drawable.xml
rename to compat/src/androidTest/res/drawable/themed_drawable.xml
diff --git a/compat/tests/res/font/dummyproviderfont.xml b/compat/src/androidTest/res/font/dummyproviderfont.xml
similarity index 100%
rename from compat/tests/res/font/dummyproviderfont.xml
rename to compat/src/androidTest/res/font/dummyproviderfont.xml
diff --git a/compat/tests/res/font/invalid_font.ttf b/compat/src/androidTest/res/font/invalid_font.ttf
similarity index 100%
rename from compat/tests/res/font/invalid_font.ttf
rename to compat/src/androidTest/res/font/invalid_font.ttf
diff --git a/compat/tests/res/font/invalid_xmlempty.xml b/compat/src/androidTest/res/font/invalid_xmlempty.xml
similarity index 100%
rename from compat/tests/res/font/invalid_xmlempty.xml
rename to compat/src/androidTest/res/font/invalid_xmlempty.xml
diff --git a/compat/tests/res/font/invalid_xmlfamily.xml b/compat/src/androidTest/res/font/invalid_xmlfamily.xml
similarity index 100%
rename from compat/tests/res/font/invalid_xmlfamily.xml
rename to compat/src/androidTest/res/font/invalid_xmlfamily.xml
diff --git a/compat/tests/res/font/invalid_xmlfont.xml b/compat/src/androidTest/res/font/invalid_xmlfont.xml
similarity index 100%
rename from compat/tests/res/font/invalid_xmlfont.xml
rename to compat/src/androidTest/res/font/invalid_xmlfont.xml
diff --git a/compat/tests/res/font/invalid_xmlfont_contains_invalid_font_file.xml b/compat/src/androidTest/res/font/invalid_xmlfont_contains_invalid_font_file.xml
similarity index 100%
rename from compat/tests/res/font/invalid_xmlfont_contains_invalid_font_file.xml
rename to compat/src/androidTest/res/font/invalid_xmlfont_contains_invalid_font_file.xml
diff --git a/compat/tests/res/font/large_a.ttf b/compat/src/androidTest/res/font/large_a.ttf
similarity index 100%
rename from compat/tests/res/font/large_a.ttf
rename to compat/src/androidTest/res/font/large_a.ttf
Binary files differ
diff --git a/compat/tests/res/font/large_b.ttf b/compat/src/androidTest/res/font/large_b.ttf
similarity index 100%
rename from compat/tests/res/font/large_b.ttf
rename to compat/src/androidTest/res/font/large_b.ttf
Binary files differ
diff --git a/compat/tests/res/font/large_c.ttf b/compat/src/androidTest/res/font/large_c.ttf
similarity index 100%
rename from compat/tests/res/font/large_c.ttf
rename to compat/src/androidTest/res/font/large_c.ttf
Binary files differ
diff --git a/compat/tests/res/font/large_d.ttf b/compat/src/androidTest/res/font/large_d.ttf
similarity index 100%
rename from compat/tests/res/font/large_d.ttf
rename to compat/src/androidTest/res/font/large_d.ttf
Binary files differ
diff --git a/compat/src/androidTest/res/font/sample_font_collection.ttc b/compat/src/androidTest/res/font/sample_font_collection.ttc
new file mode 100644
index 0000000..9252f3d
--- /dev/null
+++ b/compat/src/androidTest/res/font/sample_font_collection.ttc
Binary files differ
diff --git a/compat/tests/res/font/samplefont.ttf b/compat/src/androidTest/res/font/samplefont.ttf
similarity index 100%
rename from compat/tests/res/font/samplefont.ttf
rename to compat/src/androidTest/res/font/samplefont.ttf
Binary files differ
diff --git a/compat/tests/res/font/samplefont2.ttf b/compat/src/androidTest/res/font/samplefont2.ttf
similarity index 100%
rename from compat/tests/res/font/samplefont2.ttf
rename to compat/src/androidTest/res/font/samplefont2.ttf
Binary files differ
diff --git a/compat/tests/res/font/samplefont3.ttf b/compat/src/androidTest/res/font/samplefont3.ttf
similarity index 100%
rename from compat/tests/res/font/samplefont3.ttf
rename to compat/src/androidTest/res/font/samplefont3.ttf
Binary files differ
diff --git a/compat/tests/res/font/samplefont4.ttf b/compat/src/androidTest/res/font/samplefont4.ttf
similarity index 100%
rename from compat/tests/res/font/samplefont4.ttf
rename to compat/src/androidTest/res/font/samplefont4.ttf
Binary files differ
diff --git a/compat/tests/res/font/samplexmldownloadedfont.xml b/compat/src/androidTest/res/font/samplexmldownloadedfont.xml
similarity index 100%
rename from compat/tests/res/font/samplexmldownloadedfont.xml
rename to compat/src/androidTest/res/font/samplexmldownloadedfont.xml
diff --git a/compat/tests/res/font/samplexmldownloadedfontblocking.xml b/compat/src/androidTest/res/font/samplexmldownloadedfontblocking.xml
similarity index 100%
rename from compat/tests/res/font/samplexmldownloadedfontblocking.xml
rename to compat/src/androidTest/res/font/samplexmldownloadedfontblocking.xml
diff --git a/compat/tests/res/font/samplexmlfont.xml b/compat/src/androidTest/res/font/samplexmlfont.xml
similarity index 100%
rename from compat/tests/res/font/samplexmlfont.xml
rename to compat/src/androidTest/res/font/samplexmlfont.xml
diff --git a/compat/tests/res/font/samplexmlfont2.xml b/compat/src/androidTest/res/font/samplexmlfont2.xml
similarity index 100%
rename from compat/tests/res/font/samplexmlfont2.xml
rename to compat/src/androidTest/res/font/samplexmlfont2.xml
diff --git a/compat/src/androidTest/res/font/samplexmlfontforparsing.xml b/compat/src/androidTest/res/font/samplexmlfontforparsing.xml
new file mode 100644
index 0000000..a96385c
--- /dev/null
+++ b/compat/src/androidTest/res/font/samplexmlfontforparsing.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android"
+             xmlns:app="http://schemas.android.com/apk/res-auto">
+    <font app:fontStyle="normal" app:fontWeight="400" app:fontVariationSettings="'wdth' 0.8"
+          app:font="@font/samplefont" app:ttcIndex="0" />
+    <font app:fontStyle="italic" app:fontWeight="400" app:fontVariationSettings="'contrast' 0.5"
+          app:font="@font/samplefont2" app:ttcIndex="1" />
+    <font app:fontStyle="normal" app:fontWeight="700" app:fontVariationSettings="'wdth' 500.0, 'wght' 300.0"
+          app:font="@font/samplefont3" app:ttcIndex="2" />
+    <font app:fontStyle="italic" app:fontWeight="700" app:font="@font/samplefont4" />
+</font-family>
diff --git a/compat/src/androidTest/res/font/samplexmlfontforparsing2.xml b/compat/src/androidTest/res/font/samplexmlfontforparsing2.xml
new file mode 100644
index 0000000..eb310ba
--- /dev/null
+++ b/compat/src/androidTest/res/font/samplexmlfontforparsing2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<font-family xmlns:android="http://schemas.android.com/apk/res/android" >
+    <font android:fontStyle="normal" android:fontWeight="400" android:fontVariationSettings="'wdth' 0.8"
+          android:font="@font/samplefont" android:ttcIndex="0" />
+    <font android:fontStyle="italic" android:fontWeight="400" android:fontVariationSettings="'contrast' 0.5"
+          android:font="@font/samplefont2" android:ttcIndex="1" />
+    <font android:fontStyle="normal" android:fontWeight="700" android:fontVariationSettings="'wdth' 500.0, 'wght' 300.0"
+          android:font="@font/samplefont3" android:ttcIndex="2" />
+    <font android:fontStyle="italic" android:fontWeight="700" android:font="@font/samplefont4" />
+</font-family>
diff --git a/compat/tests/res/font/styletest_async_providerfont.xml b/compat/src/androidTest/res/font/styletest_async_providerfont.xml
similarity index 100%
rename from compat/tests/res/font/styletest_async_providerfont.xml
rename to compat/src/androidTest/res/font/styletest_async_providerfont.xml
diff --git a/compat/tests/res/font/styletest_sync_providerfont.xml b/compat/src/androidTest/res/font/styletest_sync_providerfont.xml
similarity index 100%
rename from compat/tests/res/font/styletest_sync_providerfont.xml
rename to compat/src/androidTest/res/font/styletest_sync_providerfont.xml
diff --git a/compat/tests/res/font/styletestfont.xml b/compat/src/androidTest/res/font/styletestfont.xml
similarity index 100%
rename from compat/tests/res/font/styletestfont.xml
rename to compat/src/androidTest/res/font/styletestfont.xml
diff --git a/compat/src/androidTest/res/font/ttctestfont1.xml b/compat/src/androidTest/res/font/ttctestfont1.xml
new file mode 100644
index 0000000..a2b75e3
--- /dev/null
+++ b/compat/src/androidTest/res/font/ttctestfont1.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
+    <font app:font="@font/sample_font_collection" app:ttcIndex="0" />
+</font-family>
diff --git a/compat/src/androidTest/res/font/ttctestfont2.xml b/compat/src/androidTest/res/font/ttctestfont2.xml
new file mode 100644
index 0000000..e64ed6a
--- /dev/null
+++ b/compat/src/androidTest/res/font/ttctestfont2.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
+    <font app:font="@font/sample_font_collection" app:ttcIndex="1" />
+</font-family>
diff --git a/compat/src/androidTest/res/font/variable_width_dash_font.ttf b/compat/src/androidTest/res/font/variable_width_dash_font.ttf
new file mode 100644
index 0000000..f7a256a
--- /dev/null
+++ b/compat/src/androidTest/res/font/variable_width_dash_font.ttf
Binary files differ
diff --git a/compat/src/androidTest/res/font/variationsettingstestfont1.xml b/compat/src/androidTest/res/font/variationsettingstestfont1.xml
new file mode 100644
index 0000000..39052a6
--- /dev/null
+++ b/compat/src/androidTest/res/font/variationsettingstestfont1.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
+    <font app:font="@font/variable_width_dash_font" app:fontVariationSettings="'wdth' 100.0" />
+</font-family>
diff --git a/compat/src/androidTest/res/font/variationsettingstestfont2.xml b/compat/src/androidTest/res/font/variationsettingstestfont2.xml
new file mode 100644
index 0000000..90382d0
--- /dev/null
+++ b/compat/src/androidTest/res/font/variationsettingstestfont2.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:app="http://schemas.android.com/apk/res-auto">
+    <font app:font="@font/variable_width_dash_font" app:fontVariationSettings="'wdth' 500.0" />
+</font-family>
diff --git a/compat/tests/res/layout/activity_compat_activity.xml b/compat/src/androidTest/res/layout/activity_compat_activity.xml
similarity index 100%
rename from compat/tests/res/layout/activity_compat_activity.xml
rename to compat/src/androidTest/res/layout/activity_compat_activity.xml
diff --git a/core-ui/tests/res/layout/content_loading_progress_bar_activity.xml b/compat/src/androidTest/res/layout/content_loading_progress_bar_activity.xml
similarity index 100%
rename from core-ui/tests/res/layout/content_loading_progress_bar_activity.xml
rename to compat/src/androidTest/res/layout/content_loading_progress_bar_activity.xml
diff --git a/compat/tests/res/layout/drag_source_activity.xml b/compat/src/androidTest/res/layout/drag_source_activity.xml
similarity index 100%
rename from compat/tests/res/layout/drag_source_activity.xml
rename to compat/src/androidTest/res/layout/drag_source_activity.xml
diff --git a/compat/tests/res/layout/list_view_activity.xml b/compat/src/androidTest/res/layout/list_view_activity.xml
similarity index 100%
rename from compat/tests/res/layout/list_view_activity.xml
rename to compat/src/androidTest/res/layout/list_view_activity.xml
diff --git a/compat/tests/res/layout/list_view_row.xml b/compat/src/androidTest/res/layout/list_view_row.xml
similarity index 100%
rename from compat/tests/res/layout/list_view_row.xml
rename to compat/src/androidTest/res/layout/list_view_row.xml
diff --git a/compat/tests/res/layout/text_view_activity.xml b/compat/src/androidTest/res/layout/text_view_activity.xml
similarity index 100%
rename from compat/tests/res/layout/text_view_activity.xml
rename to compat/src/androidTest/res/layout/text_view_activity.xml
diff --git a/compat/tests/res/layout/view_compat_activity.xml b/compat/src/androidTest/res/layout/view_compat_activity.xml
similarity index 100%
rename from compat/tests/res/layout/view_compat_activity.xml
rename to compat/src/androidTest/res/layout/view_compat_activity.xml
diff --git a/compat/tests/res/layout/vpa_activity.xml b/compat/src/androidTest/res/layout/vpa_activity.xml
similarity index 100%
rename from compat/tests/res/layout/vpa_activity.xml
rename to compat/src/androidTest/res/layout/vpa_activity.xml
diff --git a/compat/tests/res/values-hdpi/dimens.xml b/compat/src/androidTest/res/values-hdpi/dimens.xml
similarity index 100%
rename from compat/tests/res/values-hdpi/dimens.xml
rename to compat/src/androidTest/res/values-hdpi/dimens.xml
diff --git a/compat/tests/res/values-mdpi/dimens.xml b/compat/src/androidTest/res/values-mdpi/dimens.xml
similarity index 100%
rename from compat/tests/res/values-mdpi/dimens.xml
rename to compat/src/androidTest/res/values-mdpi/dimens.xml
diff --git a/compat/tests/res/values-xhdpi/dimens.xml b/compat/src/androidTest/res/values-xhdpi/dimens.xml
similarity index 100%
rename from compat/tests/res/values-xhdpi/dimens.xml
rename to compat/src/androidTest/res/values-xhdpi/dimens.xml
diff --git a/compat/tests/res/values-xxhdpi/dimens.xml b/compat/src/androidTest/res/values-xxhdpi/dimens.xml
similarity index 100%
rename from compat/tests/res/values-xxhdpi/dimens.xml
rename to compat/src/androidTest/res/values-xxhdpi/dimens.xml
diff --git a/compat/tests/res/values/arrays.xml b/compat/src/androidTest/res/values/arrays.xml
similarity index 100%
rename from compat/tests/res/values/arrays.xml
rename to compat/src/androidTest/res/values/arrays.xml
diff --git a/compat/tests/res/values/attrs.xml b/compat/src/androidTest/res/values/attrs.xml
similarity index 100%
rename from compat/tests/res/values/attrs.xml
rename to compat/src/androidTest/res/values/attrs.xml
diff --git a/compat/tests/res/values/colors.xml b/compat/src/androidTest/res/values/colors.xml
similarity index 100%
rename from compat/tests/res/values/colors.xml
rename to compat/src/androidTest/res/values/colors.xml
diff --git a/compat/tests/res/values/dimens.xml b/compat/src/androidTest/res/values/dimens.xml
similarity index 100%
rename from compat/tests/res/values/dimens.xml
rename to compat/src/androidTest/res/values/dimens.xml
diff --git a/compat/tests/res/values/drawables.xml b/compat/src/androidTest/res/values/drawables.xml
similarity index 100%
rename from compat/tests/res/values/drawables.xml
rename to compat/src/androidTest/res/values/drawables.xml
diff --git a/compat/tests/res/values/strings.xml b/compat/src/androidTest/res/values/strings.xml
similarity index 100%
rename from compat/tests/res/values/strings.xml
rename to compat/src/androidTest/res/values/strings.xml
diff --git a/compat/tests/res/values/styles.xml b/compat/src/androidTest/res/values/styles.xml
similarity index 100%
rename from compat/tests/res/values/styles.xml
rename to compat/src/androidTest/res/values/styles.xml
diff --git a/core-utils/tests/res/xml/paths.xml b/compat/src/androidTest/res/xml/paths.xml
similarity index 100%
rename from core-utils/tests/res/xml/paths.xml
rename to compat/src/androidTest/res/xml/paths.xml
diff --git a/compat/src/main/AndroidManifest.xml b/compat/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d13ac8c
--- /dev/null
+++ b/compat/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.compat"/>
\ No newline at end of file
diff --git a/compat/src/main/java/android/support/v4/app/INotificationSideChannel.aidl b/compat/src/main/aidl/android/support/v4/app/INotificationSideChannel.aidl
similarity index 100%
rename from compat/src/main/java/android/support/v4/app/INotificationSideChannel.aidl
rename to compat/src/main/aidl/android/support/v4/app/INotificationSideChannel.aidl
diff --git a/compat/src/main/java/android/support/v4/os/IResultReceiver.aidl b/compat/src/main/aidl/android/support/v4/os/IResultReceiver.aidl
similarity index 100%
rename from compat/src/main/java/android/support/v4/os/IResultReceiver.aidl
rename to compat/src/main/aidl/android/support/v4/os/IResultReceiver.aidl
diff --git a/compat/src/main/java/android/support/v4/os/ResultReceiver.aidl b/compat/src/main/aidl/android/support/v4/os/ResultReceiver.aidl
similarity index 100%
rename from compat/src/main/java/android/support/v4/os/ResultReceiver.aidl
rename to compat/src/main/aidl/android/support/v4/os/ResultReceiver.aidl
diff --git a/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java b/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
index d77389b..9f8511b 100644
--- a/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
+++ b/compat/src/main/java/android/support/v13/view/inputmethod/InputConnectionCompat.java
@@ -149,7 +149,7 @@
      *     the {@link android.content.ContentProvider}.</li>
      * </ul>
      */
-    public static int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 0x00000001;
+    public static final int INPUT_CONTENT_GRANT_READ_URI_PERMISSION = 0x00000001;
 
     /**
      * Listener for commitContent method call, in a backwards compatible fashion.
diff --git a/core-utils/java/android/support/v4/app/AppLaunchChecker.java b/compat/src/main/java/android/support/v4/app/AppLaunchChecker.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/AppLaunchChecker.java
rename to compat/src/main/java/android/support/v4/app/AppLaunchChecker.java
diff --git a/core-utils/java/android/support/v4/app/FrameMetricsAggregator.java b/compat/src/main/java/android/support/v4/app/FrameMetricsAggregator.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/FrameMetricsAggregator.java
rename to compat/src/main/java/android/support/v4/app/FrameMetricsAggregator.java
diff --git a/core-utils/java/android/support/v4/app/NavUtils.java b/compat/src/main/java/android/support/v4/app/NavUtils.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/NavUtils.java
rename to compat/src/main/java/android/support/v4/app/NavUtils.java
diff --git a/compat/src/main/java/android/support/v4/app/NotificationCompat.java b/compat/src/main/java/android/support/v4/app/NotificationCompat.java
index b3f0d32..f5610ed 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationCompat.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationCompat.java
@@ -404,6 +404,12 @@
     public static final String EXTRA_MESSAGES = "android.messages";
 
     /**
+     * Notification key: whether the {@link NotificationCompat.MessagingStyle} notification
+     * represents a group conversation.
+     */
+    public static final String EXTRA_IS_GROUP_CONVERSATION = "android.isGroupConversation";
+
+    /**
      * Keys into the {@link #getExtras} Bundle: the audio contents of this notification.
      *
      * This is for use when rendering the notification on an audio-focused interface;
@@ -651,6 +657,11 @@
         @RestrictTo(LIBRARY_GROUP)
         public ArrayList<Action> mActions = new ArrayList<>();
 
+        // Invisible actions are stored in the CarExtender bundle without actually being owned by
+        // CarExtender. This is to comply with an optimization of the Android OS which removes
+        // Actions from the Notification if there are no listeners for those Actions.
+        ArrayList<Action> mInvisibleActions = new ArrayList<>();
+
         CharSequence mContentTitle;
         CharSequence mContentText;
         PendingIntent mContentIntent;
@@ -1325,6 +1336,35 @@
         }
 
         /**
+         * Add an invisible action to this notification. Invisible actions are never displayed by
+         * the system, but can be retrieved and used by other application listening to
+         * system notifications. Invisible actions are supported from Android 4.4.4 (API 20) and can
+         * be retrieved using {@link NotificationCompat#getInvisibleActions(Notification)}.
+         *
+         * @param icon Resource ID of a drawable that represents the action.
+         * @param title Text describing the action.
+         * @param intent {@link android.app.PendingIntent} to be fired when the action is invoked.
+         */
+        @RequiresApi(21)
+        public Builder addInvisibleAction(int icon, CharSequence title, PendingIntent intent) {
+            return addInvisibleAction(new Action(icon, title, intent));
+        }
+
+        /**
+         * Add an invisible action to this notification. Invisible actions are never displayed by
+         * the system, but can be retrieved and used by other application listening to
+         * system notifications. Invisible actions are supported from Android 4.4.4 (API 20) and can
+         * be retrieved using {@link NotificationCompat#getInvisibleActions(Notification)}.
+         *
+         * @param action The action to add.
+         */
+        @RequiresApi(21)
+        public Builder addInvisibleAction(Action action) {
+            mInvisibleActions.add(action);
+            return this;
+        }
+
+        /**
          * Add a rich notification style to be applied at build time.
          * <br>
          * If the platform does not provide rich notification styles, this method has no effect. The
@@ -2083,8 +2123,9 @@
         public static final int MAXIMUM_RETAINED_MESSAGES = 25;
 
         CharSequence mUserDisplayName;
-        CharSequence mConversationTitle;
+        @Nullable CharSequence mConversationTitle;
         List<Message> mMessages = new ArrayList<>();
+        boolean mIsGroupConversation;
 
         MessagingStyle() {
         }
@@ -2107,20 +2148,27 @@
         }
 
         /**
-         * Sets the title to be displayed on this conversation. This should only be used for
-         * group messaging and left unset for one-on-one conversations.
-         * @param conversationTitle Title displayed for this conversation.
-         * @return this object for method chaining.
+         * Sets the title to be displayed on this conversation. May be set to {@code null}.
+         *
+         * <p>This API's behavior was changed in SDK version {@link Build.VERSION_CODES#P}. If your
+         * application's target version is less than {@link Build.VERSION_CODES#P}, setting a
+         * conversation title to a non-null value will make {@link #isGroupConversation()} return
+         * {@code true} and passing {@code null} will make it return {@code false}. In
+         * {@link Build.VERSION_CODES#P} and beyond, use {@link #setGroupConversation(boolean)}
+         * to set group conversation status.
+         *
+         * @param conversationTitle Title displayed for this conversation
+         * @return this object for method chaining
          */
-        public MessagingStyle setConversationTitle(CharSequence conversationTitle) {
+        public MessagingStyle setConversationTitle(@Nullable CharSequence conversationTitle) {
             mConversationTitle = conversationTitle;
             return this;
         }
 
         /**
-         * Return the title to be displayed on this conversation. Can be <code>null</code> and
-         * should be for one-on-one conversations
+         * Return the title to be displayed on this conversation. Can be {@code null}.
          */
+        @Nullable
         public CharSequence getConversationTitle() {
             return mConversationTitle;
         }
@@ -2169,6 +2217,42 @@
         }
 
         /**
+         * Sets whether this conversation notification represents a group.
+         * @param isGroupConversation {@code true} if the conversation represents a group,
+         * {@code false} otherwise.
+         * @return this object for method chaining
+         */
+        public MessagingStyle setGroupConversation(boolean isGroupConversation) {
+            mIsGroupConversation = isGroupConversation;
+            return this;
+        }
+
+        /**
+         * Returns {@code true} if this notification represents a group conversation, otherwise
+         * {@code false}.
+         *
+         * <p> If the application that generated this {@link MessagingStyle} targets an SDK version
+         * less than {@link Build.VERSION_CODES#P}, this method becomes dependent on whether or
+         * not the conversation title is set; returning {@code true} if the conversation title is
+         * a non-null value, or {@code false} otherwise. From {@link Build.VERSION_CODES#P} forward,
+         * this method returns what's set by {@link #setGroupConversation(boolean)} allowing for
+         * named, non-group conversations.
+         *
+         * @see #setConversationTitle(CharSequence)
+         */
+        public boolean isGroupConversation() {
+            // When target SDK version is < P, a non-null conversation title dictates if this is
+            // as group conversation.
+            if (mBuilder != null
+                    && mBuilder.mContext.getApplicationInfo().targetSdkVersion
+                    < Build.VERSION_CODES.P) {
+                return mConversationTitle != null;
+            }
+
+            return mIsGroupConversation;
+        }
+
+        /**
          * Retrieves a {@link MessagingStyle} from a {@link Notification}, enabling an application
          * that has set a {@link MessagingStyle} using {@link NotificationCompat} or
          * {@link android.app.Notification.Builder} to send messaging information to another
@@ -2316,6 +2400,7 @@
             if (!mMessages.isEmpty()) { extras.putParcelableArray(EXTRA_MESSAGES,
                     Message.getBundleArrayForMessages(mMessages));
             }
+            extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, mIsGroupConversation);
         }
 
         /**
@@ -2331,6 +2416,7 @@
             if (parcelables != null) {
                 mMessages = Message.getMessagesFromBundleArray(parcelables);
             }
+            mIsGroupConversation = extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION);
         }
 
         public static final class Message {
@@ -2744,6 +2830,71 @@
      * to attach actions.
      */
     public static class Action {
+        /**
+         * {@link SemanticAction}: No semantic action defined.
+         */
+        public static final int SEMANTIC_ACTION_NONE = 0;
+
+        /**
+         * {@link SemanticAction}: Reply to a conversation, chat, group, or wherever replies
+         * may be appropriate.
+         */
+        public static final int SEMANTIC_ACTION_REPLY = 1;
+
+        /**
+         * {@link SemanticAction}: Mark content as read.
+         */
+        public static final int SEMANTIC_ACTION_MARK_AS_READ = 2;
+
+        /**
+         * {@link SemanticAction}: Mark content as unread.
+         */
+        public static final int SEMANTIC_ACTION_MARK_AS_UNREAD = 3;
+
+        /**
+         * {@link SemanticAction}: Delete the content associated with the notification. This
+         * could mean deleting an email, message, etc.
+         */
+        public static final int SEMANTIC_ACTION_DELETE = 4;
+
+        /**
+         * {@link SemanticAction}: Archive the content associated with the notification. This
+         * could mean archiving an email, message, etc.
+         */
+        public static final int SEMANTIC_ACTION_ARCHIVE = 5;
+
+        /**
+         * {@link SemanticAction}: Mute the content associated with the notification. This could
+         * mean silencing a conversation or currently playing media.
+         */
+        public static final int SEMANTIC_ACTION_MUTE = 6;
+
+        /**
+         * {@link SemanticAction}: Unmute the content associated with the notification. This could
+         * mean un-silencing a conversation or currently playing media.
+         */
+        public static final int SEMANTIC_ACTION_UNMUTE = 7;
+
+        /**
+         * {@link SemanticAction}: Mark content with a thumbs up.
+         */
+        public static final int SEMANTIC_ACTION_THUMBS_UP = 8;
+
+        /**
+         * {@link SemanticAction}: Mark content with a thumbs down.
+         */
+        public static final int SEMANTIC_ACTION_THUMBS_DOWN = 9;
+
+        /**
+         * {@link SemanticAction}: Call a contact, group, etc.
+         */
+        public static final int SEMANTIC_ACTION_CALL = 10;
+
+        static final String EXTRA_SHOWS_USER_INTERFACE =
+                "android.support.action.showsUserInterface";
+
+        static final String EXTRA_SEMANTIC_ACTION = "android.support.action.semanticAction";
+
         final Bundle mExtras;
         private final RemoteInput[] mRemoteInputs;
 
@@ -2760,6 +2911,9 @@
         private final RemoteInput[] mDataOnlyRemoteInputs;
 
         private boolean mAllowGeneratedReplies;
+        private boolean mShowsUserInterface = true;
+
+        private final @SemanticAction int mSemanticAction;
 
         /**
          * Small icon representing the action.
@@ -2776,12 +2930,13 @@
         public PendingIntent actionIntent;
 
         public Action(int icon, CharSequence title, PendingIntent intent) {
-            this(icon, title, intent, new Bundle(), null, null, true);
+            this(icon, title, intent, new Bundle(), null, null, true, SEMANTIC_ACTION_NONE, true);
         }
 
         Action(int icon, CharSequence title, PendingIntent intent, Bundle extras,
                 RemoteInput[] remoteInputs, RemoteInput[] dataOnlyRemoteInputs,
-                boolean allowGeneratedReplies) {
+                boolean allowGeneratedReplies, @SemanticAction int semanticAction,
+                boolean showsUserInterface) {
             this.icon = icon;
             this.title = NotificationCompat.Builder.limitCharSequenceLength(title);
             this.actionIntent = intent;
@@ -2789,6 +2944,8 @@
             this.mRemoteInputs = remoteInputs;
             this.mDataOnlyRemoteInputs = dataOnlyRemoteInputs;
             this.mAllowGeneratedReplies = allowGeneratedReplies;
+            this.mSemanticAction = semanticAction;
+            this.mShowsUserInterface = showsUserInterface;
         }
 
         public int getIcon() {
@@ -2828,6 +2985,17 @@
         }
 
         /**
+         * Returns the {@link SemanticAction} associated with this {@link Action}. A
+         * {@link SemanticAction} denotes what an {@link Action}'s {@link PendingIntent} will do
+         * (eg. reply, mark as read, delete, etc).
+         *
+         * @see SemanticAction
+         */
+        public @SemanticAction int getSemanticAction() {
+            return mSemanticAction;
+        }
+
+        /**
          * Get the list of inputs to be collected from the user that ONLY accept data when this
          * action is sent. These remote inputs are guaranteed to return true on a call to
          * {@link RemoteInput#isDataOnly}.
@@ -2842,6 +3010,14 @@
         }
 
         /**
+         * Return whether or not triggering this {@link Action}'s {@link PendingIntent} will open a
+         * user interface.
+         */
+        public boolean getShowsUserInterface() {
+            return mShowsUserInterface;
+        }
+
+        /**
          * Builder class for {@link Action} objects.
          */
         public static final class Builder {
@@ -2851,6 +3027,8 @@
             private boolean mAllowGeneratedReplies = true;
             private final Bundle mExtras;
             private ArrayList<RemoteInput> mRemoteInputs;
+            private @SemanticAction int mSemanticAction;
+            private boolean mShowsUserInterface = true;
 
             /**
              * Construct a new builder for {@link Action} object.
@@ -2859,7 +3037,7 @@
              * @param intent the {@link PendingIntent} to fire when users trigger this action
              */
             public Builder(int icon, CharSequence title, PendingIntent intent) {
-                this(icon, title, intent, new Bundle(), null, true);
+                this(icon, title, intent, new Bundle(), null, true, SEMANTIC_ACTION_NONE, true);
             }
 
             /**
@@ -2869,11 +3047,13 @@
              */
             public Builder(Action action) {
                 this(action.icon, action.title, action.actionIntent, new Bundle(action.mExtras),
-                        action.getRemoteInputs(), action.getAllowGeneratedReplies());
+                        action.getRemoteInputs(), action.getAllowGeneratedReplies(),
+                        action.getSemanticAction(), action.mShowsUserInterface);
             }
 
             private Builder(int icon, CharSequence title, PendingIntent intent, Bundle extras,
-                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
+                    RemoteInput[] remoteInputs, boolean allowGeneratedReplies,
+                    @SemanticAction int semanticAction, boolean showsUserInterface) {
                 mIcon = icon;
                 mTitle = NotificationCompat.Builder.limitCharSequenceLength(title);
                 mIntent = intent;
@@ -2881,6 +3061,8 @@
                 mRemoteInputs = remoteInputs == null ? null : new ArrayList<>(
                         Arrays.asList(remoteInputs));
                 mAllowGeneratedReplies = allowGeneratedReplies;
+                mSemanticAction = semanticAction;
+                mShowsUserInterface = showsUserInterface;
             }
 
             /**
@@ -2936,6 +3118,32 @@
             }
 
             /**
+             * Sets the {@link SemanticAction} for this {@link Action}. A {@link SemanticAction}
+             * denotes what an {@link Action}'s {@link PendingIntent} will do (eg. reply, mark
+             * as read, delete, etc).
+             * @param semanticAction a {@link SemanticAction} defined within {@link Action} with
+             * {@code SEMANTIC_ACTION_} prefixes
+             * @return this object for method chaining
+             */
+            public Builder setSemanticAction(@SemanticAction int semanticAction) {
+                mSemanticAction = semanticAction;
+                return this;
+            }
+
+            /**
+             * Set whether or not this {@link Action}'s {@link PendingIntent} will open a user
+             * interface.
+             * @param showsUserInterface {@code true} if this {@link Action}'s {@link PendingIntent}
+             * will open a user interface, otherwise {@code false}
+             * @return this object for method chaining
+             * The default value is {@code true}
+             */
+            public Builder setShowsUserInterface(boolean showsUserInterface) {
+                mShowsUserInterface = showsUserInterface;
+                return this;
+            }
+
+            /**
              * Apply an extender to this action builder. Extenders may be used to add
              * metadata or change options on this builder.
              */
@@ -2966,7 +3174,8 @@
                 RemoteInput[] textInputsArr = textInputs.isEmpty()
                         ? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
                 return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
-                        dataOnlyInputsArr, mAllowGeneratedReplies);
+                        dataOnlyInputsArr, mAllowGeneratedReplies, mSemanticAction,
+                        mShowsUserInterface);
             }
         }
 
@@ -3226,6 +3435,28 @@
                 return (mFlags & FLAG_HINT_DISPLAY_INLINE) != 0;
             }
         }
+
+        /**
+         * Provides meaning to an {@link Action} that hints at what the associated
+         * {@link PendingIntent} will do. For example, an {@link Action} with a
+         * {@link PendingIntent} that replies to a text message notification may have the
+         * {@link #SEMANTIC_ACTION_REPLY} {@link SemanticAction} set within it.
+         */
+        @IntDef({
+                SEMANTIC_ACTION_NONE,
+                SEMANTIC_ACTION_REPLY,
+                SEMANTIC_ACTION_MARK_AS_READ,
+                SEMANTIC_ACTION_MARK_AS_UNREAD,
+                SEMANTIC_ACTION_DELETE,
+                SEMANTIC_ACTION_ARCHIVE,
+                SEMANTIC_ACTION_MUTE,
+                SEMANTIC_ACTION_UNMUTE,
+                SEMANTIC_ACTION_THUMBS_UP,
+                SEMANTIC_ACTION_THUMBS_DOWN,
+                SEMANTIC_ACTION_CALL
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface SemanticAction {}
     }
 
 
@@ -4135,10 +4366,15 @@
      * to access values.
      */
     public static final class CarExtender implements Extender {
-        private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
+        /** @hide **/
+        @RestrictTo(LIBRARY_GROUP)
+        static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
         private static final String EXTRA_LARGE_ICON = "large_icon";
         private static final String EXTRA_CONVERSATION = "car_conversation";
         private static final String EXTRA_COLOR = "app_color";
+        /** @hide **/
+        @RestrictTo(LIBRARY_GROUP)
+        static final String EXTRA_INVISIBLE_ACTIONS = "invisible_actions";
 
         private static final String KEY_AUTHOR = "author";
         private static final String KEY_TEXT = "text";
@@ -4626,8 +4862,41 @@
             allowGeneratedReplies = action.getExtras().getBoolean(
                     NotificationCompatJellybean.EXTRA_ALLOW_GENERATED_REPLIES);
         }
+
+        final boolean showsUserInterface =
+                action.getExtras().getBoolean(Action.EXTRA_SHOWS_USER_INTERFACE, true);
+
+        final @Action.SemanticAction int semanticAction;
+        if (Build.VERSION.SDK_INT >= 28) {
+            semanticAction = action.getSemanticAction();
+        } else {
+            semanticAction = action.getExtras().getInt(
+                    Action.EXTRA_SEMANTIC_ACTION, Action.SEMANTIC_ACTION_NONE);
+        }
+
         return new Action(action.icon, action.title, action.actionIntent,
-                action.getExtras(), remoteInputs, null, allowGeneratedReplies);
+                action.getExtras(), remoteInputs, null, allowGeneratedReplies,
+                semanticAction, showsUserInterface);
+    }
+
+    /** Returns the invisible actions contained within the given notification. */
+    @RequiresApi(21)
+    public static List<Action> getInvisibleActions(Notification notification) {
+        ArrayList<Action> result = new ArrayList<>();
+
+        Bundle carExtenderBundle = notification.extras.getBundle(CarExtender.EXTRA_CAR_EXTENDER);
+        if (carExtenderBundle == null) {
+            return result;
+        }
+
+        Bundle listBundle = carExtenderBundle.getBundle(CarExtender.EXTRA_INVISIBLE_ACTIONS);
+        if (listBundle != null) {
+            for (int i = 0; i < listBundle.size(); i++) {
+                result.add(NotificationCompatJellybean.getActionFromBundle(
+                        listBundle.getBundle(Integer.toString(i))));
+            }
+        }
+        return result;
     }
 
     /**
diff --git a/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java b/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
index db775a5..35960d2 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationCompatBuilder.java
@@ -151,6 +151,26 @@
                 mBuilder.addPerson(person);
             }
             mHeadsUpContentView = b.mHeadsUpContentView;
+
+            // Invisible actions should be stored in the extender so we need to check if one exists
+            // already.
+            Bundle carExtenderBundle =
+                    b.getExtras().getBundle(NotificationCompat.CarExtender.EXTRA_CAR_EXTENDER);
+            if (carExtenderBundle == null) {
+                carExtenderBundle = new Bundle();
+            }
+            Bundle listBundle = new Bundle();
+            for (int i = 0; i < b.mInvisibleActions.size(); i++) {
+                listBundle.putBundle(
+                        Integer.toString(i),
+                        NotificationCompatJellybean.getBundleForAction(b.mInvisibleActions.get(i)));
+            }
+            carExtenderBundle.putBundle(
+                    NotificationCompat.CarExtender.EXTRA_INVISIBLE_ACTIONS, listBundle);
+            b.getExtras().putBundle(
+                    NotificationCompat.CarExtender.EXTRA_CAR_EXTENDER, carExtenderBundle);
+            mExtras.putBundle(
+                    NotificationCompat.CarExtender.EXTRA_CAR_EXTENDER, carExtenderBundle);
         }
         if (Build.VERSION.SDK_INT >= 24) {
             mBuilder.setExtras(b.mExtras)
@@ -248,6 +268,15 @@
             if (Build.VERSION.SDK_INT >= 24) {
                 actionBuilder.setAllowGeneratedReplies(action.getAllowGeneratedReplies());
             }
+
+            actionExtras.putInt(NotificationCompat.Action.EXTRA_SEMANTIC_ACTION,
+                    action.getSemanticAction());
+            if (Build.VERSION.SDK_INT >= 28) {
+                actionBuilder.setSemanticAction(action.getSemanticAction());
+            }
+
+            actionExtras.putBoolean(NotificationCompat.Action.EXTRA_SHOWS_USER_INTERFACE,
+                    action.getShowsUserInterface());
             actionBuilder.addExtras(actionExtras);
             mBuilder.addAction(actionBuilder.build());
         } else if (Build.VERSION.SDK_INT >= 16) {
diff --git a/compat/src/main/java/android/support/v4/app/NotificationCompatJellybean.java b/compat/src/main/java/android/support/v4/app/NotificationCompatJellybean.java
index 9cdd2e9..82f8941 100644
--- a/compat/src/main/java/android/support/v4/app/NotificationCompatJellybean.java
+++ b/compat/src/main/java/android/support/v4/app/NotificationCompatJellybean.java
@@ -129,7 +129,8 @@
             allowGeneratedReplies = extras.getBoolean(EXTRA_ALLOW_GENERATED_REPLIES);
         }
         return new NotificationCompat.Action(icon, title, actionIntent, extras, remoteInputs,
-                dataOnlyRemoteInputs, allowGeneratedReplies);
+                dataOnlyRemoteInputs, allowGeneratedReplies,
+                NotificationCompat.Action.SEMANTIC_ACTION_NONE, true);
     }
 
     public static Bundle writeActionAndGetExtras(
@@ -236,7 +237,9 @@
                 bundle.getBundle(KEY_EXTRAS),
                 fromBundleArray(getBundleArrayFromBundle(bundle, KEY_REMOTE_INPUTS)),
                 fromBundleArray(getBundleArrayFromBundle(bundle, KEY_DATA_ONLY_REMOTE_INPUTS)),
-                allowGeneratedReplies);
+                allowGeneratedReplies,
+                NotificationCompat.Action.SEMANTIC_ACTION_NONE,
+                true);
     }
 
     static Bundle getBundleForAction(NotificationCompat.Action action) {
diff --git a/compat/src/main/java/android/support/v4/app/SharedElementCallback.java b/compat/src/main/java/android/support/v4/app/SharedElementCallback.java
index c218d86..7b91bd9 100644
--- a/compat/src/main/java/android/support/v4/app/SharedElementCallback.java
+++ b/compat/src/main/java/android/support/v4/app/SharedElementCallback.java
@@ -41,7 +41,7 @@
  */
 public abstract class SharedElementCallback {
     private Matrix mTempMatrix;
-    private static int MAX_IMAGE_SIZE = (1024 * 1024);
+    private static final int MAX_IMAGE_SIZE = 1024 * 1024;
     private static final String BUNDLE_SNAPSHOT_BITMAP = "sharedElement:snapshot:bitmap";
     private static final String BUNDLE_SNAPSHOT_IMAGE_SCALETYPE = "sharedElement:snapshot:imageScaleType";
     private static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "sharedElement:snapshot:imageMatrix";
diff --git a/core-utils/java/android/support/v4/app/TaskStackBuilder.java b/compat/src/main/java/android/support/v4/app/TaskStackBuilder.java
similarity index 100%
rename from core-utils/java/android/support/v4/app/TaskStackBuilder.java
rename to compat/src/main/java/android/support/v4/app/TaskStackBuilder.java
diff --git a/core-utils/java/android/support/v4/content/FileProvider.java b/compat/src/main/java/android/support/v4/content/FileProvider.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/FileProvider.java
rename to compat/src/main/java/android/support/v4/content/FileProvider.java
diff --git a/core-utils/java/android/support/v4/content/MimeTypeFilter.java b/compat/src/main/java/android/support/v4/content/MimeTypeFilter.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/MimeTypeFilter.java
rename to compat/src/main/java/android/support/v4/content/MimeTypeFilter.java
diff --git a/core-utils/java/android/support/v4/content/PermissionChecker.java b/compat/src/main/java/android/support/v4/content/PermissionChecker.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/PermissionChecker.java
rename to compat/src/main/java/android/support/v4/content/PermissionChecker.java
diff --git a/compat/src/main/java/android/support/v4/content/pm/ShortcutInfoCompat.java b/compat/src/main/java/android/support/v4/content/pm/ShortcutInfoCompat.java
index 63585e1..bbfc805 100644
--- a/compat/src/main/java/android/support/v4/content/pm/ShortcutInfoCompat.java
+++ b/compat/src/main/java/android/support/v4/content/pm/ShortcutInfoCompat.java
@@ -301,10 +301,10 @@
         public ShortcutInfoCompat build() {
             // Verify the arguments
             if (TextUtils.isEmpty(mInfo.mLabel)) {
-                throw new IllegalArgumentException("Shortcut much have a non-empty label");
+                throw new IllegalArgumentException("Shortcut must have a non-empty label");
             }
             if (mInfo.mIntents == null || mInfo.mIntents.length == 0) {
-                throw new IllegalArgumentException("Shortcut much have an intent");
+                throw new IllegalArgumentException("Shortcut must have an intent");
             }
             return mInfo;
         }
diff --git a/compat/src/main/java/android/support/v4/content/res/FontResourcesParserCompat.java b/compat/src/main/java/android/support/v4/content/res/FontResourcesParserCompat.java
index 8ad07d3..f597e68 100644
--- a/compat/src/main/java/android/support/v4/content/res/FontResourcesParserCompat.java
+++ b/compat/src/main/java/android/support/v4/content/res/FontResourcesParserCompat.java
@@ -102,13 +102,17 @@
         private final @NonNull String mFileName;
         private int mWeight;
         private boolean mItalic;
+        private String mVariationSettings;
+        private int mTtcIndex;
         private int mResourceId;
 
         public FontFileResourceEntry(@NonNull String fileName, int weight, boolean italic,
-                int resourceId) {
+                @Nullable String variationSettings, int ttcIndex, int resourceId) {
             mFileName = fileName;
             mWeight = weight;
             mItalic = italic;
+            mVariationSettings = variationSettings;
+            mTtcIndex = ttcIndex;
             mResourceId = resourceId;
         }
 
@@ -124,6 +128,14 @@
             return mItalic;
         }
 
+        public @Nullable String getVariationSettings() {
+            return mVariationSettings;
+        }
+
+        public int getTtcIndex() {
+            return mTtcIndex;
+        }
+
         public int getResourceId() {
             return mResourceId;
         }
@@ -260,6 +272,15 @@
                 ? R.styleable.FontFamilyFont_fontStyle
                 : R.styleable.FontFamilyFont_android_fontStyle;
         boolean isItalic = ITALIC == array.getInt(styleAttr, 0);
+        final int ttcIndexAttr = array.hasValue(R.styleable.FontFamilyFont_ttcIndex)
+                ? R.styleable.FontFamilyFont_ttcIndex
+                : R.styleable.FontFamilyFont_android_ttcIndex;
+        final int variationSettingsAttr =
+                array.hasValue(R.styleable.FontFamilyFont_fontVariationSettings)
+                        ? R.styleable.FontFamilyFont_fontVariationSettings
+                        : R.styleable.FontFamilyFont_android_fontVariationSettings;
+        String variationSettings = array.getString(variationSettingsAttr);
+        int ttcIndex = array.getInt(ttcIndexAttr, 0);
         final int resourceAttr = array.hasValue(R.styleable.FontFamilyFont_font)
                 ? R.styleable.FontFamilyFont_font
                 : R.styleable.FontFamilyFont_android_font;
@@ -269,7 +290,8 @@
         while (parser.next() != XmlPullParser.END_TAG) {
             skip(parser);
         }
-        return new FontFileResourceEntry(filename, weight, isItalic, resourceId);
+        return new FontFileResourceEntry(filename, weight, isItalic, variationSettings, ttcIndex,
+                resourceId);
     }
 
     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
diff --git a/compat/src/main/java/android/support/v4/graphics/ColorUtils.java b/compat/src/main/java/android/support/v4/graphics/ColorUtils.java
new file mode 100644
index 0000000..4d1f465
--- /dev/null
+++ b/compat/src/main/java/android/support/v4/graphics/ColorUtils.java
@@ -0,0 +1,618 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.graphics;
+
+import android.graphics.Color;
+import android.support.annotation.ColorInt;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+
+/**
+ * A set of color-related utility methods, building upon those available in {@code Color}.
+ */
+public final class ColorUtils {
+
+    private static final double XYZ_WHITE_REFERENCE_X = 95.047;
+    private static final double XYZ_WHITE_REFERENCE_Y = 100;
+    private static final double XYZ_WHITE_REFERENCE_Z = 108.883;
+    private static final double XYZ_EPSILON = 0.008856;
+    private static final double XYZ_KAPPA = 903.3;
+
+    private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
+    private static final int MIN_ALPHA_SEARCH_PRECISION = 1;
+
+    private static final ThreadLocal<double[]> TEMP_ARRAY = new ThreadLocal<>();
+
+    private ColorUtils() {}
+
+    /**
+     * Composite two potentially translucent colors over each other and returns the result.
+     */
+    public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
+        int bgAlpha = Color.alpha(background);
+        int fgAlpha = Color.alpha(foreground);
+        int a = compositeAlpha(fgAlpha, bgAlpha);
+
+        int r = compositeComponent(Color.red(foreground), fgAlpha,
+                Color.red(background), bgAlpha, a);
+        int g = compositeComponent(Color.green(foreground), fgAlpha,
+                Color.green(background), bgAlpha, a);
+        int b = compositeComponent(Color.blue(foreground), fgAlpha,
+                Color.blue(background), bgAlpha, a);
+
+        return Color.argb(a, r, g, b);
+    }
+
+    private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
+        return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
+    }
+
+    private static int compositeComponent(int fgC, int fgA, int bgC, int bgA, int a) {
+        if (a == 0) return 0;
+        return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
+    }
+
+    /**
+     * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}.
+     * <p>Defined as the Y component in the XYZ representation of {@code color}.</p>
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public static double calculateLuminance(@ColorInt int color) {
+        final double[] result = getTempDouble3Array();
+        colorToXYZ(color, result);
+        // Luminance is the Y component
+        return result[1] / 100;
+    }
+
+    /**
+     * Returns the contrast ratio between {@code foreground} and {@code background}.
+     * {@code background} must be opaque.
+     * <p>
+     * Formula defined
+     * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef">here</a>.
+     */
+    public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) {
+        if (Color.alpha(background) != 255) {
+            throw new IllegalArgumentException("background can not be translucent: #"
+                    + Integer.toHexString(background));
+        }
+        if (Color.alpha(foreground) < 255) {
+            // If the foreground is translucent, composite the foreground over the background
+            foreground = compositeColors(foreground, background);
+        }
+
+        final double luminance1 = calculateLuminance(foreground) + 0.05;
+        final double luminance2 = calculateLuminance(background) + 0.05;
+
+        // Now return the lighter luminance divided by the darker luminance
+        return Math.max(luminance1, luminance2) / Math.min(luminance1, luminance2);
+    }
+
+    /**
+     * Calculates the minimum alpha value which can be applied to {@code foreground} so that would
+     * have a contrast value of at least {@code minContrastRatio} when compared to
+     * {@code background}.
+     *
+     * @param foreground       the foreground color
+     * @param background       the opaque background color
+     * @param minContrastRatio the minimum contrast ratio
+     * @return the alpha value in the range 0-255, or -1 if no value could be calculated
+     */
+    public static int calculateMinimumAlpha(@ColorInt int foreground, @ColorInt int background,
+            float minContrastRatio) {
+        if (Color.alpha(background) != 255) {
+            throw new IllegalArgumentException("background can not be translucent: #"
+                    + Integer.toHexString(background));
+        }
+
+        // First lets check that a fully opaque foreground has sufficient contrast
+        int testForeground = setAlphaComponent(foreground, 255);
+        double testRatio = calculateContrast(testForeground, background);
+        if (testRatio < minContrastRatio) {
+            // Fully opaque foreground does not have sufficient contrast, return error
+            return -1;
+        }
+
+        // Binary search to find a value with the minimum value which provides sufficient contrast
+        int numIterations = 0;
+        int minAlpha = 0;
+        int maxAlpha = 255;
+
+        while (numIterations <= MIN_ALPHA_SEARCH_MAX_ITERATIONS &&
+                (maxAlpha - minAlpha) > MIN_ALPHA_SEARCH_PRECISION) {
+            final int testAlpha = (minAlpha + maxAlpha) / 2;
+
+            testForeground = setAlphaComponent(foreground, testAlpha);
+            testRatio = calculateContrast(testForeground, background);
+
+            if (testRatio < minContrastRatio) {
+                minAlpha = testAlpha;
+            } else {
+                maxAlpha = testAlpha;
+            }
+
+            numIterations++;
+        }
+
+        // Conservatively return the max of the range of possible alphas, which is known to pass.
+        return maxAlpha;
+    }
+
+    /**
+     * Convert RGB components to HSL (hue-saturation-lightness).
+     * <ul>
+     * <li>outHsl[0] is Hue [0 .. 360)</li>
+     * <li>outHsl[1] is Saturation [0...1]</li>
+     * <li>outHsl[2] is Lightness [0...1]</li>
+     * </ul>
+     *
+     * @param r      red component value [0..255]
+     * @param g      green component value [0..255]
+     * @param b      blue component value [0..255]
+     * @param outHsl 3-element array which holds the resulting HSL components
+     */
+    public static void RGBToHSL(@IntRange(from = 0x0, to = 0xFF) int r,
+            @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+            @NonNull float[] outHsl) {
+        final float rf = r / 255f;
+        final float gf = g / 255f;
+        final float bf = b / 255f;
+
+        final float max = Math.max(rf, Math.max(gf, bf));
+        final float min = Math.min(rf, Math.min(gf, bf));
+        final float deltaMaxMin = max - min;
+
+        float h, s;
+        float l = (max + min) / 2f;
+
+        if (max == min) {
+            // Monochromatic
+            h = s = 0f;
+        } else {
+            if (max == rf) {
+                h = ((gf - bf) / deltaMaxMin) % 6f;
+            } else if (max == gf) {
+                h = ((bf - rf) / deltaMaxMin) + 2f;
+            } else {
+                h = ((rf - gf) / deltaMaxMin) + 4f;
+            }
+
+            s = deltaMaxMin / (1f - Math.abs(2f * l - 1f));
+        }
+
+        h = (h * 60f) % 360f;
+        if (h < 0) {
+            h += 360f;
+        }
+
+        outHsl[0] = constrain(h, 0f, 360f);
+        outHsl[1] = constrain(s, 0f, 1f);
+        outHsl[2] = constrain(l, 0f, 1f);
+    }
+
+    /**
+     * Convert the ARGB color to its HSL (hue-saturation-lightness) components.
+     * <ul>
+     * <li>outHsl[0] is Hue [0 .. 360)</li>
+     * <li>outHsl[1] is Saturation [0...1]</li>
+     * <li>outHsl[2] is Lightness [0...1]</li>
+     * </ul>
+     *
+     * @param color  the ARGB color to convert. The alpha component is ignored
+     * @param outHsl 3-element array which holds the resulting HSL components
+     */
+    public static void colorToHSL(@ColorInt int color, @NonNull float[] outHsl) {
+        RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), outHsl);
+    }
+
+    /**
+     * Convert HSL (hue-saturation-lightness) components to a RGB color.
+     * <ul>
+     * <li>hsl[0] is Hue [0 .. 360)</li>
+     * <li>hsl[1] is Saturation [0...1]</li>
+     * <li>hsl[2] is Lightness [0...1]</li>
+     * </ul>
+     * If hsv values are out of range, they are pinned.
+     *
+     * @param hsl 3-element array which holds the input HSL components
+     * @return the resulting RGB color
+     */
+    @ColorInt
+    public static int HSLToColor(@NonNull float[] hsl) {
+        final float h = hsl[0];
+        final float s = hsl[1];
+        final float l = hsl[2];
+
+        final float c = (1f - Math.abs(2 * l - 1f)) * s;
+        final float m = l - 0.5f * c;
+        final float x = c * (1f - Math.abs((h / 60f % 2f) - 1f));
+
+        final int hueSegment = (int) h / 60;
+
+        int r = 0, g = 0, b = 0;
+
+        switch (hueSegment) {
+            case 0:
+                r = Math.round(255 * (c + m));
+                g = Math.round(255 * (x + m));
+                b = Math.round(255 * m);
+                break;
+            case 1:
+                r = Math.round(255 * (x + m));
+                g = Math.round(255 * (c + m));
+                b = Math.round(255 * m);
+                break;
+            case 2:
+                r = Math.round(255 * m);
+                g = Math.round(255 * (c + m));
+                b = Math.round(255 * (x + m));
+                break;
+            case 3:
+                r = Math.round(255 * m);
+                g = Math.round(255 * (x + m));
+                b = Math.round(255 * (c + m));
+                break;
+            case 4:
+                r = Math.round(255 * (x + m));
+                g = Math.round(255 * m);
+                b = Math.round(255 * (c + m));
+                break;
+            case 5:
+            case 6:
+                r = Math.round(255 * (c + m));
+                g = Math.round(255 * m);
+                b = Math.round(255 * (x + m));
+                break;
+        }
+
+        r = constrain(r, 0, 255);
+        g = constrain(g, 0, 255);
+        b = constrain(b, 0, 255);
+
+        return Color.rgb(r, g, b);
+    }
+
+    /**
+     * Set the alpha component of {@code color} to be {@code alpha}.
+     */
+    @ColorInt
+    public static int setAlphaComponent(@ColorInt int color,
+            @IntRange(from = 0x0, to = 0xFF) int alpha) {
+        if (alpha < 0 || alpha > 255) {
+            throw new IllegalArgumentException("alpha must be between 0 and 255.");
+        }
+        return (color & 0x00ffffff) | (alpha << 24);
+    }
+
+    /**
+     * Convert the ARGB color to its CIE Lab representative components.
+     *
+     * @param color  the ARGB color to convert. The alpha component is ignored
+     * @param outLab 3-element array which holds the resulting LAB components
+     */
+    public static void colorToLAB(@ColorInt int color, @NonNull double[] outLab) {
+        RGBToLAB(Color.red(color), Color.green(color), Color.blue(color), outLab);
+    }
+
+    /**
+     * Convert RGB components to its CIE Lab representative components.
+     *
+     * <ul>
+     * <li>outLab[0] is L [0 ...1)</li>
+     * <li>outLab[1] is a [-128...127)</li>
+     * <li>outLab[2] is b [-128...127)</li>
+     * </ul>
+     *
+     * @param r      red component value [0..255]
+     * @param g      green component value [0..255]
+     * @param b      blue component value [0..255]
+     * @param outLab 3-element array which holds the resulting LAB components
+     */
+    public static void RGBToLAB(@IntRange(from = 0x0, to = 0xFF) int r,
+            @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+            @NonNull double[] outLab) {
+        // First we convert RGB to XYZ
+        RGBToXYZ(r, g, b, outLab);
+        // outLab now contains XYZ
+        XYZToLAB(outLab[0], outLab[1], outLab[2], outLab);
+        // outLab now contains LAB representation
+    }
+
+    /**
+     * Convert the ARGB color to its CIE XYZ representative components.
+     *
+     * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+     * 2° Standard Observer (1931).</p>
+     *
+     * <ul>
+     * <li>outXyz[0] is X [0 ...95.047)</li>
+     * <li>outXyz[1] is Y [0...100)</li>
+     * <li>outXyz[2] is Z [0...108.883)</li>
+     * </ul>
+     *
+     * @param color  the ARGB color to convert. The alpha component is ignored
+     * @param outXyz 3-element array which holds the resulting LAB components
+     */
+    public static void colorToXYZ(@ColorInt int color, @NonNull double[] outXyz) {
+        RGBToXYZ(Color.red(color), Color.green(color), Color.blue(color), outXyz);
+    }
+
+    /**
+     * Convert RGB components to its CIE XYZ representative components.
+     *
+     * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+     * 2° Standard Observer (1931).</p>
+     *
+     * <ul>
+     * <li>outXyz[0] is X [0 ...95.047)</li>
+     * <li>outXyz[1] is Y [0...100)</li>
+     * <li>outXyz[2] is Z [0...108.883)</li>
+     * </ul>
+     *
+     * @param r      red component value [0..255]
+     * @param g      green component value [0..255]
+     * @param b      blue component value [0..255]
+     * @param outXyz 3-element array which holds the resulting XYZ components
+     */
+    public static void RGBToXYZ(@IntRange(from = 0x0, to = 0xFF) int r,
+            @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
+            @NonNull double[] outXyz) {
+        if (outXyz.length != 3) {
+            throw new IllegalArgumentException("outXyz must have a length of 3.");
+        }
+
+        double sr = r / 255.0;
+        sr = sr < 0.04045 ? sr / 12.92 : Math.pow((sr + 0.055) / 1.055, 2.4);
+        double sg = g / 255.0;
+        sg = sg < 0.04045 ? sg / 12.92 : Math.pow((sg + 0.055) / 1.055, 2.4);
+        double sb = b / 255.0;
+        sb = sb < 0.04045 ? sb / 12.92 : Math.pow((sb + 0.055) / 1.055, 2.4);
+
+        outXyz[0] = 100 * (sr * 0.4124 + sg * 0.3576 + sb * 0.1805);
+        outXyz[1] = 100 * (sr * 0.2126 + sg * 0.7152 + sb * 0.0722);
+        outXyz[2] = 100 * (sr * 0.0193 + sg * 0.1192 + sb * 0.9505);
+    }
+
+    /**
+     * Converts a color from CIE XYZ to CIE Lab representation.
+     *
+     * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
+     * 2° Standard Observer (1931).</p>
+     *
+     * <ul>
+     * <li>outLab[0] is L [0 ...1)</li>
+     * <li>outLab[1] is a [-128...127)</li>
+     * <li>outLab[2] is b [-128...127)</li>
+     * </ul>
+     *
+     * @param x      X component value [0...95.047)
+     * @param y      Y component value [0...100)
+     * @param z      Z component value [0...108.883)
+     * @param outLab 3-element array which holds the resulting Lab components
+     */
+    public static void XYZToLAB(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
+            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
+            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z,
+            @NonNull double[] outLab) {
+        if (outLab.length != 3) {
+            throw new IllegalArgumentException("outLab must have a length of 3.");
+        }
+        x = pivotXyzComponent(x / XYZ_WHITE_REFERENCE_X);
+        y = pivotXyzComponent(y / XYZ_WHITE_REFERENCE_Y);
+        z = pivotXyzComponent(z / XYZ_WHITE_REFERENCE_Z);
+        outLab[0] = Math.max(0, 116 * y - 16);
+        outLab[1] = 500 * (x - y);
+        outLab[2] = 200 * (y - z);
+    }
+
+    /**
+     * Converts a color from CIE Lab to CIE XYZ representation.
+     *
+     * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
+     * 2° Standard Observer (1931).</p>
+     *
+     * <ul>
+     * <li>outXyz[0] is X [0 ...95.047)</li>
+     * <li>outXyz[1] is Y [0...100)</li>
+     * <li>outXyz[2] is Z [0...108.883)</li>
+     * </ul>
+     *
+     * @param l      L component value [0...100)
+     * @param a      A component value [-128...127)
+     * @param b      B component value [-128...127)
+     * @param outXyz 3-element array which holds the resulting XYZ components
+     */
+    public static void LABToXYZ(@FloatRange(from = 0f, to = 100) final double l,
+            @FloatRange(from = -128, to = 127) final double a,
+            @FloatRange(from = -128, to = 127) final double b,
+            @NonNull double[] outXyz) {
+        final double fy = (l + 16) / 116;
+        final double fx = a / 500 + fy;
+        final double fz = fy - b / 200;
+
+        double tmp = Math.pow(fx, 3);
+        final double xr = tmp > XYZ_EPSILON ? tmp : (116 * fx - 16) / XYZ_KAPPA;
+        final double yr = l > XYZ_KAPPA * XYZ_EPSILON ? Math.pow(fy, 3) : l / XYZ_KAPPA;
+
+        tmp = Math.pow(fz, 3);
+        final double zr = tmp > XYZ_EPSILON ? tmp : (116 * fz - 16) / XYZ_KAPPA;
+
+        outXyz[0] = xr * XYZ_WHITE_REFERENCE_X;
+        outXyz[1] = yr * XYZ_WHITE_REFERENCE_Y;
+        outXyz[2] = zr * XYZ_WHITE_REFERENCE_Z;
+    }
+
+    /**
+     * Converts a color from CIE XYZ to its RGB representation.
+     *
+     * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
+     * 2° Standard Observer (1931).</p>
+     *
+     * @param x X component value [0...95.047)
+     * @param y Y component value [0...100)
+     * @param z Z component value [0...108.883)
+     * @return int containing the RGB representation
+     */
+    @ColorInt
+    public static int XYZToColor(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
+            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
+            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z) {
+        double r = (x * 3.2406 + y * -1.5372 + z * -0.4986) / 100;
+        double g = (x * -0.9689 + y * 1.8758 + z * 0.0415) / 100;
+        double b = (x * 0.0557 + y * -0.2040 + z * 1.0570) / 100;
+
+        r = r > 0.0031308 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
+        g = g > 0.0031308 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
+        b = b > 0.0031308 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
+
+        return Color.rgb(
+                constrain((int) Math.round(r * 255), 0, 255),
+                constrain((int) Math.round(g * 255), 0, 255),
+                constrain((int) Math.round(b * 255), 0, 255));
+    }
+
+    /**
+     * Converts a color from CIE Lab to its RGB representation.
+     *
+     * @param l L component value [0...100]
+     * @param a A component value [-128...127]
+     * @param b B component value [-128...127]
+     * @return int containing the RGB representation
+     */
+    @ColorInt
+    public static int LABToColor(@FloatRange(from = 0f, to = 100) final double l,
+            @FloatRange(from = -128, to = 127) final double a,
+            @FloatRange(from = -128, to = 127) final double b) {
+        final double[] result = getTempDouble3Array();
+        LABToXYZ(l, a, b, result);
+        return XYZToColor(result[0], result[1], result[2]);
+    }
+
+    /**
+     * Returns the euclidean distance between two LAB colors.
+     */
+    public static double distanceEuclidean(@NonNull double[] labX, @NonNull double[] labY) {
+        return Math.sqrt(Math.pow(labX[0] - labY[0], 2)
+                + Math.pow(labX[1] - labY[1], 2)
+                + Math.pow(labX[2] - labY[2], 2));
+    }
+
+    private static float constrain(float amount, float low, float high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+
+    private static int constrain(int amount, int low, int high) {
+        return amount < low ? low : (amount > high ? high : amount);
+    }
+
+    private static double pivotXyzComponent(double component) {
+        return component > XYZ_EPSILON
+                ? Math.pow(component, 1 / 3.0)
+                : (XYZ_KAPPA * component + 16) / 116;
+    }
+
+    /**
+     * Blend between two ARGB colors using the given ratio.
+     *
+     * <p>A blend ratio of 0.0 will result in {@code color1}, 0.5 will give an even blend,
+     * 1.0 will result in {@code color2}.</p>
+     *
+     * @param color1 the first ARGB color
+     * @param color2 the second ARGB color
+     * @param ratio  the blend ratio of {@code color1} to {@code color2}
+     */
+    @ColorInt
+    public static int blendARGB(@ColorInt int color1, @ColorInt int color2,
+            @FloatRange(from = 0.0, to = 1.0) float ratio) {
+        final float inverseRatio = 1 - ratio;
+        float a = Color.alpha(color1) * inverseRatio + Color.alpha(color2) * ratio;
+        float r = Color.red(color1) * inverseRatio + Color.red(color2) * ratio;
+        float g = Color.green(color1) * inverseRatio + Color.green(color2) * ratio;
+        float b = Color.blue(color1) * inverseRatio + Color.blue(color2) * ratio;
+        return Color.argb((int) a, (int) r, (int) g, (int) b);
+    }
+
+    /**
+     * Blend between {@code hsl1} and {@code hsl2} using the given ratio. This will interpolate
+     * the hue using the shortest angle.
+     *
+     * <p>A blend ratio of 0.0 will result in {@code hsl1}, 0.5 will give an even blend,
+     * 1.0 will result in {@code hsl2}.</p>
+     *
+     * @param hsl1      3-element array which holds the first HSL color
+     * @param hsl2      3-element array which holds the second HSL color
+     * @param ratio     the blend ratio of {@code hsl1} to {@code hsl2}
+     * @param outResult 3-element array which holds the resulting HSL components
+     */
+    public static void blendHSL(@NonNull float[] hsl1, @NonNull float[] hsl2,
+            @FloatRange(from = 0.0, to = 1.0) float ratio, @NonNull float[] outResult) {
+        if (outResult.length != 3) {
+            throw new IllegalArgumentException("result must have a length of 3.");
+        }
+        final float inverseRatio = 1 - ratio;
+        // Since hue is circular we will need to interpolate carefully
+        outResult[0] = circularInterpolate(hsl1[0], hsl2[0], ratio);
+        outResult[1] = hsl1[1] * inverseRatio + hsl2[1] * ratio;
+        outResult[2] = hsl1[2] * inverseRatio + hsl2[2] * ratio;
+    }
+
+    /**
+     * Blend between two CIE-LAB colors using the given ratio.
+     *
+     * <p>A blend ratio of 0.0 will result in {@code lab1}, 0.5 will give an even blend,
+     * 1.0 will result in {@code lab2}.</p>
+     *
+     * @param lab1      3-element array which holds the first LAB color
+     * @param lab2      3-element array which holds the second LAB color
+     * @param ratio     the blend ratio of {@code lab1} to {@code lab2}
+     * @param outResult 3-element array which holds the resulting LAB components
+     */
+    public static void blendLAB(@NonNull double[] lab1, @NonNull double[] lab2,
+            @FloatRange(from = 0.0, to = 1.0) double ratio, @NonNull double[] outResult) {
+        if (outResult.length != 3) {
+            throw new IllegalArgumentException("outResult must have a length of 3.");
+        }
+        final double inverseRatio = 1 - ratio;
+        outResult[0] = lab1[0] * inverseRatio + lab2[0] * ratio;
+        outResult[1] = lab1[1] * inverseRatio + lab2[1] * ratio;
+        outResult[2] = lab1[2] * inverseRatio + lab2[2] * ratio;
+    }
+
+    @VisibleForTesting
+    static float circularInterpolate(float a, float b, float f) {
+        if (Math.abs(b - a) > 180) {
+            if (b > a) {
+                a += 360;
+            } else {
+                b += 360;
+            }
+        }
+        return (a + ((b - a) * f)) % 360;
+    }
+
+    private static double[] getTempDouble3Array() {
+        double[] result = TEMP_ARRAY.get();
+        if (result == null) {
+            result = new double[3];
+            TEMP_ARRAY.set(result);
+        }
+        return result;
+    }
+
+}
diff --git a/compat/src/main/java/android/support/v4/graphics/TypefaceCompat.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompat.java
index 3c55df6..b763101 100644
--- a/compat/src/main/java/android/support/v4/graphics/TypefaceCompat.java
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompat.java
@@ -32,10 +32,10 @@
 import android.support.v4.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry;
 import android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
 import android.support.v4.content.res.ResourcesCompat;
+import android.support.v4.os.BuildCompat;
 import android.support.v4.provider.FontsContractCompat;
 import android.support.v4.provider.FontsContractCompat.FontInfo;
 import android.support.v4.util.LruCache;
-
 /**
  * Helper for accessing features in {@link Typeface}.
  * @hide
@@ -46,7 +46,9 @@
 
     private static final TypefaceCompatImpl sTypefaceCompatImpl;
     static {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+        if (BuildCompat.isAtLeastP()) {
+            sTypefaceCompatImpl = new TypefaceCompatApi28Impl();
+        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
             sTypefaceCompatImpl = new TypefaceCompatApi26Impl();
         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
                 && TypefaceCompatApi24Impl.isUsable()) {
diff --git a/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
index 89a6ec4..a8c1988 100644
--- a/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi24Impl.java
@@ -159,8 +159,7 @@
             if (buffer == null) {
                 return null;
             }
-            // TODO: support ttc index.
-            if (!addFontWeightStyle(family, buffer, 0, e.getWeight(), e.isItalic())) {
+            if (!addFontWeightStyle(family, buffer, e.getTtcIndex(), e.getWeight(), e.isItalic())) {
                 return null;
             }
         }
diff --git a/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
index 28ab3ed..955284e 100644
--- a/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi26Impl.java
@@ -60,76 +60,70 @@
             "createFromFamiliesWithDefault";
     private static final String FREEZE_METHOD = "freeze";
     private static final String ABORT_CREATION_METHOD = "abortCreation";
-    private static final Class sFontFamily;
-    private static final Constructor sFontFamilyCtor;
-    private static final Method sAddFontFromAssetManager;
-    private static final Method sAddFontFromBuffer;
-    private static final Method sFreeze;
-    private static final Method sAbortCreation;
-    private static final Method sCreateFromFamiliesWithDefault;
     private static final int RESOLVE_BY_FONT_TABLE = -1;
+    private static final String DEFAULT_FAMILY = "sans-serif";
 
-    static {
-        Class fontFamilyClass;
+    protected final Class mFontFamily;
+    protected final Constructor mFontFamilyCtor;
+    protected final Method mAddFontFromAssetManager;
+    protected final Method mAddFontFromBuffer;
+    protected final Method mFreeze;
+    protected final Method mAbortCreation;
+    protected final Method mCreateFromFamiliesWithDefault;
+
+    public TypefaceCompatApi26Impl() {
+        Class fontFamily;
         Constructor fontFamilyCtor;
-        Method addFontMethod;
-        Method addFromBufferMethod;
-        Method freezeMethod;
-        Method abortCreationMethod;
-        Method createFromFamiliesWithDefaultMethod;
+        Method addFontFromAssetManager;
+        Method addFontFromBuffer;
+        Method freeze;
+        Method abortCreation;
+        Method createFromFamiliesWithDefault;
         try {
-            fontFamilyClass = Class.forName(FONT_FAMILY_CLASS);
-            fontFamilyCtor = fontFamilyClass.getConstructor();
-            addFontMethod = fontFamilyClass.getMethod(ADD_FONT_FROM_ASSET_MANAGER_METHOD,
-                    AssetManager.class, String.class, Integer.TYPE, Boolean.TYPE, Integer.TYPE,
-                    Integer.TYPE, Integer.TYPE, FontVariationAxis[].class);
-            addFromBufferMethod = fontFamilyClass.getMethod(ADD_FONT_FROM_BUFFER_METHOD,
-                    ByteBuffer.class, Integer.TYPE, FontVariationAxis[].class, Integer.TYPE,
-                    Integer.TYPE);
-            freezeMethod = fontFamilyClass.getMethod(FREEZE_METHOD);
-            abortCreationMethod = fontFamilyClass.getMethod(ABORT_CREATION_METHOD);
-            Object familyArray = Array.newInstance(fontFamilyClass, 1);
-            createFromFamiliesWithDefaultMethod =
-                    Typeface.class.getDeclaredMethod(CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD,
-                            familyArray.getClass(), Integer.TYPE, Integer.TYPE);
-            createFromFamiliesWithDefaultMethod.setAccessible(true);
+            fontFamily = obtainFontFamily();
+            fontFamilyCtor = obtainFontFamilyCtor(fontFamily);
+            addFontFromAssetManager = obtainAddFontFromAssetManagerMethod(fontFamily);
+            addFontFromBuffer = obtainAddFontFromBufferMethod(fontFamily);
+            freeze = obtainFreezeMethod(fontFamily);
+            abortCreation = obtainAbortCreationMethod(fontFamily);
+            createFromFamiliesWithDefault = obtainCreateFromFamiliesWithDefaultMethod(fontFamily);
         } catch (ClassNotFoundException | NoSuchMethodException e) {
             Log.e(TAG, "Unable to collect necessary methods for class " + e.getClass().getName(),
                     e);
-            fontFamilyClass = null;
+            fontFamily = null;
             fontFamilyCtor = null;
-            addFontMethod = null;
-            addFromBufferMethod = null;
-            freezeMethod = null;
-            abortCreationMethod = null;
-            createFromFamiliesWithDefaultMethod = null;
+            addFontFromAssetManager = null;
+            addFontFromBuffer = null;
+            freeze = null;
+            abortCreation = null;
+            createFromFamiliesWithDefault = null;
         }
-        sFontFamilyCtor = fontFamilyCtor;
-        sFontFamily = fontFamilyClass;
-        sAddFontFromAssetManager = addFontMethod;
-        sAddFontFromBuffer = addFromBufferMethod;
-        sFreeze = freezeMethod;
-        sAbortCreation = abortCreationMethod;
-        sCreateFromFamiliesWithDefault = createFromFamiliesWithDefaultMethod;
+        mFontFamily = fontFamily;
+        mFontFamilyCtor = fontFamilyCtor;
+        mAddFontFromAssetManager = addFontFromAssetManager;
+        mAddFontFromBuffer = addFontFromBuffer;
+        mFreeze = freeze;
+        mAbortCreation = abortCreation;
+        mCreateFromFamiliesWithDefault = createFromFamiliesWithDefault;
     }
 
     /**
-     * Returns true if API26 implementation is usable.
+     * Returns true if all the necessary methods were found.
      */
-    private static boolean isFontFamilyPrivateAPIAvailable() {
-        if (sAddFontFromAssetManager == null) {
+    private boolean isFontFamilyPrivateAPIAvailable() {
+        if (mAddFontFromAssetManager == null) {
             Log.w(TAG, "Unable to collect necessary private methods. "
                     + "Fallback to legacy implementation.");
         }
-        return sAddFontFromAssetManager != null;
+        return mAddFontFromAssetManager != null;
     }
 
     /**
      * Create a new FontFamily instance
      */
-    private static Object newFamily() {
+    private Object newFamily() {
         try {
-            return sFontFamilyCtor.newInstance();
+            return mFontFamilyCtor.newInstance();
         } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
             throw new RuntimeException(e);
         }
@@ -139,12 +133,12 @@
      * Call FontFamily#addFontFromAssetManager(AssetManager mgr, String path, int cookie,
      *      boolean isAsset, int ttcIndex, int weight, int isItalic, FontVariationAxis[] axes)
      */
-    private static boolean addFontFromAssetManager(Context context, Object family, String fileName,
-            int ttcIndex, int weight, int style) {
+    private boolean addFontFromAssetManager(Context context, Object family, String fileName,
+            int ttcIndex, int weight, int style, @Nullable FontVariationAxis[] axes) {
         try {
-            final Boolean result = (Boolean) sAddFontFromAssetManager.invoke(family,
+            final Boolean result = (Boolean) mAddFontFromAssetManager.invoke(family,
                     context.getAssets(), fileName, 0 /* cookie */, false /* isAsset */, ttcIndex,
-                    weight, style, null /* axes */);
+                    weight, style, axes);
             return result.booleanValue();
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new RuntimeException(e);
@@ -155,10 +149,10 @@
      * Call FontFamily#addFontFromBuffer(ByteBuffer font, int ttcIndex, FontVariationAxis[] axes,
      *      int weight, int italic)
      */
-    private static boolean addFontFromBuffer(Object family, ByteBuffer buffer,
+    private boolean addFontFromBuffer(Object family, ByteBuffer buffer,
             int ttcIndex, int weight, int style) {
         try {
-            final Boolean result = (Boolean) sAddFontFromBuffer.invoke(family,
+            final Boolean result = (Boolean) mAddFontFromBuffer.invoke(family,
                     buffer, ttcIndex, null /* axes */, weight, style);
             return result.booleanValue();
         } catch (IllegalAccessException | InvocationTargetException e) {
@@ -167,14 +161,14 @@
     }
 
     /**
-     * Call static method Typeface#createFromFamiliesWithDefault(
+     * Call method Typeface#createFromFamiliesWithDefault(
      *      FontFamily[] families, int weight, int italic)
      */
-    private static Typeface createFromFamiliesWithDefault(Object family) {
+    protected Typeface createFromFamiliesWithDefault(Object family) {
         try {
-            Object familyArray = Array.newInstance(sFontFamily, 1);
+            Object familyArray = Array.newInstance(mFontFamily, 1);
             Array.set(familyArray, 0, family);
-            return (Typeface) sCreateFromFamiliesWithDefault.invoke(null /* static method */,
+            return (Typeface) mCreateFromFamiliesWithDefault.invoke(null /* static method */,
                     familyArray, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new RuntimeException(e);
@@ -184,9 +178,9 @@
     /**
      * Call FontFamily#freeze()
      */
-    private static boolean freeze(Object family) {
+    private boolean freeze(Object family) {
         try {
-            Boolean result = (Boolean) sFreeze.invoke(family);
+            Boolean result = (Boolean) mFreeze.invoke(family);
             return result.booleanValue();
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new RuntimeException(e);
@@ -196,9 +190,9 @@
     /**
      * Call FontFamily#abortCreation()
      */
-    private static void abortCreation(Object family) {
+    private void abortCreation(Object family) {
         try {
-            sAbortCreation.invoke(family);
+            mAbortCreation.invoke(family);
         } catch (IllegalAccessException | InvocationTargetException e) {
             throw new RuntimeException(e);
         }
@@ -213,9 +207,9 @@
         }
         Object fontFamily = newFamily();
         for (final FontFileResourceEntry fontFile : entry.getEntries()) {
-            // TODO: Add ttc and variation font support. (b/37853920)
             if (!addFontFromAssetManager(context, fontFamily, fontFile.getFileName(),
-                    0 /* ttcIndex */, fontFile.getWeight(), fontFile.isItalic() ? 1 : 0)) {
+                    fontFile.getTtcIndex(), fontFile.getWeight(), fontFile.isItalic() ? 1 : 0,
+                    FontVariationAxis.fromFontVariationSettings(fontFile.getVariationSettings()))) {
                 abortCreation(fontFamily);
                 return null;
             }
@@ -292,7 +286,7 @@
         Object fontFamily = newFamily();
         if (!addFontFromAssetManager(context, fontFamily, path,
                 0 /* ttcIndex */, RESOLVE_BY_FONT_TABLE /* weight */,
-                RESOLVE_BY_FONT_TABLE /* italic */)) {
+                RESOLVE_BY_FONT_TABLE /* italic */, null /* axes */)) {
             abortCreation(fontFamily);
             return null;
         }
@@ -301,4 +295,47 @@
         }
         return createFromFamiliesWithDefault(fontFamily);
     }
+
+    // The following getters retrieve by reflection the Typeface methods, belonging to the
+    // framework code, which will be invoked. Since the definitions of these methods can change
+    // across different API versions, inheriting classes should override these getters in order to
+    // reflect the method definitions in the API versions they represent.
+    //===========================================================================================
+    protected Class obtainFontFamily() throws ClassNotFoundException {
+        return Class.forName(FONT_FAMILY_CLASS);
+    }
+
+    protected Constructor obtainFontFamilyCtor(Class fontFamily) throws NoSuchMethodException {
+        return fontFamily.getConstructor();
+    }
+
+    protected Method obtainAddFontFromAssetManagerMethod(Class fontFamily)
+            throws NoSuchMethodException {
+        return fontFamily.getMethod(ADD_FONT_FROM_ASSET_MANAGER_METHOD,
+                AssetManager.class, String.class, Integer.TYPE, Boolean.TYPE, Integer.TYPE,
+                Integer.TYPE, Integer.TYPE, FontVariationAxis[].class);
+    }
+
+    protected Method obtainAddFontFromBufferMethod(Class fontFamily) throws NoSuchMethodException {
+        return fontFamily.getMethod(ADD_FONT_FROM_BUFFER_METHOD,
+                ByteBuffer.class, Integer.TYPE, FontVariationAxis[].class, Integer.TYPE,
+                Integer.TYPE);
+    }
+
+    protected Method obtainFreezeMethod(Class fontFamily) throws NoSuchMethodException {
+        return fontFamily.getMethod(FREEZE_METHOD);
+    }
+
+    protected Method obtainAbortCreationMethod(Class fontFamily) throws NoSuchMethodException {
+        return fontFamily.getMethod(ABORT_CREATION_METHOD);
+    }
+
+    protected Method obtainCreateFromFamiliesWithDefaultMethod(Class fontFamily)
+            throws NoSuchMethodException {
+        Object familyArray = Array.newInstance(fontFamily, 1);
+        Method m =  Typeface.class.getDeclaredMethod(CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD,
+                familyArray.getClass(), Integer.TYPE, Integer.TYPE);
+        m.setAccessible(true);
+        return m;
+    }
 }
diff --git a/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi28Impl.java b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi28Impl.java
new file mode 100644
index 0000000..baa2ce6
--- /dev/null
+++ b/compat/src/main/java/android/support/v4/graphics/TypefaceCompatApi28Impl.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.graphics;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.graphics.Typeface;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Implementation of the Typeface compat methods for API 28 and above.
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+@RequiresApi(28)
+public class TypefaceCompatApi28Impl extends TypefaceCompatApi26Impl {
+    private static final String TAG = "TypefaceCompatApi28Impl";
+
+    private static final String CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD =
+            "createFromFamiliesWithDefault";
+    private static final int RESOLVE_BY_FONT_TABLE = -1;
+    private static final String DEFAULT_FAMILY = "sans-serif";
+
+    /**
+     * Call method Typeface#createFromFamiliesWithDefault(
+     *      FontFamily[] families, String fallbackName, int weight, int italic)
+     */
+    @Override
+    protected Typeface createFromFamiliesWithDefault(Object family) {
+        try {
+            Object familyArray = Array.newInstance(mFontFamily, 1);
+            Array.set(familyArray, 0, family);
+            return (Typeface) mCreateFromFamiliesWithDefault.invoke(null /* static method */,
+                    familyArray, DEFAULT_FAMILY, RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected Method obtainCreateFromFamiliesWithDefaultMethod(Class fontFamily)
+            throws NoSuchMethodException {
+        Object familyArray = Array.newInstance(fontFamily, 1);
+        Method m =  Typeface.class.getDeclaredMethod(CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD,
+                familyArray.getClass(), String.class, Integer.TYPE, Integer.TYPE);
+        m.setAccessible(true);
+        return m;
+    }
+}
diff --git a/compat/src/main/java/android/support/v4/graphics/drawable/IconCompat.java b/compat/src/main/java/android/support/v4/graphics/drawable/IconCompat.java
index 359c96b..dc226c1 100644
--- a/compat/src/main/java/android/support/v4/graphics/drawable/IconCompat.java
+++ b/compat/src/main/java/android/support/v4/graphics/drawable/IconCompat.java
@@ -220,6 +220,7 @@
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
+    @SuppressWarnings("deprecation")
     public void addToShortcutIntent(@NonNull Intent outIntent, @Nullable Drawable badge) {
         Bitmap icon;
         switch (mType) {
diff --git a/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java b/compat/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
similarity index 100%
rename from core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable.java
diff --git a/core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java b/compat/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
similarity index 100%
rename from core-utils/api21/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawable21.java
diff --git a/core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java b/compat/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
similarity index 100%
rename from core-utils/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
rename to compat/src/main/java/android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory.java
diff --git a/compat/src/main/java/android/support/v4/internal/view/SupportMenu.java b/compat/src/main/java/android/support/v4/internal/view/SupportMenu.java
index c072151..c512da9 100644
--- a/compat/src/main/java/android/support/v4/internal/view/SupportMenu.java
+++ b/compat/src/main/java/android/support/v4/internal/view/SupportMenu.java
@@ -64,5 +64,13 @@
      * Flag which stops the Menu being closed when a sub menu is opened
      */
     int FLAG_KEEP_OPEN_ON_SUBMENU_OPENED = 4;
+
+    /**
+     * Enable or disable the group dividers.
+     *
+     * @param enabled True if enabled.
+     */
+    @Override
+    void setGroupDividerEnabled(boolean enabled);
 }
 
diff --git a/core-utils/java/android/support/v4/math/MathUtils.java b/compat/src/main/java/android/support/v4/math/MathUtils.java
similarity index 100%
rename from core-utils/java/android/support/v4/math/MathUtils.java
rename to compat/src/main/java/android/support/v4/math/MathUtils.java
diff --git a/compat/src/main/java/android/support/v4/text/BidiFormatter.java b/compat/src/main/java/android/support/v4/text/BidiFormatter.java
index b3b8b1c..f04d5ab 100644
--- a/compat/src/main/java/android/support/v4/text/BidiFormatter.java
+++ b/compat/src/main/java/android/support/v4/text/BidiFormatter.java
@@ -81,7 +81,7 @@
     /**
      * The default text direction heuristic.
      */
-    private static TextDirectionHeuristicCompat DEFAULT_TEXT_DIRECTION_HEURISTIC = FIRSTSTRONG_LTR;
+    private static final TextDirectionHeuristicCompat DEFAULT_TEXT_DIRECTION_HEURISTIC = FIRSTSTRONG_LTR;
 
     /**
      * Unicode "Left-To-Right Embedding" (LRE) character.
diff --git a/compat/src/main/java/android/support/v4/text/util/FindAddress.java b/compat/src/main/java/android/support/v4/text/util/FindAddress.java
new file mode 100644
index 0000000..82cba62
--- /dev/null
+++ b/compat/src/main/java/android/support/v4/text/util/FindAddress.java
@@ -0,0 +1,516 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.text.util;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+
+import java.util.Locale;
+import java.util.regex.MatchResult;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Support copy of https://cs.chromium.org/chromium/src/android_webview/java/src/org/chromium
+ * /android_webview/FindAddress.java
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+class FindAddress {
+    private static class ZipRange {
+        int mLow;
+        int mHigh;
+        int mException1;
+        int mException2;
+
+        ZipRange(int low, int high, int exception1, int exception2) {
+            mLow = low;
+            mHigh = high;
+            mException1 = exception1;
+            mException2 = exception1;
+        }
+
+        boolean matches(String zipCode) {
+            int prefix = Integer.parseInt(zipCode.substring(0, 2));
+            return (mLow <= prefix && prefix <= mHigh) || prefix == mException1
+                    || prefix == mException2;
+        }
+    }
+
+    // Addresses consist of at least this many words, not including state and zip code.
+    private static final int MIN_ADDRESS_WORDS = 4;
+
+    // Adddresses consist of at most this many words, not including state and zip code.
+    private static final int MAX_ADDRESS_WORDS = 14;
+
+    // Addresses consist of at most this many lines.
+    private static final int MAX_ADDRESS_LINES = 5;
+
+    // No words in an address are longer than this many characters.
+    private static final int kMaxAddressNameWordLength = 25;
+
+    // Location name should be in the first MAX_LOCATION_NAME_DISTANCE words
+    private static final int MAX_LOCATION_NAME_DISTANCE = 5;
+
+    private static final ZipRange[] sStateZipCodeRanges = {
+            new ZipRange(99, 99, -1, -1), // AK Alaska.
+            new ZipRange(35, 36, -1, -1), // AL Alabama.
+            new ZipRange(71, 72, -1, -1), // AR Arkansas.
+            new ZipRange(96, 96, -1, -1), // AS American Samoa.
+            new ZipRange(85, 86, -1, -1), // AZ Arizona.
+            new ZipRange(90, 96, -1, -1), // CA California.
+            new ZipRange(80, 81, -1, -1), // CO Colorado.
+            new ZipRange(6, 6, -1, -1), // CT Connecticut.
+            new ZipRange(20, 20, -1, -1), // DC District of Columbia.
+            new ZipRange(19, 19, -1, -1), // DE Delaware.
+            new ZipRange(32, 34, -1, -1), // FL Florida.
+            new ZipRange(96, 96, -1, -1), // FM Federated States of Micronesia.
+            new ZipRange(30, 31, -1, -1), // GA Georgia.
+            new ZipRange(96, 96, -1, -1), // GU Guam.
+            new ZipRange(96, 96, -1, -1), // HI Hawaii.
+            new ZipRange(50, 52, -1, -1), // IA Iowa.
+            new ZipRange(83, 83, -1, -1), // ID Idaho.
+            new ZipRange(60, 62, -1, -1), // IL Illinois.
+            new ZipRange(46, 47, -1, -1), // IN Indiana.
+            new ZipRange(66, 67, 73, -1), // KS Kansas.
+            new ZipRange(40, 42, -1, -1), // KY Kentucky.
+            new ZipRange(70, 71, -1, -1), // LA Louisiana.
+            new ZipRange(1, 2, -1, -1), // MA Massachusetts.
+            new ZipRange(20, 21, -1, -1), // MD Maryland.
+            new ZipRange(3, 4, -1, -1), // ME Maine.
+            new ZipRange(96, 96, -1, -1), // MH Marshall Islands.
+            new ZipRange(48, 49, -1, -1), // MI Michigan.
+            new ZipRange(55, 56, -1, -1), // MN Minnesota.
+            new ZipRange(63, 65, -1, -1), // MO Missouri.
+            new ZipRange(96, 96, -1, -1), // MP Northern Mariana Islands.
+            new ZipRange(38, 39, -1, -1), // MS Mississippi.
+            new ZipRange(55, 56, -1, -1), // MT Montana.
+            new ZipRange(27, 28, -1, -1), // NC North Carolina.
+            new ZipRange(58, 58, -1, -1), // ND North Dakota.
+            new ZipRange(68, 69, -1, -1), // NE Nebraska.
+            new ZipRange(3, 4, -1, -1), // NH New Hampshire.
+            new ZipRange(7, 8, -1, -1), // NJ New Jersey.
+            new ZipRange(87, 88, 86, -1), // NM New Mexico.
+            new ZipRange(88, 89, 96, -1), // NV Nevada.
+            new ZipRange(10, 14, 0, 6), // NY New York.
+            new ZipRange(43, 45, -1, -1), // OH Ohio.
+            new ZipRange(73, 74, -1, -1), // OK Oklahoma.
+            new ZipRange(97, 97, -1, -1), // OR Oregon.
+            new ZipRange(15, 19, -1, -1), // PA Pennsylvania.
+            new ZipRange(6, 6, 0, 9), // PR Puerto Rico.
+            new ZipRange(96, 96, -1, -1), // PW Palau.
+            new ZipRange(2, 2, -1, -1), // RI Rhode Island.
+            new ZipRange(29, 29, -1, -1), // SC South Carolina.
+            new ZipRange(57, 57, -1, -1), // SD South Dakota.
+            new ZipRange(37, 38, -1, -1), // TN Tennessee.
+            new ZipRange(75, 79, 87, 88), // TX Texas.
+            new ZipRange(84, 84, -1, -1), // UT Utah.
+            new ZipRange(22, 24, 20, -1), // VA Virginia.
+            new ZipRange(6, 9, -1, -1), // VI Virgin Islands.
+            new ZipRange(5, 5, -1, -1), // VT Vermont.
+            new ZipRange(98, 99, -1, -1), // WA Washington.
+            new ZipRange(53, 54, -1, -1), // WI Wisconsin.
+            new ZipRange(24, 26, -1, -1), // WV West Virginia.
+            new ZipRange(82, 83, -1, -1) // WY Wyoming.
+    };
+
+    // Newlines
+    private static final String NL = "\n\u000B\u000C\r\u0085\u2028\u2029";
+
+    // Space characters
+    private static final String SP = "\u0009\u0020\u00A0\u1680\u2000\u2001"
+            + "\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F"
+            + "\u205F\u3000";
+
+    // Whitespace
+    private static final String WS = SP + NL;
+
+    // Characters that are considered word delimiters.
+    private static final String WORD_DELIM = ",*\u2022" + WS;
+
+    // Lookahead for word end.
+    private static final String WORD_END = "(?=[" + WORD_DELIM + "]|$)";
+
+    // Address words are a sequence of non-delimiter characters.
+    private static final Pattern sWordRe =
+            Pattern.compile("[^" + WORD_DELIM + "]+" + WORD_END, Pattern.CASE_INSENSITIVE);
+
+    // Characters that are considered suffix delimiters for house numbers.
+    private static final String HOUSE_POST_DELIM = ",\"'" + WS;
+
+    // Lookahead for house end.
+    private static final String HOUSE_END = "(?=[" + HOUSE_POST_DELIM + "]|$)";
+
+    // Characters that are considered prefix delimiters for house numbers.
+    private static final String HOUSE_PRE_DELIM = ":" + HOUSE_POST_DELIM;
+
+    // A house number component is "one" or a number, optionally
+    // followed by a single alphabetic character, or
+    private static final String HOUSE_COMPONENT = "(?:one|\\d+([a-z](?=[^a-z]|$)|st|nd|rd|th)?)";
+
+    // House numbers are a repetition of |HOUSE_COMPONENT|, separated by -, and followed by
+    // a delimiter character.
+    private static final Pattern sHouseNumberRe =
+            Pattern.compile(HOUSE_COMPONENT + "(?:-" + HOUSE_COMPONENT + ")*" + HOUSE_END,
+                    Pattern.CASE_INSENSITIVE);
+
+    // XXX: do we want to accept whitespace other than 0x20 in state names?
+    private static final Pattern sStateRe = Pattern.compile("(?:"
+                    + "(ak|alaska)|"
+                    + "(al|alabama)|"
+                    + "(ar|arkansas)|"
+                    + "(as|american[" + SP + "]+samoa)|"
+                    + "(az|arizona)|"
+                    + "(ca|california)|"
+                    + "(co|colorado)|"
+                    + "(ct|connecticut)|"
+                    + "(dc|district[" + SP + "]+of[" + SP + "]+columbia)|"
+                    + "(de|delaware)|"
+                    + "(fl|florida)|"
+                    + "(fm|federated[" + SP + "]+states[" + SP + "]+of[" + SP + "]+micronesia)|"
+                    + "(ga|georgia)|"
+                    + "(gu|guam)|"
+                    + "(hi|hawaii)|"
+                    + "(ia|iowa)|"
+                    + "(id|idaho)|"
+                    + "(il|illinois)|"
+                    + "(in|indiana)|"
+                    + "(ks|kansas)|"
+                    + "(ky|kentucky)|"
+                    + "(la|louisiana)|"
+                    + "(ma|massachusetts)|"
+                    + "(md|maryland)|"
+                    + "(me|maine)|"
+                    + "(mh|marshall[" + SP + "]+islands)|"
+                    + "(mi|michigan)|"
+                    + "(mn|minnesota)|"
+                    + "(mo|missouri)|"
+                    + "(mp|northern[" + SP + "]+mariana[" + SP + "]+islands)|"
+                    + "(ms|mississippi)|"
+                    + "(mt|montana)|"
+                    + "(nc|north[" + SP + "]+carolina)|"
+                    + "(nd|north[" + SP + "]+dakota)|"
+                    + "(ne|nebraska)|"
+                    + "(nh|new[" + SP + "]+hampshire)|"
+                    + "(nj|new[" + SP + "]+jersey)|"
+                    + "(nm|new[" + SP + "]+mexico)|"
+                    + "(nv|nevada)|"
+                    + "(ny|new[" + SP + "]+york)|"
+                    + "(oh|ohio)|"
+                    + "(ok|oklahoma)|"
+                    + "(or|oregon)|"
+                    + "(pa|pennsylvania)|"
+                    + "(pr|puerto[" + SP + "]+rico)|"
+                    + "(pw|palau)|"
+                    + "(ri|rhode[" + SP + "]+island)|"
+                    + "(sc|south[" + SP + "]+carolina)|"
+                    + "(sd|south[" + SP + "]+dakota)|"
+                    + "(tn|tennessee)|"
+                    + "(tx|texas)|"
+                    + "(ut|utah)|"
+                    + "(va|virginia)|"
+                    + "(vi|virgin[" + SP + "]+islands)|"
+                    + "(vt|vermont)|"
+                    + "(wa|washington)|"
+                    + "(wi|wisconsin)|"
+                    + "(wv|west[" + SP + "]+virginia)|"
+                    + "(wy|wyoming)"
+                    + ")" + WORD_END,
+            Pattern.CASE_INSENSITIVE);
+
+    private static final Pattern sLocationNameRe = Pattern.compile("(?:"
+                    + "alley|annex|arcade|ave[.]?|avenue|alameda|bayou|"
+                    + "beach|bend|bluffs?|bottom|boulevard|branch|bridge|"
+                    + "brooks?|burgs?|bypass|broadway|camino|camp|canyon|"
+                    + "cape|causeway|centers?|circles?|cliffs?|club|common|"
+                    + "corners?|course|courts?|coves?|creek|crescent|crest|"
+                    + "crossing|crossroad|curve|circulo|dale|dam|divide|"
+                    + "drives?|estates?|expressway|extensions?|falls?|ferry|"
+                    + "fields?|flats?|fords?|forest|forges?|forks?|fort|"
+                    + "freeway|gardens?|gateway|glens?|greens?|groves?|"
+                    + "harbors?|haven|heights|highway|hills?|hollow|inlet|"
+                    + "islands?|isle|junctions?|keys?|knolls?|lakes?|land|"
+                    + "landing|lane|lights?|loaf|locks?|lodge|loop|mall|"
+                    + "manors?|meadows?|mews|mills?|mission|motorway|mount|"
+                    + "mountains?|neck|orchard|oval|overpass|parks?|"
+                    + "parkways?|pass|passage|path|pike|pines?|plains?|"
+                    + "plaza|points?|ports?|prairie|privada|radial|ramp|"
+                    + "ranch|rapids?|rd[.]?|rest|ridges?|river|roads?|route|"
+                    + "row|rue|run|shoals?|shores?|skyway|springs?|spurs?|"
+                    + "squares?|station|stravenue|stream|st[.]?|streets?|"
+                    + "summit|speedway|terrace|throughway|trace|track|"
+                    + "trafficway|trail|tunnel|turnpike|underpass|unions?|"
+                    + "valleys?|viaduct|views?|villages?|ville|vista|walks?|"
+                    + "wall|ways?|wells?|xing|xrd)" + WORD_END,
+            Pattern.CASE_INSENSITIVE);
+
+    private static final Pattern sSuffixedNumberRe =
+            Pattern.compile("(\\d+)(st|nd|rd|th)", Pattern.CASE_INSENSITIVE);
+
+    private static final Pattern sZipCodeRe =
+            Pattern.compile("(?:\\d{5}(?:-\\d{4})?)" + WORD_END, Pattern.CASE_INSENSITIVE);
+
+    private static boolean checkHouseNumber(String houseNumber) {
+        // Make sure that there are at most 5 digits.
+        int digitCount = 0;
+        for (int i = 0; i < houseNumber.length(); ++i) {
+            if (Character.isDigit(houseNumber.charAt(i))) ++digitCount;
+        }
+        if (digitCount > 5) return false;
+
+        // Make sure that any ordinals are valid.
+        Matcher suffixMatcher = sSuffixedNumberRe.matcher(houseNumber);
+        while (suffixMatcher.find()) {
+            int num = Integer.parseInt(suffixMatcher.group(1));
+            if (num == 0) {
+                return false; // 0th is invalid.
+            }
+            String suffix = suffixMatcher.group(2).toLowerCase(Locale.getDefault());
+            switch (num % 10) {
+                case 1:
+                    return suffix.equals(num % 100 == 11 ? "th" : "st");
+                case 2:
+                    return suffix.equals(num % 100 == 12 ? "th" : "nd");
+                case 3:
+                    return suffix.equals(num % 100 == 13 ? "th" : "rd");
+                default:
+                    return suffix.equals("th");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Attempt to match a house number beginnning at position offset
+     * in content.  The house number must be followed by a word
+     * delimiter or the end of the string, and if offset is non-zero,
+     * then it must also be preceded by a word delimiter.
+     *
+     * @return a MatchResult if a valid house number was found.
+     */
+    @VisibleForTesting
+    public static MatchResult matchHouseNumber(String content, int offset) {
+        if (offset > 0 && HOUSE_PRE_DELIM.indexOf(content.charAt(offset - 1)) == -1) return null;
+        Matcher matcher = sHouseNumberRe.matcher(content).region(offset, content.length());
+        if (matcher.lookingAt()) {
+            MatchResult matchResult = matcher.toMatchResult();
+            if (checkHouseNumber(matchResult.group(0))) return matchResult;
+        }
+        return null;
+    }
+
+    /**
+     * Attempt to match a US state beginnning at position offset in
+     * content.  The matching state must be followed by a word
+     * delimiter or the end of the string, and if offset is non-zero,
+     * then it must also be preceded by a word delimiter.
+     *
+     * @return a MatchResult if a valid US state (or two letter code)
+     * was found.
+     */
+    @VisibleForTesting
+    public static MatchResult matchState(String content, int offset) {
+        if (offset > 0 && WORD_DELIM.indexOf(content.charAt(offset - 1)) == -1) return null;
+        Matcher stateMatcher = sStateRe.matcher(content).region(offset, content.length());
+        return stateMatcher.lookingAt() ? stateMatcher.toMatchResult() : null;
+    }
+
+    /**
+     * Test whether zipCode matches the U.S. zip code format (ddddd or
+     * ddddd-dddd) and is within the expected range, given that
+     * stateMatch is a match of sStateRe.
+     *
+     * @return true if zipCode is a valid zip code, is legal for the
+     * matched state, and is followed by a word delimiter or the end
+     * of the string.
+     */
+    private static boolean isValidZipCode(String zipCode, MatchResult stateMatch) {
+        if (stateMatch == null) return false;
+        // Work out the index of the state, based on which group matched.
+        int stateIndex = stateMatch.groupCount();
+        while (stateIndex > 0) {
+            if (stateMatch.group(stateIndex--) != null) break;
+        }
+        return sZipCodeRe.matcher(zipCode).matches()
+                && sStateZipCodeRanges[stateIndex].matches(zipCode);
+    }
+
+    /**
+     * Test whether zipCode matches the U.S. zip code format (ddddd or
+     * ddddd-dddd) and is within the expected range, given that
+     * state holds a string that will match sStateRe.
+     *
+     * @return true if zipCode is a valid zip code, is legal for the
+     * given state, and is followed by a word delimiter or the end
+     * of the string.
+     */
+    @VisibleForTesting
+    public static boolean isValidZipCode(String zipCode, String state) {
+        return isValidZipCode(zipCode, matchState(state, 0));
+    }
+
+    /**
+     * Test whether zipCode matches the U.S. zip code format (ddddd or ddddd-dddd).
+     *
+     * @return true if zipCode is a valid zip code followed by a word
+     * delimiter or the end of the string.
+     */
+    @VisibleForTesting
+    public static boolean isValidZipCode(String zipCode) {
+        return sZipCodeRe.matcher(zipCode).matches();
+    }
+
+    /**
+     * Test whether location is one of the valid locations.
+     *
+     * @return true if location starts with a valid location name
+     * followed by a word delimiter or the end of the string.
+     */
+    @VisibleForTesting
+    public static boolean isValidLocationName(String location) {
+        return sLocationNameRe.matcher(location).matches();
+    }
+
+    /**
+     * Attempt to match a complete address in content, starting with
+     * houseNumberMatch.
+     *
+     * @param content          The string to search.
+     * @param houseNumberMatch A matching house number to start extending.
+     * @return +ve: the end of the match
+     * +ve: the position to restart searching for house numbers, negated.
+     */
+    private static int attemptMatch(String content, MatchResult houseNumberMatch) {
+        int restartPos = -1;
+        int nonZipMatch = -1;
+        int it = houseNumberMatch.end();
+        int numLines = 1;
+        boolean consecutiveHouseNumbers = true;
+        boolean foundLocationName = false;
+        int wordCount = 1;
+        String lastWord = "";
+
+        Matcher matcher = sWordRe.matcher(content);
+
+        for (; it < content.length(); lastWord = matcher.group(0), it = matcher.end()) {
+            if (!matcher.find(it)) {
+                // No more words in the input sequence.
+                return -content.length();
+            }
+            if (matcher.end() - matcher.start() > kMaxAddressNameWordLength) {
+                // Word is too long to be part of an address. Fail.
+                return -matcher.end();
+            }
+
+            // Count the number of newlines we just consumed.
+            while (it < matcher.start()) {
+                if (NL.indexOf(content.charAt(it++)) != -1) ++numLines;
+            }
+
+            // Consumed too many lines. Fail.
+            if (numLines > MAX_ADDRESS_LINES) break;
+
+            // Consumed too many words. Fail.
+            if (++wordCount > MAX_ADDRESS_WORDS) break;
+
+            if (matchHouseNumber(content, it) != null) {
+                if (consecutiveHouseNumbers && numLines > 1) {
+                    // Last line ended with a number, and this this line starts with one.
+                    // Restart at this number.
+                    return -it;
+                }
+                // Remember the position of this match as the restart position.
+                if (restartPos == -1) restartPos = it;
+                continue;
+            }
+
+            consecutiveHouseNumbers = false;
+
+            if (isValidLocationName(matcher.group(0))) {
+                foundLocationName = true;
+                continue;
+            }
+
+            if (wordCount == MAX_LOCATION_NAME_DISTANCE && !foundLocationName) {
+                // Didn't find a location name in time. Fail.
+                it = matcher.end();
+                break;
+            }
+
+            if (foundLocationName && wordCount > MIN_ADDRESS_WORDS) {
+                // We can now attempt to match a state.
+                MatchResult stateMatch = matchState(content, it);
+                if (stateMatch != null) {
+                    if (lastWord.equals("et") && stateMatch.group(0).equals("al")) {
+                        // Reject "et al" as a false postitive.
+                        it = stateMatch.end();
+                        break;
+                    }
+
+                    // At this point we've matched a state; try to match a zip code after it.
+                    Matcher zipMatcher = sWordRe.matcher(content);
+                    if (zipMatcher.find(stateMatch.end())
+                            && isValidZipCode(zipMatcher.group(0), stateMatch)) {
+                        return zipMatcher.end();
+                    }
+                    // The content ends with a state but no zip
+                    // code. This is a legal match according to the
+                    // documentation. N.B. This differs from the
+                    // original c++ implementation, which only allowed
+                    // the zip code to be optional at the end of the
+                    // string, which presumably is a bug.  Now we
+                    // prefer to find a match with a zip code, but
+                    // remember non-zip matches and return them if
+                    // necessary.
+                    nonZipMatch = stateMatch.end();
+                }
+            }
+        }
+
+        if (nonZipMatch > 0) return nonZipMatch;
+
+        return -(restartPos > 0 ? restartPos : it);
+    }
+
+    /**
+     * Return the first matching address in content.
+     *
+     * @param content The string to search.
+     * @return The first valid address, or null if no address was matched.
+     */
+    @VisibleForTesting
+    public static String findAddress(String content) {
+        Matcher houseNumberMatcher = sHouseNumberRe.matcher(content);
+        int start = 0;
+        while (houseNumberMatcher.find(start)) {
+            if (checkHouseNumber(houseNumberMatcher.group(0))) {
+                start = houseNumberMatcher.start();
+                int end = attemptMatch(content, houseNumberMatcher);
+                if (end > 0) {
+                    return content.substring(start, end);
+                }
+                start = -end;
+            } else {
+                start = houseNumberMatcher.end();
+            }
+        }
+        return null;
+    }
+}
diff --git a/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java b/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
index efd4c85..32d1914 100644
--- a/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
+++ b/compat/src/main/java/android/support/v4/text/util/LinkifyCompat.java
@@ -18,11 +18,11 @@
 
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
-import android.os.Build;
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
+import android.support.v4.os.BuildCompat;
 import android.support.v4.util.PatternsCompat;
 import android.text.Spannable;
 import android.text.SpannableString;
@@ -97,7 +97,7 @@
      *  @return True if at least one link is found and applied.
      */
     public static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) {
-        if (Build.VERSION.SDK_INT >= 27) {
+        if (shouldAddLinksFallbackToFramework()) {
             return Linkify.addLinks(text, mask);
         }
         if (mask == 0) {
@@ -110,13 +110,11 @@
             text.removeSpan(old[i]);
         }
 
-        // Use framework to linkify phone numbers.
-        boolean frameworkReturn = false;
         if ((mask & Linkify.PHONE_NUMBERS) != 0) {
-            frameworkReturn = Linkify.addLinks(text, Linkify.PHONE_NUMBERS);
+            Linkify.addLinks(text, Linkify.PHONE_NUMBERS);
         }
 
-        ArrayList<LinkSpec> links = new ArrayList<LinkSpec>();
+        final ArrayList<LinkSpec> links = new ArrayList<>();
 
         if ((mask & Linkify.WEB_URLS) != 0) {
             gatherLinks(links, text, PatternsCompat.AUTOLINK_WEB_URL,
@@ -161,7 +159,7 @@
      *  @return True if at least one link is found and applied.
      */
     public static boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) {
-        if (Build.VERSION.SDK_INT >= 26) {
+        if (shouldAddLinksFallbackToFramework()) {
             return Linkify.addLinks(text, mask);
         }
         if (mask == 0) {
@@ -204,7 +202,7 @@
      */
     public static void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
             @Nullable String scheme) {
-        if (Build.VERSION.SDK_INT >= 26) {
+        if (shouldAddLinksFallbackToFramework()) {
             Linkify.addLinks(text, pattern, scheme);
             return;
         }
@@ -228,7 +226,7 @@
     public static void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
             @Nullable String scheme, @Nullable MatchFilter matchFilter,
             @Nullable TransformFilter transformFilter) {
-        if (Build.VERSION.SDK_INT >= 26) {
+        if (shouldAddLinksFallbackToFramework()) {
             Linkify.addLinks(text, pattern, scheme, matchFilter, transformFilter);
             return;
         }
@@ -255,7 +253,7 @@
     public static void addLinks(@NonNull TextView text, @NonNull Pattern pattern,
             @Nullable String defaultScheme, @Nullable String[] schemes,
             @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
-        if (Build.VERSION.SDK_INT >= 26) {
+        if (shouldAddLinksFallbackToFramework()) {
             Linkify.addLinks(text, pattern, defaultScheme, schemes, matchFilter, transformFilter);
             return;
         }
@@ -280,7 +278,7 @@
      */
     public static boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern,
             @Nullable String scheme) {
-        if (Build.VERSION.SDK_INT >= 26) {
+        if (shouldAddLinksFallbackToFramework()) {
             return Linkify.addLinks(text, pattern, scheme);
         }
         return addLinks(text, pattern, scheme, null, null, null);
@@ -304,7 +302,7 @@
     public static boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable String scheme, @Nullable MatchFilter matchFilter,
             @Nullable TransformFilter transformFilter) {
-        if (Build.VERSION.SDK_INT >= 26) {
+        if (shouldAddLinksFallbackToFramework()) {
             return Linkify.addLinks(spannable, pattern, scheme, matchFilter, transformFilter);
         }
         return addLinks(spannable, pattern, scheme, null, matchFilter,
@@ -330,7 +328,7 @@
     public static boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern,
             @Nullable  String defaultScheme, @Nullable String[] schemes,
             @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter) {
-        if (Build.VERSION.SDK_INT >= 26) {
+        if (shouldAddLinksFallbackToFramework()) {
             return Linkify.addLinks(spannable, pattern, defaultScheme, schemes, matchFilter,
                     transformFilter);
         }
@@ -370,6 +368,10 @@
         return hasMatches;
     }
 
+    private static boolean shouldAddLinksFallbackToFramework() {
+        return BuildCompat.isAtLeastP();
+    }
+
     private static void addLinkMovementMethod(@NonNull TextView t) {
         MovementMethod m = t.getMovementMethod();
 
@@ -442,7 +444,7 @@
         int base = 0;
 
         try {
-            while ((address = WebView.findAddress(string)) != null) {
+            while ((address = findAddress(string)) != null) {
                 int start = string.indexOf(address);
 
                 if (start < 0) {
@@ -477,6 +479,13 @@
         }
     }
 
+    private static String findAddress(String addr) {
+        if (BuildCompat.isAtLeastP()) {
+            return WebView.findAddress(addr);
+        }
+        return FindAddress.findAddress(addr);
+    }
+
     private static void pruneOverlaps(ArrayList<LinkSpec> links, Spannable text) {
         // Append spans added by framework
         URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
diff --git a/compat/src/main/java/android/support/v4/util/ArrayMap.java b/compat/src/main/java/android/support/v4/util/ArrayMap.java
deleted file mode 100644
index 0a8a0ab..0000000
--- a/compat/src/main/java/android/support/v4/util/ArrayMap.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.util;
-
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * ArrayMap is a generic key->value mapping data structure that is
- * designed to be more memory efficient than a traditional {@link java.util.HashMap},
- * this implementation is a version of the platform's
- * {@link android.util.ArrayMap} that can be used on older versions of the platform.
- * It keeps its mappings in an array data structure -- an integer array of hash
- * codes for each item, and an Object array of the key/value pairs.  This allows it to
- * avoid having to create an extra object for every entry put in to the map, and it
- * also tries to control the growth of the size of these arrays more aggressively
- * (since growing them only requires copying the entries in the array, not rebuilding
- * a hash map).
- *
- * <p>If you don't need the standard Java container APIs provided here (iterators etc),
- * consider using {@link SimpleArrayMap} instead.</p>
- *
- * <p>Note that this implementation is not intended to be appropriate for data structures
- * that may contain large numbers of items.  It is generally slower than a traditional
- * HashMap, since lookups require a binary search and adds and removes require inserting
- * and deleting entries in the array.  For containers holding up to hundreds of items,
- * the performance difference is not significant, less than 50%.</p>
- *
- * <p>Because this container is intended to better balance memory use, unlike most other
- * standard Java containers it will shrink its array as items are removed from it.  Currently
- * you have no control over this shrinking -- if you set a capacity and then remove an
- * item, it may reduce the capacity to better match the current size.  In the future an
- * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
- */
-public class ArrayMap<K, V> extends SimpleArrayMap<K, V> implements Map<K, V> {
-    MapCollections<K, V> mCollections;
-
-    public ArrayMap() {
-        super();
-    }
-
-    /**
-     * Create a new ArrayMap with a given initial capacity.
-     */
-    public ArrayMap(int capacity) {
-        super(capacity);
-    }
-
-    /**
-     * Create a new ArrayMap with the mappings from the given ArrayMap.
-     */
-    public ArrayMap(SimpleArrayMap map) {
-        super(map);
-    }
-
-    private MapCollections<K, V> getCollection() {
-        if (mCollections == null) {
-            mCollections = new MapCollections<K, V>() {
-                @Override
-                protected int colGetSize() {
-                    return mSize;
-                }
-
-                @Override
-                protected Object colGetEntry(int index, int offset) {
-                    return mArray[(index<<1) + offset];
-                }
-
-                @Override
-                protected int colIndexOfKey(Object key) {
-                    return indexOfKey(key);
-                }
-
-                @Override
-                protected int colIndexOfValue(Object value) {
-                    return indexOfValue(value);
-                }
-
-                @Override
-                protected Map<K, V> colGetMap() {
-                    return ArrayMap.this;
-                }
-
-                @Override
-                protected void colPut(K key, V value) {
-                    put(key, value);
-                }
-
-                @Override
-                protected V colSetValue(int index, V value) {
-                    return setValueAt(index, value);
-                }
-
-                @Override
-                protected void colRemoveAt(int index) {
-                    removeAt(index);
-                }
-
-                @Override
-                protected void colClear() {
-                    clear();
-                }
-            };
-        }
-        return mCollections;
-    }
-
-    /**
-     * Determine if the array map contains all of the keys in the given collection.
-     * @param collection The collection whose contents are to be checked against.
-     * @return Returns true if this array map contains a key for every entry
-     * in <var>collection</var>, else returns false.
-     */
-    public boolean containsAll(Collection<?> collection) {
-        return MapCollections.containsAllHelper(this, collection);
-    }
-
-    /**
-     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>map</var>
-     * @param map The map whose contents are to be retrieved.
-     */
-    @Override
-    public void putAll(Map<? extends K, ? extends V> map) {
-        ensureCapacity(mSize + map.size());
-        for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
-            put(entry.getKey(), entry.getValue());
-        }
-    }
-
-    /**
-     * Remove all keys in the array map that exist in the given collection.
-     * @param collection The collection whose contents are to be used to remove keys.
-     * @return Returns true if any keys were removed from the array map, else false.
-     */
-    public boolean removeAll(Collection<?> collection) {
-        return MapCollections.removeAllHelper(this, collection);
-    }
-
-    /**
-     * Remove all keys in the array map that do <b>not</b> exist in the given collection.
-     * @param collection The collection whose contents are to be used to determine which
-     * keys to keep.
-     * @return Returns true if any keys were removed from the array map, else false.
-     */
-    public boolean retainAll(Collection<?> collection) {
-        return MapCollections.retainAllHelper(this, collection);
-    }
-
-    /**
-     * Return a {@link java.util.Set} for iterating over and interacting with all mappings
-     * in the array map.
-     *
-     * <p><b>Note:</b> this is a very inefficient way to access the array contents, it
-     * requires generating a number of temporary objects.</p>
-     *
-     * <p><b>Note:</b></p> the semantics of this
-     * Set are subtly different than that of a {@link java.util.HashMap}: most important,
-     * the {@link java.util.Map.Entry Map.Entry} object returned by its iterator is a single
-     * object that exists for the entire iterator, so you can <b>not</b> hold on to it
-     * after calling {@link java.util.Iterator#next() Iterator.next}.</p>
-     */
-    @Override
-    public Set<Entry<K, V>> entrySet() {
-        return getCollection().getEntrySet();
-    }
-
-    /**
-     * Return a {@link java.util.Set} for iterating over and interacting with all keys
-     * in the array map.
-     *
-     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
-     * requires generating a number of temporary objects.</p>
-     */
-    @Override
-    public Set<K> keySet() {
-        return getCollection().getKeySet();
-    }
-
-    /**
-     * Return a {@link java.util.Collection} for iterating over and interacting with all values
-     * in the array map.
-     *
-     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
-     * requires generating a number of temporary objects.</p>
-     */
-    @Override
-    public Collection<V> values() {
-        return getCollection().getValues();
-    }
-}
diff --git a/compat/src/main/java/android/support/v4/util/ArraySet.java b/compat/src/main/java/android/support/v4/util/ArraySet.java
deleted file mode 100644
index 8444d2c..0000000
--- a/compat/src/main/java/android/support/v4/util/ArraySet.java
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.util;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.util.Log;
-
-import java.lang.reflect.Array;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * ArraySet is a generic set data structure that is designed to be more memory efficient than a
- * traditional {@link java.util.HashSet}.  The design is very similar to
- * {@link ArrayMap}, with all of the caveats described there.  This implementation is
- * separate from ArrayMap, however, so the Object array contains only one item for each
- * entry in the set (instead of a pair for a mapping).
- *
- * <p>Note that this implementation is not intended to be appropriate for data structures
- * that may contain large numbers of items.  It is generally slower than a traditional
- * HashSet, since lookups require a binary search and adds and removes require inserting
- * and deleting entries in the array.  For containers holding up to hundreds of items,
- * the performance difference is not significant, less than 50%.</p>
- *
- * <p>Because this container is intended to better balance memory use, unlike most other
- * standard Java containers it will shrink its array as items are removed from it.  Currently
- * you have no control over this shrinking -- if you set a capacity and then remove an
- * item, it may reduce the capacity to better match the current size.  In the future an
- * explicit call to set the capacity should turn off this aggressive shrinking behavior.</p>
- */
-public final class ArraySet<E> implements Collection<E>, Set<E> {
-    private static final boolean DEBUG = false;
-    private static final String TAG = "ArraySet";
-    private static final int[] INT = new int[0];
-    private static final Object[] OBJECT = new Object[0];
-
-    /**
-     * The minimum amount by which the capacity of a ArraySet will increase.
-     * This is tuned to be relatively space-efficient.
-     */
-    private static final int BASE_SIZE = 4;
-
-    /**
-     * Maximum number of entries to have in array caches.
-     */
-    private static final int CACHE_SIZE = 10;
-
-    /**
-     * Caches of small array objects to avoid spamming garbage.  The cache
-     * Object[] variable is a pointer to a linked list of array objects.
-     * The first entry in the array is a pointer to the next array in the
-     * list; the second entry is a pointer to the int[] hash code array for it.
-     */
-    private static Object[] sBaseCache;
-    private static int sBaseCacheSize;
-    private static Object[] sTwiceBaseCache;
-    private static int sTwiceBaseCacheSize;
-
-    private int[] mHashes;
-    private Object[] mArray;
-    private int mSize;
-    private MapCollections<E, E> mCollections;
-
-    private int indexOf(Object key, int hash) {
-        final int N = mSize;
-
-        // Important fast case: if nothing is in here, nothing to look for.
-        if (N == 0) {
-            return ~0;
-        }
-
-        int index = ContainerHelpers.binarySearch(mHashes, N, hash);
-
-        // If the hash code wasn't found, then we have no entry for this key.
-        if (index < 0) {
-            return index;
-        }
-
-        // If the key at the returned index matches, that's what we want.
-        if (key.equals(mArray[index])) {
-            return index;
-        }
-
-        // Search for a matching key after the index.
-        int end;
-        for (end = index + 1; end < N && mHashes[end] == hash; end++) {
-            if (key.equals(mArray[end])) return end;
-        }
-
-        // Search for a matching key before the index.
-        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
-            if (key.equals(mArray[i])) return i;
-        }
-
-        // Key not found -- return negative value indicating where a
-        // new entry for this key should go.  We use the end of the
-        // hash chain to reduce the number of array entries that will
-        // need to be copied when inserting.
-        return ~end;
-    }
-
-    private int indexOfNull() {
-        final int N = mSize;
-
-        // Important fast case: if nothing is in here, nothing to look for.
-        if (N == 0) {
-            return ~0;
-        }
-
-        int index = ContainerHelpers.binarySearch(mHashes, N, 0);
-
-        // If the hash code wasn't found, then we have no entry for this key.
-        if (index < 0) {
-            return index;
-        }
-
-        // If the key at the returned index matches, that's what we want.
-        if (null == mArray[index]) {
-            return index;
-        }
-
-        // Search for a matching key after the index.
-        int end;
-        for (end = index + 1; end < N && mHashes[end] == 0; end++) {
-            if (null == mArray[end]) return end;
-        }
-
-        // Search for a matching key before the index.
-        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {
-            if (null == mArray[i]) return i;
-        }
-
-        // Key not found -- return negative value indicating where a
-        // new entry for this key should go.  We use the end of the
-        // hash chain to reduce the number of array entries that will
-        // need to be copied when inserting.
-        return ~end;
-    }
-
-    @SuppressWarnings("ArrayToString")
-    private void allocArrays(final int size) {
-        if (size == (BASE_SIZE * 2)) {
-            synchronized (ArraySet.class) {
-                if (sTwiceBaseCache != null) {
-                    final Object[] array = sTwiceBaseCache;
-                    mArray = array;
-                    sTwiceBaseCache = (Object[]) array[0];
-                    mHashes = (int[]) array[1];
-                    array[0] = array[1] = null;
-                    sTwiceBaseCacheSize--;
-                    if (DEBUG) {
-                        Log.d(TAG, "Retrieving 2x cache " + mHashes + " now have "
-                                + sTwiceBaseCacheSize + " entries");
-                    }
-                    return;
-                }
-            }
-        } else if (size == BASE_SIZE) {
-            synchronized (ArraySet.class) {
-                if (sBaseCache != null) {
-                    final Object[] array = sBaseCache;
-                    mArray = array;
-                    sBaseCache = (Object[]) array[0];
-                    mHashes = (int[]) array[1];
-                    array[0] = array[1] = null;
-                    sBaseCacheSize--;
-                    if (DEBUG) {
-                        Log.d(TAG, "Retrieving 1x cache " + mHashes + " now have " + sBaseCacheSize
-                                + " entries");
-                    }
-                    return;
-                }
-            }
-        }
-
-        mHashes = new int[size];
-        mArray = new Object[size];
-    }
-
-    @SuppressWarnings("ArrayToString")
-    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
-        if (hashes.length == (BASE_SIZE * 2)) {
-            synchronized (ArraySet.class) {
-                if (sTwiceBaseCacheSize < CACHE_SIZE) {
-                    array[0] = sTwiceBaseCache;
-                    array[1] = hashes;
-                    for (int i = size - 1; i >= 2; i--) {
-                        array[i] = null;
-                    }
-                    sTwiceBaseCache = array;
-                    sTwiceBaseCacheSize++;
-                    if (DEBUG) {
-                        Log.d(TAG, "Storing 2x cache " + array + " now have " + sTwiceBaseCacheSize
-                                + " entries");
-                    }
-                }
-            }
-        } else if (hashes.length == BASE_SIZE) {
-            synchronized (ArraySet.class) {
-                if (sBaseCacheSize < CACHE_SIZE) {
-                    array[0] = sBaseCache;
-                    array[1] = hashes;
-                    for (int i = size - 1; i >= 2; i--) {
-                        array[i] = null;
-                    }
-                    sBaseCache = array;
-                    sBaseCacheSize++;
-                    if (DEBUG) {
-                        Log.d(TAG, "Storing 1x cache " + array + " now have "
-                                + sBaseCacheSize + " entries");
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Create a new empty ArraySet.  The default capacity of an array map is 0, and
-     * will grow once items are added to it.
-     */
-    public ArraySet() {
-        this(0);
-    }
-
-    /**
-     * Create a new ArraySet with a given initial capacity.
-     */
-    public ArraySet(int capacity) {
-        if (capacity == 0) {
-            mHashes = INT;
-            mArray = OBJECT;
-        } else {
-            allocArrays(capacity);
-        }
-        mSize = 0;
-    }
-
-    /**
-     * Create a new ArraySet with the mappings from the given ArraySet.
-     */
-    public ArraySet(@Nullable ArraySet<E> set) {
-        this();
-        if (set != null) {
-            addAll(set);
-        }
-    }
-
-    /**
-     * Create a new ArraySet with the mappings from the given {@link Collection}.
-     */
-    public ArraySet(@Nullable Collection<E> set) {
-        this();
-        if (set != null) {
-            addAll(set);
-        }
-    }
-
-    /**
-     * Make the array map empty.  All storage is released.
-     */
-    @Override
-    public void clear() {
-        if (mSize != 0) {
-            freeArrays(mHashes, mArray, mSize);
-            mHashes = INT;
-            mArray = OBJECT;
-            mSize = 0;
-        }
-    }
-
-    /**
-     * Ensure the array map can hold at least <var>minimumCapacity</var>
-     * items.
-     */
-    public void ensureCapacity(int minimumCapacity) {
-        if (mHashes.length < minimumCapacity) {
-            final int[] ohashes = mHashes;
-            final Object[] oarray = mArray;
-            allocArrays(minimumCapacity);
-            if (mSize > 0) {
-                System.arraycopy(ohashes, 0, mHashes, 0, mSize);
-                System.arraycopy(oarray, 0, mArray, 0, mSize);
-            }
-            freeArrays(ohashes, oarray, mSize);
-        }
-    }
-
-    /**
-     * Check whether a value exists in the set.
-     *
-     * @param key The value to search for.
-     * @return Returns true if the value exists, else false.
-     */
-    @Override
-    public boolean contains(Object key) {
-        return indexOf(key) >= 0;
-    }
-
-    /**
-     * Returns the index of a value in the set.
-     *
-     * @param key The value to search for.
-     * @return Returns the index of the value if it exists, else a negative integer.
-     */
-    public int indexOf(Object key) {
-        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
-    }
-
-    /**
-     * Return the value at the given index in the array.
-     * @param index The desired index, must be between 0 and {@link #size()}-1.
-     * @return Returns the value stored at the given index.
-     */
-    @Nullable
-    public E valueAt(int index) {
-        return (E) mArray[index];
-    }
-
-    /**
-     * Return true if the array map contains no items.
-     */
-    @Override
-    public boolean isEmpty() {
-        return mSize <= 0;
-    }
-
-    /**
-     * Adds the specified object to this set. The set is not modified if it
-     * already contains the object.
-     *
-     * @param value the object to add.
-     * @return {@code true} if this set is modified, {@code false} otherwise.
-     * @throws ClassCastException
-     *             when the class of the object is inappropriate for this set.
-     */
-    @Override
-    public boolean add(@Nullable E value) {
-        final int hash;
-        int index;
-        if (value == null) {
-            hash = 0;
-            index = indexOfNull();
-        } else {
-            hash = value.hashCode();
-            index = indexOf(value, hash);
-        }
-        if (index >= 0) {
-            return false;
-        }
-
-        index = ~index;
-        if (mSize >= mHashes.length) {
-            final int n = mSize >= (BASE_SIZE * 2) ? (mSize + (mSize >> 1))
-                    : (mSize >= BASE_SIZE ? (BASE_SIZE * 2) : BASE_SIZE);
-
-            if (DEBUG) Log.d(TAG, "add: grow from " + mHashes.length + " to " + n);
-
-            final int[] ohashes = mHashes;
-            final Object[] oarray = mArray;
-            allocArrays(n);
-
-            if (mHashes.length > 0) {
-                if (DEBUG) Log.d(TAG, "add: copy 0-" + mSize + " to 0");
-                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
-                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
-            }
-
-            freeArrays(ohashes, oarray, mSize);
-        }
-
-        if (index < mSize) {
-            if (DEBUG) {
-                Log.d(TAG, "add: move " + index + "-" + (mSize - index) + " to " + (index + 1));
-            }
-            System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index);
-            System.arraycopy(mArray, index, mArray, index + 1, mSize - index);
-        }
-
-        mHashes[index] = hash;
-        mArray[index] = value;
-        mSize++;
-        return true;
-    }
-
-    /**
-     * Special fast path for appending items to the end of the array without validation.
-     * The array must already be large enough to contain the item.
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public void append(E value) {
-        final int index = mSize;
-        final int hash = value == null ? 0 : value.hashCode();
-        if (index >= mHashes.length) {
-            throw new IllegalStateException("Array is full");
-        }
-        if (index > 0 && mHashes[index - 1] > hash) {
-            // Cannot optimize since it would break the sorted order - fallback to add()
-            if (DEBUG) {
-                RuntimeException e = new RuntimeException("here");
-                e.fillInStackTrace();
-                Log.w(TAG, "New hash " + hash
-                        + " is before end of array hash " + mHashes[index - 1]
-                        + " at index " + index, e);
-            }
-            add(value);
-            return;
-        }
-        mSize = index + 1;
-        mHashes[index] = hash;
-        mArray[index] = value;
-    }
-
-    /**
-     * Perform a {@link #add(Object)} of all values in <var>array</var>
-     * @param array The array whose contents are to be retrieved.
-     */
-    public void addAll(@NonNull ArraySet<? extends E> array) {
-        final int N = array.mSize;
-        ensureCapacity(mSize + N);
-        if (mSize == 0) {
-            if (N > 0) {
-                System.arraycopy(array.mHashes, 0, mHashes, 0, N);
-                System.arraycopy(array.mArray, 0, mArray, 0, N);
-                mSize = N;
-            }
-        } else {
-            for (int i = 0; i < N; i++) {
-                add(array.valueAt(i));
-            }
-        }
-    }
-
-    /**
-     * Removes the specified object from this set.
-     *
-     * @param object the object to remove.
-     * @return {@code true} if this set was modified, {@code false} otherwise.
-     */
-    @Override
-    public boolean remove(Object object) {
-        final int index = indexOf(object);
-        if (index >= 0) {
-            removeAt(index);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Remove the key/value mapping at the given index.
-     * @param index The desired index, must be between 0 and {@link #size()}-1.
-     * @return Returns the value that was stored at this index.
-     */
-    public E removeAt(int index) {
-        final Object old = mArray[index];
-        if (mSize <= 1) {
-            // Now empty.
-            if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
-            freeArrays(mHashes, mArray, mSize);
-            mHashes = INT;
-            mArray = OBJECT;
-            mSize = 0;
-        } else {
-            if (mHashes.length > (BASE_SIZE * 2) && mSize < mHashes.length / 3) {
-                // Shrunk enough to reduce size of arrays.  We don't allow it to
-                // shrink smaller than (BASE_SIZE*2) to avoid flapping between
-                // that and BASE_SIZE.
-                final int n = mSize > (BASE_SIZE * 2) ? (mSize + (mSize >> 1)) : (BASE_SIZE * 2);
-
-                if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
-
-                final int[] ohashes = mHashes;
-                final Object[] oarray = mArray;
-                allocArrays(n);
-
-                mSize--;
-                if (index > 0) {
-                    if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0");
-                    System.arraycopy(ohashes, 0, mHashes, 0, index);
-                    System.arraycopy(oarray, 0, mArray, 0, index);
-                }
-                if (index < mSize) {
-                    if (DEBUG) {
-                        Log.d(TAG, "remove: copy from " + (index + 1) + "-" + mSize
-                                + " to " + index);
-                    }
-                    System.arraycopy(ohashes, index + 1, mHashes, index, mSize - index);
-                    System.arraycopy(oarray, index + 1, mArray, index, mSize - index);
-                }
-            } else {
-                mSize--;
-                if (index < mSize) {
-                    if (DEBUG) {
-                        Log.d(TAG, "remove: move " + (index + 1) + "-" + mSize + " to " + index);
-                    }
-                    System.arraycopy(mHashes, index + 1, mHashes, index, mSize - index);
-                    System.arraycopy(mArray, index + 1, mArray, index, mSize - index);
-                }
-                mArray[mSize] = null;
-            }
-        }
-        return (E) old;
-    }
-
-    /**
-     * Perform a {@link #remove(Object)} of all values in <var>array</var>
-     * @param array The array whose contents are to be removed.
-     */
-    public boolean removeAll(ArraySet<? extends E> array) {
-        // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first
-        //       pass, use the property that the sets are sorted by hash to make this linear passes
-        //       (except for hash collisions, which means worst case still n*m), then do one
-        //       collection pass into a new array. This avoids binary searches and excessive memcpy.
-        final int N = array.mSize;
-
-        // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all
-        //       the single results, compare size before and after.
-        final int originalSize = mSize;
-        for (int i = 0; i < N; i++) {
-            remove(array.valueAt(i));
-        }
-        return originalSize != mSize;
-    }
-
-    /**
-     * Return the number of items in this array map.
-     */
-    @Override
-    public int size() {
-        return mSize;
-    }
-
-    @NonNull
-    @Override
-    public Object[] toArray() {
-        Object[] result = new Object[mSize];
-        System.arraycopy(mArray, 0, result, 0, mSize);
-        return result;
-    }
-
-    @NonNull
-    @Override
-    public <T> T[] toArray(@NonNull T[] array) {
-        if (array.length < mSize) {
-            @SuppressWarnings("unchecked") T[] newArray =
-                    (T[]) Array.newInstance(array.getClass().getComponentType(), mSize);
-            array = newArray;
-        }
-        System.arraycopy(mArray, 0, array, 0, mSize);
-        if (array.length > mSize) {
-            array[mSize] = null;
-        }
-        return array;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation returns false if the object is not a set, or
-     * if the sets have different sizes.  Otherwise, for each value in this
-     * set, it checks to make sure the value also exists in the other set.
-     * If any value doesn't exist, the method returns false; otherwise, it
-     * returns true.
-     */
-    @Override
-    public boolean equals(Object object) {
-        if (this == object) {
-            return true;
-        }
-        if (object instanceof Set) {
-            Set<?> set = (Set<?>) object;
-            if (size() != set.size()) {
-                return false;
-            }
-
-            try {
-                for (int i = 0; i < mSize; i++) {
-                    E mine = valueAt(i);
-                    if (!set.contains(mine)) {
-                        return false;
-                    }
-                }
-            } catch (NullPointerException ignored) {
-                return false;
-            } catch (ClassCastException ignored) {
-                return false;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-        final int[] hashes = mHashes;
-        int result = 0;
-        for (int i = 0, s = mSize; i < s; i++) {
-            result += hashes[i];
-        }
-        return result;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation composes a string by iterating over its values. If
-     * this set contains itself as a value, the string "(this Set)"
-     * will appear in its place.
-     */
-    @Override
-    public String toString() {
-        if (isEmpty()) {
-            return "{}";
-        }
-
-        StringBuilder buffer = new StringBuilder(mSize * 14);
-        buffer.append('{');
-        for (int i = 0; i < mSize; i++) {
-            if (i > 0) {
-                buffer.append(", ");
-            }
-            Object value = valueAt(i);
-            if (value != this) {
-                buffer.append(value);
-            } else {
-                buffer.append("(this Set)");
-            }
-        }
-        buffer.append('}');
-        return buffer.toString();
-    }
-
-    // ------------------------------------------------------------------------
-    // Interop with traditional Java containers.  Not as efficient as using
-    // specialized collection APIs.
-    // ------------------------------------------------------------------------
-
-    private MapCollections<E, E> getCollection() {
-        if (mCollections == null) {
-            mCollections = new MapCollections<E, E>() {
-                @Override
-                protected int colGetSize() {
-                    return mSize;
-                }
-
-                @Override
-                protected Object colGetEntry(int index, int offset) {
-                    return mArray[index];
-                }
-
-                @Override
-                protected int colIndexOfKey(Object key) {
-                    return indexOf(key);
-                }
-
-                @Override
-                protected int colIndexOfValue(Object value) {
-                    return indexOf(value);
-                }
-
-                @Override
-                protected Map<E, E> colGetMap() {
-                    throw new UnsupportedOperationException("not a map");
-                }
-
-                @Override
-                protected void colPut(E key, E value) {
-                    add(key);
-                }
-
-                @Override
-                protected E colSetValue(int index, E value) {
-                    throw new UnsupportedOperationException("not a map");
-                }
-
-                @Override
-                protected void colRemoveAt(int index) {
-                    removeAt(index);
-                }
-
-                @Override
-                protected void colClear() {
-                    clear();
-                }
-            };
-        }
-        return mCollections;
-    }
-
-    /**
-     * Return an {@link java.util.Iterator} over all values in the set.
-     *
-     * <p><b>Note:</b> this is a fairly inefficient way to access the array contents, it
-     * requires generating a number of temporary objects and allocates additional state
-     * information associated with the container that will remain for the life of the container.</p>
-     */
-    @Override
-    public Iterator<E> iterator() {
-        return getCollection().getKeySet().iterator();
-    }
-
-    /**
-     * Determine if the array set contains all of the values in the given collection.
-     * @param collection The collection whose contents are to be checked against.
-     * @return Returns true if this array set contains a value for every entry
-     * in <var>collection</var>, else returns false.
-     */
-    @Override
-    public boolean containsAll(@NonNull Collection<?> collection) {
-        Iterator<?> it = collection.iterator();
-        while (it.hasNext()) {
-            if (!contains(it.next())) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Perform an {@link #add(Object)} of all values in <var>collection</var>
-     * @param collection The collection whose contents are to be retrieved.
-     */
-    @Override
-    public boolean addAll(@NonNull Collection<? extends E> collection) {
-        ensureCapacity(mSize + collection.size());
-        boolean added = false;
-        for (E value : collection) {
-            added |= add(value);
-        }
-        return added;
-    }
-
-    /**
-     * Remove all values in the array set that exist in the given collection.
-     * @param collection The collection whose contents are to be used to remove values.
-     * @return Returns true if any values were removed from the array set, else false.
-     */
-    @Override
-    public boolean removeAll(@NonNull Collection<?> collection) {
-        boolean removed = false;
-        for (Object value : collection) {
-            removed |= remove(value);
-        }
-        return removed;
-    }
-
-    /**
-     * Remove all values in the array set that do <b>not</b> exist in the given collection.
-     * @param collection The collection whose contents are to be used to determine which
-     * values to keep.
-     * @return Returns true if any values were removed from the array set, else false.
-     */
-    @Override
-    public boolean retainAll(@NonNull Collection<?> collection) {
-        boolean removed = false;
-        for (int i = mSize - 1; i >= 0; i--) {
-            if (!collection.contains(mArray[i])) {
-                removeAt(i);
-                removed = true;
-            }
-        }
-        return removed;
-    }
-}
diff --git a/compat/src/main/java/android/support/v4/util/LongSparseArray.java b/compat/src/main/java/android/support/v4/util/LongSparseArray.java
deleted file mode 100644
index 25b6bb9..0000000
--- a/compat/src/main/java/android/support/v4/util/LongSparseArray.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.util;
-
-/**
- * SparseArray mapping longs to Objects, a version of the platform's
- * {@link android.util.LongSparseArray} that can be used on older versions of the
- * platform.  Unlike a normal array of Objects,
- * there can be gaps in the indices.  It is intended to be more memory efficient
- * than using a HashMap to map Longs to Objects, both because it avoids
-  * auto-boxing keys and its data structure doesn't rely on an extra entry object
-  * for each mapping.
- *
- * <p>Note that this container keeps its mappings in an array data structure,
- * using a binary search to find keys.  The implementation is not intended to be appropriate for
- * data structures
- * that may contain large numbers of items.  It is generally slower than a traditional
- * HashMap, since lookups require a binary search and adds and removes require inserting
- * and deleting entries in the array.  For containers holding up to hundreds of items,
- * the performance difference is not significant, less than 50%.</p>
- *
- * <p>To help with performance, the container includes an optimization when removing
- * keys: instead of compacting its array immediately, it leaves the removed entry marked
- * as deleted.  The entry can then be re-used for the same key, or compacted later in
- * a single garbage collection step of all removed entries.  This garbage collection will
- * need to be performed at any time the array needs to be grown or the the map size or
- * entry values are retrieved.</p>
- */
-public class LongSparseArray<E> implements Cloneable {
-    private static final Object DELETED = new Object();
-    private boolean mGarbage = false;
-
-    private long[] mKeys;
-    private Object[] mValues;
-    private int mSize;
-
-    /**
-     * Creates a new LongSparseArray containing no mappings.
-     */
-    public LongSparseArray() {
-        this(10);
-    }
-
-    /**
-     * Creates a new LongSparseArray containing no mappings that will not
-     * require any additional memory allocation to store the specified
-     * number of mappings.  If you supply an initial capacity of 0, the
-     * sparse array will be initialized with a light-weight representation
-     * not requiring any additional array allocations.
-     */
-    public LongSparseArray(int initialCapacity) {
-        if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_LONGS;
-            mValues = ContainerHelpers.EMPTY_OBJECTS;
-        } else {
-            initialCapacity = ContainerHelpers.idealLongArraySize(initialCapacity);
-            mKeys = new long[initialCapacity];
-            mValues = new Object[initialCapacity];
-        }
-        mSize = 0;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public LongSparseArray<E> clone() {
-        LongSparseArray<E> clone = null;
-        try {
-            clone = (LongSparseArray<E>) super.clone();
-            clone.mKeys = mKeys.clone();
-            clone.mValues = mValues.clone();
-        } catch (CloneNotSupportedException cnse) {
-            /* ignore */
-        }
-        return clone;
-    }
-
-    /**
-     * Gets the Object mapped from the specified key, or <code>null</code>
-     * if no such mapping has been made.
-     */
-    public E get(long key) {
-        return get(key, null);
-    }
-
-    /**
-     * Gets the Object mapped from the specified key, or the specified Object
-     * if no such mapping has been made.
-     */
-    @SuppressWarnings("unchecked")
-    public E get(long key, E valueIfKeyNotFound) {
-        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i < 0 || mValues[i] == DELETED) {
-            return valueIfKeyNotFound;
-        } else {
-            return (E) mValues[i];
-        }
-    }
-
-    /**
-     * Removes the mapping from the specified key, if there was any.
-     */
-    public void delete(long key) {
-        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i >= 0) {
-            if (mValues[i] != DELETED) {
-                mValues[i] = DELETED;
-                mGarbage = true;
-            }
-        }
-    }
-
-    /**
-     * Alias for {@link #delete(long)}.
-     */
-    public void remove(long key) {
-        delete(key);
-    }
-
-    /**
-     * Removes the mapping at the specified index.
-     */
-    public void removeAt(int index) {
-        if (mValues[index] != DELETED) {
-            mValues[index] = DELETED;
-            mGarbage = true;
-        }
-    }
-
-    private void gc() {
-        // Log.e("SparseArray", "gc start with " + mSize);
-
-        int n = mSize;
-        int o = 0;
-        long[] keys = mKeys;
-        Object[] values = mValues;
-
-        for (int i = 0; i < n; i++) {
-            Object val = values[i];
-
-            if (val != DELETED) {
-                if (i != o) {
-                    keys[o] = keys[i];
-                    values[o] = val;
-                    values[i] = null;
-                }
-
-                o++;
-            }
-        }
-
-        mGarbage = false;
-        mSize = o;
-
-        // Log.e("SparseArray", "gc end with " + mSize);
-    }
-
-    /**
-     * Adds a mapping from the specified key to the specified value,
-     * replacing the previous mapping from the specified key if there
-     * was one.
-     */
-    public void put(long key, E value) {
-        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i >= 0) {
-            mValues[i] = value;
-        } else {
-            i = ~i;
-
-            if (i < mSize && mValues[i] == DELETED) {
-                mKeys[i] = key;
-                mValues[i] = value;
-                return;
-            }
-
-            if (mGarbage && mSize >= mKeys.length) {
-                gc();
-
-                // Search again because indices may have changed.
-                i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
-            }
-
-            if (mSize >= mKeys.length) {
-                int n = ContainerHelpers.idealLongArraySize(mSize + 1);
-
-                long[] nkeys = new long[n];
-                Object[] nvalues = new Object[n];
-
-                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
-            mSize++;
-        }
-    }
-
-    /**
-     * Returns the number of key-value mappings that this LongSparseArray
-     * currently stores.
-     */
-    public int size() {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mSize;
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, returns
-     * the key from the <code>index</code>th key-value mapping that this
-     * LongSparseArray stores.
-     */
-    public long keyAt(int index) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mKeys[index];
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, returns
-     * the value from the <code>index</code>th key-value mapping that this
-     * LongSparseArray stores.
-     */
-    @SuppressWarnings("unchecked")
-    public E valueAt(int index) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return (E) mValues[index];
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, sets a new
-     * value for the <code>index</code>th key-value mapping that this
-     * LongSparseArray stores.
-     */
-    public void setValueAt(int index, E value) {
-        if (mGarbage) {
-            gc();
-        }
-
-        mValues[index] = value;
-    }
-
-    /**
-     * Returns the index for which {@link #keyAt} would return the
-     * specified key, or a negative number if the specified
-     * key is not mapped.
-     */
-    public int indexOfKey(long key) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return ContainerHelpers.binarySearch(mKeys, mSize, key);
-    }
-
-    /**
-     * Returns an index for which {@link #valueAt} would return the
-     * specified key, or a negative number if no keys map to the
-     * specified value.
-     * Beware that this is a linear search, unlike lookups by key,
-     * and that multiple keys can map to the same value and this will
-     * find only one of them.
-     */
-    public int indexOfValue(E value) {
-        if (mGarbage) {
-            gc();
-        }
-
-        for (int i = 0; i < mSize; i++)
-            if (mValues[i] == value)
-                return i;
-
-        return -1;
-    }
-
-    /**
-     * Removes all key-value mappings from this LongSparseArray.
-     */
-    public void clear() {
-        int n = mSize;
-        Object[] values = mValues;
-
-        for (int i = 0; i < n; i++) {
-            values[i] = null;
-        }
-
-        mSize = 0;
-        mGarbage = false;
-    }
-
-    /**
-     * Puts a key/value pair into the array, optimizing for the case where
-     * the key is greater than all existing keys in the array.
-     */
-    public void append(long key, E value) {
-        if (mSize != 0 && key <= mKeys[mSize - 1]) {
-            put(key, value);
-            return;
-        }
-
-        if (mGarbage && mSize >= mKeys.length) {
-            gc();
-        }
-
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n = ContainerHelpers.idealLongArraySize(pos + 1);
-
-            long[] nkeys = new long[n];
-            Object[] nvalues = new Object[n];
-
-            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation composes a string by iterating over its mappings. If
-     * this map contains itself as a value, the string "(this Map)"
-     * will appear in its place.
-     */
-    @Override
-    public String toString() {
-        if (size() <= 0) {
-            return "{}";
-        }
-
-        StringBuilder buffer = new StringBuilder(mSize * 28);
-        buffer.append('{');
-        for (int i=0; i<mSize; i++) {
-            if (i > 0) {
-                buffer.append(", ");
-            }
-            long key = keyAt(i);
-            buffer.append(key);
-            buffer.append('=');
-            Object value = valueAt(i);
-            if (value != this) {
-                buffer.append(value);
-            } else {
-                buffer.append("(this Map)");
-            }
-        }
-        buffer.append('}');
-        return buffer.toString();
-    }
-}
diff --git a/compat/src/main/java/android/support/v4/util/LruCache.java b/compat/src/main/java/android/support/v4/util/LruCache.java
deleted file mode 100644
index 944b354..0000000
--- a/compat/src/main/java/android/support/v4/util/LruCache.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.util;
-
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.Map;
-
-/**
- * Static library version of {@link android.util.LruCache}. Used to write apps
- * that run on API levels prior to 12. When running on API level 12 or above,
- * this implementation is still used; it does not try to switch to the
- * framework's implementation. See the framework SDK documentation for a class
- * overview.
- */
-public class LruCache<K, V> {
-    private final LinkedHashMap<K, V> map;
-
-    /** Size of this cache in units. Not necessarily the number of elements. */
-    private int size;
-    private int maxSize;
-
-    private int putCount;
-    private int createCount;
-    private int evictionCount;
-    private int hitCount;
-    private int missCount;
-
-    /**
-     * @param maxSize for caches that do not override {@link #sizeOf}, this is
-     *     the maximum number of entries in the cache. For all other caches,
-     *     this is the maximum sum of the sizes of the entries in this cache.
-     */
-    public LruCache(int maxSize) {
-        if (maxSize <= 0) {
-            throw new IllegalArgumentException("maxSize <= 0");
-        }
-        this.maxSize = maxSize;
-        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
-    }
-
-    /**
-     * Sets the size of the cache.
-     *
-     * @param maxSize The new maximum size.
-     */
-    public void resize(int maxSize) {
-        if (maxSize <= 0) {
-            throw new IllegalArgumentException("maxSize <= 0");
-        }
-
-        synchronized (this) {
-            this.maxSize = maxSize;
-        }
-        trimToSize(maxSize);
-    }
-
-    /**
-     * Returns the value for {@code key} if it exists in the cache or can be
-     * created by {@code #create}. If a value was returned, it is moved to the
-     * head of the queue. This returns null if a value is not cached and cannot
-     * be created.
-     */
-    public final V get(K key) {
-        if (key == null) {
-            throw new NullPointerException("key == null");
-        }
-
-        V mapValue;
-        synchronized (this) {
-            mapValue = map.get(key);
-            if (mapValue != null) {
-                hitCount++;
-                return mapValue;
-            }
-            missCount++;
-        }
-
-        /*
-         * Attempt to create a value. This may take a long time, and the map
-         * may be different when create() returns. If a conflicting value was
-         * added to the map while create() was working, we leave that value in
-         * the map and release the created value.
-         */
-
-        V createdValue = create(key);
-        if (createdValue == null) {
-            return null;
-        }
-
-        synchronized (this) {
-            createCount++;
-            mapValue = map.put(key, createdValue);
-
-            if (mapValue != null) {
-                // There was a conflict so undo that last put
-                map.put(key, mapValue);
-            } else {
-                size += safeSizeOf(key, createdValue);
-            }
-        }
-
-        if (mapValue != null) {
-            entryRemoved(false, key, createdValue, mapValue);
-            return mapValue;
-        } else {
-            trimToSize(maxSize);
-            return createdValue;
-        }
-    }
-
-    /**
-     * Caches {@code value} for {@code key}. The value is moved to the head of
-     * the queue.
-     *
-     * @return the previous value mapped by {@code key}.
-     */
-    public final V put(K key, V value) {
-        if (key == null || value == null) {
-            throw new NullPointerException("key == null || value == null");
-        }
-
-        V previous;
-        synchronized (this) {
-            putCount++;
-            size += safeSizeOf(key, value);
-            previous = map.put(key, value);
-            if (previous != null) {
-                size -= safeSizeOf(key, previous);
-            }
-        }
-
-        if (previous != null) {
-            entryRemoved(false, key, previous, value);
-        }
-
-        trimToSize(maxSize);
-        return previous;
-    }
-
-    /**
-     * Remove the eldest entries until the total of remaining entries is at or
-     * below the requested size.
-     *
-     * @param maxSize the maximum size of the cache before returning. May be -1
-     *            to evict even 0-sized elements.
-     */
-    public void trimToSize(int maxSize) {
-        while (true) {
-            K key;
-            V value;
-            synchronized (this) {
-                if (size < 0 || (map.isEmpty() && size != 0)) {
-                    throw new IllegalStateException(getClass().getName()
-                            + ".sizeOf() is reporting inconsistent results!");
-                }
-
-                if (size <= maxSize || map.isEmpty()) {
-                    break;
-                }
-
-                Map.Entry<K, V> toEvict = map.entrySet().iterator().next();
-                key = toEvict.getKey();
-                value = toEvict.getValue();
-                map.remove(key);
-                size -= safeSizeOf(key, value);
-                evictionCount++;
-            }
-
-            entryRemoved(true, key, value, null);
-        }
-    }
-
-    /**
-     * Removes the entry for {@code key} if it exists.
-     *
-     * @return the previous value mapped by {@code key}.
-     */
-    public final V remove(K key) {
-        if (key == null) {
-            throw new NullPointerException("key == null");
-        }
-
-        V previous;
-        synchronized (this) {
-            previous = map.remove(key);
-            if (previous != null) {
-                size -= safeSizeOf(key, previous);
-            }
-        }
-
-        if (previous != null) {
-            entryRemoved(false, key, previous, null);
-        }
-
-        return previous;
-    }
-
-    /**
-     * Called for entries that have been evicted or removed. This method is
-     * invoked when a value is evicted to make space, removed by a call to
-     * {@link #remove}, or replaced by a call to {@link #put}. The default
-     * implementation does nothing.
-     *
-     * <p>The method is called without synchronization: other threads may
-     * access the cache while this method is executing.
-     *
-     * @param evicted true if the entry is being removed to make space, false
-     *     if the removal was caused by a {@link #put} or {@link #remove}.
-     * @param newValue the new value for {@code key}, if it exists. If non-null,
-     *     this removal was caused by a {@link #put}. Otherwise it was caused by
-     *     an eviction or a {@link #remove}.
-     */
-    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
-
-    /**
-     * Called after a cache miss to compute a value for the corresponding key.
-     * Returns the computed value or null if no value can be computed. The
-     * default implementation returns null.
-     *
-     * <p>The method is called without synchronization: other threads may
-     * access the cache while this method is executing.
-     *
-     * <p>If a value for {@code key} exists in the cache when this method
-     * returns, the created value will be released with {@link #entryRemoved}
-     * and discarded. This can occur when multiple threads request the same key
-     * at the same time (causing multiple values to be created), or when one
-     * thread calls {@link #put} while another is creating a value for the same
-     * key.
-     */
-    protected V create(K key) {
-        return null;
-    }
-
-    private int safeSizeOf(K key, V value) {
-        int result = sizeOf(key, value);
-        if (result < 0) {
-            throw new IllegalStateException("Negative size: " + key + "=" + value);
-        }
-        return result;
-    }
-
-    /**
-     * Returns the size of the entry for {@code key} and {@code value} in
-     * user-defined units.  The default implementation returns 1 so that size
-     * is the number of entries and max size is the maximum number of entries.
-     *
-     * <p>An entry's size must not change while it is in the cache.
-     */
-    protected int sizeOf(K key, V value) {
-        return 1;
-    }
-
-    /**
-     * Clear the cache, calling {@link #entryRemoved} on each removed entry.
-     */
-    public final void evictAll() {
-        trimToSize(-1); // -1 will evict 0-sized elements
-    }
-
-    /**
-     * For caches that do not override {@link #sizeOf}, this returns the number
-     * of entries in the cache. For all other caches, this returns the sum of
-     * the sizes of the entries in this cache.
-     */
-    public synchronized final int size() {
-        return size;
-    }
-
-    /**
-     * For caches that do not override {@link #sizeOf}, this returns the maximum
-     * number of entries in the cache. For all other caches, this returns the
-     * maximum sum of the sizes of the entries in this cache.
-     */
-    public synchronized final int maxSize() {
-        return maxSize;
-    }
-
-    /**
-     * Returns the number of times {@link #get} returned a value that was
-     * already present in the cache.
-     */
-    public synchronized final int hitCount() {
-        return hitCount;
-    }
-
-    /**
-     * Returns the number of times {@link #get} returned null or required a new
-     * value to be created.
-     */
-    public synchronized final int missCount() {
-        return missCount;
-    }
-
-    /**
-     * Returns the number of times {@link #create(Object)} returned a value.
-     */
-    public synchronized final int createCount() {
-        return createCount;
-    }
-
-    /**
-     * Returns the number of times {@link #put} was called.
-     */
-    public synchronized final int putCount() {
-        return putCount;
-    }
-
-    /**
-     * Returns the number of values that have been evicted.
-     */
-    public synchronized final int evictionCount() {
-        return evictionCount;
-    }
-
-    /**
-     * Returns a copy of the current contents of the cache, ordered from least
-     * recently accessed to most recently accessed.
-     */
-    public synchronized final Map<K, V> snapshot() {
-        return new LinkedHashMap<K, V>(map);
-    }
-
-    @Override public synchronized final String toString() {
-        int accesses = hitCount + missCount;
-        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
-        return String.format(Locale.US, "LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
-                maxSize, hitCount, missCount, hitPercent);
-    }
-}
diff --git a/compat/src/main/java/android/support/v4/util/SimpleArrayMap.java b/compat/src/main/java/android/support/v4/util/SimpleArrayMap.java
deleted file mode 100644
index 06e68f0..0000000
--- a/compat/src/main/java/android/support/v4/util/SimpleArrayMap.java
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.util;
-
-import android.util.Log;
-
-import java.util.ConcurrentModificationException;
-import java.util.Map;
-
-/**
- * Base implementation of {@link ArrayMap} that doesn't include any standard Java
- * container API interoperability.  These features are generally heavier-weight ways
- * to interact with the container, so discouraged, but they can be useful to make it
- * easier to use as a drop-in replacement for HashMap.  If you don't need them, this
- * class can be preferrable since it doesn't bring in any of the implementation of those
- * APIs, allowing that code to be stripped by ProGuard.
- */
-public class SimpleArrayMap<K, V> {
-    private static final boolean DEBUG = false;
-    private static final String TAG = "ArrayMap";
-
-    /**
-     * Attempt to spot concurrent modifications to this data structure.
-     *
-     * It's best-effort, but any time we can throw something more diagnostic than an
-     * ArrayIndexOutOfBoundsException deep in the ArrayMap internals it's going to
-     * save a lot of development time.
-     *
-     * Good times to look for CME include after any allocArrays() call and at the end of
-     * functions that change mSize (put/remove/clear).
-     */
-    private static final boolean CONCURRENT_MODIFICATION_EXCEPTIONS = true;
-
-    /**
-     * The minimum amount by which the capacity of a ArrayMap will increase.
-     * This is tuned to be relatively space-efficient.
-     */
-    private static final int BASE_SIZE = 4;
-
-    /**
-     * Maximum number of entries to have in array caches.
-     */
-    private static final int CACHE_SIZE = 10;
-
-    /**
-     * Caches of small array objects to avoid spamming garbage.  The cache
-     * Object[] variable is a pointer to a linked list of array objects.
-     * The first entry in the array is a pointer to the next array in the
-     * list; the second entry is a pointer to the int[] hash code array for it.
-     */
-    static Object[] mBaseCache;
-    static int mBaseCacheSize;
-    static Object[] mTwiceBaseCache;
-    static int mTwiceBaseCacheSize;
-
-    int[] mHashes;
-    Object[] mArray;
-    int mSize;
-
-    private static int binarySearchHashes(int[] hashes, int N, int hash) {
-        try {
-            return ContainerHelpers.binarySearch(hashes, N, hash);
-        } catch (ArrayIndexOutOfBoundsException e) {
-            if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
-                throw new ConcurrentModificationException();
-            } else {
-                throw e; // the cache is poisoned at this point, there's not much we can do
-            }
-        }
-    }
-
-    int indexOf(Object key, int hash) {
-        final int N = mSize;
-
-        // Important fast case: if nothing is in here, nothing to look for.
-        if (N == 0) {
-            return ~0;
-        }
-
-        int index = binarySearchHashes(mHashes, N, hash);
-
-        // If the hash code wasn't found, then we have no entry for this key.
-        if (index < 0) {
-            return index;
-        }
-
-        // If the key at the returned index matches, that's what we want.
-        if (key.equals(mArray[index<<1])) {
-            return index;
-        }
-
-        // Search for a matching key after the index.
-        int end;
-        for (end = index + 1; end < N && mHashes[end] == hash; end++) {
-            if (key.equals(mArray[end << 1])) return end;
-        }
-
-        // Search for a matching key before the index.
-        for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
-            if (key.equals(mArray[i << 1])) return i;
-        }
-
-        // Key not found -- return negative value indicating where a
-        // new entry for this key should go.  We use the end of the
-        // hash chain to reduce the number of array entries that will
-        // need to be copied when inserting.
-        return ~end;
-    }
-
-    int indexOfNull() {
-        final int N = mSize;
-
-        // Important fast case: if nothing is in here, nothing to look for.
-        if (N == 0) {
-            return ~0;
-        }
-
-        int index = binarySearchHashes(mHashes, N, 0);
-
-        // If the hash code wasn't found, then we have no entry for this key.
-        if (index < 0) {
-            return index;
-        }
-
-        // If the key at the returned index matches, that's what we want.
-        if (null == mArray[index<<1]) {
-            return index;
-        }
-
-        // Search for a matching key after the index.
-        int end;
-        for (end = index + 1; end < N && mHashes[end] == 0; end++) {
-            if (null == mArray[end << 1]) return end;
-        }
-
-        // Search for a matching key before the index.
-        for (int i = index - 1; i >= 0 && mHashes[i] == 0; i--) {
-            if (null == mArray[i << 1]) return i;
-        }
-
-        // Key not found -- return negative value indicating where a
-        // new entry for this key should go.  We use the end of the
-        // hash chain to reduce the number of array entries that will
-        // need to be copied when inserting.
-        return ~end;
-    }
-
-    @SuppressWarnings("ArrayToString")
-    private void allocArrays(final int size) {
-        if (size == (BASE_SIZE*2)) {
-            synchronized (ArrayMap.class) {
-                if (mTwiceBaseCache != null) {
-                    final Object[] array = mTwiceBaseCache;
-                    mArray = array;
-                    mTwiceBaseCache = (Object[])array[0];
-                    mHashes = (int[])array[1];
-                    array[0] = array[1] = null;
-                    mTwiceBaseCacheSize--;
-                    if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes
-                            + " now have " + mTwiceBaseCacheSize + " entries");
-                    return;
-                }
-            }
-        } else if (size == BASE_SIZE) {
-            synchronized (ArrayMap.class) {
-                if (mBaseCache != null) {
-                    final Object[] array = mBaseCache;
-                    mArray = array;
-                    mBaseCache = (Object[])array[0];
-                    mHashes = (int[])array[1];
-                    array[0] = array[1] = null;
-                    mBaseCacheSize--;
-                    if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes
-                            + " now have " + mBaseCacheSize + " entries");
-                    return;
-                }
-            }
-        }
-
-        mHashes = new int[size];
-        mArray = new Object[size<<1];
-    }
-
-    @SuppressWarnings("ArrayToString")
-    private static void freeArrays(final int[] hashes, final Object[] array, final int size) {
-        if (hashes.length == (BASE_SIZE*2)) {
-            synchronized (ArrayMap.class) {
-                if (mTwiceBaseCacheSize < CACHE_SIZE) {
-                    array[0] = mTwiceBaseCache;
-                    array[1] = hashes;
-                    for (int i=(size<<1)-1; i>=2; i--) {
-                        array[i] = null;
-                    }
-                    mTwiceBaseCache = array;
-                    mTwiceBaseCacheSize++;
-                    if (DEBUG) Log.d(TAG, "Storing 2x cache " + array
-                            + " now have " + mTwiceBaseCacheSize + " entries");
-                }
-            }
-        } else if (hashes.length == BASE_SIZE) {
-            synchronized (ArrayMap.class) {
-                if (mBaseCacheSize < CACHE_SIZE) {
-                    array[0] = mBaseCache;
-                    array[1] = hashes;
-                    for (int i=(size<<1)-1; i>=2; i--) {
-                        array[i] = null;
-                    }
-                    mBaseCache = array;
-                    mBaseCacheSize++;
-                    if (DEBUG) Log.d(TAG, "Storing 1x cache " + array
-                            + " now have " + mBaseCacheSize + " entries");
-                }
-            }
-        }
-    }
-
-    /**
-     * Create a new empty ArrayMap.  The default capacity of an array map is 0, and
-     * will grow once items are added to it.
-     */
-    public SimpleArrayMap() {
-        mHashes = ContainerHelpers.EMPTY_INTS;
-        mArray = ContainerHelpers.EMPTY_OBJECTS;
-        mSize = 0;
-    }
-
-    /**
-     * Create a new ArrayMap with a given initial capacity.
-     */
-    public SimpleArrayMap(int capacity) {
-        if (capacity == 0) {
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
-        } else {
-            allocArrays(capacity);
-        }
-        mSize = 0;
-    }
-
-    /**
-     * Create a new ArrayMap with the mappings from the given ArrayMap.
-     */
-    public SimpleArrayMap(SimpleArrayMap<K, V> map) {
-        this();
-        if (map != null) {
-            putAll(map);
-        }
-    }
-
-    /**
-     * Make the array map empty.  All storage is released.
-     */
-    public void clear() {
-        if (mSize > 0) {
-            final int[] ohashes = mHashes;
-            final Object[] oarray = mArray;
-            final int osize = mSize;
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
-            mSize = 0;
-            freeArrays(ohashes, oarray, osize);
-        }
-        if (CONCURRENT_MODIFICATION_EXCEPTIONS && mSize > 0) {
-            throw new ConcurrentModificationException();
-        }
-    }
-
-    /**
-     * Ensure the array map can hold at least <var>minimumCapacity</var>
-     * items.
-     */
-    public void ensureCapacity(int minimumCapacity) {
-        final int osize = mSize;
-        if (mHashes.length < minimumCapacity) {
-            final int[] ohashes = mHashes;
-            final Object[] oarray = mArray;
-            allocArrays(minimumCapacity);
-            if (mSize > 0) {
-                System.arraycopy(ohashes, 0, mHashes, 0, osize);
-                System.arraycopy(oarray, 0, mArray, 0, osize<<1);
-            }
-            freeArrays(ohashes, oarray, osize);
-        }
-        if (CONCURRENT_MODIFICATION_EXCEPTIONS && mSize != osize) {
-            throw new ConcurrentModificationException();
-        }
-    }
-
-    /**
-     * Check whether a key exists in the array.
-     *
-     * @param key The key to search for.
-     * @return Returns true if the key exists, else false.
-     */
-    public boolean containsKey(Object key) {
-        return indexOfKey(key) >= 0;
-    }
-
-    /**
-     * Returns the index of a key in the set.
-     *
-     * @param key The key to search for.
-     * @return Returns the index of the key if it exists, else a negative integer.
-     */
-    public int indexOfKey(Object key) {
-        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
-    }
-
-    int indexOfValue(Object value) {
-        final int N = mSize*2;
-        final Object[] array = mArray;
-        if (value == null) {
-            for (int i=1; i<N; i+=2) {
-                if (array[i] == null) {
-                    return i>>1;
-                }
-            }
-        } else {
-            for (int i=1; i<N; i+=2) {
-                if (value.equals(array[i])) {
-                    return i>>1;
-                }
-            }
-        }
-        return -1;
-    }
-
-    /**
-     * Check whether a value exists in the array.  This requires a linear search
-     * through the entire array.
-     *
-     * @param value The value to search for.
-     * @return Returns true if the value exists, else false.
-     */
-    public boolean containsValue(Object value) {
-        return indexOfValue(value) >= 0;
-    }
-
-    /**
-     * Retrieve a value from the array.
-     * @param key The key of the value to retrieve.
-     * @return Returns the value associated with the given key,
-     * or null if there is no such key.
-     */
-    public V get(Object key) {
-        final int index = indexOfKey(key);
-        return index >= 0 ? (V)mArray[(index<<1)+1] : null;
-    }
-
-    /**
-     * Return the key at the given index in the array.
-     * @param index The desired index, must be between 0 and {@link #size()}-1.
-     * @return Returns the key stored at the given index.
-     */
-    public K keyAt(int index) {
-        return (K)mArray[index << 1];
-    }
-
-    /**
-     * Return the value at the given index in the array.
-     * @param index The desired index, must be between 0 and {@link #size()}-1.
-     * @return Returns the value stored at the given index.
-     */
-    public V valueAt(int index) {
-        return (V)mArray[(index << 1) + 1];
-    }
-
-    /**
-     * Set the value at a given index in the array.
-     * @param index The desired index, must be between 0 and {@link #size()}-1.
-     * @param value The new value to store at this index.
-     * @return Returns the previous value at the given index.
-     */
-    public V setValueAt(int index, V value) {
-        index = (index << 1) + 1;
-        V old = (V)mArray[index];
-        mArray[index] = value;
-        return old;
-    }
-
-    /**
-     * Return true if the array map contains no items.
-     */
-    public boolean isEmpty() {
-        return mSize <= 0;
-    }
-
-    /**
-     * Add a new value to the array map.
-     * @param key The key under which to store the value.  <b>Must not be null.</b>  If
-     * this key already exists in the array, its value will be replaced.
-     * @param value The value to store for the given key.
-     * @return Returns the old value that was stored for the given key, or null if there
-     * was no such key.
-     */
-    public V put(K key, V value) {
-        final int osize = mSize;
-        final int hash;
-        int index;
-        if (key == null) {
-            hash = 0;
-            index = indexOfNull();
-        } else {
-            hash = key.hashCode();
-            index = indexOf(key, hash);
-        }
-        if (index >= 0) {
-            index = (index<<1) + 1;
-            final V old = (V)mArray[index];
-            mArray[index] = value;
-            return old;
-        }
-
-        index = ~index;
-        if (osize >= mHashes.length) {
-            final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
-                    : (osize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
-
-            if (DEBUG) Log.d(TAG, "put: grow from " + mHashes.length + " to " + n);
-
-            final int[] ohashes = mHashes;
-            final Object[] oarray = mArray;
-            allocArrays(n);
-
-            if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
-                throw new ConcurrentModificationException();
-            }
-
-            if (mHashes.length > 0) {
-                if (DEBUG) Log.d(TAG, "put: copy 0-" + osize + " to 0");
-                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
-                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
-            }
-
-            freeArrays(ohashes, oarray, osize);
-        }
-
-        if (index < osize) {
-            if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (osize-index)
-                    + " to " + (index+1));
-            System.arraycopy(mHashes, index, mHashes, index + 1, osize - index);
-            System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);
-        }
-
-        if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
-            if (osize != mSize || index >= mHashes.length) {
-                throw new ConcurrentModificationException();
-            }
-        }
-
-        mHashes[index] = hash;
-        mArray[index<<1] = key;
-        mArray[(index<<1)+1] = value;
-        mSize++;
-        return null;
-    }
-
-    /**
-     * Perform a {@link #put(Object, Object)} of all key/value pairs in <var>array</var>
-     * @param array The array whose contents are to be retrieved.
-     */
-    public void putAll(SimpleArrayMap<? extends K, ? extends V> array) {
-        final int N = array.mSize;
-        ensureCapacity(mSize + N);
-        if (mSize == 0) {
-            if (N > 0) {
-                System.arraycopy(array.mHashes, 0, mHashes, 0, N);
-                System.arraycopy(array.mArray, 0, mArray, 0, N<<1);
-                mSize = N;
-            }
-        } else {
-            for (int i=0; i<N; i++) {
-                put(array.keyAt(i), array.valueAt(i));
-            }
-        }
-    }
-
-    /**
-     * Remove an existing key from the array map.
-     * @param key The key of the mapping to remove.
-     * @return Returns the value that was stored under the key, or null if there
-     * was no such key.
-     */
-    public V remove(Object key) {
-        final int index = indexOfKey(key);
-        if (index >= 0) {
-            return removeAt(index);
-        }
-
-        return null;
-    }
-
-    /**
-     * Remove the key/value mapping at the given index.
-     * @param index The desired index, must be between 0 and {@link #size()}-1.
-     * @return Returns the value that was stored at this index.
-     */
-    public V removeAt(int index) {
-        final Object old = mArray[(index << 1) + 1];
-        final int osize = mSize;
-        final int nsize;
-        if (osize <= 1) {
-            // Now empty.
-            if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
-            freeArrays(mHashes, mArray, osize);
-            mHashes = ContainerHelpers.EMPTY_INTS;
-            mArray = ContainerHelpers.EMPTY_OBJECTS;
-            nsize = 0;
-        } else {
-            nsize = osize - 1;
-            if (mHashes.length > (BASE_SIZE*2) && mSize < mHashes.length/3) {
-                // Shrunk enough to reduce size of arrays.  We don't allow it to
-                // shrink smaller than (BASE_SIZE*2) to avoid flapping between
-                // that and BASE_SIZE.
-                final int n = osize > (BASE_SIZE*2) ? (osize + (osize>>1)) : (BASE_SIZE*2);
-
-                if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
-
-                final int[] ohashes = mHashes;
-                final Object[] oarray = mArray;
-                allocArrays(n);
-
-                if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
-                    throw new ConcurrentModificationException();
-                }
-
-                if (index > 0) {
-                    if (DEBUG) Log.d(TAG, "remove: copy from 0-" + index + " to 0");
-                    System.arraycopy(ohashes, 0, mHashes, 0, index);
-                    System.arraycopy(oarray, 0, mArray, 0, index << 1);
-                }
-                if (index < nsize) {
-                    if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + nsize
-                            + " to " + index);
-                    System.arraycopy(ohashes, index + 1, mHashes, index, nsize - index);
-                    System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1,
-                            (nsize - index) << 1);
-                }
-            } else {
-                if (index < nsize) {
-                    if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + nsize
-                            + " to " + index);
-                    System.arraycopy(mHashes, index + 1, mHashes, index, nsize - index);
-                    System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1,
-                            (nsize - index) << 1);
-                }
-                mArray[nsize << 1] = null;
-                mArray[(nsize << 1) + 1] = null;
-            }
-        }
-        if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
-            throw new ConcurrentModificationException();
-        }
-        mSize = nsize;
-        return (V)old;
-    }
-
-    /**
-     * Return the number of items in this array map.
-     */
-    public int size() {
-        return mSize;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation returns false if the object is not a Map or
-     * SimpleArrayMap, or if the maps have different sizes. Otherwise, for each
-     * key in this map, values of both maps are compared. If the values for any
-     * key are not equal, the method returns false, otherwise it returns true.
-     */
-    @Override
-    public boolean equals(Object object) {
-        if (this == object) {
-            return true;
-        }
-        if (object instanceof SimpleArrayMap) {
-            SimpleArrayMap<?, ?> map = (SimpleArrayMap<?, ?>) object;
-            if (size() != map.size()) {
-                return false;
-            }
-
-            try {
-                for (int i=0; i<mSize; i++) {
-                    K key = keyAt(i);
-                    V mine = valueAt(i);
-                    Object theirs = map.get(key);
-                    if (mine == null) {
-                        if (theirs != null || !map.containsKey(key)) {
-                            return false;
-                        }
-                    } else if (!mine.equals(theirs)) {
-                        return false;
-                    }
-                }
-            } catch (NullPointerException ignored) {
-                return false;
-            } catch (ClassCastException ignored) {
-                return false;
-            }
-            return true;
-        } else if (object instanceof Map) {
-            Map<?, ?> map = (Map<?, ?>) object;
-            if (size() != map.size()) {
-                return false;
-            }
-
-            try {
-                for (int i=0; i<mSize; i++) {
-                    K key = keyAt(i);
-                    V mine = valueAt(i);
-                    Object theirs = map.get(key);
-                    if (mine == null) {
-                        if (theirs != null || !map.containsKey(key)) {
-                            return false;
-                        }
-                    } else if (!mine.equals(theirs)) {
-                        return false;
-                    }
-                }
-            } catch (NullPointerException ignored) {
-                return false;
-            } catch (ClassCastException ignored) {
-                return false;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-        final int[] hashes = mHashes;
-        final Object[] array = mArray;
-        int result = 0;
-        for (int i = 0, v = 1, s = mSize; i < s; i++, v+=2) {
-            Object value = array[v];
-            result += hashes[i] ^ (value == null ? 0 : value.hashCode());
-        }
-        return result;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation composes a string by iterating over its mappings. If
-     * this map contains itself as a key or a value, the string "(this Map)"
-     * will appear in its place.
-     */
-    @Override
-    public String toString() {
-        if (isEmpty()) {
-            return "{}";
-        }
-
-        StringBuilder buffer = new StringBuilder(mSize * 28);
-        buffer.append('{');
-        for (int i=0; i<mSize; i++) {
-            if (i > 0) {
-                buffer.append(", ");
-            }
-            Object key = keyAt(i);
-            if (key != this) {
-                buffer.append(key);
-            } else {
-                buffer.append("(this Map)");
-            }
-            buffer.append('=');
-            Object value = valueAt(i);
-            if (value != this) {
-                buffer.append(value);
-            } else {
-                buffer.append("(this Map)");
-            }
-        }
-        buffer.append('}');
-        return buffer.toString();
-    }
-}
diff --git a/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java b/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
deleted file mode 100644
index aedc4ad..0000000
--- a/compat/src/main/java/android/support/v4/util/SparseArrayCompat.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.util;
-
-/**
- * A copy of the current platform (currently {@link android.os.Build.VERSION_CODES#KITKAT}
- * version of {@link android.util.SparseArray}; provides a removeAt() method and other things.
- */
-public class SparseArrayCompat<E> implements Cloneable {
-    private static final Object DELETED = new Object();
-    private boolean mGarbage = false;
-
-    private int[] mKeys;
-    private Object[] mValues;
-    private int mSize;
-
-    /**
-     * Creates a new SparseArray containing no mappings.
-     */
-    public SparseArrayCompat() {
-        this(10);
-    }
-
-    /**
-     * Creates a new SparseArray containing no mappings that will not
-     * require any additional memory allocation to store the specified
-     * number of mappings.  If you supply an initial capacity of 0, the
-     * sparse array will be initialized with a light-weight representation
-     * not requiring any additional array allocations.
-     */
-    public SparseArrayCompat(int initialCapacity) {
-        if (initialCapacity == 0) {
-            mKeys =  ContainerHelpers.EMPTY_INTS;
-            mValues =  ContainerHelpers.EMPTY_OBJECTS;
-        } else {
-            initialCapacity =  ContainerHelpers.idealIntArraySize(initialCapacity);
-            mKeys = new int[initialCapacity];
-            mValues = new Object[initialCapacity];
-        }
-        mSize = 0;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public SparseArrayCompat<E> clone() {
-        SparseArrayCompat<E> clone = null;
-        try {
-            clone = (SparseArrayCompat<E>) super.clone();
-            clone.mKeys = mKeys.clone();
-            clone.mValues = mValues.clone();
-        } catch (CloneNotSupportedException cnse) {
-            /* ignore */
-        }
-        return clone;
-    }
-
-    /**
-     * Gets the Object mapped from the specified key, or <code>null</code>
-     * if no such mapping has been made.
-     */
-    public E get(int key) {
-        return get(key, null);
-    }
-
-    /**
-     * Gets the Object mapped from the specified key, or the specified Object
-     * if no such mapping has been made.
-     */
-    @SuppressWarnings("unchecked")
-    public E get(int key, E valueIfKeyNotFound) {
-        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i < 0 || mValues[i] == DELETED) {
-            return valueIfKeyNotFound;
-        } else {
-            return (E) mValues[i];
-        }
-    }
-
-    /**
-     * Removes the mapping from the specified key, if there was any.
-     */
-    public void delete(int key) {
-        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i >= 0) {
-            if (mValues[i] != DELETED) {
-                mValues[i] = DELETED;
-                mGarbage = true;
-            }
-        }
-    }
-
-    /**
-     * Alias for {@link #delete(int)}.
-     */
-    public void remove(int key) {
-        delete(key);
-    }
-
-    /**
-     * Removes the mapping at the specified index.
-     */
-    public void removeAt(int index) {
-        if (mValues[index] != DELETED) {
-            mValues[index] = DELETED;
-            mGarbage = true;
-        }
-    }
-
-    /**
-     * Remove a range of mappings as a batch.
-     *
-     * @param index Index to begin at
-     * @param size Number of mappings to remove
-     */
-    public void removeAtRange(int index, int size) {
-        final int end = Math.min(mSize, index + size);
-        for (int i = index; i < end; i++) {
-            removeAt(i);
-        }
-    }
-
-    private void gc() {
-        // Log.e("SparseArray", "gc start with " + mSize);
-
-        int n = mSize;
-        int o = 0;
-        int[] keys = mKeys;
-        Object[] values = mValues;
-
-        for (int i = 0; i < n; i++) {
-            Object val = values[i];
-
-            if (val != DELETED) {
-                if (i != o) {
-                    keys[o] = keys[i];
-                    values[o] = val;
-                    values[i] = null;
-                }
-
-                o++;
-            }
-        }
-
-        mGarbage = false;
-        mSize = o;
-
-        // Log.e("SparseArray", "gc end with " + mSize);
-    }
-
-    /**
-     * Adds a mapping from the specified key to the specified value,
-     * replacing the previous mapping from the specified key if there
-     * was one.
-     */
-    public void put(int key, E value) {
-        int i =  ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i >= 0) {
-            mValues[i] = value;
-        } else {
-            i = ~i;
-
-            if (i < mSize && mValues[i] == DELETED) {
-                mKeys[i] = key;
-                mValues[i] = value;
-                return;
-            }
-
-            if (mGarbage && mSize >= mKeys.length) {
-                gc();
-
-                // Search again because indices may have changed.
-                i = ~ ContainerHelpers.binarySearch(mKeys, mSize, key);
-            }
-
-            if (mSize >= mKeys.length) {
-                int n =  ContainerHelpers.idealIntArraySize(mSize + 1);
-
-                int[] nkeys = new int[n];
-                Object[] nvalues = new Object[n];
-
-                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
-            mSize++;
-        }
-    }
-
-    /**
-     * Returns the number of key-value mappings that this SparseArray
-     * currently stores.
-     */
-    public int size() {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mSize;
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, returns
-     * the key from the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
-     */
-    public int keyAt(int index) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mKeys[index];
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, returns
-     * the value from the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
-     */
-    @SuppressWarnings("unchecked")
-    public E valueAt(int index) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return (E) mValues[index];
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, sets a new
-     * value for the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
-     */
-    public void setValueAt(int index, E value) {
-        if (mGarbage) {
-            gc();
-        }
-
-        mValues[index] = value;
-    }
-
-    /**
-     * Returns the index for which {@link #keyAt} would return the
-     * specified key, or a negative number if the specified
-     * key is not mapped.
-     */
-    public int indexOfKey(int key) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return  ContainerHelpers.binarySearch(mKeys, mSize, key);
-    }
-
-    /**
-     * Returns an index for which {@link #valueAt} would return the
-     * specified key, or a negative number if no keys map to the
-     * specified value.
-     * <p>Beware that this is a linear search, unlike lookups by key,
-     * and that multiple keys can map to the same value and this will
-     * find only one of them.
-     * <p>Note also that unlike most collections' {@code indexOf} methods,
-     * this method compares values using {@code ==} rather than {@code equals}.
-     */
-    public int indexOfValue(E value) {
-        if (mGarbage) {
-            gc();
-        }
-
-        for (int i = 0; i < mSize; i++)
-            if (mValues[i] == value)
-                return i;
-
-        return -1;
-    }
-
-    /**
-     * Removes all key-value mappings from this SparseArray.
-     */
-    public void clear() {
-        int n = mSize;
-        Object[] values = mValues;
-
-        for (int i = 0; i < n; i++) {
-            values[i] = null;
-        }
-
-        mSize = 0;
-        mGarbage = false;
-    }
-
-    /**
-     * Puts a key/value pair into the array, optimizing for the case where
-     * the key is greater than all existing keys in the array.
-     */
-    public void append(int key, E value) {
-        if (mSize != 0 && key <= mKeys[mSize - 1]) {
-            put(key, value);
-            return;
-        }
-
-        if (mGarbage && mSize >= mKeys.length) {
-            gc();
-        }
-
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n =  ContainerHelpers.idealIntArraySize(pos + 1);
-
-            int[] nkeys = new int[n];
-            Object[] nvalues = new Object[n];
-
-            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation composes a string by iterating over its mappings. If
-     * this map contains itself as a value, the string "(this Map)"
-     * will appear in its place.
-     */
-    @Override
-    public String toString() {
-        if (size() <= 0) {
-            return "{}";
-        }
-
-        StringBuilder buffer = new StringBuilder(mSize * 28);
-        buffer.append('{');
-        for (int i=0; i<mSize; i++) {
-            if (i > 0) {
-                buffer.append(", ");
-            }
-            int key = keyAt(i);
-            buffer.append(key);
-            buffer.append('=');
-            Object value = valueAt(i);
-            if (value != this) {
-                buffer.append(value);
-            } else {
-                buffer.append("(this Map)");
-            }
-        }
-        buffer.append('}');
-        return buffer.toString();
-    }
-}
diff --git a/compat/src/main/java/android/support/v4/view/MenuCompat.java b/compat/src/main/java/android/support/v4/view/MenuCompat.java
index bbac379..7676d56 100644
--- a/compat/src/main/java/android/support/v4/view/MenuCompat.java
+++ b/compat/src/main/java/android/support/v4/view/MenuCompat.java
@@ -16,6 +16,10 @@
 
 package android.support.v4.view;
 
+import android.annotation.SuppressLint;
+import android.support.v4.internal.view.SupportMenu;
+import android.support.v4.os.BuildCompat;
+import android.view.Menu;
 import android.view.MenuItem;
 
 /**
@@ -32,5 +36,20 @@
         item.setShowAsAction(actionEnum);
     }
 
+    /**
+     * Enable or disable the group dividers.
+     *
+     * @param menu Menu to enable/disable dividers on.
+     * @param enabled True if enabled
+     */
+    @SuppressLint("NewApi")
+    public static void setGroupDividerEnabled(Menu menu, boolean enabled) {
+        if (menu instanceof SupportMenu) {
+            ((SupportMenu) menu).setGroupDividerEnabled(enabled);
+        } else if (BuildCompat.isAtLeastP()) {
+            menu.setGroupDividerEnabled(enabled);
+        }
+    }
+
     private MenuCompat() {}
 }
diff --git a/core-ui/src/main/java/android/support/v4/view/NestedScrollingChildHelper.java b/compat/src/main/java/android/support/v4/view/NestedScrollingChildHelper.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/NestedScrollingChildHelper.java
rename to compat/src/main/java/android/support/v4/view/NestedScrollingChildHelper.java
diff --git a/core-ui/src/main/java/android/support/v4/view/NestedScrollingParentHelper.java b/compat/src/main/java/android/support/v4/view/NestedScrollingParentHelper.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/NestedScrollingParentHelper.java
rename to compat/src/main/java/android/support/v4/view/NestedScrollingParentHelper.java
diff --git a/compat/src/main/java/android/support/v4/view/ViewConfigurationCompat.java b/compat/src/main/java/android/support/v4/view/ViewConfigurationCompat.java
index 60d37a9..a12387b 100644
--- a/compat/src/main/java/android/support/v4/view/ViewConfigurationCompat.java
+++ b/compat/src/main/java/android/support/v4/view/ViewConfigurationCompat.java
@@ -117,5 +117,17 @@
         return 0;
     }
 
+    /**
+     * @param config Used to get the hover slop directly from the {@link ViewConfiguration}.
+     *
+     * @return The hover slop value.
+     */
+    public static int getScaledHoverSlop(ViewConfiguration config) {
+        if (android.os.Build.VERSION.SDK_INT >= 28) {
+            return config.getScaledHoverSlop();
+        }
+        return config.getScaledTouchSlop() / 2;
+    }
+
     private ViewConfigurationCompat() {}
 }
diff --git a/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
index 327be01..d76481c 100644
--- a/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
+++ b/compat/src/main/java/android/support/v4/view/accessibility/AccessibilityNodeInfoCompat.java
@@ -2343,16 +2343,18 @@
 
     public void setCollectionInfo(Object collectionInfo) {
         if (Build.VERSION.SDK_INT >= 19) {
-            mInfo.setCollectionInfo((AccessibilityNodeInfo.CollectionInfo)
-                    ((CollectionInfoCompat) collectionInfo).mInfo);
+            mInfo.setCollectionInfo((collectionInfo == null) ? null
+                    : (AccessibilityNodeInfo.CollectionInfo) ((CollectionInfoCompat)
+                            collectionInfo).mInfo);
         }
 
     }
 
     public void setCollectionItemInfo(Object collectionItemInfo) {
         if (Build.VERSION.SDK_INT >= 19) {
-            mInfo.setCollectionItemInfo((AccessibilityNodeInfo.CollectionItemInfo)
-                    ((CollectionItemInfoCompat) collectionItemInfo).mInfo);
+            mInfo.setCollectionItemInfo((collectionItemInfo == null) ? null
+                    : (AccessibilityNodeInfo.CollectionItemInfo) ((CollectionItemInfoCompat)
+                            collectionItemInfo).mInfo);
         }
     }
 
diff --git a/core-ui/src/main/java/android/support/v4/widget/AutoScrollHelper.java b/compat/src/main/java/android/support/v4/widget/AutoScrollHelper.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/AutoScrollHelper.java
rename to compat/src/main/java/android/support/v4/widget/AutoScrollHelper.java
diff --git a/core-ui/src/main/java/android/support/v4/widget/ContentLoadingProgressBar.java b/compat/src/main/java/android/support/v4/widget/ContentLoadingProgressBar.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/ContentLoadingProgressBar.java
rename to compat/src/main/java/android/support/v4/widget/ContentLoadingProgressBar.java
diff --git a/core-ui/src/main/java/android/support/v4/widget/ListViewAutoScrollHelper.java b/compat/src/main/java/android/support/v4/widget/ListViewAutoScrollHelper.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/ListViewAutoScrollHelper.java
rename to compat/src/main/java/android/support/v4/widget/ListViewAutoScrollHelper.java
diff --git a/core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java b/compat/src/main/java/android/support/v4/widget/NestedScrollView.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/NestedScrollView.java
rename to compat/src/main/java/android/support/v4/widget/NestedScrollView.java
diff --git a/compat/tests/AndroidManifest.xml b/compat/tests/AndroidManifest.xml
deleted file mode 100644
index 8f78188..0000000
--- a/compat/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.compat.test">
-    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
-    <uses-permission android:name="android.permission.VIBRATE"/>
-    <uses-permission android:name="android.permission.WAKE_LOCK"/>
-    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
-
-    <application
-        android:supportsRtl="true"
-        android:theme="@style/TestActivityTheme">
-        <activity android:name="android.support.v4.widget.ListViewTestActivity"/>
-
-        <activity android:name="android.support.v4.widget.TextViewTestActivity"/>
-
-        <activity android:name="android.support.v4.view.VpaActivity"/>
-
-        <activity
-            android:name="android.support.v4.ThemedYellowActivity"
-            android:theme="@style/YellowTheme"/>
-
-        <activity android:name="android.support.v4.view.ViewCompatActivity"/>
-
-        <activity android:name="android.support.v4.app.TestSupportActivity"
-                  android:icon="@drawable/test_drawable_blue"/>
-
-        <activity android:name="android.support.v13.view.DragStartHelperTestActivity"/>
-
-        <provider android:name="android.support.v4.provider.MockFontProvider"
-                  android:authorities="android.support.provider.fonts.font"
-                  android:exported="false"
-                  android:multiprocess="true"/>
-
-        <service android:name="android.support.v4.app.JobIntentServiceTest$TargetService"
-                 android:permission="android.permission.BIND_JOB_SERVICE"/>
-
-    </application>
-
-</manifest>
diff --git a/compat/tests/NO_DOCS b/compat/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/compat/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java b/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
deleted file mode 100644
index 41da709..0000000
--- a/compat/tests/java/android/support/v4/app/NotificationCompatTest.java
+++ /dev/null
@@ -1,518 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import static android.support.v4.app.NotificationCompat.DEFAULT_ALL;
-import static android.support.v4.app.NotificationCompat.DEFAULT_LIGHTS;
-import static android.support.v4.app.NotificationCompat.DEFAULT_SOUND;
-import static android.support.v4.app.NotificationCompat.DEFAULT_VIBRATE;
-import static android.support.v4.app.NotificationCompat.GROUP_ALERT_ALL;
-import static android.support.v4.app.NotificationCompat.GROUP_ALERT_CHILDREN;
-import static android.support.v4.app.NotificationCompat.GROUP_ALERT_SUMMARY;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Notification;
-import android.content.Context;
-import android.graphics.Color;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.BaseInstrumentationTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class NotificationCompatTest extends BaseInstrumentationTestCase<TestSupportActivity> {
-    private static final String TEXT_RESULT_KEY = "text";
-    private static final String DATA_RESULT_KEY = "data";
-    private static final String EXTRA_COLORIZED = "android.colorized";
-
-    Context mContext;
-
-    public NotificationCompatTest() {
-        super(TestSupportActivity.class);
-    }
-
-    @Before
-    public void setup() {
-        mContext = mActivityTestRule.getActivity();
-    }
-
-    @Test
-    public void testBadgeIcon() throws Throwable {
-        int badgeIcon = NotificationCompat.BADGE_ICON_SMALL;
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setBadgeIconType(badgeIcon)
-                .build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            assertEquals(badgeIcon, NotificationCompat.getBadgeIconType(n));
-        } else {
-            assertEquals(NotificationCompat.BADGE_ICON_NONE,
-                    NotificationCompat.getBadgeIconType(n));
-        }
-    }
-
-    @Test
-    public void testTimeout() throws Throwable {
-        long timeout = 23552;
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setTimeoutAfter(timeout)
-                .build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            assertEquals(timeout, NotificationCompat.getTimeoutAfter(n));
-        } else {
-            assertEquals(0, NotificationCompat.getTimeoutAfter(n));
-        }
-    }
-
-    @Test
-    public void testShortcutId() throws Throwable {
-        String shortcutId = "fgdfg";
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setShortcutId(shortcutId)
-                .build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            assertEquals(shortcutId, NotificationCompat.getShortcutId(n));
-        } else {
-            assertEquals(null, NotificationCompat.getShortcutId(n));
-        }
-    }
-
-    @Test
-    public void testNotificationChannel() throws Throwable {
-        String channelId = "new ID";
-        Notification n  = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setChannelId(channelId)
-                .build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            assertEquals(channelId, NotificationCompat.getChannelId(n));
-        } else {
-            assertNull(NotificationCompat.getChannelId(n));
-        }
-    }
-
-    @Test
-    public void testNotificationChannel_assignedFromBuilder() throws Throwable {
-        String channelId = "new ID";
-        Notification n  = new NotificationCompat.Builder(mActivityTestRule.getActivity(), channelId)
-                .build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            assertEquals(channelId, NotificationCompat.getChannelId(n));
-        } else {
-            assertNull(NotificationCompat.getChannelId(n));
-        }
-    }
-
-    @Test
-    public void testNotificationActionBuilder_assignsColorized() throws Throwable {
-        Notification n = newNotificationBuilder().setColorized(true).build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            Bundle extras = NotificationCompat.getExtras(n);
-            assertTrue(Boolean.TRUE.equals(extras.get(EXTRA_COLORIZED)));
-        }
-    }
-
-    @Test
-    public void testNotificationActionBuilder_unassignesColorized() throws Throwable {
-        Notification n = newNotificationBuilder().setColorized(false).build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            Bundle extras = NotificationCompat.getExtras(n);
-            assertTrue(Boolean.FALSE.equals(extras.get(EXTRA_COLORIZED)));
-        }
-    }
-
-    @Test
-    public void testNotificationActionBuilder_doesntAssignColorized() throws Throwable {
-        Notification n = newNotificationBuilder().build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            Bundle extras = NotificationCompat.getExtras(n);
-            assertFalse(extras.containsKey(EXTRA_COLORIZED));
-        }
-    }
-
-    @Test
-    public void testNotificationActionBuilder_copiesRemoteInputs() throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .addRemoteInput(new RemoteInput("a", "b", null, false, null, null)).build();
-
-        NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build();
-
-        assertSame(a.getRemoteInputs()[0], aCopy.getRemoteInputs()[0]);
-    }
-
-    @Test
-    public void testNotificationActionBuilder_copiesAllowGeneratedReplies() throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .setAllowGeneratedReplies(true).build();
-
-        NotificationCompat.Action aCopy = new NotificationCompat.Action.Builder(a).build();
-
-        assertEquals(a.getAllowGeneratedReplies(), aCopy.getAllowGeneratedReplies());
-    }
-
-    @SdkSuppress(minSdkVersion = 24)
-    @Test
-    public void testFrameworkNotificationActionBuilder_setAllowGeneratedRepliesTrue()
-            throws Throwable {
-        Notification notif = new Notification.Builder(mContext)
-                .addAction(new Notification.Action.Builder(0, "title", null)
-                        .setAllowGeneratedReplies(true).build()).build();
-        NotificationCompat.Action action = NotificationCompat.getAction(notif, 0);
-        assertTrue(action.getAllowGeneratedReplies());
-    }
-
-    @Test
-    public void testNotificationActionBuilder_defaultAllowGeneratedRepliesTrue() throws Throwable {
-        NotificationCompat.Action a = newActionBuilder().build();
-
-        assertTrue(a.getAllowGeneratedReplies());
-    }
-
-    @Test
-    public void testNotificationAction_defaultAllowGeneratedRepliesTrue() throws Throwable {
-        NotificationCompat.Action a = new NotificationCompat.Action(0, null, null);
-
-        assertTrue(a.getAllowGeneratedReplies());
-    }
-
-    @Test
-    public void testNotificationActionBuilder_setAllowGeneratedRepliesFalse() throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .setAllowGeneratedReplies(false).build();
-
-        assertFalse(a.getAllowGeneratedReplies());
-    }
-
-    @SdkSuppress(minSdkVersion = 17)
-    @Test
-    public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesTrue()
-            throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .setAllowGeneratedReplies(true).build();
-        NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
-                .addAction(a);
-        Notification notification = newNotificationBuilder().extend(extender).build();
-        assertTrue(new NotificationCompat.WearableExtender(notification).getActions().get(0)
-                .getAllowGeneratedReplies());
-    }
-
-    @SdkSuppress(minSdkVersion = 17)
-    @Test
-    public void testNotificationWearableExtenderAction_setAllowGeneratedRepliesFalse()
-            throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .setAllowGeneratedReplies(false).build();
-        NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
-                .addAction(a);
-        Notification notification = newNotificationBuilder().extend(extender).build();
-        assertFalse(new NotificationCompat.WearableExtender(notification).getActions().get(0)
-                .getAllowGeneratedReplies());
-    }
-
-
-    @SdkSuppress(maxSdkVersion = 16)
-    @SmallTest
-    @Test
-    public void testNotificationWearableExtenderAction_noActions()
-            throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .setAllowGeneratedReplies(true).build();
-        NotificationCompat.WearableExtender extender = new NotificationCompat.WearableExtender()
-                .addAction(a);
-        Notification notification = newNotificationBuilder().extend(extender).build();
-        assertTrue(new NotificationCompat.WearableExtender(notification).getActions().size() == 0);
-    }
-
-    @Test
-    public void testNotificationActionBuilder_setDataOnlyRemoteInput() throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .addRemoteInput(newDataOnlyRemoteInput()).build();
-        RemoteInput[] textInputs = a.getRemoteInputs();
-        assertTrue(textInputs == null || textInputs.length == 0);
-        verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
-    }
-
-    @Test
-    public void testNotificationActionBuilder_setTextAndDataOnlyRemoteInput() throws Throwable {
-        NotificationCompat.Action a = newActionBuilder()
-                .addRemoteInput(newDataOnlyRemoteInput())
-                .addRemoteInput(newTextRemoteInput())
-                .build();
-
-        verifyRemoteInputArrayHasSingleResult(a.getRemoteInputs(), TEXT_RESULT_KEY);
-        verifyRemoteInputArrayHasSingleResult(a.getDataOnlyRemoteInputs(), DATA_RESULT_KEY);
-    }
-
-    @Test
-    public void testMessage_setAndGetExtras() throws Throwable {
-        String extraKey = "extra_key";
-        CharSequence extraValue = "extra_value";
-        NotificationCompat.MessagingStyle.Message m =
-                new NotificationCompat.MessagingStyle.Message("text", 0 /*timestamp */, "sender");
-        m.getExtras().putCharSequence(extraKey, extraValue);
-        assertEquals(extraValue, m.getExtras().getCharSequence(extraKey));
-
-        ArrayList<NotificationCompat.MessagingStyle.Message> messages = new ArrayList<>(1);
-        messages.add(m);
-        Bundle[] bundleArray =
-                NotificationCompat.MessagingStyle.Message.getBundleArrayForMessages(messages);
-        assertEquals(1, bundleArray.length);
-        NotificationCompat.MessagingStyle.Message fromBundle =
-                NotificationCompat.MessagingStyle.Message.getMessageFromBundle(bundleArray[0]);
-        assertEquals(extraValue, fromBundle.getExtras().getCharSequence(extraKey));
-    }
-
-    @Test
-    public void testGetGroupAlertBehavior() throws Throwable {
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
-                .build();
-        if (Build.VERSION.SDK_INT >= 26) {
-            assertEquals(GROUP_ALERT_CHILDREN, NotificationCompat.getGroupAlertBehavior(n));
-        } else {
-            assertEquals(GROUP_ALERT_ALL, NotificationCompat.getGroupAlertBehavior(n));
-        }
-    }
-
-    @Test
-    public void testGroupAlertBehavior_mutesGroupNotifications() throws Throwable {
-        // valid between api 20, when groups were added, and api 25, the last to use sound
-        // and vibration from the notification itself
-
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
-                .setVibrate(new long[] {235})
-                .setSound(Uri.EMPTY)
-                .setDefaults(DEFAULT_ALL)
-                .setGroup("grouped")
-                .setGroupSummary(true)
-                .build();
-
-        Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
-                .setVibrate(new long[] {235})
-                .setSound(Uri.EMPTY)
-                .setDefaults(DEFAULT_ALL)
-                .setGroup("grouped")
-                .setGroupSummary(false)
-                .build();
-
-        if (Build.VERSION.SDK_INT >= 20 && !(Build.VERSION.SDK_INT >= 26)) {
-            assertNull(n.sound);
-            assertNull(n.vibrate);
-            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n.defaults & DEFAULT_SOUND) == 0);
-            assertTrue((n.defaults & DEFAULT_VIBRATE) == 0);
-
-            assertNull(n2.sound);
-            assertNull(n2.vibrate);
-            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n2.defaults & DEFAULT_SOUND) == 0);
-            assertTrue((n2.defaults & DEFAULT_VIBRATE) == 0);
-        } else if (Build.VERSION.SDK_INT < 20) {
-            assertNotNull(n.sound);
-            assertNotNull(n.vibrate);
-            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
-            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
-
-            assertNotNull(n2.sound);
-            assertNotNull(n2.vibrate);
-            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
-            assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
-        }
-    }
-
-    @Test
-    public void testGroupAlertBehavior_doesNotMuteIncorrectGroupNotifications() throws Throwable {
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
-                .setVibrate(new long[] {235})
-                .setSound(Uri.EMPTY)
-                .setDefaults(DEFAULT_ALL)
-                .setGroup("grouped")
-                .setGroupSummary(true)
-                .build();
-
-        Notification n2 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
-                .setVibrate(new long[] {235})
-                .setSound(Uri.EMPTY)
-                .setDefaults(DEFAULT_ALL)
-                .setGroup("grouped")
-                .setGroupSummary(false)
-                .build();
-
-        Notification n3 = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setVibrate(new long[] {235})
-                .setSound(Uri.EMPTY)
-                .setDefaults(DEFAULT_ALL)
-                .setGroup("grouped")
-                .setGroupSummary(false)
-                .build();
-
-        if (Build.VERSION.SDK_INT >= 20 && !(Build.VERSION.SDK_INT >= 26)) {
-            assertNotNull(n.sound);
-            assertNotNull(n.vibrate);
-            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
-            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
-
-            assertNotNull(n2.sound);
-            assertNotNull(n2.vibrate);
-            assertTrue((n2.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n2.defaults & DEFAULT_SOUND) != 0);
-            assertTrue((n2.defaults & DEFAULT_VIBRATE) != 0);
-
-            assertNotNull(n3.sound);
-            assertNotNull(n3.vibrate);
-            assertTrue((n3.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n3.defaults & DEFAULT_SOUND) != 0);
-            assertTrue((n3.defaults & DEFAULT_VIBRATE) != 0);
-        }
-    }
-
-    @Test
-    public void testGroupAlertBehavior_doesNotMuteNonGroupNotifications() throws Throwable {
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setGroupAlertBehavior(GROUP_ALERT_CHILDREN)
-                .setVibrate(new long[] {235})
-                .setSound(Uri.EMPTY)
-                .setDefaults(DEFAULT_ALL)
-                .setGroup(null)
-                .setGroupSummary(false)
-                .build();
-        if (!(Build.VERSION.SDK_INT >= 26)) {
-            assertNotNull(n.sound);
-            assertNotNull(n.vibrate);
-            assertTrue((n.defaults & DEFAULT_LIGHTS) != 0);
-            assertTrue((n.defaults & DEFAULT_SOUND) != 0);
-            assertTrue((n.defaults & DEFAULT_VIBRATE) != 0);
-        }
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 21)
-    public void testHasAudioAttributesFrom21() throws Throwable {
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setSound(Uri.EMPTY)
-                .build();
-        assertNotNull(n.audioAttributes);
-        assertEquals(-1, n.audioStreamType);
-        assertEquals(Uri.EMPTY, n.sound);
-
-        n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setSound(Uri.EMPTY, AudioManager.STREAM_RING)
-                .build();
-        assertNotNull(n.audioAttributes);
-        assertEquals(AudioAttributes.CONTENT_TYPE_SONIFICATION,
-                n.audioAttributes.getContentType());
-        assertEquals(-1, n.audioStreamType);
-        assertEquals(Uri.EMPTY, n.sound);
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 20)
-    public void testHasStreamTypePre21() throws Throwable {
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setSound(Uri.EMPTY, 34)
-                .build();
-        assertEquals(34, n.audioStreamType);
-        assertEquals(Uri.EMPTY, n.sound);
-    }
-
-    @SdkSuppress(minSdkVersion = 26)
-    @Test
-    public void testClearAlertingFieldsIfUsingChannels() throws Throwable {
-        long[] vibration = new long[]{100};
-
-        // stripped if using channels
-        Notification n = new NotificationCompat.Builder(mActivityTestRule.getActivity(), "test")
-                .setSound(Uri.EMPTY)
-                .setDefaults(Notification.DEFAULT_ALL)
-                .setVibrate(vibration)
-                .setLights(Color.BLUE, 100, 100)
-                .build();
-        assertNull(n.sound);
-        assertEquals(0, n.defaults);
-        assertNull(n.vibrate);
-        assertEquals(0, n.ledARGB);
-        assertEquals(0, n.ledOnMS);
-        assertEquals(0, n.ledOffMS);
-
-        // left intact if not using channels
-        n = new NotificationCompat.Builder(mActivityTestRule.getActivity())
-                .setSound(Uri.EMPTY)
-                .setDefaults(Notification.DEFAULT_ALL)
-                .setVibrate(vibration)
-                .setLights(Color.BLUE, 100, 100)
-                .build();
-        assertEquals(Uri.EMPTY, n.sound);
-        assertNotNull(n.audioAttributes);
-        assertEquals(Notification.DEFAULT_ALL, n.defaults);
-        assertEquals(vibration, n.vibrate);
-        assertEquals(Color.BLUE, n.ledARGB);
-        assertEquals(100, n.ledOnMS);
-        assertEquals(100, n.ledOffMS);
-    }
-
-    private static RemoteInput newDataOnlyRemoteInput() {
-        return new RemoteInput.Builder(DATA_RESULT_KEY)
-            .setAllowFreeFormInput(false)
-            .setAllowDataType("mimeType", true)
-            .build();
-    }
-
-    private static RemoteInput newTextRemoteInput() {
-        return new RemoteInput.Builder(TEXT_RESULT_KEY).build();  // allowFreeForm defaults to true
-    }
-
-    private static void verifyRemoteInputArrayHasSingleResult(
-            RemoteInput[] remoteInputs, String expectedResultKey) {
-        assertTrue(remoteInputs != null && remoteInputs.length == 1);
-        assertEquals(expectedResultKey, remoteInputs[0].getResultKey());
-    }
-
-    private static NotificationCompat.Action.Builder newActionBuilder() {
-        return new NotificationCompat.Action.Builder(0, "title", null);
-    }
-
-    private NotificationCompat.Builder newNotificationBuilder() {
-        return new NotificationCompat.Builder(mContext)
-                .setSmallIcon(0)
-                .setContentTitle("title")
-                .setContentText("text");
-    }
-}
diff --git a/compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java b/compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
deleted file mode 100644
index 6120eed..0000000
--- a/compat/tests/java/android/support/v4/content/res/FontResourcesParserCompatTest.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.content.res;
-
-import static android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
-import static android.support.v4.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry;
-import static android.support.v4.content.res.FontResourcesParserCompat.FontFileResourceEntry;
-import static android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import android.annotation.SuppressLint;
-import android.app.Instrumentation;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.os.Build;
-import android.support.compat.test.R;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.provider.FontRequest;
-import android.util.Base64;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.List;
-
-/**
- * Tests for {@link FontResourcesParserCompat}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class FontResourcesParserCompatTest {
-
-    private Instrumentation mInstrumentation;
-    private Resources mResources;
-
-    @Before
-    public void setup() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        mResources = mInstrumentation.getContext().getResources();
-    }
-
-    @Test
-    public void testParse() throws XmlPullParserException, IOException {
-        @SuppressLint("ResourceType")
-        XmlResourceParser parser = mResources.getXml(R.font.samplexmlfont);
-
-        FamilyResourceEntry result = FontResourcesParserCompat.parse(parser, mResources);
-
-        assertNotNull(result);
-        FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) result;
-        FontFileResourceEntry[] fileEntries = filesEntry.getEntries();
-        assertEquals(4, fileEntries.length);
-        FontFileResourceEntry font1 = fileEntries[0];
-        assertEquals(400, font1.getWeight());
-        assertEquals(false, font1.isItalic());
-        assertEquals(R.font.samplefont, font1.getResourceId());
-        FontFileResourceEntry font2 = fileEntries[1];
-        assertEquals(400, font2.getWeight());
-        assertEquals(true, font2.isItalic());
-        assertEquals(R.font.samplefont2, font2.getResourceId());
-        FontFileResourceEntry font3 = fileEntries[2];
-        assertEquals(700, font3.getWeight());
-        assertEquals(false, font3.isItalic());
-        assertEquals(R.font.samplefont3, font3.getResourceId());
-        FontFileResourceEntry font4 = fileEntries[3];
-        assertEquals(700, font4.getWeight());
-        assertEquals(true, font4.isItalic());
-        assertEquals(R.font.samplefont4, font4.getResourceId());
-    }
-
-    @Test
-    public void testParseAndroidAttrs() throws XmlPullParserException, IOException {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
-            // The following tests are only expected to pass on v22+ devices. The android
-            // resources are stripped in older versions and hence won't be parsed.
-            return;
-        }
-
-        @SuppressLint("ResourceType")
-        XmlResourceParser parser = mResources.getXml(R.font.samplexmlfont2);
-
-        FamilyResourceEntry result = FontResourcesParserCompat.parse(parser, mResources);
-
-        assertNotNull(result);
-        FontFamilyFilesResourceEntry filesEntry = (FontFamilyFilesResourceEntry) result;
-        FontFileResourceEntry[] fileEntries = filesEntry.getEntries();
-        assertEquals(4, fileEntries.length);
-        FontFileResourceEntry font1 = fileEntries[0];
-        assertEquals(400, font1.getWeight());
-        assertEquals(false, font1.isItalic());
-        assertEquals(R.font.samplefont, font1.getResourceId());
-        FontFileResourceEntry font2 = fileEntries[1];
-        assertEquals(400, font2.getWeight());
-        assertEquals(true, font2.isItalic());
-        assertEquals(R.font.samplefont2, font2.getResourceId());
-        FontFileResourceEntry font3 = fileEntries[2];
-        assertEquals(700, font3.getWeight());
-        assertEquals(false, font3.isItalic());
-        assertEquals(R.font.samplefont3, font3.getResourceId());
-        FontFileResourceEntry font4 = fileEntries[3];
-        assertEquals(700, font4.getWeight());
-        assertEquals(true, font4.isItalic());
-        assertEquals(R.font.samplefont4, font4.getResourceId());
-    }
-
-    @Test
-    public void testParseDownloadableFont() throws IOException, XmlPullParserException {
-        @SuppressLint("ResourceType")
-        XmlResourceParser parser = mResources.getXml(R.font.samplexmldownloadedfont);
-
-        FamilyResourceEntry result = FontResourcesParserCompat.parse(parser, mResources);
-
-        assertNotNull(result);
-        ProviderResourceEntry providerEntry = (ProviderResourceEntry) result;
-        FontRequest request = providerEntry.getRequest();
-        assertEquals("android.support.provider.fonts.font",
-                request.getProviderAuthority());
-        assertEquals("android.support.compat.test", request.getProviderPackage());
-        assertEquals("singleFontFamily", request.getQuery());
-    }
-
-    @Test
-    public void testReadCertsSingleArray() {
-        List<List<byte[]>> result = FontResourcesParserCompat.readCerts(mResources, R.array.certs1);
-
-        assertEquals(1, result.size());
-        List<byte[]> firstSet = result.get(0);
-        assertEquals(2, firstSet.size());
-        String firstValue = Base64.encodeToString(firstSet.get(0), Base64.DEFAULT).trim();
-        assertEquals("MIIEqDCCA5CgAwIBAgIJANWFuGx9", firstValue);
-        String secondValue = Base64.encodeToString(firstSet.get(1), Base64.DEFAULT).trim();
-        assertEquals("UEChMHQW5kcm9pZDEQMA4GA=", secondValue);
-    }
-
-    @Test
-    public void testReadCertsMultiArray() {
-        List<List<byte[]>> result =
-                FontResourcesParserCompat.readCerts(mResources, R.array.certarray);
-
-        assertEquals(2, result.size());
-        List<byte[]> firstSet = result.get(0);
-        assertEquals(2, firstSet.size());
-        String firstValue = Base64.encodeToString(firstSet.get(0), Base64.DEFAULT).trim();
-        assertEquals("MIIEqDCCA5CgAwIBAgIJANWFuGx9", firstValue);
-        String secondValue = Base64.encodeToString(firstSet.get(1), Base64.DEFAULT).trim();
-        assertEquals("UEChMHQW5kcm9pZDEQMA4GA=", secondValue);
-        List<byte[]> secondSet = result.get(1);
-        assertEquals(2, secondSet.size());
-        String thirdValue = Base64.encodeToString(secondSet.get(0), Base64.DEFAULT).trim();
-        assertEquals("MDEyMzM2NTZaMIGUMQswCQYD", thirdValue);
-        String fourthValue = Base64.encodeToString(secondSet.get(1), Base64.DEFAULT).trim();
-        assertEquals("DHThvbbR24kT9ixcOd9W+EY=", fourthValue);
-    }
-}
diff --git a/compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java b/compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java
deleted file mode 100644
index dff4c33..0000000
--- a/compat/tests/java/android/support/v4/graphics/TypefaceCompatTest.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.graphics;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.annotation.SuppressLint;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.content.res.Resources;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.support.annotation.NonNull;
-import android.support.compat.test.R;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.v4.content.res.FontResourcesParserCompat;
-import android.support.v4.content.res.FontResourcesParserCompat.FamilyResourceEntry;
-import android.support.v4.content.res.FontResourcesParserCompat.ProviderResourceEntry;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v4.provider.FontRequest;
-import android.support.v4.provider.FontsContractCompat;
-import android.support.v4.provider.MockFontProvider;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-public class TypefaceCompatTest {
-
-    public Context mContext;
-    public Resources mResources;
-
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        mResources = mContext.getResources();
-        MockFontProvider.prepareFontFiles(mContext);
-    }
-
-    @After
-    public void tearDown() {
-        MockFontProvider.cleanUpFontFiles(mContext);
-    }
-
-    // Signature to be used for authentication to access content provider.
-    // In this test case, the content provider and consumer live in the same package, self package's
-    // signature works.
-    private static final List<List<byte[]>> SIGNATURE;
-    static {
-        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        try {
-            PackageManager manager = context.getPackageManager();
-            PackageInfo info = manager.getPackageInfo(
-                    context.getPackageName(), PackageManager.GET_SIGNATURES);
-            ArrayList<byte[]> out = new ArrayList<>();
-            for (Signature sig : info.signatures) {
-                out.add(sig.toByteArray());
-            }
-            SIGNATURE = new ArrayList<>();
-            SIGNATURE.add(out);
-        } catch (PackageManager.NameNotFoundException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    /**
-     * Helper method to get the used font resource id by typeface.
-     *
-     * If the typeface is created from one of the R.font.large_a, R.font.large_b, R.font.large_c or
-     * R.font.large_d resource, this method returns the resource id used by the typeface.
-     */
-    private static int getSelectedFontResourceId(Typeface typeface) {
-        // The glyph for "a" in R.font.large_a font has a 3em width and glyph for "b", "c" and "d"
-        // have 1em width. Similarly, The glyph for "b" in R.font.large_b font, the glyph for "c"
-        // in R.font.large_c font, the glyph for "d" in R.font.large_d font has 3em width and the
-        // glyph for the rest characters have 1em. Thus we can get the resource id of the source
-        // font file by comparing width of "a", "b", "c" and "d".
-        Paint p = new Paint();
-        p.setTypeface(typeface);
-        final int[] ids = { R.font.large_a, R.font.large_b, R.font.large_c, R.font.large_d };
-        final float[] widths = {
-            p.measureText("a"), p.measureText("b"), p.measureText("c"), p.measureText("d")
-        };
-
-        int maxIndex = Integer.MIN_VALUE;
-        float maxValue = Float.MIN_VALUE;
-        for (int i = 0; i < widths.length; ++i) {
-            if (maxValue < widths[i]) {
-                maxIndex = i;
-                maxValue = widths[i];
-            }
-        }
-        return ids[maxIndex];
-    }
-
-    /**
-     * Helper method to obtain ProviderResourceEntry with overwriting correct signatures.
-     */
-    private ProviderResourceEntry getProviderResourceEntry(int id) {
-        final ProviderResourceEntry entry;
-        try {
-            entry = (ProviderResourceEntry) FontResourcesParserCompat.parse(
-                    mResources.getXml(id), mResources);
-        } catch (XmlPullParserException | IOException e) {
-            throw new RuntimeException(e);
-        }
-        final FontRequest parsedRequest = entry.getRequest();
-        final FontRequest request = new FontRequest(parsedRequest.getProviderAuthority(),
-                parsedRequest.getProviderPackage(), parsedRequest.getQuery(), SIGNATURE);
-        return new ProviderResourceEntry(request, entry.getFetchStrategy(), entry.getTimeout());
-    }
-
-    public static class FontCallback extends ResourcesCompat.FontCallback {
-        private final CountDownLatch mLatch;
-        Typeface mTypeface;
-
-        FontCallback(CountDownLatch latch) {
-            mLatch = latch;
-        }
-
-        @Override
-        public void onFontRetrieved(@NonNull Typeface typeface) {
-            mTypeface = typeface;
-            mLatch.countDown();
-        }
-
-        @Override
-        public void onFontRetrievalFailed(int reason) {
-            mLatch.countDown();
-        }
-    }
-
-    @Test
-    public void testCreateFromResourcesFamilyXml_resourceFont_asyncloading() throws Exception {
-        final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
-        CountDownLatch latch = new CountDownLatch(1);
-        final FontCallback callback = new FontCallback(latch);
-
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.NORMAL, callback,
-                        null /* handler */, false /* isXmlRequest */);
-            }
-        });
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-
-        assertEquals(R.font.large_a, getSelectedFontResourceId(callback.mTypeface));
-
-        latch = new CountDownLatch(1);
-        final FontCallback callback2 = new FontCallback(latch);
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.ITALIC, callback2,
-                        null /* handler */, false /* isXmlRequest */);
-            }
-        });
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-        assertEquals(R.font.large_b, getSelectedFontResourceId(callback2.mTypeface));
-
-        latch = new CountDownLatch(1);
-        final FontCallback callback3 = new FontCallback(latch);
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.BOLD, callback3,
-                        null /* handler */, false /* isXmlRequest */);
-            }
-        });
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-        assertEquals(R.font.large_c, getSelectedFontResourceId(callback3.mTypeface));
-
-        latch = new CountDownLatch(1);
-        final FontCallback callback4 = new FontCallback(latch);
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.styletest_async_providerfont), mResources,
-                        R.font.styletest_async_providerfont, Typeface.BOLD_ITALIC, callback4,
-                        null /* handler */, false /* isXmlRequest */);
-            }
-        });
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-        assertEquals(R.font.large_d, getSelectedFontResourceId(callback4.mTypeface));
-    }
-
-    @Test
-    public void testProviderFont_xmlRequest() {
-        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                getProviderResourceEntry(R.font.samplexmldownloadedfontblocking), mResources,
-                R.font.samplexmldownloadedfontblocking, Typeface.NORMAL, null,
-                null /* handler */, true /* isXmlRequest */);
-
-        assertNotNull(typeface);
-        assertNotEquals(Typeface.DEFAULT, typeface);
-    }
-
-    @Test
-    public void testProviderFont_nonXmlRequest_noCallback() {
-        // If we don't give a callback, the request should be blocking.
-        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                getProviderResourceEntry(R.font.samplexmldownloadedfontblocking), mResources,
-                R.font.samplexmldownloadedfontblocking, Typeface.NORMAL, null,
-                null /* handler */, false /* isXmlRequest */);
-
-        assertNotNull(typeface);
-        assertNotEquals(Typeface.DEFAULT, typeface);
-    }
-
-    @Test
-    public void testProviderFont_nonXmlRequest_withCallback() throws InterruptedException {
-        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
-        CountDownLatch latch = new CountDownLatch(1);
-        final FontCallback callback = new FontCallback(latch);
-        FontsContractCompat.resetCache();
-
-        final Typeface[] result = new Typeface[1];
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
-                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
-                        callback, null /* handler */, false /* isXmlRequest */);
-            }
-        });
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-        assertNotNull(callback.mTypeface);
-        assertNull(result[0]);
-    }
-
-    @Test
-    public void testProviderFont_nonXmlRequest_withCallback_cached() throws InterruptedException {
-        Instrumentation inst = InstrumentationRegistry.getInstrumentation();
-        CountDownLatch latch = new CountDownLatch(1);
-        final FontCallback callback = new FontCallback(latch);
-        FontsContractCompat.resetCache();
-
-        final Typeface[] result = new Typeface[2];
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
-                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
-                        callback, null /* handler */, false /* isXmlRequest */);
-            }
-        });
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-        assertNotNull(callback.mTypeface);
-        assertNull(result[0]);
-
-        latch = new CountDownLatch(1);
-        final FontCallback callback2 = new FontCallback(latch);
-
-        inst.runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                result[1] = TypefaceCompat.createFromResourcesFamilyXml(mContext,
-                        getProviderResourceEntry(R.font.samplexmldownloadedfontblocking),
-                        mResources, R.font.samplexmldownloadedfontblocking, Typeface.NORMAL,
-                        callback2, null /* handler */, false /* isXmlRequest */);
-            }
-        });
-        assertTrue(latch.await(5L, TimeUnit.SECONDS));
-        assertNotNull(callback2.mTypeface);
-        assertNotNull(result[1]);
-    }
-
-    @Test
-    public void testCreateFromResourcesFamilyXml_resourceFont() throws Exception {
-        @SuppressLint("ResourceType")
-        // We are retrieving the XML font as an XML resource for testing purposes.
-        final FamilyResourceEntry entry = FontResourcesParserCompat.parse(
-                mResources.getXml(R.font.styletestfont), mResources);
-        Typeface typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.NORMAL, null /* callback */, null /* handler */,
-                false /* isXmlRequest */);
-        Typeface cachedTypeface = TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.NORMAL);
-        assertNotNull(cachedTypeface);
-        assertEquals(typeface, cachedTypeface);
-        typeface = Typeface.create(typeface, Typeface.NORMAL);
-        // styletestfont has a node of fontStyle="normal" fontWeight="400" font="@font/large_a".
-        assertEquals(R.font.large_a, getSelectedFontResourceId(typeface));
-
-        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.ITALIC, null /* callback */, null /* handler */,
-                false /* isXmlRequest */);
-        cachedTypeface = TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.ITALIC);
-        assertNotNull(cachedTypeface);
-        assertEquals(typeface, cachedTypeface);
-        typeface = Typeface.create(typeface, Typeface.ITALIC);
-        // styletestfont has a node of fontStyle="italic" fontWeight="400" font="@font/large_b".
-        assertEquals(R.font.large_b, getSelectedFontResourceId(typeface));
-
-        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.BOLD, null /* callback */, null /* handler */,
-                false /* isXmlRequest */);
-        cachedTypeface = TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.BOLD);
-        assertNotNull(cachedTypeface);
-        assertEquals(typeface, cachedTypeface);
-        typeface = Typeface.create(typeface, Typeface.BOLD);
-        // styletestfont has a node of fontStyle="normal" fontWeight="700" font="@font/large_c".
-        assertEquals(R.font.large_c, getSelectedFontResourceId(typeface));
-
-        typeface = TypefaceCompat.createFromResourcesFamilyXml(mContext, entry, mResources,
-                R.font.styletestfont, Typeface.BOLD_ITALIC, null /* callback */,
-                null /* handler */, false /* isXmlRequest */);
-        cachedTypeface = TypefaceCompat.findFromCache(
-                mResources, R.font.styletestfont, Typeface.BOLD_ITALIC);
-        assertNotNull(cachedTypeface);
-        assertEquals(typeface, cachedTypeface);
-        typeface = Typeface.create(typeface, Typeface.BOLD_ITALIC);
-        // styletestfont has a node of fontStyle="italic" fontWeight="700" font="@font/large_d".
-        assertEquals(R.font.large_d, getSelectedFontResourceId(typeface));
-    }
-
-    @Test
-    public void testCreateFromResourcesFontFile() {
-        Typeface typeface = TypefaceCompat.createFromResourcesFontFile(mContext, mResources,
-                R.font.large_a, "res/font/large_a.ttf", Typeface.NORMAL);
-        assertNotNull(typeface);
-        Typeface cachedTypeface = TypefaceCompat.findFromCache(
-                mResources, R.font.large_a, Typeface.NORMAL);
-        assertNotNull(cachedTypeface);
-        assertEquals(typeface, cachedTypeface);
-        assertEquals(R.font.large_a, getSelectedFontResourceId(typeface));
-
-        typeface = TypefaceCompat.createFromResourcesFontFile(mContext, mResources, R.font.large_b,
-                "res/font/large_b.ttf", Typeface.NORMAL);
-        assertNotNull(typeface);
-        cachedTypeface = TypefaceCompat.findFromCache(
-                mResources, R.font.large_b, Typeface.NORMAL);
-        assertNotNull(cachedTypeface);
-        assertEquals(typeface, cachedTypeface);
-        assertEquals(R.font.large_b, getSelectedFontResourceId(typeface));
-    }
-}
diff --git a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java b/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
deleted file mode 100644
index 0822d01..0000000
--- a/compat/tests/java/android/support/v4/text/util/LinkifyCompatTest.java
+++ /dev/null
@@ -1,835 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.text.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.util.PatternsCompat;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.style.URLSpan;
-import android.text.util.Linkify;
-import android.text.util.Linkify.MatchFilter;
-import android.text.util.Linkify.TransformFilter;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Locale;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Test {@link LinkifyCompat}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class LinkifyCompatTest {
-    private static final Pattern LINKIFY_TEST_PATTERN = Pattern.compile(
-            "(test:)?[a-zA-Z0-9]+(\\.pattern)?");
-
-    private MatchFilter mMatchFilterStartWithDot = new MatchFilter() {
-        @Override
-        public boolean acceptMatch(final CharSequence s, final int start, final int end) {
-            if (start == 0) {
-                return true;
-            }
-
-            if (s.charAt(start - 1) == '.') {
-                return false;
-            }
-
-            return true;
-        }
-    };
-
-    private TransformFilter mTransformFilterUpperChar = new TransformFilter() {
-        @Override
-        public String transformUrl(final Matcher match, String url) {
-            StringBuilder buffer = new StringBuilder();
-            String matchingRegion = match.group();
-
-            for (int i = 0, size = matchingRegion.length(); i < size; i++) {
-                char character = matchingRegion.charAt(i);
-
-                if (character == '.' || Character.isLowerCase(character)
-                        || Character.isDigit(character)) {
-                    buffer.append(character);
-                }
-            }
-            return buffer.toString();
-        }
-    };
-
-    @Test
-    public void testAddLinksToSpannable() {
-        // Verify URLs including the ones that have new gTLDs, and the
-        // ones that look like gTLDs (and so are accepted by linkify)
-        // and the ones that should not be linkified due to non-compliant
-        // gTLDs
-        final String longGTLD =
-                "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabc";
-        SpannableString spannable = new SpannableString("name@gmail.com, "
-                + "www.google.com, http://www.google.com/language_tools?hl=en, "
-                + "a.bd, "   // a URL with accepted TLD so should be linkified
-                + "d.e, f.1, g.12, "  // not valid, so should not be linkified
-                + "http://h." + longGTLD + " "  // valid, should be linkified
-                + "j." + longGTLD + "a"); // not a valid URL (gtld too long), no linkify
-
-        assertTrue(LinkifyCompat.addLinks(spannable, Linkify.WEB_URLS));
-        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-        assertEquals(4, spans.length);
-        assertEquals("http://www.google.com", spans[0].getURL());
-        assertEquals("http://www.google.com/language_tools?hl=en", spans[1].getURL());
-        assertEquals("http://a.bd", spans[2].getURL());
-        assertEquals("http://h." + longGTLD, spans[3].getURL());
-
-        assertTrue(LinkifyCompat.addLinks(spannable, Linkify.EMAIL_ADDRESSES));
-        spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-        assertEquals(1, spans.length);
-        assertEquals("mailto:name@gmail.com", spans[0].getURL());
-
-        try {
-            LinkifyCompat.addLinks((Spannable) null, Linkify.WEB_URLS);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        assertFalse(LinkifyCompat.addLinks((Spannable) null, 0));
-    }
-
-    @Test
-    public void testAddLinksToSpannableWithScheme() {
-        String text = "google.pattern, test:AZ0101.pattern";
-
-        SpannableString spannable = new SpannableString(text);
-        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:");
-        URLSpan[] spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
-        assertEquals(2, spans.length);
-        assertEquals("test:google.pattern", spans[0].getURL());
-        assertEquals("test:AZ0101.pattern", spans[1].getURL());
-
-        try {
-            LinkifyCompat.addLinks((Spannable) null, LINKIFY_TEST_PATTERN, "Test:");
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-        }
-
-        try {
-            LinkifyCompat.addLinks(spannable, null, "Test:");
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-        }
-
-        spannable = new SpannableString(text);
-        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, null);
-        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
-        assertEquals(2, spans.length);
-        assertEquals("google.pattern", spans[0].getURL());
-        assertEquals("test:AZ0101.pattern", spans[1].getURL());
-    }
-
-    @Test
-    public void testAddLinks3() {
-        String text = "FilterUpperCase.pattern, 12.345.pattern";
-
-        SpannableString spannable = new SpannableString(text);
-        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:",
-                mMatchFilterStartWithDot, mTransformFilterUpperChar);
-        URLSpan[] spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
-        assertEquals(2, spans.length);
-        assertEquals("test:ilterpperase.pattern", spans[0].getURL());
-        assertEquals("test:12", spans[1].getURL());
-
-        try {
-            LinkifyCompat.addLinks((Spannable)null, LINKIFY_TEST_PATTERN, "Test:",
-                    mMatchFilterStartWithDot, mTransformFilterUpperChar);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        try {
-            LinkifyCompat.addLinks(spannable, null, "Test:", mMatchFilterStartWithDot,
-                    mTransformFilterUpperChar);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        spannable = new SpannableString(text);
-        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, null, mMatchFilterStartWithDot,
-                mTransformFilterUpperChar);
-        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
-        assertEquals(2, spans.length);
-        assertEquals("ilterpperase.pattern", spans[0].getURL());
-        assertEquals("12", spans[1].getURL());
-
-        spannable = new SpannableString(text);
-        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:", null, mTransformFilterUpperChar);
-        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
-        assertEquals(3, spans.length);
-        assertEquals("test:ilterpperase.pattern", spans[0].getURL());
-        assertEquals("test:12", spans[1].getURL());
-        assertEquals("test:345.pattern", spans[2].getURL());
-
-        spannable = new SpannableString(text);
-        LinkifyCompat.addLinks(spannable, LINKIFY_TEST_PATTERN, "Test:", mMatchFilterStartWithDot, null);
-        spans = (spannable.getSpans(0, spannable.length(), URLSpan.class));
-        assertEquals(2, spans.length);
-        assertEquals("test:FilterUpperCase.pattern", spans[0].getURL());
-        assertEquals("test:12", spans[1].getURL());
-    }
-
-    @Test
-    public void testAddLinksPhoneNumbers() {
-        String numbersInvalid = "123456789 not a phone number";
-        String numbersUKLocal = "tel:(0812)1234560 (0812)1234561";
-        String numbersUSLocal = "tel:(812)1234562 (812)123.4563 "
-                + " tel:(800)5551210 (800)555-1211 555-1212";
-        String numbersIntl = "tel:+4408121234564 +44-0812-123-4565"
-                + " tel:+18005551213 +1-800-555-1214";
-        SpannableString spannable = new SpannableString(
-                numbersInvalid
-                        + " " + numbersUKLocal
-                        + " " + numbersUSLocal
-                        + " " + numbersIntl);
-
-        // phonenumber linkify is locale-dependent
-        if (Locale.US.equals(Locale.getDefault())) {
-            assertTrue(LinkifyCompat.addLinks(spannable, Linkify.PHONE_NUMBERS));
-            URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-            // We cannot assert the contents of the spans as support library falls back to the
-            // framework libphonenumber which behaves differently for different API levels.
-            assertNotEquals("There should be more than zero phone number spans.", 0, spans.length);
-        }
-
-        try {
-            LinkifyCompat.addLinks((Spannable) null, Linkify.WEB_URLS);
-            fail("Should throw NullPointerException!");
-        } catch (NullPointerException e) {
-            // expect
-        }
-
-        assertFalse(LinkifyCompat.addLinks((Spannable) null, 0));
-    }
-
-    @Test
-    public void testAddLinks_spanOverlapPruning() {
-        SpannableString spannable = new SpannableString("800-555-1211@gmail.com 800-555-1222.com"
-                + " phone +1-800-555-1214");
-
-        // phonenumber linkify is locale-dependent
-        if (Locale.US.equals(Locale.getDefault())) {
-            assertTrue(LinkifyCompat.addLinks(spannable, Linkify.ALL));
-            URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-            assertEquals(3, spans.length);
-            assertTrue(containsUrl(spans, "tel:+18005551214"));
-            assertTrue(containsUrl(spans, "mailto:800-555-1211@gmail.com"));
-            assertTrue(containsUrl(spans, "http://800-555-1222.com"));
-        }
-    }
-
-    private boolean containsUrl(URLSpan[] spans, String expectedValue) {
-        for (URLSpan span : spans) {
-            if (span.getURL().equals(expectedValue)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Test
-    public void testAddLinks_addsLinksWhenDefaultSchemeIsNull() {
-        Spannable spannable = new SpannableString("any https://android.com any android.com any");
-        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, null, null, null);
-
-        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-        assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
-        assertEquals("https://android.com", spans[0].getURL());
-        assertEquals("android.com", spans[1].getURL());
-    }
-
-    @Test
-    public void testAddLinks_addsLinksWhenSchemesArrayIsNull() {
-        Spannable spannable = new SpannableString("any https://android.com any android.com any");
-        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, "http://", null, null);
-
-        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-        assertEquals("android.com and https://android.com should be linkified", 2, spans.length);
-        // expected behavior, passing null schemes array means: prepend defaultScheme to all links.
-        assertEquals("http://https://android.com", spans[0].getURL());
-        assertEquals("http://android.com", spans[1].getURL());
-    }
-
-    @Test
-    public void testAddLinks_prependsDefaultSchemeToBeginingOfLink() {
-        Spannable spannable = new SpannableString("any android.com any");
-        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, "http://",
-                new String[] { "http://", "https://"}, null, null);
-
-        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-        assertEquals("android.com should be linkified", 1, spans.length);
-        assertEquals("http://android.com", spans[0].getURL());
-    }
-
-    @Test
-    public void testAddLinks_doesNotPrependSchemeIfSchemeExists() {
-        Spannable spannable = new SpannableString("any https://android.com any");
-        LinkifyCompat.addLinks(spannable, PatternsCompat.AUTOLINK_WEB_URL, "http://",
-                new String[] { "http://", "https://"}, null, null);
-
-        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-        assertEquals("android.com should be linkified", 1, spans.length);
-        assertEquals("https://android.com", spans[0].getURL());
-    }
-
-    // WEB_URLS Related Tests
-
-    @Test
-    public void testAddLinks_doesNotAddLinksForUrlWithoutProtocolAndWithoutKnownTld() {
-        Spannable spannable = new SpannableString("hey man.its me");
-        boolean linksAdded = LinkifyCompat.addLinks(spannable, Linkify.ALL);
-        assertFalse("Should not add link with unknown TLD", linksAdded);
-    }
-
-    @Test
-    public void testAddLinks_shouldNotAddEmailAddressAsUrl() {
-        String url = "name@gmail.com";
-        verifyAddLinksWithWebUrlFails("Should not recognize email address as URL", url);
-    }
-
-    @Test
-    public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() {
-        String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
-        verifyAddLinksWithWebUrlSucceeds("Should accept commas", url);
-    }
-
-    @Test
-    public void testAddLinks_addsLinksForUrlWithProtocolWithoutTld() {
-        String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
-        verifyAddLinksWithWebUrlSucceeds("Should accept URL starting with protocol but does not"
-                + " have TLD", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesProtocolCaseInsensitive() {
-        String url = "hTtP://android.com";
-        verifyAddLinksWithWebUrlSucceeds("Protocol matching should be case insensitive", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesValidUrlWithSchemeAndHostname() {
-        String url = "http://www.android.com";
-        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme and hostname", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesValidUrlWithSchemeHostnameAndNewTld() {
-        String url = "http://www.android.me";
-        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with scheme hostname and new TLD",
-                url);
-    }
-
-    @Test
-    public void testAddLinks_matchesValidUrlWithHostnameAndNewTld() {
-        String url = "android.camera";
-        verifyAddLinksWithWebUrlSucceeds("Should match valid URL with hostname and new TLD", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesPunycodeUrl() {
-        String url = "http://xn--fsqu00a.xn--unup4y";
-        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesPunycodeUrlWithoutProtocol() {
-        String url = "xn--fsqu00a.xn--unup4y";
-        verifyAddLinksWithWebUrlSucceeds("Should match Punycode URL without protocol", url);
-    }
-
-    @Test
-    public void testAddLinks_doesNotMatchPunycodeTldThatStartsWithDash() {
-        String url = "xn--fsqu00a.-xn--unup4y";
-        verifyAddLinksWithWebUrlFails("Should not match Punycode TLD that starts with dash", url);
-    }
-
-    @Test
-    public void testAddLinks_partiallyMatchesPunycodeTldThatEndsWithDash() {
-        String url = "http://xn--fsqu00a.xn--unup4y-";
-        verifyAddLinksWithWebUrlPartiallyMatches("Should partially match Punycode TLD that ends "
-                + "with dash", "http://xn--fsqu00a.xn--unup4y", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesUrlWithUnicodeDomainName() {
-        String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesUrlWithUnicodeDomainNameWithoutProtocol() {
-        String url = "\uD604\uAE08\uC601\uC218\uC99D.kr";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL without protocol and with Unicode "
-                + "domain name", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesUrlWithUnicodeDomainNameAndTld() {
-        String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode domain name and TLD", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesUrlWithUnicodePath() {
-        String url = "http://android.com/\u2019/a";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL with Unicode path", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesValidUrlWithPort() {
-        String url = "http://www.example.com:8080";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL with port", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesUrlWithPortAndQuery() {
-        String url = "http://www.example.com:8080/?foo=bar";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL with port and query", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesUrlWithTilde() {
-        String url = "http://www.example.com:8080/~user/?foo=bar";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL with tilde", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesUrlStartingWithHttpAndDoesNotHaveTld() {
-        String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL without a TLD and starting with http",
-                url);
-    }
-
-    @Test
-    public void testAddLinks_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() {
-        String url = "thank.you";
-        verifyAddLinksWithWebUrlFails("Should not match URL that does not start with a protocol "
-                + "and does not contain a known TLD", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesValidUrlWithEmoji() {
-        String url = "Thank\u263A.com";
-        verifyAddLinksWithWebUrlSucceeds("Should match URL with emoji", url);
-    }
-
-    @Test
-    public void testAddLinks_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld() {
-        String url = "Thank\u263A.you";
-        verifyAddLinksWithWebUrlFails("Should not match URLs containing emoji and with unknown "
-                + "TLD", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesDomainNameWithSurrogatePairs() {
-        String url = "android\uD83C\uDF38.com";
-        verifyAddLinksWithWebUrlSucceeds("Should match domain name with Unicode surrogate pairs",
-                url);
-    }
-
-    @Test
-    public void testAddLinks_matchesTldWithSurrogatePairs() {
-        String url = "http://android.\uD83C\uDF38com";
-        verifyAddLinksWithWebUrlSucceeds("Should match TLD with Unicode surrogate pairs", url);
-    }
-
-    @Test
-    public void testAddLinks_doesNotMatchUrlWithExcludedSurrogate() {
-        String url = "android\uD83F\uDFFE.com";
-        verifyAddLinksWithWebUrlFails("Should not match URL with excluded Unicode surrogate"
-                + " pair",  url);
-    }
-
-    @Test
-    public void testAddLinks_matchesPathWithSurrogatePairs() {
-        String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38f";
-        verifyAddLinksWithWebUrlSucceeds("Should match path and query with Unicode surrogate pairs",
-                url);
-    }
-
-    @Test
-    public void testAddLinks__doesNotMatchUnicodeSpaces() {
-        String part1 = "http://and";
-        String part2 = "roid.com";
-        String[] emptySpaces = new String[]{
-                "\u00A0", // no-break space
-                "\u2000", // en quad
-                "\u2001", // em quad
-                "\u2002", // en space
-                "\u2003", // em space
-                "\u2004", // three-per-em space
-                "\u2005", // four-per-em space
-                "\u2006", // six-per-em space
-                "\u2007", // figure space
-                "\u2008", // punctuation space
-                "\u2009", // thin space
-                "\u200A", // hair space
-                "\u2028", // line separator
-                "\u2029", // paragraph separator
-                "\u202F", // narrow no-break space
-                "\u3000"  // ideographic space
-        };
-
-        for (String emptySpace : emptySpaces) {
-            String url = part1 + emptySpace + part2;
-            verifyAddLinksWithWebUrlPartiallyMatches("Should not include empty space with code: "
-                    + emptySpace.codePointAt(0), part1, url);
-        }
-    }
-
-    @Test
-    public void testAddLinks_matchesDomainNameWithDash() {
-        String url = "http://a-nd.r-oid.com";
-        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
-
-        url = "a-nd.r-oid.com";
-        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '-'", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesDomainNameWithUnderscore() {
-        String url = "http://a_nd.r_oid.com";
-        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
-
-        url = "a_nd.r_oid.com";
-        verifyAddLinksWithWebUrlSucceeds("Should match domain name with '_'", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesPathAndQueryWithDollarSign() {
-        String url = "http://android.com/path$?v=$val";
-        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
-
-        url = "android.com/path$?v=$val";
-        verifyAddLinksWithWebUrlSucceeds("Should match path and query with '$'", url);
-    }
-
-    @Test
-    public void testAddLinks_matchesEmptyPathWithQueryParams() {
-        String url = "http://android.com?q=v";
-        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
-
-        url = "android.com?q=v";
-        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
-
-        url = "http://android.com/?q=v";
-        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
-
-        url = "android.com/?q=v";
-        verifyAddLinksWithWebUrlSucceeds("Should match empty path with query params", url);
-    }
-
-    // EMAIL_ADDRESSES Related Tests
-
-    @Test
-    public void testAddLinks_email_matchesShortValidEmail() {
-        String email = "a@a.co";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-
-        email = "ab@a.co";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesRegularEmail() {
-        String email = "email@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesEmailWithMultipleSubdomains() {
-        String email = "email@e.somelongdomainnameforandroid.abc.uk";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithDot() {
-        String email = "e.mail@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithPlus() {
-        String email = "e+mail@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithUnderscore() {
-        String email = "e_mail@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithDash() {
-        String email = "e-mail@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithApostrophe() {
-        String email = "e'mail@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithDigits() {
-        String email = "123@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesUnicodeLocalPart() {
-        String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithEmoji() {
-        String email = "smiley\u263A@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartWithSurrogatePairs() {
-        String email = "a\uD83C\uDF38a@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesDomainWithDash() {
-        String email = "email@an-droid.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesUnicodeDomain() {
-        String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesUnicodeLocalPartAndDomain() {
-        String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesDomainWithEmoji() {
-        String email = "smiley@\u263Aandroid.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesDomainWithSurrogatePairs() {
-        String email = "email@\uD83C\uDF38android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartAndDomainWithSurrogatePairs() {
-        String email = "a\uD83C\uDF38a@\uD83C\uDF38android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_partiallyMatchesEmailEndingWithDot() {
-        String email = "email@android.co.uk.";
-        verifyAddLinksWithEmailPartiallyMatches("Should partially match email ending with dot",
-                "mailto:email@android.co.uk", email);
-    }
-
-    @Test
-    public void testAddLinks_email_partiallyMatchesLocalPartStartingWithDot() {
-        String email = ".email@android.com";
-        verifyAddLinksWithEmailPartiallyMatches("Should partially match email starting "
-                + "with dot", "mailto:email@android.com", email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchStringWithoutAtSign() {
-        String email = "android.com";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchPlainString() {
-        String email = "email";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchEmailWithoutTld() {
-        String email = "email@android";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchLocalPartEndingWithDot() {
-        String email = "email.@android.com";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchDomainStartingWithDash() {
-        String email = "email@-android.com";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchDomainWithConsecutiveDots() {
-        String email = "email@android..com";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchEmailWithIp() {
-        String email = "email@127.0.0.1";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_doesNotMatchEmailWithInvalidTld() {
-        String email = "email@android.c";
-        verifyAddLinksWithEmailFails("Should not match email: " + email, email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesLocalPartUpTo64Chars() {
-        String localPart = "";
-        for (int i = 0; i < 64; i++) {
-            localPart += "a";
-        }
-        String email = localPart + "@android.com";
-        verifyAddLinksWithEmailSucceeds("Should match email local part of length: "
-                + localPart.length(), email);
-
-        email = localPart + "a@android.com";
-        verifyAddLinksWithEmailFails("Should not match email local part of length:"
-                + localPart.length(), email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesSubdomainUpTo63Chars() {
-        String subdomain = "";
-        for (int i = 0; i < 63; i++) {
-            subdomain += "a";
-        }
-        String email = "email@" + subdomain + ".com";
-
-        verifyAddLinksWithEmailSucceeds("Should match email subdomain of length: "
-                + subdomain.length(), email);
-
-        subdomain += "a";
-        email = "email@" + subdomain + ".com";
-
-        verifyAddLinksWithEmailFails("Should not match email subdomain of length:"
-                + subdomain.length(), email);
-    }
-
-    @Test
-    public void testAddLinks_email_matchesDomainUpTo255Chars() {
-        String domain = "";
-        while (domain.length() <= 250) {
-            domain += "d.";
-        }
-        domain += "com";
-        assertEquals(255, domain.length());
-        String email = "a@" + domain;
-        verifyAddLinksWithEmailSucceeds("Should match email domain of length: "
-                + domain.length(), email);
-
-        email = email + "m";
-        verifyAddLinksWithEmailFails("Should not match email domain of length:"
-                + domain.length(), email);
-    }
-
-    // Utility functions
-    private static void verifyAddLinksWithWebUrlSucceeds(String msg, String url) {
-        verifyAddLinksSucceeds(msg, url, Linkify.WEB_URLS);
-    }
-
-    private static void verifyAddLinksWithWebUrlFails(String msg, String url) {
-        verifyAddLinksFails(msg, url, Linkify.WEB_URLS);
-    }
-
-    private static void verifyAddLinksWithWebUrlPartiallyMatches(String msg, String expected,
-            String url) {
-        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.WEB_URLS);
-    }
-
-    private static void verifyAddLinksWithEmailSucceeds(String msg, String url) {
-        verifyAddLinksSucceeds(msg, url, Linkify.EMAIL_ADDRESSES);
-    }
-
-    private static void verifyAddLinksWithEmailFails(String msg, String url) {
-        verifyAddLinksFails(msg, url, Linkify.EMAIL_ADDRESSES);
-    }
-
-    private static void verifyAddLinksWithEmailPartiallyMatches(String msg, String expected,
-            String url) {
-        verifyAddLinksPartiallyMatches(msg, expected, url, Linkify.EMAIL_ADDRESSES);
-    }
-
-    private static void verifyAddLinksSucceeds(String msg, String string, int type) {
-        String str = "start " + string + " end";
-        Spannable spannable = new SpannableString(str);
-
-        boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
-        URLSpan[] spans = spannable.getSpans(0, str.length(), URLSpan.class);
-
-        assertTrue(msg, linksAdded);
-        assertEquals("Span should start from the beginning of: " + string,
-                "start ".length(), spannable.getSpanStart(spans[0]));
-        assertEquals("Span should end at the end of: " + string,
-                str.length() - " end".length(), spannable.getSpanEnd(spans[0]));
-    }
-
-    private static void verifyAddLinksFails(String msg, String string, int type) {
-        Spannable spannable = new SpannableString("start " + string + " end");
-        boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
-        assertFalse(msg, linksAdded);
-    }
-
-    private static void verifyAddLinksPartiallyMatches(String msg, String expected,
-            String string, int type) {
-        Spannable spannable = new SpannableString("start " + string + " end");
-        boolean linksAdded = LinkifyCompat.addLinks(spannable, type);
-        URLSpan[] spans = spannable.getSpans(0, spannable.length(), URLSpan.class);
-        assertTrue(msg, linksAdded);
-        assertEquals(msg, expected, spans[0].getURL().toString());
-    }
-}
diff --git a/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java b/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java
deleted file mode 100644
index c00d264..0000000
--- a/compat/tests/java/android/support/v4/util/ArrayMapCompatTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v4.util;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.AbstractMap;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ArrayMapCompatTest {
-
-    @Test
-    public void testCanNotIteratePastEnd_entrySetIterator() {
-        Map<String, String> map = new ArrayMap<>();
-        map.put("key 1", "value 1");
-        map.put("key 2", "value 2");
-        Set<Map.Entry<String, String>> expectedEntriesToIterate = new HashSet<>(Arrays.asList(
-                entryOf("key 1", "value 1"),
-                entryOf("key 2", "value 2")
-        ));
-        Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
-
-        // Assert iteration over the expected two entries in any order
-        assertTrue(iterator.hasNext());
-        Map.Entry<String, String> firstEntry = copyOf(iterator.next());
-        assertTrue(expectedEntriesToIterate.remove(firstEntry));
-
-        assertTrue(iterator.hasNext());
-        Map.Entry<String, String> secondEntry = copyOf(iterator.next());
-        assertTrue(expectedEntriesToIterate.remove(secondEntry));
-
-        assertFalse(iterator.hasNext());
-
-        try {
-            iterator.next();
-            fail();
-        } catch (NoSuchElementException expected) {
-        }
-    }
-
-    private static <K, V> Map.Entry<K, V> entryOf(K key, V value) {
-        return new AbstractMap.SimpleEntry<>(key, value);
-    }
-
-    private static <K, V> Map.Entry<K, V> copyOf(Map.Entry<K, V> entry) {
-        return entryOf(entry.getKey(), entry.getValue());
-    }
-
-    @Test
-    public void testCanNotIteratePastEnd_keySetIterator() {
-        Map<String, String> map = new ArrayMap<>();
-        map.put("key 1", "value 1");
-        map.put("key 2", "value 2");
-        Set<String> expectedKeysToIterate = new HashSet<>(Arrays.asList("key 1", "key 2"));
-        Iterator<String> iterator = map.keySet().iterator();
-
-        // Assert iteration over the expected two keys in any order
-        assertTrue(iterator.hasNext());
-        String firstKey = iterator.next();
-        assertTrue(expectedKeysToIterate.remove(firstKey));
-
-        assertTrue(iterator.hasNext());
-        String secondKey = iterator.next();
-        assertTrue(expectedKeysToIterate.remove(secondKey));
-
-        assertFalse(iterator.hasNext());
-
-        try {
-            iterator.next();
-            fail();
-        } catch (NoSuchElementException expected) {
-        }
-    }
-
-    @Test
-    public void testCanNotIteratePastEnd_valuesIterator() {
-        Map<String, String> map = new ArrayMap<>();
-        map.put("key 1", "value 1");
-        map.put("key 2", "value 2");
-        Set<String> expectedValuesToIterate = new HashSet<>(Arrays.asList("value 1", "value 2"));
-        Iterator<String> iterator = map.values().iterator();
-
-        // Assert iteration over the expected two values in any order
-        assertTrue(iterator.hasNext());
-        String firstValue = iterator.next();
-        assertTrue(expectedValuesToIterate.remove(firstValue));
-
-        assertTrue(iterator.hasNext());
-        String secondValue = iterator.next();
-        assertTrue(expectedValuesToIterate.remove(secondValue));
-
-        assertFalse(iterator.hasNext());
-
-        try {
-            iterator.next();
-            fail();
-        } catch (NoSuchElementException expected) {
-        }
-    }
-}
diff --git a/compat/tests/java/android/support/v4/util/ArraySetCompatTest.java b/compat/tests/java/android/support/v4/util/ArraySetCompatTest.java
deleted file mode 100644
index 10a0b1b..0000000
--- a/compat/tests/java/android/support/v4/util/ArraySetCompatTest.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v4.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ArraySetCompatTest {
-    @Test
-    public void testCanNotIteratePastEnd() {
-        ArraySet<String> set = new ArraySet<>();
-        set.add("value");
-        Iterator<String> iterator = set.iterator();
-
-        assertTrue(iterator.hasNext());
-        assertEquals("value", iterator.next());
-        assertFalse(iterator.hasNext());
-
-        try {
-            iterator.next();
-            fail();
-        } catch (NoSuchElementException expected) {
-        }
-    }
-}
diff --git a/compat/tests/java/android/support/v4/util/SimpleArrayMapTest.java b/compat/tests/java/android/support/v4/util/SimpleArrayMapTest.java
deleted file mode 100644
index 350b917..0000000
--- a/compat/tests/java/android/support/v4/util/SimpleArrayMapTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package android.support.v4.util;
-
-import static org.junit.Assert.fail;
-
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ConcurrentModificationException;
-import java.util.Locale;
-
-/**
- * Unit tests for SimpleArrayMap
- */
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class SimpleArrayMapTest {
-    private static final String TAG = "SimpleArrayMapTest";
-    SimpleArrayMap<String, String> map = new SimpleArrayMap<>();
-    private boolean mDone;
-
-    /**
-     * Attempt to generate a ConcurrentModificationException in ArrayMap.
-     */
-    @Test
-    public void testConcurrentModificationException() throws Exception {
-        final int TEST_LEN_MS = 5000;
-        Log.d(TAG, "Starting SimpleArrayMap concurrency test");
-        mDone = false;
-        new Thread(new Runnable() {
-            @Override
-            public void run() {
-                int i = 0;
-                while (!mDone) {
-                    try {
-                        map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT");
-                    } catch (ArrayIndexOutOfBoundsException e) {
-                        // SimpleArrayMap is not thread safe, so lots of concurrent modifications
-                        // can still cause data corruption
-                        Log.w(TAG, "concurrent modification uncaught, causing indexing failure", e);
-                    } catch (ClassCastException e) {
-                        // cache corruption should not occur as it is hard to trace and one thread
-                        // may corrupt the pool for all threads in the same process.
-                        Log.e(TAG, "concurrent modification uncaught, causing cache corruption", e);
-                        fail();
-                    } catch (ConcurrentModificationException e) {
-                    }
-                }
-            }
-        }).start();
-        for (int i = 0; i < (TEST_LEN_MS / 100); i++) {
-            try {
-                Thread.sleep(100);
-                map.clear();
-            } catch (InterruptedException e) {
-            } catch (ArrayIndexOutOfBoundsException e) {
-                Log.w(TAG, "concurrent modification uncaught, causing indexing failure");
-            } catch (ClassCastException e) {
-                Log.e(TAG, "concurrent modification uncaught, causing cache corruption");
-                fail();
-            } catch (ConcurrentModificationException e) {
-            }
-        }
-        mDone = true;
-    }
-
-    /**
-     * Check to make sure the same operations behave as expected in a single thread.
-     */
-    @Test
-    public void testNonConcurrentAccesses() throws Exception {
-        for (int i = 0; i < 100000; i++) {
-            try {
-                map.put(String.format(Locale.US, "key %d", i++), "B_DONT_DO_THAT");
-                if (i % 500 == 0) {
-                    map.clear();
-                }
-            } catch (ConcurrentModificationException e) {
-                Log.e(TAG, "concurrent modification caught on single thread", e);
-                fail();
-            }
-        }
-    }
-}
diff --git a/content/Android.mk b/content/Android.mk
deleted file mode 100644
index cdd49af..0000000
--- a/content/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-content
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/content/src/androidTest/AndroidManifest.xml b/content/src/androidTest/AndroidManifest.xml
index 4a815c4..4ccc3a2 100644
--- a/content/src/androidTest/AndroidManifest.xml
+++ b/content/src/androidTest/AndroidManifest.xml
@@ -15,9 +15,8 @@
   ~ limitations under the License.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
           package="android.support.content.test">
-    <uses-sdk android:minSdkVersion="14" />
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
 
     <application android:supportsRtl="true">
         <activity android:name="android.support.content.TestActivity" />
diff --git a/content/src/androidTest/NO_DOCS b/content/src/androidTest/NO_DOCS
deleted file mode 100644
index 4dad694..0000000
--- a/content/src/androidTest/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/content/src/main/AndroidManifest.xml b/content/src/main/AndroidManifest.xml
index 8d2bc4b..a0475e5 100644
--- a/content/src/main/AndroidManifest.xml
+++ b/content/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="android.support.content">
-    <uses-sdk android:minSdkVersion="14" />
-</manifest>
+<manifest package="android.support.content"/>
diff --git a/coordinatorlayout/api/current.txt b/coordinatorlayout/api/current.txt
new file mode 100644
index 0000000..a5a44a2
--- /dev/null
+++ b/coordinatorlayout/api/current.txt
@@ -0,0 +1,97 @@
+package android.support.design.widget {
+
+  public class CoordinatorLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingParent2 {
+    ctor public CoordinatorLayout(android.content.Context);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void dispatchDependentViewsChanged(android.view.View);
+    method public boolean doViewsOverlap(android.view.View, android.view.View);
+    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateDefaultLayoutParams();
+    method public android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
+    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public java.util.List<android.view.View> getDependencies(android.view.View);
+    method public java.util.List<android.view.View> getDependents(android.view.View);
+    method public android.graphics.drawable.Drawable getStatusBarBackground();
+    method public boolean isPointInChildBounds(android.view.View, int, int);
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void onDraw(android.graphics.Canvas);
+    method public void onLayoutChild(android.view.View, int);
+    method public void onMeasureChild(android.view.View, int, int, int, int);
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackgroundColor(int);
+    method public void setStatusBarBackgroundResource(int);
+  }
+
+  public static abstract interface CoordinatorLayout.AttachedBehavior {
+    method public abstract android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+  }
+
+  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
+    ctor public CoordinatorLayout.Behavior();
+    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
+    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
+    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
+    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
+    method public static java.lang.Object getTag(android.view.View);
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
+    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDetachedFromLayoutParams();
+    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
+    method public deprecated void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[], int);
+    method public deprecated void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int, int);
+    method public deprecated void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
+    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
+    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
+    method public deprecated boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
+    method public deprecated void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int);
+    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public static void setTag(android.view.View, java.lang.Object);
+  }
+
+  public static abstract deprecated class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
+  }
+
+  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public CoordinatorLayout.LayoutParams(int, int);
+    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    method public int getAnchorId();
+    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+    method public void setAnchorId(int);
+    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
+    field public int anchorGravity;
+    field public int dodgeInsetEdges;
+    field public int gravity;
+    field public int insetEdge;
+    field public int keyline;
+  }
+
+  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
+  }
+
+}
+
diff --git a/coordinatorlayout/build.gradle b/coordinatorlayout/build.gradle
new file mode 100644
index 0000000..c6ce55b
--- /dev/null
+++ b/coordinatorlayout/build.gradle
@@ -0,0 +1,42 @@
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+    api(project(":customview"))
+
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation project(':support-testutils'), {
+        exclude group: 'com.android.support', module: 'support-core-ui'
+    }
+}
+
+android {
+    sourceSets {
+        main.res.srcDirs = [
+                'src/main/res',
+                'src/main/res-public'
+        ]
+    }
+    buildTypes.all {
+        consumerProguardFiles 'proguard-rules.pro'
+    }
+}
+
+supportLibrary {
+    name = "Android Support Library Coordinator Layout"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/core-ui/proguard-rules.pro b/coordinatorlayout/proguard-rules.pro
similarity index 100%
rename from core-ui/proguard-rules.pro
rename to coordinatorlayout/proguard-rules.pro
diff --git a/coordinatorlayout/src/androidTest/AndroidManifest.xml b/coordinatorlayout/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..ccf580d
--- /dev/null
+++ b/coordinatorlayout/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.coordinatorlayout.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <application
+        android:supportsRtl="true"
+        android:theme="@style/TestActivityTheme">
+
+        <activity android:name="android.support.design.widget.CoordinatorLayoutActivity"/>
+
+        <activity android:name="android.support.design.widget.DynamicCoordinatorLayoutActivity"/>
+
+    </application>
+
+</manifest>
diff --git a/core-ui/tests/java/android/support/design/custom/CustomBar.java b/coordinatorlayout/src/androidTest/java/android/support/design/custom/CustomBar.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/custom/CustomBar.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/custom/CustomBar.java
diff --git a/core-ui/tests/java/android/support/design/custom/CustomTextView.java b/coordinatorlayout/src/androidTest/java/android/support/design/custom/CustomTextView.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/custom/CustomTextView.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/custom/CustomTextView.java
diff --git a/core-ui/tests/java/android/support/design/custom/CustomTextView2.java b/coordinatorlayout/src/androidTest/java/android/support/design/custom/CustomTextView2.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/custom/CustomTextView2.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/custom/CustomTextView2.java
diff --git a/core-ui/tests/java/android/support/design/custom/TestFloatingBehavior.java b/coordinatorlayout/src/androidTest/java/android/support/design/custom/TestFloatingBehavior.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/custom/TestFloatingBehavior.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/custom/TestFloatingBehavior.java
diff --git a/core-ui/tests/java/android/support/design/testutils/CoordinatorLayoutUtils.java b/coordinatorlayout/src/androidTest/java/android/support/design/testutils/CoordinatorLayoutUtils.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/testutils/CoordinatorLayoutUtils.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/testutils/CoordinatorLayoutUtils.java
diff --git a/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java
new file mode 100755
index 0000000..f00d83b
--- /dev/null
+++ b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.design.widget;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.Matchers.any;
+
+import android.support.annotation.LayoutRes;
+import android.support.coordinatorlayout.test.R;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.v4.view.ViewCompat;
+import android.view.View;
+import android.view.ViewStub;
+
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.junit.After;
+
+/**
+ * Base class for tests that are exercising various aspects of {@link CoordinatorLayout}.
+ */
+public abstract class BaseDynamicCoordinatorLayoutTest
+        extends BaseInstrumentationTestCase<DynamicCoordinatorLayoutActivity> {
+    protected CoordinatorLayout mCoordinatorLayout;
+
+    public BaseDynamicCoordinatorLayoutTest() {
+        super(DynamicCoordinatorLayoutActivity.class);
+    }
+
+    @UiThreadTest
+    @After
+    public void tearDown() {
+        // Now that the test is done, replace the activity content view with ViewStub so
+        // that it's ready to be replaced for the next test.
+        final DynamicCoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
+        activity.setContentView(R.layout.dynamic_coordinator_layout);
+        mCoordinatorLayout = null;
+    }
+
+    /**
+     * Matches views that have parents.
+     */
+    private Matcher<View> hasParent() {
+        return new TypeSafeMatcher<View>() {
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("has parent");
+            }
+
+            @Override
+            public boolean matchesSafely(View view) {
+                return view.getParent() != null;
+            }
+        };
+    }
+
+    /**
+     * Inflates the <code>ViewStub</code> with the passed layout resource.
+     */
+    protected ViewAction inflateViewStub(final @LayoutRes int layoutResId) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return allOf(isAssignableFrom(ViewStub.class), hasParent());
+            }
+
+            @Override
+            public String getDescription() {
+                return "Inflates view stub";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                ViewStub viewStub = (ViewStub) view;
+                viewStub.setLayoutResource(layoutResId);
+                viewStub.inflate();
+
+                mCoordinatorLayout = (CoordinatorLayout) mActivityTestRule.getActivity()
+                        .findViewById(viewStub.getInflatedId());
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+
+    protected ViewAction setLayoutDirection(final int layoutDir) {
+        return new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return any(View.class);
+            }
+
+            @Override
+            public String getDescription() {
+                return "Sets layout direction";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                uiController.loopMainThreadUntilIdle();
+
+                ViewCompat.setLayoutDirection(view, layoutDir);
+
+                uiController.loopMainThreadUntilIdle();
+            }
+        };
+    }
+}
diff --git a/core-ui/tests/java/android/support/design/widget/BaseInstrumentationTestCase.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseInstrumentationTestCase.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/widget/BaseInstrumentationTestCase.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseInstrumentationTestCase.java
diff --git a/core-ui/tests/java/android/support/design/widget/BaseTestActivity.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/widget/BaseTestActivity.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
diff --git a/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutActivity.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutActivity.java
new file mode 100644
index 0000000..9fcc271
--- /dev/null
+++ b/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import android.support.coordinatorlayout.test.R;
+import android.support.v4.BaseTestActivity;
+import android.widget.FrameLayout;
+
+public class CoordinatorLayoutActivity extends BaseTestActivity {
+
+    FrameLayout mContainer;
+    CoordinatorLayout mCoordinatorLayout;
+
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.activity_coordinator_layout;
+    }
+
+    @Override
+    protected void onContentViewSet() {
+        mContainer = findViewById(R.id.container);
+        mCoordinatorLayout = findViewById(R.id.coordinator);
+    }
+
+}
diff --git a/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutSortTest.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutSortTest.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/widget/CoordinatorLayoutSortTest.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutSortTest.java
diff --git a/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutTest.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutTest.java
new file mode 100644
index 0000000..bbf46f9
--- /dev/null
+++ b/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorLayoutTest.java
@@ -0,0 +1,781 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.swipeUp;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.coordinatorlayout.test.R;
+import android.support.design.testutils.CoordinatorLayoutUtils;
+import android.support.design.testutils.CoordinatorLayoutUtils.DependentBehavior;
+import android.support.design.widget.CoordinatorLayout.Behavior;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.WindowInsetsCompat;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.widget.ImageView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CoordinatorLayoutTest {
+    @Rule
+    public final ActivityTestRule<CoordinatorLayoutActivity> mActivityTestRule;
+
+    private Instrumentation mInstrumentation;
+
+    public CoordinatorLayoutTest() {
+        mActivityTestRule = new ActivityTestRule<>(CoordinatorLayoutActivity.class);
+    }
+
+    @Before
+    public void setup() {
+        mInstrumentation = getInstrumentation();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 21)
+    public void testSetFitSystemWindows() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+        final View view = new View(col.getContext());
+
+        // Create a mock which calls the default impl of onApplyWindowInsets()
+        final CoordinatorLayout.Behavior<View> mockBehavior =
+                mock(CoordinatorLayout.Behavior.class);
+        doCallRealMethod().when(mockBehavior)
+                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
+
+        // Assert that the CoL is currently not set to fitSystemWindows
+        assertFalse(col.getFitsSystemWindows());
+
+        // Now add a view with our mocked behavior to the CoordinatorLayout
+        view.setFitsSystemWindows(true);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
+                lp.setBehavior(mockBehavior);
+                col.addView(view, lp);
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // Now request some insets and wait for the pass to happen
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.requestApplyInsets();
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // Verify that onApplyWindowInsets() has not been called
+        verify(mockBehavior, never())
+                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
+
+        // Now enable fits system windows and wait for a pass to happen
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.setFitsSystemWindows(true);
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // Verify that onApplyWindowInsets() has been called with some insets
+        verify(mockBehavior, atLeastOnce())
+                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
+    }
+
+    @Test
+    public void testLayoutChildren() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+        final View view = new View(col.getContext());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(view, 100, 100);
+            }
+        });
+        instrumentation.waitForIdleSync();
+        int horizontallyCentered = (col.getWidth() - view.getWidth()) / 2;
+        int end = col.getWidth() - view.getWidth();
+        int verticallyCentered = (col.getHeight() - view.getHeight()) / 2;
+        int bottom = col.getHeight() - view.getHeight();
+        final int[][] testCases = {
+                // gravity, expected left, expected top
+                {Gravity.NO_GRAVITY, 0, 0},
+                {Gravity.LEFT, 0, 0},
+                {GravityCompat.START, 0, 0},
+                {Gravity.TOP, 0, 0},
+                {Gravity.CENTER, horizontallyCentered, verticallyCentered},
+                {Gravity.CENTER_HORIZONTAL, horizontallyCentered, 0},
+                {Gravity.CENTER_VERTICAL, 0, verticallyCentered},
+                {Gravity.RIGHT, end, 0},
+                {GravityCompat.END, end, 0},
+                {Gravity.BOTTOM, 0, bottom},
+                {Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, horizontallyCentered, bottom},
+                {Gravity.RIGHT | Gravity.CENTER_VERTICAL, end, verticallyCentered},
+        };
+        for (final int[] testCase : testCases) {
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    final CoordinatorLayout.LayoutParams lp =
+                            (CoordinatorLayout.LayoutParams) view.getLayoutParams();
+                    lp.gravity = testCase[0];
+                    view.setLayoutParams(lp);
+                }
+            });
+            instrumentation.waitForIdleSync();
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    assertThat("Gravity: " + testCase[0], view.getLeft(), is(testCase[1]));
+                    assertThat("Gravity: " + testCase[0], view.getTop(), is(testCase[2]));
+                }
+            });
+        }
+    }
+
+    @Test
+    public void testInsetDependency() {
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        final CoordinatorLayout.LayoutParams lpInsetLeft = col.generateDefaultLayoutParams();
+        lpInsetLeft.insetEdge = Gravity.LEFT;
+
+        final CoordinatorLayout.LayoutParams lpInsetRight = col.generateDefaultLayoutParams();
+        lpInsetRight.insetEdge = Gravity.RIGHT;
+
+        final CoordinatorLayout.LayoutParams lpInsetTop = col.generateDefaultLayoutParams();
+        lpInsetTop.insetEdge = Gravity.TOP;
+
+        final CoordinatorLayout.LayoutParams lpInsetBottom = col.generateDefaultLayoutParams();
+        lpInsetBottom.insetEdge = Gravity.BOTTOM;
+
+        final CoordinatorLayout.LayoutParams lpDodgeLeft = col.generateDefaultLayoutParams();
+        lpDodgeLeft.dodgeInsetEdges = Gravity.LEFT;
+
+        final CoordinatorLayout.LayoutParams lpDodgeLeftAndTop = col.generateDefaultLayoutParams();
+        lpDodgeLeftAndTop.dodgeInsetEdges = Gravity.LEFT | Gravity.TOP;
+
+        final CoordinatorLayout.LayoutParams lpDodgeAll = col.generateDefaultLayoutParams();
+        lpDodgeAll.dodgeInsetEdges = Gravity.FILL;
+
+        final View a = new View(col.getContext());
+        final View b = new View(col.getContext());
+
+        assertThat(dependsOn(lpDodgeLeft, lpInsetLeft, col, a, b), is(true));
+        assertThat(dependsOn(lpDodgeLeft, lpInsetRight, col, a, b), is(false));
+        assertThat(dependsOn(lpDodgeLeft, lpInsetTop, col, a, b), is(false));
+        assertThat(dependsOn(lpDodgeLeft, lpInsetBottom, col, a, b), is(false));
+
+        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetLeft, col, a, b), is(true));
+        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetRight, col, a, b), is(false));
+        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetTop, col, a, b), is(true));
+        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetBottom, col, a, b), is(false));
+
+        assertThat(dependsOn(lpDodgeAll, lpInsetLeft, col, a, b), is(true));
+        assertThat(dependsOn(lpDodgeAll, lpInsetRight, col, a, b), is(true));
+        assertThat(dependsOn(lpDodgeAll, lpInsetTop, col, a, b), is(true));
+        assertThat(dependsOn(lpDodgeAll, lpInsetBottom, col, a, b), is(true));
+
+        assertThat(dependsOn(lpInsetLeft, lpDodgeLeft, col, a, b), is(false));
+    }
+
+    private static boolean dependsOn(CoordinatorLayout.LayoutParams lpChild,
+            CoordinatorLayout.LayoutParams lpDependency, CoordinatorLayout col,
+            View child, View dependency) {
+        child.setLayoutParams(lpChild);
+        dependency.setLayoutParams(lpDependency);
+        return lpChild.dependsOn(col, child, dependency);
+    }
+
+    @Test
+    public void testInsetEdge() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        final View insetView = new View(col.getContext());
+        final View dodgeInsetView = new View(col.getContext());
+        final AtomicInteger originalTop = new AtomicInteger();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                CoordinatorLayout.LayoutParams lpInsetView = col.generateDefaultLayoutParams();
+                lpInsetView.width = CoordinatorLayout.LayoutParams.MATCH_PARENT;
+                lpInsetView.height = 100;
+                lpInsetView.gravity = Gravity.TOP | Gravity.LEFT;
+                lpInsetView.insetEdge = Gravity.TOP;
+                col.addView(insetView, lpInsetView);
+                insetView.setBackgroundColor(0xFF0000FF);
+
+                CoordinatorLayout.LayoutParams lpDodgeInsetView = col.generateDefaultLayoutParams();
+                lpDodgeInsetView.width = 100;
+                lpDodgeInsetView.height = 100;
+                lpDodgeInsetView.gravity = Gravity.TOP | Gravity.LEFT;
+                lpDodgeInsetView.dodgeInsetEdges = Gravity.TOP;
+                col.addView(dodgeInsetView, lpDodgeInsetView);
+                dodgeInsetView.setBackgroundColor(0xFFFF0000);
+            }
+        });
+        instrumentation.waitForIdleSync();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                List<View> dependencies = col.getDependencies(dodgeInsetView);
+                assertThat(dependencies.size(), is(1));
+                assertThat(dependencies.get(0), is(insetView));
+
+                // Move the insetting view
+                originalTop.set(dodgeInsetView.getTop());
+                assertThat(originalTop.get(), is(insetView.getBottom()));
+                ViewCompat.offsetTopAndBottom(insetView, 123);
+            }
+        });
+        instrumentation.waitForIdleSync();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Confirm that the dodging view was moved by the same size
+                assertThat(dodgeInsetView.getTop() - originalTop.get(), is(123));
+            }
+        });
+    }
+
+    @Test
+    public void testDependentViewChanged() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        // Add two views, A & B, where B depends on A
+        final View viewA = new View(col.getContext());
+        final CoordinatorLayout.LayoutParams lpA = col.generateDefaultLayoutParams();
+        lpA.width = 100;
+        lpA.height = 100;
+
+        final View viewB = new View(col.getContext());
+        final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
+        lpB.width = 100;
+        lpB.height = 100;
+        final CoordinatorLayout.Behavior behavior =
+                spy(new DependentBehavior(viewA));
+        lpB.setBehavior(behavior);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(viewA, lpA);
+                col.addView(viewB, lpB);
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // Reset the Behavior since onDependentViewChanged may have already been called as part of
+        // any layout/draw passes already
+        reset(behavior);
+
+        // Now offset view A
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ViewCompat.offsetLeftAndRight(viewA, 20);
+                ViewCompat.offsetTopAndBottom(viewA, 20);
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // And assert that view B's Behavior was called appropriately
+        verify(behavior, times(1)).onDependentViewChanged(col, viewB, viewA);
+    }
+
+    @Test
+    public void testDependentViewRemoved() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        // Add two views, A & B, where B depends on A
+        final View viewA = new View(col.getContext());
+        final View viewB = new View(col.getContext());
+        final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
+        final CoordinatorLayout.Behavior behavior =
+                spy(new DependentBehavior(viewA));
+        lpB.setBehavior(behavior);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(viewA);
+                col.addView(viewB, lpB);
+            }
+        });
+        instrumentation.waitForIdleSync();
+
+        // Now remove view A
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.removeView(viewA);
+            }
+        });
+
+        // And assert that View B's Behavior was called appropriately
+        verify(behavior, times(1)).onDependentViewRemoved(col, viewB, viewA);
+    }
+
+    @Test
+    public void testGetDependenciesAfterDependentViewRemoved() throws Throwable {
+        final Instrumentation instrumentation = getInstrumentation();
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        // Add two views, A & B, where B depends on A
+        final View viewA = new View(col.getContext());
+        final View viewB = new View(col.getContext());
+        final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
+        final CoordinatorLayout.Behavior behavior =
+                new CoordinatorLayoutUtils.DependentBehavior(viewA) {
+                    @Override
+                    public void onDependentViewRemoved(
+                            CoordinatorLayout parent, View child, View dependency) {
+                        parent.getDependencies(child);
+                    }
+                };
+        lpB.setBehavior(behavior);
+
+        // Now add views
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(viewA);
+                col.addView(viewB, lpB);
+            }
+        });
+
+        // Wait for a layout
+        instrumentation.waitForIdleSync();
+
+        // Now remove view A, which will trigger onDependentViewRemoved() on view B's behavior
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.removeView(viewA);
+            }
+        });
+    }
+
+    @Test
+    public void testDodgeInsetBeforeLayout() throws Throwable {
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        // Add a dummy view, which will be used to trigger a hierarchy change.
+        final View dummy = new View(col.getContext());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(dummy);
+            }
+        });
+
+        // Wait for a layout.
+        mInstrumentation.waitForIdleSync();
+
+        final View dodge = new View(col.getContext());
+        final CoordinatorLayout.LayoutParams lpDodge = col.generateDefaultLayoutParams();
+        lpDodge.dodgeInsetEdges = Gravity.BOTTOM;
+        lpDodge.setBehavior(new Behavior() {
+            @Override
+            public boolean getInsetDodgeRect(CoordinatorLayout parent, View child, Rect rect) {
+                // Any non-empty rect is fine here.
+                rect.set(0, 0, 10, 10);
+                return true;
+            }
+        });
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(dodge, lpDodge);
+
+                // Ensure the new view is in the list of children.
+                int heightSpec = MeasureSpec.makeMeasureSpec(col.getHeight(), MeasureSpec.EXACTLY);
+                int widthSpec = MeasureSpec.makeMeasureSpec(col.getWidth(), MeasureSpec.EXACTLY);
+                col.measure(widthSpec, heightSpec);
+
+                // Force a hierarchy change.
+                col.removeView(dummy);
+            }
+        });
+
+        // Wait for a layout.
+        mInstrumentation.waitForIdleSync();
+    }
+
+    @Test
+    public void testGoneViewsNotMeasuredLaidOut() throws Throwable {
+        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
+        final CoordinatorLayout col = activity.mCoordinatorLayout;
+
+        // Now create a GONE view and add it to the CoordinatorLayout
+        final View imageView = new View(activity);
+        imageView.setVisibility(View.GONE);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                col.addView(imageView, 200, 200);
+            }
+        });
+        // Wait for a layout and measure pass
+        mInstrumentation.waitForIdleSync();
+
+        // And assert that it has not been laid out
+        assertFalse(imageView.getMeasuredWidth() > 0);
+        assertFalse(imageView.getMeasuredHeight() > 0);
+        assertFalse(ViewCompat.isLaidOut(imageView));
+
+        // Now set the view to INVISIBLE
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                imageView.setVisibility(View.INVISIBLE);
+            }
+        });
+        // Wait for a layout and measure pass
+        mInstrumentation.waitForIdleSync();
+
+        // And assert that it has been laid out
+        assertTrue(imageView.getMeasuredWidth() > 0);
+        assertTrue(imageView.getMeasuredHeight() > 0);
+        assertTrue(ViewCompat.isLaidOut(imageView));
+    }
+
+    @Test
+    public void testNestedScrollingDispatchesToBehavior() throws Throwable {
+        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
+        final CoordinatorLayout col = activity.mCoordinatorLayout;
+
+        // Now create a view and add it to the CoordinatorLayout with the spy behavior,
+        // along with a NestedScrollView
+        final ImageView imageView = new ImageView(activity);
+        final CoordinatorLayout.Behavior behavior = spy(new NestedScrollingBehavior());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                LayoutInflater.from(activity).inflate(R.layout.include_nestedscrollview, col, true);
+
+                CoordinatorLayout.LayoutParams clp = new CoordinatorLayout.LayoutParams(200, 200);
+                clp.setBehavior(behavior);
+                col.addView(imageView, clp);
+            }
+        });
+
+        // Now vertically swipe up on the NSV, causing nested scrolling to occur
+        onView(withId(R.id.nested_scrollview)).perform(swipeUp());
+
+        // Verify that the Behavior's onStartNestedScroll was called once
+        verify(behavior, times(1)).onStartNestedScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(View.class), // direct child target
+                any(int.class)); // axes
+
+        // Verify that the Behavior's onNestedScrollAccepted was called once
+        verify(behavior, times(1)).onNestedScrollAccepted(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(View.class), // direct child target
+                any(int.class)); // axes
+
+        // Verify that the Behavior's onNestedPreScroll was called at least once
+        verify(behavior, atLeastOnce()).onNestedPreScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(int.class), // dx
+                any(int.class), // dy
+                any(int[].class)); // consumed
+
+        // Verify that the Behavior's onNestedScroll was called at least once
+        verify(behavior, atLeastOnce()).onNestedScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(int.class), // dx consumed
+                any(int.class), // dy consumed
+                any(int.class), // dx unconsumed
+                any(int.class)); // dy unconsumed
+
+        // Verify that the Behavior's onStopNestedScroll was called once
+        verify(behavior, times(1)).onStopNestedScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class)); // target
+    }
+
+    @Test
+    public void testNestedScrollingDispatchingToBehaviorWithGoneView() throws Throwable {
+        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
+        final CoordinatorLayout col = activity.mCoordinatorLayout;
+
+        // Now create a GONE view and add it to the CoordinatorLayout with the spy behavior,
+        // along with a NestedScrollView
+        final ImageView imageView = new ImageView(activity);
+        imageView.setVisibility(View.GONE);
+        final CoordinatorLayout.Behavior behavior = spy(new NestedScrollingBehavior());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                LayoutInflater.from(activity).inflate(R.layout.include_nestedscrollview, col, true);
+
+                CoordinatorLayout.LayoutParams clp = new CoordinatorLayout.LayoutParams(200, 200);
+                clp.setBehavior(behavior);
+                col.addView(imageView, clp);
+            }
+        });
+
+        // Now vertically swipe up on the NSV, causing nested scrolling to occur
+        onView(withId(R.id.nested_scrollview)).perform(swipeUp());
+
+        // Verify that the Behavior's onStartNestedScroll was not called
+        verify(behavior, never()).onStartNestedScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(View.class), // direct child target
+                any(int.class)); // axes
+
+        // Verify that the Behavior's onNestedScrollAccepted was not called
+        verify(behavior, never()).onNestedScrollAccepted(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(View.class), // direct child target
+                any(int.class)); // axes
+
+        // Verify that the Behavior's onNestedPreScroll was not called
+        verify(behavior, never()).onNestedPreScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(int.class), // dx
+                any(int.class), // dy
+                any(int[].class)); // consumed
+
+        // Verify that the Behavior's onNestedScroll was not called
+        verify(behavior, never()).onNestedScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class), // target
+                any(int.class), // dx consumed
+                any(int.class), // dy consumed
+                any(int.class), // dx unconsumed
+                any(int.class)); // dy unconsumed
+
+        // Verify that the Behavior's onStopNestedScroll was not called
+        verify(behavior, never()).onStopNestedScroll(
+                eq(col), // parent
+                eq(imageView), // child
+                any(View.class)); // target
+    }
+
+    @Test
+    public void testNestedScrollingTriggeringDependentViewChanged() throws Throwable {
+        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
+        final CoordinatorLayout col = activity.mCoordinatorLayout;
+
+        // First a NestedScrollView to trigger nested scrolling
+        final View scrollView = LayoutInflater.from(activity).inflate(
+                R.layout.include_nestedscrollview, col, false);
+
+        // Now create a View and Behavior which depend on the scrollview
+        final ImageView dependentView = new ImageView(activity);
+        final CoordinatorLayout.Behavior dependentBehavior = spy(new DependentBehavior(scrollView));
+
+        // Finally a view which accepts nested scrolling in the CoordinatorLayout
+        final ImageView nestedScrollAwareView = new ImageView(activity);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // First add the ScrollView
+                col.addView(scrollView);
+
+                // Now add the view which depends on the scrollview
+                CoordinatorLayout.LayoutParams clp = new CoordinatorLayout.LayoutParams(200, 200);
+                clp.setBehavior(dependentBehavior);
+                col.addView(dependentView, clp);
+
+                // Now add the nested scrolling aware view
+                clp = new CoordinatorLayout.LayoutParams(200, 200);
+                clp.setBehavior(new NestedScrollingBehavior());
+                col.addView(nestedScrollAwareView, clp);
+            }
+        });
+
+        // Wait for any layouts, and reset the Behavior so that the call counts are 0
+        getInstrumentation().waitForIdleSync();
+        reset(dependentBehavior);
+
+        // Now vertically swipe up on the NSV, causing nested scrolling to occur
+        onView(withId(R.id.nested_scrollview)).perform(swipeUp());
+
+        // Verify that the Behavior's onDependentViewChanged is not called due to the
+        // nested scroll
+        verify(dependentBehavior, never()).onDependentViewChanged(
+                eq(col), // parent
+                eq(dependentView), // child
+                eq(scrollView)); // axes
+    }
+
+    @Test
+    public void testDodgeInsetViewWithEmptyBounds() throws Throwable {
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        // Add a view with zero height/width which is set to dodge its bounds
+        final View view = new View(col.getContext());
+        final Behavior spyBehavior = spy(new DodgeBoundsBehavior());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
+                lp.dodgeInsetEdges = Gravity.BOTTOM;
+                lp.gravity = Gravity.BOTTOM;
+                lp.height = 0;
+                lp.width = 0;
+                lp.setBehavior(spyBehavior);
+                col.addView(view, lp);
+            }
+        });
+
+        // Wait for a layout
+        mInstrumentation.waitForIdleSync();
+
+        // Now add an non-empty bounds inset view to the bottom of the CoordinatorLayout
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final View dodge = new View(col.getContext());
+                final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
+                lp.insetEdge = Gravity.BOTTOM;
+                lp.gravity = Gravity.BOTTOM;
+                lp.height = 60;
+                lp.width = CoordinatorLayout.LayoutParams.MATCH_PARENT;
+                col.addView(dodge, lp);
+            }
+        });
+
+        // Verify that the Behavior of the view with empty bounds does not have its
+        // getInsetDodgeRect() called
+        verify(spyBehavior, never())
+                .getInsetDodgeRect(same(col), same(view), any(Rect.class));
+    }
+
+    public static class NestedScrollingBehavior extends CoordinatorLayout.Behavior<View> {
+        @Override
+        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child,
+                View directTargetChild, View target, int nestedScrollAxes) {
+            // Return true so that we always accept nested scroll events
+            return true;
+        }
+    }
+
+    public static class DodgeBoundsBehavior extends Behavior<View> {
+        @Override
+        public boolean getInsetDodgeRect(CoordinatorLayout parent, View child, Rect rect) {
+            rect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
+            return true;
+        }
+    }
+
+    @UiThreadTest
+    @Test
+    public void testAnchorDependencyGraph() throws Throwable {
+        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
+
+        // Override hashcode because of implementation of SimpleArrayMap used in
+        // DirectedAcyclicGraph used for sorting dependencies. Hashcode of anchored view has to be
+        // greater than of the one it is anchored to in order to reproduce the error.
+        final View anchor = createViewWithHashCode(col.getContext(), 2);
+        anchor.setId(R.id.anchor);
+
+        final View ship = createViewWithHashCode(col.getContext(), 3);
+        final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
+        lp.setAnchorId(R.id.anchor);
+
+        col.addView(anchor);
+        col.addView(ship, lp);
+
+        // Get dependencies immediately to avoid possible call to onMeasure(), since error
+        // only happens on first computing of sorted dependencies.
+        List<View> dependencySortedChildren = col.getDependencySortedChildren();
+        assertThat(dependencySortedChildren, is(Arrays.asList(anchor, ship)));
+    }
+
+    @NonNull
+    private View createViewWithHashCode(final Context context, final int hashCode) {
+        return new View(context) {
+            @Override
+            public int hashCode() {
+                return hashCode;
+            }
+        };
+    }
+}
diff --git a/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorSnackbarWithButtonTest.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorSnackbarWithButtonTest.java
new file mode 100644
index 0000000..f9f7694
--- /dev/null
+++ b/coordinatorlayout/src/androidTest/java/android/support/design/widget/CoordinatorSnackbarWithButtonTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.support.coordinatorlayout.test.R;
+import android.support.design.custom.CustomBar;
+import android.support.design.custom.TestFloatingBehavior;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.filters.MediumTest;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.TextView;
+
+import org.hamcrest.Matcher;
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+public class CoordinatorSnackbarWithButtonTest extends BaseDynamicCoordinatorLayoutTest {
+    private View mBar;
+
+    @After
+    @UiThreadTest
+    public void teardown() throws Throwable {
+        mCoordinatorLayout.removeView(mBar);
+    }
+
+    /**
+     * Returns the location of our bar on the screen.
+     */
+    private static int[] getBarLocationOnScreen() {
+        final int[] location = new int[2];
+        onView(isAssignableFrom(CustomBar.class)).perform(new ViewAction() {
+            @Override
+            public Matcher<View> getConstraints() {
+                return isEnabled();
+            }
+
+            @Override
+            public String getDescription() {
+                return "Bar matcher";
+            }
+
+            @Override
+            public void perform(UiController uiController, View view) {
+                view.getLocationOnScreen(location);
+            }
+        });
+        return location;
+    }
+
+    /**
+     * Helper method that verifies that the passed view is above the bar in the activity
+     * window.
+     */
+    private static void verifyBarViewStacking(View view, int extraBottomMargin) {
+        // Get location of bar in window
+        final int[] barOnScreenXY = getBarLocationOnScreen();
+        // Get location of passed view in window
+        final int[] viewOnScreenXY = new int[2];
+        view.getLocationOnScreen(viewOnScreenXY);
+
+        // Compute the bottom visible edge of the view
+        int viewBottom = viewOnScreenXY[1] + view.getHeight() - extraBottomMargin;
+        int barTop = barOnScreenXY[1];
+        // and verify that our view is above the bar
+        assertTrue(viewBottom <= barTop);
+    }
+
+    private void addBar() {
+        final CountDownLatch latch = new CountDownLatch(1);
+        new Handler(Looper.getMainLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
+                mBar = inflater.inflate(R.layout.emulated_snackbar, mCoordinatorLayout, false);
+                mCoordinatorLayout.addView(mBar);
+                latch.countDown();
+            }
+        });
+        try {
+            assertTrue("Could not add emulated snackbar", latch.await(5, TimeUnit.SECONDS));
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
+    }
+
+    @Test
+    public void testBehaviorBasedSlidingFromLayoutAttribute() {
+        // Use a layout in which a TextView child has Behavior object configured via
+        // layout_behavior XML attribute
+        onView(withId(R.id.coordinator_stub)).perform(
+                inflateViewStub(R.layout.design_snackbar_behavior_layout_attr));
+
+        // Create and show the bar
+        addBar();
+
+        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
+        verifyBarViewStacking(textView, 0);
+    }
+
+    @Test
+    public void testBehaviorBasedSlidingFromClassAnnotation() {
+        // Use a layout in which a custom child view has Behavior object configured via
+        // annotation on the class that extends TextView
+        onView(withId(R.id.coordinator_stub)).perform(
+                inflateViewStub(R.layout.design_snackbar_behavior_annotation));
+
+        // Create and show the bar
+        addBar();
+
+        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
+        verifyBarViewStacking(textView, 0);
+    }
+
+    @Test
+    public void testBehaviorBasedSlidingFromClassInterface() {
+        // Use a layout in which a custom child view has Behavior object configured via
+        // the interface on the class that extends TextView
+        onView(withId(R.id.coordinator_stub)).perform(
+                inflateViewStub(R.layout.design_snackbar_behavior_interface));
+
+        // Create and show the bar
+        addBar();
+
+        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
+        verifyBarViewStacking(textView, 0);
+    }
+
+    @Test
+    public void testBehaviorBasedSlidingFromRuntimeApiCall() {
+        // Use a layout in which a TextView child doesn't have any configured Behavior
+        onView(withId(R.id.coordinator_stub)).perform(
+                inflateViewStub(R.layout.design_snackbar_behavior_runtime));
+
+        // and configure that Behavior at runtime by setting it on its LayoutParams
+        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
+        final CoordinatorLayout.LayoutParams textViewLp =
+                (CoordinatorLayout.LayoutParams) textView.getLayoutParams();
+        textViewLp.setBehavior(new TestFloatingBehavior());
+
+        // Create and show the bar
+        addBar();
+
+        verifyBarViewStacking(textView, 0);
+    }
+}
diff --git a/core-ui/tests/java/android/support/design/widget/DesignViewActions.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/DesignViewActions.java
similarity index 100%
rename from core-ui/tests/java/android/support/design/widget/DesignViewActions.java
rename to coordinatorlayout/src/androidTest/java/android/support/design/widget/DesignViewActions.java
diff --git a/coordinatorlayout/src/androidTest/java/android/support/design/widget/DynamicCoordinatorLayoutActivity.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/DynamicCoordinatorLayoutActivity.java
new file mode 100644
index 0000000..e6f7935
--- /dev/null
+++ b/coordinatorlayout/src/androidTest/java/android/support/design/widget/DynamicCoordinatorLayoutActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import android.support.coordinatorlayout.test.R;
+
+/**
+ * Test activity for testing various aspects of {@link CoordinatorLayout}.
+ */
+public class DynamicCoordinatorLayoutActivity extends BaseTestActivity {
+    @Override
+    protected int getContentViewLayoutResId() {
+        return R.layout.dynamic_coordinator_layout;
+    }
+}
diff --git a/compat/tests/java/android/support/v4/BaseTestActivity.java b/coordinatorlayout/src/androidTest/java/android/support/v4/BaseTestActivity.java
similarity index 100%
copy from compat/tests/java/android/support/v4/BaseTestActivity.java
copy to coordinatorlayout/src/androidTest/java/android/support/v4/BaseTestActivity.java
diff --git a/core-ui/tests/java/android/support/v4/widget/DirectedAcyclicGraphTest.java b/coordinatorlayout/src/androidTest/java/android/support/v4/widget/DirectedAcyclicGraphTest.java
similarity index 100%
rename from core-ui/tests/java/android/support/v4/widget/DirectedAcyclicGraphTest.java
rename to coordinatorlayout/src/androidTest/java/android/support/v4/widget/DirectedAcyclicGraphTest.java
diff --git a/core-ui/tests/res/layout/activity_coordinator_layout.xml b/coordinatorlayout/src/androidTest/res/layout/activity_coordinator_layout.xml
similarity index 100%
rename from core-ui/tests/res/layout/activity_coordinator_layout.xml
rename to coordinatorlayout/src/androidTest/res/layout/activity_coordinator_layout.xml
diff --git a/core-ui/tests/res/layout/design_snackbar_behavior_annotation.xml b/coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_annotation.xml
similarity index 100%
rename from core-ui/tests/res/layout/design_snackbar_behavior_annotation.xml
rename to coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_annotation.xml
diff --git a/core-ui/tests/res/layout/design_snackbar_behavior_interface.xml b/coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_interface.xml
similarity index 100%
rename from core-ui/tests/res/layout/design_snackbar_behavior_interface.xml
rename to coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_interface.xml
diff --git a/core-ui/tests/res/layout/design_snackbar_behavior_layout_attr.xml b/coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_layout_attr.xml
similarity index 100%
rename from core-ui/tests/res/layout/design_snackbar_behavior_layout_attr.xml
rename to coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_layout_attr.xml
diff --git a/core-ui/tests/res/layout/design_snackbar_behavior_runtime.xml b/coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_runtime.xml
similarity index 100%
rename from core-ui/tests/res/layout/design_snackbar_behavior_runtime.xml
rename to coordinatorlayout/src/androidTest/res/layout/design_snackbar_behavior_runtime.xml
diff --git a/core-ui/tests/res/layout/dynamic_coordinator_layout.xml b/coordinatorlayout/src/androidTest/res/layout/dynamic_coordinator_layout.xml
similarity index 100%
rename from core-ui/tests/res/layout/dynamic_coordinator_layout.xml
rename to coordinatorlayout/src/androidTest/res/layout/dynamic_coordinator_layout.xml
diff --git a/core-ui/tests/res/layout/emulated_snackbar.xml b/coordinatorlayout/src/androidTest/res/layout/emulated_snackbar.xml
similarity index 100%
rename from core-ui/tests/res/layout/emulated_snackbar.xml
rename to coordinatorlayout/src/androidTest/res/layout/emulated_snackbar.xml
diff --git a/core-ui/tests/res/layout/include_nestedscrollview.xml b/coordinatorlayout/src/androidTest/res/layout/include_nestedscrollview.xml
similarity index 100%
rename from core-ui/tests/res/layout/include_nestedscrollview.xml
rename to coordinatorlayout/src/androidTest/res/layout/include_nestedscrollview.xml
diff --git a/coordinatorlayout/src/androidTest/res/values/ids.xml b/coordinatorlayout/src/androidTest/res/values/ids.xml
new file mode 100644
index 0000000..b34ad80
--- /dev/null
+++ b/coordinatorlayout/src/androidTest/res/values/ids.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <item name="anchor" type="id"/>
+</resources>
\ No newline at end of file
diff --git a/core-ui/tests/res/values/styles.xml b/coordinatorlayout/src/androidTest/res/values/styles.xml
similarity index 100%
copy from core-ui/tests/res/values/styles.xml
copy to coordinatorlayout/src/androidTest/res/values/styles.xml
diff --git a/coordinatorlayout/src/main/AndroidManifest.xml b/coordinatorlayout/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bbad509
--- /dev/null
+++ b/coordinatorlayout/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.coordinatorlayout" />
diff --git a/coordinatorlayout/src/main/java/android/support/design/widget/CoordinatorLayout.java b/coordinatorlayout/src/main/java/android/support/design/widget/CoordinatorLayout.java
new file mode 100644
index 0000000..91d3fa4
--- /dev/null
+++ b/coordinatorlayout/src/main/java/android/support/design/widget/CoordinatorLayout.java
@@ -0,0 +1,3293 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.design.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IdRes;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.coordinatorlayout.R;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.util.ObjectsCompat;
+import android.support.v4.util.Pools;
+import android.support.v4.view.AbsSavedState;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.view.NestedScrollingParent;
+import android.support.v4.view.NestedScrollingParent2;
+import android.support.v4.view.NestedScrollingParentHelper;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.ViewCompat.NestedScrollType;
+import android.support.v4.view.ViewCompat.ScrollAxis;
+import android.support.v4.view.WindowInsetsCompat;
+import android.support.v4.widget.DirectedAcyclicGraph;
+import android.support.v4.widget.ViewGroupUtils;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * CoordinatorLayout is a super-powered {@link android.widget.FrameLayout FrameLayout}.
+ *
+ * <p>CoordinatorLayout is intended for two primary use cases:</p>
+ * <ol>
+ *     <li>As a top-level application decor or chrome layout</li>
+ *     <li>As a container for a specific interaction with one or more child views</li>
+ * </ol>
+ *
+ * <p>By specifying {@link Behavior Behaviors} for child views of a
+ * CoordinatorLayout you can provide many different interactions within a single parent and those
+ * views can also interact with one another. View classes can specify a default behavior when
+ * used as a child of a CoordinatorLayout using the
+ * {@link DefaultBehavior} annotation.</p>
+ *
+ * <p>Behaviors may be used to implement a variety of interactions and additional layout
+ * modifications ranging from sliding drawers and panels to swipe-dismissable elements and buttons
+ * that stick to other elements as they move and animate.</p>
+ *
+ * <p>Children of a CoordinatorLayout may have an
+ * {@link LayoutParams#setAnchorId(int) anchor}. This view id must correspond
+ * to an arbitrary descendant of the CoordinatorLayout, but it may not be the anchored child itself
+ * or a descendant of the anchored child. This can be used to place floating views relative to
+ * other arbitrary content panes.</p>
+ *
+ * <p>Children can specify {@link LayoutParams#insetEdge} to describe how the
+ * view insets the CoordinatorLayout. Any child views which are set to dodge the same inset edges by
+ * {@link LayoutParams#dodgeInsetEdges} will be moved appropriately so that the
+ * views do not overlap.</p>
+ */
+public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent2 {
+    static final String TAG = "CoordinatorLayout";
+    static final String WIDGET_PACKAGE_NAME;
+
+    static {
+        final Package pkg = CoordinatorLayout.class.getPackage();
+        WIDGET_PACKAGE_NAME = pkg != null ? pkg.getName() : null;
+    }
+
+    private static final int TYPE_ON_INTERCEPT = 0;
+    private static final int TYPE_ON_TOUCH = 1;
+
+    static {
+        if (Build.VERSION.SDK_INT >= 21) {
+            TOP_SORTED_CHILDREN_COMPARATOR = new ViewElevationComparator();
+        } else {
+            TOP_SORTED_CHILDREN_COMPARATOR = null;
+        }
+    }
+
+    static final Class<?>[] CONSTRUCTOR_PARAMS = new Class<?>[] {
+            Context.class,
+            AttributeSet.class
+    };
+
+    static final ThreadLocal<Map<String, Constructor<Behavior>>> sConstructors =
+            new ThreadLocal<>();
+
+    static final int EVENT_PRE_DRAW = 0;
+    static final int EVENT_NESTED_SCROLL = 1;
+    static final int EVENT_VIEW_REMOVED = 2;
+
+    /** @hide */
+    @RestrictTo(LIBRARY_GROUP)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({EVENT_PRE_DRAW, EVENT_NESTED_SCROLL, EVENT_VIEW_REMOVED})
+    public @interface DispatchChangeEvent {}
+
+    static final Comparator<View> TOP_SORTED_CHILDREN_COMPARATOR;
+    private static final Pools.Pool<Rect> sRectPool = new Pools.SynchronizedPool<>(12);
+
+    @NonNull
+    private static Rect acquireTempRect() {
+        Rect rect = sRectPool.acquire();
+        if (rect == null) {
+            rect = new Rect();
+        }
+        return rect;
+    }
+
+    private static void releaseTempRect(@NonNull Rect rect) {
+        rect.setEmpty();
+        sRectPool.release(rect);
+    }
+
+    private final List<View> mDependencySortedChildren = new ArrayList<>();
+    private final DirectedAcyclicGraph<View> mChildDag = new DirectedAcyclicGraph<>();
+
+    private final List<View> mTempList1 = new ArrayList<>();
+    private final List<View> mTempDependenciesList = new ArrayList<>();
+    private final int[] mTempIntPair = new int[2];
+    private Paint mScrimPaint;
+
+    private boolean mDisallowInterceptReset;
+
+    private boolean mIsAttachedToWindow;
+
+    private int[] mKeylines;
+
+    private View mBehaviorTouchView;
+    private View mNestedScrollingTarget;
+
+    private OnPreDrawListener mOnPreDrawListener;
+    private boolean mNeedsPreDrawListener;
+
+    private WindowInsetsCompat mLastInsets;
+    private boolean mDrawStatusBarBackground;
+    private Drawable mStatusBarBackground;
+
+    OnHierarchyChangeListener mOnHierarchyChangeListener;
+    private android.support.v4.view.OnApplyWindowInsetsListener mApplyWindowInsetsListener;
+
+    private final NestedScrollingParentHelper mNestedScrollingParentHelper =
+            new NestedScrollingParentHelper(this);
+
+    public CoordinatorLayout(Context context) {
+        this(context, null);
+    }
+
+    public CoordinatorLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.coordinatorLayoutStyle);
+    }
+
+    public CoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final TypedArray a = (defStyleAttr == 0)
+                ? context.obtainStyledAttributes(attrs, R.styleable.CoordinatorLayout,
+                    0, R.style.Widget_Support_CoordinatorLayout)
+                : context.obtainStyledAttributes(attrs, R.styleable.CoordinatorLayout,
+                    defStyleAttr, 0);
+        final int keylineArrayRes = a.getResourceId(R.styleable.CoordinatorLayout_keylines, 0);
+        if (keylineArrayRes != 0) {
+            final Resources res = context.getResources();
+            mKeylines = res.getIntArray(keylineArrayRes);
+            final float density = res.getDisplayMetrics().density;
+            final int count = mKeylines.length;
+            for (int i = 0; i < count; i++) {
+                mKeylines[i] = (int) (mKeylines[i] * density);
+            }
+        }
+        mStatusBarBackground = a.getDrawable(R.styleable.CoordinatorLayout_statusBarBackground);
+        a.recycle();
+
+        setupForInsets();
+        super.setOnHierarchyChangeListener(new HierarchyChangeListener());
+    }
+
+    @Override
+    public void setOnHierarchyChangeListener(OnHierarchyChangeListener onHierarchyChangeListener) {
+        mOnHierarchyChangeListener = onHierarchyChangeListener;
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        resetTouchBehaviors(false);
+        if (mNeedsPreDrawListener) {
+            if (mOnPreDrawListener == null) {
+                mOnPreDrawListener = new OnPreDrawListener();
+            }
+            final ViewTreeObserver vto = getViewTreeObserver();
+            vto.addOnPreDrawListener(mOnPreDrawListener);
+        }
+        if (mLastInsets == null && ViewCompat.getFitsSystemWindows(this)) {
+            // We're set to fitSystemWindows but we haven't had any insets yet...
+            // We should request a new dispatch of window insets
+            ViewCompat.requestApplyInsets(this);
+        }
+        mIsAttachedToWindow = true;
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        resetTouchBehaviors(false);
+        if (mNeedsPreDrawListener && mOnPreDrawListener != null) {
+            final ViewTreeObserver vto = getViewTreeObserver();
+            vto.removeOnPreDrawListener(mOnPreDrawListener);
+        }
+        if (mNestedScrollingTarget != null) {
+            onStopNestedScroll(mNestedScrollingTarget);
+        }
+        mIsAttachedToWindow = false;
+    }
+
+    /**
+     * Set a drawable to draw in the insets area for the status bar.
+     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
+     *
+     * @param bg Background drawable to draw behind the status bar
+     */
+    public void setStatusBarBackground(@Nullable final Drawable bg) {
+        if (mStatusBarBackground != bg) {
+            if (mStatusBarBackground != null) {
+                mStatusBarBackground.setCallback(null);
+            }
+            mStatusBarBackground = bg != null ? bg.mutate() : null;
+            if (mStatusBarBackground != null) {
+                if (mStatusBarBackground.isStateful()) {
+                    mStatusBarBackground.setState(getDrawableState());
+                }
+                DrawableCompat.setLayoutDirection(mStatusBarBackground,
+                        ViewCompat.getLayoutDirection(this));
+                mStatusBarBackground.setVisible(getVisibility() == VISIBLE, false);
+                mStatusBarBackground.setCallback(this);
+            }
+            ViewCompat.postInvalidateOnAnimation(this);
+        }
+    }
+
+    /**
+     * Gets the drawable used to draw in the insets area for the status bar.
+     *
+     * @return The status bar background drawable, or null if none set
+     */
+    @Nullable
+    public Drawable getStatusBarBackground() {
+        return mStatusBarBackground;
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+
+        final int[] state = getDrawableState();
+        boolean changed = false;
+
+        Drawable d = mStatusBarBackground;
+        if (d != null && d.isStateful()) {
+            changed |= d.setState(state);
+        }
+
+        if (changed) {
+            invalidate();
+        }
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return super.verifyDrawable(who) || who == mStatusBarBackground;
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+
+        final boolean visible = visibility == VISIBLE;
+        if (mStatusBarBackground != null && mStatusBarBackground.isVisible() != visible) {
+            mStatusBarBackground.setVisible(visible, false);
+        }
+    }
+
+    /**
+     * Set a drawable to draw in the insets area for the status bar.
+     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
+     *
+     * @param resId Resource id of a background drawable to draw behind the status bar
+     */
+    public void setStatusBarBackgroundResource(@DrawableRes int resId) {
+        setStatusBarBackground(resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null);
+    }
+
+    /**
+     * Set a drawable to draw in the insets area for the status bar.
+     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
+     *
+     * @param color Color to use as a background drawable to draw behind the status bar
+     *              in 0xAARRGGBB format.
+     */
+    public void setStatusBarBackgroundColor(@ColorInt int color) {
+        setStatusBarBackground(new ColorDrawable(color));
+    }
+
+    final WindowInsetsCompat setWindowInsets(WindowInsetsCompat insets) {
+        if (!ObjectsCompat.equals(mLastInsets, insets)) {
+            mLastInsets = insets;
+            mDrawStatusBarBackground = insets != null && insets.getSystemWindowInsetTop() > 0;
+            setWillNotDraw(!mDrawStatusBarBackground && getBackground() == null);
+
+            // Now dispatch to the Behaviors
+            insets = dispatchApplyWindowInsetsToBehaviors(insets);
+            requestLayout();
+        }
+        return insets;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public final WindowInsetsCompat getLastWindowInsets() {
+        return mLastInsets;
+    }
+
+    /**
+     * Reset all Behavior-related tracking records either to clean up or in preparation
+     * for a new event stream. This should be called when attached or detached from a window,
+     * in response to an UP or CANCEL event, when intercept is request-disallowed
+     * and similar cases where an event stream in progress will be aborted.
+     */
+    private void resetTouchBehaviors(boolean notifyOnInterceptTouchEvent) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final Behavior b = lp.getBehavior();
+            if (b != null) {
+                final long now = SystemClock.uptimeMillis();
+                final MotionEvent cancelEvent = MotionEvent.obtain(now, now,
+                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+                if (notifyOnInterceptTouchEvent) {
+                    b.onInterceptTouchEvent(this, child, cancelEvent);
+                } else {
+                    b.onTouchEvent(this, child, cancelEvent);
+                }
+                cancelEvent.recycle();
+            }
+        }
+
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            lp.resetTouchBehaviorTracking();
+        }
+        mBehaviorTouchView = null;
+        mDisallowInterceptReset = false;
+    }
+
+    /**
+     * Populate a list with the current child views, sorted such that the topmost views
+     * in z-order are at the front of the list. Useful for hit testing and event dispatch.
+     */
+    private void getTopSortedChildren(List<View> out) {
+        out.clear();
+
+        final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
+        final int childCount = getChildCount();
+        for (int i = childCount - 1; i >= 0; i--) {
+            final int childIndex = useCustomOrder ? getChildDrawingOrder(childCount, i) : i;
+            final View child = getChildAt(childIndex);
+            out.add(child);
+        }
+
+        if (TOP_SORTED_CHILDREN_COMPARATOR != null) {
+            Collections.sort(out, TOP_SORTED_CHILDREN_COMPARATOR);
+        }
+    }
+
+    private boolean performIntercept(MotionEvent ev, final int type) {
+        boolean intercepted = false;
+        boolean newBlock = false;
+
+        MotionEvent cancelEvent = null;
+
+        final int action = ev.getActionMasked();
+
+        final List<View> topmostChildList = mTempList1;
+        getTopSortedChildren(topmostChildList);
+
+        // Let topmost child views inspect first
+        final int childCount = topmostChildList.size();
+        for (int i = 0; i < childCount; i++) {
+            final View child = topmostChildList.get(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final Behavior b = lp.getBehavior();
+
+            if ((intercepted || newBlock) && action != MotionEvent.ACTION_DOWN) {
+                // Cancel all behaviors beneath the one that intercepted.
+                // If the event is "down" then we don't have anything to cancel yet.
+                if (b != null) {
+                    if (cancelEvent == null) {
+                        final long now = SystemClock.uptimeMillis();
+                        cancelEvent = MotionEvent.obtain(now, now,
+                                MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+                    }
+                    switch (type) {
+                        case TYPE_ON_INTERCEPT:
+                            b.onInterceptTouchEvent(this, child, cancelEvent);
+                            break;
+                        case TYPE_ON_TOUCH:
+                            b.onTouchEvent(this, child, cancelEvent);
+                            break;
+                    }
+                }
+                continue;
+            }
+
+            if (!intercepted && b != null) {
+                switch (type) {
+                    case TYPE_ON_INTERCEPT:
+                        intercepted = b.onInterceptTouchEvent(this, child, ev);
+                        break;
+                    case TYPE_ON_TOUCH:
+                        intercepted = b.onTouchEvent(this, child, ev);
+                        break;
+                }
+                if (intercepted) {
+                    mBehaviorTouchView = child;
+                }
+            }
+
+            // Don't keep going if we're not allowing interaction below this.
+            // Setting newBlock will make sure we cancel the rest of the behaviors.
+            final boolean wasBlocking = lp.didBlockInteraction();
+            final boolean isBlocking = lp.isBlockingInteractionBelow(this, child);
+            newBlock = isBlocking && !wasBlocking;
+            if (isBlocking && !newBlock) {
+                // Stop here since we don't have anything more to cancel - we already did
+                // when the behavior first started blocking things below this point.
+                break;
+            }
+        }
+
+        topmostChildList.clear();
+
+        return intercepted;
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        MotionEvent cancelEvent = null;
+
+        final int action = ev.getActionMasked();
+
+        // Make sure we reset in case we had missed a previous important event.
+        if (action == MotionEvent.ACTION_DOWN) {
+            resetTouchBehaviors(true);
+        }
+
+        final boolean intercepted = performIntercept(ev, TYPE_ON_INTERCEPT);
+
+        if (cancelEvent != null) {
+            cancelEvent.recycle();
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            resetTouchBehaviors(true);
+        }
+
+        return intercepted;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        boolean handled = false;
+        boolean cancelSuper = false;
+        MotionEvent cancelEvent = null;
+
+        final int action = ev.getActionMasked();
+
+        if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev, TYPE_ON_TOUCH))) {
+            // Safe since performIntercept guarantees that
+            // mBehaviorTouchView != null if it returns true
+            final LayoutParams lp = (LayoutParams) mBehaviorTouchView.getLayoutParams();
+            final Behavior b = lp.getBehavior();
+            if (b != null) {
+                handled = b.onTouchEvent(this, mBehaviorTouchView, ev);
+            }
+        }
+
+        // Keep the super implementation correct
+        if (mBehaviorTouchView == null) {
+            handled |= super.onTouchEvent(ev);
+        } else if (cancelSuper) {
+            if (cancelEvent == null) {
+                final long now = SystemClock.uptimeMillis();
+                cancelEvent = MotionEvent.obtain(now, now,
+                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+            }
+            super.onTouchEvent(cancelEvent);
+        }
+
+        if (!handled && action == MotionEvent.ACTION_DOWN) {
+
+        }
+
+        if (cancelEvent != null) {
+            cancelEvent.recycle();
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            resetTouchBehaviors(false);
+        }
+
+        return handled;
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        if (disallowIntercept && !mDisallowInterceptReset) {
+            resetTouchBehaviors(false);
+            mDisallowInterceptReset = true;
+        }
+    }
+
+    private int getKeyline(int index) {
+        if (mKeylines == null) {
+            Log.e(TAG, "No keylines defined for " + this + " - attempted index lookup " + index);
+            return 0;
+        }
+
+        if (index < 0 || index >= mKeylines.length) {
+            Log.e(TAG, "Keyline index " + index + " out of range for " + this);
+            return 0;
+        }
+
+        return mKeylines[index];
+    }
+
+    static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {
+        if (TextUtils.isEmpty(name)) {
+            return null;
+        }
+
+        final String fullName;
+        if (name.startsWith(".")) {
+            // Relative to the app package. Prepend the app package name.
+            fullName = context.getPackageName() + name;
+        } else if (name.indexOf('.') >= 0) {
+            // Fully qualified package name.
+            fullName = name;
+        } else {
+            // Assume stock behavior in this package (if we have one)
+            fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)
+                    ? (WIDGET_PACKAGE_NAME + '.' + name)
+                    : name;
+        }
+
+        try {
+            Map<String, Constructor<Behavior>> constructors = sConstructors.get();
+            if (constructors == null) {
+                constructors = new HashMap<>();
+                sConstructors.set(constructors);
+            }
+            Constructor<Behavior> c = constructors.get(fullName);
+            if (c == null) {
+                final Class<Behavior> clazz = (Class<Behavior>) context.getClassLoader()
+                        .loadClass(fullName);
+                c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
+                c.setAccessible(true);
+                constructors.put(fullName, c);
+            }
+            return c.newInstance(context, attrs);
+        } catch (Exception e) {
+            throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);
+        }
+    }
+
+    LayoutParams getResolvedLayoutParams(View child) {
+        final LayoutParams result = (LayoutParams) child.getLayoutParams();
+        if (!result.mBehaviorResolved) {
+            if (child instanceof AttachedBehavior) {
+                Behavior attachedBehavior = ((AttachedBehavior) child).getBehavior();
+                if (attachedBehavior == null) {
+                    Log.e(TAG, "Attached behavior class is null");
+                }
+                result.setBehavior(attachedBehavior);
+                result.mBehaviorResolved = true;
+            } else {
+                // The deprecated path that looks up the attached behavior based on annotation
+                Class<?> childClass = child.getClass();
+                DefaultBehavior defaultBehavior = null;
+                while (childClass != null
+                        && (defaultBehavior = childClass.getAnnotation(DefaultBehavior.class))
+                                == null) {
+                    childClass = childClass.getSuperclass();
+                }
+                if (defaultBehavior != null) {
+                    try {
+                        result.setBehavior(
+                                defaultBehavior.value().getDeclaredConstructor().newInstance());
+                    } catch (Exception e) {
+                        Log.e(TAG, "Default behavior class " + defaultBehavior.value().getName()
+                                        + " could not be instantiated. Did you forget"
+                                        + " a default constructor?", e);
+                    }
+                }
+                result.mBehaviorResolved = true;
+            }
+        }
+        return result;
+    }
+
+    private void prepareChildren() {
+        mDependencySortedChildren.clear();
+        mChildDag.clear();
+
+        for (int i = 0, count = getChildCount(); i < count; i++) {
+            final View view = getChildAt(i);
+
+            final LayoutParams lp = getResolvedLayoutParams(view);
+            lp.findAnchorView(this, view);
+
+            mChildDag.addNode(view);
+
+            // Now iterate again over the other children, adding any dependencies to the graph
+            for (int j = 0; j < count; j++) {
+                if (j == i) {
+                    continue;
+                }
+                final View other = getChildAt(j);
+                if (lp.dependsOn(this, view, other)) {
+                    if (!mChildDag.contains(other)) {
+                        // Make sure that the other node is added
+                        mChildDag.addNode(other);
+                    }
+                    // Now add the dependency to the graph
+                    mChildDag.addEdge(other, view);
+                }
+            }
+        }
+
+        // Finally add the sorted graph list to our list
+        mDependencySortedChildren.addAll(mChildDag.getSortedList());
+        // We also need to reverse the result since we want the start of the list to contain
+        // Views which have no dependencies, then dependent views after that
+        Collections.reverse(mDependencySortedChildren);
+    }
+
+    /**
+     * Retrieve the transformed bounding rect of an arbitrary descendant view.
+     * This does not need to be a direct child.
+     *
+     * @param descendant descendant view to reference
+     * @param out rect to set to the bounds of the descendant view
+     */
+    void getDescendantRect(View descendant, Rect out) {
+        ViewGroupUtils.getDescendantRect(this, descendant, out);
+    }
+
+    @Override
+    protected int getSuggestedMinimumWidth() {
+        return Math.max(super.getSuggestedMinimumWidth(), getPaddingLeft() + getPaddingRight());
+    }
+
+    @Override
+    protected int getSuggestedMinimumHeight() {
+        return Math.max(super.getSuggestedMinimumHeight(), getPaddingTop() + getPaddingBottom());
+    }
+
+    /**
+     * Called to measure each individual child view unless a
+     * {@link Behavior Behavior} is present. The Behavior may choose to delegate
+     * child measurement to this method.
+     *
+     * @param child the child to measure
+     * @param parentWidthMeasureSpec the width requirements for this view
+     * @param widthUsed extra space that has been used up by the parent
+     *        horizontally (possibly by other children of the parent)
+     * @param parentHeightMeasureSpec the height requirements for this view
+     * @param heightUsed extra space that has been used up by the parent
+     *        vertically (possibly by other children of the parent)
+     */
+    public void onMeasureChild(View child, int parentWidthMeasureSpec, int widthUsed,
+            int parentHeightMeasureSpec, int heightUsed) {
+        measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
+                parentHeightMeasureSpec, heightUsed);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        prepareChildren();
+        ensurePreDrawListener();
+
+        final int paddingLeft = getPaddingLeft();
+        final int paddingTop = getPaddingTop();
+        final int paddingRight = getPaddingRight();
+        final int paddingBottom = getPaddingBottom();
+        final int layoutDirection = ViewCompat.getLayoutDirection(this);
+        final boolean isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        final int widthPadding = paddingLeft + paddingRight;
+        final int heightPadding = paddingTop + paddingBottom;
+        int widthUsed = getSuggestedMinimumWidth();
+        int heightUsed = getSuggestedMinimumHeight();
+        int childState = 0;
+
+        final boolean applyInsets = mLastInsets != null && ViewCompat.getFitsSystemWindows(this);
+
+        final int childCount = mDependencySortedChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            final View child = mDependencySortedChildren.get(i);
+            if (child.getVisibility() == GONE) {
+                // If the child is GONE, skip...
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            int keylineWidthUsed = 0;
+            if (lp.keyline >= 0 && widthMode != MeasureSpec.UNSPECIFIED) {
+                final int keylinePos = getKeyline(lp.keyline);
+                final int keylineGravity = GravityCompat.getAbsoluteGravity(
+                        resolveKeylineGravity(lp.gravity), layoutDirection)
+                        & Gravity.HORIZONTAL_GRAVITY_MASK;
+                if ((keylineGravity == Gravity.LEFT && !isRtl)
+                        || (keylineGravity == Gravity.RIGHT && isRtl)) {
+                    keylineWidthUsed = Math.max(0, widthSize - paddingRight - keylinePos);
+                } else if ((keylineGravity == Gravity.RIGHT && !isRtl)
+                        || (keylineGravity == Gravity.LEFT && isRtl)) {
+                    keylineWidthUsed = Math.max(0, keylinePos - paddingLeft);
+                }
+            }
+
+            int childWidthMeasureSpec = widthMeasureSpec;
+            int childHeightMeasureSpec = heightMeasureSpec;
+            if (applyInsets && !ViewCompat.getFitsSystemWindows(child)) {
+                // We're set to handle insets but this child isn't, so we will measure the
+                // child as if there are no insets
+                final int horizInsets = mLastInsets.getSystemWindowInsetLeft()
+                        + mLastInsets.getSystemWindowInsetRight();
+                final int vertInsets = mLastInsets.getSystemWindowInsetTop()
+                        + mLastInsets.getSystemWindowInsetBottom();
+
+                childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        widthSize - horizInsets, widthMode);
+                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                        heightSize - vertInsets, heightMode);
+            }
+
+            final Behavior b = lp.getBehavior();
+            if (b == null || !b.onMeasureChild(this, child, childWidthMeasureSpec, keylineWidthUsed,
+                    childHeightMeasureSpec, 0)) {
+                onMeasureChild(child, childWidthMeasureSpec, keylineWidthUsed,
+                        childHeightMeasureSpec, 0);
+            }
+
+            widthUsed = Math.max(widthUsed, widthPadding + child.getMeasuredWidth() +
+                    lp.leftMargin + lp.rightMargin);
+
+            heightUsed = Math.max(heightUsed, heightPadding + child.getMeasuredHeight() +
+                    lp.topMargin + lp.bottomMargin);
+            childState = View.combineMeasuredStates(childState, child.getMeasuredState());
+        }
+
+        final int width = View.resolveSizeAndState(widthUsed, widthMeasureSpec,
+                childState & View.MEASURED_STATE_MASK);
+        final int height = View.resolveSizeAndState(heightUsed, heightMeasureSpec,
+                childState << View.MEASURED_HEIGHT_STATE_SHIFT);
+        setMeasuredDimension(width, height);
+    }
+
+    private WindowInsetsCompat dispatchApplyWindowInsetsToBehaviors(WindowInsetsCompat insets) {
+        if (insets.isConsumed()) {
+            return insets;
+        }
+
+        for (int i = 0, z = getChildCount(); i < z; i++) {
+            final View child = getChildAt(i);
+            if (ViewCompat.getFitsSystemWindows(child)) {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                final Behavior b = lp.getBehavior();
+
+                if (b != null) {
+                    // If the view has a behavior, let it try first
+                    insets = b.onApplyWindowInsets(this, child, insets);
+                    if (insets.isConsumed()) {
+                        // If it consumed the insets, break
+                        break;
+                    }
+                }
+            }
+        }
+
+        return insets;
+    }
+
+    /**
+     * Called to lay out each individual child view unless a
+     * {@link Behavior Behavior} is present. The Behavior may choose to
+     * delegate child measurement to this method.
+     *
+     * @param child child view to lay out
+     * @param layoutDirection the resolved layout direction for the CoordinatorLayout, such as
+     *                        {@link ViewCompat#LAYOUT_DIRECTION_LTR} or
+     *                        {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
+     */
+    public void onLayoutChild(View child, int layoutDirection) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        if (lp.checkAnchorChanged()) {
+            throw new IllegalStateException("An anchor may not be changed after CoordinatorLayout"
+                    + " measurement begins before layout is complete.");
+        }
+        if (lp.mAnchorView != null) {
+            layoutChildWithAnchor(child, lp.mAnchorView, layoutDirection);
+        } else if (lp.keyline >= 0) {
+            layoutChildWithKeyline(child, lp.keyline, layoutDirection);
+        } else {
+            layoutChild(child, layoutDirection);
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int layoutDirection = ViewCompat.getLayoutDirection(this);
+        final int childCount = mDependencySortedChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            final View child = mDependencySortedChildren.get(i);
+            if (child.getVisibility() == GONE) {
+                // If the child is GONE, skip...
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final Behavior behavior = lp.getBehavior();
+
+            if (behavior == null || !behavior.onLayoutChild(this, child, layoutDirection)) {
+                onLayoutChild(child, layoutDirection);
+            }
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas c) {
+        super.onDraw(c);
+        if (mDrawStatusBarBackground && mStatusBarBackground != null) {
+            final int inset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
+            if (inset > 0) {
+                mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
+                mStatusBarBackground.draw(c);
+            }
+        }
+    }
+
+    @Override
+    public void setFitsSystemWindows(boolean fitSystemWindows) {
+        super.setFitsSystemWindows(fitSystemWindows);
+        setupForInsets();
+    }
+
+    /**
+     * Mark the last known child position rect for the given child view.
+     * This will be used when checking if a child view's position has changed between frames.
+     * The rect used here should be one returned by
+     * {@link #getChildRect(View, boolean, Rect)}, with translation
+     * disabled.
+     *
+     * @param child child view to set for
+     * @param r rect to set
+     */
+    void recordLastChildRect(View child, Rect r) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        lp.setLastChildRect(r);
+    }
+
+    /**
+     * Get the last known child rect recorded by
+     * {@link #recordLastChildRect(View, Rect)}.
+     *
+     * @param child child view to retrieve from
+     * @param out rect to set to the outpur values
+     */
+    void getLastChildRect(View child, Rect out) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        out.set(lp.getLastChildRect());
+    }
+
+    /**
+     * Get the position rect for the given child. If the child has currently requested layout
+     * or has a visibility of GONE.
+     *
+     * @param child child view to check
+     * @param transform true to include transformation in the output rect, false to
+     *                        only account for the base position
+     * @param out rect to set to the output values
+     */
+    void getChildRect(View child, boolean transform, Rect out) {
+        if (child.isLayoutRequested() || child.getVisibility() == View.GONE) {
+            out.setEmpty();
+            return;
+        }
+        if (transform) {
+            getDescendantRect(child, out);
+        } else {
+            out.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
+        }
+    }
+
+    private void getDesiredAnchoredChildRectWithoutConstraints(View child, int layoutDirection,
+            Rect anchorRect, Rect out, LayoutParams lp, int childWidth, int childHeight) {
+        final int absGravity = GravityCompat.getAbsoluteGravity(
+                resolveAnchoredChildGravity(lp.gravity), layoutDirection);
+        final int absAnchorGravity = GravityCompat.getAbsoluteGravity(
+                resolveGravity(lp.anchorGravity),
+                layoutDirection);
+
+        final int hgrav = absGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        final int vgrav = absGravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int anchorHgrav = absAnchorGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        final int anchorVgrav = absAnchorGravity & Gravity.VERTICAL_GRAVITY_MASK;
+
+        int left;
+        int top;
+
+        // Align to the anchor. This puts us in an assumed right/bottom child view gravity.
+        // If this is not the case we will subtract out the appropriate portion of
+        // the child size below.
+        switch (anchorHgrav) {
+            default:
+            case Gravity.LEFT:
+                left = anchorRect.left;
+                break;
+            case Gravity.RIGHT:
+                left = anchorRect.right;
+                break;
+            case Gravity.CENTER_HORIZONTAL:
+                left = anchorRect.left + anchorRect.width() / 2;
+                break;
+        }
+
+        switch (anchorVgrav) {
+            default:
+            case Gravity.TOP:
+                top = anchorRect.top;
+                break;
+            case Gravity.BOTTOM:
+                top = anchorRect.bottom;
+                break;
+            case Gravity.CENTER_VERTICAL:
+                top = anchorRect.top + anchorRect.height() / 2;
+                break;
+        }
+
+        // Offset by the child view's gravity itself. The above assumed right/bottom gravity.
+        switch (hgrav) {
+            default:
+            case Gravity.LEFT:
+                left -= childWidth;
+                break;
+            case Gravity.RIGHT:
+                // Do nothing, we're already in position.
+                break;
+            case Gravity.CENTER_HORIZONTAL:
+                left -= childWidth / 2;
+                break;
+        }
+
+        switch (vgrav) {
+            default:
+            case Gravity.TOP:
+                top -= childHeight;
+                break;
+            case Gravity.BOTTOM:
+                // Do nothing, we're already in position.
+                break;
+            case Gravity.CENTER_VERTICAL:
+                top -= childHeight / 2;
+                break;
+        }
+
+        out.set(left, top, left + childWidth, top + childHeight);
+    }
+
+    private void constrainChildRect(LayoutParams lp, Rect out, int childWidth, int childHeight) {
+        final int width = getWidth();
+        final int height = getHeight();
+
+        // Obey margins and padding
+        int left = Math.max(getPaddingLeft() + lp.leftMargin,
+                Math.min(out.left,
+                        width - getPaddingRight() - childWidth - lp.rightMargin));
+        int top = Math.max(getPaddingTop() + lp.topMargin,
+                Math.min(out.top,
+                        height - getPaddingBottom() - childHeight - lp.bottomMargin));
+
+        out.set(left, top, left + childWidth, top + childHeight);
+    }
+
+    /**
+     * Calculate the desired child rect relative to an anchor rect, respecting both
+     * gravity and anchorGravity.
+     *
+     * @param child child view to calculate a rect for
+     * @param layoutDirection the desired layout direction for the CoordinatorLayout
+     * @param anchorRect rect in CoordinatorLayout coordinates of the anchor view area
+     * @param out rect to set to the output values
+     */
+    void getDesiredAnchoredChildRect(View child, int layoutDirection, Rect anchorRect, Rect out) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        final int childWidth = child.getMeasuredWidth();
+        final int childHeight = child.getMeasuredHeight();
+        getDesiredAnchoredChildRectWithoutConstraints(child, layoutDirection, anchorRect, out, lp,
+                childWidth, childHeight);
+        constrainChildRect(lp, out, childWidth, childHeight);
+    }
+
+    /**
+     * CORE ASSUMPTION: anchor has been laid out by the time this is called for a given child view.
+     *
+     * @param child child to lay out
+     * @param anchor view to anchor child relative to; already laid out.
+     * @param layoutDirection ViewCompat constant for layout direction
+     */
+    private void layoutChildWithAnchor(View child, View anchor, int layoutDirection) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+        final Rect anchorRect = acquireTempRect();
+        final Rect childRect = acquireTempRect();
+        try {
+            getDescendantRect(anchor, anchorRect);
+            getDesiredAnchoredChildRect(child, layoutDirection, anchorRect, childRect);
+            child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
+        } finally {
+            releaseTempRect(anchorRect);
+            releaseTempRect(childRect);
+        }
+    }
+
+    /**
+     * Lay out a child view with respect to a keyline.
+     *
+     * <p>The keyline represents a horizontal offset from the unpadded starting edge of
+     * the CoordinatorLayout. The child's gravity will affect how it is positioned with
+     * respect to the keyline.</p>
+     *
+     * @param child child to lay out
+     * @param keyline offset from the starting edge in pixels of the keyline to align with
+     * @param layoutDirection ViewCompat constant for layout direction
+     */
+    private void layoutChildWithKeyline(View child, int keyline, int layoutDirection) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        final int absGravity = GravityCompat.getAbsoluteGravity(
+                resolveKeylineGravity(lp.gravity), layoutDirection);
+
+        final int hgrav = absGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        final int vgrav = absGravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int width = getWidth();
+        final int height = getHeight();
+        final int childWidth = child.getMeasuredWidth();
+        final int childHeight = child.getMeasuredHeight();
+
+        if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) {
+            keyline = width - keyline;
+        }
+
+        int left = getKeyline(keyline) - childWidth;
+        int top = 0;
+
+        switch (hgrav) {
+            default:
+            case Gravity.LEFT:
+                // Nothing to do.
+                break;
+            case Gravity.RIGHT:
+                left += childWidth;
+                break;
+            case Gravity.CENTER_HORIZONTAL:
+                left += childWidth / 2;
+                break;
+        }
+
+        switch (vgrav) {
+            default:
+            case Gravity.TOP:
+                // Do nothing, we're already in position.
+                break;
+            case Gravity.BOTTOM:
+                top += childHeight;
+                break;
+            case Gravity.CENTER_VERTICAL:
+                top += childHeight / 2;
+                break;
+        }
+
+        // Obey margins and padding
+        left = Math.max(getPaddingLeft() + lp.leftMargin,
+                Math.min(left,
+                        width - getPaddingRight() - childWidth - lp.rightMargin));
+        top = Math.max(getPaddingTop() + lp.topMargin,
+                Math.min(top,
+                        height - getPaddingBottom() - childHeight - lp.bottomMargin));
+
+        child.layout(left, top, left + childWidth, top + childHeight);
+    }
+
+    /**
+     * Lay out a child view with no special handling. This will position the child as
+     * if it were within a FrameLayout or similar simple frame.
+     *
+     * @param child child view to lay out
+     * @param layoutDirection ViewCompat constant for the desired layout direction
+     */
+    private void layoutChild(View child, int layoutDirection) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        final Rect parent = acquireTempRect();
+        parent.set(getPaddingLeft() + lp.leftMargin,
+                getPaddingTop() + lp.topMargin,
+                getWidth() - getPaddingRight() - lp.rightMargin,
+                getHeight() - getPaddingBottom() - lp.bottomMargin);
+
+        if (mLastInsets != null && ViewCompat.getFitsSystemWindows(this)
+                && !ViewCompat.getFitsSystemWindows(child)) {
+            // If we're set to handle insets but this child isn't, then it has been measured as
+            // if there are no insets. We need to lay it out to match.
+            parent.left += mLastInsets.getSystemWindowInsetLeft();
+            parent.top += mLastInsets.getSystemWindowInsetTop();
+            parent.right -= mLastInsets.getSystemWindowInsetRight();
+            parent.bottom -= mLastInsets.getSystemWindowInsetBottom();
+        }
+
+        final Rect out = acquireTempRect();
+        GravityCompat.apply(resolveGravity(lp.gravity), child.getMeasuredWidth(),
+                child.getMeasuredHeight(), parent, out, layoutDirection);
+        child.layout(out.left, out.top, out.right, out.bottom);
+
+        releaseTempRect(parent);
+        releaseTempRect(out);
+    }
+
+    /**
+     * Return the given gravity value, but if either or both of the axes doesn't have any gravity
+     * specified, the default value (start or top) is specified. This should be used for children
+     * that are not anchored to another view or a keyline.
+     */
+    private static int resolveGravity(int gravity) {
+        if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
+            gravity |= GravityCompat.START;
+        }
+        if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
+            gravity |= Gravity.TOP;
+        }
+        return gravity;
+    }
+
+    /**
+     * Return the given gravity value or the default if the passed value is NO_GRAVITY.
+     * This should be used for children that are positioned relative to a keyline.
+     */
+    private static int resolveKeylineGravity(int gravity) {
+        return gravity == Gravity.NO_GRAVITY ? GravityCompat.END | Gravity.TOP : gravity;
+    }
+
+    /**
+     * Return the given gravity value or the default if the passed value is NO_GRAVITY.
+     * This should be used for children that are anchored to another view.
+     */
+    private static int resolveAnchoredChildGravity(int gravity) {
+        return gravity == Gravity.NO_GRAVITY ? Gravity.CENTER : gravity;
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        if (lp.mBehavior != null) {
+            final float scrimAlpha = lp.mBehavior.getScrimOpacity(this, child);
+            if (scrimAlpha > 0f) {
+                if (mScrimPaint == null) {
+                    mScrimPaint = new Paint();
+                }
+                mScrimPaint.setColor(lp.mBehavior.getScrimColor(this, child));
+                mScrimPaint.setAlpha(clamp(Math.round(255 * scrimAlpha), 0, 255));
+
+                final int saved = canvas.save();
+                if (child.isOpaque()) {
+                    // If the child is opaque, there is no need to draw behind it so we'll inverse
+                    // clip the canvas
+                    canvas.clipRect(child.getLeft(), child.getTop(), child.getRight(),
+                            child.getBottom(), Region.Op.DIFFERENCE);
+                }
+                // Now draw the rectangle for the scrim
+                canvas.drawRect(getPaddingLeft(), getPaddingTop(),
+                        getWidth() - getPaddingRight(), getHeight() - getPaddingBottom(),
+                        mScrimPaint);
+                canvas.restoreToCount(saved);
+            }
+        }
+        return super.drawChild(canvas, child, drawingTime);
+    }
+
+    private static int clamp(int value, int min, int max) {
+        if (value < min) {
+            return min;
+        } else if (value > max) {
+            return max;
+        }
+        return value;
+    }
+
+    /**
+     * Dispatch any dependent view changes to the relevant {@link Behavior} instances.
+     *
+     * Usually run as part of the pre-draw step when at least one child view has a reported
+     * dependency on another view. This allows CoordinatorLayout to account for layout
+     * changes and animations that occur outside of the normal layout pass.
+     *
+     * It can also be ran as part of the nested scrolling dispatch to ensure that any offsetting
+     * is completed within the correct coordinate window.
+     *
+     * The offsetting behavior implemented here does not store the computed offset in
+     * the LayoutParams; instead it expects that the layout process will always reconstruct
+     * the proper positioning.
+     *
+     * @param type the type of event which has caused this call
+     */
+    final void onChildViewsChanged(@DispatchChangeEvent final int type) {
+        final int layoutDirection = ViewCompat.getLayoutDirection(this);
+        final int childCount = mDependencySortedChildren.size();
+        final Rect inset = acquireTempRect();
+        final Rect drawRect = acquireTempRect();
+        final Rect lastDrawRect = acquireTempRect();
+
+        for (int i = 0; i < childCount; i++) {
+            final View child = mDependencySortedChildren.get(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (type == EVENT_PRE_DRAW && child.getVisibility() == View.GONE) {
+                // Do not try to update GONE child views in pre draw updates.
+                continue;
+            }
+
+            // Check child views before for anchor
+            for (int j = 0; j < i; j++) {
+                final View checkChild = mDependencySortedChildren.get(j);
+
+                if (lp.mAnchorDirectChild == checkChild) {
+                    offsetChildToAnchor(child, layoutDirection);
+                }
+            }
+
+            // Get the current draw rect of the view
+            getChildRect(child, true, drawRect);
+
+            // Accumulate inset sizes
+            if (lp.insetEdge != Gravity.NO_GRAVITY && !drawRect.isEmpty()) {
+                final int absInsetEdge = GravityCompat.getAbsoluteGravity(
+                        lp.insetEdge, layoutDirection);
+                switch (absInsetEdge & Gravity.VERTICAL_GRAVITY_MASK) {
+                    case Gravity.TOP:
+                        inset.top = Math.max(inset.top, drawRect.bottom);
+                        break;
+                    case Gravity.BOTTOM:
+                        inset.bottom = Math.max(inset.bottom, getHeight() - drawRect.top);
+                        break;
+                }
+                switch (absInsetEdge & Gravity.HORIZONTAL_GRAVITY_MASK) {
+                    case Gravity.LEFT:
+                        inset.left = Math.max(inset.left, drawRect.right);
+                        break;
+                    case Gravity.RIGHT:
+                        inset.right = Math.max(inset.right, getWidth() - drawRect.left);
+                        break;
+                }
+            }
+
+            // Dodge inset edges if necessary
+            if (lp.dodgeInsetEdges != Gravity.NO_GRAVITY && child.getVisibility() == View.VISIBLE) {
+                offsetChildByInset(child, inset, layoutDirection);
+            }
+
+            if (type != EVENT_VIEW_REMOVED) {
+                // Did it change? if not continue
+                getLastChildRect(child, lastDrawRect);
+                if (lastDrawRect.equals(drawRect)) {
+                    continue;
+                }
+                recordLastChildRect(child, drawRect);
+            }
+
+            // Update any behavior-dependent views for the change
+            for (int j = i + 1; j < childCount; j++) {
+                final View checkChild = mDependencySortedChildren.get(j);
+                final LayoutParams checkLp = (LayoutParams) checkChild.getLayoutParams();
+                final Behavior b = checkLp.getBehavior();
+
+                if (b != null && b.layoutDependsOn(this, checkChild, child)) {
+                    if (type == EVENT_PRE_DRAW && checkLp.getChangedAfterNestedScroll()) {
+                        // If this is from a pre-draw and we have already been changed
+                        // from a nested scroll, skip the dispatch and reset the flag
+                        checkLp.resetChangedAfterNestedScroll();
+                        continue;
+                    }
+
+                    final boolean handled;
+                    switch (type) {
+                        case EVENT_VIEW_REMOVED:
+                            // EVENT_VIEW_REMOVED means that we need to dispatch
+                            // onDependentViewRemoved() instead
+                            b.onDependentViewRemoved(this, checkChild, child);
+                            handled = true;
+                            break;
+                        default:
+                            // Otherwise we dispatch onDependentViewChanged()
+                            handled = b.onDependentViewChanged(this, checkChild, child);
+                            break;
+                    }
+
+                    if (type == EVENT_NESTED_SCROLL) {
+                        // If this is from a nested scroll, set the flag so that we may skip
+                        // any resulting onPreDraw dispatch (if needed)
+                        checkLp.setChangedAfterNestedScroll(handled);
+                    }
+                }
+            }
+        }
+
+        releaseTempRect(inset);
+        releaseTempRect(drawRect);
+        releaseTempRect(lastDrawRect);
+    }
+
+    private void offsetChildByInset(final View child, final Rect inset, final int layoutDirection) {
+        if (!ViewCompat.isLaidOut(child)) {
+            // The view has not been laid out yet, so we can't obtain its bounds.
+            return;
+        }
+
+        if (child.getWidth() <= 0 || child.getHeight() <= 0) {
+            // Bounds are empty so there is nothing to dodge against, skip...
+            return;
+        }
+
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        final Behavior behavior = lp.getBehavior();
+        final Rect dodgeRect = acquireTempRect();
+        final Rect bounds = acquireTempRect();
+        bounds.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
+
+        if (behavior != null && behavior.getInsetDodgeRect(this, child, dodgeRect)) {
+            // Make sure that the rect is within the view's bounds
+            if (!bounds.contains(dodgeRect)) {
+                throw new IllegalArgumentException("Rect should be within the child's bounds."
+                        + " Rect:" + dodgeRect.toShortString()
+                        + " | Bounds:" + bounds.toShortString());
+            }
+        } else {
+            dodgeRect.set(bounds);
+        }
+
+        // We can release the bounds rect now
+        releaseTempRect(bounds);
+
+        if (dodgeRect.isEmpty()) {
+            // Rect is empty so there is nothing to dodge against, skip...
+            releaseTempRect(dodgeRect);
+            return;
+        }
+
+        final int absDodgeInsetEdges = GravityCompat.getAbsoluteGravity(lp.dodgeInsetEdges,
+                layoutDirection);
+
+        boolean offsetY = false;
+        if ((absDodgeInsetEdges & Gravity.TOP) == Gravity.TOP) {
+            int distance = dodgeRect.top - lp.topMargin - lp.mInsetOffsetY;
+            if (distance < inset.top) {
+                setInsetOffsetY(child, inset.top - distance);
+                offsetY = true;
+            }
+        }
+        if ((absDodgeInsetEdges & Gravity.BOTTOM) == Gravity.BOTTOM) {
+            int distance = getHeight() - dodgeRect.bottom - lp.bottomMargin + lp.mInsetOffsetY;
+            if (distance < inset.bottom) {
+                setInsetOffsetY(child, distance - inset.bottom);
+                offsetY = true;
+            }
+        }
+        if (!offsetY) {
+            setInsetOffsetY(child, 0);
+        }
+
+        boolean offsetX = false;
+        if ((absDodgeInsetEdges & Gravity.LEFT) == Gravity.LEFT) {
+            int distance = dodgeRect.left - lp.leftMargin - lp.mInsetOffsetX;
+            if (distance < inset.left) {
+                setInsetOffsetX(child, inset.left - distance);
+                offsetX = true;
+            }
+        }
+        if ((absDodgeInsetEdges & Gravity.RIGHT) == Gravity.RIGHT) {
+            int distance = getWidth() - dodgeRect.right - lp.rightMargin + lp.mInsetOffsetX;
+            if (distance < inset.right) {
+                setInsetOffsetX(child, distance - inset.right);
+                offsetX = true;
+            }
+        }
+        if (!offsetX) {
+            setInsetOffsetX(child, 0);
+        }
+
+        releaseTempRect(dodgeRect);
+    }
+
+    private void setInsetOffsetX(View child, int offsetX) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        if (lp.mInsetOffsetX != offsetX) {
+            final int dx = offsetX - lp.mInsetOffsetX;
+            ViewCompat.offsetLeftAndRight(child, dx);
+            lp.mInsetOffsetX = offsetX;
+        }
+    }
+
+    private void setInsetOffsetY(View child, int offsetY) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        if (lp.mInsetOffsetY != offsetY) {
+            final int dy = offsetY - lp.mInsetOffsetY;
+            ViewCompat.offsetTopAndBottom(child, dy);
+            lp.mInsetOffsetY = offsetY;
+        }
+    }
+
+    /**
+     * Allows the caller to manually dispatch
+     * {@link Behavior#onDependentViewChanged(CoordinatorLayout, View, View)} to the associated
+     * {@link Behavior} instances of views which depend on the provided {@link View}.
+     *
+     * <p>You should not normally need to call this method as the it will be automatically done
+     * when the view has changed.
+     *
+     * @param view the View to find dependents of to dispatch the call.
+     */
+    public void dispatchDependentViewsChanged(View view) {
+        final List<View> dependents = mChildDag.getIncomingEdges(view);
+        if (dependents != null && !dependents.isEmpty()) {
+            for (int i = 0; i < dependents.size(); i++) {
+                final View child = dependents.get(i);
+                LayoutParams lp = (LayoutParams)
+                        child.getLayoutParams();
+                Behavior b = lp.getBehavior();
+                if (b != null) {
+                    b.onDependentViewChanged(this, child, view);
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the list of views which the provided view depends on. Do not store this list as its
+     * contents may not be valid beyond the caller.
+     *
+     * @param child the view to find dependencies for.
+     *
+     * @return the list of views which {@code child} depends on.
+     */
+    @NonNull
+    public List<View> getDependencies(@NonNull View child) {
+        final List<View> dependencies = mChildDag.getOutgoingEdges(child);
+        mTempDependenciesList.clear();
+        if (dependencies != null) {
+            mTempDependenciesList.addAll(dependencies);
+        }
+        return mTempDependenciesList;
+    }
+
+    /**
+     * Returns the list of views which depend on the provided view. Do not store this list as its
+     * contents may not be valid beyond the caller.
+     *
+     * @param child the view to find dependents of.
+     *
+     * @return the list of views which depend on {@code child}.
+     */
+    @NonNull
+    public List<View> getDependents(@NonNull View child) {
+        final List<View> edges = mChildDag.getIncomingEdges(child);
+        mTempDependenciesList.clear();
+        if (edges != null) {
+            mTempDependenciesList.addAll(edges);
+        }
+        return mTempDependenciesList;
+    }
+
+    @VisibleForTesting
+    final List<View> getDependencySortedChildren() {
+        prepareChildren();
+        return Collections.unmodifiableList(mDependencySortedChildren);
+    }
+
+    /**
+     * Add or remove the pre-draw listener as necessary.
+     */
+    void ensurePreDrawListener() {
+        boolean hasDependencies = false;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (hasDependencies(child)) {
+                hasDependencies = true;
+                break;
+            }
+        }
+
+        if (hasDependencies != mNeedsPreDrawListener) {
+            if (hasDependencies) {
+                addPreDrawListener();
+            } else {
+                removePreDrawListener();
+            }
+        }
+    }
+
+    /**
+     * Check if the given child has any layout dependencies on other child views.
+     */
+    private boolean hasDependencies(View child) {
+        return mChildDag.hasOutgoingEdges(child);
+    }
+
+    /**
+     * Add the pre-draw listener if we're attached to a window and mark that we currently
+     * need it when attached.
+     */
+    void addPreDrawListener() {
+        if (mIsAttachedToWindow) {
+            // Add the listener
+            if (mOnPreDrawListener == null) {
+                mOnPreDrawListener = new OnPreDrawListener();
+            }
+            final ViewTreeObserver vto = getViewTreeObserver();
+            vto.addOnPreDrawListener(mOnPreDrawListener);
+        }
+
+        // Record that we need the listener regardless of whether or not we're attached.
+        // We'll add the real listener when we become attached.
+        mNeedsPreDrawListener = true;
+    }
+
+    /**
+     * Remove the pre-draw listener if we're attached to a window and mark that we currently
+     * do not need it when attached.
+     */
+    void removePreDrawListener() {
+        if (mIsAttachedToWindow) {
+            if (mOnPreDrawListener != null) {
+                final ViewTreeObserver vto = getViewTreeObserver();
+                vto.removeOnPreDrawListener(mOnPreDrawListener);
+            }
+        }
+        mNeedsPreDrawListener = false;
+    }
+
+    /**
+     * Adjust the child left, top, right, bottom rect to the correct anchor view position,
+     * respecting gravity and anchor gravity.
+     *
+     * Note that child translation properties are ignored in this process, allowing children
+     * to be animated away from their anchor. However, if the anchor view is animated,
+     * the child will be offset to match the anchor's translated position.
+     */
+    void offsetChildToAnchor(View child, int layoutDirection) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        if (lp.mAnchorView != null) {
+            final Rect anchorRect = acquireTempRect();
+            final Rect childRect = acquireTempRect();
+            final Rect desiredChildRect = acquireTempRect();
+
+            getDescendantRect(lp.mAnchorView, anchorRect);
+            getChildRect(child, false, childRect);
+
+            int childWidth = child.getMeasuredWidth();
+            int childHeight = child.getMeasuredHeight();
+            getDesiredAnchoredChildRectWithoutConstraints(child, layoutDirection, anchorRect,
+                    desiredChildRect, lp, childWidth, childHeight);
+            boolean changed = desiredChildRect.left != childRect.left ||
+                    desiredChildRect.top != childRect.top;
+            constrainChildRect(lp, desiredChildRect, childWidth, childHeight);
+
+            final int dx = desiredChildRect.left - childRect.left;
+            final int dy = desiredChildRect.top - childRect.top;
+
+            if (dx != 0) {
+                ViewCompat.offsetLeftAndRight(child, dx);
+            }
+            if (dy != 0) {
+                ViewCompat.offsetTopAndBottom(child, dy);
+            }
+
+            if (changed) {
+                // If we have needed to move, make sure to notify the child's Behavior
+                final Behavior b = lp.getBehavior();
+                if (b != null) {
+                    b.onDependentViewChanged(this, child, lp.mAnchorView);
+                }
+            }
+
+            releaseTempRect(anchorRect);
+            releaseTempRect(childRect);
+            releaseTempRect(desiredChildRect);
+        }
+    }
+
+    /**
+     * Check if a given point in the CoordinatorLayout's coordinates are within the view bounds
+     * of the given direct child view.
+     *
+     * @param child child view to test
+     * @param x X coordinate to test, in the CoordinatorLayout's coordinate system
+     * @param y Y coordinate to test, in the CoordinatorLayout's coordinate system
+     * @return true if the point is within the child view's bounds, false otherwise
+     */
+    public boolean isPointInChildBounds(View child, int x, int y) {
+        final Rect r = acquireTempRect();
+        getDescendantRect(child, r);
+        try {
+            return r.contains(x, y);
+        } finally {
+            releaseTempRect(r);
+        }
+    }
+
+    /**
+     * Check whether two views overlap each other. The views need to be descendants of this
+     * {@link CoordinatorLayout} in the view hierarchy.
+     *
+     * @param first first child view to test
+     * @param second second child view to test
+     * @return true if both views are visible and overlap each other
+     */
+    public boolean doViewsOverlap(View first, View second) {
+        if (first.getVisibility() == VISIBLE && second.getVisibility() == VISIBLE) {
+            final Rect firstRect = acquireTempRect();
+            getChildRect(first, first.getParent() != this, firstRect);
+            final Rect secondRect = acquireTempRect();
+            getChildRect(second, second.getParent() != this, secondRect);
+            try {
+                return !(firstRect.left > secondRect.right || firstRect.top > secondRect.bottom
+                        || firstRect.right < secondRect.left || firstRect.bottom < secondRect.top);
+            } finally {
+                releaseTempRect(firstRect);
+                releaseTempRect(secondRect);
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        if (p instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) p);
+        } else if (p instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) p);
+        }
+        return new LayoutParams(p);
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams && super.checkLayoutParams(p);
+    }
+
+    @Override
+    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+        return onStartNestedScroll(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public boolean onStartNestedScroll(View child, View target, int axes, int type) {
+        boolean handled = false;
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            if (view.getVisibility() == View.GONE) {
+                // If it's GONE, don't dispatch
+                continue;
+            }
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            final Behavior viewBehavior = lp.getBehavior();
+            if (viewBehavior != null) {
+                final boolean accepted = viewBehavior.onStartNestedScroll(this, view, child,
+                        target, axes, type);
+                handled |= accepted;
+                lp.setNestedScrollAccepted(type, accepted);
+            } else {
+                lp.setNestedScrollAccepted(type, false);
+            }
+        }
+        return handled;
+    }
+
+    @Override
+    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
+        onNestedScrollAccepted(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes, int type) {
+        mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes, type);
+        mNestedScrollingTarget = target;
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            if (!lp.isNestedScrollAccepted(type)) {
+                continue;
+            }
+
+            final Behavior viewBehavior = lp.getBehavior();
+            if (viewBehavior != null) {
+                viewBehavior.onNestedScrollAccepted(this, view, child, target,
+                        nestedScrollAxes, type);
+            }
+        }
+    }
+
+    @Override
+    public void onStopNestedScroll(View target) {
+        onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onStopNestedScroll(View target, int type) {
+        mNestedScrollingParentHelper.onStopNestedScroll(target, type);
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            if (!lp.isNestedScrollAccepted(type)) {
+                continue;
+            }
+
+            final Behavior viewBehavior = lp.getBehavior();
+            if (viewBehavior != null) {
+                viewBehavior.onStopNestedScroll(this, view, target, type);
+            }
+            lp.resetNestedScroll(type);
+            lp.resetChangedAfterNestedScroll();
+        }
+        mNestedScrollingTarget = null;
+    }
+
+    @Override
+    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+            int dxUnconsumed, int dyUnconsumed) {
+        onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
+                ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
+            int dxUnconsumed, int dyUnconsumed, int type) {
+        final int childCount = getChildCount();
+        boolean accepted = false;
+
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            if (view.getVisibility() == GONE) {
+                // If the child is GONE, skip...
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            if (!lp.isNestedScrollAccepted(type)) {
+                continue;
+            }
+
+            final Behavior viewBehavior = lp.getBehavior();
+            if (viewBehavior != null) {
+                viewBehavior.onNestedScroll(this, view, target, dxConsumed, dyConsumed,
+                        dxUnconsumed, dyUnconsumed, type);
+                accepted = true;
+            }
+        }
+
+        if (accepted) {
+            onChildViewsChanged(EVENT_NESTED_SCROLL);
+        }
+    }
+
+    @Override
+    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+        onNestedPreScroll(target, dx, dy, consumed, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed, int  type) {
+        int xConsumed = 0;
+        int yConsumed = 0;
+        boolean accepted = false;
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            if (view.getVisibility() == GONE) {
+                // If the child is GONE, skip...
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            if (!lp.isNestedScrollAccepted(type)) {
+                continue;
+            }
+
+            final Behavior viewBehavior = lp.getBehavior();
+            if (viewBehavior != null) {
+                mTempIntPair[0] = mTempIntPair[1] = 0;
+                viewBehavior.onNestedPreScroll(this, view, target, dx, dy, mTempIntPair, type);
+
+                xConsumed = dx > 0 ? Math.max(xConsumed, mTempIntPair[0])
+                        : Math.min(xConsumed, mTempIntPair[0]);
+                yConsumed = dy > 0 ? Math.max(yConsumed, mTempIntPair[1])
+                        : Math.min(yConsumed, mTempIntPair[1]);
+
+                accepted = true;
+            }
+        }
+
+        consumed[0] = xConsumed;
+        consumed[1] = yConsumed;
+
+        if (accepted) {
+            onChildViewsChanged(EVENT_NESTED_SCROLL);
+        }
+    }
+
+    @Override
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+        boolean handled = false;
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            if (view.getVisibility() == GONE) {
+                // If the child is GONE, skip...
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            if (!lp.isNestedScrollAccepted(ViewCompat.TYPE_TOUCH)) {
+                continue;
+            }
+
+            final Behavior viewBehavior = lp.getBehavior();
+            if (viewBehavior != null) {
+                handled |= viewBehavior.onNestedFling(this, view, target, velocityX, velocityY,
+                        consumed);
+            }
+        }
+        if (handled) {
+            onChildViewsChanged(EVENT_NESTED_SCROLL);
+        }
+        return handled;
+    }
+
+    @Override
+    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
+        boolean handled = false;
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View view = getChildAt(i);
+            if (view.getVisibility() == GONE) {
+                // If the child is GONE, skip...
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            if (!lp.isNestedScrollAccepted(ViewCompat.TYPE_TOUCH)) {
+                continue;
+            }
+
+            final Behavior viewBehavior = lp.getBehavior();
+            if (viewBehavior != null) {
+                handled |= viewBehavior.onNestedPreFling(this, view, target, velocityX, velocityY);
+            }
+        }
+        return handled;
+    }
+
+    @Override
+    public int getNestedScrollAxes() {
+        return mNestedScrollingParentHelper.getNestedScrollAxes();
+    }
+
+    class OnPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
+        @Override
+        public boolean onPreDraw() {
+            onChildViewsChanged(EVENT_PRE_DRAW);
+            return true;
+        }
+    }
+
+    /**
+     * Sorts child views with higher Z values to the beginning of a collection.
+     */
+    static class ViewElevationComparator implements Comparator<View> {
+        @Override
+        public int compare(View lhs, View rhs) {
+            final float lz = ViewCompat.getZ(lhs);
+            final float rz = ViewCompat.getZ(rhs);
+            if (lz > rz) {
+                return -1;
+            } else if (lz < rz) {
+                return 1;
+            }
+            return 0;
+        }
+    }
+
+    /**
+     * Defines the default {@link Behavior} of a {@link View} class.
+     *
+     * <p>When writing a custom view, use this annotation to define the default behavior
+     * when used as a direct child of an {@link CoordinatorLayout}. The default behavior
+     * can be overridden using {@link LayoutParams#setBehavior}.</p>
+     *
+     * <p>Example: <code>@DefaultBehavior(MyBehavior.class)</code></p>
+     * @deprecated Use {@link AttachedBehavior} instead
+     */
+    @Deprecated
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface DefaultBehavior {
+        Class<? extends Behavior> value();
+    }
+
+    /**
+     * Defines the default attached {@link Behavior} of a {@link View} class
+     *
+     * <p>When writing a custom view, implement this interface to return the default behavior
+     * when used as a direct child of an {@link CoordinatorLayout}. The default behavior
+     * can be overridden using {@link LayoutParams#setBehavior}.</p>
+     */
+    public interface AttachedBehavior {
+        /**
+         * Returns the behavior associated with the matching {@link View} class.
+         *
+         * @return The behavior associated with the matching {@link View} class. Must be
+         * non-null.
+         */
+        @NonNull Behavior getBehavior();
+    }
+
+    /**
+     * Interaction behavior plugin for child views of {@link CoordinatorLayout}.
+     *
+     * <p>A Behavior implements one or more interactions that a user can take on a child view.
+     * These interactions may include drags, swipes, flings, or any other gestures.</p>
+     *
+     * @param <V> The View type that this Behavior operates on
+     */
+    public static abstract class Behavior<V extends View> {
+
+        /**
+         * Default constructor for instantiating Behaviors.
+         */
+        public Behavior() {
+        }
+
+        /**
+         * Default constructor for inflating Behaviors from layout. The Behavior will have
+         * the opportunity to parse specially defined layout parameters. These parameters will
+         * appear on the child view tag.
+         *
+         * @param context
+         * @param attrs
+         */
+        public Behavior(Context context, AttributeSet attrs) {
+        }
+
+        /**
+         * Called when the Behavior has been attached to a LayoutParams instance.
+         *
+         * <p>This will be called after the LayoutParams has been instantiated and can be
+         * modified.</p>
+         *
+         * @param params the LayoutParams instance that this Behavior has been attached to
+         */
+        public void onAttachedToLayoutParams(@NonNull CoordinatorLayout.LayoutParams params) {
+        }
+
+        /**
+         * Called when the Behavior has been detached from its holding LayoutParams instance.
+         *
+         * <p>This will only be called if the Behavior has been explicitly removed from the
+         * LayoutParams instance via {@link LayoutParams#setBehavior(Behavior)}. It will not be
+         * called if the associated view is removed from the CoordinatorLayout or similar.</p>
+         */
+        public void onDetachedFromLayoutParams() {
+        }
+
+        /**
+         * Respond to CoordinatorLayout touch events before they are dispatched to child views.
+         *
+         * <p>Behaviors can use this to monitor inbound touch events until one decides to
+         * intercept the rest of the event stream to take an action on its associated child view.
+         * This method will return false until it detects the proper intercept conditions, then
+         * return true once those conditions have occurred.</p>
+         *
+         * <p>Once a Behavior intercepts touch events, the rest of the event stream will
+         * be sent to the {@link #onTouchEvent} method.</p>
+         *
+         * <p>This method will be called regardless of the visibility of the associated child
+         * of the behavior. If you only wish to handle touch events when the child is visible, you
+         * should add a check to {@link View#isShown()} on the given child.</p>
+         *
+         * <p>The default implementation of this method always returns false.</p>
+         *
+         * @param parent the parent view currently receiving this touch event
+         * @param child the child view associated with this Behavior
+         * @param ev the MotionEvent describing the touch event being processed
+         * @return true if this Behavior would like to intercept and take over the event stream.
+         *         The default always returns false.
+         */
+        public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
+            return false;
+        }
+
+        /**
+         * Respond to CoordinatorLayout touch events after this Behavior has started
+         * {@link #onInterceptTouchEvent intercepting} them.
+         *
+         * <p>Behaviors may intercept touch events in order to help the CoordinatorLayout
+         * manipulate its child views. For example, a Behavior may allow a user to drag a
+         * UI pane open or closed. This method should perform actual mutations of view
+         * layout state.</p>
+         *
+         * <p>This method will be called regardless of the visibility of the associated child
+         * of the behavior. If you only wish to handle touch events when the child is visible, you
+         * should add a check to {@link View#isShown()} on the given child.</p>
+         *
+         * @param parent the parent view currently receiving this touch event
+         * @param child the child view associated with this Behavior
+         * @param ev the MotionEvent describing the touch event being processed
+         * @return true if this Behavior handled this touch event and would like to continue
+         *         receiving events in this stream. The default always returns false.
+         */
+        public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
+            return false;
+        }
+
+        /**
+         * Supply a scrim color that will be painted behind the associated child view.
+         *
+         * <p>A scrim may be used to indicate that the other elements beneath it are not currently
+         * interactive or actionable, drawing user focus and attention to the views above the scrim.
+         * </p>
+         *
+         * <p>The default implementation returns {@link Color#BLACK}.</p>
+         *
+         * @param parent the parent view of the given child
+         * @param child the child view above the scrim
+         * @return the desired scrim color in 0xAARRGGBB format. The default return value is
+         *         {@link Color#BLACK}.
+         * @see #getScrimOpacity(CoordinatorLayout, View)
+         */
+        @ColorInt
+        public int getScrimColor(CoordinatorLayout parent, V child) {
+            return Color.BLACK;
+        }
+
+        /**
+         * Determine the current opacity of the scrim behind a given child view
+         *
+         * <p>A scrim may be used to indicate that the other elements beneath it are not currently
+         * interactive or actionable, drawing user focus and attention to the views above the scrim.
+         * </p>
+         *
+         * <p>The default implementation returns 0.0f.</p>
+         *
+         * @param parent the parent view of the given child
+         * @param child the child view above the scrim
+         * @return the desired scrim opacity from 0.0f to 1.0f. The default return value is 0.0f.
+         */
+        @FloatRange(from = 0, to = 1)
+        public float getScrimOpacity(CoordinatorLayout parent, V child) {
+            return 0.f;
+        }
+
+        /**
+         * Determine whether interaction with views behind the given child in the child order
+         * should be blocked.
+         *
+         * <p>The default implementation returns true if
+         * {@link #getScrimOpacity(CoordinatorLayout, View)} would return > 0.0f.</p>
+         *
+         * @param parent the parent view of the given child
+         * @param child the child view to test
+         * @return true if {@link #getScrimOpacity(CoordinatorLayout, View)} would
+         *         return > 0.0f.
+         */
+        public boolean blocksInteractionBelow(CoordinatorLayout parent, V child) {
+            return getScrimOpacity(parent, child) > 0.f;
+        }
+
+        /**
+         * Determine whether the supplied child view has another specific sibling view as a
+         * layout dependency.
+         *
+         * <p>This method will be called at least once in response to a layout request. If it
+         * returns true for a given child and dependency view pair, the parent CoordinatorLayout
+         * will:</p>
+         * <ol>
+         *     <li>Always lay out this child after the dependent child is laid out, regardless
+         *     of child order.</li>
+         *     <li>Call {@link #onDependentViewChanged} when the dependency view's layout or
+         *     position changes.</li>
+         * </ol>
+         *
+         * @param parent the parent view of the given child
+         * @param child the child view to test
+         * @param dependency the proposed dependency of child
+         * @return true if child's layout depends on the proposed dependency's layout,
+         *         false otherwise
+         *
+         * @see #onDependentViewChanged(CoordinatorLayout, View, View)
+         */
+        public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) {
+            return false;
+        }
+
+        /**
+         * Respond to a change in a child's dependent view
+         *
+         * <p>This method is called whenever a dependent view changes in size or position outside
+         * of the standard layout flow. A Behavior may use this method to appropriately update
+         * the child view in response.</p>
+         *
+         * <p>A view's dependency is determined by
+         * {@link #layoutDependsOn(CoordinatorLayout, View, View)} or
+         * if {@code child} has set another view as it's anchor.</p>
+         *
+         * <p>Note that if a Behavior changes the layout of a child via this method, it should
+         * also be able to reconstruct the correct position in
+         * {@link #onLayoutChild(CoordinatorLayout, View, int) onLayoutChild}.
+         * <code>onDependentViewChanged</code> will not be called during normal layout since
+         * the layout of each child view will always happen in dependency order.</p>
+         *
+         * <p>If the Behavior changes the child view's size or position, it should return true.
+         * The default implementation returns false.</p>
+         *
+         * @param parent the parent view of the given child
+         * @param child the child view to manipulate
+         * @param dependency the dependent view that changed
+         * @return true if the Behavior changed the child view's size or position, false otherwise
+         */
+        public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) {
+            return false;
+        }
+
+        /**
+         * Respond to a child's dependent view being removed.
+         *
+         * <p>This method is called after a dependent view has been removed from the parent.
+         * A Behavior may use this method to appropriately update the child view in response.</p>
+         *
+         * <p>A view's dependency is determined by
+         * {@link #layoutDependsOn(CoordinatorLayout, View, View)} or
+         * if {@code child} has set another view as it's anchor.</p>
+         *
+         * @param parent the parent view of the given child
+         * @param child the child view to manipulate
+         * @param dependency the dependent view that has been removed
+         */
+        public void onDependentViewRemoved(CoordinatorLayout parent, V child, View dependency) {
+        }
+
+        /**
+         * Called when the parent CoordinatorLayout is about to measure the given child view.
+         *
+         * <p>This method can be used to perform custom or modified measurement of a child view
+         * in place of the default child measurement behavior. The Behavior's implementation
+         * can delegate to the standard CoordinatorLayout measurement behavior by calling
+         * {@link CoordinatorLayout#onMeasureChild(View, int, int, int, int)
+         * parent.onMeasureChild}.</p>
+         *
+         * @param parent the parent CoordinatorLayout
+         * @param child the child to measure
+         * @param parentWidthMeasureSpec the width requirements for this view
+         * @param widthUsed extra space that has been used up by the parent
+         *        horizontally (possibly by other children of the parent)
+         * @param parentHeightMeasureSpec the height requirements for this view
+         * @param heightUsed extra space that has been used up by the parent
+         *        vertically (possibly by other children of the parent)
+         * @return true if the Behavior measured the child view, false if the CoordinatorLayout
+         *         should perform its default measurement
+         */
+        public boolean onMeasureChild(CoordinatorLayout parent, V child,
+                int parentWidthMeasureSpec, int widthUsed,
+                int parentHeightMeasureSpec, int heightUsed) {
+            return false;
+        }
+
+        /**
+         * Called when the parent CoordinatorLayout is about the lay out the given child view.
+         *
+         * <p>This method can be used to perform custom or modified layout of a child view
+         * in place of the default child layout behavior. The Behavior's implementation can
+         * delegate to the standard CoordinatorLayout measurement behavior by calling
+         * {@link CoordinatorLayout#onLayoutChild(View, int)
+         * parent.onLayoutChild}.</p>
+         *
+         * <p>If a Behavior implements
+         * {@link #onDependentViewChanged(CoordinatorLayout, View, View)}
+         * to change the position of a view in response to a dependent view changing, it
+         * should also implement <code>onLayoutChild</code> in such a way that respects those
+         * dependent views. <code>onLayoutChild</code> will always be called for a dependent view
+         * <em>after</em> its dependency has been laid out.</p>
+         *
+         * @param parent the parent CoordinatorLayout
+         * @param child child view to lay out
+         * @param layoutDirection the resolved layout direction for the CoordinatorLayout, such as
+         *                        {@link ViewCompat#LAYOUT_DIRECTION_LTR} or
+         *                        {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
+         * @return true if the Behavior performed layout of the child view, false to request
+         *         default layout behavior
+         */
+        public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
+            return false;
+        }
+
+        // Utility methods for accessing child-specific, behavior-modifiable properties.
+
+        /**
+         * Associate a Behavior-specific tag object with the given child view.
+         * This object will be stored with the child view's LayoutParams.
+         *
+         * @param child child view to set tag with
+         * @param tag tag object to set
+         */
+        public static void setTag(View child, Object tag) {
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            lp.mBehaviorTag = tag;
+        }
+
+        /**
+         * Get the behavior-specific tag object with the given child view.
+         * This object is stored with the child view's LayoutParams.
+         *
+         * @param child child view to get tag with
+         * @return the previously stored tag object
+         */
+        public static Object getTag(View child) {
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            return lp.mBehaviorTag;
+        }
+
+        /**
+         * @deprecated You should now override
+         * {@link #onStartNestedScroll(CoordinatorLayout, View, View, View, int, int)}. This
+         * method will still continue to be called if the type is {@link ViewCompat#TYPE_TOUCH}.
+         */
+        @Deprecated
+        public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
+                @ScrollAxis int axes) {
+            return false;
+        }
+
+        /**
+         * Called when a descendant of the CoordinatorLayout attempts to initiate a nested scroll.
+         *
+         * <p>Any Behavior associated with any direct child of the CoordinatorLayout may respond
+         * to this event and return true to indicate that the CoordinatorLayout should act as
+         * a nested scrolling parent for this scroll. Only Behaviors that return true from
+         * this method will receive subsequent nested scroll events.</p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param directTargetChild the child view of the CoordinatorLayout that either is or
+         *                          contains the target of the nested scroll operation
+         * @param target the descendant view of the CoordinatorLayout initiating the nested scroll
+         * @param axes the axes that this nested scroll applies to. See
+         *                         {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
+         *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL}
+         * @param type the type of input which cause this scroll event
+         * @return true if the Behavior wishes to accept this nested scroll
+         *
+         * @see NestedScrollingParent2#onStartNestedScroll(View, View, int, int)
+         */
+        public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
+                @ScrollAxis int axes, @NestedScrollType int type) {
+            if (type == ViewCompat.TYPE_TOUCH) {
+                return onStartNestedScroll(coordinatorLayout, child, directTargetChild,
+                        target, axes);
+            }
+            return false;
+        }
+
+        /**
+         * @deprecated You should now override
+         * {@link #onNestedScrollAccepted(CoordinatorLayout, View, View, View, int, int)}. This
+         * method will still continue to be called if the type is {@link ViewCompat#TYPE_TOUCH}.
+         */
+        @Deprecated
+        public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
+                @ScrollAxis int axes) {
+            // Do nothing
+        }
+
+        /**
+         * Called when a nested scroll has been accepted by the CoordinatorLayout.
+         *
+         * <p>Any Behavior associated with any direct child of the CoordinatorLayout may elect
+         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
+         * that returned true will receive subsequent nested scroll events for that nested scroll.
+         * </p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param directTargetChild the child view of the CoordinatorLayout that either is or
+         *                          contains the target of the nested scroll operation
+         * @param target the descendant view of the CoordinatorLayout initiating the nested scroll
+         * @param axes the axes that this nested scroll applies to. See
+         *                         {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
+         *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL}
+         * @param type the type of input which cause this scroll event
+         *
+         * @see NestedScrollingParent2#onNestedScrollAccepted(View, View, int, int)
+         */
+        public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
+                @ScrollAxis int axes, @NestedScrollType int type) {
+            if (type == ViewCompat.TYPE_TOUCH) {
+                onNestedScrollAccepted(coordinatorLayout, child, directTargetChild,
+                        target, axes);
+            }
+        }
+
+        /**
+         * @deprecated You should now override
+         * {@link #onStopNestedScroll(CoordinatorLayout, View, View, int)}. This method will still
+         * continue to be called if the type is {@link ViewCompat#TYPE_TOUCH}.
+         */
+        @Deprecated
+        public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View target) {
+            // Do nothing
+        }
+
+        /**
+         * Called when a nested scroll has ended.
+         *
+         * <p>Any Behavior associated with any direct child of the CoordinatorLayout may elect
+         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
+         * that returned true will receive subsequent nested scroll events for that nested scroll.
+         * </p>
+         *
+         * <p><code>onStopNestedScroll</code> marks the end of a single nested scroll event
+         * sequence. This is a good place to clean up any state related to the nested scroll.
+         * </p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param target the descendant view of the CoordinatorLayout that initiated
+         *               the nested scroll
+         * @param type the type of input which cause this scroll event
+         *
+         * @see NestedScrollingParent2#onStopNestedScroll(View, int)
+         */
+        public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View target, @NestedScrollType int type) {
+            if (type == ViewCompat.TYPE_TOUCH) {
+                onStopNestedScroll(coordinatorLayout, child, target);
+            }
+        }
+
+        /**
+         * @deprecated You should now override
+         * {@link #onNestedScroll(CoordinatorLayout, View, View, int, int, int, int, int)}.
+         * This method will still continue to be called if the type is
+         * {@link ViewCompat#TYPE_TOUCH}.
+         */
+        @Deprecated
+        public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
+                @NonNull View target, int dxConsumed, int dyConsumed,
+                int dxUnconsumed, int dyUnconsumed) {
+            // Do nothing
+        }
+
+        /**
+         * Called when a nested scroll in progress has updated and the target has scrolled or
+         * attempted to scroll.
+         *
+         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
+         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
+         * that returned true will receive subsequent nested scroll events for that nested scroll.
+         * </p>
+         *
+         * <p><code>onNestedScroll</code> is called each time the nested scroll is updated by the
+         * nested scrolling child, with both consumed and unconsumed components of the scroll
+         * supplied in pixels. <em>Each Behavior responding to the nested scroll will receive the
+         * same values.</em>
+         * </p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
+         * @param dxConsumed horizontal pixels consumed by the target's own scrolling operation
+         * @param dyConsumed vertical pixels consumed by the target's own scrolling operation
+         * @param dxUnconsumed horizontal pixels not consumed by the target's own scrolling
+         *                     operation, but requested by the user
+         * @param dyUnconsumed vertical pixels not consumed by the target's own scrolling operation,
+         *                     but requested by the user
+         * @param type the type of input which cause this scroll event
+         *
+         * @see NestedScrollingParent2#onNestedScroll(View, int, int, int, int, int)
+         */
+        public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
+                @NonNull View target, int dxConsumed, int dyConsumed,
+                int dxUnconsumed, int dyUnconsumed, @NestedScrollType int type) {
+            if (type == ViewCompat.TYPE_TOUCH) {
+                onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
+                        dxUnconsumed, dyUnconsumed);
+            }
+        }
+
+        /**
+         * @deprecated You should now override
+         * {@link #onNestedPreScroll(CoordinatorLayout, View, View, int, int, int[], int)}.
+         * This method will still continue to be called if the type is
+         * {@link ViewCompat#TYPE_TOUCH}.
+         */
+        @Deprecated
+        public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View target, int dx, int dy, @NonNull int[] consumed) {
+            // Do nothing
+        }
+
+        /**
+         * Called when a nested scroll in progress is about to update, before the target has
+         * consumed any of the scrolled distance.
+         *
+         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
+         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
+         * that returned true will receive subsequent nested scroll events for that nested scroll.
+         * </p>
+         *
+         * <p><code>onNestedPreScroll</code> is called each time the nested scroll is updated
+         * by the nested scrolling child, before the nested scrolling child has consumed the scroll
+         * distance itself. <em>Each Behavior responding to the nested scroll will receive the
+         * same values.</em> The CoordinatorLayout will report as consumed the maximum number
+         * of pixels in either direction that any Behavior responding to the nested scroll reported
+         * as consumed.</p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
+         * @param dx the raw horizontal number of pixels that the user attempted to scroll
+         * @param dy the raw vertical number of pixels that the user attempted to scroll
+         * @param consumed out parameter. consumed[0] should be set to the distance of dx that
+         *                 was consumed, consumed[1] should be set to the distance of dy that
+         *                 was consumed
+         * @param type the type of input which cause this scroll event
+         *
+         * @see NestedScrollingParent2#onNestedPreScroll(View, int, int, int[], int)
+         */
+        public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View target, int dx, int dy, @NonNull int[] consumed,
+                @NestedScrollType int type) {
+            if (type == ViewCompat.TYPE_TOUCH) {
+                onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
+            }
+        }
+
+        /**
+         * Called when a nested scrolling child is starting a fling or an action that would
+         * be a fling.
+         *
+         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
+         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
+         * that returned true will receive subsequent nested scroll events for that nested scroll.
+         * </p>
+         *
+         * <p><code>onNestedFling</code> is called when the current nested scrolling child view
+         * detects the proper conditions for a fling. It reports if the child itself consumed
+         * the fling. If it did not, the child is expected to show some sort of overscroll
+         * indication. This method should return true if it consumes the fling, so that a child
+         * that did not itself take an action in response can choose not to show an overfling
+         * indication.</p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
+         * @param velocityX horizontal velocity of the attempted fling
+         * @param velocityY vertical velocity of the attempted fling
+         * @param consumed true if the nested child view consumed the fling
+         * @return true if the Behavior consumed the fling
+         *
+         * @see NestedScrollingParent#onNestedFling(View, float, float, boolean)
+         */
+        public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View target, float velocityX, float velocityY,
+                boolean consumed) {
+            return false;
+        }
+
+        /**
+         * Called when a nested scrolling child is about to start a fling.
+         *
+         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
+         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
+         * that returned true will receive subsequent nested scroll events for that nested scroll.
+         * </p>
+         *
+         * <p><code>onNestedPreFling</code> is called when the current nested scrolling child view
+         * detects the proper conditions for a fling, but it has not acted on it yet. A
+         * Behavior can return true to indicate that it consumed the fling. If at least one
+         * Behavior returns true, the fling should not be acted upon by the child.</p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
+         * @param velocityX horizontal velocity of the attempted fling
+         * @param velocityY vertical velocity of the attempted fling
+         * @return true if the Behavior consumed the fling
+         *
+         * @see NestedScrollingParent#onNestedPreFling(View, float, float)
+         */
+        public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout,
+                @NonNull V child, @NonNull View target, float velocityX, float velocityY) {
+            return false;
+        }
+
+        /**
+         * Called when the window insets have changed.
+         *
+         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
+         * to handle the window inset change on behalf of it's associated view.
+         * </p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child the child view of the CoordinatorLayout this Behavior is associated with
+         * @param insets the new window insets.
+         *
+         * @return The insets supplied, minus any insets that were consumed
+         */
+        @NonNull
+        public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout,
+                V child, WindowInsetsCompat insets) {
+            return insets;
+        }
+
+        /**
+         * Called when a child of the view associated with this behavior wants a particular
+         * rectangle to be positioned onto the screen.
+         *
+         * <p>The contract for this method is the same as
+         * {@link ViewParent#requestChildRectangleOnScreen(View, Rect, boolean)}.</p>
+         *
+         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
+         *                          associated with
+         * @param child             the child view of the CoordinatorLayout this Behavior is
+         *                          associated with
+         * @param rectangle         The rectangle which the child wishes to be on the screen
+         *                          in the child's coordinates
+         * @param immediate         true to forbid animated or delayed scrolling, false otherwise
+         * @return true if the Behavior handled the request
+         * @see ViewParent#requestChildRectangleOnScreen(View, Rect, boolean)
+         */
+        public boolean onRequestChildRectangleOnScreen(CoordinatorLayout coordinatorLayout,
+                V child, Rect rectangle, boolean immediate) {
+            return false;
+        }
+
+        /**
+         * Hook allowing a behavior to re-apply a representation of its internal state that had
+         * previously been generated by {@link #onSaveInstanceState}. This function will never
+         * be called with a null state.
+         *
+         * @param parent the parent CoordinatorLayout
+         * @param child child view to restore from
+         * @param state The frozen state that had previously been returned by
+         *        {@link #onSaveInstanceState}.
+         *
+         * @see #onSaveInstanceState()
+         */
+        public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
+            // no-op
+        }
+
+        /**
+         * Hook allowing a behavior to generate a representation of its internal state
+         * that can later be used to create a new instance with that same state.
+         * This state should only contain information that is not persistent or can
+         * not be reconstructed later.
+         *
+         * <p>Behavior state is only saved when both the parent {@link CoordinatorLayout} and
+         * a view using this behavior have valid IDs set.</p>
+         *
+         * @param parent the parent CoordinatorLayout
+         * @param child child view to restore from
+         *
+         * @return Returns a Parcelable object containing the behavior's current dynamic
+         *         state.
+         *
+         * @see #onRestoreInstanceState(Parcelable)
+         * @see View#onSaveInstanceState()
+         */
+        public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
+            return BaseSavedState.EMPTY_STATE;
+        }
+
+        /**
+         * Called when a view is set to dodge view insets.
+         *
+         * <p>This method allows a behavior to update the rectangle that should be dodged.
+         * The rectangle should be in the parent's coordinate system and within the child's
+         * bounds. If not, a {@link IllegalArgumentException} is thrown.</p>
+         *
+         * @param parent the CoordinatorLayout parent of the view this Behavior is
+         *               associated with
+         * @param child  the child view of the CoordinatorLayout this Behavior is associated with
+         * @param rect   the rect to update with the dodge rectangle
+         * @return true the rect was updated, false if we should use the child's bounds
+         */
+        public boolean getInsetDodgeRect(@NonNull CoordinatorLayout parent, @NonNull V child,
+                @NonNull Rect rect) {
+            return false;
+        }
+    }
+
+    /**
+     * Parameters describing the desired layout for a child of a {@link CoordinatorLayout}.
+     */
+    public static class LayoutParams extends MarginLayoutParams {
+        /**
+         * A {@link Behavior} that the child view should obey.
+         */
+        Behavior mBehavior;
+
+        boolean mBehaviorResolved = false;
+
+        /**
+         * A {@link Gravity} value describing how this child view should lay out.
+         * If either or both of the axes are not specified, they are treated by CoordinatorLayout
+         * as {@link Gravity#TOP} or {@link GravityCompat#START}. If an
+         * {@link #setAnchorId(int) anchor} is also specified, the gravity describes how this child
+         * view should be positioned relative to its anchored position.
+         */
+        public int gravity = Gravity.NO_GRAVITY;
+
+        /**
+         * A {@link Gravity} value describing which edge of a child view's
+         * {@link #getAnchorId() anchor} view the child should position itself relative to.
+         */
+        public int anchorGravity = Gravity.NO_GRAVITY;
+
+        /**
+         * The index of the horizontal keyline specified to the parent CoordinatorLayout that this
+         * child should align relative to. If an {@link #setAnchorId(int) anchor} is present the
+         * keyline will be ignored.
+         */
+        public int keyline = -1;
+
+        /**
+         * A {@link View#getId() view id} of a descendant view of the CoordinatorLayout that
+         * this child should position relative to.
+         */
+        int mAnchorId = View.NO_ID;
+
+        /**
+         * A {@link Gravity} value describing how this child view insets the CoordinatorLayout.
+         * Other child views which are set to dodge the same inset edges will be moved appropriately
+         * so that the views do not overlap.
+         */
+        public int insetEdge = Gravity.NO_GRAVITY;
+
+        /**
+         * A {@link Gravity} value describing how this child view dodges any inset child views in
+         * the CoordinatorLayout. Any views which are inset on the same edge as this view is set to
+         * dodge will result in this view being moved so that the views do not overlap.
+         */
+        public int dodgeInsetEdges = Gravity.NO_GRAVITY;
+
+        int mInsetOffsetX;
+        int mInsetOffsetY;
+
+        View mAnchorView;
+        View mAnchorDirectChild;
+
+        private boolean mDidBlockInteraction;
+        private boolean mDidAcceptNestedScrollTouch;
+        private boolean mDidAcceptNestedScrollNonTouch;
+        private boolean mDidChangeAfterNestedScroll;
+
+        final Rect mLastChildRect = new Rect();
+
+        Object mBehaviorTag;
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        LayoutParams(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            final TypedArray a = context.obtainStyledAttributes(attrs,
+                    R.styleable.CoordinatorLayout_Layout);
+
+            this.gravity = a.getInteger(
+                    R.styleable.CoordinatorLayout_Layout_android_layout_gravity,
+                    Gravity.NO_GRAVITY);
+            mAnchorId = a.getResourceId(R.styleable.CoordinatorLayout_Layout_layout_anchor,
+                    View.NO_ID);
+            this.anchorGravity = a.getInteger(
+                    R.styleable.CoordinatorLayout_Layout_layout_anchorGravity,
+                    Gravity.NO_GRAVITY);
+
+            this.keyline = a.getInteger(R.styleable.CoordinatorLayout_Layout_layout_keyline,
+                    -1);
+
+            insetEdge = a.getInt(R.styleable.CoordinatorLayout_Layout_layout_insetEdge, 0);
+            dodgeInsetEdges = a.getInt(
+                    R.styleable.CoordinatorLayout_Layout_layout_dodgeInsetEdges, 0);
+            mBehaviorResolved = a.hasValue(
+                    R.styleable.CoordinatorLayout_Layout_layout_behavior);
+            if (mBehaviorResolved) {
+                mBehavior = parseBehavior(context, attrs, a.getString(
+                        R.styleable.CoordinatorLayout_Layout_layout_behavior));
+            }
+            a.recycle();
+
+            if (mBehavior != null) {
+                // If we have a Behavior, dispatch that it has been attached
+                mBehavior.onAttachedToLayoutParams(this);
+            }
+        }
+
+        public LayoutParams(LayoutParams p) {
+            super(p);
+        }
+
+        public LayoutParams(MarginLayoutParams p) {
+            super(p);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams p) {
+            super(p);
+        }
+
+        /**
+         * Get the id of this view's anchor.
+         *
+         * @return A {@link View#getId() view id} or {@link View#NO_ID} if there is no anchor
+         */
+        @IdRes
+        public int getAnchorId() {
+            return mAnchorId;
+        }
+
+        /**
+         * Set the id of this view's anchor.
+         *
+         * <p>The view with this id must be a descendant of the CoordinatorLayout containing
+         * the child view this LayoutParams belongs to. It may not be the child view with
+         * this LayoutParams or a descendant of it.</p>
+         *
+         * @param id The {@link View#getId() view id} of the anchor or
+         *           {@link View#NO_ID} if there is no anchor
+         */
+        public void setAnchorId(@IdRes int id) {
+            invalidateAnchor();
+            mAnchorId = id;
+        }
+
+        /**
+         * Get the behavior governing the layout and interaction of the child view within
+         * a parent CoordinatorLayout.
+         *
+         * @return The current behavior or null if no behavior is specified
+         */
+        @Nullable
+        public Behavior getBehavior() {
+            return mBehavior;
+        }
+
+        /**
+         * Set the behavior governing the layout and interaction of the child view within
+         * a parent CoordinatorLayout.
+         *
+         * <p>Setting a new behavior will remove any currently associated
+         * {@link Behavior#setTag(View, Object) Behavior tag}.</p>
+         *
+         * @param behavior The behavior to set or null for no special behavior
+         */
+        public void setBehavior(@Nullable Behavior behavior) {
+            if (mBehavior != behavior) {
+                if (mBehavior != null) {
+                    // First detach any old behavior
+                    mBehavior.onDetachedFromLayoutParams();
+                }
+
+                mBehavior = behavior;
+                mBehaviorTag = null;
+                mBehaviorResolved = true;
+
+                if (behavior != null) {
+                    // Now dispatch that the Behavior has been attached
+                    behavior.onAttachedToLayoutParams(this);
+                }
+            }
+        }
+
+        /**
+         * Set the last known position rect for this child view
+         * @param r the rect to set
+         */
+        void setLastChildRect(Rect r) {
+            mLastChildRect.set(r);
+        }
+
+        /**
+         * Get the last known position rect for this child view.
+         * Note: do not mutate the result of this call.
+         */
+        Rect getLastChildRect() {
+            return mLastChildRect;
+        }
+
+        /**
+         * Returns true if the anchor id changed to another valid view id since the anchor view
+         * was resolved.
+         */
+        boolean checkAnchorChanged() {
+            return mAnchorView == null && mAnchorId != View.NO_ID;
+        }
+
+        /**
+         * Returns true if the associated Behavior previously blocked interaction with other views
+         * below the associated child since the touch behavior tracking was last
+         * {@link #resetTouchBehaviorTracking() reset}.
+         *
+         * @see #isBlockingInteractionBelow(CoordinatorLayout, View)
+         */
+        boolean didBlockInteraction() {
+            if (mBehavior == null) {
+                mDidBlockInteraction = false;
+            }
+            return mDidBlockInteraction;
+        }
+
+        /**
+         * Check if the associated Behavior wants to block interaction below the given child
+         * view. The given child view should be the child this LayoutParams is associated with.
+         *
+         * <p>Once interaction is blocked, it will remain blocked until touch interaction tracking
+         * is {@link #resetTouchBehaviorTracking() reset}.</p>
+         *
+         * @param parent the parent CoordinatorLayout
+         * @param child the child view this LayoutParams is associated with
+         * @return true to block interaction below the given child
+         */
+        boolean isBlockingInteractionBelow(CoordinatorLayout parent, View child) {
+            if (mDidBlockInteraction) {
+                return true;
+            }
+
+            return mDidBlockInteraction |= mBehavior != null
+                    ? mBehavior.blocksInteractionBelow(parent, child)
+                    : false;
+        }
+
+        /**
+         * Reset tracking of Behavior-specific touch interactions. This includes
+         * interaction blocking.
+         *
+         * @see #isBlockingInteractionBelow(CoordinatorLayout, View)
+         * @see #didBlockInteraction()
+         */
+        void resetTouchBehaviorTracking() {
+            mDidBlockInteraction = false;
+        }
+
+        void resetNestedScroll(int type) {
+            setNestedScrollAccepted(type, false);
+        }
+
+        void setNestedScrollAccepted(int type, boolean accept) {
+            switch (type) {
+                case ViewCompat.TYPE_TOUCH:
+                    mDidAcceptNestedScrollTouch = accept;
+                    break;
+                case ViewCompat.TYPE_NON_TOUCH:
+                    mDidAcceptNestedScrollNonTouch = accept;
+                    break;
+            }
+        }
+
+        boolean isNestedScrollAccepted(int type) {
+            switch (type) {
+                case ViewCompat.TYPE_TOUCH:
+                    return mDidAcceptNestedScrollTouch;
+                case ViewCompat.TYPE_NON_TOUCH:
+                    return mDidAcceptNestedScrollNonTouch;
+            }
+            return false;
+        }
+
+        boolean getChangedAfterNestedScroll() {
+            return mDidChangeAfterNestedScroll;
+        }
+
+        void setChangedAfterNestedScroll(boolean changed) {
+            mDidChangeAfterNestedScroll = changed;
+        }
+
+        void resetChangedAfterNestedScroll() {
+            mDidChangeAfterNestedScroll = false;
+        }
+
+        /**
+         * Check if an associated child view depends on another child view of the CoordinatorLayout.
+         *
+         * @param parent the parent CoordinatorLayout
+         * @param child the child to check
+         * @param dependency the proposed dependency to check
+         * @return true if child depends on dependency
+         */
+        boolean dependsOn(CoordinatorLayout parent, View child, View dependency) {
+            return dependency == mAnchorDirectChild
+                    || shouldDodge(dependency, ViewCompat.getLayoutDirection(parent))
+                    || (mBehavior != null && mBehavior.layoutDependsOn(parent, child, dependency));
+        }
+
+        /**
+         * Invalidate the cached anchor view and direct child ancestor of that anchor.
+         * The anchor will need to be
+         * {@link #findAnchorView(CoordinatorLayout, View) found} before
+         * being used again.
+         */
+        void invalidateAnchor() {
+            mAnchorView = mAnchorDirectChild = null;
+        }
+
+        /**
+         * Locate the appropriate anchor view by the current {@link #setAnchorId(int) anchor id}
+         * or return the cached anchor view if already known.
+         *
+         * @param parent the parent CoordinatorLayout
+         * @param forChild the child this LayoutParams is associated with
+         * @return the located descendant anchor view, or null if the anchor id is
+         *         {@link View#NO_ID}.
+         */
+        View findAnchorView(CoordinatorLayout parent, View forChild) {
+            if (mAnchorId == View.NO_ID) {
+                mAnchorView = mAnchorDirectChild = null;
+                return null;
+            }
+
+            if (mAnchorView == null || !verifyAnchorView(forChild, parent)) {
+                resolveAnchorView(forChild, parent);
+            }
+            return mAnchorView;
+        }
+
+        /**
+         * Determine the anchor view for the child view this LayoutParams is assigned to.
+         * Assumes mAnchorId is valid.
+         */
+        private void resolveAnchorView(final View forChild, final CoordinatorLayout parent) {
+            mAnchorView = parent.findViewById(mAnchorId);
+            if (mAnchorView != null) {
+                if (mAnchorView == parent) {
+                    if (parent.isInEditMode()) {
+                        mAnchorView = mAnchorDirectChild = null;
+                        return;
+                    }
+                    throw new IllegalStateException(
+                            "View can not be anchored to the the parent CoordinatorLayout");
+                }
+
+                View directChild = mAnchorView;
+                for (ViewParent p = mAnchorView.getParent();
+                        p != parent && p != null;
+                        p = p.getParent()) {
+                    if (p == forChild) {
+                        if (parent.isInEditMode()) {
+                            mAnchorView = mAnchorDirectChild = null;
+                            return;
+                        }
+                        throw new IllegalStateException(
+                                "Anchor must not be a descendant of the anchored view");
+                    }
+                    if (p instanceof View) {
+                        directChild = (View) p;
+                    }
+                }
+                mAnchorDirectChild = directChild;
+            } else {
+                if (parent.isInEditMode()) {
+                    mAnchorView = mAnchorDirectChild = null;
+                    return;
+                }
+                throw new IllegalStateException("Could not find CoordinatorLayout descendant view"
+                        + " with id " + parent.getResources().getResourceName(mAnchorId)
+                        + " to anchor view " + forChild);
+            }
+        }
+
+        /**
+         * Verify that the previously resolved anchor view is still valid - that it is still
+         * a descendant of the expected parent view, it is not the child this LayoutParams
+         * is assigned to or a descendant of it, and it has the expected id.
+         */
+        private boolean verifyAnchorView(View forChild, CoordinatorLayout parent) {
+            if (mAnchorView.getId() != mAnchorId) {
+                return false;
+            }
+
+            View directChild = mAnchorView;
+            for (ViewParent p = mAnchorView.getParent();
+                    p != parent;
+                    p = p.getParent()) {
+                if (p == null || p == forChild) {
+                    mAnchorView = mAnchorDirectChild = null;
+                    return false;
+                }
+                if (p instanceof View) {
+                    directChild = (View) p;
+                }
+            }
+            mAnchorDirectChild = directChild;
+            return true;
+        }
+
+        /**
+         * Checks whether the view with this LayoutParams should dodge the specified view.
+         */
+        private boolean shouldDodge(View other, int layoutDirection) {
+            LayoutParams lp = (LayoutParams) other.getLayoutParams();
+            final int absInset = GravityCompat.getAbsoluteGravity(lp.insetEdge, layoutDirection);
+            return absInset != Gravity.NO_GRAVITY && (absInset &
+                    GravityCompat.getAbsoluteGravity(dodgeInsetEdges, layoutDirection)) == absInset;
+        }
+    }
+
+    private class HierarchyChangeListener implements OnHierarchyChangeListener {
+        HierarchyChangeListener() {
+        }
+
+        @Override
+        public void onChildViewAdded(View parent, View child) {
+            if (mOnHierarchyChangeListener != null) {
+                mOnHierarchyChangeListener.onChildViewAdded(parent, child);
+            }
+        }
+
+        @Override
+        public void onChildViewRemoved(View parent, View child) {
+            onChildViewsChanged(EVENT_VIEW_REMOVED);
+
+            if (mOnHierarchyChangeListener != null) {
+                mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
+            }
+        }
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        final SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        final SparseArray<Parcelable> behaviorStates = ss.behaviorStates;
+
+        for (int i = 0, count = getChildCount(); i < count; i++) {
+            final View child = getChildAt(i);
+            final int childId = child.getId();
+            final LayoutParams lp = getResolvedLayoutParams(child);
+            final Behavior b = lp.getBehavior();
+
+            if (childId != NO_ID && b != null) {
+                Parcelable savedState = behaviorStates.get(childId);
+                if (savedState != null) {
+                    b.onRestoreInstanceState(this, child, savedState);
+                }
+            }
+        }
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        final SavedState ss = new SavedState(super.onSaveInstanceState());
+
+        final SparseArray<Parcelable> behaviorStates = new SparseArray<>();
+        for (int i = 0, count = getChildCount(); i < count; i++) {
+            final View child = getChildAt(i);
+            final int childId = child.getId();
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            final Behavior b = lp.getBehavior();
+
+            if (childId != NO_ID && b != null) {
+                // If the child has an ID and a Behavior, let it save some state...
+                Parcelable state = b.onSaveInstanceState(this, child);
+                if (state != null) {
+                    behaviorStates.append(childId, state);
+                }
+            }
+        }
+        ss.behaviorStates = behaviorStates;
+        return ss;
+    }
+
+    @Override
+    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        final Behavior behavior = lp.getBehavior();
+
+        if (behavior != null
+                && behavior.onRequestChildRectangleOnScreen(this, child, rectangle, immediate)) {
+            return true;
+        }
+
+        return super.requestChildRectangleOnScreen(child, rectangle, immediate);
+    }
+
+    private void setupForInsets() {
+        if (Build.VERSION.SDK_INT < 21) {
+            return;
+        }
+
+        if (ViewCompat.getFitsSystemWindows(this)) {
+            if (mApplyWindowInsetsListener == null) {
+                mApplyWindowInsetsListener =
+                        new android.support.v4.view.OnApplyWindowInsetsListener() {
+                            @Override
+                            public WindowInsetsCompat onApplyWindowInsets(View v,
+                                    WindowInsetsCompat insets) {
+                                return setWindowInsets(insets);
+                            }
+                        };
+            }
+            // First apply the insets listener
+            ViewCompat.setOnApplyWindowInsetsListener(this, mApplyWindowInsetsListener);
+
+            // Now set the sys ui flags to enable us to lay out in the window insets
+            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+        } else {
+            ViewCompat.setOnApplyWindowInsetsListener(this, null);
+        }
+    }
+
+    protected static class SavedState extends AbsSavedState {
+        SparseArray<Parcelable> behaviorStates;
+
+        public SavedState(Parcel source, ClassLoader loader) {
+            super(source, loader);
+
+            final int size = source.readInt();
+
+            final int[] ids = new int[size];
+            source.readIntArray(ids);
+
+            final Parcelable[] states = source.readParcelableArray(loader);
+
+            behaviorStates = new SparseArray<>(size);
+            for (int i = 0; i < size; i++) {
+                behaviorStates.append(ids[i], states[i]);
+            }
+        }
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+
+            final int size = behaviorStates != null ? behaviorStates.size() : 0;
+            dest.writeInt(size);
+
+            final int[] ids = new int[size];
+            final Parcelable[] states = new Parcelable[size];
+
+            for (int i = 0; i < size; i++) {
+                ids[i] = behaviorStates.keyAt(i);
+                states[i] = behaviorStates.valueAt(i);
+            }
+            dest.writeIntArray(ids);
+            dest.writeParcelableArray(states, flags);
+
+        }
+
+        public static final Creator<SavedState> CREATOR =
+                new ClassLoaderCreator<SavedState>() {
+                    @Override
+                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                        return new SavedState(in, loader);
+                    }
+
+                    @Override
+                    public SavedState createFromParcel(Parcel in) {
+                        return new SavedState(in, null);
+                    }
+
+                    @Override
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
+    }
+}
diff --git a/core-ui/src/main/java/android/support/v4/widget/DirectedAcyclicGraph.java b/coordinatorlayout/src/main/java/android/support/v4/widget/DirectedAcyclicGraph.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/DirectedAcyclicGraph.java
rename to coordinatorlayout/src/main/java/android/support/v4/widget/DirectedAcyclicGraph.java
diff --git a/core-ui/src/main/java/android/support/v4/widget/ViewGroupUtils.java b/coordinatorlayout/src/main/java/android/support/v4/widget/ViewGroupUtils.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/ViewGroupUtils.java
rename to coordinatorlayout/src/main/java/android/support/v4/widget/ViewGroupUtils.java
diff --git a/core-ui/res-public/values/public_attrs.xml b/coordinatorlayout/src/main/res-public/values/public_attrs.xml
similarity index 100%
rename from core-ui/res-public/values/public_attrs.xml
rename to coordinatorlayout/src/main/res-public/values/public_attrs.xml
diff --git a/core-ui/res-public/values/public_styles.xml b/coordinatorlayout/src/main/res-public/values/public_styles.xml
similarity index 100%
rename from core-ui/res-public/values/public_styles.xml
rename to coordinatorlayout/src/main/res-public/values/public_styles.xml
diff --git a/core-ui/res/values/attrs.xml b/coordinatorlayout/src/main/res/values/attrs.xml
similarity index 100%
rename from core-ui/res/values/attrs.xml
rename to coordinatorlayout/src/main/res/values/attrs.xml
diff --git a/core-ui/res/values/styles.xml b/coordinatorlayout/src/main/res/values/styles.xml
similarity index 100%
rename from core-ui/res/values/styles.xml
rename to coordinatorlayout/src/main/res/values/styles.xml
diff --git a/core-ui/Android.mk b/core-ui/Android.mk
deleted file mode 100644
index 1473381..0000000
--- a/core-ui/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-core-ui \
-#       android-support-compat
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-core-ui
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat \
-    android-support-core-utils
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-LOCAL_EXPORT_PROGUARD_FLAG_FILES := proguard-rules.pro
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/core-ui/AndroidManifest.xml b/core-ui/AndroidManifest.xml
deleted file mode 100644
index f498d26..0000000
--- a/core-ui/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.coreui">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/core-ui/api/27.1.0.ignore b/core-ui/api/27.1.0.ignore
new file mode 100644
index 0000000..5175a59
--- /dev/null
+++ b/core-ui/api/27.1.0.ignore
@@ -0,0 +1,29 @@
+21edeac
+c8f5cd8
+c6c4dfc
+528a17a
+3ee7015
+9dbd12a
+9d26569
+897caa3
+0a4a21e
+9a73d77
+2812bc8
+2b135f6
+6862ae7
+15490c8
+1bdc70f
+c79ca3e
+40d58a6
+3251849
+d95e163
+56b0aa1
+c9f0c98
+4a9b508
+0058a00
+28bb044
+8a30c7e
+19e12f3
+b7ca703
+c4280d0
+1017c49
diff --git a/core-ui/api/current.txt b/core-ui/api/current.txt
index 815d6e3..6aa3e11 100644
--- a/core-ui/api/current.txt
+++ b/core-ui/api/current.txt
@@ -1,100 +1,3 @@
-package android.support.design.widget {
-
-  public class CoordinatorLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingParent2 {
-    ctor public CoordinatorLayout(android.content.Context);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void dispatchDependentViewsChanged(android.view.View);
-    method public boolean doViewsOverlap(android.view.View, android.view.View);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public java.util.List<android.view.View> getDependencies(android.view.View);
-    method public java.util.List<android.view.View> getDependents(android.view.View);
-    method public android.graphics.drawable.Drawable getStatusBarBackground();
-    method public boolean isPointInChildBounds(android.view.View, int, int);
-    method public void onAttachedToWindow();
-    method public void onDetachedFromWindow();
-    method public void onDraw(android.graphics.Canvas);
-    method public void onLayoutChild(android.view.View, int);
-    method public void onMeasureChild(android.view.View, int, int, int, int);
-    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.view.View, int, int, int, int, int);
-    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
-    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.view.View, int);
-    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
-    method public void setStatusBarBackgroundColor(int);
-    method public void setStatusBarBackgroundResource(int);
-  }
-
-  public static abstract interface CoordinatorLayout.AttachedBehavior {
-    method public abstract android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
-  }
-
-  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
-    ctor public CoordinatorLayout.Behavior();
-    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
-    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
-    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
-    method public static java.lang.Object getTag(android.view.View);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
-    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDetachedFromLayoutParams();
-    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
-    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
-    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
-    method public deprecated void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[], int);
-    method public deprecated void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int, int);
-    method public deprecated void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
-    method public deprecated boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public deprecated void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int);
-    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public static void setTag(android.view.View, java.lang.Object);
-  }
-
-  public static abstract deprecated class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
-  }
-
-  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public CoordinatorLayout.LayoutParams(int, int);
-    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getAnchorId();
-    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
-    method public void setAnchorId(int);
-    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
-    field public int anchorGravity;
-    field public int dodgeInsetEdges;
-    field public int gravity;
-    field public int insetEdge;
-    field public int keyline;
-  }
-
-  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
-  }
-
-}
-
 package android.support.v4.app {
 
   public deprecated class ActionBarDrawerToggle implements android.support.v4.widget.DrawerLayout.DrawerListener {
@@ -125,523 +28,8 @@
 
 }
 
-package android.support.v4.view {
-
-  public abstract class AbsSavedState implements android.os.Parcelable {
-    ctor protected AbsSavedState(android.os.Parcelable);
-    ctor protected AbsSavedState(android.os.Parcel);
-    ctor protected AbsSavedState(android.os.Parcel, java.lang.ClassLoader);
-    method public int describeContents();
-    method public final android.os.Parcelable getSuperState();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.support.v4.view.AbsSavedState> CREATOR;
-    field public static final android.support.v4.view.AbsSavedState EMPTY_STATE;
-  }
-
-  public final class AsyncLayoutInflater {
-    ctor public AsyncLayoutInflater(android.content.Context);
-    method public void inflate(int, android.view.ViewGroup, android.support.v4.view.AsyncLayoutInflater.OnInflateFinishedListener);
-  }
-
-  public static abstract interface AsyncLayoutInflater.OnInflateFinishedListener {
-    method public abstract void onInflateFinished(android.view.View, int, android.view.ViewGroup);
-  }
-
-  public class NestedScrollingChildHelper {
-    ctor public NestedScrollingChildHelper(android.view.View);
-    method public boolean dispatchNestedFling(float, float, boolean);
-    method public boolean dispatchNestedPreFling(float, float);
-    method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
-    method public boolean dispatchNestedPreScroll(int, int, int[], int[], int);
-    method public boolean dispatchNestedScroll(int, int, int, int, int[]);
-    method public boolean dispatchNestedScroll(int, int, int, int, int[], int);
-    method public boolean hasNestedScrollingParent();
-    method public boolean hasNestedScrollingParent(int);
-    method public boolean isNestedScrollingEnabled();
-    method public void onDetachedFromWindow();
-    method public void onStopNestedScroll(android.view.View);
-    method public void setNestedScrollingEnabled(boolean);
-    method public boolean startNestedScroll(int);
-    method public boolean startNestedScroll(int, int);
-    method public void stopNestedScroll();
-    method public void stopNestedScroll(int);
-  }
-
-  public class NestedScrollingParentHelper {
-    ctor public NestedScrollingParentHelper(android.view.ViewGroup);
-    method public int getNestedScrollAxes();
-    method public void onNestedScrollAccepted(android.view.View, android.view.View, int);
-    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.view.View);
-    method public void onStopNestedScroll(android.view.View, int);
-  }
-
-  public abstract class PagerAdapter {
-    ctor public PagerAdapter();
-    method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
-    method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
-    method public void finishUpdate(android.view.ViewGroup);
-    method public deprecated void finishUpdate(android.view.View);
-    method public abstract int getCount();
-    method public int getItemPosition(java.lang.Object);
-    method public java.lang.CharSequence getPageTitle(int);
-    method public float getPageWidth(int);
-    method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
-    method public deprecated java.lang.Object instantiateItem(android.view.View, int);
-    method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
-    method public void notifyDataSetChanged();
-    method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
-    method public android.os.Parcelable saveState();
-    method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
-    method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
-    method public void startUpdate(android.view.ViewGroup);
-    method public deprecated void startUpdate(android.view.View);
-    method public void unregisterDataSetObserver(android.database.DataSetObserver);
-    field public static final int POSITION_NONE = -2; // 0xfffffffe
-    field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
-  }
-
-  public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
-    ctor public PagerTabStrip(android.content.Context);
-    ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
-    method public boolean getDrawFullUnderline();
-    method public int getTabIndicatorColor();
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setDrawFullUnderline(boolean);
-    method public void setTabIndicatorColor(int);
-    method public void setTabIndicatorColorResource(int);
-  }
-
-  public class PagerTitleStrip extends android.view.ViewGroup {
-    ctor public PagerTitleStrip(android.content.Context);
-    ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
-    method public int getTextSpacing();
-    method public void setGravity(int);
-    method public void setNonPrimaryAlpha(float);
-    method public void setTextColor(int);
-    method public void setTextSize(int, float);
-    method public void setTextSpacing(int);
-  }
-
-  public class ViewPager extends android.view.ViewGroup {
-    ctor public ViewPager(android.content.Context);
-    ctor public ViewPager(android.content.Context, android.util.AttributeSet);
-    method public void addOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
-    method public void addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
-    method public boolean arrowScroll(int);
-    method public boolean beginFakeDrag();
-    method protected boolean canScroll(android.view.View, boolean, int, int, int);
-    method public void clearOnPageChangeListeners();
-    method public void endFakeDrag();
-    method public boolean executeKeyEvent(android.view.KeyEvent);
-    method public void fakeDragBy(float);
-    method public android.support.v4.view.PagerAdapter getAdapter();
-    method public int getCurrentItem();
-    method public int getOffscreenPageLimit();
-    method public int getPageMargin();
-    method public boolean isFakeDragging();
-    method protected void onPageScrolled(int, float, int);
-    method public void onRestoreInstanceState(android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState();
-    method public void removeOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
-    method public void removeOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
-    method public void setAdapter(android.support.v4.view.PagerAdapter);
-    method public void setCurrentItem(int);
-    method public void setCurrentItem(int, boolean);
-    method public void setOffscreenPageLimit(int);
-    method public deprecated void setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
-    method public void setPageMargin(int);
-    method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
-    method public void setPageMarginDrawable(int);
-    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
-    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer, int);
-    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
-    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
-    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
-  }
-
-  public static abstract class ViewPager.DecorView implements java.lang.annotation.Annotation {
-  }
-
-  public static class ViewPager.LayoutParams extends android.view.ViewGroup.LayoutParams {
-    ctor public ViewPager.LayoutParams();
-    ctor public ViewPager.LayoutParams(android.content.Context, android.util.AttributeSet);
-    field public int gravity;
-    field public boolean isDecor;
-  }
-
-  public static abstract interface ViewPager.OnAdapterChangeListener {
-    method public abstract void onAdapterChanged(android.support.v4.view.ViewPager, android.support.v4.view.PagerAdapter, android.support.v4.view.PagerAdapter);
-  }
-
-  public static abstract interface ViewPager.OnPageChangeListener {
-    method public abstract void onPageScrollStateChanged(int);
-    method public abstract void onPageScrolled(int, float, int);
-    method public abstract void onPageSelected(int);
-  }
-
-  public static abstract interface ViewPager.PageTransformer {
-    method public abstract void transformPage(android.view.View, float);
-  }
-
-  public static class ViewPager.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public ViewPager.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.v4.view.ViewPager.SavedState> CREATOR;
-  }
-
-  public static class ViewPager.SimpleOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
-    ctor public ViewPager.SimpleOnPageChangeListener();
-    method public void onPageScrollStateChanged(int);
-    method public void onPageScrolled(int, float, int);
-    method public void onPageSelected(int);
-  }
-
-}
-
-package android.support.v4.view.animation {
-
-  public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
-    ctor public FastOutLinearInInterpolator();
-  }
-
-  public class FastOutSlowInInterpolator implements android.view.animation.Interpolator {
-    ctor public FastOutSlowInInterpolator();
-  }
-
-  public class LinearOutSlowInInterpolator implements android.view.animation.Interpolator {
-    ctor public LinearOutSlowInInterpolator();
-  }
-
-}
-
 package android.support.v4.widget {
 
-  public abstract class AutoScrollHelper implements android.view.View.OnTouchListener {
-    ctor public AutoScrollHelper(android.view.View);
-    method public abstract boolean canTargetScrollHorizontally(int);
-    method public abstract boolean canTargetScrollVertically(int);
-    method public boolean isEnabled();
-    method public boolean isExclusive();
-    method public boolean onTouch(android.view.View, android.view.MotionEvent);
-    method public abstract void scrollTargetBy(int, int);
-    method public android.support.v4.widget.AutoScrollHelper setActivationDelay(int);
-    method public android.support.v4.widget.AutoScrollHelper setEdgeType(int);
-    method public android.support.v4.widget.AutoScrollHelper setEnabled(boolean);
-    method public android.support.v4.widget.AutoScrollHelper setExclusive(boolean);
-    method public android.support.v4.widget.AutoScrollHelper setMaximumEdges(float, float);
-    method public android.support.v4.widget.AutoScrollHelper setMaximumVelocity(float, float);
-    method public android.support.v4.widget.AutoScrollHelper setMinimumVelocity(float, float);
-    method public android.support.v4.widget.AutoScrollHelper setRampDownDuration(int);
-    method public android.support.v4.widget.AutoScrollHelper setRampUpDuration(int);
-    method public android.support.v4.widget.AutoScrollHelper setRelativeEdges(float, float);
-    method public android.support.v4.widget.AutoScrollHelper setRelativeVelocity(float, float);
-    field public static final int EDGE_TYPE_INSIDE = 0; // 0x0
-    field public static final int EDGE_TYPE_INSIDE_EXTEND = 1; // 0x1
-    field public static final int EDGE_TYPE_OUTSIDE = 2; // 0x2
-    field public static final float NO_MAX = 3.4028235E38f;
-    field public static final float NO_MIN = 0.0f;
-    field public static final float RELATIVE_UNSPECIFIED = 0.0f;
-  }
-
-  public class CircularProgressDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
-    ctor public CircularProgressDrawable(android.content.Context);
-    method public void draw(android.graphics.Canvas);
-    method public boolean getArrowEnabled();
-    method public float getArrowHeight();
-    method public float getArrowScale();
-    method public float getArrowWidth();
-    method public int getBackgroundColor();
-    method public float getCenterRadius();
-    method public int[] getColorSchemeColors();
-    method public float getEndTrim();
-    method public int getOpacity();
-    method public float getProgressRotation();
-    method public float getStartTrim();
-    method public android.graphics.Paint.Cap getStrokeCap();
-    method public float getStrokeWidth();
-    method public boolean isRunning();
-    method public void setAlpha(int);
-    method public void setArrowDimensions(float, float);
-    method public void setArrowEnabled(boolean);
-    method public void setArrowScale(float);
-    method public void setBackgroundColor(int);
-    method public void setCenterRadius(float);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setColorSchemeColors(int...);
-    method public void setProgressRotation(float);
-    method public void setStartEndTrim(float, float);
-    method public void setStrokeCap(android.graphics.Paint.Cap);
-    method public void setStrokeWidth(float);
-    method public void setStyle(int);
-    method public void start();
-    method public void stop();
-    field public static final int DEFAULT = 1; // 0x1
-    field public static final int LARGE = 0; // 0x0
-  }
-
-  public class ContentLoadingProgressBar extends android.widget.ProgressBar {
-    ctor public ContentLoadingProgressBar(android.content.Context);
-    ctor public ContentLoadingProgressBar(android.content.Context, android.util.AttributeSet);
-    method public synchronized void hide();
-    method public void onAttachedToWindow();
-    method public void onDetachedFromWindow();
-    method public synchronized void show();
-  }
-
-  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
-    ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
-    ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
-    ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
-    method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
-    method public void changeCursor(android.database.Cursor);
-    method public java.lang.CharSequence convertToString(android.database.Cursor);
-    method public int getCount();
-    method public android.database.Cursor getCursor();
-    method public android.widget.Filter getFilter();
-    method public android.widget.FilterQueryProvider getFilterQueryProvider();
-    method public java.lang.Object getItem(int);
-    method public long getItemId(int);
-    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
-    method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
-    method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
-    method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
-    method protected void onContentChanged();
-    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
-    method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
-    method public android.database.Cursor swapCursor(android.database.Cursor);
-    field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
-    field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
-  }
-
-  public class DrawerLayout extends android.view.ViewGroup {
-    ctor public DrawerLayout(android.content.Context);
-    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
-    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void addDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
-    method public void closeDrawer(android.view.View);
-    method public void closeDrawer(android.view.View, boolean);
-    method public void closeDrawer(int);
-    method public void closeDrawer(int, boolean);
-    method public void closeDrawers();
-    method public float getDrawerElevation();
-    method public int getDrawerLockMode(int);
-    method public int getDrawerLockMode(android.view.View);
-    method public java.lang.CharSequence getDrawerTitle(int);
-    method public android.graphics.drawable.Drawable getStatusBarBackgroundDrawable();
-    method public boolean isDrawerOpen(android.view.View);
-    method public boolean isDrawerOpen(int);
-    method public boolean isDrawerVisible(android.view.View);
-    method public boolean isDrawerVisible(int);
-    method public void onDraw(android.graphics.Canvas);
-    method public void openDrawer(android.view.View);
-    method public void openDrawer(android.view.View, boolean);
-    method public void openDrawer(int);
-    method public void openDrawer(int, boolean);
-    method public void removeDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
-    method public void setDrawerElevation(float);
-    method public deprecated void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
-    method public void setDrawerLockMode(int);
-    method public void setDrawerLockMode(int, int);
-    method public void setDrawerLockMode(int, android.view.View);
-    method public void setDrawerShadow(android.graphics.drawable.Drawable, int);
-    method public void setDrawerShadow(int, int);
-    method public void setDrawerTitle(int, java.lang.CharSequence);
-    method public void setScrimColor(int);
-    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
-    method public void setStatusBarBackground(int);
-    method public void setStatusBarBackgroundColor(int);
-    field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
-    field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
-    field public static final int LOCK_MODE_UNDEFINED = 3; // 0x3
-    field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_IDLE = 0; // 0x0
-    field public static final int STATE_SETTLING = 2; // 0x2
-  }
-
-  public static abstract interface DrawerLayout.DrawerListener {
-    method public abstract void onDrawerClosed(android.view.View);
-    method public abstract void onDrawerOpened(android.view.View);
-    method public abstract void onDrawerSlide(android.view.View, float);
-    method public abstract void onDrawerStateChanged(int);
-  }
-
-  public static class DrawerLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public DrawerLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public DrawerLayout.LayoutParams(int, int);
-    ctor public DrawerLayout.LayoutParams(int, int, int);
-    ctor public DrawerLayout.LayoutParams(android.support.v4.widget.DrawerLayout.LayoutParams);
-    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    field public int gravity;
-  }
-
-  protected static class DrawerLayout.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public DrawerLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public DrawerLayout.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.v4.widget.DrawerLayout.SavedState> CREATOR;
-  }
-
-  public static abstract class DrawerLayout.SimpleDrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
-    ctor public DrawerLayout.SimpleDrawerListener();
-    method public void onDrawerClosed(android.view.View);
-    method public void onDrawerOpened(android.view.View);
-    method public void onDrawerSlide(android.view.View, float);
-    method public void onDrawerStateChanged(int);
-  }
-
-  public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
-    ctor public ExploreByTouchHelper(android.view.View);
-    method public final boolean clearKeyboardFocusForVirtualView(int);
-    method public final boolean dispatchHoverEvent(android.view.MotionEvent);
-    method public final boolean dispatchKeyEvent(android.view.KeyEvent);
-    method public final int getAccessibilityFocusedVirtualViewId();
-    method public deprecated int getFocusedVirtualView();
-    method public final int getKeyboardFocusedVirtualViewId();
-    method protected abstract int getVirtualViewAt(float, float);
-    method protected abstract void getVisibleVirtualViews(java.util.List<java.lang.Integer>);
-    method public final void invalidateRoot();
-    method public final void invalidateVirtualView(int);
-    method public final void invalidateVirtualView(int, int);
-    method public final void onFocusChanged(boolean, int, android.graphics.Rect);
-    method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
-    method protected void onPopulateEventForHost(android.view.accessibility.AccessibilityEvent);
-    method protected void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
-    method protected void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
-    method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
-    method protected void onVirtualViewKeyboardFocusChanged(int, boolean);
-    method public final boolean requestKeyboardFocusForVirtualView(int);
-    method public final boolean sendEventForVirtualView(int, int);
-    field public static final int HOST_ID = -1; // 0xffffffff
-    field public static final int INVALID_ID = -2147483648; // 0x80000000
-  }
-
-  public class ListViewAutoScrollHelper extends android.support.v4.widget.AutoScrollHelper {
-    ctor public ListViewAutoScrollHelper(android.widget.ListView);
-    method public boolean canTargetScrollHorizontally(int);
-    method public boolean canTargetScrollVertically(int);
-    method public void scrollTargetBy(int, int);
-  }
-
-  public class NestedScrollView extends android.widget.FrameLayout implements android.support.v4.view.NestedScrollingChild2 android.support.v4.view.NestedScrollingParent android.support.v4.view.ScrollingView {
-    ctor public NestedScrollView(android.content.Context);
-    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet);
-    ctor public NestedScrollView(android.content.Context, android.util.AttributeSet, int);
-    method public boolean arrowScroll(int);
-    method public int computeHorizontalScrollExtent();
-    method public int computeHorizontalScrollOffset();
-    method public int computeHorizontalScrollRange();
-    method protected int computeScrollDeltaToGetChildRectOnScreen(android.graphics.Rect);
-    method public int computeVerticalScrollExtent();
-    method public int computeVerticalScrollOffset();
-    method public int computeVerticalScrollRange();
-    method public boolean dispatchNestedPreScroll(int, int, int[], int[], int);
-    method public boolean dispatchNestedScroll(int, int, int, int, int[], int);
-    method public boolean executeKeyEvent(android.view.KeyEvent);
-    method public void fling(int);
-    method public boolean fullScroll(int);
-    method public int getMaxScrollAmount();
-    method public boolean hasNestedScrollingParent(int);
-    method public boolean isFillViewport();
-    method public boolean isSmoothScrollingEnabled();
-    method public void onAttachedToWindow();
-    method public boolean pageScroll(int);
-    method public void setFillViewport(boolean);
-    method public void setOnScrollChangeListener(android.support.v4.widget.NestedScrollView.OnScrollChangeListener);
-    method public void setSmoothScrollingEnabled(boolean);
-    method public final void smoothScrollBy(int, int);
-    method public final void smoothScrollTo(int, int);
-    method public boolean startNestedScroll(int, int);
-    method public void stopNestedScroll(int);
-  }
-
-  public static abstract interface NestedScrollView.OnScrollChangeListener {
-    method public abstract void onScrollChange(android.support.v4.widget.NestedScrollView, int, int, int, int);
-  }
-
-  public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
-    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
-    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
-    ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
-    method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
-    method public void setDropDownViewResource(int);
-    method public void setViewResource(int);
-  }
-
-  public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
-    ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
-    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
-    method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
-    method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
-    method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
-    method public int getStringConversionColumn();
-    method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
-    method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
-    method public void setStringConversionColumn(int);
-    method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
-    method public void setViewImage(android.widget.ImageView, java.lang.String);
-    method public void setViewText(android.widget.TextView, java.lang.String);
-  }
-
-  public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
-    method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
-  }
-
-  public static abstract interface SimpleCursorAdapter.ViewBinder {
-    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
-  }
-
-  public class SlidingPaneLayout extends android.view.ViewGroup {
-    ctor public SlidingPaneLayout(android.content.Context);
-    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
-    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
-    method protected boolean canScroll(android.view.View, boolean, int, int, int);
-    method public deprecated boolean canSlide();
-    method public boolean closePane();
-    method public int getCoveredFadeColor();
-    method public int getParallaxDistance();
-    method public int getSliderFadeColor();
-    method public boolean isOpen();
-    method public boolean isSlideable();
-    method public boolean openPane();
-    method public void setCoveredFadeColor(int);
-    method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
-    method public void setParallaxDistance(int);
-    method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
-    method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
-    method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
-    method public deprecated void setShadowResource(int);
-    method public void setShadowResourceLeft(int);
-    method public void setShadowResourceRight(int);
-    method public void setSliderFadeColor(int);
-    method public deprecated void smoothSlideClosed();
-    method public deprecated void smoothSlideOpen();
-  }
-
-  public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public SlidingPaneLayout.LayoutParams();
-    ctor public SlidingPaneLayout.LayoutParams(int, int);
-    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
-    ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    field public float weight;
-  }
-
-  public static abstract interface SlidingPaneLayout.PanelSlideListener {
-    method public abstract void onPanelClosed(android.view.View);
-    method public abstract void onPanelOpened(android.view.View);
-    method public abstract void onPanelSlide(android.view.View, float);
-  }
-
-  public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
-    ctor public SlidingPaneLayout.SimplePanelSlideListener();
-    method public void onPanelClosed(android.view.View);
-    method public void onPanelOpened(android.view.View);
-    method public void onPanelSlide(android.view.View, float);
-  }
-
   public deprecated class Space extends android.view.View {
     ctor public deprecated Space(android.content.Context, android.util.AttributeSet, int);
     ctor public deprecated Space(android.content.Context, android.util.AttributeSet);
@@ -650,101 +38,5 @@
     method protected deprecated void onMeasure(int, int);
   }
 
-  public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
-    ctor public SwipeRefreshLayout(android.content.Context);
-    ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
-    method public boolean canChildScrollUp();
-    method public int getProgressCircleDiameter();
-    method public int getProgressViewEndOffset();
-    method public int getProgressViewStartOffset();
-    method public boolean isRefreshing();
-    method public void onMeasure(int, int);
-    method public deprecated void setColorScheme(int...);
-    method public void setColorSchemeColors(int...);
-    method public void setColorSchemeResources(int...);
-    method public void setDistanceToTriggerSync(int);
-    method public void setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback);
-    method public void setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener);
-    method public deprecated void setProgressBackgroundColor(int);
-    method public void setProgressBackgroundColorSchemeColor(int);
-    method public void setProgressBackgroundColorSchemeResource(int);
-    method public void setProgressViewEndTarget(boolean, int);
-    method public void setProgressViewOffset(boolean, int, int);
-    method public void setRefreshing(boolean);
-    method public void setSize(int);
-    field public static final int DEFAULT = 1; // 0x1
-    field public static final int LARGE = 0; // 0x0
-    field protected int mFrom;
-    field protected int mOriginalOffsetTop;
-  }
-
-  public static abstract interface SwipeRefreshLayout.OnChildScrollUpCallback {
-    method public abstract boolean canChildScrollUp(android.support.v4.widget.SwipeRefreshLayout, android.view.View);
-  }
-
-  public static abstract interface SwipeRefreshLayout.OnRefreshListener {
-    method public abstract void onRefresh();
-  }
-
-  public class ViewDragHelper {
-    method public void abort();
-    method protected boolean canScroll(android.view.View, boolean, int, int, int, int);
-    method public void cancel();
-    method public void captureChildView(android.view.View, int);
-    method public boolean checkTouchSlop(int);
-    method public boolean checkTouchSlop(int, int);
-    method public boolean continueSettling(boolean);
-    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, android.support.v4.widget.ViewDragHelper.Callback);
-    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, float, android.support.v4.widget.ViewDragHelper.Callback);
-    method public android.view.View findTopChildUnder(int, int);
-    method public void flingCapturedView(int, int, int, int);
-    method public int getActivePointerId();
-    method public android.view.View getCapturedView();
-    method public int getEdgeSize();
-    method public float getMinVelocity();
-    method public int getTouchSlop();
-    method public int getViewDragState();
-    method public boolean isCapturedViewUnder(int, int);
-    method public boolean isEdgeTouched(int);
-    method public boolean isEdgeTouched(int, int);
-    method public boolean isPointerDown(int);
-    method public boolean isViewUnder(android.view.View, int, int);
-    method public void processTouchEvent(android.view.MotionEvent);
-    method public void setEdgeTrackingEnabled(int);
-    method public void setMinVelocity(float);
-    method public boolean settleCapturedViewAt(int, int);
-    method public boolean shouldInterceptTouchEvent(android.view.MotionEvent);
-    method public boolean smoothSlideViewTo(android.view.View, int, int);
-    field public static final int DIRECTION_ALL = 3; // 0x3
-    field public static final int DIRECTION_HORIZONTAL = 1; // 0x1
-    field public static final int DIRECTION_VERTICAL = 2; // 0x2
-    field public static final int EDGE_ALL = 15; // 0xf
-    field public static final int EDGE_BOTTOM = 8; // 0x8
-    field public static final int EDGE_LEFT = 1; // 0x1
-    field public static final int EDGE_RIGHT = 2; // 0x2
-    field public static final int EDGE_TOP = 4; // 0x4
-    field public static final int INVALID_POINTER = -1; // 0xffffffff
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_IDLE = 0; // 0x0
-    field public static final int STATE_SETTLING = 2; // 0x2
-  }
-
-  public static abstract class ViewDragHelper.Callback {
-    ctor public ViewDragHelper.Callback();
-    method public int clampViewPositionHorizontal(android.view.View, int, int);
-    method public int clampViewPositionVertical(android.view.View, int, int);
-    method public int getOrderedChildIndex(int);
-    method public int getViewHorizontalDragRange(android.view.View);
-    method public int getViewVerticalDragRange(android.view.View);
-    method public void onEdgeDragStarted(int, int);
-    method public boolean onEdgeLock(int);
-    method public void onEdgeTouched(int, int);
-    method public void onViewCaptured(android.view.View, int);
-    method public void onViewDragStateChanged(int);
-    method public void onViewPositionChanged(android.view.View, int, int, int, int);
-    method public void onViewReleased(android.view.View, float, float);
-    method public abstract boolean tryCaptureView(android.view.View, int);
-  }
-
 }
 
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 4ff27cb..12f5525 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -9,7 +9,16 @@
 dependencies {
     api(project(":support-annotations"))
     api(project(":support-compat"))
-    api project(':support-core-utils')
+    api(project(":support-core-utils"))
+    api(project(":customview"))
+    api(project(":viewpager"))
+    api(project(":coordinatorlayout"))
+    api(project(":drawerlayout"))
+    api(project(":slidingpanelayout"))
+    api(project(":interpolator"))
+    api(project(":swiperefreshlayout"))
+    api(project(":asynclayoutinflater"))
+    api(project(":cursoradapter"))
 
     androidTestImplementation(TEST_RUNNER)
     androidTestImplementation(ESPRESSO_CORE)
@@ -22,18 +31,6 @@
     testImplementation(JUNIT)
 }
 
-android {
-    sourceSets {
-        main.res.srcDirs = [
-                'res',
-                'res-public'
-        ]
-    }
-    buildTypes.all {
-        consumerProguardFiles 'proguard-rules.pro'
-    }
-}
-
 supportLibrary {
     name = "Android Support Library core UI"
     publish = true
@@ -41,5 +38,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2011"
     description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
-    legacySourceLocation = true
 }
diff --git a/core-ui/lint-baseline.xml b/core-ui/lint-baseline.xml
deleted file mode 100644
index 5869ece..0000000
--- a/core-ui/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-alpha9">
-
-    <issue
-        id="WrongConstant"
-        message="Must be one or more of: Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END"
-        errorLine1="                            + gravityToString(childGravity) + &quot; but this &quot; + TAG + &quot; already has a &quot;"
-        errorLine2="                                              ~~~~~~~~~~~~">
-        <location
-            file="java/android/support/v4/widget/DrawerLayout.java"
-            line="1075"
-            column="47"/>
-    </issue>
-
-</issues>
diff --git a/core-ui/src/main/AndroidManifest.xml b/core-ui/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c00d503
--- /dev/null
+++ b/core-ui/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.coreui"/>
diff --git a/core-ui/src/main/java/android/support/design/widget/CoordinatorLayout.java b/core-ui/src/main/java/android/support/design/widget/CoordinatorLayout.java
deleted file mode 100644
index ef4d1ed..0000000
--- a/core-ui/src/main/java/android/support/design/widget/CoordinatorLayout.java
+++ /dev/null
@@ -1,3285 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.FloatRange;
-import android.support.annotation.IdRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
-import android.support.coreui.R;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.math.MathUtils;
-import android.support.v4.util.ObjectsCompat;
-import android.support.v4.util.Pools;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.NestedScrollingParent;
-import android.support.v4.view.NestedScrollingParent2;
-import android.support.v4.view.NestedScrollingParentHelper;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewCompat.NestedScrollType;
-import android.support.v4.view.ViewCompat.ScrollAxis;
-import android.support.v4.view.WindowInsetsCompat;
-import android.support.v4.widget.DirectedAcyclicGraph;
-import android.support.v4.widget.ViewGroupUtils;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.ViewTreeObserver;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * CoordinatorLayout is a super-powered {@link android.widget.FrameLayout FrameLayout}.
- *
- * <p>CoordinatorLayout is intended for two primary use cases:</p>
- * <ol>
- *     <li>As a top-level application decor or chrome layout</li>
- *     <li>As a container for a specific interaction with one or more child views</li>
- * </ol>
- *
- * <p>By specifying {@link Behavior Behaviors} for child views of a
- * CoordinatorLayout you can provide many different interactions within a single parent and those
- * views can also interact with one another. View classes can specify a default behavior when
- * used as a child of a CoordinatorLayout using the
- * {@link DefaultBehavior} annotation.</p>
- *
- * <p>Behaviors may be used to implement a variety of interactions and additional layout
- * modifications ranging from sliding drawers and panels to swipe-dismissable elements and buttons
- * that stick to other elements as they move and animate.</p>
- *
- * <p>Children of a CoordinatorLayout may have an
- * {@link LayoutParams#setAnchorId(int) anchor}. This view id must correspond
- * to an arbitrary descendant of the CoordinatorLayout, but it may not be the anchored child itself
- * or a descendant of the anchored child. This can be used to place floating views relative to
- * other arbitrary content panes.</p>
- *
- * <p>Children can specify {@link LayoutParams#insetEdge} to describe how the
- * view insets the CoordinatorLayout. Any child views which are set to dodge the same inset edges by
- * {@link LayoutParams#dodgeInsetEdges} will be moved appropriately so that the
- * views do not overlap.</p>
- */
-public class CoordinatorLayout extends ViewGroup implements NestedScrollingParent2 {
-    static final String TAG = "CoordinatorLayout";
-    static final String WIDGET_PACKAGE_NAME;
-
-    static {
-        final Package pkg = CoordinatorLayout.class.getPackage();
-        WIDGET_PACKAGE_NAME = pkg != null ? pkg.getName() : null;
-    }
-
-    private static final int TYPE_ON_INTERCEPT = 0;
-    private static final int TYPE_ON_TOUCH = 1;
-
-    static {
-        if (Build.VERSION.SDK_INT >= 21) {
-            TOP_SORTED_CHILDREN_COMPARATOR = new ViewElevationComparator();
-        } else {
-            TOP_SORTED_CHILDREN_COMPARATOR = null;
-        }
-    }
-
-    static final Class<?>[] CONSTRUCTOR_PARAMS = new Class<?>[] {
-            Context.class,
-            AttributeSet.class
-    };
-
-    static final ThreadLocal<Map<String, Constructor<Behavior>>> sConstructors =
-            new ThreadLocal<>();
-
-    static final int EVENT_PRE_DRAW = 0;
-    static final int EVENT_NESTED_SCROLL = 1;
-    static final int EVENT_VIEW_REMOVED = 2;
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({EVENT_PRE_DRAW, EVENT_NESTED_SCROLL, EVENT_VIEW_REMOVED})
-    public @interface DispatchChangeEvent {}
-
-    static final Comparator<View> TOP_SORTED_CHILDREN_COMPARATOR;
-    private static final Pools.Pool<Rect> sRectPool = new Pools.SynchronizedPool<>(12);
-
-    @NonNull
-    private static Rect acquireTempRect() {
-        Rect rect = sRectPool.acquire();
-        if (rect == null) {
-            rect = new Rect();
-        }
-        return rect;
-    }
-
-    private static void releaseTempRect(@NonNull Rect rect) {
-        rect.setEmpty();
-        sRectPool.release(rect);
-    }
-
-    private final List<View> mDependencySortedChildren = new ArrayList<>();
-    private final DirectedAcyclicGraph<View> mChildDag = new DirectedAcyclicGraph<>();
-
-    private final List<View> mTempList1 = new ArrayList<>();
-    private final List<View> mTempDependenciesList = new ArrayList<>();
-    private final int[] mTempIntPair = new int[2];
-    private Paint mScrimPaint;
-
-    private boolean mDisallowInterceptReset;
-
-    private boolean mIsAttachedToWindow;
-
-    private int[] mKeylines;
-
-    private View mBehaviorTouchView;
-    private View mNestedScrollingTarget;
-
-    private OnPreDrawListener mOnPreDrawListener;
-    private boolean mNeedsPreDrawListener;
-
-    private WindowInsetsCompat mLastInsets;
-    private boolean mDrawStatusBarBackground;
-    private Drawable mStatusBarBackground;
-
-    OnHierarchyChangeListener mOnHierarchyChangeListener;
-    private android.support.v4.view.OnApplyWindowInsetsListener mApplyWindowInsetsListener;
-
-    private final NestedScrollingParentHelper mNestedScrollingParentHelper =
-            new NestedScrollingParentHelper(this);
-
-    public CoordinatorLayout(Context context) {
-        this(context, null);
-    }
-
-    public CoordinatorLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, R.attr.coordinatorLayoutStyle);
-    }
-
-    public CoordinatorLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        final TypedArray a = (defStyleAttr == 0)
-                ? context.obtainStyledAttributes(attrs, R.styleable.CoordinatorLayout,
-                    0, R.style.Widget_Support_CoordinatorLayout)
-                : context.obtainStyledAttributes(attrs, R.styleable.CoordinatorLayout,
-                    defStyleAttr, 0);
-        final int keylineArrayRes = a.getResourceId(R.styleable.CoordinatorLayout_keylines, 0);
-        if (keylineArrayRes != 0) {
-            final Resources res = context.getResources();
-            mKeylines = res.getIntArray(keylineArrayRes);
-            final float density = res.getDisplayMetrics().density;
-            final int count = mKeylines.length;
-            for (int i = 0; i < count; i++) {
-                mKeylines[i] = (int) (mKeylines[i] * density);
-            }
-        }
-        mStatusBarBackground = a.getDrawable(R.styleable.CoordinatorLayout_statusBarBackground);
-        a.recycle();
-
-        setupForInsets();
-        super.setOnHierarchyChangeListener(new HierarchyChangeListener());
-    }
-
-    @Override
-    public void setOnHierarchyChangeListener(OnHierarchyChangeListener onHierarchyChangeListener) {
-        mOnHierarchyChangeListener = onHierarchyChangeListener;
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        resetTouchBehaviors(false);
-        if (mNeedsPreDrawListener) {
-            if (mOnPreDrawListener == null) {
-                mOnPreDrawListener = new OnPreDrawListener();
-            }
-            final ViewTreeObserver vto = getViewTreeObserver();
-            vto.addOnPreDrawListener(mOnPreDrawListener);
-        }
-        if (mLastInsets == null && ViewCompat.getFitsSystemWindows(this)) {
-            // We're set to fitSystemWindows but we haven't had any insets yet...
-            // We should request a new dispatch of window insets
-            ViewCompat.requestApplyInsets(this);
-        }
-        mIsAttachedToWindow = true;
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        resetTouchBehaviors(false);
-        if (mNeedsPreDrawListener && mOnPreDrawListener != null) {
-            final ViewTreeObserver vto = getViewTreeObserver();
-            vto.removeOnPreDrawListener(mOnPreDrawListener);
-        }
-        if (mNestedScrollingTarget != null) {
-            onStopNestedScroll(mNestedScrollingTarget);
-        }
-        mIsAttachedToWindow = false;
-    }
-
-    /**
-     * Set a drawable to draw in the insets area for the status bar.
-     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
-     *
-     * @param bg Background drawable to draw behind the status bar
-     */
-    public void setStatusBarBackground(@Nullable final Drawable bg) {
-        if (mStatusBarBackground != bg) {
-            if (mStatusBarBackground != null) {
-                mStatusBarBackground.setCallback(null);
-            }
-            mStatusBarBackground = bg != null ? bg.mutate() : null;
-            if (mStatusBarBackground != null) {
-                if (mStatusBarBackground.isStateful()) {
-                    mStatusBarBackground.setState(getDrawableState());
-                }
-                DrawableCompat.setLayoutDirection(mStatusBarBackground,
-                        ViewCompat.getLayoutDirection(this));
-                mStatusBarBackground.setVisible(getVisibility() == VISIBLE, false);
-                mStatusBarBackground.setCallback(this);
-            }
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    /**
-     * Gets the drawable used to draw in the insets area for the status bar.
-     *
-     * @return The status bar background drawable, or null if none set
-     */
-    @Nullable
-    public Drawable getStatusBarBackground() {
-        return mStatusBarBackground;
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-
-        final int[] state = getDrawableState();
-        boolean changed = false;
-
-        Drawable d = mStatusBarBackground;
-        if (d != null && d.isStateful()) {
-            changed |= d.setState(state);
-        }
-
-        if (changed) {
-            invalidate();
-        }
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == mStatusBarBackground;
-    }
-
-    @Override
-    public void setVisibility(int visibility) {
-        super.setVisibility(visibility);
-
-        final boolean visible = visibility == VISIBLE;
-        if (mStatusBarBackground != null && mStatusBarBackground.isVisible() != visible) {
-            mStatusBarBackground.setVisible(visible, false);
-        }
-    }
-
-    /**
-     * Set a drawable to draw in the insets area for the status bar.
-     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
-     *
-     * @param resId Resource id of a background drawable to draw behind the status bar
-     */
-    public void setStatusBarBackgroundResource(@DrawableRes int resId) {
-        setStatusBarBackground(resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null);
-    }
-
-    /**
-     * Set a drawable to draw in the insets area for the status bar.
-     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
-     *
-     * @param color Color to use as a background drawable to draw behind the status bar
-     *              in 0xAARRGGBB format.
-     */
-    public void setStatusBarBackgroundColor(@ColorInt int color) {
-        setStatusBarBackground(new ColorDrawable(color));
-    }
-
-    final WindowInsetsCompat setWindowInsets(WindowInsetsCompat insets) {
-        if (!ObjectsCompat.equals(mLastInsets, insets)) {
-            mLastInsets = insets;
-            mDrawStatusBarBackground = insets != null && insets.getSystemWindowInsetTop() > 0;
-            setWillNotDraw(!mDrawStatusBarBackground && getBackground() == null);
-
-            // Now dispatch to the Behaviors
-            insets = dispatchApplyWindowInsetsToBehaviors(insets);
-            requestLayout();
-        }
-        return insets;
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public final WindowInsetsCompat getLastWindowInsets() {
-        return mLastInsets;
-    }
-
-    /**
-     * Reset all Behavior-related tracking records either to clean up or in preparation
-     * for a new event stream. This should be called when attached or detached from a window,
-     * in response to an UP or CANCEL event, when intercept is request-disallowed
-     * and similar cases where an event stream in progress will be aborted.
-     */
-    private void resetTouchBehaviors(boolean notifyOnInterceptTouchEvent) {
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final Behavior b = lp.getBehavior();
-            if (b != null) {
-                final long now = SystemClock.uptimeMillis();
-                final MotionEvent cancelEvent = MotionEvent.obtain(now, now,
-                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
-                if (notifyOnInterceptTouchEvent) {
-                    b.onInterceptTouchEvent(this, child, cancelEvent);
-                } else {
-                    b.onTouchEvent(this, child, cancelEvent);
-                }
-                cancelEvent.recycle();
-            }
-        }
-
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            lp.resetTouchBehaviorTracking();
-        }
-        mBehaviorTouchView = null;
-        mDisallowInterceptReset = false;
-    }
-
-    /**
-     * Populate a list with the current child views, sorted such that the topmost views
-     * in z-order are at the front of the list. Useful for hit testing and event dispatch.
-     */
-    private void getTopSortedChildren(List<View> out) {
-        out.clear();
-
-        final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
-        final int childCount = getChildCount();
-        for (int i = childCount - 1; i >= 0; i--) {
-            final int childIndex = useCustomOrder ? getChildDrawingOrder(childCount, i) : i;
-            final View child = getChildAt(childIndex);
-            out.add(child);
-        }
-
-        if (TOP_SORTED_CHILDREN_COMPARATOR != null) {
-            Collections.sort(out, TOP_SORTED_CHILDREN_COMPARATOR);
-        }
-    }
-
-    private boolean performIntercept(MotionEvent ev, final int type) {
-        boolean intercepted = false;
-        boolean newBlock = false;
-
-        MotionEvent cancelEvent = null;
-
-        final int action = ev.getActionMasked();
-
-        final List<View> topmostChildList = mTempList1;
-        getTopSortedChildren(topmostChildList);
-
-        // Let topmost child views inspect first
-        final int childCount = topmostChildList.size();
-        for (int i = 0; i < childCount; i++) {
-            final View child = topmostChildList.get(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final Behavior b = lp.getBehavior();
-
-            if ((intercepted || newBlock) && action != MotionEvent.ACTION_DOWN) {
-                // Cancel all behaviors beneath the one that intercepted.
-                // If the event is "down" then we don't have anything to cancel yet.
-                if (b != null) {
-                    if (cancelEvent == null) {
-                        final long now = SystemClock.uptimeMillis();
-                        cancelEvent = MotionEvent.obtain(now, now,
-                                MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
-                    }
-                    switch (type) {
-                        case TYPE_ON_INTERCEPT:
-                            b.onInterceptTouchEvent(this, child, cancelEvent);
-                            break;
-                        case TYPE_ON_TOUCH:
-                            b.onTouchEvent(this, child, cancelEvent);
-                            break;
-                    }
-                }
-                continue;
-            }
-
-            if (!intercepted && b != null) {
-                switch (type) {
-                    case TYPE_ON_INTERCEPT:
-                        intercepted = b.onInterceptTouchEvent(this, child, ev);
-                        break;
-                    case TYPE_ON_TOUCH:
-                        intercepted = b.onTouchEvent(this, child, ev);
-                        break;
-                }
-                if (intercepted) {
-                    mBehaviorTouchView = child;
-                }
-            }
-
-            // Don't keep going if we're not allowing interaction below this.
-            // Setting newBlock will make sure we cancel the rest of the behaviors.
-            final boolean wasBlocking = lp.didBlockInteraction();
-            final boolean isBlocking = lp.isBlockingInteractionBelow(this, child);
-            newBlock = isBlocking && !wasBlocking;
-            if (isBlocking && !newBlock) {
-                // Stop here since we don't have anything more to cancel - we already did
-                // when the behavior first started blocking things below this point.
-                break;
-            }
-        }
-
-        topmostChildList.clear();
-
-        return intercepted;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        MotionEvent cancelEvent = null;
-
-        final int action = ev.getActionMasked();
-
-        // Make sure we reset in case we had missed a previous important event.
-        if (action == MotionEvent.ACTION_DOWN) {
-            resetTouchBehaviors(true);
-        }
-
-        final boolean intercepted = performIntercept(ev, TYPE_ON_INTERCEPT);
-
-        if (cancelEvent != null) {
-            cancelEvent.recycle();
-        }
-
-        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            resetTouchBehaviors(true);
-        }
-
-        return intercepted;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        boolean handled = false;
-        boolean cancelSuper = false;
-        MotionEvent cancelEvent = null;
-
-        final int action = ev.getActionMasked();
-
-        if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev, TYPE_ON_TOUCH))) {
-            // Safe since performIntercept guarantees that
-            // mBehaviorTouchView != null if it returns true
-            final LayoutParams lp = (LayoutParams) mBehaviorTouchView.getLayoutParams();
-            final Behavior b = lp.getBehavior();
-            if (b != null) {
-                handled = b.onTouchEvent(this, mBehaviorTouchView, ev);
-            }
-        }
-
-        // Keep the super implementation correct
-        if (mBehaviorTouchView == null) {
-            handled |= super.onTouchEvent(ev);
-        } else if (cancelSuper) {
-            if (cancelEvent == null) {
-                final long now = SystemClock.uptimeMillis();
-                cancelEvent = MotionEvent.obtain(now, now,
-                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
-            }
-            super.onTouchEvent(cancelEvent);
-        }
-
-        if (!handled && action == MotionEvent.ACTION_DOWN) {
-
-        }
-
-        if (cancelEvent != null) {
-            cancelEvent.recycle();
-        }
-
-        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
-            resetTouchBehaviors(false);
-        }
-
-        return handled;
-    }
-
-    @Override
-    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        super.requestDisallowInterceptTouchEvent(disallowIntercept);
-        if (disallowIntercept && !mDisallowInterceptReset) {
-            resetTouchBehaviors(false);
-            mDisallowInterceptReset = true;
-        }
-    }
-
-    private int getKeyline(int index) {
-        if (mKeylines == null) {
-            Log.e(TAG, "No keylines defined for " + this + " - attempted index lookup " + index);
-            return 0;
-        }
-
-        if (index < 0 || index >= mKeylines.length) {
-            Log.e(TAG, "Keyline index " + index + " out of range for " + this);
-            return 0;
-        }
-
-        return mKeylines[index];
-    }
-
-    static Behavior parseBehavior(Context context, AttributeSet attrs, String name) {
-        if (TextUtils.isEmpty(name)) {
-            return null;
-        }
-
-        final String fullName;
-        if (name.startsWith(".")) {
-            // Relative to the app package. Prepend the app package name.
-            fullName = context.getPackageName() + name;
-        } else if (name.indexOf('.') >= 0) {
-            // Fully qualified package name.
-            fullName = name;
-        } else {
-            // Assume stock behavior in this package (if we have one)
-            fullName = !TextUtils.isEmpty(WIDGET_PACKAGE_NAME)
-                    ? (WIDGET_PACKAGE_NAME + '.' + name)
-                    : name;
-        }
-
-        try {
-            Map<String, Constructor<Behavior>> constructors = sConstructors.get();
-            if (constructors == null) {
-                constructors = new HashMap<>();
-                sConstructors.set(constructors);
-            }
-            Constructor<Behavior> c = constructors.get(fullName);
-            if (c == null) {
-                final Class<Behavior> clazz = (Class<Behavior>) context.getClassLoader()
-                        .loadClass(fullName);
-                c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
-                c.setAccessible(true);
-                constructors.put(fullName, c);
-            }
-            return c.newInstance(context, attrs);
-        } catch (Exception e) {
-            throw new RuntimeException("Could not inflate Behavior subclass " + fullName, e);
-        }
-    }
-
-    LayoutParams getResolvedLayoutParams(View child) {
-        final LayoutParams result = (LayoutParams) child.getLayoutParams();
-        if (!result.mBehaviorResolved) {
-            if (child instanceof AttachedBehavior) {
-                Behavior attachedBehavior = ((AttachedBehavior) child).getBehavior();
-                if (attachedBehavior == null) {
-                    Log.e(TAG, "Attached behavior class is null");
-                }
-                result.setBehavior(attachedBehavior);
-                result.mBehaviorResolved = true;
-            } else {
-                // The deprecated path that looks up the attached behavior based on annotation
-                Class<?> childClass = child.getClass();
-                DefaultBehavior defaultBehavior = null;
-                while (childClass != null
-                        && (defaultBehavior = childClass.getAnnotation(DefaultBehavior.class))
-                                == null) {
-                    childClass = childClass.getSuperclass();
-                }
-                if (defaultBehavior != null) {
-                    try {
-                        result.setBehavior(
-                                defaultBehavior.value().getDeclaredConstructor().newInstance());
-                    } catch (Exception e) {
-                        Log.e(TAG, "Default behavior class " + defaultBehavior.value().getName()
-                                        + " could not be instantiated. Did you forget"
-                                        + " a default constructor?", e);
-                    }
-                }
-                result.mBehaviorResolved = true;
-            }
-        }
-        return result;
-    }
-
-    private void prepareChildren() {
-        mDependencySortedChildren.clear();
-        mChildDag.clear();
-
-        for (int i = 0, count = getChildCount(); i < count; i++) {
-            final View view = getChildAt(i);
-
-            final LayoutParams lp = getResolvedLayoutParams(view);
-            lp.findAnchorView(this, view);
-
-            mChildDag.addNode(view);
-
-            // Now iterate again over the other children, adding any dependencies to the graph
-            for (int j = 0; j < count; j++) {
-                if (j == i) {
-                    continue;
-                }
-                final View other = getChildAt(j);
-                if (lp.dependsOn(this, view, other)) {
-                    if (!mChildDag.contains(other)) {
-                        // Make sure that the other node is added
-                        mChildDag.addNode(other);
-                    }
-                    // Now add the dependency to the graph
-                    mChildDag.addEdge(other, view);
-                }
-            }
-        }
-
-        // Finally add the sorted graph list to our list
-        mDependencySortedChildren.addAll(mChildDag.getSortedList());
-        // We also need to reverse the result since we want the start of the list to contain
-        // Views which have no dependencies, then dependent views after that
-        Collections.reverse(mDependencySortedChildren);
-    }
-
-    /**
-     * Retrieve the transformed bounding rect of an arbitrary descendant view.
-     * This does not need to be a direct child.
-     *
-     * @param descendant descendant view to reference
-     * @param out rect to set to the bounds of the descendant view
-     */
-    void getDescendantRect(View descendant, Rect out) {
-        ViewGroupUtils.getDescendantRect(this, descendant, out);
-    }
-
-    @Override
-    protected int getSuggestedMinimumWidth() {
-        return Math.max(super.getSuggestedMinimumWidth(), getPaddingLeft() + getPaddingRight());
-    }
-
-    @Override
-    protected int getSuggestedMinimumHeight() {
-        return Math.max(super.getSuggestedMinimumHeight(), getPaddingTop() + getPaddingBottom());
-    }
-
-    /**
-     * Called to measure each individual child view unless a
-     * {@link Behavior Behavior} is present. The Behavior may choose to delegate
-     * child measurement to this method.
-     *
-     * @param child the child to measure
-     * @param parentWidthMeasureSpec the width requirements for this view
-     * @param widthUsed extra space that has been used up by the parent
-     *        horizontally (possibly by other children of the parent)
-     * @param parentHeightMeasureSpec the height requirements for this view
-     * @param heightUsed extra space that has been used up by the parent
-     *        vertically (possibly by other children of the parent)
-     */
-    public void onMeasureChild(View child, int parentWidthMeasureSpec, int widthUsed,
-            int parentHeightMeasureSpec, int heightUsed) {
-        measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
-                parentHeightMeasureSpec, heightUsed);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        prepareChildren();
-        ensurePreDrawListener();
-
-        final int paddingLeft = getPaddingLeft();
-        final int paddingTop = getPaddingTop();
-        final int paddingRight = getPaddingRight();
-        final int paddingBottom = getPaddingBottom();
-        final int layoutDirection = ViewCompat.getLayoutDirection(this);
-        final boolean isRtl = layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL;
-        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
-        final int widthPadding = paddingLeft + paddingRight;
-        final int heightPadding = paddingTop + paddingBottom;
-        int widthUsed = getSuggestedMinimumWidth();
-        int heightUsed = getSuggestedMinimumHeight();
-        int childState = 0;
-
-        final boolean applyInsets = mLastInsets != null && ViewCompat.getFitsSystemWindows(this);
-
-        final int childCount = mDependencySortedChildren.size();
-        for (int i = 0; i < childCount; i++) {
-            final View child = mDependencySortedChildren.get(i);
-            if (child.getVisibility() == GONE) {
-                // If the child is GONE, skip...
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            int keylineWidthUsed = 0;
-            if (lp.keyline >= 0 && widthMode != MeasureSpec.UNSPECIFIED) {
-                final int keylinePos = getKeyline(lp.keyline);
-                final int keylineGravity = GravityCompat.getAbsoluteGravity(
-                        resolveKeylineGravity(lp.gravity), layoutDirection)
-                        & Gravity.HORIZONTAL_GRAVITY_MASK;
-                if ((keylineGravity == Gravity.LEFT && !isRtl)
-                        || (keylineGravity == Gravity.RIGHT && isRtl)) {
-                    keylineWidthUsed = Math.max(0, widthSize - paddingRight - keylinePos);
-                } else if ((keylineGravity == Gravity.RIGHT && !isRtl)
-                        || (keylineGravity == Gravity.LEFT && isRtl)) {
-                    keylineWidthUsed = Math.max(0, keylinePos - paddingLeft);
-                }
-            }
-
-            int childWidthMeasureSpec = widthMeasureSpec;
-            int childHeightMeasureSpec = heightMeasureSpec;
-            if (applyInsets && !ViewCompat.getFitsSystemWindows(child)) {
-                // We're set to handle insets but this child isn't, so we will measure the
-                // child as if there are no insets
-                final int horizInsets = mLastInsets.getSystemWindowInsetLeft()
-                        + mLastInsets.getSystemWindowInsetRight();
-                final int vertInsets = mLastInsets.getSystemWindowInsetTop()
-                        + mLastInsets.getSystemWindowInsetBottom();
-
-                childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        widthSize - horizInsets, widthMode);
-                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        heightSize - vertInsets, heightMode);
-            }
-
-            final Behavior b = lp.getBehavior();
-            if (b == null || !b.onMeasureChild(this, child, childWidthMeasureSpec, keylineWidthUsed,
-                    childHeightMeasureSpec, 0)) {
-                onMeasureChild(child, childWidthMeasureSpec, keylineWidthUsed,
-                        childHeightMeasureSpec, 0);
-            }
-
-            widthUsed = Math.max(widthUsed, widthPadding + child.getMeasuredWidth() +
-                    lp.leftMargin + lp.rightMargin);
-
-            heightUsed = Math.max(heightUsed, heightPadding + child.getMeasuredHeight() +
-                    lp.topMargin + lp.bottomMargin);
-            childState = View.combineMeasuredStates(childState, child.getMeasuredState());
-        }
-
-        final int width = View.resolveSizeAndState(widthUsed, widthMeasureSpec,
-                childState & View.MEASURED_STATE_MASK);
-        final int height = View.resolveSizeAndState(heightUsed, heightMeasureSpec,
-                childState << View.MEASURED_HEIGHT_STATE_SHIFT);
-        setMeasuredDimension(width, height);
-    }
-
-    private WindowInsetsCompat dispatchApplyWindowInsetsToBehaviors(WindowInsetsCompat insets) {
-        if (insets.isConsumed()) {
-            return insets;
-        }
-
-        for (int i = 0, z = getChildCount(); i < z; i++) {
-            final View child = getChildAt(i);
-            if (ViewCompat.getFitsSystemWindows(child)) {
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                final Behavior b = lp.getBehavior();
-
-                if (b != null) {
-                    // If the view has a behavior, let it try first
-                    insets = b.onApplyWindowInsets(this, child, insets);
-                    if (insets.isConsumed()) {
-                        // If it consumed the insets, break
-                        break;
-                    }
-                }
-            }
-        }
-
-        return insets;
-    }
-
-    /**
-     * Called to lay out each individual child view unless a
-     * {@link Behavior Behavior} is present. The Behavior may choose to
-     * delegate child measurement to this method.
-     *
-     * @param child child view to lay out
-     * @param layoutDirection the resolved layout direction for the CoordinatorLayout, such as
-     *                        {@link ViewCompat#LAYOUT_DIRECTION_LTR} or
-     *                        {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
-     */
-    public void onLayoutChild(View child, int layoutDirection) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        if (lp.checkAnchorChanged()) {
-            throw new IllegalStateException("An anchor may not be changed after CoordinatorLayout"
-                    + " measurement begins before layout is complete.");
-        }
-        if (lp.mAnchorView != null) {
-            layoutChildWithAnchor(child, lp.mAnchorView, layoutDirection);
-        } else if (lp.keyline >= 0) {
-            layoutChildWithKeyline(child, lp.keyline, layoutDirection);
-        } else {
-            layoutChild(child, layoutDirection);
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        final int layoutDirection = ViewCompat.getLayoutDirection(this);
-        final int childCount = mDependencySortedChildren.size();
-        for (int i = 0; i < childCount; i++) {
-            final View child = mDependencySortedChildren.get(i);
-            if (child.getVisibility() == GONE) {
-                // If the child is GONE, skip...
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final Behavior behavior = lp.getBehavior();
-
-            if (behavior == null || !behavior.onLayoutChild(this, child, layoutDirection)) {
-                onLayoutChild(child, layoutDirection);
-            }
-        }
-    }
-
-    @Override
-    public void onDraw(Canvas c) {
-        super.onDraw(c);
-        if (mDrawStatusBarBackground && mStatusBarBackground != null) {
-            final int inset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
-            if (inset > 0) {
-                mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
-                mStatusBarBackground.draw(c);
-            }
-        }
-    }
-
-    @Override
-    public void setFitsSystemWindows(boolean fitSystemWindows) {
-        super.setFitsSystemWindows(fitSystemWindows);
-        setupForInsets();
-    }
-
-    /**
-     * Mark the last known child position rect for the given child view.
-     * This will be used when checking if a child view's position has changed between frames.
-     * The rect used here should be one returned by
-     * {@link #getChildRect(View, boolean, Rect)}, with translation
-     * disabled.
-     *
-     * @param child child view to set for
-     * @param r rect to set
-     */
-    void recordLastChildRect(View child, Rect r) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        lp.setLastChildRect(r);
-    }
-
-    /**
-     * Get the last known child rect recorded by
-     * {@link #recordLastChildRect(View, Rect)}.
-     *
-     * @param child child view to retrieve from
-     * @param out rect to set to the outpur values
-     */
-    void getLastChildRect(View child, Rect out) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        out.set(lp.getLastChildRect());
-    }
-
-    /**
-     * Get the position rect for the given child. If the child has currently requested layout
-     * or has a visibility of GONE.
-     *
-     * @param child child view to check
-     * @param transform true to include transformation in the output rect, false to
-     *                        only account for the base position
-     * @param out rect to set to the output values
-     */
-    void getChildRect(View child, boolean transform, Rect out) {
-        if (child.isLayoutRequested() || child.getVisibility() == View.GONE) {
-            out.setEmpty();
-            return;
-        }
-        if (transform) {
-            getDescendantRect(child, out);
-        } else {
-            out.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
-        }
-    }
-
-    private void getDesiredAnchoredChildRectWithoutConstraints(View child, int layoutDirection,
-            Rect anchorRect, Rect out, LayoutParams lp, int childWidth, int childHeight) {
-        final int absGravity = GravityCompat.getAbsoluteGravity(
-                resolveAnchoredChildGravity(lp.gravity), layoutDirection);
-        final int absAnchorGravity = GravityCompat.getAbsoluteGravity(
-                resolveGravity(lp.anchorGravity),
-                layoutDirection);
-
-        final int hgrav = absGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-        final int vgrav = absGravity & Gravity.VERTICAL_GRAVITY_MASK;
-        final int anchorHgrav = absAnchorGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-        final int anchorVgrav = absAnchorGravity & Gravity.VERTICAL_GRAVITY_MASK;
-
-        int left;
-        int top;
-
-        // Align to the anchor. This puts us in an assumed right/bottom child view gravity.
-        // If this is not the case we will subtract out the appropriate portion of
-        // the child size below.
-        switch (anchorHgrav) {
-            default:
-            case Gravity.LEFT:
-                left = anchorRect.left;
-                break;
-            case Gravity.RIGHT:
-                left = anchorRect.right;
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-                left = anchorRect.left + anchorRect.width() / 2;
-                break;
-        }
-
-        switch (anchorVgrav) {
-            default:
-            case Gravity.TOP:
-                top = anchorRect.top;
-                break;
-            case Gravity.BOTTOM:
-                top = anchorRect.bottom;
-                break;
-            case Gravity.CENTER_VERTICAL:
-                top = anchorRect.top + anchorRect.height() / 2;
-                break;
-        }
-
-        // Offset by the child view's gravity itself. The above assumed right/bottom gravity.
-        switch (hgrav) {
-            default:
-            case Gravity.LEFT:
-                left -= childWidth;
-                break;
-            case Gravity.RIGHT:
-                // Do nothing, we're already in position.
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-                left -= childWidth / 2;
-                break;
-        }
-
-        switch (vgrav) {
-            default:
-            case Gravity.TOP:
-                top -= childHeight;
-                break;
-            case Gravity.BOTTOM:
-                // Do nothing, we're already in position.
-                break;
-            case Gravity.CENTER_VERTICAL:
-                top -= childHeight / 2;
-                break;
-        }
-
-        out.set(left, top, left + childWidth, top + childHeight);
-    }
-
-    private void constrainChildRect(LayoutParams lp, Rect out, int childWidth, int childHeight) {
-        final int width = getWidth();
-        final int height = getHeight();
-
-        // Obey margins and padding
-        int left = Math.max(getPaddingLeft() + lp.leftMargin,
-                Math.min(out.left,
-                        width - getPaddingRight() - childWidth - lp.rightMargin));
-        int top = Math.max(getPaddingTop() + lp.topMargin,
-                Math.min(out.top,
-                        height - getPaddingBottom() - childHeight - lp.bottomMargin));
-
-        out.set(left, top, left + childWidth, top + childHeight);
-    }
-
-    /**
-     * Calculate the desired child rect relative to an anchor rect, respecting both
-     * gravity and anchorGravity.
-     *
-     * @param child child view to calculate a rect for
-     * @param layoutDirection the desired layout direction for the CoordinatorLayout
-     * @param anchorRect rect in CoordinatorLayout coordinates of the anchor view area
-     * @param out rect to set to the output values
-     */
-    void getDesiredAnchoredChildRect(View child, int layoutDirection, Rect anchorRect, Rect out) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        final int childWidth = child.getMeasuredWidth();
-        final int childHeight = child.getMeasuredHeight();
-        getDesiredAnchoredChildRectWithoutConstraints(child, layoutDirection, anchorRect, out, lp,
-                childWidth, childHeight);
-        constrainChildRect(lp, out, childWidth, childHeight);
-    }
-
-    /**
-     * CORE ASSUMPTION: anchor has been laid out by the time this is called for a given child view.
-     *
-     * @param child child to lay out
-     * @param anchor view to anchor child relative to; already laid out.
-     * @param layoutDirection ViewCompat constant for layout direction
-     */
-    private void layoutChildWithAnchor(View child, View anchor, int layoutDirection) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-        final Rect anchorRect = acquireTempRect();
-        final Rect childRect = acquireTempRect();
-        try {
-            getDescendantRect(anchor, anchorRect);
-            getDesiredAnchoredChildRect(child, layoutDirection, anchorRect, childRect);
-            child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
-        } finally {
-            releaseTempRect(anchorRect);
-            releaseTempRect(childRect);
-        }
-    }
-
-    /**
-     * Lay out a child view with respect to a keyline.
-     *
-     * <p>The keyline represents a horizontal offset from the unpadded starting edge of
-     * the CoordinatorLayout. The child's gravity will affect how it is positioned with
-     * respect to the keyline.</p>
-     *
-     * @param child child to lay out
-     * @param keyline offset from the starting edge in pixels of the keyline to align with
-     * @param layoutDirection ViewCompat constant for layout direction
-     */
-    private void layoutChildWithKeyline(View child, int keyline, int layoutDirection) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        final int absGravity = GravityCompat.getAbsoluteGravity(
-                resolveKeylineGravity(lp.gravity), layoutDirection);
-
-        final int hgrav = absGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
-        final int vgrav = absGravity & Gravity.VERTICAL_GRAVITY_MASK;
-        final int width = getWidth();
-        final int height = getHeight();
-        final int childWidth = child.getMeasuredWidth();
-        final int childHeight = child.getMeasuredHeight();
-
-        if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_RTL) {
-            keyline = width - keyline;
-        }
-
-        int left = getKeyline(keyline) - childWidth;
-        int top = 0;
-
-        switch (hgrav) {
-            default:
-            case Gravity.LEFT:
-                // Nothing to do.
-                break;
-            case Gravity.RIGHT:
-                left += childWidth;
-                break;
-            case Gravity.CENTER_HORIZONTAL:
-                left += childWidth / 2;
-                break;
-        }
-
-        switch (vgrav) {
-            default:
-            case Gravity.TOP:
-                // Do nothing, we're already in position.
-                break;
-            case Gravity.BOTTOM:
-                top += childHeight;
-                break;
-            case Gravity.CENTER_VERTICAL:
-                top += childHeight / 2;
-                break;
-        }
-
-        // Obey margins and padding
-        left = Math.max(getPaddingLeft() + lp.leftMargin,
-                Math.min(left,
-                        width - getPaddingRight() - childWidth - lp.rightMargin));
-        top = Math.max(getPaddingTop() + lp.topMargin,
-                Math.min(top,
-                        height - getPaddingBottom() - childHeight - lp.bottomMargin));
-
-        child.layout(left, top, left + childWidth, top + childHeight);
-    }
-
-    /**
-     * Lay out a child view with no special handling. This will position the child as
-     * if it were within a FrameLayout or similar simple frame.
-     *
-     * @param child child view to lay out
-     * @param layoutDirection ViewCompat constant for the desired layout direction
-     */
-    private void layoutChild(View child, int layoutDirection) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        final Rect parent = acquireTempRect();
-        parent.set(getPaddingLeft() + lp.leftMargin,
-                getPaddingTop() + lp.topMargin,
-                getWidth() - getPaddingRight() - lp.rightMargin,
-                getHeight() - getPaddingBottom() - lp.bottomMargin);
-
-        if (mLastInsets != null && ViewCompat.getFitsSystemWindows(this)
-                && !ViewCompat.getFitsSystemWindows(child)) {
-            // If we're set to handle insets but this child isn't, then it has been measured as
-            // if there are no insets. We need to lay it out to match.
-            parent.left += mLastInsets.getSystemWindowInsetLeft();
-            parent.top += mLastInsets.getSystemWindowInsetTop();
-            parent.right -= mLastInsets.getSystemWindowInsetRight();
-            parent.bottom -= mLastInsets.getSystemWindowInsetBottom();
-        }
-
-        final Rect out = acquireTempRect();
-        GravityCompat.apply(resolveGravity(lp.gravity), child.getMeasuredWidth(),
-                child.getMeasuredHeight(), parent, out, layoutDirection);
-        child.layout(out.left, out.top, out.right, out.bottom);
-
-        releaseTempRect(parent);
-        releaseTempRect(out);
-    }
-
-    /**
-     * Return the given gravity value, but if either or both of the axes doesn't have any gravity
-     * specified, the default value (start or top) is specified. This should be used for children
-     * that are not anchored to another view or a keyline.
-     */
-    private static int resolveGravity(int gravity) {
-        if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
-            gravity |= GravityCompat.START;
-        }
-        if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.NO_GRAVITY) {
-            gravity |= Gravity.TOP;
-        }
-        return gravity;
-    }
-
-    /**
-     * Return the given gravity value or the default if the passed value is NO_GRAVITY.
-     * This should be used for children that are positioned relative to a keyline.
-     */
-    private static int resolveKeylineGravity(int gravity) {
-        return gravity == Gravity.NO_GRAVITY ? GravityCompat.END | Gravity.TOP : gravity;
-    }
-
-    /**
-     * Return the given gravity value or the default if the passed value is NO_GRAVITY.
-     * This should be used for children that are anchored to another view.
-     */
-    private static int resolveAnchoredChildGravity(int gravity) {
-        return gravity == Gravity.NO_GRAVITY ? Gravity.CENTER : gravity;
-    }
-
-    @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        if (lp.mBehavior != null) {
-            final float scrimAlpha = lp.mBehavior.getScrimOpacity(this, child);
-            if (scrimAlpha > 0f) {
-                if (mScrimPaint == null) {
-                    mScrimPaint = new Paint();
-                }
-                mScrimPaint.setColor(lp.mBehavior.getScrimColor(this, child));
-                mScrimPaint.setAlpha(MathUtils.clamp(Math.round(255 * scrimAlpha), 0, 255));
-
-                final int saved = canvas.save();
-                if (child.isOpaque()) {
-                    // If the child is opaque, there is no need to draw behind it so we'll inverse
-                    // clip the canvas
-                    canvas.clipRect(child.getLeft(), child.getTop(), child.getRight(),
-                            child.getBottom(), Region.Op.DIFFERENCE);
-                }
-                // Now draw the rectangle for the scrim
-                canvas.drawRect(getPaddingLeft(), getPaddingTop(),
-                        getWidth() - getPaddingRight(), getHeight() - getPaddingBottom(),
-                        mScrimPaint);
-                canvas.restoreToCount(saved);
-            }
-        }
-        return super.drawChild(canvas, child, drawingTime);
-    }
-
-    /**
-     * Dispatch any dependent view changes to the relevant {@link Behavior} instances.
-     *
-     * Usually run as part of the pre-draw step when at least one child view has a reported
-     * dependency on another view. This allows CoordinatorLayout to account for layout
-     * changes and animations that occur outside of the normal layout pass.
-     *
-     * It can also be ran as part of the nested scrolling dispatch to ensure that any offsetting
-     * is completed within the correct coordinate window.
-     *
-     * The offsetting behavior implemented here does not store the computed offset in
-     * the LayoutParams; instead it expects that the layout process will always reconstruct
-     * the proper positioning.
-     *
-     * @param type the type of event which has caused this call
-     */
-    final void onChildViewsChanged(@DispatchChangeEvent final int type) {
-        final int layoutDirection = ViewCompat.getLayoutDirection(this);
-        final int childCount = mDependencySortedChildren.size();
-        final Rect inset = acquireTempRect();
-        final Rect drawRect = acquireTempRect();
-        final Rect lastDrawRect = acquireTempRect();
-
-        for (int i = 0; i < childCount; i++) {
-            final View child = mDependencySortedChildren.get(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            if (type == EVENT_PRE_DRAW && child.getVisibility() == View.GONE) {
-                // Do not try to update GONE child views in pre draw updates.
-                continue;
-            }
-
-            // Check child views before for anchor
-            for (int j = 0; j < i; j++) {
-                final View checkChild = mDependencySortedChildren.get(j);
-
-                if (lp.mAnchorDirectChild == checkChild) {
-                    offsetChildToAnchor(child, layoutDirection);
-                }
-            }
-
-            // Get the current draw rect of the view
-            getChildRect(child, true, drawRect);
-
-            // Accumulate inset sizes
-            if (lp.insetEdge != Gravity.NO_GRAVITY && !drawRect.isEmpty()) {
-                final int absInsetEdge = GravityCompat.getAbsoluteGravity(
-                        lp.insetEdge, layoutDirection);
-                switch (absInsetEdge & Gravity.VERTICAL_GRAVITY_MASK) {
-                    case Gravity.TOP:
-                        inset.top = Math.max(inset.top, drawRect.bottom);
-                        break;
-                    case Gravity.BOTTOM:
-                        inset.bottom = Math.max(inset.bottom, getHeight() - drawRect.top);
-                        break;
-                }
-                switch (absInsetEdge & Gravity.HORIZONTAL_GRAVITY_MASK) {
-                    case Gravity.LEFT:
-                        inset.left = Math.max(inset.left, drawRect.right);
-                        break;
-                    case Gravity.RIGHT:
-                        inset.right = Math.max(inset.right, getWidth() - drawRect.left);
-                        break;
-                }
-            }
-
-            // Dodge inset edges if necessary
-            if (lp.dodgeInsetEdges != Gravity.NO_GRAVITY && child.getVisibility() == View.VISIBLE) {
-                offsetChildByInset(child, inset, layoutDirection);
-            }
-
-            if (type != EVENT_VIEW_REMOVED) {
-                // Did it change? if not continue
-                getLastChildRect(child, lastDrawRect);
-                if (lastDrawRect.equals(drawRect)) {
-                    continue;
-                }
-                recordLastChildRect(child, drawRect);
-            }
-
-            // Update any behavior-dependent views for the change
-            for (int j = i + 1; j < childCount; j++) {
-                final View checkChild = mDependencySortedChildren.get(j);
-                final LayoutParams checkLp = (LayoutParams) checkChild.getLayoutParams();
-                final Behavior b = checkLp.getBehavior();
-
-                if (b != null && b.layoutDependsOn(this, checkChild, child)) {
-                    if (type == EVENT_PRE_DRAW && checkLp.getChangedAfterNestedScroll()) {
-                        // If this is from a pre-draw and we have already been changed
-                        // from a nested scroll, skip the dispatch and reset the flag
-                        checkLp.resetChangedAfterNestedScroll();
-                        continue;
-                    }
-
-                    final boolean handled;
-                    switch (type) {
-                        case EVENT_VIEW_REMOVED:
-                            // EVENT_VIEW_REMOVED means that we need to dispatch
-                            // onDependentViewRemoved() instead
-                            b.onDependentViewRemoved(this, checkChild, child);
-                            handled = true;
-                            break;
-                        default:
-                            // Otherwise we dispatch onDependentViewChanged()
-                            handled = b.onDependentViewChanged(this, checkChild, child);
-                            break;
-                    }
-
-                    if (type == EVENT_NESTED_SCROLL) {
-                        // If this is from a nested scroll, set the flag so that we may skip
-                        // any resulting onPreDraw dispatch (if needed)
-                        checkLp.setChangedAfterNestedScroll(handled);
-                    }
-                }
-            }
-        }
-
-        releaseTempRect(inset);
-        releaseTempRect(drawRect);
-        releaseTempRect(lastDrawRect);
-    }
-
-    private void offsetChildByInset(final View child, final Rect inset, final int layoutDirection) {
-        if (!ViewCompat.isLaidOut(child)) {
-            // The view has not been laid out yet, so we can't obtain its bounds.
-            return;
-        }
-
-        if (child.getWidth() <= 0 || child.getHeight() <= 0) {
-            // Bounds are empty so there is nothing to dodge against, skip...
-            return;
-        }
-
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        final Behavior behavior = lp.getBehavior();
-        final Rect dodgeRect = acquireTempRect();
-        final Rect bounds = acquireTempRect();
-        bounds.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
-
-        if (behavior != null && behavior.getInsetDodgeRect(this, child, dodgeRect)) {
-            // Make sure that the rect is within the view's bounds
-            if (!bounds.contains(dodgeRect)) {
-                throw new IllegalArgumentException("Rect should be within the child's bounds."
-                        + " Rect:" + dodgeRect.toShortString()
-                        + " | Bounds:" + bounds.toShortString());
-            }
-        } else {
-            dodgeRect.set(bounds);
-        }
-
-        // We can release the bounds rect now
-        releaseTempRect(bounds);
-
-        if (dodgeRect.isEmpty()) {
-            // Rect is empty so there is nothing to dodge against, skip...
-            releaseTempRect(dodgeRect);
-            return;
-        }
-
-        final int absDodgeInsetEdges = GravityCompat.getAbsoluteGravity(lp.dodgeInsetEdges,
-                layoutDirection);
-
-        boolean offsetY = false;
-        if ((absDodgeInsetEdges & Gravity.TOP) == Gravity.TOP) {
-            int distance = dodgeRect.top - lp.topMargin - lp.mInsetOffsetY;
-            if (distance < inset.top) {
-                setInsetOffsetY(child, inset.top - distance);
-                offsetY = true;
-            }
-        }
-        if ((absDodgeInsetEdges & Gravity.BOTTOM) == Gravity.BOTTOM) {
-            int distance = getHeight() - dodgeRect.bottom - lp.bottomMargin + lp.mInsetOffsetY;
-            if (distance < inset.bottom) {
-                setInsetOffsetY(child, distance - inset.bottom);
-                offsetY = true;
-            }
-        }
-        if (!offsetY) {
-            setInsetOffsetY(child, 0);
-        }
-
-        boolean offsetX = false;
-        if ((absDodgeInsetEdges & Gravity.LEFT) == Gravity.LEFT) {
-            int distance = dodgeRect.left - lp.leftMargin - lp.mInsetOffsetX;
-            if (distance < inset.left) {
-                setInsetOffsetX(child, inset.left - distance);
-                offsetX = true;
-            }
-        }
-        if ((absDodgeInsetEdges & Gravity.RIGHT) == Gravity.RIGHT) {
-            int distance = getWidth() - dodgeRect.right - lp.rightMargin + lp.mInsetOffsetX;
-            if (distance < inset.right) {
-                setInsetOffsetX(child, distance - inset.right);
-                offsetX = true;
-            }
-        }
-        if (!offsetX) {
-            setInsetOffsetX(child, 0);
-        }
-
-        releaseTempRect(dodgeRect);
-    }
-
-    private void setInsetOffsetX(View child, int offsetX) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        if (lp.mInsetOffsetX != offsetX) {
-            final int dx = offsetX - lp.mInsetOffsetX;
-            ViewCompat.offsetLeftAndRight(child, dx);
-            lp.mInsetOffsetX = offsetX;
-        }
-    }
-
-    private void setInsetOffsetY(View child, int offsetY) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        if (lp.mInsetOffsetY != offsetY) {
-            final int dy = offsetY - lp.mInsetOffsetY;
-            ViewCompat.offsetTopAndBottom(child, dy);
-            lp.mInsetOffsetY = offsetY;
-        }
-    }
-
-    /**
-     * Allows the caller to manually dispatch
-     * {@link Behavior#onDependentViewChanged(CoordinatorLayout, View, View)} to the associated
-     * {@link Behavior} instances of views which depend on the provided {@link View}.
-     *
-     * <p>You should not normally need to call this method as the it will be automatically done
-     * when the view has changed.
-     *
-     * @param view the View to find dependents of to dispatch the call.
-     */
-    public void dispatchDependentViewsChanged(View view) {
-        final List<View> dependents = mChildDag.getIncomingEdges(view);
-        if (dependents != null && !dependents.isEmpty()) {
-            for (int i = 0; i < dependents.size(); i++) {
-                final View child = dependents.get(i);
-                LayoutParams lp = (LayoutParams)
-                        child.getLayoutParams();
-                Behavior b = lp.getBehavior();
-                if (b != null) {
-                    b.onDependentViewChanged(this, child, view);
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns the list of views which the provided view depends on. Do not store this list as its
-     * contents may not be valid beyond the caller.
-     *
-     * @param child the view to find dependencies for.
-     *
-     * @return the list of views which {@code child} depends on.
-     */
-    @NonNull
-    public List<View> getDependencies(@NonNull View child) {
-        final List<View> dependencies = mChildDag.getOutgoingEdges(child);
-        mTempDependenciesList.clear();
-        if (dependencies != null) {
-            mTempDependenciesList.addAll(dependencies);
-        }
-        return mTempDependenciesList;
-    }
-
-    /**
-     * Returns the list of views which depend on the provided view. Do not store this list as its
-     * contents may not be valid beyond the caller.
-     *
-     * @param child the view to find dependents of.
-     *
-     * @return the list of views which depend on {@code child}.
-     */
-    @NonNull
-    public List<View> getDependents(@NonNull View child) {
-        final List<View> edges = mChildDag.getIncomingEdges(child);
-        mTempDependenciesList.clear();
-        if (edges != null) {
-            mTempDependenciesList.addAll(edges);
-        }
-        return mTempDependenciesList;
-    }
-
-    @VisibleForTesting
-    final List<View> getDependencySortedChildren() {
-        prepareChildren();
-        return Collections.unmodifiableList(mDependencySortedChildren);
-    }
-
-    /**
-     * Add or remove the pre-draw listener as necessary.
-     */
-    void ensurePreDrawListener() {
-        boolean hasDependencies = false;
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            if (hasDependencies(child)) {
-                hasDependencies = true;
-                break;
-            }
-        }
-
-        if (hasDependencies != mNeedsPreDrawListener) {
-            if (hasDependencies) {
-                addPreDrawListener();
-            } else {
-                removePreDrawListener();
-            }
-        }
-    }
-
-    /**
-     * Check if the given child has any layout dependencies on other child views.
-     */
-    private boolean hasDependencies(View child) {
-        return mChildDag.hasOutgoingEdges(child);
-    }
-
-    /**
-     * Add the pre-draw listener if we're attached to a window and mark that we currently
-     * need it when attached.
-     */
-    void addPreDrawListener() {
-        if (mIsAttachedToWindow) {
-            // Add the listener
-            if (mOnPreDrawListener == null) {
-                mOnPreDrawListener = new OnPreDrawListener();
-            }
-            final ViewTreeObserver vto = getViewTreeObserver();
-            vto.addOnPreDrawListener(mOnPreDrawListener);
-        }
-
-        // Record that we need the listener regardless of whether or not we're attached.
-        // We'll add the real listener when we become attached.
-        mNeedsPreDrawListener = true;
-    }
-
-    /**
-     * Remove the pre-draw listener if we're attached to a window and mark that we currently
-     * do not need it when attached.
-     */
-    void removePreDrawListener() {
-        if (mIsAttachedToWindow) {
-            if (mOnPreDrawListener != null) {
-                final ViewTreeObserver vto = getViewTreeObserver();
-                vto.removeOnPreDrawListener(mOnPreDrawListener);
-            }
-        }
-        mNeedsPreDrawListener = false;
-    }
-
-    /**
-     * Adjust the child left, top, right, bottom rect to the correct anchor view position,
-     * respecting gravity and anchor gravity.
-     *
-     * Note that child translation properties are ignored in this process, allowing children
-     * to be animated away from their anchor. However, if the anchor view is animated,
-     * the child will be offset to match the anchor's translated position.
-     */
-    void offsetChildToAnchor(View child, int layoutDirection) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        if (lp.mAnchorView != null) {
-            final Rect anchorRect = acquireTempRect();
-            final Rect childRect = acquireTempRect();
-            final Rect desiredChildRect = acquireTempRect();
-
-            getDescendantRect(lp.mAnchorView, anchorRect);
-            getChildRect(child, false, childRect);
-
-            int childWidth = child.getMeasuredWidth();
-            int childHeight = child.getMeasuredHeight();
-            getDesiredAnchoredChildRectWithoutConstraints(child, layoutDirection, anchorRect,
-                    desiredChildRect, lp, childWidth, childHeight);
-            boolean changed = desiredChildRect.left != childRect.left ||
-                    desiredChildRect.top != childRect.top;
-            constrainChildRect(lp, desiredChildRect, childWidth, childHeight);
-
-            final int dx = desiredChildRect.left - childRect.left;
-            final int dy = desiredChildRect.top - childRect.top;
-
-            if (dx != 0) {
-                ViewCompat.offsetLeftAndRight(child, dx);
-            }
-            if (dy != 0) {
-                ViewCompat.offsetTopAndBottom(child, dy);
-            }
-
-            if (changed) {
-                // If we have needed to move, make sure to notify the child's Behavior
-                final Behavior b = lp.getBehavior();
-                if (b != null) {
-                    b.onDependentViewChanged(this, child, lp.mAnchorView);
-                }
-            }
-
-            releaseTempRect(anchorRect);
-            releaseTempRect(childRect);
-            releaseTempRect(desiredChildRect);
-        }
-    }
-
-    /**
-     * Check if a given point in the CoordinatorLayout's coordinates are within the view bounds
-     * of the given direct child view.
-     *
-     * @param child child view to test
-     * @param x X coordinate to test, in the CoordinatorLayout's coordinate system
-     * @param y Y coordinate to test, in the CoordinatorLayout's coordinate system
-     * @return true if the point is within the child view's bounds, false otherwise
-     */
-    public boolean isPointInChildBounds(View child, int x, int y) {
-        final Rect r = acquireTempRect();
-        getDescendantRect(child, r);
-        try {
-            return r.contains(x, y);
-        } finally {
-            releaseTempRect(r);
-        }
-    }
-
-    /**
-     * Check whether two views overlap each other. The views need to be descendants of this
-     * {@link CoordinatorLayout} in the view hierarchy.
-     *
-     * @param first first child view to test
-     * @param second second child view to test
-     * @return true if both views are visible and overlap each other
-     */
-    public boolean doViewsOverlap(View first, View second) {
-        if (first.getVisibility() == VISIBLE && second.getVisibility() == VISIBLE) {
-            final Rect firstRect = acquireTempRect();
-            getChildRect(first, first.getParent() != this, firstRect);
-            final Rect secondRect = acquireTempRect();
-            getChildRect(second, second.getParent() != this, secondRect);
-            try {
-                return !(firstRect.left > secondRect.right || firstRect.top > secondRect.bottom
-                        || firstRect.right < secondRect.left || firstRect.bottom < secondRect.top);
-            } finally {
-                releaseTempRect(firstRect);
-                releaseTempRect(secondRect);
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        if (p instanceof LayoutParams) {
-            return new LayoutParams((LayoutParams) p);
-        } else if (p instanceof MarginLayoutParams) {
-            return new LayoutParams((MarginLayoutParams) p);
-        }
-        return new LayoutParams(p);
-    }
-
-    @Override
-    protected LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams && super.checkLayoutParams(p);
-    }
-
-    @Override
-    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
-        return onStartNestedScroll(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public boolean onStartNestedScroll(View child, View target, int axes, int type) {
-        boolean handled = false;
-
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View view = getChildAt(i);
-            if (view.getVisibility() == View.GONE) {
-                // If it's GONE, don't dispatch
-                continue;
-            }
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            final Behavior viewBehavior = lp.getBehavior();
-            if (viewBehavior != null) {
-                final boolean accepted = viewBehavior.onStartNestedScroll(this, view, child,
-                        target, axes, type);
-                handled |= accepted;
-                lp.setNestedScrollAccepted(type, accepted);
-            } else {
-                lp.setNestedScrollAccepted(type, false);
-            }
-        }
-        return handled;
-    }
-
-    @Override
-    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
-        onNestedScrollAccepted(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes, int type) {
-        mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, nestedScrollAxes, type);
-        mNestedScrollingTarget = target;
-
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View view = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            if (!lp.isNestedScrollAccepted(type)) {
-                continue;
-            }
-
-            final Behavior viewBehavior = lp.getBehavior();
-            if (viewBehavior != null) {
-                viewBehavior.onNestedScrollAccepted(this, view, child, target,
-                        nestedScrollAxes, type);
-            }
-        }
-    }
-
-    @Override
-    public void onStopNestedScroll(View target) {
-        onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onStopNestedScroll(View target, int type) {
-        mNestedScrollingParentHelper.onStopNestedScroll(target, type);
-
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View view = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            if (!lp.isNestedScrollAccepted(type)) {
-                continue;
-            }
-
-            final Behavior viewBehavior = lp.getBehavior();
-            if (viewBehavior != null) {
-                viewBehavior.onStopNestedScroll(this, view, target, type);
-            }
-            lp.resetNestedScroll(type);
-            lp.resetChangedAfterNestedScroll();
-        }
-        mNestedScrollingTarget = null;
-    }
-
-    @Override
-    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
-            int dxUnconsumed, int dyUnconsumed) {
-        onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
-                ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
-            int dxUnconsumed, int dyUnconsumed, int type) {
-        final int childCount = getChildCount();
-        boolean accepted = false;
-
-        for (int i = 0; i < childCount; i++) {
-            final View view = getChildAt(i);
-            if (view.getVisibility() == GONE) {
-                // If the child is GONE, skip...
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            if (!lp.isNestedScrollAccepted(type)) {
-                continue;
-            }
-
-            final Behavior viewBehavior = lp.getBehavior();
-            if (viewBehavior != null) {
-                viewBehavior.onNestedScroll(this, view, target, dxConsumed, dyConsumed,
-                        dxUnconsumed, dyUnconsumed, type);
-                accepted = true;
-            }
-        }
-
-        if (accepted) {
-            onChildViewsChanged(EVENT_NESTED_SCROLL);
-        }
-    }
-
-    @Override
-    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
-        onNestedPreScroll(target, dx, dy, consumed, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed, int  type) {
-        int xConsumed = 0;
-        int yConsumed = 0;
-        boolean accepted = false;
-
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View view = getChildAt(i);
-            if (view.getVisibility() == GONE) {
-                // If the child is GONE, skip...
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            if (!lp.isNestedScrollAccepted(type)) {
-                continue;
-            }
-
-            final Behavior viewBehavior = lp.getBehavior();
-            if (viewBehavior != null) {
-                mTempIntPair[0] = mTempIntPair[1] = 0;
-                viewBehavior.onNestedPreScroll(this, view, target, dx, dy, mTempIntPair, type);
-
-                xConsumed = dx > 0 ? Math.max(xConsumed, mTempIntPair[0])
-                        : Math.min(xConsumed, mTempIntPair[0]);
-                yConsumed = dy > 0 ? Math.max(yConsumed, mTempIntPair[1])
-                        : Math.min(yConsumed, mTempIntPair[1]);
-
-                accepted = true;
-            }
-        }
-
-        consumed[0] = xConsumed;
-        consumed[1] = yConsumed;
-
-        if (accepted) {
-            onChildViewsChanged(EVENT_NESTED_SCROLL);
-        }
-    }
-
-    @Override
-    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
-        boolean handled = false;
-
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View view = getChildAt(i);
-            if (view.getVisibility() == GONE) {
-                // If the child is GONE, skip...
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            if (!lp.isNestedScrollAccepted(ViewCompat.TYPE_TOUCH)) {
-                continue;
-            }
-
-            final Behavior viewBehavior = lp.getBehavior();
-            if (viewBehavior != null) {
-                handled |= viewBehavior.onNestedFling(this, view, target, velocityX, velocityY,
-                        consumed);
-            }
-        }
-        if (handled) {
-            onChildViewsChanged(EVENT_NESTED_SCROLL);
-        }
-        return handled;
-    }
-
-    @Override
-    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
-        boolean handled = false;
-
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View view = getChildAt(i);
-            if (view.getVisibility() == GONE) {
-                // If the child is GONE, skip...
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            if (!lp.isNestedScrollAccepted(ViewCompat.TYPE_TOUCH)) {
-                continue;
-            }
-
-            final Behavior viewBehavior = lp.getBehavior();
-            if (viewBehavior != null) {
-                handled |= viewBehavior.onNestedPreFling(this, view, target, velocityX, velocityY);
-            }
-        }
-        return handled;
-    }
-
-    @Override
-    public int getNestedScrollAxes() {
-        return mNestedScrollingParentHelper.getNestedScrollAxes();
-    }
-
-    class OnPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
-        @Override
-        public boolean onPreDraw() {
-            onChildViewsChanged(EVENT_PRE_DRAW);
-            return true;
-        }
-    }
-
-    /**
-     * Sorts child views with higher Z values to the beginning of a collection.
-     */
-    static class ViewElevationComparator implements Comparator<View> {
-        @Override
-        public int compare(View lhs, View rhs) {
-            final float lz = ViewCompat.getZ(lhs);
-            final float rz = ViewCompat.getZ(rhs);
-            if (lz > rz) {
-                return -1;
-            } else if (lz < rz) {
-                return 1;
-            }
-            return 0;
-        }
-    }
-
-    /**
-     * Defines the default {@link Behavior} of a {@link View} class.
-     *
-     * <p>When writing a custom view, use this annotation to define the default behavior
-     * when used as a direct child of an {@link CoordinatorLayout}. The default behavior
-     * can be overridden using {@link LayoutParams#setBehavior}.</p>
-     *
-     * <p>Example: <code>@DefaultBehavior(MyBehavior.class)</code></p>
-     * @deprecated Use {@link AttachedBehavior} instead
-     */
-    @Deprecated
-    @Retention(RetentionPolicy.RUNTIME)
-    public @interface DefaultBehavior {
-        Class<? extends Behavior> value();
-    }
-
-    /**
-     * Defines the default attached {@link Behavior} of a {@link View} class
-     *
-     * <p>When writing a custom view, implement this interface to return the default behavior
-     * when used as a direct child of an {@link CoordinatorLayout}. The default behavior
-     * can be overridden using {@link LayoutParams#setBehavior}.</p>
-     */
-    public interface AttachedBehavior {
-        /**
-         * Returns the behavior associated with the matching {@link View} class.
-         *
-         * @return The behavior associated with the matching {@link View} class. Must be
-         * non-null.
-         */
-        @NonNull Behavior getBehavior();
-    }
-
-    /**
-     * Interaction behavior plugin for child views of {@link CoordinatorLayout}.
-     *
-     * <p>A Behavior implements one or more interactions that a user can take on a child view.
-     * These interactions may include drags, swipes, flings, or any other gestures.</p>
-     *
-     * @param <V> The View type that this Behavior operates on
-     */
-    public static abstract class Behavior<V extends View> {
-
-        /**
-         * Default constructor for instantiating Behaviors.
-         */
-        public Behavior() {
-        }
-
-        /**
-         * Default constructor for inflating Behaviors from layout. The Behavior will have
-         * the opportunity to parse specially defined layout parameters. These parameters will
-         * appear on the child view tag.
-         *
-         * @param context
-         * @param attrs
-         */
-        public Behavior(Context context, AttributeSet attrs) {
-        }
-
-        /**
-         * Called when the Behavior has been attached to a LayoutParams instance.
-         *
-         * <p>This will be called after the LayoutParams has been instantiated and can be
-         * modified.</p>
-         *
-         * @param params the LayoutParams instance that this Behavior has been attached to
-         */
-        public void onAttachedToLayoutParams(@NonNull CoordinatorLayout.LayoutParams params) {
-        }
-
-        /**
-         * Called when the Behavior has been detached from its holding LayoutParams instance.
-         *
-         * <p>This will only be called if the Behavior has been explicitly removed from the
-         * LayoutParams instance via {@link LayoutParams#setBehavior(Behavior)}. It will not be
-         * called if the associated view is removed from the CoordinatorLayout or similar.</p>
-         */
-        public void onDetachedFromLayoutParams() {
-        }
-
-        /**
-         * Respond to CoordinatorLayout touch events before they are dispatched to child views.
-         *
-         * <p>Behaviors can use this to monitor inbound touch events until one decides to
-         * intercept the rest of the event stream to take an action on its associated child view.
-         * This method will return false until it detects the proper intercept conditions, then
-         * return true once those conditions have occurred.</p>
-         *
-         * <p>Once a Behavior intercepts touch events, the rest of the event stream will
-         * be sent to the {@link #onTouchEvent} method.</p>
-         *
-         * <p>This method will be called regardless of the visibility of the associated child
-         * of the behavior. If you only wish to handle touch events when the child is visible, you
-         * should add a check to {@link View#isShown()} on the given child.</p>
-         *
-         * <p>The default implementation of this method always returns false.</p>
-         *
-         * @param parent the parent view currently receiving this touch event
-         * @param child the child view associated with this Behavior
-         * @param ev the MotionEvent describing the touch event being processed
-         * @return true if this Behavior would like to intercept and take over the event stream.
-         *         The default always returns false.
-         */
-        public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
-            return false;
-        }
-
-        /**
-         * Respond to CoordinatorLayout touch events after this Behavior has started
-         * {@link #onInterceptTouchEvent intercepting} them.
-         *
-         * <p>Behaviors may intercept touch events in order to help the CoordinatorLayout
-         * manipulate its child views. For example, a Behavior may allow a user to drag a
-         * UI pane open or closed. This method should perform actual mutations of view
-         * layout state.</p>
-         *
-         * <p>This method will be called regardless of the visibility of the associated child
-         * of the behavior. If you only wish to handle touch events when the child is visible, you
-         * should add a check to {@link View#isShown()} on the given child.</p>
-         *
-         * @param parent the parent view currently receiving this touch event
-         * @param child the child view associated with this Behavior
-         * @param ev the MotionEvent describing the touch event being processed
-         * @return true if this Behavior handled this touch event and would like to continue
-         *         receiving events in this stream. The default always returns false.
-         */
-        public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
-            return false;
-        }
-
-        /**
-         * Supply a scrim color that will be painted behind the associated child view.
-         *
-         * <p>A scrim may be used to indicate that the other elements beneath it are not currently
-         * interactive or actionable, drawing user focus and attention to the views above the scrim.
-         * </p>
-         *
-         * <p>The default implementation returns {@link Color#BLACK}.</p>
-         *
-         * @param parent the parent view of the given child
-         * @param child the child view above the scrim
-         * @return the desired scrim color in 0xAARRGGBB format. The default return value is
-         *         {@link Color#BLACK}.
-         * @see #getScrimOpacity(CoordinatorLayout, View)
-         */
-        @ColorInt
-        public int getScrimColor(CoordinatorLayout parent, V child) {
-            return Color.BLACK;
-        }
-
-        /**
-         * Determine the current opacity of the scrim behind a given child view
-         *
-         * <p>A scrim may be used to indicate that the other elements beneath it are not currently
-         * interactive or actionable, drawing user focus and attention to the views above the scrim.
-         * </p>
-         *
-         * <p>The default implementation returns 0.0f.</p>
-         *
-         * @param parent the parent view of the given child
-         * @param child the child view above the scrim
-         * @return the desired scrim opacity from 0.0f to 1.0f. The default return value is 0.0f.
-         */
-        @FloatRange(from = 0, to = 1)
-        public float getScrimOpacity(CoordinatorLayout parent, V child) {
-            return 0.f;
-        }
-
-        /**
-         * Determine whether interaction with views behind the given child in the child order
-         * should be blocked.
-         *
-         * <p>The default implementation returns true if
-         * {@link #getScrimOpacity(CoordinatorLayout, View)} would return > 0.0f.</p>
-         *
-         * @param parent the parent view of the given child
-         * @param child the child view to test
-         * @return true if {@link #getScrimOpacity(CoordinatorLayout, View)} would
-         *         return > 0.0f.
-         */
-        public boolean blocksInteractionBelow(CoordinatorLayout parent, V child) {
-            return getScrimOpacity(parent, child) > 0.f;
-        }
-
-        /**
-         * Determine whether the supplied child view has another specific sibling view as a
-         * layout dependency.
-         *
-         * <p>This method will be called at least once in response to a layout request. If it
-         * returns true for a given child and dependency view pair, the parent CoordinatorLayout
-         * will:</p>
-         * <ol>
-         *     <li>Always lay out this child after the dependent child is laid out, regardless
-         *     of child order.</li>
-         *     <li>Call {@link #onDependentViewChanged} when the dependency view's layout or
-         *     position changes.</li>
-         * </ol>
-         *
-         * @param parent the parent view of the given child
-         * @param child the child view to test
-         * @param dependency the proposed dependency of child
-         * @return true if child's layout depends on the proposed dependency's layout,
-         *         false otherwise
-         *
-         * @see #onDependentViewChanged(CoordinatorLayout, View, View)
-         */
-        public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) {
-            return false;
-        }
-
-        /**
-         * Respond to a change in a child's dependent view
-         *
-         * <p>This method is called whenever a dependent view changes in size or position outside
-         * of the standard layout flow. A Behavior may use this method to appropriately update
-         * the child view in response.</p>
-         *
-         * <p>A view's dependency is determined by
-         * {@link #layoutDependsOn(CoordinatorLayout, View, View)} or
-         * if {@code child} has set another view as it's anchor.</p>
-         *
-         * <p>Note that if a Behavior changes the layout of a child via this method, it should
-         * also be able to reconstruct the correct position in
-         * {@link #onLayoutChild(CoordinatorLayout, View, int) onLayoutChild}.
-         * <code>onDependentViewChanged</code> will not be called during normal layout since
-         * the layout of each child view will always happen in dependency order.</p>
-         *
-         * <p>If the Behavior changes the child view's size or position, it should return true.
-         * The default implementation returns false.</p>
-         *
-         * @param parent the parent view of the given child
-         * @param child the child view to manipulate
-         * @param dependency the dependent view that changed
-         * @return true if the Behavior changed the child view's size or position, false otherwise
-         */
-        public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) {
-            return false;
-        }
-
-        /**
-         * Respond to a child's dependent view being removed.
-         *
-         * <p>This method is called after a dependent view has been removed from the parent.
-         * A Behavior may use this method to appropriately update the child view in response.</p>
-         *
-         * <p>A view's dependency is determined by
-         * {@link #layoutDependsOn(CoordinatorLayout, View, View)} or
-         * if {@code child} has set another view as it's anchor.</p>
-         *
-         * @param parent the parent view of the given child
-         * @param child the child view to manipulate
-         * @param dependency the dependent view that has been removed
-         */
-        public void onDependentViewRemoved(CoordinatorLayout parent, V child, View dependency) {
-        }
-
-        /**
-         * Called when the parent CoordinatorLayout is about to measure the given child view.
-         *
-         * <p>This method can be used to perform custom or modified measurement of a child view
-         * in place of the default child measurement behavior. The Behavior's implementation
-         * can delegate to the standard CoordinatorLayout measurement behavior by calling
-         * {@link CoordinatorLayout#onMeasureChild(View, int, int, int, int)
-         * parent.onMeasureChild}.</p>
-         *
-         * @param parent the parent CoordinatorLayout
-         * @param child the child to measure
-         * @param parentWidthMeasureSpec the width requirements for this view
-         * @param widthUsed extra space that has been used up by the parent
-         *        horizontally (possibly by other children of the parent)
-         * @param parentHeightMeasureSpec the height requirements for this view
-         * @param heightUsed extra space that has been used up by the parent
-         *        vertically (possibly by other children of the parent)
-         * @return true if the Behavior measured the child view, false if the CoordinatorLayout
-         *         should perform its default measurement
-         */
-        public boolean onMeasureChild(CoordinatorLayout parent, V child,
-                int parentWidthMeasureSpec, int widthUsed,
-                int parentHeightMeasureSpec, int heightUsed) {
-            return false;
-        }
-
-        /**
-         * Called when the parent CoordinatorLayout is about the lay out the given child view.
-         *
-         * <p>This method can be used to perform custom or modified layout of a child view
-         * in place of the default child layout behavior. The Behavior's implementation can
-         * delegate to the standard CoordinatorLayout measurement behavior by calling
-         * {@link CoordinatorLayout#onLayoutChild(View, int)
-         * parent.onLayoutChild}.</p>
-         *
-         * <p>If a Behavior implements
-         * {@link #onDependentViewChanged(CoordinatorLayout, View, View)}
-         * to change the position of a view in response to a dependent view changing, it
-         * should also implement <code>onLayoutChild</code> in such a way that respects those
-         * dependent views. <code>onLayoutChild</code> will always be called for a dependent view
-         * <em>after</em> its dependency has been laid out.</p>
-         *
-         * @param parent the parent CoordinatorLayout
-         * @param child child view to lay out
-         * @param layoutDirection the resolved layout direction for the CoordinatorLayout, such as
-         *                        {@link ViewCompat#LAYOUT_DIRECTION_LTR} or
-         *                        {@link ViewCompat#LAYOUT_DIRECTION_RTL}.
-         * @return true if the Behavior performed layout of the child view, false to request
-         *         default layout behavior
-         */
-        public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
-            return false;
-        }
-
-        // Utility methods for accessing child-specific, behavior-modifiable properties.
-
-        /**
-         * Associate a Behavior-specific tag object with the given child view.
-         * This object will be stored with the child view's LayoutParams.
-         *
-         * @param child child view to set tag with
-         * @param tag tag object to set
-         */
-        public static void setTag(View child, Object tag) {
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            lp.mBehaviorTag = tag;
-        }
-
-        /**
-         * Get the behavior-specific tag object with the given child view.
-         * This object is stored with the child view's LayoutParams.
-         *
-         * @param child child view to get tag with
-         * @return the previously stored tag object
-         */
-        public static Object getTag(View child) {
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            return lp.mBehaviorTag;
-        }
-
-        /**
-         * @deprecated You should now override
-         * {@link #onStartNestedScroll(CoordinatorLayout, View, View, View, int, int)}. This
-         * method will still continue to be called if the type is {@link ViewCompat#TYPE_TOUCH}.
-         */
-        @Deprecated
-        public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
-                @ScrollAxis int axes) {
-            return false;
-        }
-
-        /**
-         * Called when a descendant of the CoordinatorLayout attempts to initiate a nested scroll.
-         *
-         * <p>Any Behavior associated with any direct child of the CoordinatorLayout may respond
-         * to this event and return true to indicate that the CoordinatorLayout should act as
-         * a nested scrolling parent for this scroll. Only Behaviors that return true from
-         * this method will receive subsequent nested scroll events.</p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param directTargetChild the child view of the CoordinatorLayout that either is or
-         *                          contains the target of the nested scroll operation
-         * @param target the descendant view of the CoordinatorLayout initiating the nested scroll
-         * @param axes the axes that this nested scroll applies to. See
-         *                         {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
-         *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL}
-         * @param type the type of input which cause this scroll event
-         * @return true if the Behavior wishes to accept this nested scroll
-         *
-         * @see NestedScrollingParent2#onStartNestedScroll(View, View, int, int)
-         */
-        public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
-                @ScrollAxis int axes, @NestedScrollType int type) {
-            if (type == ViewCompat.TYPE_TOUCH) {
-                return onStartNestedScroll(coordinatorLayout, child, directTargetChild,
-                        target, axes);
-            }
-            return false;
-        }
-
-        /**
-         * @deprecated You should now override
-         * {@link #onNestedScrollAccepted(CoordinatorLayout, View, View, View, int, int)}. This
-         * method will still continue to be called if the type is {@link ViewCompat#TYPE_TOUCH}.
-         */
-        @Deprecated
-        public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
-                @ScrollAxis int axes) {
-            // Do nothing
-        }
-
-        /**
-         * Called when a nested scroll has been accepted by the CoordinatorLayout.
-         *
-         * <p>Any Behavior associated with any direct child of the CoordinatorLayout may elect
-         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
-         * that returned true will receive subsequent nested scroll events for that nested scroll.
-         * </p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param directTargetChild the child view of the CoordinatorLayout that either is or
-         *                          contains the target of the nested scroll operation
-         * @param target the descendant view of the CoordinatorLayout initiating the nested scroll
-         * @param axes the axes that this nested scroll applies to. See
-         *                         {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
-         *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL}
-         * @param type the type of input which cause this scroll event
-         *
-         * @see NestedScrollingParent2#onNestedScrollAccepted(View, View, int, int)
-         */
-        public void onNestedScrollAccepted(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View directTargetChild, @NonNull View target,
-                @ScrollAxis int axes, @NestedScrollType int type) {
-            if (type == ViewCompat.TYPE_TOUCH) {
-                onNestedScrollAccepted(coordinatorLayout, child, directTargetChild,
-                        target, axes);
-            }
-        }
-
-        /**
-         * @deprecated You should now override
-         * {@link #onStopNestedScroll(CoordinatorLayout, View, View, int)}. This method will still
-         * continue to be called if the type is {@link ViewCompat#TYPE_TOUCH}.
-         */
-        @Deprecated
-        public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View target) {
-            // Do nothing
-        }
-
-        /**
-         * Called when a nested scroll has ended.
-         *
-         * <p>Any Behavior associated with any direct child of the CoordinatorLayout may elect
-         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
-         * that returned true will receive subsequent nested scroll events for that nested scroll.
-         * </p>
-         *
-         * <p><code>onStopNestedScroll</code> marks the end of a single nested scroll event
-         * sequence. This is a good place to clean up any state related to the nested scroll.
-         * </p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param target the descendant view of the CoordinatorLayout that initiated
-         *               the nested scroll
-         * @param type the type of input which cause this scroll event
-         *
-         * @see NestedScrollingParent2#onStopNestedScroll(View, int)
-         */
-        public void onStopNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View target, @NestedScrollType int type) {
-            if (type == ViewCompat.TYPE_TOUCH) {
-                onStopNestedScroll(coordinatorLayout, child, target);
-            }
-        }
-
-        /**
-         * @deprecated You should now override
-         * {@link #onNestedScroll(CoordinatorLayout, View, View, int, int, int, int, int)}.
-         * This method will still continue to be called if the type is
-         * {@link ViewCompat#TYPE_TOUCH}.
-         */
-        @Deprecated
-        public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
-                @NonNull View target, int dxConsumed, int dyConsumed,
-                int dxUnconsumed, int dyUnconsumed) {
-            // Do nothing
-        }
-
-        /**
-         * Called when a nested scroll in progress has updated and the target has scrolled or
-         * attempted to scroll.
-         *
-         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
-         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
-         * that returned true will receive subsequent nested scroll events for that nested scroll.
-         * </p>
-         *
-         * <p><code>onNestedScroll</code> is called each time the nested scroll is updated by the
-         * nested scrolling child, with both consumed and unconsumed components of the scroll
-         * supplied in pixels. <em>Each Behavior responding to the nested scroll will receive the
-         * same values.</em>
-         * </p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
-         * @param dxConsumed horizontal pixels consumed by the target's own scrolling operation
-         * @param dyConsumed vertical pixels consumed by the target's own scrolling operation
-         * @param dxUnconsumed horizontal pixels not consumed by the target's own scrolling
-         *                     operation, but requested by the user
-         * @param dyUnconsumed vertical pixels not consumed by the target's own scrolling operation,
-         *                     but requested by the user
-         * @param type the type of input which cause this scroll event
-         *
-         * @see NestedScrollingParent2#onNestedScroll(View, int, int, int, int, int)
-         */
-        public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child,
-                @NonNull View target, int dxConsumed, int dyConsumed,
-                int dxUnconsumed, int dyUnconsumed, @NestedScrollType int type) {
-            if (type == ViewCompat.TYPE_TOUCH) {
-                onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
-                        dxUnconsumed, dyUnconsumed);
-            }
-        }
-
-        /**
-         * @deprecated You should now override
-         * {@link #onNestedPreScroll(CoordinatorLayout, View, View, int, int, int[], int)}.
-         * This method will still continue to be called if the type is
-         * {@link ViewCompat#TYPE_TOUCH}.
-         */
-        @Deprecated
-        public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View target, int dx, int dy, @NonNull int[] consumed) {
-            // Do nothing
-        }
-
-        /**
-         * Called when a nested scroll in progress is about to update, before the target has
-         * consumed any of the scrolled distance.
-         *
-         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
-         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
-         * that returned true will receive subsequent nested scroll events for that nested scroll.
-         * </p>
-         *
-         * <p><code>onNestedPreScroll</code> is called each time the nested scroll is updated
-         * by the nested scrolling child, before the nested scrolling child has consumed the scroll
-         * distance itself. <em>Each Behavior responding to the nested scroll will receive the
-         * same values.</em> The CoordinatorLayout will report as consumed the maximum number
-         * of pixels in either direction that any Behavior responding to the nested scroll reported
-         * as consumed.</p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
-         * @param dx the raw horizontal number of pixels that the user attempted to scroll
-         * @param dy the raw vertical number of pixels that the user attempted to scroll
-         * @param consumed out parameter. consumed[0] should be set to the distance of dx that
-         *                 was consumed, consumed[1] should be set to the distance of dy that
-         *                 was consumed
-         * @param type the type of input which cause this scroll event
-         *
-         * @see NestedScrollingParent2#onNestedPreScroll(View, int, int, int[], int)
-         */
-        public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View target, int dx, int dy, @NonNull int[] consumed,
-                @NestedScrollType int type) {
-            if (type == ViewCompat.TYPE_TOUCH) {
-                onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
-            }
-        }
-
-        /**
-         * Called when a nested scrolling child is starting a fling or an action that would
-         * be a fling.
-         *
-         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
-         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
-         * that returned true will receive subsequent nested scroll events for that nested scroll.
-         * </p>
-         *
-         * <p><code>onNestedFling</code> is called when the current nested scrolling child view
-         * detects the proper conditions for a fling. It reports if the child itself consumed
-         * the fling. If it did not, the child is expected to show some sort of overscroll
-         * indication. This method should return true if it consumes the fling, so that a child
-         * that did not itself take an action in response can choose not to show an overfling
-         * indication.</p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
-         * @param velocityX horizontal velocity of the attempted fling
-         * @param velocityY vertical velocity of the attempted fling
-         * @param consumed true if the nested child view consumed the fling
-         * @return true if the Behavior consumed the fling
-         *
-         * @see NestedScrollingParent#onNestedFling(View, float, float, boolean)
-         */
-        public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View target, float velocityX, float velocityY,
-                boolean consumed) {
-            return false;
-        }
-
-        /**
-         * Called when a nested scrolling child is about to start a fling.
-         *
-         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
-         * to accept the nested scroll as part of {@link #onStartNestedScroll}. Each Behavior
-         * that returned true will receive subsequent nested scroll events for that nested scroll.
-         * </p>
-         *
-         * <p><code>onNestedPreFling</code> is called when the current nested scrolling child view
-         * detects the proper conditions for a fling, but it has not acted on it yet. A
-         * Behavior can return true to indicate that it consumed the fling. If at least one
-         * Behavior returns true, the fling should not be acted upon by the child.</p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param target the descendant view of the CoordinatorLayout performing the nested scroll
-         * @param velocityX horizontal velocity of the attempted fling
-         * @param velocityY vertical velocity of the attempted fling
-         * @return true if the Behavior consumed the fling
-         *
-         * @see NestedScrollingParent#onNestedPreFling(View, float, float)
-         */
-        public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout,
-                @NonNull V child, @NonNull View target, float velocityX, float velocityY) {
-            return false;
-        }
-
-        /**
-         * Called when the window insets have changed.
-         *
-         * <p>Any Behavior associated with the direct child of the CoordinatorLayout may elect
-         * to handle the window inset change on behalf of it's associated view.
-         * </p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child the child view of the CoordinatorLayout this Behavior is associated with
-         * @param insets the new window insets.
-         *
-         * @return The insets supplied, minus any insets that were consumed
-         */
-        @NonNull
-        public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout,
-                V child, WindowInsetsCompat insets) {
-            return insets;
-        }
-
-        /**
-         * Called when a child of the view associated with this behavior wants a particular
-         * rectangle to be positioned onto the screen.
-         *
-         * <p>The contract for this method is the same as
-         * {@link ViewParent#requestChildRectangleOnScreen(View, Rect, boolean)}.</p>
-         *
-         * @param coordinatorLayout the CoordinatorLayout parent of the view this Behavior is
-         *                          associated with
-         * @param child             the child view of the CoordinatorLayout this Behavior is
-         *                          associated with
-         * @param rectangle         The rectangle which the child wishes to be on the screen
-         *                          in the child's coordinates
-         * @param immediate         true to forbid animated or delayed scrolling, false otherwise
-         * @return true if the Behavior handled the request
-         * @see ViewParent#requestChildRectangleOnScreen(View, Rect, boolean)
-         */
-        public boolean onRequestChildRectangleOnScreen(CoordinatorLayout coordinatorLayout,
-                V child, Rect rectangle, boolean immediate) {
-            return false;
-        }
-
-        /**
-         * Hook allowing a behavior to re-apply a representation of its internal state that had
-         * previously been generated by {@link #onSaveInstanceState}. This function will never
-         * be called with a null state.
-         *
-         * @param parent the parent CoordinatorLayout
-         * @param child child view to restore from
-         * @param state The frozen state that had previously been returned by
-         *        {@link #onSaveInstanceState}.
-         *
-         * @see #onSaveInstanceState()
-         */
-        public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
-            // no-op
-        }
-
-        /**
-         * Hook allowing a behavior to generate a representation of its internal state
-         * that can later be used to create a new instance with that same state.
-         * This state should only contain information that is not persistent or can
-         * not be reconstructed later.
-         *
-         * <p>Behavior state is only saved when both the parent {@link CoordinatorLayout} and
-         * a view using this behavior have valid IDs set.</p>
-         *
-         * @param parent the parent CoordinatorLayout
-         * @param child child view to restore from
-         *
-         * @return Returns a Parcelable object containing the behavior's current dynamic
-         *         state.
-         *
-         * @see #onRestoreInstanceState(Parcelable)
-         * @see View#onSaveInstanceState()
-         */
-        public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
-            return BaseSavedState.EMPTY_STATE;
-        }
-
-        /**
-         * Called when a view is set to dodge view insets.
-         *
-         * <p>This method allows a behavior to update the rectangle that should be dodged.
-         * The rectangle should be in the parent's coordinate system and within the child's
-         * bounds. If not, a {@link IllegalArgumentException} is thrown.</p>
-         *
-         * @param parent the CoordinatorLayout parent of the view this Behavior is
-         *               associated with
-         * @param child  the child view of the CoordinatorLayout this Behavior is associated with
-         * @param rect   the rect to update with the dodge rectangle
-         * @return true the rect was updated, false if we should use the child's bounds
-         */
-        public boolean getInsetDodgeRect(@NonNull CoordinatorLayout parent, @NonNull V child,
-                @NonNull Rect rect) {
-            return false;
-        }
-    }
-
-    /**
-     * Parameters describing the desired layout for a child of a {@link CoordinatorLayout}.
-     */
-    public static class LayoutParams extends MarginLayoutParams {
-        /**
-         * A {@link Behavior} that the child view should obey.
-         */
-        Behavior mBehavior;
-
-        boolean mBehaviorResolved = false;
-
-        /**
-         * A {@link Gravity} value describing how this child view should lay out.
-         * If either or both of the axes are not specified, they are treated by CoordinatorLayout
-         * as {@link Gravity#TOP} or {@link GravityCompat#START}. If an
-         * {@link #setAnchorId(int) anchor} is also specified, the gravity describes how this child
-         * view should be positioned relative to its anchored position.
-         */
-        public int gravity = Gravity.NO_GRAVITY;
-
-        /**
-         * A {@link Gravity} value describing which edge of a child view's
-         * {@link #getAnchorId() anchor} view the child should position itself relative to.
-         */
-        public int anchorGravity = Gravity.NO_GRAVITY;
-
-        /**
-         * The index of the horizontal keyline specified to the parent CoordinatorLayout that this
-         * child should align relative to. If an {@link #setAnchorId(int) anchor} is present the
-         * keyline will be ignored.
-         */
-        public int keyline = -1;
-
-        /**
-         * A {@link View#getId() view id} of a descendant view of the CoordinatorLayout that
-         * this child should position relative to.
-         */
-        int mAnchorId = View.NO_ID;
-
-        /**
-         * A {@link Gravity} value describing how this child view insets the CoordinatorLayout.
-         * Other child views which are set to dodge the same inset edges will be moved appropriately
-         * so that the views do not overlap.
-         */
-        public int insetEdge = Gravity.NO_GRAVITY;
-
-        /**
-         * A {@link Gravity} value describing how this child view dodges any inset child views in
-         * the CoordinatorLayout. Any views which are inset on the same edge as this view is set to
-         * dodge will result in this view being moved so that the views do not overlap.
-         */
-        public int dodgeInsetEdges = Gravity.NO_GRAVITY;
-
-        int mInsetOffsetX;
-        int mInsetOffsetY;
-
-        View mAnchorView;
-        View mAnchorDirectChild;
-
-        private boolean mDidBlockInteraction;
-        private boolean mDidAcceptNestedScrollTouch;
-        private boolean mDidAcceptNestedScrollNonTouch;
-        private boolean mDidChangeAfterNestedScroll;
-
-        final Rect mLastChildRect = new Rect();
-
-        Object mBehaviorTag;
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        LayoutParams(Context context, AttributeSet attrs) {
-            super(context, attrs);
-
-            final TypedArray a = context.obtainStyledAttributes(attrs,
-                    R.styleable.CoordinatorLayout_Layout);
-
-            this.gravity = a.getInteger(
-                    R.styleable.CoordinatorLayout_Layout_android_layout_gravity,
-                    Gravity.NO_GRAVITY);
-            mAnchorId = a.getResourceId(R.styleable.CoordinatorLayout_Layout_layout_anchor,
-                    View.NO_ID);
-            this.anchorGravity = a.getInteger(
-                    R.styleable.CoordinatorLayout_Layout_layout_anchorGravity,
-                    Gravity.NO_GRAVITY);
-
-            this.keyline = a.getInteger(R.styleable.CoordinatorLayout_Layout_layout_keyline,
-                    -1);
-
-            insetEdge = a.getInt(R.styleable.CoordinatorLayout_Layout_layout_insetEdge, 0);
-            dodgeInsetEdges = a.getInt(
-                    R.styleable.CoordinatorLayout_Layout_layout_dodgeInsetEdges, 0);
-            mBehaviorResolved = a.hasValue(
-                    R.styleable.CoordinatorLayout_Layout_layout_behavior);
-            if (mBehaviorResolved) {
-                mBehavior = parseBehavior(context, attrs, a.getString(
-                        R.styleable.CoordinatorLayout_Layout_layout_behavior));
-            }
-            a.recycle();
-
-            if (mBehavior != null) {
-                // If we have a Behavior, dispatch that it has been attached
-                mBehavior.onAttachedToLayoutParams(this);
-            }
-        }
-
-        public LayoutParams(LayoutParams p) {
-            super(p);
-        }
-
-        public LayoutParams(MarginLayoutParams p) {
-            super(p);
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams p) {
-            super(p);
-        }
-
-        /**
-         * Get the id of this view's anchor.
-         *
-         * @return A {@link View#getId() view id} or {@link View#NO_ID} if there is no anchor
-         */
-        @IdRes
-        public int getAnchorId() {
-            return mAnchorId;
-        }
-
-        /**
-         * Set the id of this view's anchor.
-         *
-         * <p>The view with this id must be a descendant of the CoordinatorLayout containing
-         * the child view this LayoutParams belongs to. It may not be the child view with
-         * this LayoutParams or a descendant of it.</p>
-         *
-         * @param id The {@link View#getId() view id} of the anchor or
-         *           {@link View#NO_ID} if there is no anchor
-         */
-        public void setAnchorId(@IdRes int id) {
-            invalidateAnchor();
-            mAnchorId = id;
-        }
-
-        /**
-         * Get the behavior governing the layout and interaction of the child view within
-         * a parent CoordinatorLayout.
-         *
-         * @return The current behavior or null if no behavior is specified
-         */
-        @Nullable
-        public Behavior getBehavior() {
-            return mBehavior;
-        }
-
-        /**
-         * Set the behavior governing the layout and interaction of the child view within
-         * a parent CoordinatorLayout.
-         *
-         * <p>Setting a new behavior will remove any currently associated
-         * {@link Behavior#setTag(View, Object) Behavior tag}.</p>
-         *
-         * @param behavior The behavior to set or null for no special behavior
-         */
-        public void setBehavior(@Nullable Behavior behavior) {
-            if (mBehavior != behavior) {
-                if (mBehavior != null) {
-                    // First detach any old behavior
-                    mBehavior.onDetachedFromLayoutParams();
-                }
-
-                mBehavior = behavior;
-                mBehaviorTag = null;
-                mBehaviorResolved = true;
-
-                if (behavior != null) {
-                    // Now dispatch that the Behavior has been attached
-                    behavior.onAttachedToLayoutParams(this);
-                }
-            }
-        }
-
-        /**
-         * Set the last known position rect for this child view
-         * @param r the rect to set
-         */
-        void setLastChildRect(Rect r) {
-            mLastChildRect.set(r);
-        }
-
-        /**
-         * Get the last known position rect for this child view.
-         * Note: do not mutate the result of this call.
-         */
-        Rect getLastChildRect() {
-            return mLastChildRect;
-        }
-
-        /**
-         * Returns true if the anchor id changed to another valid view id since the anchor view
-         * was resolved.
-         */
-        boolean checkAnchorChanged() {
-            return mAnchorView == null && mAnchorId != View.NO_ID;
-        }
-
-        /**
-         * Returns true if the associated Behavior previously blocked interaction with other views
-         * below the associated child since the touch behavior tracking was last
-         * {@link #resetTouchBehaviorTracking() reset}.
-         *
-         * @see #isBlockingInteractionBelow(CoordinatorLayout, View)
-         */
-        boolean didBlockInteraction() {
-            if (mBehavior == null) {
-                mDidBlockInteraction = false;
-            }
-            return mDidBlockInteraction;
-        }
-
-        /**
-         * Check if the associated Behavior wants to block interaction below the given child
-         * view. The given child view should be the child this LayoutParams is associated with.
-         *
-         * <p>Once interaction is blocked, it will remain blocked until touch interaction tracking
-         * is {@link #resetTouchBehaviorTracking() reset}.</p>
-         *
-         * @param parent the parent CoordinatorLayout
-         * @param child the child view this LayoutParams is associated with
-         * @return true to block interaction below the given child
-         */
-        boolean isBlockingInteractionBelow(CoordinatorLayout parent, View child) {
-            if (mDidBlockInteraction) {
-                return true;
-            }
-
-            return mDidBlockInteraction |= mBehavior != null
-                    ? mBehavior.blocksInteractionBelow(parent, child)
-                    : false;
-        }
-
-        /**
-         * Reset tracking of Behavior-specific touch interactions. This includes
-         * interaction blocking.
-         *
-         * @see #isBlockingInteractionBelow(CoordinatorLayout, View)
-         * @see #didBlockInteraction()
-         */
-        void resetTouchBehaviorTracking() {
-            mDidBlockInteraction = false;
-        }
-
-        void resetNestedScroll(int type) {
-            setNestedScrollAccepted(type, false);
-        }
-
-        void setNestedScrollAccepted(int type, boolean accept) {
-            switch (type) {
-                case ViewCompat.TYPE_TOUCH:
-                    mDidAcceptNestedScrollTouch = accept;
-                    break;
-                case ViewCompat.TYPE_NON_TOUCH:
-                    mDidAcceptNestedScrollNonTouch = accept;
-                    break;
-            }
-        }
-
-        boolean isNestedScrollAccepted(int type) {
-            switch (type) {
-                case ViewCompat.TYPE_TOUCH:
-                    return mDidAcceptNestedScrollTouch;
-                case ViewCompat.TYPE_NON_TOUCH:
-                    return mDidAcceptNestedScrollNonTouch;
-            }
-            return false;
-        }
-
-        boolean getChangedAfterNestedScroll() {
-            return mDidChangeAfterNestedScroll;
-        }
-
-        void setChangedAfterNestedScroll(boolean changed) {
-            mDidChangeAfterNestedScroll = changed;
-        }
-
-        void resetChangedAfterNestedScroll() {
-            mDidChangeAfterNestedScroll = false;
-        }
-
-        /**
-         * Check if an associated child view depends on another child view of the CoordinatorLayout.
-         *
-         * @param parent the parent CoordinatorLayout
-         * @param child the child to check
-         * @param dependency the proposed dependency to check
-         * @return true if child depends on dependency
-         */
-        boolean dependsOn(CoordinatorLayout parent, View child, View dependency) {
-            return dependency == mAnchorDirectChild
-                    || shouldDodge(dependency, ViewCompat.getLayoutDirection(parent))
-                    || (mBehavior != null && mBehavior.layoutDependsOn(parent, child, dependency));
-        }
-
-        /**
-         * Invalidate the cached anchor view and direct child ancestor of that anchor.
-         * The anchor will need to be
-         * {@link #findAnchorView(CoordinatorLayout, View) found} before
-         * being used again.
-         */
-        void invalidateAnchor() {
-            mAnchorView = mAnchorDirectChild = null;
-        }
-
-        /**
-         * Locate the appropriate anchor view by the current {@link #setAnchorId(int) anchor id}
-         * or return the cached anchor view if already known.
-         *
-         * @param parent the parent CoordinatorLayout
-         * @param forChild the child this LayoutParams is associated with
-         * @return the located descendant anchor view, or null if the anchor id is
-         *         {@link View#NO_ID}.
-         */
-        View findAnchorView(CoordinatorLayout parent, View forChild) {
-            if (mAnchorId == View.NO_ID) {
-                mAnchorView = mAnchorDirectChild = null;
-                return null;
-            }
-
-            if (mAnchorView == null || !verifyAnchorView(forChild, parent)) {
-                resolveAnchorView(forChild, parent);
-            }
-            return mAnchorView;
-        }
-
-        /**
-         * Determine the anchor view for the child view this LayoutParams is assigned to.
-         * Assumes mAnchorId is valid.
-         */
-        private void resolveAnchorView(final View forChild, final CoordinatorLayout parent) {
-            mAnchorView = parent.findViewById(mAnchorId);
-            if (mAnchorView != null) {
-                if (mAnchorView == parent) {
-                    if (parent.isInEditMode()) {
-                        mAnchorView = mAnchorDirectChild = null;
-                        return;
-                    }
-                    throw new IllegalStateException(
-                            "View can not be anchored to the the parent CoordinatorLayout");
-                }
-
-                View directChild = mAnchorView;
-                for (ViewParent p = mAnchorView.getParent();
-                        p != parent && p != null;
-                        p = p.getParent()) {
-                    if (p == forChild) {
-                        if (parent.isInEditMode()) {
-                            mAnchorView = mAnchorDirectChild = null;
-                            return;
-                        }
-                        throw new IllegalStateException(
-                                "Anchor must not be a descendant of the anchored view");
-                    }
-                    if (p instanceof View) {
-                        directChild = (View) p;
-                    }
-                }
-                mAnchorDirectChild = directChild;
-            } else {
-                if (parent.isInEditMode()) {
-                    mAnchorView = mAnchorDirectChild = null;
-                    return;
-                }
-                throw new IllegalStateException("Could not find CoordinatorLayout descendant view"
-                        + " with id " + parent.getResources().getResourceName(mAnchorId)
-                        + " to anchor view " + forChild);
-            }
-        }
-
-        /**
-         * Verify that the previously resolved anchor view is still valid - that it is still
-         * a descendant of the expected parent view, it is not the child this LayoutParams
-         * is assigned to or a descendant of it, and it has the expected id.
-         */
-        private boolean verifyAnchorView(View forChild, CoordinatorLayout parent) {
-            if (mAnchorView.getId() != mAnchorId) {
-                return false;
-            }
-
-            View directChild = mAnchorView;
-            for (ViewParent p = mAnchorView.getParent();
-                    p != parent;
-                    p = p.getParent()) {
-                if (p == null || p == forChild) {
-                    mAnchorView = mAnchorDirectChild = null;
-                    return false;
-                }
-                if (p instanceof View) {
-                    directChild = (View) p;
-                }
-            }
-            mAnchorDirectChild = directChild;
-            return true;
-        }
-
-        /**
-         * Checks whether the view with this LayoutParams should dodge the specified view.
-         */
-        private boolean shouldDodge(View other, int layoutDirection) {
-            LayoutParams lp = (LayoutParams) other.getLayoutParams();
-            final int absInset = GravityCompat.getAbsoluteGravity(lp.insetEdge, layoutDirection);
-            return absInset != Gravity.NO_GRAVITY && (absInset &
-                    GravityCompat.getAbsoluteGravity(dodgeInsetEdges, layoutDirection)) == absInset;
-        }
-    }
-
-    private class HierarchyChangeListener implements OnHierarchyChangeListener {
-        HierarchyChangeListener() {
-        }
-
-        @Override
-        public void onChildViewAdded(View parent, View child) {
-            if (mOnHierarchyChangeListener != null) {
-                mOnHierarchyChangeListener.onChildViewAdded(parent, child);
-            }
-        }
-
-        @Override
-        public void onChildViewRemoved(View parent, View child) {
-            onChildViewsChanged(EVENT_VIEW_REMOVED);
-
-            if (mOnHierarchyChangeListener != null) {
-                mOnHierarchyChangeListener.onChildViewRemoved(parent, child);
-            }
-        }
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-
-        final SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-
-        final SparseArray<Parcelable> behaviorStates = ss.behaviorStates;
-
-        for (int i = 0, count = getChildCount(); i < count; i++) {
-            final View child = getChildAt(i);
-            final int childId = child.getId();
-            final LayoutParams lp = getResolvedLayoutParams(child);
-            final Behavior b = lp.getBehavior();
-
-            if (childId != NO_ID && b != null) {
-                Parcelable savedState = behaviorStates.get(childId);
-                if (savedState != null) {
-                    b.onRestoreInstanceState(this, child, savedState);
-                }
-            }
-        }
-    }
-
-    @Override
-    protected Parcelable onSaveInstanceState() {
-        final SavedState ss = new SavedState(super.onSaveInstanceState());
-
-        final SparseArray<Parcelable> behaviorStates = new SparseArray<>();
-        for (int i = 0, count = getChildCount(); i < count; i++) {
-            final View child = getChildAt(i);
-            final int childId = child.getId();
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final Behavior b = lp.getBehavior();
-
-            if (childId != NO_ID && b != null) {
-                // If the child has an ID and a Behavior, let it save some state...
-                Parcelable state = b.onSaveInstanceState(this, child);
-                if (state != null) {
-                    behaviorStates.append(childId, state);
-                }
-            }
-        }
-        ss.behaviorStates = behaviorStates;
-        return ss;
-    }
-
-    @Override
-    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        final Behavior behavior = lp.getBehavior();
-
-        if (behavior != null
-                && behavior.onRequestChildRectangleOnScreen(this, child, rectangle, immediate)) {
-            return true;
-        }
-
-        return super.requestChildRectangleOnScreen(child, rectangle, immediate);
-    }
-
-    private void setupForInsets() {
-        if (Build.VERSION.SDK_INT < 21) {
-            return;
-        }
-
-        if (ViewCompat.getFitsSystemWindows(this)) {
-            if (mApplyWindowInsetsListener == null) {
-                mApplyWindowInsetsListener =
-                        new android.support.v4.view.OnApplyWindowInsetsListener() {
-                            @Override
-                            public WindowInsetsCompat onApplyWindowInsets(View v,
-                                    WindowInsetsCompat insets) {
-                                return setWindowInsets(insets);
-                            }
-                        };
-            }
-            // First apply the insets listener
-            ViewCompat.setOnApplyWindowInsetsListener(this, mApplyWindowInsetsListener);
-
-            // Now set the sys ui flags to enable us to lay out in the window insets
-            setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
-        } else {
-            ViewCompat.setOnApplyWindowInsetsListener(this, null);
-        }
-    }
-
-    protected static class SavedState extends AbsSavedState {
-        SparseArray<Parcelable> behaviorStates;
-
-        public SavedState(Parcel source, ClassLoader loader) {
-            super(source, loader);
-
-            final int size = source.readInt();
-
-            final int[] ids = new int[size];
-            source.readIntArray(ids);
-
-            final Parcelable[] states = source.readParcelableArray(loader);
-
-            behaviorStates = new SparseArray<>(size);
-            for (int i = 0; i < size; i++) {
-                behaviorStates.append(ids[i], states[i]);
-            }
-        }
-
-        public SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-
-            final int size = behaviorStates != null ? behaviorStates.size() : 0;
-            dest.writeInt(size);
-
-            final int[] ids = new int[size];
-            final Parcelable[] states = new Parcelable[size];
-
-            for (int i = 0; i < size; i++) {
-                ids[i] = behaviorStates.keyAt(i);
-                states[i] = behaviorStates.valueAt(i);
-            }
-            dest.writeIntArray(ids);
-            dest.writeParcelableArray(states, flags);
-
-        }
-
-        public static final Creator<SavedState> CREATOR =
-                new ClassLoaderCreator<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                        return new SavedState(in, loader);
-                    }
-
-                    @Override
-                    public SavedState createFromParcel(Parcel in) {
-                        return new SavedState(in, null);
-                    }
-
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                };
-    }
-}
diff --git a/core-ui/src/main/java/android/support/v4/widget/DrawerLayout.java b/core-ui/src/main/java/android/support/v4/widget/DrawerLayout.java
deleted file mode 100644
index aa2077d..0000000
--- a/core-ui/src/main/java/android/support/v4/widget/DrawerLayout.java
+++ /dev/null
@@ -1,2384 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.support.v4.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.WindowInsets;
-import android.view.accessibility.AccessibilityEvent;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * DrawerLayout acts as a top-level container for window content that allows for
- * interactive "drawer" views to be pulled out from one or both vertical edges of the window.
- *
- * <p>Drawer positioning and layout is controlled using the <code>android:layout_gravity</code>
- * attribute on child views corresponding to which side of the view you want the drawer
- * to emerge from: left or right (or start/end on platform versions that support layout direction.)
- * Note that you can only have one drawer view for each vertical edge of the window. If your
- * layout configures more than one drawer view per vertical edge of the window, an exception will
- * be thrown at runtime.
- * </p>
- *
- * <p>To use a DrawerLayout, position your primary content view as the first child with
- * width and height of <code>match_parent</code> and no <code>layout_gravity></code>.
- * Add drawers as child views after the main content view and set the <code>layout_gravity</code>
- * appropriately. Drawers commonly use <code>match_parent</code> for height with a fixed width.</p>
- *
- * <p>{@link DrawerListener} can be used to monitor the state and motion of drawer views.
- * Avoid performing expensive operations such as layout during animation as it can cause
- * stuttering; try to perform expensive operations during the {@link #STATE_IDLE} state.
- * {@link SimpleDrawerListener} offers default/no-op implementations of each callback method.</p>
- *
- * <p>As per the <a href="{@docRoot}design/patterns/navigation-drawer.html">Android Design
- * guide</a>, any drawers positioned to the left/start should
- * always contain content for navigating around the application, whereas any drawers
- * positioned to the right/end should always contain actions to take on the current content.
- * This preserves the same navigation left, actions right structure present in the Action Bar
- * and elsewhere.</p>
- *
- * <p>For more information about how to use DrawerLayout, read <a
- * href="{@docRoot}training/implementing-navigation/nav-drawer.html">Creating a Navigation
- * Drawer</a>.</p>
- */
-public class DrawerLayout extends ViewGroup {
-    private static final String TAG = "DrawerLayout";
-
-    private static final int[] THEME_ATTRS = {
-            android.R.attr.colorPrimaryDark
-    };
-
-    @IntDef({STATE_IDLE, STATE_DRAGGING, STATE_SETTLING})
-    @Retention(RetentionPolicy.SOURCE)
-    private @interface State {}
-
-    /**
-     * Indicates that any drawers are in an idle, settled state. No animation is in progress.
-     */
-    public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
-
-    /**
-     * Indicates that a drawer is currently being dragged by the user.
-     */
-    public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
-
-    /**
-     * Indicates that a drawer is in the process of settling to a final position.
-     */
-    public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
-
-    @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN,
-            LOCK_MODE_UNDEFINED})
-    @Retention(RetentionPolicy.SOURCE)
-    private @interface LockMode {}
-
-    /**
-     * The drawer is unlocked.
-     */
-    public static final int LOCK_MODE_UNLOCKED = 0;
-
-    /**
-     * The drawer is locked closed. The user may not open it, though
-     * the app may open it programmatically.
-     */
-    public static final int LOCK_MODE_LOCKED_CLOSED = 1;
-
-    /**
-     * The drawer is locked open. The user may not close it, though the app
-     * may close it programmatically.
-     */
-    public static final int LOCK_MODE_LOCKED_OPEN = 2;
-
-    /**
-     * The drawer's lock state is reset to default.
-     */
-    public static final int LOCK_MODE_UNDEFINED = 3;
-
-    @IntDef(value = {Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END},
-            flag = true)
-    @Retention(RetentionPolicy.SOURCE)
-    private @interface EdgeGravity {}
-
-
-    private static final int MIN_DRAWER_MARGIN = 64; // dp
-    private static final int DRAWER_ELEVATION = 10; //dp
-
-    private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
-
-    /**
-     * Length of time to delay before peeking the drawer.
-     */
-    private static final int PEEK_DELAY = 160; // ms
-
-    /**
-     * Minimum velocity that will be detected as a fling
-     */
-    private static final int MIN_FLING_VELOCITY = 400; // dips per second
-
-    /**
-     * Experimental feature.
-     */
-    private static final boolean ALLOW_EDGE_LOCK = false;
-
-    private static final boolean CHILDREN_DISALLOW_INTERCEPT = true;
-
-    private static final float TOUCH_SLOP_SENSITIVITY = 1.f;
-
-    static final int[] LAYOUT_ATTRS = new int[] {
-            android.R.attr.layout_gravity
-    };
-
-    /** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */
-    static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
-
-    /** Whether the drawer shadow comes from setting elevation on the drawer. */
-    private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION =
-            Build.VERSION.SDK_INT >= 21;
-
-    private final ChildAccessibilityDelegate mChildAccessibilityDelegate =
-            new ChildAccessibilityDelegate();
-    private float mDrawerElevation;
-
-    private int mMinDrawerMargin;
-
-    private int mScrimColor = DEFAULT_SCRIM_COLOR;
-    private float mScrimOpacity;
-    private Paint mScrimPaint = new Paint();
-
-    private final ViewDragHelper mLeftDragger;
-    private final ViewDragHelper mRightDragger;
-    private final ViewDragCallback mLeftCallback;
-    private final ViewDragCallback mRightCallback;
-    private int mDrawerState;
-    private boolean mInLayout;
-    private boolean mFirstLayout = true;
-
-    private @LockMode int mLockModeLeft = LOCK_MODE_UNDEFINED;
-    private @LockMode int mLockModeRight = LOCK_MODE_UNDEFINED;
-    private @LockMode int mLockModeStart = LOCK_MODE_UNDEFINED;
-    private @LockMode int mLockModeEnd = LOCK_MODE_UNDEFINED;
-
-    private boolean mDisallowInterceptRequested;
-    private boolean mChildrenCanceledTouch;
-
-    private @Nullable DrawerListener mListener;
-    private List<DrawerListener> mListeners;
-
-    private float mInitialMotionX;
-    private float mInitialMotionY;
-
-    private Drawable mStatusBarBackground;
-    private Drawable mShadowLeftResolved;
-    private Drawable mShadowRightResolved;
-
-    private CharSequence mTitleLeft;
-    private CharSequence mTitleRight;
-
-    private Object mLastInsets;
-    private boolean mDrawStatusBarBackground;
-
-    /** Shadow drawables for different gravity */
-    private Drawable mShadowStart = null;
-    private Drawable mShadowEnd = null;
-    private Drawable mShadowLeft = null;
-    private Drawable mShadowRight = null;
-
-    private final ArrayList<View> mNonDrawerViews;
-
-    /**
-     * Listener for monitoring events about drawers.
-     */
-    public interface DrawerListener {
-        /**
-         * Called when a drawer's position changes.
-         * @param drawerView The child view that was moved
-         * @param slideOffset The new offset of this drawer within its range, from 0-1
-         */
-        void onDrawerSlide(@NonNull View drawerView, float slideOffset);
-
-        /**
-         * Called when a drawer has settled in a completely open state.
-         * The drawer is interactive at this point.
-         *
-         * @param drawerView Drawer view that is now open
-         */
-        void onDrawerOpened(@NonNull View drawerView);
-
-        /**
-         * Called when a drawer has settled in a completely closed state.
-         *
-         * @param drawerView Drawer view that is now closed
-         */
-        void onDrawerClosed(@NonNull View drawerView);
-
-        /**
-         * Called when the drawer motion state changes. The new state will
-         * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
-         *
-         * @param newState The new drawer motion state
-         */
-        void onDrawerStateChanged(@State int newState);
-    }
-
-    /**
-     * Stub/no-op implementations of all methods of {@link DrawerListener}.
-     * Override this if you only care about a few of the available callback methods.
-     */
-    public abstract static class SimpleDrawerListener implements DrawerListener {
-        @Override
-        public void onDrawerSlide(View drawerView, float slideOffset) {
-        }
-
-        @Override
-        public void onDrawerOpened(View drawerView) {
-        }
-
-        @Override
-        public void onDrawerClosed(View drawerView) {
-        }
-
-        @Override
-        public void onDrawerStateChanged(int newState) {
-        }
-    }
-
-    public DrawerLayout(@NonNull Context context) {
-        this(context, null);
-    }
-
-    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
-        final float density = getResources().getDisplayMetrics().density;
-        mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);
-        final float minVel = MIN_FLING_VELOCITY * density;
-
-        mLeftCallback = new ViewDragCallback(Gravity.LEFT);
-        mRightCallback = new ViewDragCallback(Gravity.RIGHT);
-
-        mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);
-        mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
-        mLeftDragger.setMinVelocity(minVel);
-        mLeftCallback.setDragger(mLeftDragger);
-
-        mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback);
-        mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
-        mRightDragger.setMinVelocity(minVel);
-        mRightCallback.setDragger(mRightDragger);
-
-        // So that we can catch the back button
-        setFocusableInTouchMode(true);
-
-        ViewCompat.setImportantForAccessibility(this,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-
-        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
-        setMotionEventSplittingEnabled(false);
-        if (ViewCompat.getFitsSystemWindows(this)) {
-            if (Build.VERSION.SDK_INT >= 21) {
-                setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
-                    @TargetApi(21)
-                    @Override
-                    public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
-                        final DrawerLayout drawerLayout = (DrawerLayout) view;
-                        drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
-                        return insets.consumeSystemWindowInsets();
-                    }
-                });
-                setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
-                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
-                final TypedArray a = context.obtainStyledAttributes(THEME_ATTRS);
-                try {
-                    mStatusBarBackground = a.getDrawable(0);
-                } finally {
-                    a.recycle();
-                }
-            } else {
-                mStatusBarBackground = null;
-            }
-        }
-
-        mDrawerElevation = DRAWER_ELEVATION * density;
-
-        mNonDrawerViews = new ArrayList<View>();
-    }
-
-    /**
-     * Sets the base elevation of the drawer(s) relative to the parent, in pixels. Note that the
-     * elevation change is only supported in API 21 and above.
-     *
-     * @param elevation The base depth position of the view, in pixels.
-     */
-    public void setDrawerElevation(float elevation) {
-        mDrawerElevation = elevation;
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (isDrawerView(child)) {
-                ViewCompat.setElevation(child, mDrawerElevation);
-            }
-        }
-    }
-
-    /**
-     * The base elevation of the drawer(s) relative to the parent, in pixels. Note that the
-     * elevation change is only supported in API 21 and above. For unsupported API levels, 0 will
-     * be returned as the elevation.
-     *
-     * @return The base depth position of the view, in pixels.
-     */
-    public float getDrawerElevation() {
-        if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
-            return mDrawerElevation;
-        }
-        return 0f;
-    }
-
-    /**
-     * @hide Internal use only; called to apply window insets when configured
-     * with fitsSystemWindows="true"
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public void setChildInsets(Object insets, boolean draw) {
-        mLastInsets = insets;
-        mDrawStatusBarBackground = draw;
-        setWillNotDraw(!draw && getBackground() == null);
-        requestLayout();
-    }
-
-    /**
-     * Set a simple drawable used for the left or right shadow. The drawable provided must have a
-     * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
-     * instead of using the provided shadow drawable.
-     *
-     * <p>Note that for better support for both left-to-right and right-to-left layout
-     * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
-     * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
-     * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
-     * auto-mirrored such that the drawable will be mirrored in RTL layout.</p>
-     *
-     * @param shadowDrawable Shadow drawable to use at the edge of a drawer
-     * @param gravity Which drawer the shadow should apply to
-     */
-    public void setDrawerShadow(Drawable shadowDrawable, @EdgeGravity int gravity) {
-        /*
-         * TODO Someone someday might want to set more complex drawables here.
-         * They're probably nuts, but we might want to consider registering callbacks,
-         * setting states, etc. properly.
-         */
-        if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
-            // No op. Drawer shadow will come from setting an elevation on the drawer.
-            return;
-        }
-        if ((gravity & GravityCompat.START) == GravityCompat.START) {
-            mShadowStart = shadowDrawable;
-        } else if ((gravity & GravityCompat.END) == GravityCompat.END) {
-            mShadowEnd = shadowDrawable;
-        } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
-            mShadowLeft = shadowDrawable;
-        } else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
-            mShadowRight = shadowDrawable;
-        } else {
-            return;
-        }
-        resolveShadowDrawables();
-        invalidate();
-    }
-
-    /**
-     * Set a simple drawable used for the left or right shadow. The drawable provided must have a
-     * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
-     * instead of using the provided shadow drawable.
-     *
-     * <p>Note that for better support for both left-to-right and right-to-left layout
-     * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
-     * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
-     * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
-     * auto-mirrored such that the drawable will be mirrored in RTL layout.</p>
-     *
-     * @param resId Resource id of a shadow drawable to use at the edge of a drawer
-     * @param gravity Which drawer the shadow should apply to
-     */
-    public void setDrawerShadow(@DrawableRes int resId, @EdgeGravity int gravity) {
-        setDrawerShadow(ContextCompat.getDrawable(getContext(), resId), gravity);
-    }
-
-    /**
-     * Set a color to use for the scrim that obscures primary content while a drawer is open.
-     *
-     * @param color Color to use in 0xAARRGGBB format.
-     */
-    public void setScrimColor(@ColorInt int color) {
-        mScrimColor = color;
-        invalidate();
-    }
-
-    /**
-     * Set a listener to be notified of drawer events. Note that this method is deprecated
-     * and you should use {@link #addDrawerListener(DrawerListener)} to add a listener and
-     * {@link #removeDrawerListener(DrawerListener)} to remove a registered listener.
-     *
-     * @param listener Listener to notify when drawer events occur
-     * @deprecated Use {@link #addDrawerListener(DrawerListener)}
-     * @see DrawerListener
-     * @see #addDrawerListener(DrawerListener)
-     * @see #removeDrawerListener(DrawerListener)
-     */
-    @Deprecated
-    public void setDrawerListener(DrawerListener listener) {
-        // The logic in this method emulates what we had before support for multiple
-        // registered listeners.
-        if (mListener != null) {
-            removeDrawerListener(mListener);
-        }
-        if (listener != null) {
-            addDrawerListener(listener);
-        }
-        // Update the deprecated field so that we can remove the passed listener the next
-        // time we're called
-        mListener = listener;
-    }
-
-    /**
-     * Adds the specified listener to the list of listeners that will be notified of drawer events.
-     *
-     * @param listener Listener to notify when drawer events occur.
-     * @see #removeDrawerListener(DrawerListener)
-     */
-    public void addDrawerListener(@NonNull DrawerListener listener) {
-        if (listener == null) {
-            return;
-        }
-        if (mListeners == null) {
-            mListeners = new ArrayList<DrawerListener>();
-        }
-        mListeners.add(listener);
-    }
-
-    /**
-     * Removes the specified listener from the list of listeners that will be notified of drawer
-     * events.
-     *
-     * @param listener Listener to remove from being notified of drawer events
-     * @see #addDrawerListener(DrawerListener)
-     */
-    public void removeDrawerListener(@NonNull DrawerListener listener) {
-        if (listener == null) {
-            return;
-        }
-        if (mListeners == null) {
-            // This can happen if this method is called before the first call to addDrawerListener
-            return;
-        }
-        mListeners.remove(listener);
-    }
-
-    /**
-     * Enable or disable interaction with all drawers.
-     *
-     * <p>This allows the application to restrict the user's ability to open or close
-     * any drawer within this layout. DrawerLayout will still respond to calls to
-     * {@link #openDrawer(int)}, {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
-     *
-     * <p>Locking drawers open or closed will implicitly open or close
-     * any drawers as appropriate.</p>
-     *
-     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
-     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
-     */
-    public void setDrawerLockMode(@LockMode int lockMode) {
-        setDrawerLockMode(lockMode, Gravity.LEFT);
-        setDrawerLockMode(lockMode, Gravity.RIGHT);
-    }
-
-    /**
-     * Enable or disable interaction with the given drawer.
-     *
-     * <p>This allows the application to restrict the user's ability to open or close
-     * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
-     * {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
-     *
-     * <p>Locking a drawer open or closed will implicitly open or close
-     * that drawer as appropriate.</p>
-     *
-     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
-     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
-     * @param edgeGravity Gravity.LEFT, RIGHT, START or END.
-     *                    Expresses which drawer to change the mode for.
-     *
-     * @see #LOCK_MODE_UNLOCKED
-     * @see #LOCK_MODE_LOCKED_CLOSED
-     * @see #LOCK_MODE_LOCKED_OPEN
-     */
-    public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) {
-        final int absGravity = GravityCompat.getAbsoluteGravity(edgeGravity,
-                ViewCompat.getLayoutDirection(this));
-
-        switch (edgeGravity) {
-            case Gravity.LEFT:
-                mLockModeLeft = lockMode;
-                break;
-            case Gravity.RIGHT:
-                mLockModeRight = lockMode;
-                break;
-            case GravityCompat.START:
-                mLockModeStart = lockMode;
-                break;
-            case GravityCompat.END:
-                mLockModeEnd = lockMode;
-                break;
-        }
-
-        if (lockMode != LOCK_MODE_UNLOCKED) {
-            // Cancel interaction in progress
-            final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger;
-            helper.cancel();
-        }
-        switch (lockMode) {
-            case LOCK_MODE_LOCKED_OPEN:
-                final View toOpen = findDrawerWithGravity(absGravity);
-                if (toOpen != null) {
-                    openDrawer(toOpen);
-                }
-                break;
-            case LOCK_MODE_LOCKED_CLOSED:
-                final View toClose = findDrawerWithGravity(absGravity);
-                if (toClose != null) {
-                    closeDrawer(toClose);
-                }
-                break;
-            // default: do nothing
-        }
-    }
-
-    /**
-     * Enable or disable interaction with the given drawer.
-     *
-     * <p>This allows the application to restrict the user's ability to open or close
-     * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
-     * {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
-     *
-     * <p>Locking a drawer open or closed will implicitly open or close
-     * that drawer as appropriate.</p>
-     *
-     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
-     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
-     * @param drawerView The drawer view to change the lock mode for
-     *
-     * @see #LOCK_MODE_UNLOCKED
-     * @see #LOCK_MODE_LOCKED_CLOSED
-     * @see #LOCK_MODE_LOCKED_OPEN
-     */
-    public void setDrawerLockMode(@LockMode int lockMode, @NonNull View drawerView) {
-        if (!isDrawerView(drawerView)) {
-            throw new IllegalArgumentException("View " + drawerView + " is not a "
-                    + "drawer with appropriate layout_gravity");
-        }
-        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
-        setDrawerLockMode(lockMode, gravity);
-    }
-
-    /**
-     * Check the lock mode of the drawer with the given gravity.
-     *
-     * @param edgeGravity Gravity of the drawer to check
-     * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
-     *         {@link #LOCK_MODE_LOCKED_OPEN}.
-     */
-    @LockMode
-    public int getDrawerLockMode(@EdgeGravity int edgeGravity) {
-        int layoutDirection = ViewCompat.getLayoutDirection(this);
-
-        switch (edgeGravity) {
-            case Gravity.LEFT:
-                if (mLockModeLeft != LOCK_MODE_UNDEFINED) {
-                    return mLockModeLeft;
-                }
-                int leftLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
-                        ? mLockModeStart : mLockModeEnd;
-                if (leftLockMode != LOCK_MODE_UNDEFINED) {
-                    return leftLockMode;
-                }
-                break;
-            case Gravity.RIGHT:
-                if (mLockModeRight != LOCK_MODE_UNDEFINED) {
-                    return mLockModeRight;
-                }
-                int rightLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
-                        ? mLockModeEnd : mLockModeStart;
-                if (rightLockMode != LOCK_MODE_UNDEFINED) {
-                    return rightLockMode;
-                }
-                break;
-            case GravityCompat.START:
-                if (mLockModeStart != LOCK_MODE_UNDEFINED) {
-                    return mLockModeStart;
-                }
-                int startLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
-                        ? mLockModeLeft : mLockModeRight;
-                if (startLockMode != LOCK_MODE_UNDEFINED) {
-                    return startLockMode;
-                }
-                break;
-            case GravityCompat.END:
-                if (mLockModeEnd != LOCK_MODE_UNDEFINED) {
-                    return mLockModeEnd;
-                }
-                int endLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
-                        ? mLockModeRight : mLockModeLeft;
-                if (endLockMode != LOCK_MODE_UNDEFINED) {
-                    return endLockMode;
-                }
-                break;
-        }
-
-        return LOCK_MODE_UNLOCKED;
-    }
-
-    /**
-     * Check the lock mode of the given drawer view.
-     *
-     * @param drawerView Drawer view to check lock mode
-     * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
-     *         {@link #LOCK_MODE_LOCKED_OPEN}.
-     */
-    @LockMode
-    public int getDrawerLockMode(@NonNull View drawerView) {
-        if (!isDrawerView(drawerView)) {
-            throw new IllegalArgumentException("View " + drawerView + " is not a drawer");
-        }
-        final int drawerGravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
-        return getDrawerLockMode(drawerGravity);
-    }
-
-    /**
-     * Sets the title of the drawer with the given gravity.
-     * <p>
-     * When accessibility is turned on, this is the title that will be used to
-     * identify the drawer to the active accessibility service.
-     *
-     * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which
-     *            drawer to set the title for.
-     * @param title The title for the drawer.
-     */
-    public void setDrawerTitle(@EdgeGravity int edgeGravity, @Nullable CharSequence title) {
-        final int absGravity = GravityCompat.getAbsoluteGravity(
-                edgeGravity, ViewCompat.getLayoutDirection(this));
-        if (absGravity == Gravity.LEFT) {
-            mTitleLeft = title;
-        } else if (absGravity == Gravity.RIGHT) {
-            mTitleRight = title;
-        }
-    }
-
-    /**
-     * Returns the title of the drawer with the given gravity.
-     *
-     * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which
-     *            drawer to return the title for.
-     * @return The title of the drawer, or null if none set.
-     * @see #setDrawerTitle(int, CharSequence)
-     */
-    @Nullable
-    public CharSequence getDrawerTitle(@EdgeGravity int edgeGravity) {
-        final int absGravity = GravityCompat.getAbsoluteGravity(
-                edgeGravity, ViewCompat.getLayoutDirection(this));
-        if (absGravity == Gravity.LEFT) {
-            return mTitleLeft;
-        } else if (absGravity == Gravity.RIGHT) {
-            return mTitleRight;
-        }
-        return null;
-    }
-
-    /**
-     * Resolve the shared state of all drawers from the component ViewDragHelpers.
-     * Should be called whenever a ViewDragHelper's state changes.
-     */
-    void updateDrawerState(int forGravity, @State int activeState, View activeDrawer) {
-        final int leftState = mLeftDragger.getViewDragState();
-        final int rightState = mRightDragger.getViewDragState();
-
-        final int state;
-        if (leftState == STATE_DRAGGING || rightState == STATE_DRAGGING) {
-            state = STATE_DRAGGING;
-        } else if (leftState == STATE_SETTLING || rightState == STATE_SETTLING) {
-            state = STATE_SETTLING;
-        } else {
-            state = STATE_IDLE;
-        }
-
-        if (activeDrawer != null && activeState == STATE_IDLE) {
-            final LayoutParams lp = (LayoutParams) activeDrawer.getLayoutParams();
-            if (lp.onScreen == 0) {
-                dispatchOnDrawerClosed(activeDrawer);
-            } else if (lp.onScreen == 1) {
-                dispatchOnDrawerOpened(activeDrawer);
-            }
-        }
-
-        if (state != mDrawerState) {
-            mDrawerState = state;
-
-            if (mListeners != null) {
-                // Notify the listeners. Do that from the end of the list so that if a listener
-                // removes itself as the result of being called, it won't mess up with our iteration
-                int listenerCount = mListeners.size();
-                for (int i = listenerCount - 1; i >= 0; i--) {
-                    mListeners.get(i).onDrawerStateChanged(state);
-                }
-            }
-        }
-    }
-
-    void dispatchOnDrawerClosed(View drawerView) {
-        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
-        if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
-            lp.openState = 0;
-
-            if (mListeners != null) {
-                // Notify the listeners. Do that from the end of the list so that if a listener
-                // removes itself as the result of being called, it won't mess up with our iteration
-                int listenerCount = mListeners.size();
-                for (int i = listenerCount - 1; i >= 0; i--) {
-                    mListeners.get(i).onDrawerClosed(drawerView);
-                }
-            }
-
-            updateChildrenImportantForAccessibility(drawerView, false);
-
-            // Only send WINDOW_STATE_CHANGE if the host has window focus. This
-            // may change if support for multiple foreground windows (e.g. IME)
-            // improves.
-            if (hasWindowFocus()) {
-                final View rootView = getRootView();
-                if (rootView != null) {
-                    rootView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-                }
-            }
-        }
-    }
-
-    void dispatchOnDrawerOpened(View drawerView) {
-        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
-        if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 0) {
-            lp.openState = LayoutParams.FLAG_IS_OPENED;
-            if (mListeners != null) {
-                // Notify the listeners. Do that from the end of the list so that if a listener
-                // removes itself as the result of being called, it won't mess up with our iteration
-                int listenerCount = mListeners.size();
-                for (int i = listenerCount - 1; i >= 0; i--) {
-                    mListeners.get(i).onDrawerOpened(drawerView);
-                }
-            }
-
-            updateChildrenImportantForAccessibility(drawerView, true);
-
-            // Only send WINDOW_STATE_CHANGE if the host has window focus.
-            if (hasWindowFocus()) {
-                sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-            }
-        }
-    }
-
-    private void updateChildrenImportantForAccessibility(View drawerView, boolean isDrawerOpen) {
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            if ((!isDrawerOpen && !isDrawerView(child)) || (isDrawerOpen && child == drawerView)) {
-                // Drawer is closed and this is a content view or this is an
-                // open drawer view, so it should be visible.
-                ViewCompat.setImportantForAccessibility(child,
-                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-            } else {
-                ViewCompat.setImportantForAccessibility(child,
-                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
-            }
-        }
-    }
-
-    void dispatchOnDrawerSlide(View drawerView, float slideOffset) {
-        if (mListeners != null) {
-            // Notify the listeners. Do that from the end of the list so that if a listener
-            // removes itself as the result of being called, it won't mess up with our iteration
-            int listenerCount = mListeners.size();
-            for (int i = listenerCount - 1; i >= 0; i--) {
-                mListeners.get(i).onDrawerSlide(drawerView, slideOffset);
-            }
-        }
-    }
-
-    void setDrawerViewOffset(View drawerView, float slideOffset) {
-        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
-        if (slideOffset == lp.onScreen) {
-            return;
-        }
-
-        lp.onScreen = slideOffset;
-        dispatchOnDrawerSlide(drawerView, slideOffset);
-    }
-
-    float getDrawerViewOffset(View drawerView) {
-        return ((LayoutParams) drawerView.getLayoutParams()).onScreen;
-    }
-
-    /**
-     * @return the absolute gravity of the child drawerView, resolved according
-     *         to the current layout direction
-     */
-    int getDrawerViewAbsoluteGravity(View drawerView) {
-        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
-        return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(this));
-    }
-
-    boolean checkDrawerViewAbsoluteGravity(View drawerView, int checkFor) {
-        final int absGravity = getDrawerViewAbsoluteGravity(drawerView);
-        return (absGravity & checkFor) == checkFor;
-    }
-
-    View findOpenDrawer() {
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
-            if ((childLp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
-                return child;
-            }
-        }
-        return null;
-    }
-
-    void moveDrawerToOffset(View drawerView, float slideOffset) {
-        final float oldOffset = getDrawerViewOffset(drawerView);
-        final int width = drawerView.getWidth();
-        final int oldPos = (int) (width * oldOffset);
-        final int newPos = (int) (width * slideOffset);
-        final int dx = newPos - oldPos;
-
-        drawerView.offsetLeftAndRight(
-                checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT) ? dx : -dx);
-        setDrawerViewOffset(drawerView, slideOffset);
-    }
-
-    /**
-     * @param gravity the gravity of the child to return. If specified as a
-     *            relative value, it will be resolved according to the current
-     *            layout direction.
-     * @return the drawer with the specified gravity
-     */
-    View findDrawerWithGravity(int gravity) {
-        final int absHorizGravity = GravityCompat.getAbsoluteGravity(
-                gravity, ViewCompat.getLayoutDirection(this)) & Gravity.HORIZONTAL_GRAVITY_MASK;
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final int childAbsGravity = getDrawerViewAbsoluteGravity(child);
-            if ((childAbsGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == absHorizGravity) {
-                return child;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Simple gravity to string - only supports LEFT and RIGHT for debugging output.
-     *
-     * @param gravity Absolute gravity value
-     * @return LEFT or RIGHT as appropriate, or a hex string
-     */
-    static String gravityToString(@EdgeGravity int gravity) {
-        if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
-            return "LEFT";
-        }
-        if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
-            return "RIGHT";
-        }
-        return Integer.toHexString(gravity);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mFirstLayout = true;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mFirstLayout = true;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
-        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
-        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
-        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
-
-        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
-            if (isInEditMode()) {
-                // Don't crash the layout editor. Consume all of the space if specified
-                // or pick a magic number from thin air otherwise.
-                // TODO Better communication with tools of this bogus state.
-                // It will crash on a real device.
-                if (widthMode == MeasureSpec.AT_MOST) {
-                    widthMode = MeasureSpec.EXACTLY;
-                } else if (widthMode == MeasureSpec.UNSPECIFIED) {
-                    widthMode = MeasureSpec.EXACTLY;
-                    widthSize = 300;
-                }
-                if (heightMode == MeasureSpec.AT_MOST) {
-                    heightMode = MeasureSpec.EXACTLY;
-                } else if (heightMode == MeasureSpec.UNSPECIFIED) {
-                    heightMode = MeasureSpec.EXACTLY;
-                    heightSize = 300;
-                }
-            } else {
-                throw new IllegalArgumentException(
-                        "DrawerLayout must be measured with MeasureSpec.EXACTLY.");
-            }
-        }
-
-        setMeasuredDimension(widthSize, heightSize);
-
-        final boolean applyInsets = mLastInsets != null && ViewCompat.getFitsSystemWindows(this);
-        final int layoutDirection = ViewCompat.getLayoutDirection(this);
-
-        // Only one drawer is permitted along each vertical edge (left / right). These two booleans
-        // are tracking the presence of the edge drawers.
-        boolean hasDrawerOnLeftEdge = false;
-        boolean hasDrawerOnRightEdge = false;
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (applyInsets) {
-                final int cgrav = GravityCompat.getAbsoluteGravity(lp.gravity, layoutDirection);
-                if (ViewCompat.getFitsSystemWindows(child)) {
-                    if (Build.VERSION.SDK_INT >= 21) {
-                        WindowInsets wi = (WindowInsets) mLastInsets;
-                        if (cgrav == Gravity.LEFT) {
-                            wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(),
-                                    wi.getSystemWindowInsetTop(), 0,
-                                    wi.getSystemWindowInsetBottom());
-                        } else if (cgrav == Gravity.RIGHT) {
-                            wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(),
-                                    wi.getSystemWindowInsetRight(),
-                                    wi.getSystemWindowInsetBottom());
-                        }
-                        child.dispatchApplyWindowInsets(wi);
-                    }
-                } else {
-                    if (Build.VERSION.SDK_INT >= 21) {
-                        WindowInsets wi = (WindowInsets) mLastInsets;
-                        if (cgrav == Gravity.LEFT) {
-                            wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(),
-                                    wi.getSystemWindowInsetTop(), 0,
-                                    wi.getSystemWindowInsetBottom());
-                        } else if (cgrav == Gravity.RIGHT) {
-                            wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(),
-                                    wi.getSystemWindowInsetRight(),
-                                    wi.getSystemWindowInsetBottom());
-                        }
-                        lp.leftMargin = wi.getSystemWindowInsetLeft();
-                        lp.topMargin = wi.getSystemWindowInsetTop();
-                        lp.rightMargin = wi.getSystemWindowInsetRight();
-                        lp.bottomMargin = wi.getSystemWindowInsetBottom();
-                    }
-                }
-            }
-
-            if (isContentView(child)) {
-                // Content views get measured at exactly the layout's size.
-                final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
-                        widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
-                final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
-                        heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
-                child.measure(contentWidthSpec, contentHeightSpec);
-            } else if (isDrawerView(child)) {
-                if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
-                    if (ViewCompat.getElevation(child) != mDrawerElevation) {
-                        ViewCompat.setElevation(child, mDrawerElevation);
-                    }
-                }
-                final @EdgeGravity int childGravity =
-                        getDrawerViewAbsoluteGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
-                // Note that the isDrawerView check guarantees that childGravity here is either
-                // LEFT or RIGHT
-                boolean isLeftEdgeDrawer = (childGravity == Gravity.LEFT);
-                if ((isLeftEdgeDrawer && hasDrawerOnLeftEdge)
-                        || (!isLeftEdgeDrawer && hasDrawerOnRightEdge)) {
-                    throw new IllegalStateException("Child drawer has absolute gravity "
-                            + gravityToString(childGravity) + " but this " + TAG + " already has a "
-                            + "drawer view along that edge");
-                }
-                if (isLeftEdgeDrawer) {
-                    hasDrawerOnLeftEdge = true;
-                } else {
-                    hasDrawerOnRightEdge = true;
-                }
-                final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
-                        mMinDrawerMargin + lp.leftMargin + lp.rightMargin,
-                        lp.width);
-                final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
-                        lp.topMargin + lp.bottomMargin,
-                        lp.height);
-                child.measure(drawerWidthSpec, drawerHeightSpec);
-            } else {
-                throw new IllegalStateException("Child " + child + " at index " + i
-                        + " does not have a valid layout_gravity - must be Gravity.LEFT, "
-                        + "Gravity.RIGHT or Gravity.NO_GRAVITY");
-            }
-        }
-    }
-
-    private void resolveShadowDrawables() {
-        if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
-            return;
-        }
-        mShadowLeftResolved = resolveLeftShadow();
-        mShadowRightResolved = resolveRightShadow();
-    }
-
-    private Drawable resolveLeftShadow() {
-        int layoutDirection = ViewCompat.getLayoutDirection(this);
-        // Prefer shadows defined with start/end gravity over left and right.
-        if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
-            if (mShadowStart != null) {
-                // Correct drawable layout direction, if needed.
-                mirror(mShadowStart, layoutDirection);
-                return mShadowStart;
-            }
-        } else {
-            if (mShadowEnd != null) {
-                // Correct drawable layout direction, if needed.
-                mirror(mShadowEnd, layoutDirection);
-                return mShadowEnd;
-            }
-        }
-        return mShadowLeft;
-    }
-
-    private Drawable resolveRightShadow() {
-        int layoutDirection = ViewCompat.getLayoutDirection(this);
-        if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
-            if (mShadowEnd != null) {
-                // Correct drawable layout direction, if needed.
-                mirror(mShadowEnd, layoutDirection);
-                return mShadowEnd;
-            }
-        } else {
-            if (mShadowStart != null) {
-                // Correct drawable layout direction, if needed.
-                mirror(mShadowStart, layoutDirection);
-                return mShadowStart;
-            }
-        }
-        return mShadowRight;
-    }
-
-    /**
-     * Change the layout direction of the given drawable.
-     * Return true if auto-mirror is supported and drawable's layout direction can be changed.
-     * Otherwise, return false.
-     */
-    private boolean mirror(Drawable drawable, int layoutDirection) {
-        if (drawable == null || !DrawableCompat.isAutoMirrored(drawable)) {
-            return false;
-        }
-
-        DrawableCompat.setLayoutDirection(drawable, layoutDirection);
-        return true;
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        mInLayout = true;
-        final int width = r - l;
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (isContentView(child)) {
-                child.layout(lp.leftMargin, lp.topMargin,
-                        lp.leftMargin + child.getMeasuredWidth(),
-                        lp.topMargin + child.getMeasuredHeight());
-            } else { // Drawer, if it wasn't onMeasure would have thrown an exception.
-                final int childWidth = child.getMeasuredWidth();
-                final int childHeight = child.getMeasuredHeight();
-                int childLeft;
-
-                final float newOffset;
-                if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
-                    childLeft = -childWidth + (int) (childWidth * lp.onScreen);
-                    newOffset = (float) (childWidth + childLeft) / childWidth;
-                } else { // Right; onMeasure checked for us.
-                    childLeft = width - (int) (childWidth * lp.onScreen);
-                    newOffset = (float) (width - childLeft) / childWidth;
-                }
-
-                final boolean changeOffset = newOffset != lp.onScreen;
-
-                final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
-
-                switch (vgrav) {
-                    default:
-                    case Gravity.TOP: {
-                        child.layout(childLeft, lp.topMargin, childLeft + childWidth,
-                                lp.topMargin + childHeight);
-                        break;
-                    }
-
-                    case Gravity.BOTTOM: {
-                        final int height = b - t;
-                        child.layout(childLeft,
-                                height - lp.bottomMargin - child.getMeasuredHeight(),
-                                childLeft + childWidth,
-                                height - lp.bottomMargin);
-                        break;
-                    }
-
-                    case Gravity.CENTER_VERTICAL: {
-                        final int height = b - t;
-                        int childTop = (height - childHeight) / 2;
-
-                        // Offset for margins. If things don't fit right because of
-                        // bad measurement before, oh well.
-                        if (childTop < lp.topMargin) {
-                            childTop = lp.topMargin;
-                        } else if (childTop + childHeight > height - lp.bottomMargin) {
-                            childTop = height - lp.bottomMargin - childHeight;
-                        }
-                        child.layout(childLeft, childTop, childLeft + childWidth,
-                                childTop + childHeight);
-                        break;
-                    }
-                }
-
-                if (changeOffset) {
-                    setDrawerViewOffset(child, newOffset);
-                }
-
-                final int newVisibility = lp.onScreen > 0 ? VISIBLE : INVISIBLE;
-                if (child.getVisibility() != newVisibility) {
-                    child.setVisibility(newVisibility);
-                }
-            }
-        }
-        mInLayout = false;
-        mFirstLayout = false;
-    }
-
-    @Override
-    public void requestLayout() {
-        if (!mInLayout) {
-            super.requestLayout();
-        }
-    }
-
-    @Override
-    public void computeScroll() {
-        final int childCount = getChildCount();
-        float scrimOpacity = 0;
-        for (int i = 0; i < childCount; i++) {
-            final float onscreen = ((LayoutParams) getChildAt(i).getLayoutParams()).onScreen;
-            scrimOpacity = Math.max(scrimOpacity, onscreen);
-        }
-        mScrimOpacity = scrimOpacity;
-
-        boolean leftDraggerSettling = mLeftDragger.continueSettling(true);
-        boolean rightDraggerSettling = mRightDragger.continueSettling(true);
-        if (leftDraggerSettling || rightDraggerSettling) {
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    private static boolean hasOpaqueBackground(View v) {
-        final Drawable bg = v.getBackground();
-        if (bg != null) {
-            return bg.getOpacity() == PixelFormat.OPAQUE;
-        }
-        return false;
-    }
-
-    /**
-     * Set a drawable to draw in the insets area for the status bar.
-     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
-     *
-     * @param bg Background drawable to draw behind the status bar
-     */
-    public void setStatusBarBackground(@Nullable Drawable bg) {
-        mStatusBarBackground = bg;
-        invalidate();
-    }
-
-    /**
-     * Gets the drawable used to draw in the insets area for the status bar.
-     *
-     * @return The status bar background drawable, or null if none set
-     */
-    @Nullable
-    public Drawable getStatusBarBackgroundDrawable() {
-        return mStatusBarBackground;
-    }
-
-    /**
-     * Set a drawable to draw in the insets area for the status bar.
-     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
-     *
-     * @param resId Resource id of a background drawable to draw behind the status bar
-     */
-    public void setStatusBarBackground(int resId) {
-        mStatusBarBackground = resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null;
-        invalidate();
-    }
-
-    /**
-     * Set a drawable to draw in the insets area for the status bar.
-     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
-     *
-     * @param color Color to use as a background drawable to draw behind the status bar
-     *              in 0xAARRGGBB format.
-     */
-    public void setStatusBarBackgroundColor(@ColorInt int color) {
-        mStatusBarBackground = new ColorDrawable(color);
-        invalidate();
-    }
-
-    @Override
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        resolveShadowDrawables();
-    }
-
-    @Override
-    public void onDraw(Canvas c) {
-        super.onDraw(c);
-        if (mDrawStatusBarBackground && mStatusBarBackground != null) {
-            final int inset;
-            if (Build.VERSION.SDK_INT >= 21) {
-                inset = mLastInsets != null
-                        ? ((WindowInsets) mLastInsets).getSystemWindowInsetTop() : 0;
-            } else {
-                inset = 0;
-            }
-            if (inset > 0) {
-                mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
-                mStatusBarBackground.draw(c);
-            }
-        }
-    }
-
-    @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        final int height = getHeight();
-        final boolean drawingContent = isContentView(child);
-        int clipLeft = 0, clipRight = getWidth();
-
-        final int restoreCount = canvas.save();
-        if (drawingContent) {
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View v = getChildAt(i);
-                if (v == child || v.getVisibility() != VISIBLE
-                        || !hasOpaqueBackground(v) || !isDrawerView(v)
-                        || v.getHeight() < height) {
-                    continue;
-                }
-
-                if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) {
-                    final int vright = v.getRight();
-                    if (vright > clipLeft) clipLeft = vright;
-                } else {
-                    final int vleft = v.getLeft();
-                    if (vleft < clipRight) clipRight = vleft;
-                }
-            }
-            canvas.clipRect(clipLeft, 0, clipRight, getHeight());
-        }
-        final boolean result = super.drawChild(canvas, child, drawingTime);
-        canvas.restoreToCount(restoreCount);
-
-        if (mScrimOpacity > 0 && drawingContent) {
-            final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;
-            final int imag = (int) (baseAlpha * mScrimOpacity);
-            final int color = imag << 24 | (mScrimColor & 0xffffff);
-            mScrimPaint.setColor(color);
-
-            canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint);
-        } else if (mShadowLeftResolved != null
-                &&  checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
-            final int shadowWidth = mShadowLeftResolved.getIntrinsicWidth();
-            final int childRight = child.getRight();
-            final int drawerPeekDistance = mLeftDragger.getEdgeSize();
-            final float alpha =
-                    Math.max(0, Math.min((float) childRight / drawerPeekDistance, 1.f));
-            mShadowLeftResolved.setBounds(childRight, child.getTop(),
-                    childRight + shadowWidth, child.getBottom());
-            mShadowLeftResolved.setAlpha((int) (0xff * alpha));
-            mShadowLeftResolved.draw(canvas);
-        } else if (mShadowRightResolved != null
-                &&  checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) {
-            final int shadowWidth = mShadowRightResolved.getIntrinsicWidth();
-            final int childLeft = child.getLeft();
-            final int showing = getWidth() - childLeft;
-            final int drawerPeekDistance = mRightDragger.getEdgeSize();
-            final float alpha =
-                    Math.max(0, Math.min((float) showing / drawerPeekDistance, 1.f));
-            mShadowRightResolved.setBounds(childLeft - shadowWidth, child.getTop(),
-                    childLeft, child.getBottom());
-            mShadowRightResolved.setAlpha((int) (0xff * alpha));
-            mShadowRightResolved.draw(canvas);
-        }
-        return result;
-    }
-
-    boolean isContentView(View child) {
-        return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
-    }
-
-    boolean isDrawerView(View child) {
-        final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
-        final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
-                ViewCompat.getLayoutDirection(child));
-        if ((absGravity & Gravity.LEFT) != 0) {
-            // This child is a left-edge drawer
-            return true;
-        }
-        if ((absGravity & Gravity.RIGHT) != 0) {
-            // This child is a right-edge drawer
-            return true;
-        }
-        return false;
-    }
-
-    @SuppressWarnings("ShortCircuitBoolean")
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        final int action = ev.getActionMasked();
-
-        // "|" used deliberately here; both methods should be invoked.
-        final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev)
-                | mRightDragger.shouldInterceptTouchEvent(ev);
-
-        boolean interceptForTap = false;
-
-        switch (action) {
-            case MotionEvent.ACTION_DOWN: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                mInitialMotionX = x;
-                mInitialMotionY = y;
-                if (mScrimOpacity > 0) {
-                    final View child = mLeftDragger.findTopChildUnder((int) x, (int) y);
-                    if (child != null && isContentView(child)) {
-                        interceptForTap = true;
-                    }
-                }
-                mDisallowInterceptRequested = false;
-                mChildrenCanceledTouch = false;
-                break;
-            }
-
-            case MotionEvent.ACTION_MOVE: {
-                // If we cross the touch slop, don't perform the delayed peek for an edge touch.
-                if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
-                    mLeftCallback.removeCallbacks();
-                    mRightCallback.removeCallbacks();
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP: {
-                closeDrawers(true);
-                mDisallowInterceptRequested = false;
-                mChildrenCanceledTouch = false;
-            }
-        }
-
-        return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        mLeftDragger.processTouchEvent(ev);
-        mRightDragger.processTouchEvent(ev);
-
-        final int action = ev.getAction();
-        boolean wantTouchEvents = true;
-
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                mInitialMotionX = x;
-                mInitialMotionY = y;
-                mDisallowInterceptRequested = false;
-                mChildrenCanceledTouch = false;
-                break;
-            }
-
-            case MotionEvent.ACTION_UP: {
-                final float x = ev.getX();
-                final float y = ev.getY();
-                boolean peekingOnly = true;
-                final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y);
-                if (touchedView != null && isContentView(touchedView)) {
-                    final float dx = x - mInitialMotionX;
-                    final float dy = y - mInitialMotionY;
-                    final int slop = mLeftDragger.getTouchSlop();
-                    if (dx * dx + dy * dy < slop * slop) {
-                        // Taps close a dimmed open drawer but only if it isn't locked open.
-                        final View openDrawer = findOpenDrawer();
-                        if (openDrawer != null) {
-                            peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN;
-                        }
-                    }
-                }
-                closeDrawers(peekingOnly);
-                mDisallowInterceptRequested = false;
-                break;
-            }
-
-            case MotionEvent.ACTION_CANCEL: {
-                closeDrawers(true);
-                mDisallowInterceptRequested = false;
-                mChildrenCanceledTouch = false;
-                break;
-            }
-        }
-
-        return wantTouchEvents;
-    }
-
-    @Override
-    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
-        if (CHILDREN_DISALLOW_INTERCEPT
-                || (!mLeftDragger.isEdgeTouched(ViewDragHelper.EDGE_LEFT)
-                        && !mRightDragger.isEdgeTouched(ViewDragHelper.EDGE_RIGHT))) {
-            // If we have an edge touch we want to skip this and track it for later instead.
-            super.requestDisallowInterceptTouchEvent(disallowIntercept);
-        }
-        mDisallowInterceptRequested = disallowIntercept;
-        if (disallowIntercept) {
-            closeDrawers(true);
-        }
-    }
-
-    /**
-     * Close all currently open drawer views by animating them out of view.
-     */
-    public void closeDrawers() {
-        closeDrawers(false);
-    }
-
-    void closeDrawers(boolean peekingOnly) {
-        boolean needsInvalidate = false;
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
-            if (!isDrawerView(child) || (peekingOnly && !lp.isPeeking)) {
-                continue;
-            }
-
-            final int childWidth = child.getWidth();
-
-            if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
-                needsInvalidate |= mLeftDragger.smoothSlideViewTo(child,
-                        -childWidth, child.getTop());
-            } else {
-                needsInvalidate |= mRightDragger.smoothSlideViewTo(child,
-                        getWidth(), child.getTop());
-            }
-
-            lp.isPeeking = false;
-        }
-
-        mLeftCallback.removeCallbacks();
-        mRightCallback.removeCallbacks();
-
-        if (needsInvalidate) {
-            invalidate();
-        }
-    }
-
-    /**
-     * Open the specified drawer view by animating it into view.
-     *
-     * @param drawerView Drawer view to open
-     */
-    public void openDrawer(@NonNull View drawerView) {
-        openDrawer(drawerView, true);
-    }
-
-    /**
-     * Open the specified drawer view.
-     *
-     * @param drawerView Drawer view to open
-     * @param animate Whether opening of the drawer should be animated.
-     */
-    public void openDrawer(@NonNull View drawerView, boolean animate) {
-        if (!isDrawerView(drawerView)) {
-            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
-        }
-
-        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
-        if (mFirstLayout) {
-            lp.onScreen = 1.f;
-            lp.openState = LayoutParams.FLAG_IS_OPENED;
-
-            updateChildrenImportantForAccessibility(drawerView, true);
-        } else if (animate) {
-            lp.openState |= LayoutParams.FLAG_IS_OPENING;
-
-            if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
-                mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
-            } else {
-                mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(),
-                        drawerView.getTop());
-            }
-        } else {
-            moveDrawerToOffset(drawerView, 1.f);
-            updateDrawerState(lp.gravity, STATE_IDLE, drawerView);
-            drawerView.setVisibility(VISIBLE);
-        }
-        invalidate();
-    }
-
-    /**
-     * Open the specified drawer by animating it out of view.
-     *
-     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
-     *                GravityCompat.START or GravityCompat.END may also be used.
-     */
-    public void openDrawer(@EdgeGravity int gravity) {
-        openDrawer(gravity, true);
-    }
-
-    /**
-     * Open the specified drawer.
-     *
-     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
-     *                GravityCompat.START or GravityCompat.END may also be used.
-     * @param animate Whether opening of the drawer should be animated.
-     */
-    public void openDrawer(@EdgeGravity int gravity, boolean animate) {
-        final View drawerView = findDrawerWithGravity(gravity);
-        if (drawerView == null) {
-            throw new IllegalArgumentException("No drawer view found with gravity "
-                    + gravityToString(gravity));
-        }
-        openDrawer(drawerView, animate);
-    }
-
-    /**
-     * Close the specified drawer view by animating it into view.
-     *
-     * @param drawerView Drawer view to close
-     */
-    public void closeDrawer(@NonNull View drawerView) {
-        closeDrawer(drawerView, true);
-    }
-
-    /**
-     * Close the specified drawer view.
-     *
-     * @param drawerView Drawer view to close
-     * @param animate Whether closing of the drawer should be animated.
-     */
-    public void closeDrawer(@NonNull View drawerView, boolean animate) {
-        if (!isDrawerView(drawerView)) {
-            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
-        }
-
-        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
-        if (mFirstLayout) {
-            lp.onScreen = 0.f;
-            lp.openState = 0;
-        } else if (animate) {
-            lp.openState |= LayoutParams.FLAG_IS_CLOSING;
-
-            if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
-                mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(),
-                        drawerView.getTop());
-            } else {
-                mRightDragger.smoothSlideViewTo(drawerView, getWidth(), drawerView.getTop());
-            }
-        } else {
-            moveDrawerToOffset(drawerView, 0.f);
-            updateDrawerState(lp.gravity, STATE_IDLE, drawerView);
-            drawerView.setVisibility(INVISIBLE);
-        }
-        invalidate();
-    }
-
-    /**
-     * Close the specified drawer by animating it out of view.
-     *
-     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
-     *                GravityCompat.START or GravityCompat.END may also be used.
-     */
-    public void closeDrawer(@EdgeGravity int gravity) {
-        closeDrawer(gravity, true);
-    }
-
-    /**
-     * Close the specified drawer.
-     *
-     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
-     *                GravityCompat.START or GravityCompat.END may also be used.
-     * @param animate Whether closing of the drawer should be animated.
-     */
-    public void closeDrawer(@EdgeGravity int gravity, boolean animate) {
-        final View drawerView = findDrawerWithGravity(gravity);
-        if (drawerView == null) {
-            throw new IllegalArgumentException("No drawer view found with gravity "
-                    + gravityToString(gravity));
-        }
-        closeDrawer(drawerView, animate);
-    }
-
-    /**
-     * Check if the given drawer view is currently in an open state.
-     * To be considered "open" the drawer must have settled into its fully
-     * visible state. To check for partial visibility use
-     * {@link #isDrawerVisible(android.view.View)}.
-     *
-     * @param drawer Drawer view to check
-     * @return true if the given drawer view is in an open state
-     * @see #isDrawerVisible(android.view.View)
-     */
-    public boolean isDrawerOpen(@NonNull View drawer) {
-        if (!isDrawerView(drawer)) {
-            throw new IllegalArgumentException("View " + drawer + " is not a drawer");
-        }
-        LayoutParams drawerLp = (LayoutParams) drawer.getLayoutParams();
-        return (drawerLp.openState & LayoutParams.FLAG_IS_OPENED) == 1;
-    }
-
-    /**
-     * Check if the given drawer view is currently in an open state.
-     * To be considered "open" the drawer must have settled into its fully
-     * visible state. If there is no drawer with the given gravity this method
-     * will return false.
-     *
-     * @param drawerGravity Gravity of the drawer to check
-     * @return true if the given drawer view is in an open state
-     */
-    public boolean isDrawerOpen(@EdgeGravity int drawerGravity) {
-        final View drawerView = findDrawerWithGravity(drawerGravity);
-        if (drawerView != null) {
-            return isDrawerOpen(drawerView);
-        }
-        return false;
-    }
-
-    /**
-     * Check if a given drawer view is currently visible on-screen. The drawer
-     * may be only peeking onto the screen, fully extended, or anywhere inbetween.
-     *
-     * @param drawer Drawer view to check
-     * @return true if the given drawer is visible on-screen
-     * @see #isDrawerOpen(android.view.View)
-     */
-    public boolean isDrawerVisible(@NonNull View drawer) {
-        if (!isDrawerView(drawer)) {
-            throw new IllegalArgumentException("View " + drawer + " is not a drawer");
-        }
-        return ((LayoutParams) drawer.getLayoutParams()).onScreen > 0;
-    }
-
-    /**
-     * Check if a given drawer view is currently visible on-screen. The drawer
-     * may be only peeking onto the screen, fully extended, or anywhere in between.
-     * If there is no drawer with the given gravity this method will return false.
-     *
-     * @param drawerGravity Gravity of the drawer to check
-     * @return true if the given drawer is visible on-screen
-     */
-    public boolean isDrawerVisible(@EdgeGravity int drawerGravity) {
-        final View drawerView = findDrawerWithGravity(drawerGravity);
-        if (drawerView != null) {
-            return isDrawerVisible(drawerView);
-        }
-        return false;
-    }
-
-    private boolean hasPeekingDrawer() {
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
-            if (lp.isPeeking) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams
-                ? new LayoutParams((LayoutParams) p)
-                : p instanceof ViewGroup.MarginLayoutParams
-                ? new LayoutParams((MarginLayoutParams) p)
-                : new LayoutParams(p);
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams && super.checkLayoutParams(p);
-    }
-
-    @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
-        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
-            return;
-        }
-
-        // Only the views in the open drawers are focusables. Add normal child views when
-        // no drawers are opened.
-        final int childCount = getChildCount();
-        boolean isDrawerOpen = false;
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            if (isDrawerView(child)) {
-                if (isDrawerOpen(child)) {
-                    isDrawerOpen = true;
-                    child.addFocusables(views, direction, focusableMode);
-                }
-            } else {
-                mNonDrawerViews.add(child);
-            }
-        }
-
-        if (!isDrawerOpen) {
-            final int nonDrawerViewsCount = mNonDrawerViews.size();
-            for (int i = 0; i < nonDrawerViewsCount; ++i) {
-                final View child = mNonDrawerViews.get(i);
-                if (child.getVisibility() == View.VISIBLE) {
-                    child.addFocusables(views, direction, focusableMode);
-                }
-            }
-        }
-
-        mNonDrawerViews.clear();
-    }
-
-    private boolean hasVisibleDrawer() {
-        return findVisibleDrawer() != null;
-    }
-
-    View findVisibleDrawer() {
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            if (isDrawerView(child) && isDrawerVisible(child)) {
-                return child;
-            }
-        }
-        return null;
-    }
-
-    void cancelChildViewTouch() {
-        // Cancel child touches
-        if (!mChildrenCanceledTouch) {
-            final long now = SystemClock.uptimeMillis();
-            final MotionEvent cancelEvent = MotionEvent.obtain(now, now,
-                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                getChildAt(i).dispatchTouchEvent(cancelEvent);
-            }
-            cancelEvent.recycle();
-            mChildrenCanceledTouch = true;
-        }
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK && hasVisibleDrawer()) {
-            event.startTracking();
-            return true;
-        }
-        return super.onKeyDown(keyCode, event);
-    }
-
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            final View visibleDrawer = findVisibleDrawer();
-            if (visibleDrawer != null && getDrawerLockMode(visibleDrawer) == LOCK_MODE_UNLOCKED) {
-                closeDrawers();
-            }
-            return visibleDrawer != null;
-        }
-        return super.onKeyUp(keyCode, event);
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-
-        final SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-
-        if (ss.openDrawerGravity != Gravity.NO_GRAVITY) {
-            final View toOpen = findDrawerWithGravity(ss.openDrawerGravity);
-            if (toOpen != null) {
-                openDrawer(toOpen);
-            }
-        }
-
-        if (ss.lockModeLeft != LOCK_MODE_UNDEFINED) {
-            setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
-        }
-        if (ss.lockModeRight != LOCK_MODE_UNDEFINED) {
-            setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
-        }
-        if (ss.lockModeStart != LOCK_MODE_UNDEFINED) {
-            setDrawerLockMode(ss.lockModeStart, GravityCompat.START);
-        }
-        if (ss.lockModeEnd != LOCK_MODE_UNDEFINED) {
-            setDrawerLockMode(ss.lockModeEnd, GravityCompat.END);
-        }
-    }
-
-    @Override
-    protected Parcelable onSaveInstanceState() {
-        final Parcelable superState = super.onSaveInstanceState();
-        final SavedState ss = new SavedState(superState);
-
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final View child = getChildAt(i);
-            LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            // Is the current child fully opened (that is, not closing)?
-            boolean isOpenedAndNotClosing = (lp.openState == LayoutParams.FLAG_IS_OPENED);
-            // Is the current child opening?
-            boolean isClosedAndOpening = (lp.openState == LayoutParams.FLAG_IS_OPENING);
-            if (isOpenedAndNotClosing || isClosedAndOpening) {
-                // If one of the conditions above holds, save the child's gravity
-                // so that we open that child during state restore.
-                ss.openDrawerGravity = lp.gravity;
-                break;
-            }
-        }
-
-        ss.lockModeLeft = mLockModeLeft;
-        ss.lockModeRight = mLockModeRight;
-        ss.lockModeStart = mLockModeStart;
-        ss.lockModeEnd = mLockModeEnd;
-
-        return ss;
-    }
-
-    @Override
-    public void addView(View child, int index, ViewGroup.LayoutParams params) {
-        super.addView(child, index, params);
-
-        final View openDrawer = findOpenDrawer();
-        if (openDrawer != null || isDrawerView(child)) {
-            // A drawer is already open or the new view is a drawer, so the
-            // new view should start out hidden.
-            ViewCompat.setImportantForAccessibility(child,
-                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
-        } else {
-            // Otherwise this is a content view and no drawer is open, so the
-            // new view should start out visible.
-            ViewCompat.setImportantForAccessibility(child,
-                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-
-        // We only need a delegate here if the framework doesn't understand
-        // NO_HIDE_DESCENDANTS importance.
-        if (!CAN_HIDE_DESCENDANTS) {
-            ViewCompat.setAccessibilityDelegate(child, mChildAccessibilityDelegate);
-        }
-    }
-
-    static boolean includeChildForAccessibility(View child) {
-        // If the child is not important for accessibility we make
-        // sure this hides the entire subtree rooted at it as the
-        // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDATS is not
-        // supported on older platforms but we want to hide the entire
-        // content and not opened drawers if a drawer is opened.
-        return ViewCompat.getImportantForAccessibility(child)
-                != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
-                    && ViewCompat.getImportantForAccessibility(child)
-                != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO;
-    }
-
-    /**
-     * State persisted across instances
-     */
-    protected static class SavedState extends AbsSavedState {
-        int openDrawerGravity = Gravity.NO_GRAVITY;
-        @LockMode int lockModeLeft;
-        @LockMode int lockModeRight;
-        @LockMode int lockModeStart;
-        @LockMode int lockModeEnd;
-
-        public SavedState(@NonNull Parcel in, @Nullable ClassLoader loader) {
-            super(in, loader);
-            openDrawerGravity = in.readInt();
-            lockModeLeft = in.readInt();
-            lockModeRight = in.readInt();
-            lockModeStart = in.readInt();
-            lockModeEnd = in.readInt();
-        }
-
-        public SavedState(@NonNull Parcelable superState) {
-            super(superState);
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(openDrawerGravity);
-            dest.writeInt(lockModeLeft);
-            dest.writeInt(lockModeRight);
-            dest.writeInt(lockModeStart);
-            dest.writeInt(lockModeEnd);
-        }
-
-        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                return new SavedState(in, loader);
-            }
-
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in, null);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    private class ViewDragCallback extends ViewDragHelper.Callback {
-        private final int mAbsGravity;
-        private ViewDragHelper mDragger;
-
-        private final Runnable mPeekRunnable = new Runnable() {
-            @Override public void run() {
-                peekDrawer();
-            }
-        };
-
-        ViewDragCallback(int gravity) {
-            mAbsGravity = gravity;
-        }
-
-        public void setDragger(ViewDragHelper dragger) {
-            mDragger = dragger;
-        }
-
-        public void removeCallbacks() {
-            DrawerLayout.this.removeCallbacks(mPeekRunnable);
-        }
-
-        @Override
-        public boolean tryCaptureView(View child, int pointerId) {
-            // Only capture views where the gravity matches what we're looking for.
-            // This lets us use two ViewDragHelpers, one for each side drawer.
-            return isDrawerView(child) && checkDrawerViewAbsoluteGravity(child, mAbsGravity)
-                    && getDrawerLockMode(child) == LOCK_MODE_UNLOCKED;
-        }
-
-        @Override
-        public void onViewDragStateChanged(int state) {
-            updateDrawerState(mAbsGravity, state, mDragger.getCapturedView());
-        }
-
-        @Override
-        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
-            float offset;
-            final int childWidth = changedView.getWidth();
-
-            // This reverses the positioning shown in onLayout.
-            if (checkDrawerViewAbsoluteGravity(changedView, Gravity.LEFT)) {
-                offset = (float) (childWidth + left) / childWidth;
-            } else {
-                final int width = getWidth();
-                offset = (float) (width - left) / childWidth;
-            }
-            setDrawerViewOffset(changedView, offset);
-            changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE);
-            invalidate();
-        }
-
-        @Override
-        public void onViewCaptured(View capturedChild, int activePointerId) {
-            final LayoutParams lp = (LayoutParams) capturedChild.getLayoutParams();
-            lp.isPeeking = false;
-
-            closeOtherDrawer();
-        }
-
-        private void closeOtherDrawer() {
-            final int otherGrav = mAbsGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT;
-            final View toClose = findDrawerWithGravity(otherGrav);
-            if (toClose != null) {
-                closeDrawer(toClose);
-            }
-        }
-
-        @Override
-        public void onViewReleased(View releasedChild, float xvel, float yvel) {
-            // Offset is how open the drawer is, therefore left/right values
-            // are reversed from one another.
-            final float offset = getDrawerViewOffset(releasedChild);
-            final int childWidth = releasedChild.getWidth();
-
-            int left;
-            if (checkDrawerViewAbsoluteGravity(releasedChild, Gravity.LEFT)) {
-                left = xvel > 0 || (xvel == 0 && offset > 0.5f) ? 0 : -childWidth;
-            } else {
-                final int width = getWidth();
-                left = xvel < 0 || (xvel == 0 && offset > 0.5f) ? width - childWidth : width;
-            }
-
-            mDragger.settleCapturedViewAt(left, releasedChild.getTop());
-            invalidate();
-        }
-
-        @Override
-        public void onEdgeTouched(int edgeFlags, int pointerId) {
-            postDelayed(mPeekRunnable, PEEK_DELAY);
-        }
-
-        void peekDrawer() {
-            final View toCapture;
-            final int childLeft;
-            final int peekDistance = mDragger.getEdgeSize();
-            final boolean leftEdge = mAbsGravity == Gravity.LEFT;
-            if (leftEdge) {
-                toCapture = findDrawerWithGravity(Gravity.LEFT);
-                childLeft = (toCapture != null ? -toCapture.getWidth() : 0) + peekDistance;
-            } else {
-                toCapture = findDrawerWithGravity(Gravity.RIGHT);
-                childLeft = getWidth() - peekDistance;
-            }
-            // Only peek if it would mean making the drawer more visible and the drawer isn't locked
-            if (toCapture != null && ((leftEdge && toCapture.getLeft() < childLeft)
-                    || (!leftEdge && toCapture.getLeft() > childLeft))
-                    && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
-                final LayoutParams lp = (LayoutParams) toCapture.getLayoutParams();
-                mDragger.smoothSlideViewTo(toCapture, childLeft, toCapture.getTop());
-                lp.isPeeking = true;
-                invalidate();
-
-                closeOtherDrawer();
-
-                cancelChildViewTouch();
-            }
-        }
-
-        @Override
-        public boolean onEdgeLock(int edgeFlags) {
-            if (ALLOW_EDGE_LOCK) {
-                final View drawer = findDrawerWithGravity(mAbsGravity);
-                if (drawer != null && !isDrawerOpen(drawer)) {
-                    closeDrawer(drawer);
-                }
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
-            final View toCapture;
-            if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) {
-                toCapture = findDrawerWithGravity(Gravity.LEFT);
-            } else {
-                toCapture = findDrawerWithGravity(Gravity.RIGHT);
-            }
-
-            if (toCapture != null && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
-                mDragger.captureChildView(toCapture, pointerId);
-            }
-        }
-
-        @Override
-        public int getViewHorizontalDragRange(View child) {
-            return isDrawerView(child) ? child.getWidth() : 0;
-        }
-
-        @Override
-        public int clampViewPositionHorizontal(View child, int left, int dx) {
-            if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
-                return Math.max(-child.getWidth(), Math.min(left, 0));
-            } else {
-                final int width = getWidth();
-                return Math.max(width - child.getWidth(), Math.min(left, width));
-            }
-        }
-
-        @Override
-        public int clampViewPositionVertical(View child, int top, int dy) {
-            return child.getTop();
-        }
-    }
-
-    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
-        private static final int FLAG_IS_OPENED = 0x1;
-        private static final int FLAG_IS_OPENING = 0x2;
-        private static final int FLAG_IS_CLOSING = 0x4;
-
-        public int gravity = Gravity.NO_GRAVITY;
-        float onScreen;
-        boolean isPeeking;
-        int openState;
-
-        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
-            super(c, attrs);
-
-            final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
-            this.gravity = a.getInt(0, Gravity.NO_GRAVITY);
-            a.recycle();
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(int width, int height, int gravity) {
-            this(width, height);
-            this.gravity = gravity;
-        }
-
-        public LayoutParams(@NonNull LayoutParams source) {
-            super(source);
-            this.gravity = source.gravity;
-        }
-
-        public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
-            super(source);
-        }
-    }
-
-    class AccessibilityDelegate extends AccessibilityDelegateCompat {
-        private final Rect mTmpRect = new Rect();
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-            if (CAN_HIDE_DESCENDANTS) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-            } else {
-                // Obtain a node for the host, then manually generate the list
-                // of children to only include non-obscured views.
-                final AccessibilityNodeInfoCompat superNode =
-                        AccessibilityNodeInfoCompat.obtain(info);
-                super.onInitializeAccessibilityNodeInfo(host, superNode);
-
-                info.setSource(host);
-                final ViewParent parent = ViewCompat.getParentForAccessibility(host);
-                if (parent instanceof View) {
-                    info.setParent((View) parent);
-                }
-                copyNodeInfoNoChildren(info, superNode);
-                superNode.recycle();
-
-                addChildrenForAccessibility(info, (ViewGroup) host);
-            }
-
-            info.setClassName(DrawerLayout.class.getName());
-
-            // This view reports itself as focusable so that it can intercept
-            // the back button, but we should prevent this view from reporting
-            // itself as focusable to accessibility services.
-            info.setFocusable(false);
-            info.setFocused(false);
-            info.removeAction(AccessibilityActionCompat.ACTION_FOCUS);
-            info.removeAction(AccessibilityActionCompat.ACTION_CLEAR_FOCUS);
-        }
-
-        @Override
-        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-            super.onInitializeAccessibilityEvent(host, event);
-
-            event.setClassName(DrawerLayout.class.getName());
-        }
-
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-            // Special case to handle window state change events. As far as
-            // accessibility services are concerned, state changes from
-            // DrawerLayout invalidate the entire contents of the screen (like
-            // an Activity or Dialog) and they should announce the title of the
-            // new content.
-            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-                final List<CharSequence> eventText = event.getText();
-                final View visibleDrawer = findVisibleDrawer();
-                if (visibleDrawer != null) {
-                    final int edgeGravity = getDrawerViewAbsoluteGravity(visibleDrawer);
-                    final CharSequence title = getDrawerTitle(edgeGravity);
-                    if (title != null) {
-                        eventText.add(title);
-                    }
-                }
-
-                return true;
-            }
-
-            return super.dispatchPopulateAccessibilityEvent(host, event);
-        }
-
-        @Override
-        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
-                AccessibilityEvent event) {
-            if (CAN_HIDE_DESCENDANTS || includeChildForAccessibility(child)) {
-                return super.onRequestSendAccessibilityEvent(host, child, event);
-            }
-            return false;
-        }
-
-        private void addChildrenForAccessibility(AccessibilityNodeInfoCompat info, ViewGroup v) {
-            final int childCount = v.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                final View child = v.getChildAt(i);
-                if (includeChildForAccessibility(child)) {
-                    info.addChild(child);
-                }
-            }
-        }
-
-        /**
-         * This should really be in AccessibilityNodeInfoCompat, but there unfortunately
-         * seem to be a few elements that are not easily cloneable using the underlying API.
-         * Leave it private here as it's not general-purpose useful.
-         */
-        private void copyNodeInfoNoChildren(AccessibilityNodeInfoCompat dest,
-                AccessibilityNodeInfoCompat src) {
-            final Rect rect = mTmpRect;
-
-            src.getBoundsInParent(rect);
-            dest.setBoundsInParent(rect);
-
-            src.getBoundsInScreen(rect);
-            dest.setBoundsInScreen(rect);
-
-            dest.setVisibleToUser(src.isVisibleToUser());
-            dest.setPackageName(src.getPackageName());
-            dest.setClassName(src.getClassName());
-            dest.setContentDescription(src.getContentDescription());
-
-            dest.setEnabled(src.isEnabled());
-            dest.setClickable(src.isClickable());
-            dest.setFocusable(src.isFocusable());
-            dest.setFocused(src.isFocused());
-            dest.setAccessibilityFocused(src.isAccessibilityFocused());
-            dest.setSelected(src.isSelected());
-            dest.setLongClickable(src.isLongClickable());
-
-            dest.addAction(src.getActions());
-        }
-    }
-
-    static final class ChildAccessibilityDelegate extends AccessibilityDelegateCompat {
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View child,
-                AccessibilityNodeInfoCompat info) {
-            super.onInitializeAccessibilityNodeInfo(child, info);
-
-            if (!includeChildForAccessibility(child)) {
-                // If we are ignoring the sub-tree rooted at the child,
-                // break the connection to the rest of the node tree.
-                // For details refer to includeChildForAccessibility.
-                info.setParent(null);
-            }
-        }
-    }
-}
diff --git a/core-ui/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java b/core-ui/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java
deleted file mode 100644
index 2b5ed0a..0000000
--- a/core-ui/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java
+++ /dev/null
@@ -1,1262 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.util.SparseArrayCompat;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewCompat.FocusDirection;
-import android.support.v4.view.ViewCompat.FocusRealDirection;
-import android.support.v4.view.ViewParentCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
-import android.support.v4.view.accessibility.AccessibilityRecordCompat;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityRecord;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * ExploreByTouchHelper is a utility class for implementing accessibility
- * support in custom {@link View}s that represent a collection of View-like
- * logical items. It extends {@link AccessibilityNodeProviderCompat} and
- * simplifies many aspects of providing information to accessibility services
- * and managing accessibility focus.
- * <p>
- * Clients should override abstract methods on this class and attach it to the
- * host view using {@link ViewCompat#setAccessibilityDelegate}:
- * <p>
- * <pre>
- * class MyCustomView extends View {
- *     private MyVirtualViewHelper mVirtualViewHelper;
- *
- *     public MyCustomView(Context context, ...) {
- *         ...
- *         mVirtualViewHelper = new MyVirtualViewHelper(this);
- *         ViewCompat.setAccessibilityDelegate(this, mVirtualViewHelper);
- *     }
- *
- *     &#64;Override
- *     public boolean dispatchHoverEvent(MotionEvent event) {
- *       return mHelper.dispatchHoverEvent(this, event)
- *           || super.dispatchHoverEvent(event);
- *     }
- *
- *     &#64;Override
- *     public boolean dispatchKeyEvent(KeyEvent event) {
- *       return mHelper.dispatchKeyEvent(event)
- *           || super.dispatchKeyEvent(event);
- *     }
- *
- *     &#64;Override
- *     public boolean onFocusChanged(boolean gainFocus, int direction,
- *         Rect previouslyFocusedRect) {
- *       super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
- *       mHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
- *     }
- * }
- * mAccessHelper = new MyExploreByTouchHelper(someView);
- * ViewCompat.setAccessibilityDelegate(someView, mAccessHelper);
- * </pre>
- */
-public abstract class ExploreByTouchHelper extends AccessibilityDelegateCompat {
-    /** Virtual node identifier value for invalid nodes. */
-    public static final int INVALID_ID = Integer.MIN_VALUE;
-
-    /** Virtual node identifier value for the host view's node. */
-    public static final int HOST_ID = View.NO_ID;
-
-    /** Default class name used for virtual views. */
-    private static final String DEFAULT_CLASS_NAME = "android.view.View";
-
-    /** Default bounds used to determine if the client didn't set any. */
-    private static final Rect INVALID_PARENT_BOUNDS = new Rect(
-            Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
-
-    // Temporary, reusable data structures.
-    private final Rect mTempScreenRect = new Rect();
-    private final Rect mTempParentRect = new Rect();
-    private final Rect mTempVisibleRect = new Rect();
-    private final int[] mTempGlobalRect = new int[2];
-
-    /** System accessibility manager, used to check state and send events. */
-    private final AccessibilityManager mManager;
-
-    /** View whose internal structure is exposed through this helper. */
-    private final View mHost;
-
-    /** Virtual node provider used to expose logical structure to services. */
-    private MyNodeProvider mNodeProvider;
-
-    /** Identifier for the virtual view that holds accessibility focus. */
-    private int mAccessibilityFocusedVirtualViewId = INVALID_ID;
-
-    /** Identifier for the virtual view that holds keyboard focus. */
-    private int mKeyboardFocusedVirtualViewId = INVALID_ID;
-
-    /** Identifier for the virtual view that is currently hovered. */
-    private int mHoveredVirtualViewId = INVALID_ID;
-
-    /**
-     * Constructs a new helper that can expose a virtual view hierarchy for the
-     * specified host view.
-     *
-     * @param host view whose virtual view hierarchy is exposed by this helper
-     */
-    public ExploreByTouchHelper(@NonNull View host) {
-        if (host == null) {
-            throw new IllegalArgumentException("View may not be null");
-        }
-
-        mHost = host;
-
-        final Context context = host.getContext();
-        mManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
-
-        // Host view must be focusable so that we can delegate to virtual
-        // views.
-        host.setFocusable(true);
-        if (ViewCompat.getImportantForAccessibility(host)
-                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            ViewCompat.setImportantForAccessibility(
-                    host, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-    }
-
-    @Override
-    public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
-        if (mNodeProvider == null) {
-            mNodeProvider = new MyNodeProvider();
-        }
-        return mNodeProvider;
-    }
-
-    /**
-     * Delegates hover events from the host view.
-     * <p>
-     * Dispatches hover {@link MotionEvent}s to the virtual view hierarchy when
-     * the Explore by Touch feature is enabled.
-     * <p>
-     * This method should be called by overriding the host view's
-     * {@link View#dispatchHoverEvent(MotionEvent)} method:
-     * <pre>&#64;Override
-     * public boolean dispatchHoverEvent(MotionEvent event) {
-     *   return mHelper.dispatchHoverEvent(this, event)
-     *       || super.dispatchHoverEvent(event);
-     * }
-     * </pre>
-     *
-     * @param event The hover event to dispatch to the virtual view hierarchy.
-     * @return Whether the hover event was handled.
-     */
-    public final boolean dispatchHoverEvent(@NonNull MotionEvent event) {
-        if (!mManager.isEnabled() || !mManager.isTouchExplorationEnabled()) {
-            return false;
-        }
-
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_HOVER_MOVE:
-            case MotionEvent.ACTION_HOVER_ENTER:
-                final int virtualViewId = getVirtualViewAt(event.getX(), event.getY());
-                updateHoveredVirtualView(virtualViewId);
-                return (virtualViewId != INVALID_ID);
-            case MotionEvent.ACTION_HOVER_EXIT:
-                if (mAccessibilityFocusedVirtualViewId != INVALID_ID) {
-                    updateHoveredVirtualView(INVALID_ID);
-                    return true;
-                }
-                return false;
-            default:
-                return false;
-        }
-    }
-
-    /**
-     * Delegates key events from the host view.
-     * <p>
-     * This method should be called by overriding the host view's
-     * {@link View#dispatchKeyEvent(KeyEvent)} method:
-     * <pre>&#64;Override
-     * public boolean dispatchKeyEvent(KeyEvent event) {
-     *   return mHelper.dispatchKeyEvent(event)
-     *       || super.dispatchKeyEvent(event);
-     * }
-     * </pre>
-     */
-    public final boolean dispatchKeyEvent(@NonNull KeyEvent event) {
-        boolean handled = false;
-
-        final int action = event.getAction();
-        if (action != KeyEvent.ACTION_UP) {
-            final int keyCode = event.getKeyCode();
-            switch (keyCode) {
-                case KeyEvent.KEYCODE_DPAD_LEFT:
-                case KeyEvent.KEYCODE_DPAD_UP:
-                case KeyEvent.KEYCODE_DPAD_RIGHT:
-                case KeyEvent.KEYCODE_DPAD_DOWN:
-                    if (event.hasNoModifiers()) {
-                        final int direction = keyToDirection(keyCode);
-                        final int count = 1 + event.getRepeatCount();
-                        for (int i = 0; i < count; i++) {
-                            if (moveFocus(direction, null)) {
-                                handled = true;
-                            } else {
-                                break;
-                            }
-                        }
-                    }
-                    break;
-                case KeyEvent.KEYCODE_DPAD_CENTER:
-                case KeyEvent.KEYCODE_ENTER:
-                    if (event.hasNoModifiers()) {
-                        if (event.getRepeatCount() == 0) {
-                            clickKeyboardFocusedVirtualView();
-                            handled = true;
-                        }
-                    }
-                    break;
-                case KeyEvent.KEYCODE_TAB:
-                    if (event.hasNoModifiers()) {
-                        handled = moveFocus(View.FOCUS_FORWARD, null);
-                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
-                        handled = moveFocus(View.FOCUS_BACKWARD, null);
-                    }
-                    break;
-            }
-        }
-
-        return handled;
-    }
-
-    /**
-     * Delegates focus changes from the host view.
-     * <p>
-     * This method should be called by overriding the host view's
-     * {@link View#onFocusChanged(boolean, int, Rect)} method:
-     * <pre>&#64;Override
-     * public boolean onFocusChanged(boolean gainFocus, int direction,
-     *     Rect previouslyFocusedRect) {
-     *   super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
-     *   mHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
-     * }
-     * </pre>
-     */
-    public final void onFocusChanged(boolean gainFocus, int direction,
-            @Nullable Rect previouslyFocusedRect) {
-        if (mKeyboardFocusedVirtualViewId != INVALID_ID) {
-            clearKeyboardFocusForVirtualView(mKeyboardFocusedVirtualViewId);
-        }
-
-        if (gainFocus) {
-            moveFocus(direction, previouslyFocusedRect);
-        }
-    }
-
-    /**
-     * @return the identifier of the virtual view that has accessibility focus
-     *         or {@link #INVALID_ID} if no virtual view has accessibility
-     *         focus
-     */
-    public final int getAccessibilityFocusedVirtualViewId() {
-        return mAccessibilityFocusedVirtualViewId;
-    }
-
-    /**
-     * @return the identifier of the virtual view that has keyboard focus
-     *         or {@link #INVALID_ID} if no virtual view has keyboard focus
-     */
-    public final int getKeyboardFocusedVirtualViewId() {
-        return mKeyboardFocusedVirtualViewId;
-    }
-
-    /**
-     * Maps key event codes to focus directions.
-     *
-     * @param keyCode the key event code
-     * @return the corresponding focus direction
-     */
-    @FocusRealDirection
-    private static int keyToDirection(int keyCode) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-                return View.FOCUS_LEFT;
-            case KeyEvent.KEYCODE_DPAD_UP:
-                return View.FOCUS_UP;
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                return View.FOCUS_RIGHT;
-            default:
-                return View.FOCUS_DOWN;
-        }
-    }
-
-    /**
-     * Obtains the bounds for the specified virtual view.
-     *
-     * @param virtualViewId the identifier of the virtual view
-     * @param outBounds the rect to populate with virtual view bounds
-     */
-    private void getBoundsInParent(int virtualViewId, Rect outBounds) {
-        final AccessibilityNodeInfoCompat node = obtainAccessibilityNodeInfo(virtualViewId);
-        node.getBoundsInParent(outBounds);
-    }
-
-    /**
-     * Adapts AccessibilityNodeInfoCompat for obtaining bounds.
-     */
-    private static final FocusStrategy.BoundsAdapter<AccessibilityNodeInfoCompat> NODE_ADAPTER =
-            new FocusStrategy.BoundsAdapter<AccessibilityNodeInfoCompat>() {
-                @Override
-                public void obtainBounds(AccessibilityNodeInfoCompat node, Rect outBounds) {
-                    node.getBoundsInParent(outBounds);
-                }
-            };
-
-    /**
-     * Adapts SparseArrayCompat for iterating through values.
-     */
-    private static final FocusStrategy.CollectionAdapter<SparseArrayCompat<
-            AccessibilityNodeInfoCompat>, AccessibilityNodeInfoCompat> SPARSE_VALUES_ADAPTER =
-            new FocusStrategy.CollectionAdapter<SparseArrayCompat<
-                    AccessibilityNodeInfoCompat>, AccessibilityNodeInfoCompat>() {
-                @Override
-                public AccessibilityNodeInfoCompat get(
-                        SparseArrayCompat<AccessibilityNodeInfoCompat> collection, int index) {
-                    return collection.valueAt(index);
-                }
-
-                @Override
-                public int size(SparseArrayCompat<AccessibilityNodeInfoCompat> collection) {
-                    return collection.size();
-                }
-            };
-
-    /**
-     * Attempts to move keyboard focus in the specified direction.
-     *
-     * @param direction the direction in which to move keyboard focus
-     * @param previouslyFocusedRect the bounds of the previously focused item,
-     *                              or {@code null} if not available
-     * @return {@code true} if keyboard focus moved to a virtual view managed
-     *         by this helper, or {@code false} otherwise
-     */
-    private boolean moveFocus(@FocusDirection int direction, @Nullable Rect previouslyFocusedRect) {
-        final SparseArrayCompat<AccessibilityNodeInfoCompat> allNodes = getAllNodes();
-
-        final int focusedNodeId = mKeyboardFocusedVirtualViewId;
-        final AccessibilityNodeInfoCompat focusedNode =
-                focusedNodeId == INVALID_ID ? null : allNodes.get(focusedNodeId);
-
-        final AccessibilityNodeInfoCompat nextFocusedNode;
-        switch (direction) {
-            case View.FOCUS_FORWARD:
-            case View.FOCUS_BACKWARD:
-                final boolean isLayoutRtl =
-                        ViewCompat.getLayoutDirection(mHost) == ViewCompat.LAYOUT_DIRECTION_RTL;
-                nextFocusedNode = FocusStrategy.findNextFocusInRelativeDirection(allNodes,
-                        SPARSE_VALUES_ADAPTER, NODE_ADAPTER, focusedNode, direction, isLayoutRtl,
-                        false);
-                break;
-            case View.FOCUS_LEFT:
-            case View.FOCUS_UP:
-            case View.FOCUS_RIGHT:
-            case View.FOCUS_DOWN:
-                final Rect selectedRect = new Rect();
-                if (mKeyboardFocusedVirtualViewId != INVALID_ID) {
-                    // Focus is moving from a virtual view within the host.
-                    getBoundsInParent(mKeyboardFocusedVirtualViewId, selectedRect);
-                } else if (previouslyFocusedRect != null) {
-                    // Focus is moving from a real view outside the host.
-                    selectedRect.set(previouslyFocusedRect);
-                } else {
-                    // Focus is moving from... somewhere? Make a guess.
-                    // Usually this happens when another view was too lazy
-                    // to pass the previously focused rect (ex. ScrollView
-                    // when moving UP or DOWN).
-                    guessPreviouslyFocusedRect(mHost, direction, selectedRect);
-                }
-                nextFocusedNode = FocusStrategy.findNextFocusInAbsoluteDirection(allNodes,
-                        SPARSE_VALUES_ADAPTER, NODE_ADAPTER, focusedNode, selectedRect, direction);
-                break;
-            default:
-                throw new IllegalArgumentException("direction must be one of "
-                        + "{FOCUS_FORWARD, FOCUS_BACKWARD, FOCUS_UP, FOCUS_DOWN, "
-                        + "FOCUS_LEFT, FOCUS_RIGHT}.");
-        }
-
-        final int nextFocusedNodeId;
-        if (nextFocusedNode == null) {
-            nextFocusedNodeId = INVALID_ID;
-        } else {
-            final int index = allNodes.indexOfValue(nextFocusedNode);
-            nextFocusedNodeId = allNodes.keyAt(index);
-        }
-
-        return requestKeyboardFocusForVirtualView(nextFocusedNodeId);
-    }
-
-    private SparseArrayCompat<AccessibilityNodeInfoCompat> getAllNodes() {
-        final List<Integer> virtualViewIds = new ArrayList<>();
-        getVisibleVirtualViews(virtualViewIds);
-
-        final SparseArrayCompat<AccessibilityNodeInfoCompat> allNodes = new SparseArrayCompat<>();
-        for (int virtualViewId = 0; virtualViewId < virtualViewIds.size(); virtualViewId++) {
-            final AccessibilityNodeInfoCompat virtualView = createNodeForChild(virtualViewId);
-            allNodes.put(virtualViewId, virtualView);
-        }
-
-        return allNodes;
-    }
-
-    /**
-     * Obtains a best guess for the previously focused rect for keyboard focus
-     * moving in the specified direction.
-     *
-     * @param host the view into which focus is moving
-     * @param direction the absolute direction in which focus is moving
-     * @param outBounds the rect to populate with the best-guess bounds for the
-     *                  previous focus rect
-     */
-    private static Rect guessPreviouslyFocusedRect(@NonNull View host,
-            @FocusRealDirection int direction, @NonNull Rect outBounds) {
-        final int w = host.getWidth();
-        final int h = host.getHeight();
-
-        switch (direction) {
-            case View.FOCUS_LEFT:
-                outBounds.set(w, 0, w, h);
-                break;
-            case View.FOCUS_UP:
-                outBounds.set(0, h, w, h);
-                break;
-            case View.FOCUS_RIGHT:
-                outBounds.set(-1, 0, -1, h);
-                break;
-            case View.FOCUS_DOWN:
-                outBounds.set(0, -1, w, -1);
-                break;
-            default:
-                throw new IllegalArgumentException("direction must be one of "
-                        + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-        }
-
-        return outBounds;
-    }
-
-    /**
-     * Performs a click action on the keyboard focused virtual view, if any.
-     *
-     * @return {@code true} if the click action was performed successfully or
-     *         {@code false} otherwise
-     */
-    private boolean clickKeyboardFocusedVirtualView() {
-        return mKeyboardFocusedVirtualViewId != INVALID_ID && onPerformActionForVirtualView(
-                mKeyboardFocusedVirtualViewId, AccessibilityNodeInfoCompat.ACTION_CLICK, null);
-    }
-
-    /**
-     * Populates an event of the specified type with information about an item
-     * and attempts to send it up through the view hierarchy.
-     * <p>
-     * You should call this method after performing a user action that normally
-     * fires an accessibility event, such as clicking on an item.
-     * <p>
-     * <pre>public void performItemClick(T item) {
-     *   ...
-     *   sendEventForVirtualViewId(item.id, AccessibilityEvent.TYPE_VIEW_CLICKED);
-     * }
-     * </pre>
-     *
-     * @param virtualViewId the identifier of the virtual view for which to
-     *                      send an event
-     * @param eventType the type of event to send
-     * @return {@code true} if the event was sent successfully, {@code false}
-     *         otherwise
-     */
-    public final boolean sendEventForVirtualView(int virtualViewId, int eventType) {
-        if ((virtualViewId == INVALID_ID) || !mManager.isEnabled()) {
-            return false;
-        }
-
-        final ViewParent parent = mHost.getParent();
-        if (parent == null) {
-            return false;
-        }
-
-        final AccessibilityEvent event = createEvent(virtualViewId, eventType);
-        return ViewParentCompat.requestSendAccessibilityEvent(parent, mHost, event);
-    }
-
-    /**
-     * Notifies the accessibility framework that the properties of the parent
-     * view have changed.
-     * <p>
-     * You <strong>must</strong> call this method after adding or removing
-     * items from the parent view.
-     */
-    public final void invalidateRoot() {
-        invalidateVirtualView(HOST_ID, AccessibilityEventCompat.CONTENT_CHANGE_TYPE_SUBTREE);
-    }
-
-    /**
-     * Notifies the accessibility framework that the properties of a particular
-     * item have changed.
-     * <p>
-     * You <strong>must</strong> call this method after changing any of the
-     * properties set in
-     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}.
-     *
-     * @param virtualViewId the virtual view id to invalidate, or
-     *                      {@link #HOST_ID} to invalidate the root view
-     * @see #invalidateVirtualView(int, int)
-     */
-    public final void invalidateVirtualView(int virtualViewId) {
-        invalidateVirtualView(virtualViewId,
-                AccessibilityEventCompat.CONTENT_CHANGE_TYPE_UNDEFINED);
-    }
-
-    /**
-     * Notifies the accessibility framework that the properties of a particular
-     * item have changed.
-     * <p>
-     * You <strong>must</strong> call this method after changing any of the
-     * properties set in
-     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}.
-     *
-     * @param virtualViewId the virtual view id to invalidate, or
-     *                      {@link #HOST_ID} to invalidate the root view
-     * @param changeTypes the bit mask of change types. May be {@code 0} for the
-     *                    default (undefined) change type or one or more of:
-     *         <ul>
-     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
-     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_SUBTREE}
-     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_TEXT}
-     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_UNDEFINED}
-     *         </ul>
-     */
-    public final void invalidateVirtualView(int virtualViewId, int changeTypes) {
-        if (virtualViewId != INVALID_ID && mManager.isEnabled()) {
-            final ViewParent parent = mHost.getParent();
-            if (parent != null) {
-                // Send events up the hierarchy so they can be coalesced.
-                final AccessibilityEvent event = createEvent(virtualViewId,
-                        AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED);
-                AccessibilityEventCompat.setContentChangeTypes(event, changeTypes);
-                ViewParentCompat.requestSendAccessibilityEvent(parent, mHost, event);
-            }
-        }
-    }
-
-    /**
-     * Returns the virtual view ID for the currently accessibility focused
-     * item.
-     *
-     * @return the identifier of the virtual view that has accessibility focus
-     *         or {@link #INVALID_ID} if no virtual view has accessibility
-     *         focus
-     * @deprecated Use {@link #getAccessibilityFocusedVirtualViewId()}.
-     */
-    @Deprecated
-    public int getFocusedVirtualView() {
-        return getAccessibilityFocusedVirtualViewId();
-    }
-
-    /**
-     * Called when the focus state of a virtual view changes.
-     *
-     * @param virtualViewId the virtual view identifier
-     * @param hasFocus      {@code true} if the view has focus, {@code false}
-     *                      otherwise
-     */
-    protected void onVirtualViewKeyboardFocusChanged(int virtualViewId, boolean hasFocus) {
-        // Stub method.
-    }
-
-    /**
-     * Sets the currently hovered item, sending hover accessibility events as
-     * necessary to maintain the correct state.
-     *
-     * @param virtualViewId the virtual view id for the item currently being
-     *                      hovered, or {@link #INVALID_ID} if no item is
-     *                      hovered within the parent view
-     */
-    private void updateHoveredVirtualView(int virtualViewId) {
-        if (mHoveredVirtualViewId == virtualViewId) {
-            return;
-        }
-
-        final int previousVirtualViewId = mHoveredVirtualViewId;
-        mHoveredVirtualViewId = virtualViewId;
-
-        // Stay consistent with framework behavior by sending ENTER/EXIT pairs
-        // in reverse order. This is accurate as of API 18.
-        sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
-        sendEventForVirtualView(
-                previousVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
-    }
-
-    /**
-     * Constructs and returns an {@link AccessibilityEvent} for the specified
-     * virtual view id, which includes the host view ({@link #HOST_ID}).
-     *
-     * @param virtualViewId the virtual view id for the item for which to
-     *                      construct an event
-     * @param eventType the type of event to construct
-     * @return an {@link AccessibilityEvent} populated with information about
-     *         the specified item
-     */
-    private AccessibilityEvent createEvent(int virtualViewId, int eventType) {
-        switch (virtualViewId) {
-            case HOST_ID:
-                return createEventForHost(eventType);
-            default:
-                return createEventForChild(virtualViewId, eventType);
-        }
-    }
-
-    /**
-     * Constructs and returns an {@link AccessibilityEvent} for the host node.
-     *
-     * @param eventType the type of event to construct
-     * @return an {@link AccessibilityEvent} populated with information about
-     *         the specified item
-     */
-    private AccessibilityEvent createEventForHost(int eventType) {
-        final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
-        mHost.onInitializeAccessibilityEvent(event);
-        return event;
-    }
-
-    @Override
-    public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-        super.onInitializeAccessibilityEvent(host, event);
-
-        // Allow the client to populate the event.
-        onPopulateEventForHost(event);
-    }
-
-    /**
-     * Constructs and returns an {@link AccessibilityEvent} populated with
-     * information about the specified item.
-     *
-     * @param virtualViewId the virtual view id for the item for which to
-     *                      construct an event
-     * @param eventType the type of event to construct
-     * @return an {@link AccessibilityEvent} populated with information about
-     *         the specified item
-     */
-    private AccessibilityEvent createEventForChild(int virtualViewId, int eventType) {
-        final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
-        final AccessibilityNodeInfoCompat node = obtainAccessibilityNodeInfo(virtualViewId);
-
-        // Allow the client to override these properties,
-        event.getText().add(node.getText());
-        event.setContentDescription(node.getContentDescription());
-        event.setScrollable(node.isScrollable());
-        event.setPassword(node.isPassword());
-        event.setEnabled(node.isEnabled());
-        event.setChecked(node.isChecked());
-
-        // Allow the client to populate the event.
-        onPopulateEventForVirtualView(virtualViewId, event);
-
-        // Make sure the developer is following the rules.
-        if (event.getText().isEmpty() && (event.getContentDescription() == null)) {
-            throw new RuntimeException("Callbacks must add text or a content description in "
-                    + "populateEventForVirtualViewId()");
-        }
-
-        // Don't allow the client to override these properties.
-        event.setClassName(node.getClassName());
-        AccessibilityRecordCompat.setSource(event, mHost, virtualViewId);
-        event.setPackageName(mHost.getContext().getPackageName());
-
-        return event;
-    }
-
-    /**
-     * Obtains a populated {@link AccessibilityNodeInfoCompat} for the
-     * virtual view with the specified identifier.
-     * <p>
-     * This method may be called with identifier {@link #HOST_ID} to obtain a
-     * node for the host view.
-     *
-     * @param virtualViewId the identifier of the virtual view for which to
-     *                      construct a node
-     * @return an {@link AccessibilityNodeInfoCompat} populated with information
-     *         about the specified item
-     */
-    @NonNull
-    AccessibilityNodeInfoCompat obtainAccessibilityNodeInfo(int virtualViewId) {
-        if (virtualViewId == HOST_ID) {
-            return createNodeForHost();
-        }
-
-        return createNodeForChild(virtualViewId);
-    }
-
-    /**
-     * Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
-     * host view populated with its virtual descendants.
-     *
-     * @return an {@link AccessibilityNodeInfoCompat} for the parent node
-     */
-    @NonNull
-    private AccessibilityNodeInfoCompat createNodeForHost() {
-        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(mHost);
-        ViewCompat.onInitializeAccessibilityNodeInfo(mHost, info);
-
-        // Add the virtual descendants.
-        final ArrayList<Integer> virtualViewIds = new ArrayList<>();
-        getVisibleVirtualViews(virtualViewIds);
-
-        final int realNodeCount = info.getChildCount();
-        if (realNodeCount > 0 && virtualViewIds.size() > 0) {
-            throw new RuntimeException("Views cannot have both real and virtual children");
-        }
-
-        for (int i = 0, count = virtualViewIds.size(); i < count; i++) {
-            info.addChild(mHost, virtualViewIds.get(i));
-        }
-
-        return info;
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-        super.onInitializeAccessibilityNodeInfo(host, info);
-
-        // Allow the client to populate the host node.
-        onPopulateNodeForHost(info);
-    }
-
-    /**
-     * Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
-     * specified item. Automatically manages accessibility focus actions.
-     * <p>
-     * Allows the implementing class to specify most node properties, but
-     * overrides the following:
-     * <ul>
-     * <li>{@link AccessibilityNodeInfoCompat#setPackageName}
-     * <li>{@link AccessibilityNodeInfoCompat#setClassName}
-     * <li>{@link AccessibilityNodeInfoCompat#setParent(View)}
-     * <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)}
-     * <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
-     * <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
-     * </ul>
-     * <p>
-     * Uses the bounds of the parent view and the parent-relative bounding
-     * rectangle specified by
-     * {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically
-     * update the following properties:
-     * <ul>
-     * <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
-     * <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent}
-     * </ul>
-     *
-     * @param virtualViewId the virtual view id for item for which to construct
-     *                      a node
-     * @return an {@link AccessibilityNodeInfoCompat} for the specified item
-     */
-    @NonNull
-    private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
-        final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
-
-        // Ensure the client has good defaults.
-        node.setEnabled(true);
-        node.setFocusable(true);
-        node.setClassName(DEFAULT_CLASS_NAME);
-        node.setBoundsInParent(INVALID_PARENT_BOUNDS);
-        node.setBoundsInScreen(INVALID_PARENT_BOUNDS);
-        node.setParent(mHost);
-
-        // Allow the client to populate the node.
-        onPopulateNodeForVirtualView(virtualViewId, node);
-
-        // Make sure the developer is following the rules.
-        if ((node.getText() == null) && (node.getContentDescription() == null)) {
-            throw new RuntimeException("Callbacks must add text or a content description in "
-                    + "populateNodeForVirtualViewId()");
-        }
-
-        node.getBoundsInParent(mTempParentRect);
-        if (mTempParentRect.equals(INVALID_PARENT_BOUNDS)) {
-            throw new RuntimeException("Callbacks must set parent bounds in "
-                    + "populateNodeForVirtualViewId()");
-        }
-
-        final int actions = node.getActions();
-        if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
-            throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in "
-                    + "populateNodeForVirtualViewId()");
-        }
-        if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
-            throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in "
-                    + "populateNodeForVirtualViewId()");
-        }
-
-        // Don't allow the client to override these properties.
-        node.setPackageName(mHost.getContext().getPackageName());
-        node.setSource(mHost, virtualViewId);
-
-        // Manage internal accessibility focus state.
-        if (mAccessibilityFocusedVirtualViewId == virtualViewId) {
-            node.setAccessibilityFocused(true);
-            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
-        } else {
-            node.setAccessibilityFocused(false);
-            node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
-        }
-
-        // Manage internal keyboard focus state.
-        final boolean isFocused = mKeyboardFocusedVirtualViewId == virtualViewId;
-        if (isFocused) {
-            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS);
-        } else if (node.isFocusable()) {
-            node.addAction(AccessibilityNodeInfoCompat.ACTION_FOCUS);
-        }
-        node.setFocused(isFocused);
-
-        mHost.getLocationOnScreen(mTempGlobalRect);
-
-        // If not explicitly specified, calculate screen-relative bounds and
-        // offset for scroll position based on bounds in parent.
-        node.getBoundsInScreen(mTempScreenRect);
-        if (mTempScreenRect.equals(INVALID_PARENT_BOUNDS)) {
-            node.getBoundsInParent(mTempScreenRect);
-
-            // If there is a parent node, adjust bounds based on the parent node.
-            if (node.mParentVirtualDescendantId != HOST_ID) {
-                AccessibilityNodeInfoCompat parentNode = AccessibilityNodeInfoCompat.obtain();
-                // Walk up the node tree to adjust the screen rect.
-                for (int virtualDescendantId = node.mParentVirtualDescendantId;
-                        virtualDescendantId != HOST_ID;
-                        virtualDescendantId = parentNode.mParentVirtualDescendantId) {
-                    // Reset the values in the parent node we'll be using.
-                    parentNode.setParent(mHost, HOST_ID);
-                    parentNode.setBoundsInParent(INVALID_PARENT_BOUNDS);
-                    // Adjust the bounds for the parent node.
-                    onPopulateNodeForVirtualView(virtualDescendantId, parentNode);
-                    parentNode.getBoundsInParent(mTempParentRect);
-                    mTempScreenRect.offset(mTempParentRect.left, mTempParentRect.top);
-                }
-                parentNode.recycle();
-            }
-            // Adjust the rect for the host view's location.
-            mTempScreenRect.offset(mTempGlobalRect[0] - mHost.getScrollX(),
-                    mTempGlobalRect[1] - mHost.getScrollY());
-        }
-
-        if (mHost.getLocalVisibleRect(mTempVisibleRect)) {
-            mTempVisibleRect.offset(mTempGlobalRect[0] - mHost.getScrollX(),
-                    mTempGlobalRect[1] - mHost.getScrollY());
-            final boolean intersects = mTempScreenRect.intersect(mTempVisibleRect);
-            if (intersects) {
-                node.setBoundsInScreen(mTempScreenRect);
-
-                if (isVisibleToUser(mTempScreenRect)) {
-                    node.setVisibleToUser(true);
-                }
-            }
-        }
-
-        return node;
-    }
-
-    boolean performAction(int virtualViewId, int action, Bundle arguments) {
-        switch (virtualViewId) {
-            case HOST_ID:
-                return performActionForHost(action, arguments);
-            default:
-                return performActionForChild(virtualViewId, action, arguments);
-        }
-    }
-
-    private boolean performActionForHost(int action, Bundle arguments) {
-        return ViewCompat.performAccessibilityAction(mHost, action, arguments);
-    }
-
-    private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) {
-        switch (action) {
-            case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
-                return requestAccessibilityFocus(virtualViewId);
-            case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
-                return clearAccessibilityFocus(virtualViewId);
-            case AccessibilityNodeInfoCompat.ACTION_FOCUS:
-                return requestKeyboardFocusForVirtualView(virtualViewId);
-            case AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS:
-                return clearKeyboardFocusForVirtualView(virtualViewId);
-            default:
-                return onPerformActionForVirtualView(virtualViewId, action, arguments);
-        }
-    }
-
-    /**
-     * Computes whether the specified {@link Rect} intersects with the visible
-     * portion of its parent {@link View}. Modifies {@code localRect} to contain
-     * only the visible portion.
-     *
-     * @param localRect a rectangle in local (parent) coordinates
-     * @return whether the specified {@link Rect} is visible on the screen
-     */
-    private boolean isVisibleToUser(Rect localRect) {
-        // Missing or empty bounds mean this view is not visible.
-        if ((localRect == null) || localRect.isEmpty()) {
-            return false;
-        }
-
-        // Attached to invisible window means this view is not visible.
-        if (mHost.getWindowVisibility() != View.VISIBLE) {
-            return false;
-        }
-
-        // An invisible predecessor means that this view is not visible.
-        ViewParent viewParent = mHost.getParent();
-        while (viewParent instanceof View) {
-            final View view = (View) viewParent;
-            if ((view.getAlpha() <= 0) || (view.getVisibility() != View.VISIBLE)) {
-                return false;
-            }
-            viewParent = view.getParent();
-        }
-
-        // A null parent implies the view is not visible.
-        return viewParent != null;
-    }
-
-    /**
-     * Attempts to give accessibility focus to a virtual view.
-     * <p>
-     * A virtual view will not actually take focus if
-     * {@link AccessibilityManager#isEnabled()} returns false,
-     * {@link AccessibilityManager#isTouchExplorationEnabled()} returns false,
-     * or the view already has accessibility focus.
-     *
-     * @param virtualViewId the identifier of the virtual view on which to
-     *                      place accessibility focus
-     * @return whether this virtual view actually took accessibility focus
-     */
-    private boolean requestAccessibilityFocus(int virtualViewId) {
-        if (!mManager.isEnabled() || !mManager.isTouchExplorationEnabled()) {
-            return false;
-        }
-        // TODO: Check virtual view visibility.
-        if (mAccessibilityFocusedVirtualViewId != virtualViewId) {
-            // Clear focus from the previously focused view, if applicable.
-            if (mAccessibilityFocusedVirtualViewId != INVALID_ID) {
-                clearAccessibilityFocus(mAccessibilityFocusedVirtualViewId);
-            }
-
-            // Set focus on the new view.
-            mAccessibilityFocusedVirtualViewId = virtualViewId;
-
-            // TODO: Only invalidate virtual view bounds.
-            mHost.invalidate();
-            sendEventForVirtualView(virtualViewId,
-                    AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Attempts to clear accessibility focus from a virtual view.
-     *
-     * @param virtualViewId the identifier of the virtual view from which to
-     *                      clear accessibility focus
-     * @return whether this virtual view actually cleared accessibility focus
-     */
-    private boolean clearAccessibilityFocus(int virtualViewId) {
-        if (mAccessibilityFocusedVirtualViewId == virtualViewId) {
-            mAccessibilityFocusedVirtualViewId = INVALID_ID;
-            mHost.invalidate();
-            sendEventForVirtualView(virtualViewId,
-                    AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Attempts to give keyboard focus to a virtual view.
-     *
-     * @param virtualViewId the identifier of the virtual view on which to
-     *                      place keyboard focus
-     * @return whether this virtual view actually took keyboard focus
-     */
-    public final boolean requestKeyboardFocusForVirtualView(int virtualViewId) {
-        if (!mHost.isFocused() && !mHost.requestFocus()) {
-            // Host must have real keyboard focus.
-            return false;
-        }
-
-        if (mKeyboardFocusedVirtualViewId == virtualViewId) {
-            // The virtual view already has focus.
-            return false;
-        }
-
-        if (mKeyboardFocusedVirtualViewId != INVALID_ID) {
-            clearKeyboardFocusForVirtualView(mKeyboardFocusedVirtualViewId);
-        }
-
-        mKeyboardFocusedVirtualViewId = virtualViewId;
-
-        onVirtualViewKeyboardFocusChanged(virtualViewId, true);
-        sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_FOCUSED);
-
-        return true;
-    }
-
-    /**
-     * Attempts to clear keyboard focus from a virtual view.
-     *
-     * @param virtualViewId the identifier of the virtual view from which to
-     *                      clear keyboard focus
-     * @return whether this virtual view actually cleared keyboard focus
-     */
-    public final boolean clearKeyboardFocusForVirtualView(int virtualViewId) {
-        if (mKeyboardFocusedVirtualViewId != virtualViewId) {
-            // The virtual view is not focused.
-            return false;
-        }
-
-        mKeyboardFocusedVirtualViewId = INVALID_ID;
-
-        onVirtualViewKeyboardFocusChanged(virtualViewId, false);
-        sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_FOCUSED);
-
-        return true;
-    }
-
-    /**
-     * Provides a mapping between view-relative coordinates and logical
-     * items.
-     *
-     * @param x The view-relative x coordinate
-     * @param y The view-relative y coordinate
-     * @return virtual view identifier for the logical item under
-     *         coordinates (x,y) or {@link #HOST_ID} if there is no item at
-     *         the given coordinates
-     */
-    protected abstract int getVirtualViewAt(float x, float y);
-
-    /**
-     * Populates a list with the view's visible items. The ordering of items
-     * within {@code virtualViewIds} specifies order of accessibility focus
-     * traversal.
-     *
-     * @param virtualViewIds The list to populate with visible items
-     */
-    protected abstract void getVisibleVirtualViews(List<Integer> virtualViewIds);
-
-    /**
-     * Populates an {@link AccessibilityEvent} with information about the
-     * specified item.
-     * <p>
-     * The helper class automatically populates the following fields based on
-     * the values set by
-     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)},
-     * but implementations may optionally override them:
-     * <ul>
-     * <li>event text, see {@link AccessibilityEvent#getText()}
-     * <li>content description, see
-     * {@link AccessibilityEvent#setContentDescription(CharSequence)}
-     * <li>scrollability, see {@link AccessibilityEvent#setScrollable(boolean)}
-     * <li>password state, see {@link AccessibilityEvent#setPassword(boolean)}
-     * <li>enabled state, see {@link AccessibilityEvent#setEnabled(boolean)}
-     * <li>checked state, see {@link AccessibilityEvent#setChecked(boolean)}
-     * </ul>
-     * <p>
-     * The following required fields are automatically populated by the
-     * helper class and may not be overridden:
-     * <ul>
-     * <li>item class name, set to the value used in
-     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}
-     * <li>package name, set to the package of the host view's
-     * {@link Context}, see {@link AccessibilityEvent#setPackageName}
-     * <li>event source, set to the host view and virtual view identifier,
-     * see {@link AccessibilityRecordCompat#setSource(AccessibilityRecord, View, int)}
-     * </ul>
-     *
-     * @param virtualViewId The virtual view id for the item for which to
-     *            populate the event
-     * @param event The event to populate
-     */
-    protected void onPopulateEventForVirtualView(int virtualViewId,
-            @NonNull AccessibilityEvent event) {
-        // Default implementation is no-op.
-    }
-
-    /**
-     * Populates an {@link AccessibilityEvent} with information about the host
-     * view.
-     * <p>
-     * The default implementation is a no-op.
-     *
-     * @param event the event to populate with information about the host view
-     */
-    protected void onPopulateEventForHost(@NonNull AccessibilityEvent event) {
-        // Default implementation is no-op.
-    }
-
-    /**
-     * Populates an {@link AccessibilityNodeInfoCompat} with information
-     * about the specified item.
-     * <p>
-     * Implementations <strong>must</strong> populate the following required
-     * fields:
-     * <ul>
-     * <li>event text, see
-     * {@link AccessibilityNodeInfoCompat#setText(CharSequence)} or
-     * {@link AccessibilityNodeInfoCompat#setContentDescription(CharSequence)}
-     * <li>bounds in parent coordinates, see
-     * {@link AccessibilityNodeInfoCompat#setBoundsInParent(Rect)}
-     * </ul>
-     * <p>
-     * The helper class automatically populates the following fields with
-     * default values, but implementations may optionally override them:
-     * <ul>
-     * <li>enabled state, set to {@code true}, see
-     * {@link AccessibilityNodeInfoCompat#setEnabled(boolean)}
-     * <li>keyboard focusability, set to {@code true}, see
-     * {@link AccessibilityNodeInfoCompat#setFocusable(boolean)}
-     * <li>item class name, set to {@code android.view.View}, see
-     * {@link AccessibilityNodeInfoCompat#setClassName(CharSequence)}
-     * </ul>
-     * <p>
-     * The following required fields are automatically populated by the
-     * helper class and may not be overridden:
-     * <ul>
-     * <li>package name, identical to the package name set by
-     * {@link #onPopulateEventForVirtualView(int, AccessibilityEvent)}, see
-     * {@link AccessibilityNodeInfoCompat#setPackageName}
-     * <li>node source, identical to the event source set in
-     * {@link #onPopulateEventForVirtualView(int, AccessibilityEvent)}, see
-     * {@link AccessibilityNodeInfoCompat#setSource(View, int)}
-     * <li>parent view, set to the host view, see
-     * {@link AccessibilityNodeInfoCompat#setParent(View)}
-     * <li>visibility, computed based on parent-relative bounds, see
-     * {@link AccessibilityNodeInfoCompat#setVisibleToUser(boolean)}
-     * <li>accessibility focus, computed based on internal helper state, see
-     * {@link AccessibilityNodeInfoCompat#setAccessibilityFocused(boolean)}
-     * <li>keyboard focus, computed based on internal helper state, see
-     * {@link AccessibilityNodeInfoCompat#setFocused(boolean)}
-     * <li>bounds in screen coordinates, computed based on host view bounds,
-     * see {@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
-     * </ul>
-     * <p>
-     * Additionally, the helper class automatically handles keyboard focus and
-     * accessibility focus management by adding the appropriate
-     * {@link AccessibilityNodeInfoCompat#ACTION_FOCUS},
-     * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_FOCUS},
-     * {@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS}, or
-     * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS}
-     * actions. Implementations must <strong>never</strong> manually add these
-     * actions.
-     * <p>
-     * The helper class also automatically modifies parent- and
-     * screen-relative bounds to reflect the portion of the item visible
-     * within its parent.
-     *
-     * @param virtualViewId The virtual view identifier of the item for
-     *            which to populate the node
-     * @param node The node to populate
-     */
-    protected abstract void onPopulateNodeForVirtualView(
-            int virtualViewId, @NonNull AccessibilityNodeInfoCompat node);
-
-    /**
-     * Populates an {@link AccessibilityNodeInfoCompat} with information
-     * about the host view.
-     * <p>
-     * The default implementation is a no-op.
-     *
-     * @param node the node to populate with information about the host view
-     */
-    protected void onPopulateNodeForHost(@NonNull AccessibilityNodeInfoCompat node) {
-        // Default implementation is no-op.
-    }
-
-    /**
-     * Performs the specified accessibility action on the item associated
-     * with the virtual view identifier. See
-     * {@link AccessibilityNodeInfoCompat#performAction(int, Bundle)} for
-     * more information.
-     * <p>
-     * Implementations <strong>must</strong> handle any actions added manually
-     * in
-     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}.
-     * <p>
-     * The helper class automatically handles focus management resulting
-     * from {@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS}
-     * and
-     * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS}
-     * actions.
-     *
-     * @param virtualViewId The virtual view identifier of the item on which
-     *            to perform the action
-     * @param action The accessibility action to perform
-     * @param arguments (Optional) A bundle with additional arguments, or
-     *            null
-     * @return true if the action was performed
-     */
-    protected abstract boolean onPerformActionForVirtualView(
-            int virtualViewId, int action, @Nullable Bundle arguments);
-
-    /**
-     * Exposes a virtual view hierarchy to the accessibility framework.
-     */
-    private class MyNodeProvider extends AccessibilityNodeProviderCompat {
-        MyNodeProvider() {
-        }
-
-        @Override
-        public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) {
-            // The caller takes ownership of the node and is expected to
-            // recycle it when done, so always return a copy.
-            final AccessibilityNodeInfoCompat node =
-                    ExploreByTouchHelper.this.obtainAccessibilityNodeInfo(virtualViewId);
-            return AccessibilityNodeInfoCompat.obtain(node);
-        }
-
-        @Override
-        public boolean performAction(int virtualViewId, int action, Bundle arguments) {
-            return ExploreByTouchHelper.this.performAction(virtualViewId, action, arguments);
-        }
-
-        @Override
-        public AccessibilityNodeInfoCompat findFocus(int focusType) {
-            int focusedId = (focusType == AccessibilityNodeInfoCompat.FOCUS_ACCESSIBILITY) ?
-                    mAccessibilityFocusedVirtualViewId : mKeyboardFocusedVirtualViewId;
-            if (focusedId == INVALID_ID) {
-                return null;
-            }
-            return createAccessibilityNodeInfo(focusedId);
-        }
-    }
-}
diff --git a/core-ui/src/main/java/android/support/v4/widget/FocusStrategy.java b/core-ui/src/main/java/android/support/v4/widget/FocusStrategy.java
deleted file mode 100644
index 77353c5..0000000
--- a/core-ui/src/main/java/android/support/v4/widget/FocusStrategy.java
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.view.View;
-
-import android.support.v4.view.ViewCompat.FocusRealDirection;
-import android.support.v4.view.ViewCompat.FocusRelativeDirection;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-/**
- * Implements absolute and relative focus movement strategies. Adapted from
- * android.view.FocusFinder to work with generic collections of bounded items.
- */
-class FocusStrategy {
-    public static <L, T> T findNextFocusInRelativeDirection(@NonNull L focusables,
-            @NonNull CollectionAdapter<L, T> collectionAdapter, @NonNull BoundsAdapter<T> adapter,
-            @Nullable T focused, @FocusRelativeDirection int direction, boolean isLayoutRtl,
-            boolean wrap) {
-        final int count = collectionAdapter.size(focusables);
-        final ArrayList<T> sortedFocusables = new ArrayList<>(count);
-        for (int i = 0; i < count; i++) {
-            sortedFocusables.add(collectionAdapter.get(focusables, i));
-        }
-
-        final SequentialComparator<T> comparator = new SequentialComparator<>(isLayoutRtl, adapter);
-        Collections.sort(sortedFocusables, comparator);
-
-        switch (direction) {
-            case View.FOCUS_FORWARD:
-                return getNextFocusable(focused, sortedFocusables, wrap);
-            case View.FOCUS_BACKWARD:
-                return getPreviousFocusable(focused, sortedFocusables, wrap);
-            default:
-                throw new IllegalArgumentException("direction must be one of "
-                        + "{FOCUS_FORWARD, FOCUS_BACKWARD}.");
-        }
-    }
-
-    private static <T> T getNextFocusable(T focused, ArrayList<T> focusables, boolean wrap) {
-        final int count = focusables.size();
-
-        // The position of the next focusable item, which is the first item if
-        // no item is currently focused.
-        final int position = (focused == null ? -1 : focusables.lastIndexOf(focused)) + 1;
-        if (position < count) {
-            return focusables.get(position);
-        } else if (wrap && count > 0) {
-            return focusables.get(0);
-        } else {
-            return null;
-        }
-    }
-
-    private static <T> T getPreviousFocusable(T focused, ArrayList<T> focusables, boolean wrap) {
-        final int count = focusables.size();
-
-        // The position of the previous focusable item, which is the last item
-        // if no item is currently focused.
-        final int position = (focused == null ? count : focusables.indexOf(focused)) - 1;
-        if (position >= 0) {
-            return focusables.get(position);
-        } else if (wrap && count > 0) {
-            return focusables.get(count - 1);
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Sorts views according to their visual layout and geometry for default tab order.
-     * This is used for sequential focus traversal.
-     */
-    private static class SequentialComparator<T> implements Comparator<T> {
-        private final Rect mTemp1 = new Rect();
-        private final Rect mTemp2 = new Rect();
-
-        private final boolean mIsLayoutRtl;
-        private final BoundsAdapter<T> mAdapter;
-
-        SequentialComparator(boolean isLayoutRtl, BoundsAdapter<T> adapter) {
-            mIsLayoutRtl = isLayoutRtl;
-            mAdapter = adapter;
-        }
-
-        @Override
-        public int compare(T first, T second) {
-            final Rect firstRect = mTemp1;
-            final Rect secondRect = mTemp2;
-
-            mAdapter.obtainBounds(first, firstRect);
-            mAdapter.obtainBounds(second, secondRect);
-
-            if (firstRect.top < secondRect.top) {
-                return -1;
-            } else if (firstRect.top > secondRect.top) {
-                return 1;
-            } else if (firstRect.left < secondRect.left) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (firstRect.left > secondRect.left) {
-                return mIsLayoutRtl ? -1 : 1;
-            } else if (firstRect.bottom < secondRect.bottom) {
-                return -1;
-            } else if (firstRect.bottom > secondRect.bottom) {
-                return 1;
-            } else if (firstRect.right < secondRect.right) {
-                return mIsLayoutRtl ? 1 : -1;
-            } else if (firstRect.right > secondRect.right) {
-                return mIsLayoutRtl ? -1 : 1;
-            } else {
-                // The view are distinct but completely coincident so we
-                // consider them equal for our purposes. Since the sort is
-                // stable, this means that the views will retain their
-                // layout order relative to one another.
-                return 0;
-            }
-        }
-    }
-
-    public static <L, T> T findNextFocusInAbsoluteDirection(@NonNull L focusables,
-            @NonNull CollectionAdapter<L, T> collectionAdapter, @NonNull BoundsAdapter<T> adapter,
-            @Nullable T focused, @NonNull Rect focusedRect, int direction) {
-        // Initialize the best candidate to something impossible so that
-        // the first plausible view will become the best choice.
-        final Rect bestCandidateRect = new Rect(focusedRect);
-
-        switch (direction) {
-            case View.FOCUS_LEFT:
-                bestCandidateRect.offset(focusedRect.width() + 1, 0);
-                break;
-            case View.FOCUS_RIGHT:
-                bestCandidateRect.offset(-(focusedRect.width() + 1), 0);
-                break;
-            case View.FOCUS_UP:
-                bestCandidateRect.offset(0, focusedRect.height() + 1);
-                break;
-            case View.FOCUS_DOWN:
-                bestCandidateRect.offset(0, -(focusedRect.height() + 1));
-                break;
-            default:
-                throw new IllegalArgumentException("direction must be one of "
-                        + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-        }
-
-        T closest = null;
-
-        final int count = collectionAdapter.size(focusables);
-        final Rect focusableRect = new Rect();
-        for (int i = 0; i < count; i++) {
-            final T focusable = collectionAdapter.get(focusables, i);
-            if (focusable == focused) {
-                continue;
-            }
-
-            // get focus bounds of other view
-            adapter.obtainBounds(focusable, focusableRect);
-            if (isBetterCandidate(direction, focusedRect, focusableRect, bestCandidateRect)) {
-                bestCandidateRect.set(focusableRect);
-                closest = focusable;
-            }
-        }
-
-        return closest;
-    }
-
-    /**
-     * Is candidate a better candidate than currentBest for a focus search
-     * in a particular direction from a source rect? This is the core
-     * routine that determines the order of focus searching.
-     *
-     * @param direction   the direction (up, down, left, right)
-     * @param source      the source from which we are searching
-     * @param candidate   the candidate rectangle
-     * @param currentBest the current best rectangle
-     * @return {@code true} if the candidate rectangle is a better than the
-     * current best rectangle, {@code false} otherwise
-     */
-    private static boolean isBetterCandidate(
-            @FocusRealDirection int direction, @NonNull Rect source,
-            @NonNull Rect candidate, @NonNull Rect currentBest) {
-        // To be a better candidate, need to at least be a candidate in the
-        // first place. :)
-        if (!isCandidate(source, candidate, direction)) {
-            return false;
-        }
-
-        // We know that candidateRect is a candidate. If currentBest is not
-        // a candidate, candidateRect is better.
-        if (!isCandidate(source, currentBest, direction)) {
-            return true;
-        }
-
-        // If candidateRect is better by beam, it wins.
-        if (beamBeats(direction, source, candidate, currentBest)) {
-            return true;
-        }
-
-        // If currentBest is better, then candidateRect cant' be. :)
-        if (beamBeats(direction, source, currentBest, candidate)) {
-            return false;
-        }
-
-        // Otherwise, do fudge-tastic comparison of the major and minor
-        // axis.
-        final int candidateDist = getWeightedDistanceFor(
-                majorAxisDistance(direction, source, candidate),
-                minorAxisDistance(direction, source, candidate));
-        final int currentBestDist = getWeightedDistanceFor(
-                majorAxisDistance(direction, source, currentBest),
-                minorAxisDistance(direction, source, currentBest));
-        return candidateDist < currentBestDist;
-    }
-
-    /**
-     * One rectangle may be another candidate than another by virtue of
-     * being exclusively in the beam of the source rect.
-     *
-     * @return whether rect1 is a better candidate than rect2 by virtue of
-     * it being in source's beam
-     */
-    private static boolean beamBeats(@FocusRealDirection int direction,
-            @NonNull Rect source, @NonNull Rect rect1, @NonNull Rect rect2) {
-        final boolean rect1InSrcBeam = beamsOverlap(direction, source, rect1);
-        final boolean rect2InSrcBeam = beamsOverlap(direction, source, rect2);
-
-        // If rect1 isn't exclusively in the src beam, it doesn't win.
-        if (rect2InSrcBeam || !rect1InSrcBeam) {
-            return false;
-        }
-
-        // We know rect1 is in the beam, and rect2 is not.
-
-        // If rect1 is to the direction of, and rect2 is not, rect1 wins.
-        // For example, for direction left, if rect1 is to the left of the
-        // source and rect2 is below, then we always prefer the in beam
-        // rect1, since rect2 could be reached by going down.
-        if (!isToDirectionOf(direction, source, rect2)) {
-            return true;
-        }
-
-        // For horizontal directions, being exclusively in beam always
-        // wins.
-        if (direction == View.FOCUS_LEFT || direction == View.FOCUS_RIGHT) {
-            return true;
-        }
-
-        // For vertical directions, beams only beat up to a point: now, as
-        // long as rect2 isn't completely closer, rect1 wins, e.g. for
-        // direction down, completely closer means for rect2's top edge to
-        // be closer to the source's top edge than rect1's bottom edge.
-        return majorAxisDistance(direction, source, rect1)
-                < majorAxisDistanceToFarEdge(direction, source, rect2);
-    }
-
-    /**
-     * Fudge-factor opportunity: how to calculate distance given major and
-     * minor axis distances.
-     * <p/>
-     * Warning: this fudge factor is finely tuned, be sure to run all focus
-     * tests if you dare tweak it.
-     */
-    private static int getWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance) {
-        return 13 * majorAxisDistance * majorAxisDistance
-                + minorAxisDistance * minorAxisDistance;
-    }
-
-    /**
-     * Is destRect a candidate for the next focus given the direction? This
-     * checks whether the dest is at least partially to the direction of
-     * (e.g. left of) from source.
-     * <p/>
-     * Includes an edge case for an empty rect,which is used in some cases
-     * when searching from a point on the screen.
-     */
-    private static boolean isCandidate(@NonNull Rect srcRect, @NonNull Rect destRect,
-            @FocusRealDirection int direction) {
-        switch (direction) {
-            case View.FOCUS_LEFT:
-                return (srcRect.right > destRect.right || srcRect.left >= destRect.right)
-                        && srcRect.left > destRect.left;
-            case View.FOCUS_RIGHT:
-                return (srcRect.left < destRect.left || srcRect.right <= destRect.left)
-                        && srcRect.right < destRect.right;
-            case View.FOCUS_UP:
-                return (srcRect.bottom > destRect.bottom || srcRect.top >= destRect.bottom)
-                        && srcRect.top > destRect.top;
-            case View.FOCUS_DOWN:
-                return (srcRect.top < destRect.top || srcRect.bottom <= destRect.top)
-                        && srcRect.bottom < destRect.bottom;
-        }
-        throw new IllegalArgumentException("direction must be one of "
-                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-    }
-
-
-    /**
-     * Do the "beams" w.r.t the given direction's axis of rect1 and rect2 overlap?
-     *
-     * @param direction the direction (up, down, left, right)
-     * @param rect1     the first rectangle
-     * @param rect2     the second rectangle
-     * @return whether the beams overlap
-     */
-    private static boolean beamsOverlap(@FocusRealDirection int direction,
-            @NonNull Rect rect1, @NonNull Rect rect2) {
-        switch (direction) {
-            case View.FOCUS_LEFT:
-            case View.FOCUS_RIGHT:
-                return (rect2.bottom >= rect1.top) && (rect2.top <= rect1.bottom);
-            case View.FOCUS_UP:
-            case View.FOCUS_DOWN:
-                return (rect2.right >= rect1.left) && (rect2.left <= rect1.right);
-        }
-        throw new IllegalArgumentException("direction must be one of "
-                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-    }
-
-    /**
-     * e.g for left, is 'to left of'
-     */
-    private static boolean isToDirectionOf(@FocusRealDirection int direction,
-            @NonNull Rect src, @NonNull Rect dest) {
-        switch (direction) {
-            case View.FOCUS_LEFT:
-                return src.left >= dest.right;
-            case View.FOCUS_RIGHT:
-                return src.right <= dest.left;
-            case View.FOCUS_UP:
-                return src.top >= dest.bottom;
-            case View.FOCUS_DOWN:
-                return src.bottom <= dest.top;
-        }
-        throw new IllegalArgumentException("direction must be one of "
-                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-    }
-
-    /**
-     * @return the distance from the edge furthest in the given direction
-     * of source to the edge nearest in the given direction of
-     * dest. If the dest is not in the direction from source,
-     * returns 0.
-     */
-    private static int majorAxisDistance(@FocusRealDirection int direction,
-            @NonNull Rect source, @NonNull Rect dest) {
-        return Math.max(0, majorAxisDistanceRaw(direction, source, dest));
-    }
-
-    private static int majorAxisDistanceRaw(@FocusRealDirection int direction,
-            @NonNull Rect source, @NonNull Rect dest) {
-        switch (direction) {
-            case View.FOCUS_LEFT:
-                return source.left - dest.right;
-            case View.FOCUS_RIGHT:
-                return dest.left - source.right;
-            case View.FOCUS_UP:
-                return source.top - dest.bottom;
-            case View.FOCUS_DOWN:
-                return dest.top - source.bottom;
-        }
-        throw new IllegalArgumentException("direction must be one of "
-                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-    }
-
-    /**
-     * @return the distance along the major axis w.r.t the direction from
-     * the edge of source to the far edge of dest. If the dest is
-     * not in the direction from source, returns 1 to break ties
-     * with {@link #majorAxisDistance}.
-     */
-    private static int majorAxisDistanceToFarEdge(@FocusRealDirection int direction,
-            @NonNull Rect source, @NonNull Rect dest) {
-        return Math.max(1, majorAxisDistanceToFarEdgeRaw(direction, source, dest));
-    }
-
-    private static int majorAxisDistanceToFarEdgeRaw(
-            @FocusRealDirection int direction, @NonNull Rect source,
-            @NonNull Rect dest) {
-        switch (direction) {
-            case View.FOCUS_LEFT:
-                return source.left - dest.left;
-            case View.FOCUS_RIGHT:
-                return dest.right - source.right;
-            case View.FOCUS_UP:
-                return source.top - dest.top;
-            case View.FOCUS_DOWN:
-                return dest.bottom - source.bottom;
-        }
-        throw new IllegalArgumentException("direction must be one of "
-                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-    }
-
-    /**
-     * Finds the distance on the minor axis w.r.t the direction to the
-     * nearest edge of the destination rectangle.
-     *
-     * @param direction the direction (up, down, left, right)
-     * @param source the source rect
-     * @param dest the destination rect
-     * @return the distance
-     */
-    private static int minorAxisDistance(@FocusRealDirection int direction, @NonNull Rect source,
-            @NonNull Rect dest) {
-        switch (direction) {
-            case View.FOCUS_LEFT:
-            case View.FOCUS_RIGHT:
-                // the distance between the center verticals
-                return Math.abs(
-                        ((source.top + source.height() / 2) - ((dest.top + dest.height() / 2))));
-            case View.FOCUS_UP:
-            case View.FOCUS_DOWN:
-                // the distance between the center horizontals
-                return Math.abs(
-                        ((source.left + source.width() / 2) -
-                                ((dest.left + dest.width() / 2))));
-        }
-        throw new IllegalArgumentException("direction must be one of "
-                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
-    }
-
-    /**
-     * Adapter used to obtain bounds from a generic data type.
-     */
-    public interface BoundsAdapter<T> {
-        void obtainBounds(T data, Rect outBounds);
-    }
-
-    /**
-     * Adapter used to obtain items from a generic collection type.
-     */
-    public interface CollectionAdapter<T, V> {
-        V get(T collection, int index);
-        int size(T collection);
-    }
-}
diff --git a/core-ui/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java b/core-ui/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java
deleted file mode 100644
index 8a0136a..0000000
--- a/core-ui/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.LayoutInflater;
-
-/**
- * Static library support version of the framework's {@link android.widget.ResourceCursorAdapter}.
- * Used to write apps that run on platforms prior to Android 3.0.  When running
- * on Android 3.0 or above, this implementation is still used; it does not try
- * to switch to the framework's implementation.  See the framework SDK
- * documentation for a class overview.
- */
-public abstract class ResourceCursorAdapter extends CursorAdapter {
-    private int mLayout;
-
-    private int mDropDownLayout;
-
-    private LayoutInflater mInflater;
-
-    /**
-     * Constructor the enables auto-requery.
-     *
-     * @deprecated This option is discouraged, as it results in Cursor queries
-     * being performed on the application's UI thread and thus can cause poor
-     * responsiveness or even Application Not Responding errors.  As an alternative,
-     * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
-     *
-     * @param context The context where the ListView associated with this adapter is running
-     * @param layout resource identifier of a layout file that defines the views
-     *            for this list item.  Unless you override them later, this will
-     *            define both the item views and the drop down views.
-     */
-    @Deprecated
-    public ResourceCursorAdapter(Context context, int layout, Cursor c) {
-        super(context, c);
-        mLayout = mDropDownLayout = layout;
-        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    }
-
-    /**
-     * Constructor with default behavior as per
-     * {@link CursorAdapter#CursorAdapter(Context, Cursor, boolean)}; it is recommended
-     * you not use this, but instead {@link #ResourceCursorAdapter(Context, int, Cursor, int)}.
-     * When using this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER}
-     * will always be set.
-     *
-     * @deprecated This option is discouraged, as it results in Cursor queries
-     * being performed on the application's UI thread and thus can cause poor
-     * responsiveness or even Application Not Responding errors.  As an alternative,
-     * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
-     *
-     * @param context The context where the ListView associated with this adapter is running
-     * @param layout resource identifier of a layout file that defines the views
-     *            for this list item.  Unless you override them later, this will
-     *            define both the item views and the drop down views.
-     * @param c The cursor from which to get the data.
-     * @param autoRequery If true the adapter will call requery() on the
-     *                    cursor whenever it changes so the most recent
-     *                    data is always displayed.  Using true here is discouraged.
-     */
-    @Deprecated
-    public ResourceCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) {
-        super(context, c, autoRequery);
-        mLayout = mDropDownLayout = layout;
-        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    }
-
-    /**
-     * Standard constructor.
-     *
-     * @param context The context where the ListView associated with this adapter is running
-     * @param layout Resource identifier of a layout file that defines the views
-     *            for this list item.  Unless you override them later, this will
-     *            define both the item views and the drop down views.
-     * @param c The cursor from which to get the data.
-     * @param flags Flags used to determine the behavior of the adapter,
-     * as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}.
-     */
-    public ResourceCursorAdapter(Context context, int layout, Cursor c, int flags) {
-        super(context, c, flags);
-        mLayout = mDropDownLayout = layout;
-        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    }
-
-    /**
-     * Inflates view(s) from the specified XML file.
-     *
-     * @see android.widget.CursorAdapter#newView(android.content.Context,
-     *      android.database.Cursor, ViewGroup)
-     */
-    @Override
-    public View newView(Context context, Cursor cursor, ViewGroup parent) {
-        return mInflater.inflate(mLayout, parent, false);
-    }
-
-    @Override
-    public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
-        return mInflater.inflate(mDropDownLayout, parent, false);
-    }
-
-    /**
-     * <p>Sets the layout resource of the item views.</p>
-     *
-     * @param layout the layout resources used to create item views
-     */
-    public void setViewResource(int layout) {
-        mLayout = layout;
-    }
-
-    /**
-     * <p>Sets the layout resource of the drop down views.</p>
-     *
-     * @param dropDownLayout the layout resources used to create drop down views
-     */
-    public void setDropDownViewResource(int dropDownLayout) {
-        mDropDownLayout = dropDownLayout;
-    }
-}
diff --git a/core-ui/tests/AndroidManifest.xml b/core-ui/tests/AndroidManifest.xml
deleted file mode 100644
index 4ea7691..0000000
--- a/core-ui/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.coreui.test">
-    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
-    <uses-permission android:name="android.permission.VIBRATE"/>
-    <uses-permission android:name="android.permission.WAKE_LOCK"/>
-    <uses-permission android:name="android.permission.READ_CONTACTS"/>
-    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
-
-    <application
-        android:supportsRtl="true"
-        android:theme="@style/TestActivityTheme">
-        <activity android:name="android.support.v4.widget.ExploreByTouchHelperTestActivity"/>
-
-        <activity android:name="android.support.v4.widget.CircularProgressDrawableActivity"/>
-
-        <activity android:name="android.support.v4.widget.SwipeRefreshLayoutActivity"/>
-
-        <activity android:name="android.support.v4.widget.ContentLoadingProgressBarActivity"/>
-
-        <activity android:name="android.support.v4.view.ViewPagerWithTitleStripActivity"/>
-
-        <activity android:name="android.support.v4.view.ViewPagerWithTabStripActivity"/>
-
-        <activity android:name="android.support.v4.view.ViewPagerTest$ViewPagerActivity"/>
-
-        <activity android:name="android.support.design.widget.CoordinatorLayoutActivity"/>
-
-        <activity android:name="android.support.design.widget.DynamicCoordinatorLayoutActivity"/>
-
-    </application>
-
-</manifest>
diff --git a/core-ui/tests/NO_DOCS b/core-ui/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/core-ui/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/core-ui/tests/java/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java b/core-ui/tests/java/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java
deleted file mode 100755
index 5c79b21..0000000
--- a/core-ui/tests/java/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.Matchers.any;
-
-import android.support.annotation.LayoutRes;
-import android.support.coreui.test.R;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-import android.view.ViewStub;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
-
-/**
- * Base class for tests that are exercising various aspects of {@link CoordinatorLayout}.
- */
-public abstract class BaseDynamicCoordinatorLayoutTest
-        extends BaseInstrumentationTestCase<DynamicCoordinatorLayoutActivity> {
-    protected CoordinatorLayout mCoordinatorLayout;
-
-    public BaseDynamicCoordinatorLayoutTest() {
-        super(DynamicCoordinatorLayoutActivity.class);
-    }
-
-    @UiThreadTest
-    @After
-    public void tearDown() {
-        // Now that the test is done, replace the activity content view with ViewStub so
-        // that it's ready to be replaced for the next test.
-        final DynamicCoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        activity.setContentView(R.layout.dynamic_coordinator_layout);
-        mCoordinatorLayout = null;
-    }
-
-    /**
-     * Matches views that have parents.
-     */
-    private Matcher<View> hasParent() {
-        return new TypeSafeMatcher<View>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("has parent");
-            }
-
-            @Override
-            public boolean matchesSafely(View view) {
-                return view.getParent() != null;
-            }
-        };
-    }
-
-    /**
-     * Inflates the <code>ViewStub</code> with the passed layout resource.
-     */
-    protected ViewAction inflateViewStub(final @LayoutRes int layoutResId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return allOf(isAssignableFrom(ViewStub.class), hasParent());
-            }
-
-            @Override
-            public String getDescription() {
-                return "Inflates view stub";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewStub viewStub = (ViewStub) view;
-                viewStub.setLayoutResource(layoutResId);
-                viewStub.inflate();
-
-                mCoordinatorLayout = (CoordinatorLayout) mActivityTestRule.getActivity()
-                        .findViewById(viewStub.getInflatedId());
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    protected ViewAction setLayoutDirection(final int layoutDir) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return any(View.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets layout direction";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewCompat.setLayoutDirection(view, layoutDir);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-}
diff --git a/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutActivity.java b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutActivity.java
deleted file mode 100644
index b7fe740..0000000
--- a/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutActivity.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.coreui.test.R;
-import android.support.v4.BaseTestActivity;
-import android.widget.FrameLayout;
-
-public class CoordinatorLayoutActivity extends BaseTestActivity {
-
-    FrameLayout mContainer;
-    CoordinatorLayout mCoordinatorLayout;
-
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.activity_coordinator_layout;
-    }
-
-    @Override
-    protected void onContentViewSet() {
-        mContainer = findViewById(R.id.container);
-        mCoordinatorLayout = findViewById(R.id.coordinator);
-    }
-
-}
diff --git a/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutTest.java b/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutTest.java
deleted file mode 100644
index 9b4c586..0000000
--- a/core-ui/tests/java/android/support/design/widget/CoordinatorLayoutTest.java
+++ /dev/null
@@ -1,781 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.swipeUp;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.same;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doCallRealMethod;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.Instrumentation;
-import android.content.Context;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.coreui.test.R;
-import android.support.design.testutils.CoordinatorLayoutUtils;
-import android.support.design.testutils.CoordinatorLayoutUtils.DependentBehavior;
-import android.support.design.widget.CoordinatorLayout.Behavior;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.widget.ImageView;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class CoordinatorLayoutTest {
-    @Rule
-    public final ActivityTestRule<CoordinatorLayoutActivity> mActivityTestRule;
-
-    private Instrumentation mInstrumentation;
-
-    public CoordinatorLayoutTest() {
-        mActivityTestRule = new ActivityTestRule<>(CoordinatorLayoutActivity.class);
-    }
-
-    @Before
-    public void setup() {
-        mInstrumentation = getInstrumentation();
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 21)
-    public void testSetFitSystemWindows() throws Throwable {
-        final Instrumentation instrumentation = getInstrumentation();
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-        final View view = new View(col.getContext());
-
-        // Create a mock which calls the default impl of onApplyWindowInsets()
-        final CoordinatorLayout.Behavior<View> mockBehavior =
-                mock(CoordinatorLayout.Behavior.class);
-        doCallRealMethod().when(mockBehavior)
-                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
-
-        // Assert that the CoL is currently not set to fitSystemWindows
-        assertFalse(col.getFitsSystemWindows());
-
-        // Now add a view with our mocked behavior to the CoordinatorLayout
-        view.setFitsSystemWindows(true);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
-                lp.setBehavior(mockBehavior);
-                col.addView(view, lp);
-            }
-        });
-        instrumentation.waitForIdleSync();
-
-        // Now request some insets and wait for the pass to happen
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.requestApplyInsets();
-            }
-        });
-        instrumentation.waitForIdleSync();
-
-        // Verify that onApplyWindowInsets() has not been called
-        verify(mockBehavior, never())
-                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
-
-        // Now enable fits system windows and wait for a pass to happen
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.setFitsSystemWindows(true);
-            }
-        });
-        instrumentation.waitForIdleSync();
-
-        // Verify that onApplyWindowInsets() has been called with some insets
-        verify(mockBehavior, atLeastOnce())
-                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
-    }
-
-    @Test
-    public void testLayoutChildren() throws Throwable {
-        final Instrumentation instrumentation = getInstrumentation();
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-        final View view = new View(col.getContext());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.addView(view, 100, 100);
-            }
-        });
-        instrumentation.waitForIdleSync();
-        int horizontallyCentered = (col.getWidth() - view.getWidth()) / 2;
-        int end = col.getWidth() - view.getWidth();
-        int verticallyCentered = (col.getHeight() - view.getHeight()) / 2;
-        int bottom = col.getHeight() - view.getHeight();
-        final int[][] testCases = {
-                // gravity, expected left, expected top
-                {Gravity.NO_GRAVITY, 0, 0},
-                {Gravity.LEFT, 0, 0},
-                {GravityCompat.START, 0, 0},
-                {Gravity.TOP, 0, 0},
-                {Gravity.CENTER, horizontallyCentered, verticallyCentered},
-                {Gravity.CENTER_HORIZONTAL, horizontallyCentered, 0},
-                {Gravity.CENTER_VERTICAL, 0, verticallyCentered},
-                {Gravity.RIGHT, end, 0},
-                {GravityCompat.END, end, 0},
-                {Gravity.BOTTOM, 0, bottom},
-                {Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, horizontallyCentered, bottom},
-                {Gravity.RIGHT | Gravity.CENTER_VERTICAL, end, verticallyCentered},
-        };
-        for (final int[] testCase : testCases) {
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    final CoordinatorLayout.LayoutParams lp =
-                            (CoordinatorLayout.LayoutParams) view.getLayoutParams();
-                    lp.gravity = testCase[0];
-                    view.setLayoutParams(lp);
-                }
-            });
-            instrumentation.waitForIdleSync();
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    assertThat("Gravity: " + testCase[0], view.getLeft(), is(testCase[1]));
-                    assertThat("Gravity: " + testCase[0], view.getTop(), is(testCase[2]));
-                }
-            });
-        }
-    }
-
-    @Test
-    public void testInsetDependency() {
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        final CoordinatorLayout.LayoutParams lpInsetLeft = col.generateDefaultLayoutParams();
-        lpInsetLeft.insetEdge = Gravity.LEFT;
-
-        final CoordinatorLayout.LayoutParams lpInsetRight = col.generateDefaultLayoutParams();
-        lpInsetRight.insetEdge = Gravity.RIGHT;
-
-        final CoordinatorLayout.LayoutParams lpInsetTop = col.generateDefaultLayoutParams();
-        lpInsetTop.insetEdge = Gravity.TOP;
-
-        final CoordinatorLayout.LayoutParams lpInsetBottom = col.generateDefaultLayoutParams();
-        lpInsetBottom.insetEdge = Gravity.BOTTOM;
-
-        final CoordinatorLayout.LayoutParams lpDodgeLeft = col.generateDefaultLayoutParams();
-        lpDodgeLeft.dodgeInsetEdges = Gravity.LEFT;
-
-        final CoordinatorLayout.LayoutParams lpDodgeLeftAndTop = col.generateDefaultLayoutParams();
-        lpDodgeLeftAndTop.dodgeInsetEdges = Gravity.LEFT | Gravity.TOP;
-
-        final CoordinatorLayout.LayoutParams lpDodgeAll = col.generateDefaultLayoutParams();
-        lpDodgeAll.dodgeInsetEdges = Gravity.FILL;
-
-        final View a = new View(col.getContext());
-        final View b = new View(col.getContext());
-
-        assertThat(dependsOn(lpDodgeLeft, lpInsetLeft, col, a, b), is(true));
-        assertThat(dependsOn(lpDodgeLeft, lpInsetRight, col, a, b), is(false));
-        assertThat(dependsOn(lpDodgeLeft, lpInsetTop, col, a, b), is(false));
-        assertThat(dependsOn(lpDodgeLeft, lpInsetBottom, col, a, b), is(false));
-
-        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetLeft, col, a, b), is(true));
-        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetRight, col, a, b), is(false));
-        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetTop, col, a, b), is(true));
-        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetBottom, col, a, b), is(false));
-
-        assertThat(dependsOn(lpDodgeAll, lpInsetLeft, col, a, b), is(true));
-        assertThat(dependsOn(lpDodgeAll, lpInsetRight, col, a, b), is(true));
-        assertThat(dependsOn(lpDodgeAll, lpInsetTop, col, a, b), is(true));
-        assertThat(dependsOn(lpDodgeAll, lpInsetBottom, col, a, b), is(true));
-
-        assertThat(dependsOn(lpInsetLeft, lpDodgeLeft, col, a, b), is(false));
-    }
-
-    private static boolean dependsOn(CoordinatorLayout.LayoutParams lpChild,
-            CoordinatorLayout.LayoutParams lpDependency, CoordinatorLayout col,
-            View child, View dependency) {
-        child.setLayoutParams(lpChild);
-        dependency.setLayoutParams(lpDependency);
-        return lpChild.dependsOn(col, child, dependency);
-    }
-
-    @Test
-    public void testInsetEdge() throws Throwable {
-        final Instrumentation instrumentation = getInstrumentation();
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        final View insetView = new View(col.getContext());
-        final View dodgeInsetView = new View(col.getContext());
-        final AtomicInteger originalTop = new AtomicInteger();
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                CoordinatorLayout.LayoutParams lpInsetView = col.generateDefaultLayoutParams();
-                lpInsetView.width = CoordinatorLayout.LayoutParams.MATCH_PARENT;
-                lpInsetView.height = 100;
-                lpInsetView.gravity = Gravity.TOP | Gravity.LEFT;
-                lpInsetView.insetEdge = Gravity.TOP;
-                col.addView(insetView, lpInsetView);
-                insetView.setBackgroundColor(0xFF0000FF);
-
-                CoordinatorLayout.LayoutParams lpDodgeInsetView = col.generateDefaultLayoutParams();
-                lpDodgeInsetView.width = 100;
-                lpDodgeInsetView.height = 100;
-                lpDodgeInsetView.gravity = Gravity.TOP | Gravity.LEFT;
-                lpDodgeInsetView.dodgeInsetEdges = Gravity.TOP;
-                col.addView(dodgeInsetView, lpDodgeInsetView);
-                dodgeInsetView.setBackgroundColor(0xFFFF0000);
-            }
-        });
-        instrumentation.waitForIdleSync();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                List<View> dependencies = col.getDependencies(dodgeInsetView);
-                assertThat(dependencies.size(), is(1));
-                assertThat(dependencies.get(0), is(insetView));
-
-                // Move the insetting view
-                originalTop.set(dodgeInsetView.getTop());
-                assertThat(originalTop.get(), is(insetView.getBottom()));
-                ViewCompat.offsetTopAndBottom(insetView, 123);
-            }
-        });
-        instrumentation.waitForIdleSync();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Confirm that the dodging view was moved by the same size
-                assertThat(dodgeInsetView.getTop() - originalTop.get(), is(123));
-            }
-        });
-    }
-
-    @Test
-    public void testDependentViewChanged() throws Throwable {
-        final Instrumentation instrumentation = getInstrumentation();
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        // Add two views, A & B, where B depends on A
-        final View viewA = new View(col.getContext());
-        final CoordinatorLayout.LayoutParams lpA = col.generateDefaultLayoutParams();
-        lpA.width = 100;
-        lpA.height = 100;
-
-        final View viewB = new View(col.getContext());
-        final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
-        lpB.width = 100;
-        lpB.height = 100;
-        final CoordinatorLayout.Behavior behavior =
-                spy(new DependentBehavior(viewA));
-        lpB.setBehavior(behavior);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.addView(viewA, lpA);
-                col.addView(viewB, lpB);
-            }
-        });
-        instrumentation.waitForIdleSync();
-
-        // Reset the Behavior since onDependentViewChanged may have already been called as part of
-        // any layout/draw passes already
-        reset(behavior);
-
-        // Now offset view A
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ViewCompat.offsetLeftAndRight(viewA, 20);
-                ViewCompat.offsetTopAndBottom(viewA, 20);
-            }
-        });
-        instrumentation.waitForIdleSync();
-
-        // And assert that view B's Behavior was called appropriately
-        verify(behavior, times(1)).onDependentViewChanged(col, viewB, viewA);
-    }
-
-    @Test
-    public void testDependentViewRemoved() throws Throwable {
-        final Instrumentation instrumentation = getInstrumentation();
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        // Add two views, A & B, where B depends on A
-        final View viewA = new View(col.getContext());
-        final View viewB = new View(col.getContext());
-        final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
-        final CoordinatorLayout.Behavior behavior =
-                spy(new DependentBehavior(viewA));
-        lpB.setBehavior(behavior);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.addView(viewA);
-                col.addView(viewB, lpB);
-            }
-        });
-        instrumentation.waitForIdleSync();
-
-        // Now remove view A
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.removeView(viewA);
-            }
-        });
-
-        // And assert that View B's Behavior was called appropriately
-        verify(behavior, times(1)).onDependentViewRemoved(col, viewB, viewA);
-    }
-
-    @Test
-    public void testGetDependenciesAfterDependentViewRemoved() throws Throwable {
-        final Instrumentation instrumentation = getInstrumentation();
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        // Add two views, A & B, where B depends on A
-        final View viewA = new View(col.getContext());
-        final View viewB = new View(col.getContext());
-        final CoordinatorLayout.LayoutParams lpB = col.generateDefaultLayoutParams();
-        final CoordinatorLayout.Behavior behavior =
-                new CoordinatorLayoutUtils.DependentBehavior(viewA) {
-                    @Override
-                    public void onDependentViewRemoved(
-                            CoordinatorLayout parent, View child, View dependency) {
-                        parent.getDependencies(child);
-                    }
-                };
-        lpB.setBehavior(behavior);
-
-        // Now add views
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.addView(viewA);
-                col.addView(viewB, lpB);
-            }
-        });
-
-        // Wait for a layout
-        instrumentation.waitForIdleSync();
-
-        // Now remove view A, which will trigger onDependentViewRemoved() on view B's behavior
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.removeView(viewA);
-            }
-        });
-    }
-
-    @Test
-    public void testDodgeInsetBeforeLayout() throws Throwable {
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        // Add a dummy view, which will be used to trigger a hierarchy change.
-        final View dummy = new View(col.getContext());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.addView(dummy);
-            }
-        });
-
-        // Wait for a layout.
-        mInstrumentation.waitForIdleSync();
-
-        final View dodge = new View(col.getContext());
-        final CoordinatorLayout.LayoutParams lpDodge = col.generateDefaultLayoutParams();
-        lpDodge.dodgeInsetEdges = Gravity.BOTTOM;
-        lpDodge.setBehavior(new Behavior() {
-            @Override
-            public boolean getInsetDodgeRect(CoordinatorLayout parent, View child, Rect rect) {
-                // Any non-empty rect is fine here.
-                rect.set(0, 0, 10, 10);
-                return true;
-            }
-        });
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.addView(dodge, lpDodge);
-
-                // Ensure the new view is in the list of children.
-                int heightSpec = MeasureSpec.makeMeasureSpec(col.getHeight(), MeasureSpec.EXACTLY);
-                int widthSpec = MeasureSpec.makeMeasureSpec(col.getWidth(), MeasureSpec.EXACTLY);
-                col.measure(widthSpec, heightSpec);
-
-                // Force a hierarchy change.
-                col.removeView(dummy);
-            }
-        });
-
-        // Wait for a layout.
-        mInstrumentation.waitForIdleSync();
-    }
-
-    @Test
-    public void testGoneViewsNotMeasuredLaidOut() throws Throwable {
-        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        final CoordinatorLayout col = activity.mCoordinatorLayout;
-
-        // Now create a GONE view and add it to the CoordinatorLayout
-        final View imageView = new View(activity);
-        imageView.setVisibility(View.GONE);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                col.addView(imageView, 200, 200);
-            }
-        });
-        // Wait for a layout and measure pass
-        mInstrumentation.waitForIdleSync();
-
-        // And assert that it has not been laid out
-        assertFalse(imageView.getMeasuredWidth() > 0);
-        assertFalse(imageView.getMeasuredHeight() > 0);
-        assertFalse(ViewCompat.isLaidOut(imageView));
-
-        // Now set the view to INVISIBLE
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                imageView.setVisibility(View.INVISIBLE);
-            }
-        });
-        // Wait for a layout and measure pass
-        mInstrumentation.waitForIdleSync();
-
-        // And assert that it has been laid out
-        assertTrue(imageView.getMeasuredWidth() > 0);
-        assertTrue(imageView.getMeasuredHeight() > 0);
-        assertTrue(ViewCompat.isLaidOut(imageView));
-    }
-
-    @Test
-    public void testNestedScrollingDispatchesToBehavior() throws Throwable {
-        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        final CoordinatorLayout col = activity.mCoordinatorLayout;
-
-        // Now create a view and add it to the CoordinatorLayout with the spy behavior,
-        // along with a NestedScrollView
-        final ImageView imageView = new ImageView(activity);
-        final CoordinatorLayout.Behavior behavior = spy(new NestedScrollingBehavior());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                LayoutInflater.from(activity).inflate(R.layout.include_nestedscrollview, col, true);
-
-                CoordinatorLayout.LayoutParams clp = new CoordinatorLayout.LayoutParams(200, 200);
-                clp.setBehavior(behavior);
-                col.addView(imageView, clp);
-            }
-        });
-
-        // Now vertically swipe up on the NSV, causing nested scrolling to occur
-        onView(withId(R.id.nested_scrollview)).perform(swipeUp());
-
-        // Verify that the Behavior's onStartNestedScroll was called once
-        verify(behavior, times(1)).onStartNestedScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(View.class), // direct child target
-                any(int.class)); // axes
-
-        // Verify that the Behavior's onNestedScrollAccepted was called once
-        verify(behavior, times(1)).onNestedScrollAccepted(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(View.class), // direct child target
-                any(int.class)); // axes
-
-        // Verify that the Behavior's onNestedPreScroll was called at least once
-        verify(behavior, atLeastOnce()).onNestedPreScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(int.class), // dx
-                any(int.class), // dy
-                any(int[].class)); // consumed
-
-        // Verify that the Behavior's onNestedScroll was called at least once
-        verify(behavior, atLeastOnce()).onNestedScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(int.class), // dx consumed
-                any(int.class), // dy consumed
-                any(int.class), // dx unconsumed
-                any(int.class)); // dy unconsumed
-
-        // Verify that the Behavior's onStopNestedScroll was called once
-        verify(behavior, times(1)).onStopNestedScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class)); // target
-    }
-
-    @Test
-    public void testNestedScrollingDispatchingToBehaviorWithGoneView() throws Throwable {
-        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        final CoordinatorLayout col = activity.mCoordinatorLayout;
-
-        // Now create a GONE view and add it to the CoordinatorLayout with the spy behavior,
-        // along with a NestedScrollView
-        final ImageView imageView = new ImageView(activity);
-        imageView.setVisibility(View.GONE);
-        final CoordinatorLayout.Behavior behavior = spy(new NestedScrollingBehavior());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                LayoutInflater.from(activity).inflate(R.layout.include_nestedscrollview, col, true);
-
-                CoordinatorLayout.LayoutParams clp = new CoordinatorLayout.LayoutParams(200, 200);
-                clp.setBehavior(behavior);
-                col.addView(imageView, clp);
-            }
-        });
-
-        // Now vertically swipe up on the NSV, causing nested scrolling to occur
-        onView(withId(R.id.nested_scrollview)).perform(swipeUp());
-
-        // Verify that the Behavior's onStartNestedScroll was not called
-        verify(behavior, never()).onStartNestedScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(View.class), // direct child target
-                any(int.class)); // axes
-
-        // Verify that the Behavior's onNestedScrollAccepted was not called
-        verify(behavior, never()).onNestedScrollAccepted(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(View.class), // direct child target
-                any(int.class)); // axes
-
-        // Verify that the Behavior's onNestedPreScroll was not called
-        verify(behavior, never()).onNestedPreScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(int.class), // dx
-                any(int.class), // dy
-                any(int[].class)); // consumed
-
-        // Verify that the Behavior's onNestedScroll was not called
-        verify(behavior, never()).onNestedScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class), // target
-                any(int.class), // dx consumed
-                any(int.class), // dy consumed
-                any(int.class), // dx unconsumed
-                any(int.class)); // dy unconsumed
-
-        // Verify that the Behavior's onStopNestedScroll was not called
-        verify(behavior, never()).onStopNestedScroll(
-                eq(col), // parent
-                eq(imageView), // child
-                any(View.class)); // target
-    }
-
-    @Test
-    public void testNestedScrollingTriggeringDependentViewChanged() throws Throwable {
-        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        final CoordinatorLayout col = activity.mCoordinatorLayout;
-
-        // First a NestedScrollView to trigger nested scrolling
-        final View scrollView = LayoutInflater.from(activity).inflate(
-                R.layout.include_nestedscrollview, col, false);
-
-        // Now create a View and Behavior which depend on the scrollview
-        final ImageView dependentView = new ImageView(activity);
-        final CoordinatorLayout.Behavior dependentBehavior = spy(new DependentBehavior(scrollView));
-
-        // Finally a view which accepts nested scrolling in the CoordinatorLayout
-        final ImageView nestedScrollAwareView = new ImageView(activity);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // First add the ScrollView
-                col.addView(scrollView);
-
-                // Now add the view which depends on the scrollview
-                CoordinatorLayout.LayoutParams clp = new CoordinatorLayout.LayoutParams(200, 200);
-                clp.setBehavior(dependentBehavior);
-                col.addView(dependentView, clp);
-
-                // Now add the nested scrolling aware view
-                clp = new CoordinatorLayout.LayoutParams(200, 200);
-                clp.setBehavior(new NestedScrollingBehavior());
-                col.addView(nestedScrollAwareView, clp);
-            }
-        });
-
-        // Wait for any layouts, and reset the Behavior so that the call counts are 0
-        getInstrumentation().waitForIdleSync();
-        reset(dependentBehavior);
-
-        // Now vertically swipe up on the NSV, causing nested scrolling to occur
-        onView(withId(R.id.nested_scrollview)).perform(swipeUp());
-
-        // Verify that the Behavior's onDependentViewChanged is not called due to the
-        // nested scroll
-        verify(dependentBehavior, never()).onDependentViewChanged(
-                eq(col), // parent
-                eq(dependentView), // child
-                eq(scrollView)); // axes
-    }
-
-    @Test
-    public void testDodgeInsetViewWithEmptyBounds() throws Throwable {
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        // Add a view with zero height/width which is set to dodge its bounds
-        final View view = new View(col.getContext());
-        final Behavior spyBehavior = spy(new DodgeBoundsBehavior());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
-                lp.dodgeInsetEdges = Gravity.BOTTOM;
-                lp.gravity = Gravity.BOTTOM;
-                lp.height = 0;
-                lp.width = 0;
-                lp.setBehavior(spyBehavior);
-                col.addView(view, lp);
-            }
-        });
-
-        // Wait for a layout
-        mInstrumentation.waitForIdleSync();
-
-        // Now add an non-empty bounds inset view to the bottom of the CoordinatorLayout
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View dodge = new View(col.getContext());
-                final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
-                lp.insetEdge = Gravity.BOTTOM;
-                lp.gravity = Gravity.BOTTOM;
-                lp.height = 60;
-                lp.width = CoordinatorLayout.LayoutParams.MATCH_PARENT;
-                col.addView(dodge, lp);
-            }
-        });
-
-        // Verify that the Behavior of the view with empty bounds does not have its
-        // getInsetDodgeRect() called
-        verify(spyBehavior, never())
-                .getInsetDodgeRect(same(col), same(view), any(Rect.class));
-    }
-
-    public static class NestedScrollingBehavior extends CoordinatorLayout.Behavior<View> {
-        @Override
-        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child,
-                View directTargetChild, View target, int nestedScrollAxes) {
-            // Return true so that we always accept nested scroll events
-            return true;
-        }
-    }
-
-    public static class DodgeBoundsBehavior extends Behavior<View> {
-        @Override
-        public boolean getInsetDodgeRect(CoordinatorLayout parent, View child, Rect rect) {
-            rect.set(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
-            return true;
-        }
-    }
-
-    @UiThreadTest
-    @Test
-    public void testAnchorDependencyGraph() throws Throwable {
-        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
-
-        // Override hashcode because of implementation of SimpleArrayMap used in
-        // DirectedAcyclicGraph used for sorting dependencies. Hashcode of anchored view has to be
-        // greater than of the one it is anchored to in order to reproduce the error.
-        final View anchor = createViewWithHashCode(col.getContext(), 2);
-        anchor.setId(R.id.anchor);
-
-        final View ship = createViewWithHashCode(col.getContext(), 3);
-        final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
-        lp.setAnchorId(R.id.anchor);
-
-        col.addView(anchor);
-        col.addView(ship, lp);
-
-        // Get dependencies immediately to avoid possible call to onMeasure(), since error
-        // only happens on first computing of sorted dependencies.
-        List<View> dependencySortedChildren = col.getDependencySortedChildren();
-        assertThat(dependencySortedChildren, is(Arrays.asList(anchor, ship)));
-    }
-
-    @NonNull
-    private View createViewWithHashCode(final Context context, final int hashCode) {
-        return new View(context) {
-            @Override
-            public int hashCode() {
-                return hashCode;
-            }
-        };
-    }
-}
diff --git a/core-ui/tests/java/android/support/design/widget/CoordinatorSnackbarWithButtonTest.java b/core-ui/tests/java/android/support/design/widget/CoordinatorSnackbarWithButtonTest.java
deleted file mode 100644
index 7089b80..0000000
--- a/core-ui/tests/java/android/support/design/widget/CoordinatorSnackbarWithButtonTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.support.coreui.test.R;
-import android.support.design.custom.CustomBar;
-import android.support.design.custom.TestFloatingBehavior;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.filters.MediumTest;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextView;
-
-import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Test;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@MediumTest
-public class CoordinatorSnackbarWithButtonTest extends BaseDynamicCoordinatorLayoutTest {
-    private View mBar;
-
-    @After
-    @UiThreadTest
-    public void teardown() throws Throwable {
-        mCoordinatorLayout.removeView(mBar);
-    }
-
-    /**
-     * Returns the location of our bar on the screen.
-     */
-    private static int[] getBarLocationOnScreen() {
-        final int[] location = new int[2];
-        onView(isAssignableFrom(CustomBar.class)).perform(new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isEnabled();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Bar matcher";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                view.getLocationOnScreen(location);
-            }
-        });
-        return location;
-    }
-
-    /**
-     * Helper method that verifies that the passed view is above the bar in the activity
-     * window.
-     */
-    private static void verifyBarViewStacking(View view, int extraBottomMargin) {
-        // Get location of bar in window
-        final int[] barOnScreenXY = getBarLocationOnScreen();
-        // Get location of passed view in window
-        final int[] viewOnScreenXY = new int[2];
-        view.getLocationOnScreen(viewOnScreenXY);
-
-        // Compute the bottom visible edge of the view
-        int viewBottom = viewOnScreenXY[1] + view.getHeight() - extraBottomMargin;
-        int barTop = barOnScreenXY[1];
-        // and verify that our view is above the bar
-        assertTrue(viewBottom <= barTop);
-    }
-
-    private void addBar() {
-        final CountDownLatch latch = new CountDownLatch(1);
-        new Handler(Looper.getMainLooper()).post(new Runnable() {
-            @Override
-            public void run() {
-                LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-                mBar = inflater.inflate(R.layout.emulated_snackbar, mCoordinatorLayout, false);
-                mCoordinatorLayout.addView(mBar);
-                latch.countDown();
-            }
-        });
-        try {
-            assertTrue("Could not add emulated snackbar", latch.await(5, TimeUnit.SECONDS));
-        } catch (Throwable t) {
-            throw new RuntimeException(t);
-        }
-    }
-
-    @Test
-    public void testBehaviorBasedSlidingFromLayoutAttribute() {
-        // Use a layout in which a TextView child has Behavior object configured via
-        // layout_behavior XML attribute
-        onView(withId(R.id.coordinator_stub)).perform(
-                inflateViewStub(R.layout.design_snackbar_behavior_layout_attr));
-
-        // Create and show the bar
-        addBar();
-
-        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
-        verifyBarViewStacking(textView, 0);
-    }
-
-    @Test
-    public void testBehaviorBasedSlidingFromClassAnnotation() {
-        // Use a layout in which a custom child view has Behavior object configured via
-        // annotation on the class that extends TextView
-        onView(withId(R.id.coordinator_stub)).perform(
-                inflateViewStub(R.layout.design_snackbar_behavior_annotation));
-
-        // Create and show the bar
-        addBar();
-
-        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
-        verifyBarViewStacking(textView, 0);
-    }
-
-    @Test
-    public void testBehaviorBasedSlidingFromClassInterface() {
-        // Use a layout in which a custom child view has Behavior object configured via
-        // the interface on the class that extends TextView
-        onView(withId(R.id.coordinator_stub)).perform(
-                inflateViewStub(R.layout.design_snackbar_behavior_interface));
-
-        // Create and show the bar
-        addBar();
-
-        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
-        verifyBarViewStacking(textView, 0);
-    }
-
-    @Test
-    public void testBehaviorBasedSlidingFromRuntimeApiCall() {
-        // Use a layout in which a TextView child doesn't have any configured Behavior
-        onView(withId(R.id.coordinator_stub)).perform(
-                inflateViewStub(R.layout.design_snackbar_behavior_runtime));
-
-        // and configure that Behavior at runtime by setting it on its LayoutParams
-        final TextView textView = mCoordinatorLayout.findViewById(R.id.text);
-        final CoordinatorLayout.LayoutParams textViewLp =
-                (CoordinatorLayout.LayoutParams) textView.getLayoutParams();
-        textViewLp.setBehavior(new TestFloatingBehavior());
-
-        // Create and show the bar
-        addBar();
-
-        verifyBarViewStacking(textView, 0);
-    }
-}
diff --git a/core-ui/tests/java/android/support/design/widget/DynamicCoordinatorLayoutActivity.java b/core-ui/tests/java/android/support/design/widget/DynamicCoordinatorLayoutActivity.java
deleted file mode 100644
index ac61704..0000000
--- a/core-ui/tests/java/android/support/design/widget/DynamicCoordinatorLayoutActivity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.coreui.test.R;
-
-/**
- * Test activity for testing various aspects of {@link CoordinatorLayout}.
- */
-public class DynamicCoordinatorLayoutActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.dynamic_coordinator_layout;
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/BaseInstrumentationTestCase.java b/core-ui/tests/java/android/support/v4/BaseInstrumentationTestCase.java
deleted file mode 100644
index 5f9ce85..0000000
--- a/core-ui/tests/java/android/support/v4/BaseInstrumentationTestCase.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4;
-
-import android.app.Activity;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import org.junit.Rule;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public abstract class BaseInstrumentationTestCase<A extends Activity> {
-    @Rule
-    public final ActivityTestRule<A> mActivityTestRule;
-
-    protected BaseInstrumentationTestCase(Class<A> activityClass) {
-        mActivityTestRule = new ActivityTestRule<A>(activityClass);
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/BaseTestActivity.java b/core-ui/tests/java/android/support/v4/BaseTestActivity.java
deleted file mode 100755
index e0682ce..0000000
--- a/core-ui/tests/java/android/support/v4/BaseTestActivity.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.WindowManager;
-
-public abstract class BaseTestActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        final int contentView = getContentViewLayoutResId();
-        if (contentView > 0) {
-            setContentView(contentView);
-        }
-        onContentViewSet();
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-    }
-
-    protected abstract int getContentViewLayoutResId();
-
-    protected void onContentViewSet() {}
-}
diff --git a/core-ui/tests/java/android/support/v4/testutils/TestUtils.java b/core-ui/tests/java/android/support/v4/testutils/TestUtils.java
deleted file mode 100644
index 1f82dd0..0000000
--- a/core-ui/tests/java/android/support/v4/testutils/TestUtils.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.support.v4.testutils;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
-
-public class TestUtils {
-    /**
-     * Checks whether all the pixels in the specified drawable are of the same specified color.
-     * If the passed <code>Drawable</code> does not have positive intrinsic dimensions set, this
-     * method will throw an <code>IllegalArgumentException</code>. If there is a color mismatch,
-     * this method will call <code>Assert.fail</code> with detailed description of the mismatch.
-     */
-    public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
-            @ColorInt int color) {
-        int drawableWidth = drawable.getIntrinsicWidth();
-        int drawableHeight = drawable.getIntrinsicHeight();
-
-        if ((drawableWidth <= 0) || (drawableHeight <= 0)) {
-            throw new IllegalArgumentException("Drawable must be configured to have non-zero size");
-        }
-
-        assertAllPixelsOfColor(failMessagePrefix, drawable, drawableWidth, drawableHeight, color,
-                false);
-    }
-
-    /**
-     * Checks whether all the pixels in the specified drawable are of the same specified color.
-     *
-     * In case there is a color mismatch, the behavior of this method depends on the
-     * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
-     * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
-     * <code>Assert.fail</code> with detailed description of the mismatch.
-     */
-    public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
-            int drawableWidth, int drawableHeight, @ColorInt int color,
-            boolean throwExceptionIfFails) {
-        // Create a bitmap
-        Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
-        // Create a canvas that wraps the bitmap
-        Canvas canvas = new Canvas(bitmap);
-        // Configure the drawable to have bounds that match its intrinsic size
-        drawable.setBounds(0, 0, drawableWidth, drawableHeight);
-        // And ask the drawable to draw itself to the canvas / bitmap
-        drawable.draw(canvas);
-
-        try {
-            int[] rowPixels = new int[drawableWidth];
-            for (int row = 0; row < drawableHeight; row++) {
-                bitmap.getPixels(rowPixels, 0, drawableWidth, 0, row, drawableWidth, 1);
-                for (int column = 0; column < drawableWidth; column++) {
-                    if (rowPixels[column] != color) {
-                        String mismatchDescription = failMessagePrefix
-                                + ": expected all drawable colors to be ["
-                                + Color.red(color) + "," + Color.green(color) + ","
-                                + Color.blue(color)
-                                + "] but at position (" + row + "," + column + ") found ["
-                                + Color.red(rowPixels[column]) + ","
-                                + Color.green(rowPixels[column]) + ","
-                                + Color.blue(rowPixels[column]) + "]";
-                        if (throwExceptionIfFails) {
-                            throw new RuntimeException(mismatchDescription);
-                        } else {
-                            fail(mismatchDescription);
-                        }
-                    }
-                }
-            }
-        } finally {
-            bitmap.recycle();
-        }
-    }
-
-    /**
-     * Checks whether the specified rectangle matches the specified left / top / right /
-     * bottom bounds.
-     */
-    public static void assertRectangleBounds(String failMessagePrefix, @NonNull Rect rectangle,
-            int left, int top, int right, int bottom) {
-        assertEquals(failMessagePrefix + " left", rectangle.left, left);
-        assertEquals(failMessagePrefix + " top", rectangle.top, top);
-        assertEquals(failMessagePrefix + " right", rectangle.right, right);
-        assertEquals(failMessagePrefix + " bottom", rectangle.bottom, bottom);
-    }
-}
\ No newline at end of file
diff --git a/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java b/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
deleted file mode 100644
index f26942b..0000000
--- a/core-ui/tests/java/android/support/v4/view/BaseViewPagerTest.java
+++ /dev/null
@@ -1,1108 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v4.view;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.pressKey;
-import static android.support.test.espresso.action.ViewActions.swipeLeft;
-import static android.support.test.espresso.action.ViewActions.swipeRight;
-import static android.support.test.espresso.assertion.PositionAssertions.isBelow;
-import static android.support.test.espresso.assertion.PositionAssertions.isBottomAlignedWith;
-import static android.support.test.espresso.assertion.PositionAssertions.isLeftAlignedWith;
-import static android.support.test.espresso.assertion.PositionAssertions.isRightAlignedWith;
-import static android.support.test.espresso.assertion.PositionAssertions.isTopAlignedWith;
-import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.v4.testutils.TestUtilsAssertions.hasDisplayedChildren;
-import static android.support.v4.testutils.TestUtilsMatchers.backgroundColor;
-import static android.support.v4.testutils.TestUtilsMatchers.centerAlignedInParent;
-import static android.support.v4.testutils.TestUtilsMatchers.endAlignedToParent;
-import static android.support.v4.testutils.TestUtilsMatchers.isOfClass;
-import static android.support.v4.testutils.TestUtilsMatchers.startAlignedToParent;
-import static android.support.v4.view.ViewPagerActions.arrowScroll;
-import static android.support.v4.view.ViewPagerActions.scrollLeft;
-import static android.support.v4.view.ViewPagerActions.scrollRight;
-import static android.support.v4.view.ViewPagerActions.scrollToFirst;
-import static android.support.v4.view.ViewPagerActions.scrollToLast;
-import static android.support.v4.view.ViewPagerActions.scrollToPage;
-import static android.support.v4.view.ViewPagerActions.setAdapter;
-import static android.support.v4.view.ViewPagerActions.wrap;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.core.IsNot.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.Activity;
-import android.graphics.Color;
-import android.support.coreui.test.R;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.EspressoKey;
-import android.support.test.filters.FlakyTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.v4.BaseInstrumentationTestCase;
-import android.support.v4.testutils.TestUtilsMatchers;
-import android.text.TextUtils;
-import android.util.Pair;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Base class for testing <code>ViewPager</code>. Most of the testing logic should be in this
- * class as it is independent on the specific pager title implementation (interactive or non
- * interactive).
- *
- * Testing logic that does depend on the specific pager title implementation is pushed into the
- * extending classes in <code>assertStripInteraction()</code> method.
- */
-public abstract class BaseViewPagerTest<T extends Activity> extends BaseInstrumentationTestCase<T> {
-    private static final int DIRECTION_LEFT = -1;
-    private static final int DIRECTION_RIGHT = 1;
-    protected ViewPager mViewPager;
-
-    protected static class BasePagerAdapter<Q> extends PagerAdapter {
-        protected ArrayList<Pair<String, Q>> mEntries = new ArrayList<>();
-
-        public void add(String title, Q content) {
-            mEntries.add(new Pair<>(title, content));
-        }
-
-        @Override
-        public int getCount() {
-            return mEntries.size();
-        }
-
-        protected void configureInstantiatedItem(View view, int position) {
-            switch (position) {
-                case 0:
-                    view.setId(R.id.page_0);
-                    break;
-                case 1:
-                    view.setId(R.id.page_1);
-                    break;
-                case 2:
-                    view.setId(R.id.page_2);
-                    break;
-                case 3:
-                    view.setId(R.id.page_3);
-                    break;
-                case 4:
-                    view.setId(R.id.page_4);
-                    break;
-                case 5:
-                    view.setId(R.id.page_5);
-                    break;
-                case 6:
-                    view.setId(R.id.page_6);
-                    break;
-                case 7:
-                    view.setId(R.id.page_7);
-                    break;
-                case 8:
-                    view.setId(R.id.page_8);
-                    break;
-                case 9:
-                    view.setId(R.id.page_9);
-                    break;
-            }
-        }
-
-        @Override
-        public void destroyItem(ViewGroup container, int position, Object object) {
-            // The adapter is also responsible for removing the view.
-            container.removeView(((ViewHolder) object).view);
-        }
-
-        @Override
-        public int getItemPosition(Object object) {
-            return ((ViewHolder) object).position;
-        }
-
-        @Override
-        public boolean isViewFromObject(View view, Object object) {
-            return ((ViewHolder) object).view == view;
-        }
-
-        @Override
-        public CharSequence getPageTitle(int position) {
-            return mEntries.get(position).first;
-        }
-
-        protected static class ViewHolder {
-            final View view;
-            final int position;
-
-            public ViewHolder(View view, int position) {
-                this.view = view;
-                this.position = position;
-            }
-        }
-    }
-
-    protected static class ColorPagerAdapter extends BasePagerAdapter<Integer> {
-        @Override
-        public Object instantiateItem(ViewGroup container, int position) {
-            final View view = new View(container.getContext());
-            view.setBackgroundColor(mEntries.get(position).second);
-            configureInstantiatedItem(view, position);
-
-            // Unlike ListView adapters, the ViewPager adapter is responsible
-            // for adding the view to the container.
-            container.addView(view);
-
-            return new ViewHolder(view, position);
-        }
-    }
-
-    protected static class TextPagerAdapter extends BasePagerAdapter<String> {
-        @Override
-        public Object instantiateItem(ViewGroup container, int position) {
-            final TextView view = new TextView(container.getContext());
-            view.setText(mEntries.get(position).second);
-            configureInstantiatedItem(view, position);
-
-            // Unlike ListView adapters, the ViewPager adapter is responsible
-            // for adding the view to the container.
-            container.addView(view);
-
-            return new ViewHolder(view, position);
-        }
-    }
-
-    protected static class ButtonPagerAdapter extends BasePagerAdapter<Integer> {
-        private ArrayList<Button[]> mButtons = new ArrayList<>();
-
-        @Override
-        public void add(String title, Integer content) {
-            super.add(title, content);
-            mButtons.add(new Button[3]);
-        }
-
-        @Override
-        public Object instantiateItem(ViewGroup container, int position) {
-            final LinearLayout view = new LinearLayout(container.getContext());
-            view.setBackgroundColor(mEntries.get(position).second);
-            view.setOrientation(LinearLayout.HORIZONTAL);
-            configureInstantiatedItem(view, position);
-
-            for (int i = 0; i < 3; ++i) {
-                Button but = new Button(container.getContext());
-                but.setText("" + i);
-                but.setFocusableInTouchMode(true);
-                view.addView(but, ViewGroup.LayoutParams.WRAP_CONTENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
-                mButtons.get(position)[i] = but;
-            }
-
-            // Unlike ListView adapters, the ViewPager adapter is responsible
-            // for adding the view to the container.
-            container.addView(view);
-
-            return new ViewHolder(view, position);
-        }
-
-        public View getButton(int page, int idx) {
-            return mButtons.get(page)[idx];
-        }
-    }
-
-    public BaseViewPagerTest(Class<T> activityClass) {
-        super(activityClass);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        final T activity = mActivityTestRule.getActivity();
-        mViewPager = (ViewPager) activity.findViewById(R.id.pager);
-
-        ColorPagerAdapter adapter = new ColorPagerAdapter();
-        adapter.add("Red", Color.RED);
-        adapter.add("Green", Color.GREEN);
-        adapter.add("Blue", Color.BLUE);
-        onView(withId(R.id.pager)).perform(setAdapter(adapter), scrollToPage(0, false));
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        onView(withId(R.id.pager)).perform(setAdapter(null));
-    }
-
-    private void verifyPageSelections(boolean smoothScroll) {
-        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
-
-        ViewPager.OnPageChangeListener mockPageChangeListener =
-                mock(ViewPager.OnPageChangeListener.class);
-        mViewPager.addOnPageChangeListener(mockPageChangeListener);
-
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right", 1, mViewPager.getCurrentItem());
-        verify(mockPageChangeListener, times(1)).onPageSelected(1);
-
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right", 2, mViewPager.getCurrentItem());
-        verify(mockPageChangeListener, times(1)).onPageSelected(2);
-
-        // Try "scrolling" beyond the last page and test that we're still on the last page.
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right beyond last page", 2, mViewPager.getCurrentItem());
-        // We're still on this page, so we shouldn't have been called again with index 2
-        verify(mockPageChangeListener, times(1)).onPageSelected(2);
-
-        onView(withId(R.id.pager)).perform(scrollLeft(smoothScroll));
-        assertEquals("Scroll left", 1, mViewPager.getCurrentItem());
-        // Verify that this is the second time we're called on index 1
-        verify(mockPageChangeListener, times(2)).onPageSelected(1);
-
-        onView(withId(R.id.pager)).perform(scrollLeft(smoothScroll));
-        assertEquals("Scroll left", 0, mViewPager.getCurrentItem());
-        // Verify that this is the first time we're called on index 0
-        verify(mockPageChangeListener, times(1)).onPageSelected(0);
-
-        // Try "scrolling" beyond the first page and test that we're still on the first page.
-        onView(withId(R.id.pager)).perform(scrollLeft(smoothScroll));
-        assertEquals("Scroll left beyond first page", 0, mViewPager.getCurrentItem());
-        // We're still on this page, so we shouldn't have been called again with index 0
-        verify(mockPageChangeListener, times(1)).onPageSelected(0);
-
-        // Unregister our listener
-        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
-
-        // Go from index 0 to index 2
-        onView(withId(R.id.pager)).perform(scrollToPage(2, smoothScroll));
-        assertEquals("Scroll to last page", 2, mViewPager.getCurrentItem());
-        // Our listener is not registered anymore, so we shouldn't have been called with index 2
-        verify(mockPageChangeListener, times(1)).onPageSelected(2);
-
-        // And back to 0
-        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
-        assertEquals("Scroll to first page", 0, mViewPager.getCurrentItem());
-        // Our listener is not registered anymore, so we shouldn't have been called with index 0
-        verify(mockPageChangeListener, times(1)).onPageSelected(0);
-
-        // Verify the overall sequence of calls to onPageSelected of our listener
-        ArgumentCaptor<Integer> pageSelectedCaptor = ArgumentCaptor.forClass(int.class);
-        verify(mockPageChangeListener, times(4)).onPageSelected(pageSelectedCaptor.capture());
-        assertThat(pageSelectedCaptor.getAllValues(), TestUtilsMatchers.matches(1, 2, 1, 0));
-    }
-
-    @Test
-    @MediumTest
-    public void testPageSelectionsImmediate() {
-        verifyPageSelections(false);
-    }
-
-    @Test
-    @LargeTest
-    public void testPageSelectionsSmooth() {
-        verifyPageSelections(true);
-    }
-
-    private void verifyPageChangeViewActions(ViewAction next, ViewAction previous) {
-        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
-        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
-
-        ViewPager.OnPageChangeListener mockPageChangeListener =
-                mock(ViewPager.OnPageChangeListener.class);
-        mViewPager.addOnPageChangeListener(mockPageChangeListener);
-
-        onView(withId(R.id.pager)).perform(next);
-        assertEquals("Move to next page", 1, mViewPager.getCurrentItem());
-        verify(mockPageChangeListener, times(1)).onPageSelected(1);
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
-
-        onView(withId(R.id.pager)).perform(next);
-        assertEquals("Move to next page", 2, mViewPager.getCurrentItem());
-        verify(mockPageChangeListener, times(1)).onPageSelected(2);
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
-        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
-
-        // Try swiping beyond the last page and test that we're still on the last page.
-        onView(withId(R.id.pager)).perform(next);
-        assertEquals("Attempt to move to next page beyond last page", 2,
-                mViewPager.getCurrentItem());
-        // We're still on this page, so we shouldn't have been called again with index 2
-        verify(mockPageChangeListener, times(1)).onPageSelected(2);
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
-        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
-
-        onView(withId(R.id.pager)).perform(previous);
-        assertEquals("Move to previous page", 1, mViewPager.getCurrentItem());
-        // Verify that this is the second time we're called on index 1
-        verify(mockPageChangeListener, times(2)).onPageSelected(1);
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
-
-        onView(withId(R.id.pager)).perform(previous);
-        assertEquals("Move to previous page", 0, mViewPager.getCurrentItem());
-        // Verify that this is the first time we're called on index 0
-        verify(mockPageChangeListener, times(1)).onPageSelected(0);
-        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
-
-        // Try swiping beyond the first page and test that we're still on the first page.
-        onView(withId(R.id.pager)).perform(previous);
-        assertEquals("Attempt to move to previous page beyond first page", 0,
-                mViewPager.getCurrentItem());
-        // We're still on this page, so we shouldn't have been called again with index 0
-        verify(mockPageChangeListener, times(1)).onPageSelected(0);
-        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
-        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
-
-        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
-
-        // Verify the overall sequence of calls to onPageSelected of our listener
-        ArgumentCaptor<Integer> pageSelectedCaptor = ArgumentCaptor.forClass(int.class);
-        verify(mockPageChangeListener, times(4)).onPageSelected(pageSelectedCaptor.capture());
-        assertThat(pageSelectedCaptor.getAllValues(), TestUtilsMatchers.matches(1, 2, 1, 0));
-    }
-
-    @Test
-    @LargeTest
-    public void testPageSwipes() {
-        verifyPageChangeViewActions(wrap(swipeLeft()), wrap(swipeRight()));
-    }
-
-    @Test
-    @LargeTest
-    public void testArrowPageChanges() {
-        verifyPageChangeViewActions(arrowScroll(View.FOCUS_RIGHT), arrowScroll(View.FOCUS_LEFT));
-    }
-
-    @Test
-    @LargeTest
-    public void testPageSwipesComposite() {
-        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
-
-        onView(withId(R.id.pager)).perform(wrap(swipeLeft()), wrap(swipeLeft()));
-        assertEquals("Swipe twice left", 2, mViewPager.getCurrentItem());
-
-        onView(withId(R.id.pager)).perform(wrap(swipeLeft()), wrap(swipeRight()));
-        assertEquals("Swipe left beyond last page and then right", 1, mViewPager.getCurrentItem());
-
-        onView(withId(R.id.pager)).perform(wrap(swipeRight()), wrap(swipeRight()));
-        assertEquals("Swipe right and then right beyond first page", 0,
-                mViewPager.getCurrentItem());
-
-        onView(withId(R.id.pager)).perform(wrap(swipeRight()), wrap(swipeLeft()));
-        assertEquals("Swipe right beyond first page and then left", 1, mViewPager.getCurrentItem());
-    }
-
-    private void verifyPageContent(boolean smoothScroll) {
-        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
-
-        // Verify the displayed content to match the initial adapter - with 3 pages and each
-        // one rendered as a View.
-
-        // Page #0 should be displayed, page #1 should not be displayed and page #2 should not exist
-        // yet as it's outside of the offscreen window limit.
-        onView(withId(R.id.page_0)).check(matches(allOf(
-                isOfClass(View.class),
-                isDisplayed(),
-                backgroundColor(Color.RED))));
-        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_2)).check(doesNotExist());
-
-        // Scroll one page to select page #1
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right", 1, mViewPager.getCurrentItem());
-        // Pages #0 / #2 should not be displayed, page #1 should be displayed.
-        onView(withId(R.id.page_0)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_1)).check(matches(allOf(
-                isOfClass(View.class),
-                isDisplayed(),
-                backgroundColor(Color.GREEN))));
-        onView(withId(R.id.page_2)).check(matches(not(isDisplayed())));
-
-        // Scroll one more page to select page #2
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right again", 2, mViewPager.getCurrentItem());
-        // Page #0 should not exist as it's bumped to the outside of the offscreen window limit,
-        // page #1 should not be displayed, page #2 should be displayed.
-        onView(withId(R.id.page_0)).check(doesNotExist());
-        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_2)).check(matches(allOf(
-                isOfClass(View.class),
-                isDisplayed(),
-                backgroundColor(Color.BLUE))));
-    }
-
-    @Test
-    @MediumTest
-    public void testPageContentImmediate() {
-        verifyPageContent(false);
-    }
-
-    @Test
-    @LargeTest
-    public void testPageContentSmooth() {
-        verifyPageContent(true);
-    }
-
-    private void verifyAdapterChange(boolean smoothScroll) {
-        // Verify that we have the expected initial adapter
-        PagerAdapter initialAdapter = mViewPager.getAdapter();
-        assertEquals("Initial adapter class", ColorPagerAdapter.class, initialAdapter.getClass());
-        assertEquals("Initial adapter page count", 3, initialAdapter.getCount());
-
-        // Create a new adapter
-        TextPagerAdapter newAdapter = new TextPagerAdapter();
-        newAdapter.add("Title 0", "Body 0");
-        newAdapter.add("Title 1", "Body 1");
-        newAdapter.add("Title 2", "Body 2");
-        newAdapter.add("Title 3", "Body 3");
-        onView(withId(R.id.pager)).perform(setAdapter(newAdapter), scrollToPage(0, smoothScroll));
-
-        // Verify the displayed content to match the newly set adapter - with 4 pages and each
-        // one rendered as a TextView.
-
-        // Page #0 should be displayed, page #1 should not be displayed and pages #2 / #3 should not
-        // exist yet as they're outside of the offscreen window limit.
-        onView(withId(R.id.page_0)).check(matches(allOf(
-                isOfClass(TextView.class),
-                isDisplayed(),
-                withText("Body 0"))));
-        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_2)).check(doesNotExist());
-        onView(withId(R.id.page_3)).check(doesNotExist());
-
-        // Scroll one page to select page #1
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right", 1, mViewPager.getCurrentItem());
-        // Pages #0 / #2 should not be displayed, page #1 should be displayed, page #3 is still
-        // outside the offscreen limit.
-        onView(withId(R.id.page_0)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_1)).check(matches(allOf(
-                isOfClass(TextView.class),
-                isDisplayed(),
-                withText("Body 1"))));
-        onView(withId(R.id.page_2)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_3)).check(doesNotExist());
-
-        // Scroll one more page to select page #2
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right again", 2, mViewPager.getCurrentItem());
-        // Page #0 should not exist as it's bumped to the outside of the offscreen window limit,
-        // pages #1 / #3 should not be displayed, page #2 should be displayed.
-        onView(withId(R.id.page_0)).check(doesNotExist());
-        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_2)).check(matches(allOf(
-                isOfClass(TextView.class),
-                isDisplayed(),
-                withText("Body 2"))));
-        onView(withId(R.id.page_3)).check(matches(not(isDisplayed())));
-
-        // Scroll one more page to select page #2
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        assertEquals("Scroll right one more time", 3, mViewPager.getCurrentItem());
-        // Pages #0 / #1 should not exist as they're bumped to the outside of the offscreen window
-        // limit, page #2 should not be displayed, page #3 should be displayed.
-        onView(withId(R.id.page_0)).check(doesNotExist());
-        onView(withId(R.id.page_1)).check(doesNotExist());
-        onView(withId(R.id.page_2)).check(matches(not(isDisplayed())));
-        onView(withId(R.id.page_3)).check(matches(allOf(
-                isOfClass(TextView.class),
-                isDisplayed(),
-                withText("Body 3"))));
-    }
-
-    @Test
-    @MediumTest
-    public void testAdapterChangeImmediate() {
-        verifyAdapterChange(false);
-    }
-
-    @Test
-    @LargeTest
-    public void testAdapterChangeSmooth() {
-        verifyAdapterChange(true);
-    }
-
-    private void verifyTitleStripLayout(String expectedStartTitle, String expectedSelectedTitle,
-            String expectedEndTitle, int selectedPageId) {
-        // Check that the title strip spans the whole width of the pager and is aligned to
-        // its top
-        onView(withId(R.id.titles)).check(isLeftAlignedWith(withId(R.id.pager)));
-        onView(withId(R.id.titles)).check(isRightAlignedWith(withId(R.id.pager)));
-        onView(withId(R.id.titles)).check(isTopAlignedWith(withId(R.id.pager)));
-
-        // Check that the currently selected page spans the whole width of the pager and is below
-        // the title strip
-        onView(withId(selectedPageId)).check(isLeftAlignedWith(withId(R.id.pager)));
-        onView(withId(selectedPageId)).check(isRightAlignedWith(withId(R.id.pager)));
-        onView(withId(selectedPageId)).check(isBelow(withId(R.id.titles)));
-        onView(withId(selectedPageId)).check(isBottomAlignedWith(withId(R.id.pager)));
-
-        boolean hasStartTitle = !TextUtils.isEmpty(expectedStartTitle);
-        boolean hasEndTitle = !TextUtils.isEmpty(expectedEndTitle);
-
-        // Check that the title strip shows the expected number of children (tab titles)
-        int nonNullTitles = (hasStartTitle ? 1 : 0) + 1 + (hasEndTitle ? 1 : 0);
-        onView(withId(R.id.titles)).check(hasDisplayedChildren(nonNullTitles));
-
-        if (hasStartTitle) {
-            // Check that the title for the start page is displayed at the start edge of its parent
-            // (title strip)
-            onView(withId(R.id.titles)).check(matches(hasDescendant(
-                    allOf(withText(expectedStartTitle), isDisplayed(), startAlignedToParent()))));
-        }
-        // Check that the title for the selected page is displayed centered in its parent
-        // (title strip)
-        onView(withId(R.id.titles)).check(matches(hasDescendant(
-                allOf(withText(expectedSelectedTitle), isDisplayed(), centerAlignedInParent()))));
-        if (hasEndTitle) {
-            // Check that the title for the end page is displayed at the end edge of its parent
-            // (title strip)
-            onView(withId(R.id.titles)).check(matches(hasDescendant(
-                    allOf(withText(expectedEndTitle), isDisplayed(), endAlignedToParent()))));
-        }
-    }
-
-    private void verifyPagerStrip(boolean smoothScroll) {
-        // Set an adapter with 5 pages
-        final ColorPagerAdapter adapter = new ColorPagerAdapter();
-        adapter.add("Red", Color.RED);
-        adapter.add("Green", Color.GREEN);
-        adapter.add("Blue", Color.BLUE);
-        adapter.add("Yellow", Color.YELLOW);
-        adapter.add("Magenta", Color.MAGENTA);
-        onView(withId(R.id.pager)).perform(setAdapter(adapter),
-                scrollToPage(0, smoothScroll));
-
-        // Check that the pager has a title strip
-        onView(withId(R.id.pager)).check(matches(hasDescendant(withId(R.id.titles))));
-        // Check that the title strip is displayed and is of the expected class
-        onView(withId(R.id.titles)).check(matches(allOf(
-                isDisplayed(), isOfClass(getStripClass()))));
-
-        // The following block tests the overall layout of tab strip and main pager content
-        // (vertical stacking), the content of the tab strip (showing texts for the selected
-        // tab and the ones on its left / right) as well as the alignment of the content in the
-        // tab strip (selected in center, others on left and right).
-
-        // Check the content and alignment of title strip for selected page #0
-        verifyTitleStripLayout(null, "Red", "Green", R.id.page_0);
-
-        // Scroll one page to select page #1 and check layout / content of title strip
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        verifyTitleStripLayout("Red", "Green", "Blue", R.id.page_1);
-
-        // Scroll one page to select page #2 and check layout / content of title strip
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        verifyTitleStripLayout("Green", "Blue", "Yellow", R.id.page_2);
-
-        // Scroll one page to select page #3 and check layout / content of title strip
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        verifyTitleStripLayout("Blue", "Yellow", "Magenta", R.id.page_3);
-
-        // Scroll one page to select page #4 and check layout / content of title strip
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-        verifyTitleStripLayout("Yellow", "Magenta", null, R.id.page_4);
-
-        // Scroll back to page #0
-        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
-
-        assertStripInteraction(smoothScroll);
-    }
-
-    @Test
-    @LargeTest
-    public void testPagerStripImmediate() {
-        verifyPagerStrip(false);
-    }
-
-    @Test
-    @LargeTest
-    public void testPagerStripSmooth() {
-        verifyPagerStrip(true);
-    }
-
-    /**
-     * Returns the class of the pager strip.
-     */
-    protected abstract Class getStripClass();
-
-    /**
-     * Checks assertions that are specific to the pager strip implementation (interactive or
-     * non interactive).
-     */
-    protected abstract void assertStripInteraction(boolean smoothScroll);
-
-    /**
-     * Helper method that performs the specified action on the <code>ViewPager</code> and then
-     * checks the sequence of calls to the page change listener based on the specified expected
-     * scroll state changes.
-     *
-     * If that expected list is empty, this method verifies that there were no calls to
-     * onPageScrollStateChanged when the action was performed. Otherwise it verifies that the actual
-     * sequence of calls to onPageScrollStateChanged matches the expected (specified) one.
-     */
-    private void verifyScrollStateChange(ViewAction viewAction, int... expectedScrollStateChanges) {
-        ViewPager.OnPageChangeListener mockPageChangeListener =
-                mock(ViewPager.OnPageChangeListener.class);
-        mViewPager.addOnPageChangeListener(mockPageChangeListener);
-
-        // Perform our action
-        onView(withId(R.id.pager)).perform(viewAction);
-
-        int expectedScrollStateChangeCount = (expectedScrollStateChanges != null) ?
-                expectedScrollStateChanges.length : 0;
-
-        if (expectedScrollStateChangeCount == 0) {
-            verify(mockPageChangeListener, never()).onPageScrollStateChanged(anyInt());
-        } else {
-            ArgumentCaptor<Integer> pageScrollStateCaptor = ArgumentCaptor.forClass(int.class);
-            verify(mockPageChangeListener, times(expectedScrollStateChangeCount)).
-                    onPageScrollStateChanged(pageScrollStateCaptor.capture());
-            assertThat(pageScrollStateCaptor.getAllValues(),
-                    TestUtilsMatchers.matches(expectedScrollStateChanges));
-        }
-
-        // Remove our mock listener to get back to clean state for the next test
-        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
-    }
-
-    @Test
-    @MediumTest
-    public void testPageScrollStateChangedImmediate() {
-        // Note that all the actions tested in this method are immediate (no scrolling) and
-        // as such we test that we do not get any calls to onPageScrollStateChanged in any of them
-
-        // Select one page to the right
-        verifyScrollStateChange(scrollRight(false));
-        // Select one more page to the right
-        verifyScrollStateChange(scrollRight(false));
-        // Select one page to the left
-        verifyScrollStateChange(scrollLeft(false));
-        // Select one more page to the left
-        verifyScrollStateChange(scrollLeft(false));
-        // Select last page
-        verifyScrollStateChange(scrollToLast(false));
-        // Select first page
-        verifyScrollStateChange(scrollToFirst(false));
-    }
-
-    @Test
-    @LargeTest
-    public void testPageScrollStateChangedSmooth() {
-        // Note that all the actions tested in this method use smooth scrolling and as such we test
-        // that we get the matching calls to onPageScrollStateChanged
-        final int[] expectedScrollStateChanges = new int[] {
-                ViewPager.SCROLL_STATE_SETTLING, ViewPager.SCROLL_STATE_IDLE
-        };
-
-        // Select one page to the right
-        verifyScrollStateChange(scrollRight(true), expectedScrollStateChanges);
-        // Select one more page to the right
-        verifyScrollStateChange(scrollRight(true), expectedScrollStateChanges);
-        // Select one page to the left
-        verifyScrollStateChange(scrollLeft(true), expectedScrollStateChanges);
-        // Select one more page to the left
-        verifyScrollStateChange(scrollLeft(true), expectedScrollStateChanges);
-        // Select last page
-        verifyScrollStateChange(scrollToLast(true), expectedScrollStateChanges);
-        // Select first page
-        verifyScrollStateChange(scrollToFirst(true), expectedScrollStateChanges);
-    }
-
-    @Test
-    @LargeTest
-    public void testPageScrollStateChangedSwipe() {
-        // Note that all the actions tested in this method use swiping and as such we test
-        // that we get the matching calls to onPageScrollStateChanged
-        final int[] expectedScrollStateChanges = new int[] { ViewPager.SCROLL_STATE_DRAGGING,
-                ViewPager.SCROLL_STATE_SETTLING, ViewPager.SCROLL_STATE_IDLE };
-
-        // Swipe one page to the left
-        verifyScrollStateChange(wrap(swipeLeft()), expectedScrollStateChanges);
-        assertEquals("Swipe left", 1, mViewPager.getCurrentItem());
-
-        // Swipe one more page to the left
-        verifyScrollStateChange(wrap(swipeLeft()), expectedScrollStateChanges);
-        assertEquals("Swipe left", 2, mViewPager.getCurrentItem());
-
-        // Swipe one page to the right
-        verifyScrollStateChange(wrap(swipeRight()), expectedScrollStateChanges);
-        assertEquals("Swipe right", 1, mViewPager.getCurrentItem());
-
-        // Swipe one more page to the right
-        verifyScrollStateChange(wrap(swipeRight()), expectedScrollStateChanges);
-        assertEquals("Swipe right", 0, mViewPager.getCurrentItem());
-    }
-
-    /**
-     * Helper method to verify the internal consistency of values passed to
-     * {@link ViewPager.OnPageChangeListener#onPageScrolled} callback when we go from a page with
-     * lower index to a page with higher index.
-     *
-     * @param startPageIndex Index of the starting page.
-     * @param endPageIndex Index of the ending page.
-     * @param pageWidth Page width in pixels.
-     * @param positions List of "position" values passed to all
-     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
-     * @param positionOffsets List of "positionOffset" values passed to all
-     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
-     * @param positionOffsetPixels List of "positionOffsetPixel" values passed to all
-     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
-     */
-    private void verifyScrollCallbacksToHigherPage(int startPageIndex, int endPageIndex,
-            int pageWidth, List<Integer> positions, List<Float> positionOffsets,
-            List<Integer> positionOffsetPixels) {
-        int callbackCount = positions.size();
-
-        // The last entry in all three lists must match the index of the end page
-        Assert.assertEquals("Position at last index",
-                endPageIndex, (int) positions.get(callbackCount - 1));
-        Assert.assertEquals("Position offset at last index",
-                0.0f, positionOffsets.get(callbackCount - 1), 0.0f);
-        Assert.assertEquals("Position offset pixel at last index",
-                0, (int) positionOffsetPixels.get(callbackCount - 1));
-
-        // If this was our only callback, return. This can happen on immediate page change
-        // or on very slow devices.
-        if (callbackCount == 1) {
-            return;
-        }
-
-        // If we have additional callbacks, verify that the values provided to our callback reflect
-        // a valid sequence of events going from startPageIndex to endPageIndex.
-        for (int i = 0; i < callbackCount - 1; i++) {
-            // Page position must be between start page and end page
-            int pagePositionCurr = positions.get(i);
-            if ((pagePositionCurr < startPageIndex) || (pagePositionCurr > endPageIndex)) {
-                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
-                        ", but should be between " + startPageIndex + " and " + endPageIndex);
-            }
-
-            // Page position sequence cannot be decreasing
-            int pagePositionNext = positions.get(i + 1);
-            if (pagePositionCurr > pagePositionNext) {
-                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
-                        " and then decreases to " + pagePositionNext + " at #" + (i + 1));
-            }
-
-            // Position offset must be in [0..1) range (inclusive / exclusive)
-            float positionOffsetCurr = positionOffsets.get(i);
-            if ((positionOffsetCurr < 0.0f) || (positionOffsetCurr >= 1.0f)) {
-                Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
-                        ", but should be in [0..1) range");
-            }
-
-            // Position pixel offset must be in [0..pageWidth) range (inclusive / exclusive)
-            int positionOffsetPixelCurr = positionOffsetPixels.get(i);
-            if ((positionOffsetPixelCurr < 0.0f) || (positionOffsetPixelCurr >= pageWidth)) {
-                Assert.fail("Position pixel offset at #" + i + " is " + positionOffsetCurr +
-                        ", but should be in [0.." + pageWidth + ") range");
-            }
-
-            // Position pixel offset must match the position offset and page width within
-            // a one-pixel tolerance range
-            Assert.assertEquals("Position pixel offset at #" + i + " is " +
-                    positionOffsetPixelCurr + ", but doesn't match position offset which is" +
-                    positionOffsetCurr + " and page width which is " + pageWidth,
-                    positionOffsetPixelCurr, positionOffsetCurr * pageWidth, 1.0f);
-
-            // If we stay on the same page between this index and the next one, both position
-            // offset and position pixel offset must increase
-            if (pagePositionNext == pagePositionCurr) {
-                float positionOffsetNext = positionOffsets.get(i + 1);
-                // Note that since position offset sequence is float, we are checking for strict
-                // increasing
-                if (positionOffsetNext <= positionOffsetCurr) {
-                    Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
-                            " and at #" + (i + 1) + " is " + positionOffsetNext +
-                            ". Since both are for page " + pagePositionCurr +
-                            ", they cannot decrease");
-                }
-
-                int positionOffsetPixelNext = positionOffsetPixels.get(i + 1);
-                // Note that since position offset pixel sequence is the mapping of position offset
-                // into screen pixels, we can get two (or more) callbacks with strictly increasing
-                // position offsets that are converted into the same pixel value. This is why here
-                // we are checking for non-strict increasing
-                if (positionOffsetPixelNext < positionOffsetPixelCurr) {
-                    Assert.fail("Position offset pixel at #" + i + " is " +
-                            positionOffsetPixelCurr + " and at #" + (i + 1) + " is " +
-                            positionOffsetPixelNext + ". Since both are for page " +
-                            pagePositionCurr + ", they cannot decrease");
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper method to verify the internal consistency of values passed to
-     * {@link ViewPager.OnPageChangeListener#onPageScrolled} callback when we go from a page with
-     * higher index to a page with lower index.
-     *
-     * @param startPageIndex Index of the starting page.
-     * @param endPageIndex Index of the ending page.
-     * @param pageWidth Page width in pixels.
-     * @param positions List of "position" values passed to all
-     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
-     * @param positionOffsets List of "positionOffset" values passed to all
-     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
-     * @param positionOffsetPixels List of "positionOffsetPixel" values passed to all
-     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
-     */
-    private void verifyScrollCallbacksToLowerPage(int startPageIndex, int endPageIndex,
-            int pageWidth, List<Integer> positions, List<Float> positionOffsets,
-            List<Integer> positionOffsetPixels) {
-        int callbackCount = positions.size();
-
-        // The last entry in all three lists must match the index of the end page
-        Assert.assertEquals("Position at last index",
-                endPageIndex, (int) positions.get(callbackCount - 1));
-        Assert.assertEquals("Position offset at last index",
-                0.0f, positionOffsets.get(callbackCount - 1), 0.0f);
-        Assert.assertEquals("Position offset pixel at last index",
-                0, (int) positionOffsetPixels.get(callbackCount - 1));
-
-        // If this was our only callback, return. This can happen on immediate page change
-        // or on very slow devices.
-        if (callbackCount == 1) {
-            return;
-        }
-
-        // If we have additional callbacks, verify that the values provided to our callback reflect
-        // a valid sequence of events going from startPageIndex to endPageIndex.
-        for (int i = 0; i < callbackCount - 1; i++) {
-            // Page position must be between start page and end page
-            int pagePositionCurr = positions.get(i);
-            if ((pagePositionCurr > startPageIndex) || (pagePositionCurr < endPageIndex)) {
-                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
-                        ", but should be between " + endPageIndex + " and " + startPageIndex);
-            }
-
-            // Page position sequence cannot be increasing
-            int pagePositionNext = positions.get(i + 1);
-            if (pagePositionCurr < pagePositionNext) {
-                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
-                        " and then increases to " + pagePositionNext + " at #" + (i + 1));
-            }
-
-            // Position offset must be in [0..1) range (inclusive / exclusive)
-            float positionOffsetCurr = positionOffsets.get(i);
-            if ((positionOffsetCurr < 0.0f) || (positionOffsetCurr >= 1.0f)) {
-                Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
-                        ", but should be in [0..1) range");
-            }
-
-            // Position pixel offset must be in [0..pageWidth) range (inclusive / exclusive)
-            int positionOffsetPixelCurr = positionOffsetPixels.get(i);
-            if ((positionOffsetPixelCurr < 0.0f) || (positionOffsetPixelCurr >= pageWidth)) {
-                Assert.fail("Position pixel offset at #" + i + " is " + positionOffsetCurr +
-                        ", but should be in [0.." + pageWidth + ") range");
-            }
-
-            // Position pixel offset must match the position offset and page width within
-            // a one-pixel tolerance range
-            Assert.assertEquals("Position pixel offset at #" + i + " is " +
-                            positionOffsetPixelCurr + ", but doesn't match position offset which is" +
-                            positionOffsetCurr + " and page width which is " + pageWidth,
-                    positionOffsetPixelCurr, positionOffsetCurr * pageWidth, 1.0f);
-
-            // If we stay on the same page between this index and the next one, both position
-            // offset and position pixel offset must decrease
-            if (pagePositionNext == pagePositionCurr) {
-                float positionOffsetNext = positionOffsets.get(i + 1);
-                // Note that since position offset sequence is float, we are checking for strict
-                // decreasing
-                if (positionOffsetNext >= positionOffsetCurr) {
-                    Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
-                            " and at #" + (i + 1) + " is " + positionOffsetNext +
-                            ". Since both are for page " + pagePositionCurr +
-                            ", they cannot increase");
-                }
-
-                int positionOffsetPixelNext = positionOffsetPixels.get(i + 1);
-                // Note that since position offset pixel sequence is the mapping of position offset
-                // into screen pixels, we can get two (or more) callbacks with strictly decreasing
-                // position offsets that are converted into the same pixel value. This is why here
-                // we are checking for non-strict decreasing
-                if (positionOffsetPixelNext > positionOffsetPixelCurr) {
-                    Assert.fail("Position offset pixel at #" + i + " is " +
-                            positionOffsetPixelCurr + " and at #" + (i + 1) + " is " +
-                            positionOffsetPixelNext + ". Since both are for page " +
-                            pagePositionCurr + ", they cannot increase");
-                }
-            }
-        }
-    }
-
-    private void verifyScrollCallbacksToHigherPage(ViewAction viewAction,
-            int expectedEndPageIndex) {
-        final int startPageIndex = mViewPager.getCurrentItem();
-
-        ViewPager.OnPageChangeListener mockPageChangeListener =
-                mock(ViewPager.OnPageChangeListener.class);
-        mViewPager.addOnPageChangeListener(mockPageChangeListener);
-
-        // Perform our action
-        onView(withId(R.id.pager)).perform(viewAction);
-
-        final int endPageIndex = mViewPager.getCurrentItem();
-        Assert.assertEquals("Current item after action", expectedEndPageIndex, endPageIndex);
-
-        ArgumentCaptor<Integer> positionCaptor = ArgumentCaptor.forClass(int.class);
-        ArgumentCaptor<Float> positionOffsetCaptor = ArgumentCaptor.forClass(float.class);
-        ArgumentCaptor<Integer> positionOffsetPixelsCaptor = ArgumentCaptor.forClass(int.class);
-        verify(mockPageChangeListener, atLeastOnce()).onPageScrolled(positionCaptor.capture(),
-                positionOffsetCaptor.capture(), positionOffsetPixelsCaptor.capture());
-
-        verifyScrollCallbacksToHigherPage(startPageIndex, endPageIndex, mViewPager.getWidth(),
-                positionCaptor.getAllValues(), positionOffsetCaptor.getAllValues(),
-                positionOffsetPixelsCaptor.getAllValues());
-
-        // Remove our mock listener to get back to clean state for the next test
-        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
-    }
-
-    private void verifyScrollCallbacksToLowerPage(ViewAction viewAction,
-            int expectedEndPageIndex) {
-        final int startPageIndex = mViewPager.getCurrentItem();
-
-        ViewPager.OnPageChangeListener mockPageChangeListener =
-                mock(ViewPager.OnPageChangeListener.class);
-        mViewPager.addOnPageChangeListener(mockPageChangeListener);
-
-        // Perform our action
-        onView(withId(R.id.pager)).perform(viewAction);
-
-        final int endPageIndex = mViewPager.getCurrentItem();
-        Assert.assertEquals("Current item after action", expectedEndPageIndex, endPageIndex);
-
-        ArgumentCaptor<Integer> positionCaptor = ArgumentCaptor.forClass(int.class);
-        ArgumentCaptor<Float> positionOffsetCaptor = ArgumentCaptor.forClass(float.class);
-        ArgumentCaptor<Integer> positionOffsetPixelsCaptor = ArgumentCaptor.forClass(int.class);
-        verify(mockPageChangeListener, atLeastOnce()).onPageScrolled(positionCaptor.capture(),
-                positionOffsetCaptor.capture(), positionOffsetPixelsCaptor.capture());
-
-        verifyScrollCallbacksToLowerPage(startPageIndex, endPageIndex, mViewPager.getWidth(),
-                positionCaptor.getAllValues(), positionOffsetCaptor.getAllValues(),
-                positionOffsetPixelsCaptor.getAllValues());
-
-        // Remove our mock listener to get back to clean state for the next test
-        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
-    }
-
-    @Test
-    @MediumTest
-    public void testPageScrollPositionChangesImmediate() {
-        // Scroll one page to the right
-        verifyScrollCallbacksToHigherPage(scrollRight(false), 1);
-        // Scroll one more page to the right
-        verifyScrollCallbacksToHigherPage(scrollRight(false), 2);
-        // Scroll one page to the left
-        verifyScrollCallbacksToLowerPage(scrollLeft(false), 1);
-        // Scroll one more page to the left
-        verifyScrollCallbacksToLowerPage(scrollLeft(false), 0);
-
-        // Scroll to the last page
-        verifyScrollCallbacksToHigherPage(scrollToLast(false), 2);
-        // Scroll to the first page
-        verifyScrollCallbacksToLowerPage(scrollToFirst(false), 0);
-    }
-
-    @Test
-    @LargeTest
-    public void testPageScrollPositionChangesSmooth() {
-        // Scroll one page to the right
-        verifyScrollCallbacksToHigherPage(scrollRight(true), 1);
-        // Scroll one more page to the right
-        verifyScrollCallbacksToHigherPage(scrollRight(true), 2);
-        // Scroll one page to the left
-        verifyScrollCallbacksToLowerPage(scrollLeft(true), 1);
-        // Scroll one more page to the left
-        verifyScrollCallbacksToLowerPage(scrollLeft(true), 0);
-
-        // Scroll to the last page
-        verifyScrollCallbacksToHigherPage(scrollToLast(true), 2);
-        // Scroll to the first page
-        verifyScrollCallbacksToLowerPage(scrollToFirst(true), 0);
-    }
-
-    @Test
-    @LargeTest
-    public void testPageScrollPositionChangesSwipe() {
-        // Swipe one page to the left
-        verifyScrollCallbacksToHigherPage(wrap(swipeLeft()), 1);
-        // Swipe one more page to the left
-        verifyScrollCallbacksToHigherPage(wrap(swipeLeft()), 2);
-        // Swipe one page to the right
-        verifyScrollCallbacksToLowerPage(wrap(swipeRight()), 1);
-        // Swipe one more page to the right
-        verifyScrollCallbacksToLowerPage(wrap(swipeRight()), 0);
-    }
-
-    @FlakyTest(bugId = 38260187)
-    @Test
-    @LargeTest
-    public void testKeyboardNavigation() {
-        ButtonPagerAdapter adapter = new ButtonPagerAdapter();
-        adapter.add("Red", Color.RED);
-        adapter.add("Green", Color.GREEN);
-        adapter.add("Blue", Color.BLUE);
-        onView(withId(R.id.pager)).perform(setAdapter(adapter), scrollToPage(0, false));
-        View firstButton = adapter.getButton(0, 0);
-        firstButton.requestFocus();
-        assertTrue(firstButton.isFocused());
-        assertEquals(0, mViewPager.getCurrentItem());
-
-        // Normal arrows should traverse contents first
-        onView(is(firstButton)).perform(pressKey(KeyEvent.KEYCODE_DPAD_RIGHT));
-        assertEquals(0, mViewPager.getCurrentItem());
-        assertTrue(adapter.getButton(0, 1).isFocused());
-
-        // Alt arrows should change page even if there are more focusables in that direction
-        onView(is(adapter.getButton(0, 1))).perform(pressKey(new EspressoKey.Builder()
-                .withAltPressed(true).withKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT).build()));
-        assertEquals(1, mViewPager.getCurrentItem());
-        assertTrue(adapter.getButton(1, 0).isFocused());
-
-        // Normal arrows should change page if there are no more focusables in that direction
-        onView(is(adapter.getButton(1, 0))).perform(pressKey(KeyEvent.KEYCODE_DPAD_LEFT));
-        assertEquals(0, mViewPager.getCurrentItem());
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTabStripActivity.java b/core-ui/tests/java/android/support/v4/view/ViewPagerWithTabStripActivity.java
deleted file mode 100644
index 55fd51e..0000000
--- a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTabStripActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.coreui.test.R;
-import android.view.WindowManager;
-
-public class ViewPagerWithTabStripActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        setContentView(R.layout.view_pager_with_tab_strip);
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTabStripTest.java b/core-ui/tests/java/android/support/v4/view/ViewPagerWithTabStripTest.java
deleted file mode 100644
index cd26461..0000000
--- a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTabStripTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v4.view;
-
-import android.support.coreui.test.R;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.v4.view.ViewPagerActions.clickBetweenTwoTitles;
-import static android.support.v4.view.ViewPagerActions.scrollRight;
-import static android.support.v4.view.ViewPagerActions.scrollToPage;
-import static org.hamcrest.Matchers.allOf;
-import static org.junit.Assert.assertEquals;
-
-/**
- * Provides assertions that depend on the interactive nature of <code>PagerTabStrip</code>.
- */
-public class ViewPagerWithTabStripTest extends BaseViewPagerTest<ViewPagerWithTabStripActivity> {
-    public ViewPagerWithTabStripTest() {
-        super(ViewPagerWithTabStripActivity.class);
-    }
-
-    @Override
-    protected Class getStripClass() {
-        return PagerTabStrip.class;
-    }
-
-    @Override
-    protected void assertStripInteraction(boolean smoothScroll) {
-        // The following block tests that ViewPager page selection changes on clicking titles of
-        // various tabs as PagerTabStrip is interactive
-
-        // Click the tab title for page #0 and verify that we're still on page #0
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
-        assertEquals("Click tab #0 on tab #0", 0, mViewPager.getCurrentItem());
-
-        // Click the tab title for page #1 and verify that we're on page #1
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
-        assertEquals("Click tab #1 on tab #0", 1, mViewPager.getCurrentItem());
-
-        // Click the tab title for page #0 and verify that we're on page #0
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
-        assertEquals("Click tab #0 on tab #1", 0, mViewPager.getCurrentItem());
-
-        // Go back to page #1
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-
-        // Click the tab title for page #1 and verify that we're still on page #1
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
-        assertEquals("Click tab #1 on tab #1", 1, mViewPager.getCurrentItem());
-
-        // Click the tab title for page #2 and verify that we're on page #2
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Blue"))).perform(click());
-        assertEquals("Click tab #2 on tab #1", 2, mViewPager.getCurrentItem());
-
-        // The following block tests that ViewPager page selection changes on clicking in
-        // between titles of tabs as that functionality is exposed by PagerTabStrip
-
-        // Scroll back to page #0
-        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
-
-        // Click between titles of page #0 and page #1 and verify that we're on page #1
-        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
-        assertEquals("Click in between tabs #0 and #1 on tab #0", 1, mViewPager.getCurrentItem());
-
-        // Click between titles of page #0 and page #1 and verify that we're on page #0
-        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
-        assertEquals("Click in between tabs #0 and #1 on tab #1", 0, mViewPager.getCurrentItem());
-
-        // Go back to page #1
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-
-        // Click between titles of page #1 and page #2 and verify that we're on page #2
-        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Green", "Blue"));
-        assertEquals("Click in between tabs #1 and #2 on tab #1", 2, mViewPager.getCurrentItem());
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java b/core-ui/tests/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java
deleted file mode 100644
index e5a62a1..0000000
--- a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.view;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.coreui.test.R;
-import android.view.WindowManager;
-
-public class ViewPagerWithTitleStripActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        setContentView(R.layout.view_pager_with_title_strip);
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTitleStripTest.java b/core-ui/tests/java/android/support/v4/view/ViewPagerWithTitleStripTest.java
deleted file mode 100644
index d54992c..0000000
--- a/core-ui/tests/java/android/support/v4/view/ViewPagerWithTitleStripTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v4.view;
-
-import android.support.coreui.test.R;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.v4.view.ViewPagerActions.clickBetweenTwoTitles;
-import static android.support.v4.view.ViewPagerActions.scrollRight;
-import static android.support.v4.view.ViewPagerActions.scrollToPage;
-import static org.hamcrest.Matchers.allOf;
-import static org.junit.Assert.assertEquals;
-
-/**
- * Provides assertions that depend on the non-interactive nature of <code>PagerTabStrip</code>.
- */
-public class ViewPagerWithTitleStripTest
-        extends BaseViewPagerTest<ViewPagerWithTitleStripActivity> {
-    public ViewPagerWithTitleStripTest() {
-        super(ViewPagerWithTitleStripActivity.class);
-    }
-
-    @Override
-    protected Class getStripClass() {
-        return PagerTitleStrip.class;
-    }
-
-    @Override
-    protected void assertStripInteraction(boolean smoothScroll) {
-        // The following block tests that nothing happens on clicking titles of various tabs
-        // as PagerTitleStrip is not interactive
-
-        // Click the tab title for page #0 and verify that we're still on page #0
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
-        assertEquals("Click tab #0 on tab #0", 0, mViewPager.getCurrentItem());
-
-        // Click the tab title for page #1 and verify that we're still on page #0
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
-        assertEquals("Click tab #1 on tab #0", 0, mViewPager.getCurrentItem());
-
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-
-        // Click the tab title for page #0 and verify that we're still on page #1
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
-        assertEquals("Click tab #0 on tab #1", 1, mViewPager.getCurrentItem());
-
-        // Click the tab title for page #1 and verify that we're still on page #1
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
-        assertEquals("Click tab #1 on tab #1", 1, mViewPager.getCurrentItem());
-
-        // Click the tab title for page #2 and verify that we're still on page #1
-        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Blue"))).perform(click());
-        assertEquals("Click tab #2 on tab #1", 1, mViewPager.getCurrentItem());
-
-
-        // The following block tests that nothing happens on clicking in between titles of various
-        // tabs as PagerTitleStrip is not interactive
-
-        // Scroll back to page #0
-        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
-
-        // Click between titles of page #0 and page #1 and verify that we're still on page #0
-        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
-        assertEquals("Click in between tabs #0 and #1 on tab #0", 0, mViewPager.getCurrentItem());
-
-        // Go to page #1
-        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
-
-        // Click between titles of page #1 and page #2 and verify that we're still on page #1
-        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Green", "Blue"));
-        assertEquals("Click in between tabs #1 and #2 on tab #1", 1, mViewPager.getCurrentItem());
-
-        // Click between titles of page #0 and page #1 and verify that we're still on page #1
-        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
-        assertEquals("Click in between tabs #0 and #1 on tab #1", 1, mViewPager.getCurrentItem());
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/CircularProgressDrawableActivity.java b/core-ui/tests/java/android/support/v4/widget/CircularProgressDrawableActivity.java
deleted file mode 100644
index 743cd7d..0000000
--- a/core-ui/tests/java/android/support/v4/widget/CircularProgressDrawableActivity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.support.coreui.test.R;
-import android.support.v4.BaseTestActivity;
-
-public class CircularProgressDrawableActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.circular_progress_drawable_activity;
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/CircularProgressDrawableTest.java b/core-ui/tests/java/android/support/v4/widget/CircularProgressDrawableTest.java
deleted file mode 100644
index cf31952..0000000
--- a/core-ui/tests/java/android/support/v4/widget/CircularProgressDrawableTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyFloat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.support.test.filters.SmallTest;
-import android.support.v4.BaseInstrumentationTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-
-/**
- * Tests for CircularProgressDrawable
- */
-public class CircularProgressDrawableTest extends
-        BaseInstrumentationTestCase<CircularProgressDrawableActivity> {
-
-    public CircularProgressDrawableTest() {
-        super(CircularProgressDrawableActivity.class);
-    }
-
-    private CircularProgressDrawable mDrawableUnderTest;
-
-    @Mock
-    Canvas mMockCanvas;
-
-    @Before
-    public void setUp() {
-        Context context = mActivityTestRule.getActivity().getApplicationContext();
-        mMockCanvas = mock(Canvas.class);
-        mDrawableUnderTest = new CircularProgressDrawable(context);
-    }
-
-    @Test
-    @SmallTest
-    public void sizeIsSquareBasedOnSmallerEdgeWithNoCenterRadius() {
-        int width = 100;
-        int height = 50;
-        mDrawableUnderTest.setBounds(new Rect(0, 0, width, height));
-        mDrawableUnderTest.draw(mMockCanvas);
-
-        ArgumentCaptor<RectF> captor = ArgumentCaptor.forClass(RectF.class);
-        verify(mMockCanvas).drawArc(captor.capture(), anyFloat(), anyFloat(), anyBoolean(),
-                any(Paint.class));
-
-        assertTrue(captor.getValue().width() == captor.getValue().height());
-        assertTrue(captor.getValue().width() <= width);
-        assertTrue(captor.getValue().width() <= height);
-    }
-
-    @Test
-    @SmallTest
-    public void setCenterRadiusFixesSize() {
-        float radius = 10f;
-        float strokeWidth = 4f;
-        mDrawableUnderTest.setCenterRadius(radius);
-        mDrawableUnderTest.setStrokeWidth(strokeWidth);
-        mDrawableUnderTest.setBounds(new Rect(0, 0, 100, 50));
-        mDrawableUnderTest.draw(mMockCanvas);
-
-        ArgumentCaptor<RectF> boundsCaptor = ArgumentCaptor.forClass(RectF.class);
-        verify(mMockCanvas).drawArc(boundsCaptor.capture(), anyFloat(), anyFloat(), anyBoolean(),
-                any(Paint.class));
-
-        assertEquals((radius + strokeWidth / 2f) * 2, boundsCaptor.getValue().width(), 0.5);
-        assertEquals((radius + strokeWidth / 2f) * 2, boundsCaptor.getValue().height(), 0.5);
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/ContentLoadingProgressBarActivity.java b/core-ui/tests/java/android/support/v4/widget/ContentLoadingProgressBarActivity.java
deleted file mode 100644
index 7eb2342..0000000
--- a/core-ui/tests/java/android/support/v4/widget/ContentLoadingProgressBarActivity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.support.coreui.test.R;
-import android.support.v4.BaseTestActivity;
-
-public class ContentLoadingProgressBarActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.content_loading_progress_bar_activity;
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/ContentLoadingProgressBarTest.java b/core-ui/tests/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
deleted file mode 100644
index 837bf33..0000000
--- a/core-ui/tests/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import static org.junit.Assert.assertEquals;
-
-import android.support.coreui.test.R;
-import android.support.test.filters.LargeTest;
-import android.support.testutils.PollingCheck;
-import android.support.v4.BaseInstrumentationTestCase;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Tests for {@link ContentLoadingProgressBar}
- */
-public class ContentLoadingProgressBarTest extends
-        BaseInstrumentationTestCase<ContentLoadingProgressBarActivity> {
-
-    public ContentLoadingProgressBarTest() {
-        super(ContentLoadingProgressBarActivity.class);
-    }
-
-    private ContentLoadingProgressBar mContentLoadingProgressBar;
-
-    @Before
-    public void setUp() {
-        mContentLoadingProgressBar = mActivityTestRule.getActivity().findViewById(R.id.progressBar);
-    }
-
-    @Test
-    @LargeTest
-    public void showAndThenLaterHide() {
-        mContentLoadingProgressBar.show();
-
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mContentLoadingProgressBar.getVisibility() == View.VISIBLE;
-            }
-        });
-
-        mContentLoadingProgressBar.hide();
-
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mContentLoadingProgressBar.getVisibility() == View.GONE;
-            }
-        });
-    }
-
-    @Test
-    @LargeTest
-    public void showAndImmediatelyHide() {
-        mContentLoadingProgressBar.show();
-        mContentLoadingProgressBar.hide();
-
-        // show() followed immediately by hide() should leave the progress bar in GONE state
-        assertEquals(mContentLoadingProgressBar.getVisibility(), View.GONE);
-
-        // The next show() should eventually show the progress bar
-        mContentLoadingProgressBar.show();
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mContentLoadingProgressBar.getVisibility() == View.VISIBLE;
-            }
-        });
-
-
-        // The next hide() should eventually hide the progress bar
-        mContentLoadingProgressBar.hide();
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mContentLoadingProgressBar.getVisibility() == View.GONE;
-            }
-        });
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTest.java b/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTest.java
deleted file mode 100644
index d78b49b..0000000
--- a/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTest.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
-
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.coreui.test.R;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-import android.support.v4.BaseInstrumentationTestCase;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.List;
-
-@SmallTest
-public class ExploreByTouchHelperTest extends BaseInstrumentationTestCase<ExploreByTouchHelperTestActivity> {
-    private View mHost;
-
-    public ExploreByTouchHelperTest() {
-        super(ExploreByTouchHelperTestActivity.class);
-    }
-
-    @Before
-    public void setUp() {
-        // Accessibility delegates are only supported on API 14+.
-        assumeTrue(Build.VERSION.SDK_INT >= 14);
-        mHost = mActivityTestRule.getActivity().findViewById(R.id.host_view);
-    }
-
-    @Test
-    @UiThreadTest
-    public void testBoundsInScreen() {
-        final ExploreByTouchHelper helper = new ParentBoundsHelper(mHost);
-        ViewCompat.setAccessibilityDelegate(mHost, helper);
-
-        final AccessibilityNodeInfoCompat node =
-                helper.getAccessibilityNodeProvider(mHost).createAccessibilityNodeInfo(1);
-        assertNotNull(node);
-
-        final Rect hostBounds = new Rect();
-        mHost.getLocalVisibleRect(hostBounds);
-        assertFalse("Host has not been laid out", hostBounds.isEmpty());
-
-        final Rect nodeBoundsInParent = new Rect();
-        node.getBoundsInParent(nodeBoundsInParent);
-        assertEquals("Wrong bounds in parent", hostBounds, nodeBoundsInParent);
-
-        final Rect hostBoundsOnScreen = getBoundsOnScreen(mHost);
-        final Rect nodeBoundsInScreen = new Rect();
-        node.getBoundsInScreen(nodeBoundsInScreen);
-        assertEquals("Wrong bounds in screen", hostBoundsOnScreen, nodeBoundsInScreen);
-
-        final int scrollX = 100;
-        final int scrollY = 50;
-        mHost.scrollTo(scrollX, scrollY);
-
-        // Generate a node for the new position.
-        final AccessibilityNodeInfoCompat scrolledNode =
-                helper.getAccessibilityNodeProvider(mHost).createAccessibilityNodeInfo(1);
-        assertNotNull(scrolledNode);
-
-        // Bounds in parent should not be affected by visibility.
-        final Rect scrolledNodeBoundsInParent = new Rect();
-        scrolledNode.getBoundsInParent(scrolledNodeBoundsInParent);
-        assertEquals("Wrong bounds in parent after scrolling",
-                hostBounds, scrolledNodeBoundsInParent);
-
-        final Rect expectedBoundsInScreen = new Rect(hostBoundsOnScreen);
-        expectedBoundsInScreen.offset(-scrollX, -scrollY);
-        expectedBoundsInScreen.intersect(hostBoundsOnScreen);
-        scrolledNode.getBoundsInScreen(nodeBoundsInScreen);
-        assertEquals("Wrong bounds in screen after scrolling",
-                expectedBoundsInScreen, nodeBoundsInScreen);
-
-        ViewCompat.setAccessibilityDelegate(mHost, null);
-    }
-
-    private static Rect getBoundsOnScreen(View v) {
-        final int[] tempLocation = new int[2];
-        final Rect hostBoundsOnScreen = new Rect(0, 0, v.getWidth(), v.getHeight());
-        v.getLocationOnScreen(tempLocation);
-        hostBoundsOnScreen.offset(tempLocation[0], tempLocation[1]);
-        return hostBoundsOnScreen;
-    }
-
-    /**
-     * An extension of ExploreByTouchHelper that contains a single virtual view
-     * whose bounds match the host view.
-     */
-    private static class ParentBoundsHelper extends ExploreByTouchHelper {
-        private final View mHost;
-
-        ParentBoundsHelper(View host) {
-            super(host);
-
-            mHost = host;
-        }
-
-        @Override
-        protected int getVirtualViewAt(float x, float y) {
-            return 1;
-        }
-
-        @Override
-        protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
-            virtualViewIds.add(1);
-        }
-
-        @Override
-        protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfoCompat node) {
-            if (virtualViewId == 1) {
-                node.setContentDescription("test");
-
-                final Rect hostBounds = new Rect(0, 0, mHost.getWidth(), mHost.getHeight());
-                node.setBoundsInParent(hostBounds);
-            }
-        }
-
-        @Override
-        protected boolean onPerformActionForVirtualView(int virtualViewId, int action, Bundle arguments) {
-            return false;
-        }
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTestActivity.java b/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTestActivity.java
deleted file mode 100644
index 19d1598..0000000
--- a/core-ui/tests/java/android/support/v4/widget/ExploreByTouchHelperTestActivity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.support.coreui.test.R;
-import android.support.v4.BaseTestActivity;
-
-public class ExploreByTouchHelperTestActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.explore_by_touch_helper_activity;
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutActivity.java b/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutActivity.java
deleted file mode 100644
index f9245bc..0000000
--- a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutActivity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import android.support.coreui.test.R;
-import android.support.v4.BaseTestActivity;
-
-public class SwipeRefreshLayoutActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.swipe_refresh_layout_activity;
-    }
-}
diff --git a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java b/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
deleted file mode 100644
index 04a2835..0000000
--- a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.widget;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.v4.widget.SwipeRefreshLayoutActions.setEnabled;
-import static android.support.v4.widget.SwipeRefreshLayoutActions.setRefreshing;
-import static android.support.v4.widget.SwipeRefreshLayoutActions.setSize;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.support.coreui.test.R;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.testutils.PollingCheck;
-import android.support.v4.BaseInstrumentationTestCase;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Tests SwipeRefreshLayout widget.
- */
-public class SwipeRefreshLayoutTest
-        extends BaseInstrumentationTestCase<SwipeRefreshLayoutActivity> {
-    private static final long TIMEOUT = 1000;
-    private static final int INVALID_SIZE = 1000;
-
-    private SwipeRefreshLayout mSwipeRefresh;
-
-    public SwipeRefreshLayoutTest() {
-        super(SwipeRefreshLayoutActivity.class);
-    }
-
-    @Before
-    public void setUp() {
-        mSwipeRefresh = (SwipeRefreshLayout) mActivityTestRule.getActivity().findViewById(
-                R.id.swipe_refresh);
-    }
-
-    @Test
-    @MediumTest
-    public void testStartAndStopRefreshing() throws Throwable {
-        SwipeRefreshLayout.OnRefreshListener mockListener =
-                mock(SwipeRefreshLayout.OnRefreshListener.class);
-        mSwipeRefresh.setOnRefreshListener(mockListener);
-
-        assertFalse(mSwipeRefresh.isRefreshing());
-        for (int i = 0; i < 5; i++) {
-            onView(withId(R.id.swipe_refresh)).perform(setRefreshing());
-            assertTrue(mSwipeRefresh.isRefreshing());
-
-            // onView(..).perform(..) does not work when views are animated.
-            // Therefore this is using a posted task to turn off refreshing.
-            mSwipeRefresh.getHandler().post(new Runnable() {
-                @Override
-                public void run() {
-                    mSwipeRefresh.setRefreshing(false);
-                }
-            });
-
-            PollingCheck.waitFor(TIMEOUT, new PollingCheck.PollingCheckCondition() {
-                @Override
-                public boolean canProceed() {
-                    return !mSwipeRefresh.isRefreshing();
-                }
-            });
-        }
-        verify(mockListener, times(0)).onRefresh();
-    }
-
-    @Test
-    @MediumTest
-    public void testSwipeDownToRefresh() throws Throwable {
-        assertFalse(mSwipeRefresh.isRefreshing());
-
-        swipeToRefreshVerifyThenStopRefreshing(true);
-    }
-
-    @Test
-    @SmallTest
-    public void testSetSize() throws Throwable {
-        float density = mSwipeRefresh.getResources().getDisplayMetrics().density;
-        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
-                mSwipeRefresh.getProgressCircleDiameter());
-        onView(withId(R.id.swipe_refresh)).perform(setSize(SwipeRefreshLayout.LARGE));
-        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER_LARGE * density),
-                mSwipeRefresh.getProgressCircleDiameter());
-        onView(withId(R.id.swipe_refresh)).perform(setSize(SwipeRefreshLayout.DEFAULT));
-        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
-                mSwipeRefresh.getProgressCircleDiameter());
-        onView(withId(R.id.swipe_refresh)).perform(setSize(SwipeRefreshLayout.DEFAULT));
-        onView(withId(R.id.swipe_refresh)).perform(setSize(INVALID_SIZE));
-        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
-                mSwipeRefresh.getProgressCircleDiameter());
-    }
-
-    @Test
-    @SmallTest
-    public void testSetOnChildScrollUpCallback() throws Throwable {
-        SwipeRefreshLayout.OnChildScrollUpCallback mockCallback =
-                mock(SwipeRefreshLayout.OnChildScrollUpCallback.class);
-        when(mockCallback.canChildScrollUp(eq(mSwipeRefresh), any(View.class)))
-                .thenReturn(true)
-                .thenReturn(true)
-                .thenReturn(false)
-                .thenReturn(false);
-        mSwipeRefresh.setOnChildScrollUpCallback(mockCallback);
-        assertTrue(mSwipeRefresh.canChildScrollUp());
-        assertTrue(mSwipeRefresh.canChildScrollUp());
-        assertFalse(mSwipeRefresh.canChildScrollUp());
-        assertFalse(mSwipeRefresh.canChildScrollUp());
-    }
-
-    @Test
-    @LargeTest
-    public void testSwipeDownToRefreshInitiallyDisabled() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivityTestRule.getActivity().setContentView(
-                        R.layout.swipe_refresh_layout_disabled_activity);
-            }
-        });
-        mSwipeRefresh = (SwipeRefreshLayout) mActivityTestRule.getActivity().findViewById(
-                R.id.swipe_refresh);
-
-        assertFalse(mSwipeRefresh.isRefreshing());
-
-        swipeToRefreshVerifyThenStopRefreshing(false);
-
-        onView(withId(R.id.swipe_refresh)).perform(setEnabled(true));
-
-        swipeToRefreshVerifyThenStopRefreshing(true);
-    }
-
-    private void swipeToRefreshVerifyThenStopRefreshing(boolean expectRefreshing) throws Throwable {
-        final CountDownLatch latch = new CountDownLatch(1);
-        SwipeRefreshLayout.OnRefreshListener listener = new SwipeRefreshLayout.OnRefreshListener() {
-            @Override
-            public void onRefresh() {
-                latch.countDown();
-                assertTrue(mSwipeRefresh.isRefreshing());
-                mSwipeRefresh.setRefreshing(false);
-            }
-        };
-        mSwipeRefresh.setOnRefreshListener(listener);
-        onView(withId(R.id.content)).perform(ViewActions.swipeDown());
-        if (expectRefreshing) {
-            assertTrue("SwipeRefreshLayout never started refreshing",
-                    latch.await(500, TimeUnit.MILLISECONDS));
-        } else {
-            assertFalse("SwipeRefreshLayout unexpectedly started refreshing",
-                    latch.await(500, TimeUnit.MILLISECONDS));
-        }
-    }
-}
diff --git a/core-ui/tests/res/anim/fade_in.xml b/core-ui/tests/res/anim/fade_in.xml
deleted file mode 100644
index 92d5bbe..0000000
--- a/core-ui/tests/res/anim/fade_in.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-       android:duration="300"
-       android:fromAlpha="0.0"
-       android:toAlpha="1.0"/>
diff --git a/core-ui/tests/res/anim/fade_out.xml b/core-ui/tests/res/anim/fade_out.xml
deleted file mode 100644
index bc5a2ab..0000000
--- a/core-ui/tests/res/anim/fade_out.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
--->
-
-<alpha xmlns:android="http://schemas.android.com/apk/res/android"
-       android:duration="300"
-       android:fromAlpha="1.0"
-       android:toAlpha="0.0"/>
diff --git a/core-ui/tests/res/anim/long_fade_in.xml b/core-ui/tests/res/anim/long_fade_in.xml
deleted file mode 100644
index 5d6f496..0000000
--- a/core-ui/tests/res/anim/long_fade_in.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>

-

-<alpha xmlns:android="http://schemas.android.com/apk/res/android"

-       android:interpolator="@android:interpolator/decelerate_quad"

-       android:fromAlpha="0.0" android:toAlpha="1.0"

-       android:duration="5000" />

diff --git a/core-ui/tests/res/anim/long_fade_out.xml b/core-ui/tests/res/anim/long_fade_out.xml
deleted file mode 100644
index fe9fc6a..0000000
--- a/core-ui/tests/res/anim/long_fade_out.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>

-

-<alpha xmlns:android="http://schemas.android.com/apk/res/android"

-       android:interpolator="@android:interpolator/decelerate_quad"

-       android:fromAlpha="1.0" android:toAlpha="0.0"

-       android:duration="5000" />

diff --git a/core-ui/tests/res/layout/activity_content.xml b/core-ui/tests/res/layout/activity_content.xml
deleted file mode 100644
index 8870e60..0000000
--- a/core-ui/tests/res/layout/activity_content.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/content"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"/>
diff --git a/core-ui/tests/res/layout/fragment_a.xml b/core-ui/tests/res/layout/fragment_a.xml
deleted file mode 100644
index 38e0423..0000000
--- a/core-ui/tests/res/layout/fragment_a.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textA"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/core-ui/tests/res/layout/fragment_b.xml b/core-ui/tests/res/layout/fragment_b.xml
deleted file mode 100644
index d8ed961..0000000
--- a/core-ui/tests/res/layout/fragment_b.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textB"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/core-ui/tests/res/layout/fragment_c.xml b/core-ui/tests/res/layout/fragment_c.xml
deleted file mode 100644
index ed3c753..0000000
--- a/core-ui/tests/res/layout/fragment_c.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textC"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/core-ui/tests/res/layout/fragment_end.xml b/core-ui/tests/res/layout/fragment_end.xml
deleted file mode 100644
index aa3d9e8..0000000
--- a/core-ui/tests/res/layout/fragment_end.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:transitionName="destination"
-              android:id="@+id/hello"
-              android:text="@string/hello"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#0F0"
-          android:id="@+id/greenSquare"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#F00"
-          android:id="@+id/redSquare"/>
-</LinearLayout>
diff --git a/core-ui/tests/res/layout/fragment_middle.xml b/core-ui/tests/res/layout/fragment_middle.xml
deleted file mode 100644
index 7d1409b..0000000
--- a/core-ui/tests/res/layout/fragment_middle.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#00F"
-          android:id="@+id/blueSquare"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#FF0"
-          android:id="@+id/yellowSquare"/>
-</LinearLayout>
diff --git a/core-ui/tests/res/layout/fragment_start.xml b/core-ui/tests/res/layout/fragment_start.xml
deleted file mode 100644
index 793e9b5..0000000
--- a/core-ui/tests/res/layout/fragment_start.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#0F0"
-          android:id="@+id/greenSquare"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#F00"
-          android:id="@+id/redSquare"/>
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:transitionName="source"
-              android:id="@+id/hello"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/core-ui/tests/res/layout/strict_view_fragment.xml b/core-ui/tests/res/layout/strict_view_fragment.xml
deleted file mode 100644
index 324f8d0..0000000
--- a/core-ui/tests/res/layout/strict_view_fragment.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright 2016, The Android Open Source Project
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:id="@+id/text1" />
diff --git a/core-ui/tests/res/transition/change_bounds.xml b/core-ui/tests/res/transition/change_bounds.xml
deleted file mode 100644
index 766bcea..0000000
--- a/core-ui/tests/res/transition/change_bounds.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<changeBounds/>
diff --git a/core-ui/tests/res/transition/fade.xml b/core-ui/tests/res/transition/fade.xml
deleted file mode 100644
index 617f70e..0000000
--- a/core-ui/tests/res/transition/fade.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<fade xmlns:android="http://schemas.android.com/apk/res/android"/>
diff --git a/core-ui/tests/res/values/colors.xml b/core-ui/tests/res/values/colors.xml
deleted file mode 100644
index 3c7bf7c..0000000
--- a/core-ui/tests/res/values/colors.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <color name="text_color">#FF8090</color>
-
-    <color name="test_red">#FF6030</color>
-    <color name="test_green">#50E080</color>
-    <color name="test_blue">#3050CF</color>
-    <color name="test_yellow">#F0F000</color>
-</resources>
diff --git a/core-ui/tests/res/values/dimens.xml b/core-ui/tests/res/values/dimens.xml
deleted file mode 100644
index d473645..0000000
--- a/core-ui/tests/res/values/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <dimen name="text_medium_size">20sp</dimen>
-</resources>
\ No newline at end of file
diff --git a/core-ui/tests/res/values/ids.xml b/core-ui/tests/res/values/ids.xml
deleted file mode 100644
index f3ac9b4..0000000
--- a/core-ui/tests/res/values/ids.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <item name="page_0" type="id"/>
-    <item name="page_1" type="id"/>
-    <item name="page_2" type="id"/>
-    <item name="page_3" type="id"/>
-    <item name="page_4" type="id"/>
-    <item name="page_5" type="id"/>
-    <item name="page_6" type="id"/>
-    <item name="page_7" type="id"/>
-    <item name="page_8" type="id"/>
-    <item name="page_9" type="id"/>
-    <item name="anchor" type="id"/>
-</resources>
\ No newline at end of file
diff --git a/core-ui/tests/res/values/strings.xml b/core-ui/tests/res/values/strings.xml
deleted file mode 100644
index 100ae69..0000000
--- a/core-ui/tests/res/values/strings.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <string name="hello">Hello World</string>
-    <string name="button">Button</string>
-</resources>
\ No newline at end of file
diff --git a/core-utils/Android.mk b/core-utils/Android.mk
deleted file mode 100644
index 751091b..0000000
--- a/core-utils/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-core-utils \
-#       android-support-compat
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-core-utils
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,kitkat) \
-    $(call all-java-files-under,api21) \
-    $(call all-java-files-under,java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/core-utils/AndroidManifest.xml b/core-utils/AndroidManifest.xml
deleted file mode 100644
index 248229b..0000000
--- a/core-utils/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.coreutils">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/core-utils/api/27.1.0.ignore b/core-utils/api/27.1.0.ignore
new file mode 100644
index 0000000..a87a3ad
--- /dev/null
+++ b/core-utils/api/27.1.0.ignore
@@ -0,0 +1,16 @@
+96e4e09
+a557a52
+11d000b
+1aaa4c2
+b240d34
+0fb487a
+8c14ef6
+34b446e
+8588484
+6814c90
+52fa9e6
+8fa5cd3
+b94ed02
+5797fb2
+0261292
+d663798
diff --git a/core-utils/api/current.txt b/core-utils/api/current.txt
index d535653..3880c59 100644
--- a/core-utils/api/current.txt
+++ b/core-utils/api/current.txt
@@ -1,188 +1,5 @@
-package android.support.v4.app {
-
-  public class AppLaunchChecker {
-    ctor public AppLaunchChecker();
-    method public static boolean hasStartedFromLauncher(android.content.Context);
-    method public static void onActivityCreate(android.app.Activity);
-  }
-
-  public class FrameMetricsAggregator {
-    ctor public FrameMetricsAggregator();
-    ctor public FrameMetricsAggregator(int);
-    method public void add(android.app.Activity);
-    method public android.util.SparseIntArray[] getMetrics();
-    method public android.util.SparseIntArray[] remove(android.app.Activity);
-    method public android.util.SparseIntArray[] reset();
-    method public android.util.SparseIntArray[] stop();
-    field public static final int ANIMATION_DURATION = 256; // 0x100
-    field public static final int ANIMATION_INDEX = 8; // 0x8
-    field public static final int COMMAND_DURATION = 32; // 0x20
-    field public static final int COMMAND_INDEX = 5; // 0x5
-    field public static final int DELAY_DURATION = 128; // 0x80
-    field public static final int DELAY_INDEX = 7; // 0x7
-    field public static final int DRAW_DURATION = 8; // 0x8
-    field public static final int DRAW_INDEX = 3; // 0x3
-    field public static final int EVERY_DURATION = 511; // 0x1ff
-    field public static final int INPUT_DURATION = 2; // 0x2
-    field public static final int INPUT_INDEX = 1; // 0x1
-    field public static final int LAYOUT_MEASURE_DURATION = 4; // 0x4
-    field public static final int LAYOUT_MEASURE_INDEX = 2; // 0x2
-    field public static final int SWAP_DURATION = 64; // 0x40
-    field public static final int SWAP_INDEX = 6; // 0x6
-    field public static final int SYNC_DURATION = 16; // 0x10
-    field public static final int SYNC_INDEX = 4; // 0x4
-    field public static final int TOTAL_DURATION = 1; // 0x1
-    field public static final int TOTAL_INDEX = 0; // 0x0
-  }
-
-  public final class NavUtils {
-    method public static android.content.Intent getParentActivityIntent(android.app.Activity);
-    method public static android.content.Intent getParentActivityIntent(android.content.Context, java.lang.Class<?>) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public static android.content.Intent getParentActivityIntent(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public static java.lang.String getParentActivityName(android.app.Activity);
-    method public static java.lang.String getParentActivityName(android.content.Context, android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public static void navigateUpFromSameTask(android.app.Activity);
-    method public static void navigateUpTo(android.app.Activity, android.content.Intent);
-    method public static boolean shouldUpRecreateTask(android.app.Activity, android.content.Intent);
-    field public static final java.lang.String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
-  }
-
-  public final class TaskStackBuilder implements java.lang.Iterable {
-    method public android.support.v4.app.TaskStackBuilder addNextIntent(android.content.Intent);
-    method public android.support.v4.app.TaskStackBuilder addNextIntentWithParentStack(android.content.Intent);
-    method public android.support.v4.app.TaskStackBuilder addParentStack(android.app.Activity);
-    method public android.support.v4.app.TaskStackBuilder addParentStack(java.lang.Class<?>);
-    method public android.support.v4.app.TaskStackBuilder addParentStack(android.content.ComponentName);
-    method public static android.support.v4.app.TaskStackBuilder create(android.content.Context);
-    method public android.content.Intent editIntentAt(int);
-    method public static deprecated android.support.v4.app.TaskStackBuilder from(android.content.Context);
-    method public deprecated android.content.Intent getIntent(int);
-    method public int getIntentCount();
-    method public android.content.Intent[] getIntents();
-    method public android.app.PendingIntent getPendingIntent(int, int);
-    method public android.app.PendingIntent getPendingIntent(int, int, android.os.Bundle);
-    method public deprecated java.util.Iterator<android.content.Intent> iterator();
-    method public void startActivities();
-    method public void startActivities(android.os.Bundle);
-  }
-
-  public static abstract interface TaskStackBuilder.SupportParentable {
-    method public abstract android.content.Intent getSupportParentActivityIntent();
-  }
-
-}
-
 package android.support.v4.content {
 
-  public abstract class AsyncTaskLoader<D> extends android.support.v4.content.Loader {
-    ctor public AsyncTaskLoader(android.content.Context);
-    method public void cancelLoadInBackground();
-    method public boolean isLoadInBackgroundCanceled();
-    method public abstract D loadInBackground();
-    method public void onCanceled(D);
-    method protected D onLoadInBackground();
-    method public void setUpdateThrottle(long);
-  }
-
-  public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
-    ctor public CursorLoader(android.content.Context);
-    ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public void deliverResult(android.database.Cursor);
-    method public java.lang.String[] getProjection();
-    method public java.lang.String getSelection();
-    method public java.lang.String[] getSelectionArgs();
-    method public java.lang.String getSortOrder();
-    method public android.net.Uri getUri();
-    method public android.database.Cursor loadInBackground();
-    method public void onCanceled(android.database.Cursor);
-    method public void setProjection(java.lang.String[]);
-    method public void setSelection(java.lang.String);
-    method public void setSelectionArgs(java.lang.String[]);
-    method public void setSortOrder(java.lang.String);
-    method public void setUri(android.net.Uri);
-  }
-
-  public class FileProvider extends android.content.ContentProvider {
-    ctor public FileProvider();
-    method public int delete(android.net.Uri, java.lang.String, java.lang.String[]);
-    method public java.lang.String getType(android.net.Uri);
-    method public static android.net.Uri getUriForFile(android.content.Context, java.lang.String, java.io.File);
-    method public android.net.Uri insert(android.net.Uri, android.content.ContentValues);
-    method public boolean onCreate();
-    method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
-    method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]);
-  }
-
-  public class Loader<D> {
-    ctor public Loader(android.content.Context);
-    method public void abandon();
-    method public boolean cancelLoad();
-    method public void commitContentChanged();
-    method public java.lang.String dataToString(D);
-    method public void deliverCancellation();
-    method public void deliverResult(D);
-    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public void forceLoad();
-    method public android.content.Context getContext();
-    method public int getId();
-    method public boolean isAbandoned();
-    method public boolean isReset();
-    method public boolean isStarted();
-    method protected void onAbandon();
-    method protected boolean onCancelLoad();
-    method public void onContentChanged();
-    method protected void onForceLoad();
-    method protected void onReset();
-    method protected void onStartLoading();
-    method protected void onStopLoading();
-    method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
-    method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
-    method public void reset();
-    method public void rollbackContentChanged();
-    method public final void startLoading();
-    method public void stopLoading();
-    method public boolean takeContentChanged();
-    method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
-    method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
-  }
-
-  public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
-    ctor public Loader.ForceLoadContentObserver();
-  }
-
-  public static abstract interface Loader.OnLoadCanceledListener<D> {
-    method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
-  }
-
-  public static abstract interface Loader.OnLoadCompleteListener<D> {
-    method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
-  }
-
-  public final class LocalBroadcastManager {
-    method public static android.support.v4.content.LocalBroadcastManager getInstance(android.content.Context);
-    method public void registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
-    method public boolean sendBroadcast(android.content.Intent);
-    method public void sendBroadcastSync(android.content.Intent);
-    method public void unregisterReceiver(android.content.BroadcastReceiver);
-  }
-
-  public final class MimeTypeFilter {
-    method public static boolean matches(java.lang.String, java.lang.String);
-    method public static java.lang.String matches(java.lang.String, java.lang.String[]);
-    method public static java.lang.String matches(java.lang.String[], java.lang.String);
-    method public static java.lang.String[] matchesMany(java.lang.String[], java.lang.String);
-  }
-
-  public final class PermissionChecker {
-    method public static int checkCallingOrSelfPermission(android.content.Context, java.lang.String);
-    method public static int checkCallingPermission(android.content.Context, java.lang.String, java.lang.String);
-    method public static int checkPermission(android.content.Context, java.lang.String, int, int, java.lang.String);
-    method public static int checkSelfPermission(android.content.Context, java.lang.String);
-    field public static final int PERMISSION_DENIED = -1; // 0xffffffff
-    field public static final int PERMISSION_DENIED_APP_OP = -2; // 0xfffffffe
-    field public static final int PERMISSION_GRANTED = 0; // 0x0
-  }
-
   public abstract deprecated class WakefulBroadcastReceiver extends android.content.BroadcastReceiver {
     ctor public WakefulBroadcastReceiver();
     method public static boolean completeWakefulIntent(android.content.Intent);
@@ -191,131 +8,3 @@
 
 }
 
-package android.support.v4.graphics {
-
-  public final class ColorUtils {
-    method public static int HSLToColor(float[]);
-    method public static int LABToColor(double, double, double);
-    method public static void LABToXYZ(double, double, double, double[]);
-    method public static void RGBToHSL(int, int, int, float[]);
-    method public static void RGBToLAB(int, int, int, double[]);
-    method public static void RGBToXYZ(int, int, int, double[]);
-    method public static int XYZToColor(double, double, double);
-    method public static void XYZToLAB(double, double, double, double[]);
-    method public static int blendARGB(int, int, float);
-    method public static void blendHSL(float[], float[], float, float[]);
-    method public static void blendLAB(double[], double[], double, double[]);
-    method public static double calculateContrast(int, int);
-    method public static double calculateLuminance(int);
-    method public static int calculateMinimumAlpha(int, int, float);
-    method public static void colorToHSL(int, float[]);
-    method public static void colorToLAB(int, double[]);
-    method public static void colorToXYZ(int, double[]);
-    method public static int compositeColors(int, int);
-    method public static double distanceEuclidean(double[], double[]);
-    method public static int setAlphaComponent(int, int);
-  }
-
-}
-
-package android.support.v4.graphics.drawable {
-
-  public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
-    method public void draw(android.graphics.Canvas);
-    method public final android.graphics.Bitmap getBitmap();
-    method public float getCornerRadius();
-    method public int getGravity();
-    method public int getOpacity();
-    method public final android.graphics.Paint getPaint();
-    method public boolean hasAntiAlias();
-    method public boolean hasMipMap();
-    method public boolean isCircular();
-    method public void setAlpha(int);
-    method public void setAntiAlias(boolean);
-    method public void setCircular(boolean);
-    method public void setColorFilter(android.graphics.ColorFilter);
-    method public void setCornerRadius(float);
-    method public void setDither(boolean);
-    method public void setGravity(int);
-    method public void setMipMap(boolean);
-    method public void setTargetDensity(android.graphics.Canvas);
-    method public void setTargetDensity(android.util.DisplayMetrics);
-    method public void setTargetDensity(int);
-  }
-
-  public final class RoundedBitmapDrawableFactory {
-    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, android.graphics.Bitmap);
-    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.lang.String);
-    method public static android.support.v4.graphics.drawable.RoundedBitmapDrawable create(android.content.res.Resources, java.io.InputStream);
-  }
-
-}
-
-package android.support.v4.math {
-
-  public class MathUtils {
-    method public static float clamp(float, float, float);
-    method public static double clamp(double, double, double);
-    method public static int clamp(int, int, int);
-  }
-
-}
-
-package android.support.v4.print {
-
-  public final class PrintHelper {
-    ctor public PrintHelper(android.content.Context);
-    method public int getColorMode();
-    method public int getOrientation();
-    method public int getScaleMode();
-    method public void printBitmap(java.lang.String, android.graphics.Bitmap);
-    method public void printBitmap(java.lang.String, android.graphics.Bitmap, android.support.v4.print.PrintHelper.OnPrintFinishCallback);
-    method public void printBitmap(java.lang.String, android.net.Uri) throws java.io.FileNotFoundException;
-    method public void printBitmap(java.lang.String, android.net.Uri, android.support.v4.print.PrintHelper.OnPrintFinishCallback) throws java.io.FileNotFoundException;
-    method public void setColorMode(int);
-    method public void setOrientation(int);
-    method public void setScaleMode(int);
-    method public static boolean systemSupportsPrint();
-    field public static final int COLOR_MODE_COLOR = 2; // 0x2
-    field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
-    field public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
-    field public static final int ORIENTATION_PORTRAIT = 2; // 0x2
-    field public static final int SCALE_MODE_FILL = 2; // 0x2
-    field public static final int SCALE_MODE_FIT = 1; // 0x1
-  }
-
-  public static abstract interface PrintHelper.OnPrintFinishCallback {
-    method public abstract void onFinish();
-  }
-
-}
-
-package android.support.v4.provider {
-
-  public abstract class DocumentFile {
-    method public abstract boolean canRead();
-    method public abstract boolean canWrite();
-    method public abstract android.support.v4.provider.DocumentFile createDirectory(java.lang.String);
-    method public abstract android.support.v4.provider.DocumentFile createFile(java.lang.String, java.lang.String);
-    method public abstract boolean delete();
-    method public abstract boolean exists();
-    method public android.support.v4.provider.DocumentFile findFile(java.lang.String);
-    method public static android.support.v4.provider.DocumentFile fromFile(java.io.File);
-    method public static android.support.v4.provider.DocumentFile fromSingleUri(android.content.Context, android.net.Uri);
-    method public static android.support.v4.provider.DocumentFile fromTreeUri(android.content.Context, android.net.Uri);
-    method public abstract java.lang.String getName();
-    method public android.support.v4.provider.DocumentFile getParentFile();
-    method public abstract java.lang.String getType();
-    method public abstract android.net.Uri getUri();
-    method public abstract boolean isDirectory();
-    method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
-    method public abstract boolean isFile();
-    method public abstract boolean isVirtual();
-    method public abstract long lastModified();
-    method public abstract long length();
-    method public abstract android.support.v4.provider.DocumentFile[] listFiles();
-    method public abstract boolean renameTo(java.lang.String);
-  }
-
-}
-
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index 75555c0..ffc0ab8 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -9,6 +9,10 @@
 dependencies {
     api(project(":support-annotations"))
     api(project(":support-compat"))
+    api(project(":documentfile"))
+    api(project(":loader"))
+    api(project(":localbroadcastmanager"))
+    api(project(":print"))
 
     androidTestImplementation(TEST_RUNNER)
     androidTestImplementation(ESPRESSO_CORE)
@@ -16,16 +20,6 @@
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
 }
 
-android {
-    sourceSets {
-        main.java.srcDirs = [
-                'kitkat',
-                'api21',
-                'java'
-        ]
-    }
-}
-
 supportLibrary {
     name = "Android Support Library core utils"
     publish = true
@@ -33,5 +27,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2011"
     description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
-    legacySourceLocation = true
 }
diff --git a/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java b/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java
deleted file mode 100644
index 8ec3eee..0000000
--- a/core-utils/java/android/support/v4/content/WakefulBroadcastReceiver.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.content;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.PowerManager;
-import android.util.Log;
-import android.util.SparseArray;
-
-/**
- * This helper is for an old pattern of implementing a {@link BroadcastReceiver}
- * that receives a device wakeup event and then passes the work off
- * to a {@link android.app.Service}, while ensuring that the
- * device does not go back to sleep during the transition.
- *
- * <p>This class takes care of creating and managing a partial wake lock
- * for you; you must request the {@link android.Manifest.permission#WAKE_LOCK}
- * permission to use it.</p>
- *
- * <h3>Example</h3>
- *
- * <p>A {@link WakefulBroadcastReceiver} uses the method
- * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
- * to start the service that does the work. This method is comparable to
- * {@link android.content.Context#startService startService()}, except that
- * the {@link WakefulBroadcastReceiver} is holding a wake lock when the service
- * starts. The intent that is passed with
- * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
- * holds an extra identifying the wake lock.</p>
- *
- * {@sample frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/content/SimpleWakefulReceiver.java
- *      complete}
- *
- * <p>The service (in this example, an {@link android.app.IntentService}) does
- * some work. When it is finished, it releases the wake lock by calling
- * {@link WakefulBroadcastReceiver#completeWakefulIntent
- * completeWakefulIntent(intent)}. The intent it passes as a parameter
- * is the same intent that the {@link WakefulBroadcastReceiver} originally
- * passed in.</p>
- *
- * {@sample frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/content/SimpleWakefulService.java
- *      complete}
- *
- * @deprecated As of {@link android.os.Build.VERSION_CODES#O Android O}, background check
- * restrictions make this class no longer generally useful.  (It is generally not safe to
- * start a service from the receipt of a broadcast, because you don't have any guarantees
- * that your app is in the foreground at this point and thus allowed to do so.)  Instead,
- * developers should use android.app.job.JobScheduler to schedule a job, and this
- * does not require that the app hold a wake lock while doing so (the system will take
- * care of holding a wake lock for the job).
- */
-@Deprecated
-public abstract class WakefulBroadcastReceiver extends BroadcastReceiver {
-    private static final String EXTRA_WAKE_LOCK_ID = "android.support.content.wakelockid";
-
-    private static final SparseArray<PowerManager.WakeLock> sActiveWakeLocks = new SparseArray<>();
-    private static int mNextId = 1;
-
-    /**
-     * Do a {@link android.content.Context#startService(android.content.Intent)
-     * Context.startService}, but holding a wake lock while the service starts.
-     * This will modify the Intent to hold an extra identifying the wake lock;
-     * when the service receives it in {@link android.app.Service#onStartCommand
-     * Service.onStartCommand}, it should pass back the Intent it receives there to
-     * {@link #completeWakefulIntent(android.content.Intent)} in order to release
-     * the wake lock.
-     *
-     * @param context The Context in which it operate.
-     * @param intent The Intent with which to start the service, as per
-     * {@link android.content.Context#startService(android.content.Intent)
-     * Context.startService}.
-     */
-    public static ComponentName startWakefulService(Context context, Intent intent) {
-        synchronized (sActiveWakeLocks) {
-            int id = mNextId;
-            mNextId++;
-            if (mNextId <= 0) {
-                mNextId = 1;
-            }
-
-            intent.putExtra(EXTRA_WAKE_LOCK_ID, id);
-            ComponentName comp = context.startService(intent);
-            if (comp == null) {
-                return null;
-            }
-
-            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
-                    "wake:" + comp.flattenToShortString());
-            wl.setReferenceCounted(false);
-            wl.acquire(60 * 1000);
-            sActiveWakeLocks.put(id, wl);
-            return comp;
-        }
-    }
-
-    /**
-     * Finish the execution from a previous {@link #startWakefulService}.  Any wake lock
-     * that was being held will now be released.
-     *
-     * @param intent The Intent as originally generated by {@link #startWakefulService}.
-     * @return Returns true if the intent is associated with a wake lock that is
-     * now released; returns false if there was no wake lock specified for it.
-     */
-    public static boolean completeWakefulIntent(Intent intent) {
-        final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0);
-        if (id == 0) {
-            return false;
-        }
-        synchronized (sActiveWakeLocks) {
-            PowerManager.WakeLock wl = sActiveWakeLocks.get(id);
-            if (wl != null) {
-                wl.release();
-                sActiveWakeLocks.remove(id);
-                return true;
-            }
-            // We return true whether or not we actually found the wake lock
-            // the return code is defined to indicate whether the Intent contained
-            // an identifier for a wake lock that it was supposed to match.
-            // We just log a warning here if there is no wake lock found, which could
-            // happen for example if this function is called twice on the same
-            // intent or the process is killed and restarted before processing the intent.
-            Log.w("WakefulBroadcastReceiv.", "No active wake lock id #" + id);
-            return true;
-        }
-    }
-}
diff --git a/core-utils/java/android/support/v4/graphics/ColorUtils.java b/core-utils/java/android/support/v4/graphics/ColorUtils.java
deleted file mode 100644
index c58d2ba..0000000
--- a/core-utils/java/android/support/v4/graphics/ColorUtils.java
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.graphics;
-
-import android.graphics.Color;
-import android.support.annotation.ColorInt;
-import android.support.annotation.FloatRange;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.VisibleForTesting;
-
-/**
- * A set of color-related utility methods, building upon those available in {@code Color}.
- */
-public final class ColorUtils {
-
-    private static final double XYZ_WHITE_REFERENCE_X = 95.047;
-    private static final double XYZ_WHITE_REFERENCE_Y = 100;
-    private static final double XYZ_WHITE_REFERENCE_Z = 108.883;
-    private static final double XYZ_EPSILON = 0.008856;
-    private static final double XYZ_KAPPA = 903.3;
-
-    private static final int MIN_ALPHA_SEARCH_MAX_ITERATIONS = 10;
-    private static final int MIN_ALPHA_SEARCH_PRECISION = 1;
-
-    private static final ThreadLocal<double[]> TEMP_ARRAY = new ThreadLocal<>();
-
-    private ColorUtils() {}
-
-    /**
-     * Composite two potentially translucent colors over each other and returns the result.
-     */
-    public static int compositeColors(@ColorInt int foreground, @ColorInt int background) {
-        int bgAlpha = Color.alpha(background);
-        int fgAlpha = Color.alpha(foreground);
-        int a = compositeAlpha(fgAlpha, bgAlpha);
-
-        int r = compositeComponent(Color.red(foreground), fgAlpha,
-                Color.red(background), bgAlpha, a);
-        int g = compositeComponent(Color.green(foreground), fgAlpha,
-                Color.green(background), bgAlpha, a);
-        int b = compositeComponent(Color.blue(foreground), fgAlpha,
-                Color.blue(background), bgAlpha, a);
-
-        return Color.argb(a, r, g, b);
-    }
-
-    private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
-        return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
-    }
-
-    private static int compositeComponent(int fgC, int fgA, int bgC, int bgA, int a) {
-        if (a == 0) return 0;
-        return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF);
-    }
-
-    /**
-     * Returns the luminance of a color as a float between {@code 0.0} and {@code 1.0}.
-     * <p>Defined as the Y component in the XYZ representation of {@code color}.</p>
-     */
-    @FloatRange(from = 0.0, to = 1.0)
-    public static double calculateLuminance(@ColorInt int color) {
-        final double[] result = getTempDouble3Array();
-        colorToXYZ(color, result);
-        // Luminance is the Y component
-        return result[1] / 100;
-    }
-
-    /**
-     * Returns the contrast ratio between {@code foreground} and {@code background}.
-     * {@code background} must be opaque.
-     * <p>
-     * Formula defined
-     * <a href="http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef">here</a>.
-     */
-    public static double calculateContrast(@ColorInt int foreground, @ColorInt int background) {
-        if (Color.alpha(background) != 255) {
-            throw new IllegalArgumentException("background can not be translucent: #"
-                    + Integer.toHexString(background));
-        }
-        if (Color.alpha(foreground) < 255) {
-            // If the foreground is translucent, composite the foreground over the background
-            foreground = compositeColors(foreground, background);
-        }
-
-        final double luminance1 = calculateLuminance(foreground) + 0.05;
-        final double luminance2 = calculateLuminance(background) + 0.05;
-
-        // Now return the lighter luminance divided by the darker luminance
-        return Math.max(luminance1, luminance2) / Math.min(luminance1, luminance2);
-    }
-
-    /**
-     * Calculates the minimum alpha value which can be applied to {@code foreground} so that would
-     * have a contrast value of at least {@code minContrastRatio} when compared to
-     * {@code background}.
-     *
-     * @param foreground       the foreground color
-     * @param background       the opaque background color
-     * @param minContrastRatio the minimum contrast ratio
-     * @return the alpha value in the range 0-255, or -1 if no value could be calculated
-     */
-    public static int calculateMinimumAlpha(@ColorInt int foreground, @ColorInt int background,
-            float minContrastRatio) {
-        if (Color.alpha(background) != 255) {
-            throw new IllegalArgumentException("background can not be translucent: #"
-                    + Integer.toHexString(background));
-        }
-
-        // First lets check that a fully opaque foreground has sufficient contrast
-        int testForeground = setAlphaComponent(foreground, 255);
-        double testRatio = calculateContrast(testForeground, background);
-        if (testRatio < minContrastRatio) {
-            // Fully opaque foreground does not have sufficient contrast, return error
-            return -1;
-        }
-
-        // Binary search to find a value with the minimum value which provides sufficient contrast
-        int numIterations = 0;
-        int minAlpha = 0;
-        int maxAlpha = 255;
-
-        while (numIterations <= MIN_ALPHA_SEARCH_MAX_ITERATIONS &&
-                (maxAlpha - minAlpha) > MIN_ALPHA_SEARCH_PRECISION) {
-            final int testAlpha = (minAlpha + maxAlpha) / 2;
-
-            testForeground = setAlphaComponent(foreground, testAlpha);
-            testRatio = calculateContrast(testForeground, background);
-
-            if (testRatio < minContrastRatio) {
-                minAlpha = testAlpha;
-            } else {
-                maxAlpha = testAlpha;
-            }
-
-            numIterations++;
-        }
-
-        // Conservatively return the max of the range of possible alphas, which is known to pass.
-        return maxAlpha;
-    }
-
-    /**
-     * Convert RGB components to HSL (hue-saturation-lightness).
-     * <ul>
-     * <li>outHsl[0] is Hue [0 .. 360)</li>
-     * <li>outHsl[1] is Saturation [0...1]</li>
-     * <li>outHsl[2] is Lightness [0...1]</li>
-     * </ul>
-     *
-     * @param r      red component value [0..255]
-     * @param g      green component value [0..255]
-     * @param b      blue component value [0..255]
-     * @param outHsl 3-element array which holds the resulting HSL components
-     */
-    public static void RGBToHSL(@IntRange(from = 0x0, to = 0xFF) int r,
-            @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
-            @NonNull float[] outHsl) {
-        final float rf = r / 255f;
-        final float gf = g / 255f;
-        final float bf = b / 255f;
-
-        final float max = Math.max(rf, Math.max(gf, bf));
-        final float min = Math.min(rf, Math.min(gf, bf));
-        final float deltaMaxMin = max - min;
-
-        float h, s;
-        float l = (max + min) / 2f;
-
-        if (max == min) {
-            // Monochromatic
-            h = s = 0f;
-        } else {
-            if (max == rf) {
-                h = ((gf - bf) / deltaMaxMin) % 6f;
-            } else if (max == gf) {
-                h = ((bf - rf) / deltaMaxMin) + 2f;
-            } else {
-                h = ((rf - gf) / deltaMaxMin) + 4f;
-            }
-
-            s = deltaMaxMin / (1f - Math.abs(2f * l - 1f));
-        }
-
-        h = (h * 60f) % 360f;
-        if (h < 0) {
-            h += 360f;
-        }
-
-        outHsl[0] = constrain(h, 0f, 360f);
-        outHsl[1] = constrain(s, 0f, 1f);
-        outHsl[2] = constrain(l, 0f, 1f);
-    }
-
-    /**
-     * Convert the ARGB color to its HSL (hue-saturation-lightness) components.
-     * <ul>
-     * <li>outHsl[0] is Hue [0 .. 360)</li>
-     * <li>outHsl[1] is Saturation [0...1]</li>
-     * <li>outHsl[2] is Lightness [0...1]</li>
-     * </ul>
-     *
-     * @param color  the ARGB color to convert. The alpha component is ignored
-     * @param outHsl 3-element array which holds the resulting HSL components
-     */
-    public static void colorToHSL(@ColorInt int color, @NonNull float[] outHsl) {
-        RGBToHSL(Color.red(color), Color.green(color), Color.blue(color), outHsl);
-    }
-
-    /**
-     * Convert HSL (hue-saturation-lightness) components to a RGB color.
-     * <ul>
-     * <li>hsl[0] is Hue [0 .. 360)</li>
-     * <li>hsl[1] is Saturation [0...1]</li>
-     * <li>hsl[2] is Lightness [0...1]</li>
-     * </ul>
-     * If hsv values are out of range, they are pinned.
-     *
-     * @param hsl 3-element array which holds the input HSL components
-     * @return the resulting RGB color
-     */
-    @ColorInt
-    public static int HSLToColor(@NonNull float[] hsl) {
-        final float h = hsl[0];
-        final float s = hsl[1];
-        final float l = hsl[2];
-
-        final float c = (1f - Math.abs(2 * l - 1f)) * s;
-        final float m = l - 0.5f * c;
-        final float x = c * (1f - Math.abs((h / 60f % 2f) - 1f));
-
-        final int hueSegment = (int) h / 60;
-
-        int r = 0, g = 0, b = 0;
-
-        switch (hueSegment) {
-            case 0:
-                r = Math.round(255 * (c + m));
-                g = Math.round(255 * (x + m));
-                b = Math.round(255 * m);
-                break;
-            case 1:
-                r = Math.round(255 * (x + m));
-                g = Math.round(255 * (c + m));
-                b = Math.round(255 * m);
-                break;
-            case 2:
-                r = Math.round(255 * m);
-                g = Math.round(255 * (c + m));
-                b = Math.round(255 * (x + m));
-                break;
-            case 3:
-                r = Math.round(255 * m);
-                g = Math.round(255 * (x + m));
-                b = Math.round(255 * (c + m));
-                break;
-            case 4:
-                r = Math.round(255 * (x + m));
-                g = Math.round(255 * m);
-                b = Math.round(255 * (c + m));
-                break;
-            case 5:
-            case 6:
-                r = Math.round(255 * (c + m));
-                g = Math.round(255 * m);
-                b = Math.round(255 * (x + m));
-                break;
-        }
-
-        r = constrain(r, 0, 255);
-        g = constrain(g, 0, 255);
-        b = constrain(b, 0, 255);
-
-        return Color.rgb(r, g, b);
-    }
-
-    /**
-     * Set the alpha component of {@code color} to be {@code alpha}.
-     */
-    @ColorInt
-    public static int setAlphaComponent(@ColorInt int color,
-            @IntRange(from = 0x0, to = 0xFF) int alpha) {
-        if (alpha < 0 || alpha > 255) {
-            throw new IllegalArgumentException("alpha must be between 0 and 255.");
-        }
-        return (color & 0x00ffffff) | (alpha << 24);
-    }
-
-    /**
-     * Convert the ARGB color to its CIE Lab representative components.
-     *
-     * @param color  the ARGB color to convert. The alpha component is ignored
-     * @param outLab 3-element array which holds the resulting LAB components
-     */
-    public static void colorToLAB(@ColorInt int color, @NonNull double[] outLab) {
-        RGBToLAB(Color.red(color), Color.green(color), Color.blue(color), outLab);
-    }
-
-    /**
-     * Convert RGB components to its CIE Lab representative components.
-     *
-     * <ul>
-     * <li>outLab[0] is L [0 ...1)</li>
-     * <li>outLab[1] is a [-128...127)</li>
-     * <li>outLab[2] is b [-128...127)</li>
-     * </ul>
-     *
-     * @param r      red component value [0..255]
-     * @param g      green component value [0..255]
-     * @param b      blue component value [0..255]
-     * @param outLab 3-element array which holds the resulting LAB components
-     */
-    public static void RGBToLAB(@IntRange(from = 0x0, to = 0xFF) int r,
-            @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
-            @NonNull double[] outLab) {
-        // First we convert RGB to XYZ
-        RGBToXYZ(r, g, b, outLab);
-        // outLab now contains XYZ
-        XYZToLAB(outLab[0], outLab[1], outLab[2], outLab);
-        // outLab now contains LAB representation
-    }
-
-    /**
-     * Convert the ARGB color to its CIE XYZ representative components.
-     *
-     * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
-     * 2° Standard Observer (1931).</p>
-     *
-     * <ul>
-     * <li>outXyz[0] is X [0 ...95.047)</li>
-     * <li>outXyz[1] is Y [0...100)</li>
-     * <li>outXyz[2] is Z [0...108.883)</li>
-     * </ul>
-     *
-     * @param color  the ARGB color to convert. The alpha component is ignored
-     * @param outXyz 3-element array which holds the resulting LAB components
-     */
-    public static void colorToXYZ(@ColorInt int color, @NonNull double[] outXyz) {
-        RGBToXYZ(Color.red(color), Color.green(color), Color.blue(color), outXyz);
-    }
-
-    /**
-     * Convert RGB components to its CIE XYZ representative components.
-     *
-     * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
-     * 2° Standard Observer (1931).</p>
-     *
-     * <ul>
-     * <li>outXyz[0] is X [0 ...95.047)</li>
-     * <li>outXyz[1] is Y [0...100)</li>
-     * <li>outXyz[2] is Z [0...108.883)</li>
-     * </ul>
-     *
-     * @param r      red component value [0..255]
-     * @param g      green component value [0..255]
-     * @param b      blue component value [0..255]
-     * @param outXyz 3-element array which holds the resulting XYZ components
-     */
-    public static void RGBToXYZ(@IntRange(from = 0x0, to = 0xFF) int r,
-            @IntRange(from = 0x0, to = 0xFF) int g, @IntRange(from = 0x0, to = 0xFF) int b,
-            @NonNull double[] outXyz) {
-        if (outXyz.length != 3) {
-            throw new IllegalArgumentException("outXyz must have a length of 3.");
-        }
-
-        double sr = r / 255.0;
-        sr = sr < 0.04045 ? sr / 12.92 : Math.pow((sr + 0.055) / 1.055, 2.4);
-        double sg = g / 255.0;
-        sg = sg < 0.04045 ? sg / 12.92 : Math.pow((sg + 0.055) / 1.055, 2.4);
-        double sb = b / 255.0;
-        sb = sb < 0.04045 ? sb / 12.92 : Math.pow((sb + 0.055) / 1.055, 2.4);
-
-        outXyz[0] = 100 * (sr * 0.4124 + sg * 0.3576 + sb * 0.1805);
-        outXyz[1] = 100 * (sr * 0.2126 + sg * 0.7152 + sb * 0.0722);
-        outXyz[2] = 100 * (sr * 0.0193 + sg * 0.1192 + sb * 0.9505);
-    }
-
-    /**
-     * Converts a color from CIE XYZ to CIE Lab representation.
-     *
-     * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
-     * 2° Standard Observer (1931).</p>
-     *
-     * <ul>
-     * <li>outLab[0] is L [0 ...1)</li>
-     * <li>outLab[1] is a [-128...127)</li>
-     * <li>outLab[2] is b [-128...127)</li>
-     * </ul>
-     *
-     * @param x      X component value [0...95.047)
-     * @param y      Y component value [0...100)
-     * @param z      Z component value [0...108.883)
-     * @param outLab 3-element array which holds the resulting Lab components
-     */
-    public static void XYZToLAB(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
-            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
-            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z,
-            @NonNull double[] outLab) {
-        if (outLab.length != 3) {
-            throw new IllegalArgumentException("outLab must have a length of 3.");
-        }
-        x = pivotXyzComponent(x / XYZ_WHITE_REFERENCE_X);
-        y = pivotXyzComponent(y / XYZ_WHITE_REFERENCE_Y);
-        z = pivotXyzComponent(z / XYZ_WHITE_REFERENCE_Z);
-        outLab[0] = Math.max(0, 116 * y - 16);
-        outLab[1] = 500 * (x - y);
-        outLab[2] = 200 * (y - z);
-    }
-
-    /**
-     * Converts a color from CIE Lab to CIE XYZ representation.
-     *
-     * <p>The resulting XYZ representation will use the D65 illuminant and the CIE
-     * 2° Standard Observer (1931).</p>
-     *
-     * <ul>
-     * <li>outXyz[0] is X [0 ...95.047)</li>
-     * <li>outXyz[1] is Y [0...100)</li>
-     * <li>outXyz[2] is Z [0...108.883)</li>
-     * </ul>
-     *
-     * @param l      L component value [0...100)
-     * @param a      A component value [-128...127)
-     * @param b      B component value [-128...127)
-     * @param outXyz 3-element array which holds the resulting XYZ components
-     */
-    public static void LABToXYZ(@FloatRange(from = 0f, to = 100) final double l,
-            @FloatRange(from = -128, to = 127) final double a,
-            @FloatRange(from = -128, to = 127) final double b,
-            @NonNull double[] outXyz) {
-        final double fy = (l + 16) / 116;
-        final double fx = a / 500 + fy;
-        final double fz = fy - b / 200;
-
-        double tmp = Math.pow(fx, 3);
-        final double xr = tmp > XYZ_EPSILON ? tmp : (116 * fx - 16) / XYZ_KAPPA;
-        final double yr = l > XYZ_KAPPA * XYZ_EPSILON ? Math.pow(fy, 3) : l / XYZ_KAPPA;
-
-        tmp = Math.pow(fz, 3);
-        final double zr = tmp > XYZ_EPSILON ? tmp : (116 * fz - 16) / XYZ_KAPPA;
-
-        outXyz[0] = xr * XYZ_WHITE_REFERENCE_X;
-        outXyz[1] = yr * XYZ_WHITE_REFERENCE_Y;
-        outXyz[2] = zr * XYZ_WHITE_REFERENCE_Z;
-    }
-
-    /**
-     * Converts a color from CIE XYZ to its RGB representation.
-     *
-     * <p>This method expects the XYZ representation to use the D65 illuminant and the CIE
-     * 2° Standard Observer (1931).</p>
-     *
-     * @param x X component value [0...95.047)
-     * @param y Y component value [0...100)
-     * @param z Z component value [0...108.883)
-     * @return int containing the RGB representation
-     */
-    @ColorInt
-    public static int XYZToColor(@FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_X) double x,
-            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Y) double y,
-            @FloatRange(from = 0f, to = XYZ_WHITE_REFERENCE_Z) double z) {
-        double r = (x * 3.2406 + y * -1.5372 + z * -0.4986) / 100;
-        double g = (x * -0.9689 + y * 1.8758 + z * 0.0415) / 100;
-        double b = (x * 0.0557 + y * -0.2040 + z * 1.0570) / 100;
-
-        r = r > 0.0031308 ? 1.055 * Math.pow(r, 1 / 2.4) - 0.055 : 12.92 * r;
-        g = g > 0.0031308 ? 1.055 * Math.pow(g, 1 / 2.4) - 0.055 : 12.92 * g;
-        b = b > 0.0031308 ? 1.055 * Math.pow(b, 1 / 2.4) - 0.055 : 12.92 * b;
-
-        return Color.rgb(
-                constrain((int) Math.round(r * 255), 0, 255),
-                constrain((int) Math.round(g * 255), 0, 255),
-                constrain((int) Math.round(b * 255), 0, 255));
-    }
-
-    /**
-     * Converts a color from CIE Lab to its RGB representation.
-     *
-     * @param l L component value [0...100]
-     * @param a A component value [-128...127]
-     * @param b B component value [-128...127]
-     * @return int containing the RGB representation
-     */
-    @ColorInt
-    public static int LABToColor(@FloatRange(from = 0f, to = 100) final double l,
-            @FloatRange(from = -128, to = 127) final double a,
-            @FloatRange(from = -128, to = 127) final double b) {
-        final double[] result = getTempDouble3Array();
-        LABToXYZ(l, a, b, result);
-        return XYZToColor(result[0], result[1], result[2]);
-    }
-
-    /**
-     * Returns the euclidean distance between two LAB colors.
-     */
-    public static double distanceEuclidean(@NonNull double[] labX, @NonNull double[] labY) {
-        return Math.sqrt(Math.pow(labX[0] - labY[0], 2)
-                + Math.pow(labX[1] - labY[1], 2)
-                + Math.pow(labX[2] - labY[2], 2));
-    }
-
-    private static float constrain(float amount, float low, float high) {
-        return amount < low ? low : (amount > high ? high : amount);
-    }
-
-    private static int constrain(int amount, int low, int high) {
-        return amount < low ? low : (amount > high ? high : amount);
-    }
-
-    private static double pivotXyzComponent(double component) {
-        return component > XYZ_EPSILON
-                ? Math.pow(component, 1 / 3.0)
-                : (XYZ_KAPPA * component + 16) / 116;
-    }
-
-    /**
-     * Blend between two ARGB colors using the given ratio.
-     *
-     * <p>A blend ratio of 0.0 will result in {@code color1}, 0.5 will give an even blend,
-     * 1.0 will result in {@code color2}.</p>
-     *
-     * @param color1 the first ARGB color
-     * @param color2 the second ARGB color
-     * @param ratio  the blend ratio of {@code color1} to {@code color2}
-     */
-    @ColorInt
-    public static int blendARGB(@ColorInt int color1, @ColorInt int color2,
-            @FloatRange(from = 0.0, to = 1.0) float ratio) {
-        final float inverseRatio = 1 - ratio;
-        float a = Color.alpha(color1) * inverseRatio + Color.alpha(color2) * ratio;
-        float r = Color.red(color1) * inverseRatio + Color.red(color2) * ratio;
-        float g = Color.green(color1) * inverseRatio + Color.green(color2) * ratio;
-        float b = Color.blue(color1) * inverseRatio + Color.blue(color2) * ratio;
-        return Color.argb((int) a, (int) r, (int) g, (int) b);
-    }
-
-    /**
-     * Blend between {@code hsl1} and {@code hsl2} using the given ratio. This will interpolate
-     * the hue using the shortest angle.
-     *
-     * <p>A blend ratio of 0.0 will result in {@code hsl1}, 0.5 will give an even blend,
-     * 1.0 will result in {@code hsl2}.</p>
-     *
-     * @param hsl1      3-element array which holds the first HSL color
-     * @param hsl2      3-element array which holds the second HSL color
-     * @param ratio     the blend ratio of {@code hsl1} to {@code hsl2}
-     * @param outResult 3-element array which holds the resulting HSL components
-     */
-    public static void blendHSL(@NonNull float[] hsl1, @NonNull float[] hsl2,
-            @FloatRange(from = 0.0, to = 1.0) float ratio, @NonNull float[] outResult) {
-        if (outResult.length != 3) {
-            throw new IllegalArgumentException("result must have a length of 3.");
-        }
-        final float inverseRatio = 1 - ratio;
-        // Since hue is circular we will need to interpolate carefully
-        outResult[0] = circularInterpolate(hsl1[0], hsl2[0], ratio);
-        outResult[1] = hsl1[1] * inverseRatio + hsl2[1] * ratio;
-        outResult[2] = hsl1[2] * inverseRatio + hsl2[2] * ratio;
-    }
-
-    /**
-     * Blend between two CIE-LAB colors using the given ratio.
-     *
-     * <p>A blend ratio of 0.0 will result in {@code lab1}, 0.5 will give an even blend,
-     * 1.0 will result in {@code lab2}.</p>
-     *
-     * @param lab1      3-element array which holds the first LAB color
-     * @param lab2      3-element array which holds the second LAB color
-     * @param ratio     the blend ratio of {@code lab1} to {@code lab2}
-     * @param outResult 3-element array which holds the resulting LAB components
-     */
-    public static void blendLAB(@NonNull double[] lab1, @NonNull double[] lab2,
-            @FloatRange(from = 0.0, to = 1.0) double ratio, @NonNull double[] outResult) {
-        if (outResult.length != 3) {
-            throw new IllegalArgumentException("outResult must have a length of 3.");
-        }
-        final double inverseRatio = 1 - ratio;
-        outResult[0] = lab1[0] * inverseRatio + lab2[0] * ratio;
-        outResult[1] = lab1[1] * inverseRatio + lab2[1] * ratio;
-        outResult[2] = lab1[2] * inverseRatio + lab2[2] * ratio;
-    }
-
-    @VisibleForTesting
-    static float circularInterpolate(float a, float b, float f) {
-        if (Math.abs(b - a) > 180) {
-            if (b > a) {
-                a += 360;
-            } else {
-                b += 360;
-            }
-        }
-        return (a + ((b - a) * f)) % 360;
-    }
-
-    private static double[] getTempDouble3Array() {
-        double[] result = TEMP_ARRAY.get();
-        if (result == null) {
-            result = new double[3];
-            TEMP_ARRAY.set(result);
-        }
-        return result;
-    }
-
-}
diff --git a/core-utils/src/main/AndroidManifest.xml b/core-utils/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b89595f
--- /dev/null
+++ b/core-utils/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.coreutils"/>
diff --git a/core-utils/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java b/core-utils/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java
new file mode 100644
index 0000000..78555aa
--- /dev/null
+++ b/core-utils/src/main/java/android/support/v4/content/WakefulBroadcastReceiver.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.content;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+/**
+ * This helper is for an old pattern of implementing a {@link BroadcastReceiver}
+ * that receives a device wakeup event and then passes the work off
+ * to a {@link android.app.Service}, while ensuring that the
+ * device does not go back to sleep during the transition.
+ *
+ * <p>This class takes care of creating and managing a partial wake lock
+ * for you; you must request the {@link android.Manifest.permission#WAKE_LOCK}
+ * permission to use it.</p>
+ *
+ * <p>Wakelocks held by this class are reported to tools as
+ * {@code "androidx.core:wake:<component-name>"}.</p>
+ *
+ * <h3>Example</h3>
+ *
+ * <p>A {@link WakefulBroadcastReceiver} uses the method
+ * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
+ * to start the service that does the work. This method is comparable to
+ * {@link android.content.Context#startService startService()}, except that
+ * the {@link WakefulBroadcastReceiver} is holding a wake lock when the service
+ * starts. The intent that is passed with
+ * {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
+ * holds an extra identifying the wake lock.</p>
+ *
+ * {@sample frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/content/SimpleWakefulReceiver.java
+ *      complete}
+ *
+ * <p>The service (in this example, an {@link android.app.IntentService}) does
+ * some work. When it is finished, it releases the wake lock by calling
+ * {@link WakefulBroadcastReceiver#completeWakefulIntent
+ * completeWakefulIntent(intent)}. The intent it passes as a parameter
+ * is the same intent that the {@link WakefulBroadcastReceiver} originally
+ * passed in.</p>
+ *
+ * {@sample frameworks/support/samples/Support4Demos/src/main/java/com/example/android/supportv4/content/SimpleWakefulService.java
+ *      complete}
+ *
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#O Android O}, background check
+ * restrictions make this class no longer generally useful.  (It is generally not safe to
+ * start a service from the receipt of a broadcast, because you don't have any guarantees
+ * that your app is in the foreground at this point and thus allowed to do so.)  Instead,
+ * developers should use android.app.job.JobScheduler to schedule a job, and this
+ * does not require that the app hold a wake lock while doing so (the system will take
+ * care of holding a wake lock for the job).
+ */
+@Deprecated
+public abstract class WakefulBroadcastReceiver extends BroadcastReceiver {
+    private static final String EXTRA_WAKE_LOCK_ID = "android.support.content.wakelockid";
+
+    private static final SparseArray<PowerManager.WakeLock> sActiveWakeLocks = new SparseArray<>();
+    private static int mNextId = 1;
+
+    /**
+     * Do a {@link android.content.Context#startService(android.content.Intent)
+     * Context.startService}, but holding a wake lock while the service starts.
+     * This will modify the Intent to hold an extra identifying the wake lock;
+     * when the service receives it in {@link android.app.Service#onStartCommand
+     * Service.onStartCommand}, it should pass back the Intent it receives there to
+     * {@link #completeWakefulIntent(android.content.Intent)} in order to release
+     * the wake lock.
+     *
+     * @param context The Context in which it operate.
+     * @param intent The Intent with which to start the service, as per
+     * {@link android.content.Context#startService(android.content.Intent)
+     * Context.startService}.
+     */
+    public static ComponentName startWakefulService(Context context, Intent intent) {
+        synchronized (sActiveWakeLocks) {
+            int id = mNextId;
+            mNextId++;
+            if (mNextId <= 0) {
+                mNextId = 1;
+            }
+
+            intent.putExtra(EXTRA_WAKE_LOCK_ID, id);
+            ComponentName comp = context.startService(intent);
+            if (comp == null) {
+                return null;
+            }
+
+            PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+            PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+                    "androidx.core:wake:" + comp.flattenToShortString());
+            wl.setReferenceCounted(false);
+            wl.acquire(60 * 1000);
+            sActiveWakeLocks.put(id, wl);
+            return comp;
+        }
+    }
+
+    /**
+     * Finish the execution from a previous {@link #startWakefulService}.  Any wake lock
+     * that was being held will now be released.
+     *
+     * @param intent The Intent as originally generated by {@link #startWakefulService}.
+     * @return Returns true if the intent is associated with a wake lock that is
+     * now released; returns false if there was no wake lock specified for it.
+     */
+    public static boolean completeWakefulIntent(Intent intent) {
+        final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0);
+        if (id == 0) {
+            return false;
+        }
+        synchronized (sActiveWakeLocks) {
+            PowerManager.WakeLock wl = sActiveWakeLocks.get(id);
+            if (wl != null) {
+                wl.release();
+                sActiveWakeLocks.remove(id);
+                return true;
+            }
+            // We return true whether or not we actually found the wake lock
+            // the return code is defined to indicate whether the Intent contained
+            // an identifier for a wake lock that it was supposed to match.
+            // We just log a warning here if there is no wake lock found, which could
+            // happen for example if this function is called twice on the same
+            // intent or the process is killed and restarted before processing the intent.
+            Log.w("WakefulBroadcastReceiv.", "No active wake lock id #" + id);
+            return true;
+        }
+    }
+}
diff --git a/core-utils/tests/AndroidManifest.xml b/core-utils/tests/AndroidManifest.xml
deleted file mode 100644
index e3d060c..0000000
--- a/core-utils/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.coreutils.test">
-    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
-    <uses-permission android:name="android.permission.VIBRATE"/>
-    <uses-permission android:name="android.permission.WAKE_LOCK"/>
-    <uses-permission android:name="android.permission.READ_CONTACTS"/>
-    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
-
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-
-    <application>
-        <activity android:name="android.support.v4.widget.test.TextViewTestActivity"/>
-        <activity android:name="android.support.v4.app.FrameMetricsActivity"/>
-        <activity android:name="android.support.v4.app.FrameMetricsSubActivity"/>
-        <activity android:name="android.support.v4.widget.TestActivity"/>
-        <activity android:name="android.support.v4.provider.GrantActivity"
-                  android:label="_GrantActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN"/>
-                <category android:name="android.intent.category.LAUNCHER"/>
-            </intent-filter>
-        </activity>
-        <provider
-            android:name="android.support.v4.content.FileProvider"
-            android:authorities="moocow"
-            android:exported="false"
-            android:grantUriPermissions="true">
-            <meta-data
-                android:name="android.support.FILE_PROVIDER_PATHS"
-                android:resource="@xml/paths"/>
-        </provider>
-    </application>
-
-</manifest>
diff --git a/core-utils/tests/NO_DOCS b/core-utils/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/core-utils/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/core-utils/tests/java/android/support/v4/graphics/ColorUtilsTest.java b/core-utils/tests/java/android/support/v4/graphics/ColorUtilsTest.java
deleted file mode 100644
index 5a78c92..0000000
--- a/core-utils/tests/java/android/support/v4/graphics/ColorUtilsTest.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.graphics;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Color;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class ColorUtilsTest {
-
-    // 0.5% of the max value
-    private static final float ALLOWED_OFFSET_HUE = 360 * 0.005f;
-    private static final float ALLOWED_OFFSET_SATURATION = 0.005f;
-    private static final float ALLOWED_OFFSET_LIGHTNESS = 0.005f;
-    private static final float ALLOWED_OFFSET_MIN_ALPHA = 0.01f;
-    private static final double ALLOWED_OFFSET_LAB = 0.01;
-    private static final double ALLOWED_OFFSET_XYZ = 0.01;
-
-    private static final int ALLOWED_OFFSET_RGB_COMPONENT = 2;
-
-    private static final ArrayList<TestEntry> sEntryList = new ArrayList<>();
-
-    static {
-        sEntryList.add(new TestEntry(Color.BLACK).setHsl(0f, 0f, 0f)
-                .setLab(0, 0, 0).setXyz(0, 0, 0)
-                .setWhiteMinAlpha30(0.35f).setWhiteMinAlpha45(0.46f));
-
-        sEntryList.add(new TestEntry(Color.WHITE).setHsl(0f, 0f, 1f)
-                .setLab(100, 0.005, -0.01).setXyz(95.05, 100, 108.9)
-                .setBlackMinAlpha30(0.42f).setBlackMinAlpha45(0.54f));
-
-        sEntryList.add(new TestEntry(Color.BLUE).setHsl(240f, 1f, 0.5f)
-                .setLab(32.303, 79.197, -107.864).setXyz(18.05, 7.22, 95.05)
-                .setWhiteMinAlpha30(0.55f).setWhiteMinAlpha45(0.71f));
-
-        sEntryList.add(new TestEntry(Color.GREEN).setHsl(120f, 1f, 0.5f)
-                .setLab(87.737, -86.185, 83.181).setXyz(35.76, 71.520, 11.920)
-                .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
-
-        sEntryList.add(new TestEntry(Color.RED).setHsl(0f, 1f, 0.5f)
-                .setLab(53.233, 80.109, 67.22).setXyz(41.24, 21.26, 1.93)
-                .setWhiteMinAlpha30(0.84f).setBlackMinAlpha30(0.55f).setBlackMinAlpha45(0.78f));
-
-        sEntryList.add(new TestEntry(Color.CYAN).setHsl(180f, 1f, 0.5f)
-                .setLab(91.117, -48.08, -14.138).setXyz(53.81, 78.74, 106.97)
-                .setBlackMinAlpha30(0.43f).setBlackMinAlpha45(0.55f));
-
-        sEntryList.add(new TestEntry(0xFF2196F3).setHsl(207f, 0.9f, 0.54f)
-                .setLab(60.433, 2.091, -55.116).setXyz(27.711, 28.607, 88.855)
-                .setBlackMinAlpha30(0.52f).setWhiteMinAlpha30(0.97f).setBlackMinAlpha45(0.7f));
-
-        sEntryList.add(new TestEntry(0xFFD1C4E9).setHsl(261f, 0.46f, 0.84f)
-                .setLab(81.247, 11.513, -16.677).setXyz(60.742, 58.918, 85.262)
-                .setBlackMinAlpha30(0.45f).setBlackMinAlpha45(0.58f));
-
-        sEntryList.add(new TestEntry(0xFF311B92).setHsl(251.09f, 0.687f, 0.339f)
-                .setLab(21.988, 44.301, -60.942).setXyz(6.847, 3.512, 27.511)
-                .setWhiteMinAlpha30(0.39f).setWhiteMinAlpha45(0.54f));
-    }
-
-    @Test
-    public void testColorToHSL() {
-        for (TestEntry entry : sEntryList) {
-            verifyColorToHSL(entry.rgb, entry.hsl);
-        }
-    }
-
-    @Test
-    public void testHSLToColor() {
-        for (TestEntry entry : sEntryList) {
-            verifyHSLToColor(entry.hsl, entry.rgb);
-        }
-    }
-
-    @Test
-    public void testColorToHslLimits() {
-        final float[] hsl = new float[3];
-
-        for (TestEntry entry : sEntryList) {
-            ColorUtils.colorToHSL(entry.rgb, hsl);
-
-            assertTrue(hsl[0] >= 0f && hsl[0] <= 360f);
-            assertTrue(hsl[1] >= 0f && hsl[1] <= 1f);
-            assertTrue(hsl[2] >= 0f && hsl[2] <= 1f);
-        }
-    }
-
-    @Test
-    public void testColorToXYZ() {
-        for (TestEntry entry : sEntryList) {
-            verifyColorToXYZ(entry.rgb, entry.xyz);
-        }
-    }
-
-    @Test
-    public void testColorToLAB() {
-        for (TestEntry entry : sEntryList) {
-            verifyColorToLAB(entry.rgb, entry.lab);
-        }
-    }
-
-    @Test
-    public void testLABToXYZ() {
-        for (TestEntry entry : sEntryList) {
-            verifyLABToXYZ(entry.lab, entry.xyz);
-        }
-    }
-
-    @Test
-    public void testXYZToColor() {
-        for (TestEntry entry : sEntryList) {
-            verifyXYZToColor(entry.xyz, entry.rgb);
-        }
-    }
-
-    @Test
-    public void testLABToColor() {
-        for (TestEntry entry : sEntryList) {
-            verifyLABToColor(entry.lab, entry.rgb);
-        }
-    }
-
-    @Test
-    public void testMinAlphas() {
-        for (TestEntry entry : sEntryList) {
-            verifyMinAlpha("Black title", entry.rgb, entry.blackMinAlpha30,
-                    ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 3.0f));
-            verifyMinAlpha("Black body", entry.rgb, entry.blackMinAlpha45,
-                    ColorUtils.calculateMinimumAlpha(Color.BLACK, entry.rgb, 4.5f));
-            verifyMinAlpha("White title", entry.rgb, entry.whiteMinAlpha30,
-                    ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 3.0f));
-            verifyMinAlpha("White body", entry.rgb, entry.whiteMinAlpha45,
-                    ColorUtils.calculateMinimumAlpha(Color.WHITE, entry.rgb, 4.5f));
-        }
-    }
-
-    @Test
-    public void testCircularInterpolationForwards() {
-        assertEquals(0f, ColorUtils.circularInterpolate(0, 180, 0f), 0f);
-        assertEquals(90f, ColorUtils.circularInterpolate(0, 180, 0.5f), 0f);
-        assertEquals(180f, ColorUtils.circularInterpolate(0, 180, 1f), 0f);
-    }
-
-    @Test
-    public void testCircularInterpolationBackwards() {
-        assertEquals(180f, ColorUtils.circularInterpolate(180, 0, 0f), 0f);
-        assertEquals(90f, ColorUtils.circularInterpolate(180, 0, 0.5f), 0f);
-        assertEquals(0f, ColorUtils.circularInterpolate(180, 0, 1f), 0f);
-    }
-
-    @Test
-    public void testCircularInterpolationCrossZero() {
-        assertEquals(270f, ColorUtils.circularInterpolate(270, 90, 0f), 0f);
-        assertEquals(180f, ColorUtils.circularInterpolate(270, 90, 0.5f), 0f);
-        assertEquals(90f, ColorUtils.circularInterpolate(270, 90, 1f), 0f);
-    }
-
-    private static void verifyMinAlpha(String title, int color, float expected, int actual) {
-        final String message = title + " text within error for #" + Integer.toHexString(color);
-        if (expected < 0) {
-            assertEquals(message, actual, -1);
-        } else {
-            assertEquals(message, expected, actual / 255f, ALLOWED_OFFSET_MIN_ALPHA);
-        }
-    }
-
-    private static void verifyColorToHSL(int color, float[] expected) {
-        float[] actualHSL = new float[3];
-        ColorUtils.colorToHSL(color, actualHSL);
-
-        assertEquals("Hue not within offset", expected[0], actualHSL[0],
-                ALLOWED_OFFSET_HUE);
-        assertEquals("Saturation not within offset", expected[1], actualHSL[1],
-                ALLOWED_OFFSET_SATURATION);
-        assertEquals("Lightness not within offset", expected[2], actualHSL[2],
-                ALLOWED_OFFSET_LIGHTNESS);
-    }
-
-    private static void verifyHSLToColor(float[] hsl, int expected) {
-        final int actualRgb = ColorUtils.HSLToColor(hsl);
-
-        assertEquals("Red not within offset", Color.red(expected), Color.red(actualRgb),
-                ALLOWED_OFFSET_RGB_COMPONENT);
-        assertEquals("Green not within offset", Color.green(expected), Color.green(actualRgb),
-                ALLOWED_OFFSET_RGB_COMPONENT);
-        assertEquals("Blue not within offset", Color.blue(expected), Color.blue(actualRgb),
-                ALLOWED_OFFSET_RGB_COMPONENT);
-    }
-
-    private static void verifyColorToLAB(int color, double[] expected) {
-        double[] result = new double[3];
-        ColorUtils.colorToLAB(color, result);
-
-        assertEquals("L not within offset", expected[0], result[0], ALLOWED_OFFSET_LAB);
-        assertEquals("A not within offset", expected[1], result[1], ALLOWED_OFFSET_LAB);
-        assertEquals("B not within offset", expected[2], result[2], ALLOWED_OFFSET_LAB);
-    }
-
-    private static void verifyColorToXYZ(int color, double[] expected) {
-        double[] result = new double[3];
-        ColorUtils.colorToXYZ(color, result);
-
-        assertEquals("X not within offset", expected[0], result[0], ALLOWED_OFFSET_XYZ);
-        assertEquals("Y not within offset", expected[1], result[1], ALLOWED_OFFSET_XYZ);
-        assertEquals("Z not within offset", expected[2], result[2], ALLOWED_OFFSET_XYZ);
-    }
-
-    private static void verifyLABToXYZ(double[] lab, double[] expected) {
-        double[] result = new double[3];
-        ColorUtils.LABToXYZ(lab[0], lab[1], lab[2], result);
-
-        assertEquals("X not within offset", expected[0], result[0], ALLOWED_OFFSET_XYZ);
-        assertEquals("Y not within offset", expected[1], result[1], ALLOWED_OFFSET_XYZ);
-        assertEquals("Z not within offset", expected[2], result[2], ALLOWED_OFFSET_XYZ);
-    }
-
-    private static void verifyXYZToColor(double[] xyz, int expected) {
-        final int result = ColorUtils.XYZToColor(xyz[0], xyz[1], xyz[2]);
-        verifyRGBComponentsClose(expected, result);
-    }
-
-    private static void verifyLABToColor(double[] lab, int expected) {
-        final int result = ColorUtils.LABToColor(lab[0], lab[1], lab[2]);
-        verifyRGBComponentsClose(expected, result);
-    }
-
-    private static void verifyRGBComponentsClose(int expected, int actual) {
-        final String message = "Expected: #" + Integer.toHexString(expected)
-                + ", Actual: #" + Integer.toHexString(actual);
-        assertEquals("R not equal: " + message, Color.red(expected), Color.red(actual), 1);
-        assertEquals("G not equal: " + message, Color.green(expected), Color.green(actual), 1);
-        assertEquals("B not equal: " + message, Color.blue(expected), Color.blue(actual), 1);
-    }
-
-    private static class TestEntry {
-        final int rgb;
-        final float[] hsl = new float[3];
-        final double[] xyz = new double[3];
-        final double[] lab = new double[3];
-
-        float blackMinAlpha45 = -1;
-        float blackMinAlpha30 = -1;
-        float whiteMinAlpha45 = -1;
-        float whiteMinAlpha30 = -1;
-
-        TestEntry(int rgb) {
-            this.rgb = rgb;
-        }
-
-        TestEntry setHsl(float h, float s, float l) {
-            hsl[0] = h;
-            hsl[1] = s;
-            hsl[2] = l;
-            return this;
-        }
-
-        TestEntry setXyz(double x, double y, double z) {
-            xyz[0] = x;
-            xyz[1] = y;
-            xyz[2] = z;
-            return this;
-        }
-
-        TestEntry setLab(double l, double a, double b) {
-            lab[0] = l;
-            lab[1] = a;
-            lab[2] = b;
-            return this;
-        }
-
-        TestEntry setBlackMinAlpha30(float minAlpha) {
-            blackMinAlpha30 = minAlpha;
-            return this;
-        }
-
-        TestEntry setBlackMinAlpha45(float minAlpha) {
-            blackMinAlpha45 = minAlpha;
-            return this;
-        }
-
-        TestEntry setWhiteMinAlpha30(float minAlpha) {
-            whiteMinAlpha30 = minAlpha;
-            return this;
-        }
-
-        TestEntry setWhiteMinAlpha45(float minAlpha) {
-            whiteMinAlpha45 = minAlpha;
-            return this;
-        }
-    }
-}
\ No newline at end of file
diff --git a/core-utils/tests/java/android/support/v4/provider/GrantActivity.java b/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
deleted file mode 100644
index a354201..0000000
--- a/core-utils/tests/java/android/support/v4/provider/GrantActivity.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.provider;
-
-import android.app.Activity;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.os.Bundle;
-
-/**
- * Stub activity used to request a permission grant for
- * {@link DocumentFileTest}.
- */
-public class GrantActivity extends Activity {
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
-        startActivityForResult(intent, 12);
-    }
-
-    @Override
-    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-        if (requestCode == 12 && resultCode == RESULT_OK) {
-            final ContentResolver resolver = getContentResolver();
-            resolver.takePersistableUriPermission(data.getData(),
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-        }
-    }
-}
diff --git a/cursoradapter/api/current.txt b/cursoradapter/api/current.txt
new file mode 100644
index 0000000..07f7287
--- /dev/null
+++ b/cursoradapter/api/current.txt
@@ -0,0 +1,61 @@
+package android.support.v4.widget {
+
+  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+    ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
+    method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursor(android.database.Cursor);
+    method public java.lang.CharSequence convertToString(android.database.Cursor);
+    method public int getCount();
+    method public android.database.Cursor getCursor();
+    method public android.widget.Filter getFilter();
+    method public android.widget.FilterQueryProvider getFilterQueryProvider();
+    method public java.lang.Object getItem(int);
+    method public long getItemId(int);
+    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+    method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+    method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method protected void onContentChanged();
+    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+    field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+    field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
+  }
+
+  public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
+    ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
+    method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public void setDropDownViewResource(int);
+    method public void setViewResource(int);
+  }
+
+  public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
+    ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
+    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+    method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+    method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
+    method public int getStringConversionColumn();
+    method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
+    method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
+    method public void setStringConversionColumn(int);
+    method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
+    method public void setViewImage(android.widget.ImageView, java.lang.String);
+    method public void setViewText(android.widget.TextView, java.lang.String);
+  }
+
+  public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
+    method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+  }
+
+  public static abstract interface SimpleCursorAdapter.ViewBinder {
+    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+  }
+
+}
+
diff --git a/cursoradapter/build.gradle b/cursoradapter/build.gradle
new file mode 100644
index 0000000..d08a8bc
--- /dev/null
+++ b/cursoradapter/build.gradle
@@ -0,0 +1,19 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+}
+
+supportLibrary {
+    name = "Android Support Library Cursor Adapter"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/cursoradapter/src/main/AndroidManifest.xml b/cursoradapter/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6965f79
--- /dev/null
+++ b/cursoradapter/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.cursoradapter"/>
diff --git a/core-ui/src/main/java/android/support/v4/widget/CursorAdapter.java b/cursoradapter/src/main/java/android/support/v4/widget/CursorAdapter.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/CursorAdapter.java
rename to cursoradapter/src/main/java/android/support/v4/widget/CursorAdapter.java
diff --git a/core-ui/src/main/java/android/support/v4/widget/CursorFilter.java b/cursoradapter/src/main/java/android/support/v4/widget/CursorFilter.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/CursorFilter.java
rename to cursoradapter/src/main/java/android/support/v4/widget/CursorFilter.java
diff --git a/cursoradapter/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java b/cursoradapter/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java
new file mode 100644
index 0000000..57051ca
--- /dev/null
+++ b/cursoradapter/src/main/java/android/support/v4/widget/ResourceCursorAdapter.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Static library support version of the framework's {@link android.widget.ResourceCursorAdapter}.
+ * Used to write apps that run on platforms prior to Android 3.0.  When running
+ * on Android 3.0 or above, this implementation is still used; it does not try
+ * to switch to the framework's implementation.  See the framework SDK
+ * documentation for a class overview.
+ */
+public abstract class ResourceCursorAdapter extends CursorAdapter {
+    private int mLayout;
+
+    private int mDropDownLayout;
+
+    private LayoutInflater mInflater;
+
+    /**
+     * Constructor the enables auto-requery.
+     *
+     * @deprecated This option is discouraged, as it results in Cursor queries
+     * being performed on the application's UI thread and thus can cause poor
+     * responsiveness or even Application Not Responding errors.  As an alternative,
+     * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
+     *
+     * @param context The context where the ListView associated with this adapter is running
+     * @param layout resource identifier of a layout file that defines the views
+     *            for this list item.  Unless you override them later, this will
+     *            define both the item views and the drop down views.
+     */
+    @Deprecated
+    public ResourceCursorAdapter(Context context, int layout, Cursor c) {
+        super(context, c);
+        mLayout = mDropDownLayout = layout;
+        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    }
+
+    /**
+     * Constructor with default behavior as per
+     * {@link CursorAdapter#CursorAdapter(Context, Cursor, boolean)}; it is recommended
+     * you not use this, but instead {@link #ResourceCursorAdapter(Context, int, Cursor, int)}.
+     * When using this constructor, {@link #FLAG_REGISTER_CONTENT_OBSERVER}
+     * will always be set.
+     *
+     * @deprecated This option is discouraged, as it results in Cursor queries
+     * being performed on the application's UI thread and thus can cause poor
+     * responsiveness or even Application Not Responding errors.  As an alternative,
+     * use {@link android.app.LoaderManager} with a {@link android.content.CursorLoader}.
+     *
+     * @param context The context where the ListView associated with this adapter is running
+     * @param layout resource identifier of a layout file that defines the views
+     *            for this list item.  Unless you override them later, this will
+     *            define both the item views and the drop down views.
+     * @param c The cursor from which to get the data.
+     * @param autoRequery If true the adapter will call requery() on the
+     *                    cursor whenever it changes so the most recent
+     *                    data is always displayed.  Using true here is discouraged.
+     */
+    @Deprecated
+    public ResourceCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) {
+        super(context, c, autoRequery);
+        mLayout = mDropDownLayout = layout;
+        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    }
+
+    /**
+     * Standard constructor.
+     *
+     * @param context The context where the ListView associated with this adapter is running
+     * @param layout Resource identifier of a layout file that defines the views
+     *            for this list item.  Unless you override them later, this will
+     *            define both the item views and the drop down views.
+     * @param c The cursor from which to get the data.
+     * @param flags Flags used to determine the behavior of the adapter,
+     * as per {@link CursorAdapter#CursorAdapter(Context, Cursor, int)}.
+     */
+    public ResourceCursorAdapter(Context context, int layout, Cursor c, int flags) {
+        super(context, c, flags);
+        mLayout = mDropDownLayout = layout;
+        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    }
+
+    /**
+     * Inflates view(s) from the specified XML file.
+     *
+     * @see android.widget.CursorAdapter#newView(android.content.Context,
+     *      android.database.Cursor, ViewGroup)
+     */
+    @Override
+    public View newView(Context context, Cursor cursor, ViewGroup parent) {
+        return mInflater.inflate(mLayout, parent, false);
+    }
+
+    @Override
+    public View newDropDownView(Context context, Cursor cursor, ViewGroup parent) {
+        return mInflater.inflate(mDropDownLayout, parent, false);
+    }
+
+    /**
+     * <p>Sets the layout resource of the item views.</p>
+     *
+     * @param layout the layout resources used to create item views
+     */
+    public void setViewResource(int layout) {
+        mLayout = layout;
+    }
+
+    /**
+     * <p>Sets the layout resource of the drop down views.</p>
+     *
+     * @param dropDownLayout the layout resources used to create drop down views
+     */
+    public void setDropDownViewResource(int dropDownLayout) {
+        mDropDownLayout = dropDownLayout;
+    }
+}
diff --git a/core-ui/src/main/java/android/support/v4/widget/SimpleCursorAdapter.java b/cursoradapter/src/main/java/android/support/v4/widget/SimpleCursorAdapter.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/SimpleCursorAdapter.java
rename to cursoradapter/src/main/java/android/support/v4/widget/SimpleCursorAdapter.java
diff --git a/customtabs/Android.mk b/customtabs/Android.mk
deleted file mode 100644
index 27b92a0..0000000
--- a/customtabs/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-customtabs \
-#       android-support-compat
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-customtabs
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src/main/java
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,src/main/java) \
-    $(call all-Iaidl-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v7-appcompat \
-    android-support-compat \
-    android-support-core-ui
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/customtabs/AndroidManifest.xml b/customtabs/AndroidManifest.xml
deleted file mode 100644
index c913ad6..0000000
--- a/customtabs/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.customtabs">
-    <uses-sdk android:minSdkVersion="15"/>
-</manifest>
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index a15566a..ced95b8 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -17,12 +17,6 @@
     androidTestImplementation(project(":support-testutils"))
 }
 
-android {
-    sourceSets {
-        main.aidl.srcDirs = ["src/main/java"]
-    }
-}
-
 supportLibrary {
     name = "Android Support Custom Tabs"
     publish = true
@@ -30,6 +24,5 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Custom Tabs"
-    legacySourceLocation = true
     minSdkVersion = 15
 }
diff --git a/customtabs/tests/AndroidManifest.xml b/customtabs/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from customtabs/tests/AndroidManifest.xml
rename to customtabs/src/androidTest/AndroidManifest.xml
diff --git a/customtabs/tests/src/android/support/customtabs/CustomTabsIntentTest.java b/customtabs/src/androidTest/java/android/support/customtabs/CustomTabsIntentTest.java
similarity index 100%
rename from customtabs/tests/src/android/support/customtabs/CustomTabsIntentTest.java
rename to customtabs/src/androidTest/java/android/support/customtabs/CustomTabsIntentTest.java
diff --git a/customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
similarity index 100%
rename from customtabs/tests/src/android/support/customtabs/PostMessageServiceConnectionTest.java
rename to customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
diff --git a/customtabs/tests/src/android/support/customtabs/PostMessageTest.java b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
similarity index 100%
rename from customtabs/tests/src/android/support/customtabs/PostMessageTest.java
rename to customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
diff --git a/customtabs/tests/src/android/support/customtabs/TestActivity.java b/customtabs/src/androidTest/java/android/support/customtabs/TestActivity.java
similarity index 100%
rename from customtabs/tests/src/android/support/customtabs/TestActivity.java
rename to customtabs/src/androidTest/java/android/support/customtabs/TestActivity.java
diff --git a/customtabs/tests/src/android/support/customtabs/TestCustomTabsCallback.java b/customtabs/src/androidTest/java/android/support/customtabs/TestCustomTabsCallback.java
similarity index 100%
rename from customtabs/tests/src/android/support/customtabs/TestCustomTabsCallback.java
rename to customtabs/src/androidTest/java/android/support/customtabs/TestCustomTabsCallback.java
diff --git a/customtabs/tests/src/android/support/customtabs/TestCustomTabsService.java b/customtabs/src/androidTest/java/android/support/customtabs/TestCustomTabsService.java
similarity index 100%
rename from customtabs/tests/src/android/support/customtabs/TestCustomTabsService.java
rename to customtabs/src/androidTest/java/android/support/customtabs/TestCustomTabsService.java
diff --git a/customtabs/tests/src/android/support/customtabs/TrustedWebUtilsTest.java b/customtabs/src/androidTest/java/android/support/customtabs/TrustedWebUtilsTest.java
similarity index 100%
rename from customtabs/tests/src/android/support/customtabs/TrustedWebUtilsTest.java
rename to customtabs/src/androidTest/java/android/support/customtabs/TrustedWebUtilsTest.java
diff --git a/customtabs/tests/src/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java b/customtabs/src/androidTest/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java
similarity index 100%
rename from customtabs/tests/src/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java
rename to customtabs/src/androidTest/java/androidx/browser/browseractions/BrowserActionsFallbackMenuUiTest.java
diff --git a/customtabs/tests/src/androidx/browser/browseractions/BrowserActionsIntentTest.java b/customtabs/src/androidTest/java/androidx/browser/browseractions/BrowserActionsIntentTest.java
similarity index 100%
rename from customtabs/tests/src/androidx/browser/browseractions/BrowserActionsIntentTest.java
rename to customtabs/src/androidTest/java/androidx/browser/browseractions/BrowserActionsIntentTest.java
diff --git a/customtabs/src/main/AndroidManifest.xml b/customtabs/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..38a0e4f
--- /dev/null
+++ b/customtabs/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.customtabs"/>
diff --git a/customtabs/src/main/java/android/support/customtabs/ICustomTabsCallback.aidl b/customtabs/src/main/aidl/android/support/customtabs/ICustomTabsCallback.aidl
similarity index 100%
rename from customtabs/src/main/java/android/support/customtabs/ICustomTabsCallback.aidl
rename to customtabs/src/main/aidl/android/support/customtabs/ICustomTabsCallback.aidl
diff --git a/customtabs/src/main/java/android/support/customtabs/ICustomTabsService.aidl b/customtabs/src/main/aidl/android/support/customtabs/ICustomTabsService.aidl
similarity index 100%
rename from customtabs/src/main/java/android/support/customtabs/ICustomTabsService.aidl
rename to customtabs/src/main/aidl/android/support/customtabs/ICustomTabsService.aidl
diff --git a/customtabs/src/main/java/android/support/customtabs/IPostMessageService.aidl b/customtabs/src/main/aidl/android/support/customtabs/IPostMessageService.aidl
similarity index 100%
rename from customtabs/src/main/java/android/support/customtabs/IPostMessageService.aidl
rename to customtabs/src/main/aidl/android/support/customtabs/IPostMessageService.aidl
diff --git a/customtabs/tests/NO_DOCS b/customtabs/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/customtabs/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/customview/api/current.txt b/customview/api/current.txt
new file mode 100644
index 0000000..1e8a9c1
--- /dev/null
+++ b/customview/api/current.txt
@@ -0,0 +1,105 @@
+package android.support.v4.view {
+
+  public abstract class AbsSavedState implements android.os.Parcelable {
+    ctor protected AbsSavedState(android.os.Parcelable);
+    ctor protected AbsSavedState(android.os.Parcel);
+    ctor protected AbsSavedState(android.os.Parcel, java.lang.ClassLoader);
+    method public int describeContents();
+    method public final android.os.Parcelable getSuperState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.view.AbsSavedState> CREATOR;
+    field public static final android.support.v4.view.AbsSavedState EMPTY_STATE;
+  }
+
+}
+
+package android.support.v4.widget {
+
+  public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public ExploreByTouchHelper(android.view.View);
+    method public final boolean clearKeyboardFocusForVirtualView(int);
+    method public final boolean dispatchHoverEvent(android.view.MotionEvent);
+    method public final boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public final int getAccessibilityFocusedVirtualViewId();
+    method public deprecated int getFocusedVirtualView();
+    method public final int getKeyboardFocusedVirtualViewId();
+    method protected abstract int getVirtualViewAt(float, float);
+    method protected abstract void getVisibleVirtualViews(java.util.List<java.lang.Integer>);
+    method public final void invalidateRoot();
+    method public final void invalidateVirtualView(int);
+    method public final void invalidateVirtualView(int, int);
+    method public final void onFocusChanged(boolean, int, android.graphics.Rect);
+    method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
+    method protected void onPopulateEventForHost(android.view.accessibility.AccessibilityEvent);
+    method protected void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
+    method protected void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method protected void onVirtualViewKeyboardFocusChanged(int, boolean);
+    method public final boolean requestKeyboardFocusForVirtualView(int);
+    method public final boolean sendEventForVirtualView(int, int);
+    field public static final int HOST_ID = -1; // 0xffffffff
+    field public static final int INVALID_ID = -2147483648; // 0x80000000
+  }
+
+  public class ViewDragHelper {
+    method public void abort();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int, int);
+    method public void cancel();
+    method public void captureChildView(android.view.View, int);
+    method public boolean checkTouchSlop(int);
+    method public boolean checkTouchSlop(int, int);
+    method public boolean continueSettling(boolean);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, android.support.v4.widget.ViewDragHelper.Callback);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, float, android.support.v4.widget.ViewDragHelper.Callback);
+    method public android.view.View findTopChildUnder(int, int);
+    method public void flingCapturedView(int, int, int, int);
+    method public int getActivePointerId();
+    method public android.view.View getCapturedView();
+    method public int getEdgeSize();
+    method public float getMinVelocity();
+    method public int getTouchSlop();
+    method public int getViewDragState();
+    method public boolean isCapturedViewUnder(int, int);
+    method public boolean isEdgeTouched(int);
+    method public boolean isEdgeTouched(int, int);
+    method public boolean isPointerDown(int);
+    method public boolean isViewUnder(android.view.View, int, int);
+    method public void processTouchEvent(android.view.MotionEvent);
+    method public void setEdgeTrackingEnabled(int);
+    method public void setMinVelocity(float);
+    method public boolean settleCapturedViewAt(int, int);
+    method public boolean shouldInterceptTouchEvent(android.view.MotionEvent);
+    method public boolean smoothSlideViewTo(android.view.View, int, int);
+    field public static final int DIRECTION_ALL = 3; // 0x3
+    field public static final int DIRECTION_HORIZONTAL = 1; // 0x1
+    field public static final int DIRECTION_VERTICAL = 2; // 0x2
+    field public static final int EDGE_ALL = 15; // 0xf
+    field public static final int EDGE_BOTTOM = 8; // 0x8
+    field public static final int EDGE_LEFT = 1; // 0x1
+    field public static final int EDGE_RIGHT = 2; // 0x2
+    field public static final int EDGE_TOP = 4; // 0x4
+    field public static final int INVALID_POINTER = -1; // 0xffffffff
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class ViewDragHelper.Callback {
+    ctor public ViewDragHelper.Callback();
+    method public int clampViewPositionHorizontal(android.view.View, int, int);
+    method public int clampViewPositionVertical(android.view.View, int, int);
+    method public int getOrderedChildIndex(int);
+    method public int getViewHorizontalDragRange(android.view.View);
+    method public int getViewVerticalDragRange(android.view.View);
+    method public void onEdgeDragStarted(int, int);
+    method public boolean onEdgeLock(int);
+    method public void onEdgeTouched(int, int);
+    method public void onViewCaptured(android.view.View, int);
+    method public void onViewDragStateChanged(int);
+    method public void onViewPositionChanged(android.view.View, int, int, int, int);
+    method public void onViewReleased(android.view.View, float, float);
+    method public abstract boolean tryCaptureView(android.view.View, int);
+  }
+
+}
+
diff --git a/customview/build.gradle b/customview/build.gradle
new file mode 100644
index 0000000..108ec71
--- /dev/null
+++ b/customview/build.gradle
@@ -0,0 +1,25 @@
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+
+    androidTestImplementation(JUNIT)
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(TEST_RULES)
+}
+
+supportLibrary {
+    name = "Android Support Library Custom View"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/customview/src/androidTest/AndroidManifest.xml b/customview/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..e65bd94
--- /dev/null
+++ b/customview/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.customview.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <application android:supportsRtl="true">
+        <activity android:name="android.support.v4.widget.ExploreByTouchHelperTestActivity"/>
+    </application>
+
+</manifest>
diff --git a/customview/src/androidTest/java/android/support/v4/widget/ExploreByTouchHelperTest.java b/customview/src/androidTest/java/android/support/v4/widget/ExploreByTouchHelperTest.java
new file mode 100644
index 0000000..4fe9aa0
--- /dev/null
+++ b/customview/src/androidTest/java/android/support/v4/widget/ExploreByTouchHelperTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.customview.test.R;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ExploreByTouchHelperTest {
+    @Rule
+    public final ActivityTestRule<ExploreByTouchHelperTestActivity> mActivityTestRule;
+
+    private View mHost;
+
+    public ExploreByTouchHelperTest() {
+        mActivityTestRule = new ActivityTestRule<>(ExploreByTouchHelperTestActivity.class);
+    }
+
+    @Before
+    public void setUp() {
+        mHost = mActivityTestRule.getActivity().findViewById(R.id.host_view);
+    }
+
+    @Test
+    @UiThreadTest
+    public void testBoundsInScreen() {
+        final ExploreByTouchHelper helper = new ParentBoundsHelper(mHost);
+        ViewCompat.setAccessibilityDelegate(mHost, helper);
+
+        final AccessibilityNodeInfoCompat node =
+                helper.getAccessibilityNodeProvider(mHost).createAccessibilityNodeInfo(1);
+        assertNotNull(node);
+
+        final Rect hostBounds = new Rect();
+        mHost.getLocalVisibleRect(hostBounds);
+        assertFalse("Host has not been laid out", hostBounds.isEmpty());
+
+        final Rect nodeBoundsInParent = new Rect();
+        node.getBoundsInParent(nodeBoundsInParent);
+        assertEquals("Wrong bounds in parent", hostBounds, nodeBoundsInParent);
+
+        final Rect hostBoundsOnScreen = getBoundsOnScreen(mHost);
+        final Rect nodeBoundsInScreen = new Rect();
+        node.getBoundsInScreen(nodeBoundsInScreen);
+        assertEquals("Wrong bounds in screen", hostBoundsOnScreen, nodeBoundsInScreen);
+
+        final int scrollX = 100;
+        final int scrollY = 50;
+        mHost.scrollTo(scrollX, scrollY);
+
+        // Generate a node for the new position.
+        final AccessibilityNodeInfoCompat scrolledNode =
+                helper.getAccessibilityNodeProvider(mHost).createAccessibilityNodeInfo(1);
+        assertNotNull(scrolledNode);
+
+        // Bounds in parent should not be affected by visibility.
+        final Rect scrolledNodeBoundsInParent = new Rect();
+        scrolledNode.getBoundsInParent(scrolledNodeBoundsInParent);
+        assertEquals("Wrong bounds in parent after scrolling",
+                hostBounds, scrolledNodeBoundsInParent);
+
+        final Rect expectedBoundsInScreen = new Rect(hostBoundsOnScreen);
+        expectedBoundsInScreen.offset(-scrollX, -scrollY);
+        expectedBoundsInScreen.intersect(hostBoundsOnScreen);
+        scrolledNode.getBoundsInScreen(nodeBoundsInScreen);
+        assertEquals("Wrong bounds in screen after scrolling",
+                expectedBoundsInScreen, nodeBoundsInScreen);
+
+        ViewCompat.setAccessibilityDelegate(mHost, null);
+    }
+
+    private static Rect getBoundsOnScreen(View v) {
+        final int[] tempLocation = new int[2];
+        final Rect hostBoundsOnScreen = new Rect(0, 0, v.getWidth(), v.getHeight());
+        v.getLocationOnScreen(tempLocation);
+        hostBoundsOnScreen.offset(tempLocation[0], tempLocation[1]);
+        return hostBoundsOnScreen;
+    }
+
+    /**
+     * An extension of ExploreByTouchHelper that contains a single virtual view
+     * whose bounds match the host view.
+     */
+    private static class ParentBoundsHelper extends ExploreByTouchHelper {
+        private final View mHost;
+
+        ParentBoundsHelper(View host) {
+            super(host);
+
+            mHost = host;
+        }
+
+        @Override
+        protected int getVirtualViewAt(float x, float y) {
+            return 1;
+        }
+
+        @Override
+        protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {
+            virtualViewIds.add(1);
+        }
+
+        @Override
+        protected void onPopulateNodeForVirtualView(int virtualViewId,
+                @NonNull AccessibilityNodeInfoCompat node) {
+            if (virtualViewId == 1) {
+                node.setContentDescription("test");
+
+                final Rect hostBounds = new Rect(0, 0, mHost.getWidth(), mHost.getHeight());
+                node.setBoundsInParent(hostBounds);
+            }
+        }
+
+        @Override
+        protected boolean onPerformActionForVirtualView(int virtualViewId, int action,
+                Bundle arguments) {
+            return false;
+        }
+    }
+}
diff --git a/customview/src/androidTest/java/android/support/v4/widget/ExploreByTouchHelperTestActivity.java b/customview/src/androidTest/java/android/support/v4/widget/ExploreByTouchHelperTestActivity.java
new file mode 100644
index 0000000..16e3faa
--- /dev/null
+++ b/customview/src/androidTest/java/android/support/v4/widget/ExploreByTouchHelperTestActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.customview.test.R;
+
+public class ExploreByTouchHelperTestActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.explore_by_touch_helper_activity);
+    }
+}
diff --git a/core-ui/tests/res/layout/explore_by_touch_helper_activity.xml b/customview/src/androidTest/res/layout/explore_by_touch_helper_activity.xml
similarity index 100%
rename from core-ui/tests/res/layout/explore_by_touch_helper_activity.xml
rename to customview/src/androidTest/res/layout/explore_by_touch_helper_activity.xml
diff --git a/customview/src/main/AndroidManifest.xml b/customview/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..30bedbe
--- /dev/null
+++ b/customview/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.customview"/>
diff --git a/core-ui/src/main/java/android/support/v4/view/AbsSavedState.java b/customview/src/main/java/android/support/v4/view/AbsSavedState.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/AbsSavedState.java
rename to customview/src/main/java/android/support/v4/view/AbsSavedState.java
diff --git a/customview/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java b/customview/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java
new file mode 100644
index 0000000..d7de9be
--- /dev/null
+++ b/customview/src/main/java/android/support/v4/widget/ExploreByTouchHelper.java
@@ -0,0 +1,1262 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.SparseArrayCompat;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.ViewCompat.FocusDirection;
+import android.support.v4.view.ViewCompat.FocusRealDirection;
+import android.support.v4.view.ViewParentCompat;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
+import android.support.v4.view.accessibility.AccessibilityRecordCompat;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityRecord;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * ExploreByTouchHelper is a utility class for implementing accessibility
+ * support in custom {@link View}s that represent a collection of View-like
+ * logical items. It extends {@link AccessibilityNodeProviderCompat} and
+ * simplifies many aspects of providing information to accessibility services
+ * and managing accessibility focus.
+ * <p>
+ * Clients should override abstract methods on this class and attach it to the
+ * host view using {@link ViewCompat#setAccessibilityDelegate}:
+ * <p>
+ * <pre>
+ * class MyCustomView extends View {
+ *     private MyVirtualViewHelper mVirtualViewHelper;
+ *
+ *     public MyCustomView(Context context, ...) {
+ *         ...
+ *         mVirtualViewHelper = new MyVirtualViewHelper(this);
+ *         ViewCompat.setAccessibilityDelegate(this, mVirtualViewHelper);
+ *     }
+ *
+ *     &#64;Override
+ *     public boolean dispatchHoverEvent(MotionEvent event) {
+ *       return mHelper.dispatchHoverEvent(this, event)
+ *           || super.dispatchHoverEvent(event);
+ *     }
+ *
+ *     &#64;Override
+ *     public boolean dispatchKeyEvent(KeyEvent event) {
+ *       return mHelper.dispatchKeyEvent(event)
+ *           || super.dispatchKeyEvent(event);
+ *     }
+ *
+ *     &#64;Override
+ *     public boolean onFocusChanged(boolean gainFocus, int direction,
+ *         Rect previouslyFocusedRect) {
+ *       super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ *       mHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+ *     }
+ * }
+ * mAccessHelper = new MyExploreByTouchHelper(someView);
+ * ViewCompat.setAccessibilityDelegate(someView, mAccessHelper);
+ * </pre>
+ */
+public abstract class ExploreByTouchHelper extends AccessibilityDelegateCompat {
+    /** Virtual node identifier value for invalid nodes. */
+    public static final int INVALID_ID = Integer.MIN_VALUE;
+
+    /** Virtual node identifier value for the host view's node. */
+    public static final int HOST_ID = View.NO_ID;
+
+    /** Default class name used for virtual views. */
+    private static final String DEFAULT_CLASS_NAME = "android.view.View";
+
+    /** Default bounds used to determine if the client didn't set any. */
+    private static final Rect INVALID_PARENT_BOUNDS = new Rect(
+            Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
+
+    // Temporary, reusable data structures.
+    private final Rect mTempScreenRect = new Rect();
+    private final Rect mTempParentRect = new Rect();
+    private final Rect mTempVisibleRect = new Rect();
+    private final int[] mTempGlobalRect = new int[2];
+
+    /** System accessibility manager, used to check state and send events. */
+    private final AccessibilityManager mManager;
+
+    /** View whose internal structure is exposed through this helper. */
+    private final View mHost;
+
+    /** Virtual node provider used to expose logical structure to services. */
+    private MyNodeProvider mNodeProvider;
+
+    /** Identifier for the virtual view that holds accessibility focus. */
+    private int mAccessibilityFocusedVirtualViewId = INVALID_ID;
+
+    /** Identifier for the virtual view that holds keyboard focus. */
+    private int mKeyboardFocusedVirtualViewId = INVALID_ID;
+
+    /** Identifier for the virtual view that is currently hovered. */
+    private int mHoveredVirtualViewId = INVALID_ID;
+
+    /**
+     * Constructs a new helper that can expose a virtual view hierarchy for the
+     * specified host view.
+     *
+     * @param host view whose virtual view hierarchy is exposed by this helper
+     */
+    public ExploreByTouchHelper(@NonNull View host) {
+        if (host == null) {
+            throw new IllegalArgumentException("View may not be null");
+        }
+
+        mHost = host;
+
+        final Context context = host.getContext();
+        mManager = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+
+        // Host view must be focusable so that we can delegate to virtual
+        // views.
+        host.setFocusable(true);
+        if (ViewCompat.getImportantForAccessibility(host)
+                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            ViewCompat.setImportantForAccessibility(
+                    host, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    @Override
+    public AccessibilityNodeProviderCompat getAccessibilityNodeProvider(View host) {
+        if (mNodeProvider == null) {
+            mNodeProvider = new MyNodeProvider();
+        }
+        return mNodeProvider;
+    }
+
+    /**
+     * Delegates hover events from the host view.
+     * <p>
+     * Dispatches hover {@link MotionEvent}s to the virtual view hierarchy when
+     * the Explore by Touch feature is enabled.
+     * <p>
+     * This method should be called by overriding the host view's
+     * {@link View#dispatchHoverEvent(MotionEvent)} method:
+     * <pre>&#64;Override
+     * public boolean dispatchHoverEvent(MotionEvent event) {
+     *   return mHelper.dispatchHoverEvent(this, event)
+     *       || super.dispatchHoverEvent(event);
+     * }
+     * </pre>
+     *
+     * @param event The hover event to dispatch to the virtual view hierarchy.
+     * @return Whether the hover event was handled.
+     */
+    public final boolean dispatchHoverEvent(@NonNull MotionEvent event) {
+        if (!mManager.isEnabled() || !mManager.isTouchExplorationEnabled()) {
+            return false;
+        }
+
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_HOVER_MOVE:
+            case MotionEvent.ACTION_HOVER_ENTER:
+                final int virtualViewId = getVirtualViewAt(event.getX(), event.getY());
+                updateHoveredVirtualView(virtualViewId);
+                return (virtualViewId != INVALID_ID);
+            case MotionEvent.ACTION_HOVER_EXIT:
+                if (mAccessibilityFocusedVirtualViewId != INVALID_ID) {
+                    updateHoveredVirtualView(INVALID_ID);
+                    return true;
+                }
+                return false;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Delegates key events from the host view.
+     * <p>
+     * This method should be called by overriding the host view's
+     * {@link View#dispatchKeyEvent(KeyEvent)} method:
+     * <pre>&#64;Override
+     * public boolean dispatchKeyEvent(KeyEvent event) {
+     *   return mHelper.dispatchKeyEvent(event)
+     *       || super.dispatchKeyEvent(event);
+     * }
+     * </pre>
+     */
+    public final boolean dispatchKeyEvent(@NonNull KeyEvent event) {
+        boolean handled = false;
+
+        final int action = event.getAction();
+        if (action != KeyEvent.ACTION_UP) {
+            final int keyCode = event.getKeyCode();
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_DPAD_LEFT:
+                case KeyEvent.KEYCODE_DPAD_UP:
+                case KeyEvent.KEYCODE_DPAD_RIGHT:
+                case KeyEvent.KEYCODE_DPAD_DOWN:
+                    if (event.hasNoModifiers()) {
+                        final int direction = keyToDirection(keyCode);
+                        final int count = 1 + event.getRepeatCount();
+                        for (int i = 0; i < count; i++) {
+                            if (moveFocus(direction, null)) {
+                                handled = true;
+                            } else {
+                                break;
+                            }
+                        }
+                    }
+                    break;
+                case KeyEvent.KEYCODE_DPAD_CENTER:
+                case KeyEvent.KEYCODE_ENTER:
+                    if (event.hasNoModifiers()) {
+                        if (event.getRepeatCount() == 0) {
+                            clickKeyboardFocusedVirtualView();
+                            handled = true;
+                        }
+                    }
+                    break;
+                case KeyEvent.KEYCODE_TAB:
+                    if (event.hasNoModifiers()) {
+                        handled = moveFocus(View.FOCUS_FORWARD, null);
+                    } else if (event.hasModifiers(KeyEvent.META_SHIFT_ON)) {
+                        handled = moveFocus(View.FOCUS_BACKWARD, null);
+                    }
+                    break;
+            }
+        }
+
+        return handled;
+    }
+
+    /**
+     * Delegates focus changes from the host view.
+     * <p>
+     * This method should be called by overriding the host view's
+     * {@link View#onFocusChanged(boolean, int, Rect)} method:
+     * <pre>&#64;Override
+     * public boolean onFocusChanged(boolean gainFocus, int direction,
+     *     Rect previouslyFocusedRect) {
+     *   super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+     *   mHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+     * }
+     * </pre>
+     */
+    public final void onFocusChanged(boolean gainFocus, int direction,
+            @Nullable Rect previouslyFocusedRect) {
+        if (mKeyboardFocusedVirtualViewId != INVALID_ID) {
+            clearKeyboardFocusForVirtualView(mKeyboardFocusedVirtualViewId);
+        }
+
+        if (gainFocus) {
+            moveFocus(direction, previouslyFocusedRect);
+        }
+    }
+
+    /**
+     * @return the identifier of the virtual view that has accessibility focus
+     *         or {@link #INVALID_ID} if no virtual view has accessibility
+     *         focus
+     */
+    public final int getAccessibilityFocusedVirtualViewId() {
+        return mAccessibilityFocusedVirtualViewId;
+    }
+
+    /**
+     * @return the identifier of the virtual view that has keyboard focus
+     *         or {@link #INVALID_ID} if no virtual view has keyboard focus
+     */
+    public final int getKeyboardFocusedVirtualViewId() {
+        return mKeyboardFocusedVirtualViewId;
+    }
+
+    /**
+     * Maps key event codes to focus directions.
+     *
+     * @param keyCode the key event code
+     * @return the corresponding focus direction
+     */
+    @FocusRealDirection
+    private static int keyToDirection(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                return View.FOCUS_LEFT;
+            case KeyEvent.KEYCODE_DPAD_UP:
+                return View.FOCUS_UP;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                return View.FOCUS_RIGHT;
+            default:
+                return View.FOCUS_DOWN;
+        }
+    }
+
+    /**
+     * Obtains the bounds for the specified virtual view.
+     *
+     * @param virtualViewId the identifier of the virtual view
+     * @param outBounds the rect to populate with virtual view bounds
+     */
+    private void getBoundsInParent(int virtualViewId, Rect outBounds) {
+        final AccessibilityNodeInfoCompat node = obtainAccessibilityNodeInfo(virtualViewId);
+        node.getBoundsInParent(outBounds);
+    }
+
+    /**
+     * Adapts AccessibilityNodeInfoCompat for obtaining bounds.
+     */
+    private static final FocusStrategy.BoundsAdapter<AccessibilityNodeInfoCompat> NODE_ADAPTER =
+            new FocusStrategy.BoundsAdapter<AccessibilityNodeInfoCompat>() {
+                @Override
+                public void obtainBounds(AccessibilityNodeInfoCompat node, Rect outBounds) {
+                    node.getBoundsInParent(outBounds);
+                }
+            };
+
+    /**
+     * Adapts SparseArrayCompat for iterating through values.
+     */
+    private static final FocusStrategy.CollectionAdapter<SparseArrayCompat<
+            AccessibilityNodeInfoCompat>, AccessibilityNodeInfoCompat> SPARSE_VALUES_ADAPTER =
+            new FocusStrategy.CollectionAdapter<SparseArrayCompat<
+                    AccessibilityNodeInfoCompat>, AccessibilityNodeInfoCompat>() {
+                @Override
+                public AccessibilityNodeInfoCompat get(
+                        SparseArrayCompat<AccessibilityNodeInfoCompat> collection, int index) {
+                    return collection.valueAt(index);
+                }
+
+                @Override
+                public int size(SparseArrayCompat<AccessibilityNodeInfoCompat> collection) {
+                    return collection.size();
+                }
+            };
+
+    /**
+     * Attempts to move keyboard focus in the specified direction.
+     *
+     * @param direction the direction in which to move keyboard focus
+     * @param previouslyFocusedRect the bounds of the previously focused item,
+     *                              or {@code null} if not available
+     * @return {@code true} if keyboard focus moved to a virtual view managed
+     *         by this helper, or {@code false} otherwise
+     */
+    private boolean moveFocus(@FocusDirection int direction, @Nullable Rect previouslyFocusedRect) {
+        final SparseArrayCompat<AccessibilityNodeInfoCompat> allNodes = getAllNodes();
+
+        final int focusedNodeId = mKeyboardFocusedVirtualViewId;
+        final AccessibilityNodeInfoCompat focusedNode =
+                focusedNodeId == INVALID_ID ? null : allNodes.get(focusedNodeId);
+
+        final AccessibilityNodeInfoCompat nextFocusedNode;
+        switch (direction) {
+            case View.FOCUS_FORWARD:
+            case View.FOCUS_BACKWARD:
+                final boolean isLayoutRtl =
+                        ViewCompat.getLayoutDirection(mHost) == ViewCompat.LAYOUT_DIRECTION_RTL;
+                nextFocusedNode = FocusStrategy.findNextFocusInRelativeDirection(allNodes,
+                        SPARSE_VALUES_ADAPTER, NODE_ADAPTER, focusedNode, direction, isLayoutRtl,
+                        false);
+                break;
+            case View.FOCUS_LEFT:
+            case View.FOCUS_UP:
+            case View.FOCUS_RIGHT:
+            case View.FOCUS_DOWN:
+                final Rect selectedRect = new Rect();
+                if (mKeyboardFocusedVirtualViewId != INVALID_ID) {
+                    // Focus is moving from a virtual view within the host.
+                    getBoundsInParent(mKeyboardFocusedVirtualViewId, selectedRect);
+                } else if (previouslyFocusedRect != null) {
+                    // Focus is moving from a real view outside the host.
+                    selectedRect.set(previouslyFocusedRect);
+                } else {
+                    // Focus is moving from... somewhere? Make a guess.
+                    // Usually this happens when another view was too lazy
+                    // to pass the previously focused rect (ex. ScrollView
+                    // when moving UP or DOWN).
+                    guessPreviouslyFocusedRect(mHost, direction, selectedRect);
+                }
+                nextFocusedNode = FocusStrategy.findNextFocusInAbsoluteDirection(allNodes,
+                        SPARSE_VALUES_ADAPTER, NODE_ADAPTER, focusedNode, selectedRect, direction);
+                break;
+            default:
+                throw new IllegalArgumentException("direction must be one of "
+                        + "{FOCUS_FORWARD, FOCUS_BACKWARD, FOCUS_UP, FOCUS_DOWN, "
+                        + "FOCUS_LEFT, FOCUS_RIGHT}.");
+        }
+
+        final int nextFocusedNodeId;
+        if (nextFocusedNode == null) {
+            nextFocusedNodeId = INVALID_ID;
+        } else {
+            final int index = allNodes.indexOfValue(nextFocusedNode);
+            nextFocusedNodeId = allNodes.keyAt(index);
+        }
+
+        return requestKeyboardFocusForVirtualView(nextFocusedNodeId);
+    }
+
+    private SparseArrayCompat<AccessibilityNodeInfoCompat> getAllNodes() {
+        final List<Integer> virtualViewIds = new ArrayList<>();
+        getVisibleVirtualViews(virtualViewIds);
+
+        final SparseArrayCompat<AccessibilityNodeInfoCompat> allNodes = new SparseArrayCompat<>();
+        for (int virtualViewId = 0; virtualViewId < virtualViewIds.size(); virtualViewId++) {
+            final AccessibilityNodeInfoCompat virtualView = createNodeForChild(virtualViewId);
+            allNodes.put(virtualViewId, virtualView);
+        }
+
+        return allNodes;
+    }
+
+    /**
+     * Obtains a best guess for the previously focused rect for keyboard focus
+     * moving in the specified direction.
+     *
+     * @param host the view into which focus is moving
+     * @param direction the absolute direction in which focus is moving
+     * @param outBounds the rect to populate with the best-guess bounds for the
+     *                  previous focus rect
+     */
+    private static Rect guessPreviouslyFocusedRect(@NonNull View host,
+            @FocusRealDirection int direction, @NonNull Rect outBounds) {
+        final int w = host.getWidth();
+        final int h = host.getHeight();
+
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                outBounds.set(w, 0, w, h);
+                break;
+            case View.FOCUS_UP:
+                outBounds.set(0, h, w, h);
+                break;
+            case View.FOCUS_RIGHT:
+                outBounds.set(-1, 0, -1, h);
+                break;
+            case View.FOCUS_DOWN:
+                outBounds.set(0, -1, w, -1);
+                break;
+            default:
+                throw new IllegalArgumentException("direction must be one of "
+                        + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+        }
+
+        return outBounds;
+    }
+
+    /**
+     * Performs a click action on the keyboard focused virtual view, if any.
+     *
+     * @return {@code true} if the click action was performed successfully or
+     *         {@code false} otherwise
+     */
+    private boolean clickKeyboardFocusedVirtualView() {
+        return mKeyboardFocusedVirtualViewId != INVALID_ID && onPerformActionForVirtualView(
+                mKeyboardFocusedVirtualViewId, AccessibilityNodeInfoCompat.ACTION_CLICK, null);
+    }
+
+    /**
+     * Populates an event of the specified type with information about an item
+     * and attempts to send it up through the view hierarchy.
+     * <p>
+     * You should call this method after performing a user action that normally
+     * fires an accessibility event, such as clicking on an item.
+     * <p>
+     * <pre>public void performItemClick(T item) {
+     *   ...
+     *   sendEventForVirtualViewId(item.id, AccessibilityEvent.TYPE_VIEW_CLICKED);
+     * }
+     * </pre>
+     *
+     * @param virtualViewId the identifier of the virtual view for which to
+     *                      send an event
+     * @param eventType the type of event to send
+     * @return {@code true} if the event was sent successfully, {@code false}
+     *         otherwise
+     */
+    public final boolean sendEventForVirtualView(int virtualViewId, int eventType) {
+        if ((virtualViewId == INVALID_ID) || !mManager.isEnabled()) {
+            return false;
+        }
+
+        final ViewParent parent = mHost.getParent();
+        if (parent == null) {
+            return false;
+        }
+
+        final AccessibilityEvent event = createEvent(virtualViewId, eventType);
+        return ViewParentCompat.requestSendAccessibilityEvent(parent, mHost, event);
+    }
+
+    /**
+     * Notifies the accessibility framework that the properties of the parent
+     * view have changed.
+     * <p>
+     * You <strong>must</strong> call this method after adding or removing
+     * items from the parent view.
+     */
+    public final void invalidateRoot() {
+        invalidateVirtualView(HOST_ID, AccessibilityEventCompat.CONTENT_CHANGE_TYPE_SUBTREE);
+    }
+
+    /**
+     * Notifies the accessibility framework that the properties of a particular
+     * item have changed.
+     * <p>
+     * You <strong>must</strong> call this method after changing any of the
+     * properties set in
+     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}.
+     *
+     * @param virtualViewId the virtual view id to invalidate, or
+     *                      {@link #HOST_ID} to invalidate the root view
+     * @see #invalidateVirtualView(int, int)
+     */
+    public final void invalidateVirtualView(int virtualViewId) {
+        invalidateVirtualView(virtualViewId,
+                AccessibilityEventCompat.CONTENT_CHANGE_TYPE_UNDEFINED);
+    }
+
+    /**
+     * Notifies the accessibility framework that the properties of a particular
+     * item have changed.
+     * <p>
+     * You <strong>must</strong> call this method after changing any of the
+     * properties set in
+     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}.
+     *
+     * @param virtualViewId the virtual view id to invalidate, or
+     *                      {@link #HOST_ID} to invalidate the root view
+     * @param changeTypes the bit mask of change types. May be {@code 0} for the
+     *                    default (undefined) change type or one or more of:
+     *         <ul>
+     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
+     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_SUBTREE}
+     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_TEXT}
+     *         <li>{@link AccessibilityEventCompat#CONTENT_CHANGE_TYPE_UNDEFINED}
+     *         </ul>
+     */
+    public final void invalidateVirtualView(int virtualViewId, int changeTypes) {
+        if (virtualViewId != INVALID_ID && mManager.isEnabled()) {
+            final ViewParent parent = mHost.getParent();
+            if (parent != null) {
+                // Send events up the hierarchy so they can be coalesced.
+                final AccessibilityEvent event = createEvent(virtualViewId,
+                        AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED);
+                AccessibilityEventCompat.setContentChangeTypes(event, changeTypes);
+                ViewParentCompat.requestSendAccessibilityEvent(parent, mHost, event);
+            }
+        }
+    }
+
+    /**
+     * Returns the virtual view ID for the currently accessibility focused
+     * item.
+     *
+     * @return the identifier of the virtual view that has accessibility focus
+     *         or {@link #INVALID_ID} if no virtual view has accessibility
+     *         focus
+     * @deprecated Use {@link #getAccessibilityFocusedVirtualViewId()}.
+     */
+    @Deprecated
+    public int getFocusedVirtualView() {
+        return getAccessibilityFocusedVirtualViewId();
+    }
+
+    /**
+     * Called when the focus state of a virtual view changes.
+     *
+     * @param virtualViewId the virtual view identifier
+     * @param hasFocus      {@code true} if the view has focus, {@code false}
+     *                      otherwise
+     */
+    protected void onVirtualViewKeyboardFocusChanged(int virtualViewId, boolean hasFocus) {
+        // Stub method.
+    }
+
+    /**
+     * Sets the currently hovered item, sending hover accessibility events as
+     * necessary to maintain the correct state.
+     *
+     * @param virtualViewId the virtual view id for the item currently being
+     *                      hovered, or {@link #INVALID_ID} if no item is
+     *                      hovered within the parent view
+     */
+    private void updateHoveredVirtualView(int virtualViewId) {
+        if (mHoveredVirtualViewId == virtualViewId) {
+            return;
+        }
+
+        final int previousVirtualViewId = mHoveredVirtualViewId;
+        mHoveredVirtualViewId = virtualViewId;
+
+        // Stay consistent with framework behavior by sending ENTER/EXIT pairs
+        // in reverse order. This is accurate as of API 18.
+        sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER);
+        sendEventForVirtualView(
+                previousVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT);
+    }
+
+    /**
+     * Constructs and returns an {@link AccessibilityEvent} for the specified
+     * virtual view id, which includes the host view ({@link #HOST_ID}).
+     *
+     * @param virtualViewId the virtual view id for the item for which to
+     *                      construct an event
+     * @param eventType the type of event to construct
+     * @return an {@link AccessibilityEvent} populated with information about
+     *         the specified item
+     */
+    private AccessibilityEvent createEvent(int virtualViewId, int eventType) {
+        switch (virtualViewId) {
+            case HOST_ID:
+                return createEventForHost(eventType);
+            default:
+                return createEventForChild(virtualViewId, eventType);
+        }
+    }
+
+    /**
+     * Constructs and returns an {@link AccessibilityEvent} for the host node.
+     *
+     * @param eventType the type of event to construct
+     * @return an {@link AccessibilityEvent} populated with information about
+     *         the specified item
+     */
+    private AccessibilityEvent createEventForHost(int eventType) {
+        final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+        mHost.onInitializeAccessibilityEvent(event);
+        return event;
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(host, event);
+
+        // Allow the client to populate the event.
+        onPopulateEventForHost(event);
+    }
+
+    /**
+     * Constructs and returns an {@link AccessibilityEvent} populated with
+     * information about the specified item.
+     *
+     * @param virtualViewId the virtual view id for the item for which to
+     *                      construct an event
+     * @param eventType the type of event to construct
+     * @return an {@link AccessibilityEvent} populated with information about
+     *         the specified item
+     */
+    private AccessibilityEvent createEventForChild(int virtualViewId, int eventType) {
+        final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
+        final AccessibilityNodeInfoCompat node = obtainAccessibilityNodeInfo(virtualViewId);
+
+        // Allow the client to override these properties,
+        event.getText().add(node.getText());
+        event.setContentDescription(node.getContentDescription());
+        event.setScrollable(node.isScrollable());
+        event.setPassword(node.isPassword());
+        event.setEnabled(node.isEnabled());
+        event.setChecked(node.isChecked());
+
+        // Allow the client to populate the event.
+        onPopulateEventForVirtualView(virtualViewId, event);
+
+        // Make sure the developer is following the rules.
+        if (event.getText().isEmpty() && (event.getContentDescription() == null)) {
+            throw new RuntimeException("Callbacks must add text or a content description in "
+                    + "populateEventForVirtualViewId()");
+        }
+
+        // Don't allow the client to override these properties.
+        event.setClassName(node.getClassName());
+        AccessibilityRecordCompat.setSource(event, mHost, virtualViewId);
+        event.setPackageName(mHost.getContext().getPackageName());
+
+        return event;
+    }
+
+    /**
+     * Obtains a populated {@link AccessibilityNodeInfoCompat} for the
+     * virtual view with the specified identifier.
+     * <p>
+     * This method may be called with identifier {@link #HOST_ID} to obtain a
+     * node for the host view.
+     *
+     * @param virtualViewId the identifier of the virtual view for which to
+     *                      construct a node
+     * @return an {@link AccessibilityNodeInfoCompat} populated with information
+     *         about the specified item
+     */
+    @NonNull
+    AccessibilityNodeInfoCompat obtainAccessibilityNodeInfo(int virtualViewId) {
+        if (virtualViewId == HOST_ID) {
+            return createNodeForHost();
+        }
+
+        return createNodeForChild(virtualViewId);
+    }
+
+    /**
+     * Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
+     * host view populated with its virtual descendants.
+     *
+     * @return an {@link AccessibilityNodeInfoCompat} for the parent node
+     */
+    @NonNull
+    private AccessibilityNodeInfoCompat createNodeForHost() {
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(mHost);
+        ViewCompat.onInitializeAccessibilityNodeInfo(mHost, info);
+
+        // Add the virtual descendants.
+        final ArrayList<Integer> virtualViewIds = new ArrayList<>();
+        getVisibleVirtualViews(virtualViewIds);
+
+        final int realNodeCount = info.getChildCount();
+        if (realNodeCount > 0 && virtualViewIds.size() > 0) {
+            throw new RuntimeException("Views cannot have both real and virtual children");
+        }
+
+        for (int i = 0, count = virtualViewIds.size(); i < count; i++) {
+            info.addChild(mHost, virtualViewIds.get(i));
+        }
+
+        return info;
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+        super.onInitializeAccessibilityNodeInfo(host, info);
+
+        // Allow the client to populate the host node.
+        onPopulateNodeForHost(info);
+    }
+
+    /**
+     * Constructs and returns an {@link AccessibilityNodeInfoCompat} for the
+     * specified item. Automatically manages accessibility focus actions.
+     * <p>
+     * Allows the implementing class to specify most node properties, but
+     * overrides the following:
+     * <ul>
+     * <li>{@link AccessibilityNodeInfoCompat#setPackageName}
+     * <li>{@link AccessibilityNodeInfoCompat#setClassName}
+     * <li>{@link AccessibilityNodeInfoCompat#setParent(View)}
+     * <li>{@link AccessibilityNodeInfoCompat#setSource(View, int)}
+     * <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
+     * <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
+     * </ul>
+     * <p>
+     * Uses the bounds of the parent view and the parent-relative bounding
+     * rectangle specified by
+     * {@link AccessibilityNodeInfoCompat#getBoundsInParent} to automatically
+     * update the following properties:
+     * <ul>
+     * <li>{@link AccessibilityNodeInfoCompat#setVisibleToUser}
+     * <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent}
+     * </ul>
+     *
+     * @param virtualViewId the virtual view id for item for which to construct
+     *                      a node
+     * @return an {@link AccessibilityNodeInfoCompat} for the specified item
+     */
+    @NonNull
+    private AccessibilityNodeInfoCompat createNodeForChild(int virtualViewId) {
+        final AccessibilityNodeInfoCompat node = AccessibilityNodeInfoCompat.obtain();
+
+        // Ensure the client has good defaults.
+        node.setEnabled(true);
+        node.setFocusable(true);
+        node.setClassName(DEFAULT_CLASS_NAME);
+        node.setBoundsInParent(INVALID_PARENT_BOUNDS);
+        node.setBoundsInScreen(INVALID_PARENT_BOUNDS);
+        node.setParent(mHost);
+
+        // Allow the client to populate the node.
+        onPopulateNodeForVirtualView(virtualViewId, node);
+
+        // Make sure the developer is following the rules.
+        if ((node.getText() == null) && (node.getContentDescription() == null)) {
+            throw new RuntimeException("Callbacks must add text or a content description in "
+                    + "populateNodeForVirtualViewId()");
+        }
+
+        node.getBoundsInParent(mTempParentRect);
+        if (mTempParentRect.equals(INVALID_PARENT_BOUNDS)) {
+            throw new RuntimeException("Callbacks must set parent bounds in "
+                    + "populateNodeForVirtualViewId()");
+        }
+
+        final int actions = node.getActions();
+        if ((actions & AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS) != 0) {
+            throw new RuntimeException("Callbacks must not add ACTION_ACCESSIBILITY_FOCUS in "
+                    + "populateNodeForVirtualViewId()");
+        }
+        if ((actions & AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS) != 0) {
+            throw new RuntimeException("Callbacks must not add ACTION_CLEAR_ACCESSIBILITY_FOCUS in "
+                    + "populateNodeForVirtualViewId()");
+        }
+
+        // Don't allow the client to override these properties.
+        node.setPackageName(mHost.getContext().getPackageName());
+        node.setSource(mHost, virtualViewId);
+
+        // Manage internal accessibility focus state.
+        if (mAccessibilityFocusedVirtualViewId == virtualViewId) {
+            node.setAccessibilityFocused(true);
+            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+        } else {
+            node.setAccessibilityFocused(false);
+            node.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
+        }
+
+        // Manage internal keyboard focus state.
+        final boolean isFocused = mKeyboardFocusedVirtualViewId == virtualViewId;
+        if (isFocused) {
+            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS);
+        } else if (node.isFocusable()) {
+            node.addAction(AccessibilityNodeInfoCompat.ACTION_FOCUS);
+        }
+        node.setFocused(isFocused);
+
+        mHost.getLocationOnScreen(mTempGlobalRect);
+
+        // If not explicitly specified, calculate screen-relative bounds and
+        // offset for scroll position based on bounds in parent.
+        node.getBoundsInScreen(mTempScreenRect);
+        if (mTempScreenRect.equals(INVALID_PARENT_BOUNDS)) {
+            node.getBoundsInParent(mTempScreenRect);
+
+            // If there is a parent node, adjust bounds based on the parent node.
+            if (node.mParentVirtualDescendantId != HOST_ID) {
+                AccessibilityNodeInfoCompat parentNode = AccessibilityNodeInfoCompat.obtain();
+                // Walk up the node tree to adjust the screen rect.
+                for (int virtualDescendantId = node.mParentVirtualDescendantId;
+                        virtualDescendantId != HOST_ID;
+                        virtualDescendantId = parentNode.mParentVirtualDescendantId) {
+                    // Reset the values in the parent node we'll be using.
+                    parentNode.setParent(mHost, HOST_ID);
+                    parentNode.setBoundsInParent(INVALID_PARENT_BOUNDS);
+                    // Adjust the bounds for the parent node.
+                    onPopulateNodeForVirtualView(virtualDescendantId, parentNode);
+                    parentNode.getBoundsInParent(mTempParentRect);
+                    mTempScreenRect.offset(mTempParentRect.left, mTempParentRect.top);
+                }
+                parentNode.recycle();
+            }
+            // Adjust the rect for the host view's location.
+            mTempScreenRect.offset(mTempGlobalRect[0] - mHost.getScrollX(),
+                    mTempGlobalRect[1] - mHost.getScrollY());
+        }
+
+        if (mHost.getLocalVisibleRect(mTempVisibleRect)) {
+            mTempVisibleRect.offset(mTempGlobalRect[0] - mHost.getScrollX(),
+                    mTempGlobalRect[1] - mHost.getScrollY());
+            final boolean intersects = mTempScreenRect.intersect(mTempVisibleRect);
+            if (intersects) {
+                node.setBoundsInScreen(mTempScreenRect);
+
+                if (isVisibleToUser(mTempScreenRect)) {
+                    node.setVisibleToUser(true);
+                }
+            }
+        }
+
+        return node;
+    }
+
+    boolean performAction(int virtualViewId, int action, Bundle arguments) {
+        switch (virtualViewId) {
+            case HOST_ID:
+                return performActionForHost(action, arguments);
+            default:
+                return performActionForChild(virtualViewId, action, arguments);
+        }
+    }
+
+    private boolean performActionForHost(int action, Bundle arguments) {
+        return ViewCompat.performAccessibilityAction(mHost, action, arguments);
+    }
+
+    private boolean performActionForChild(int virtualViewId, int action, Bundle arguments) {
+        switch (action) {
+            case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
+                return requestAccessibilityFocus(virtualViewId);
+            case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
+                return clearAccessibilityFocus(virtualViewId);
+            case AccessibilityNodeInfoCompat.ACTION_FOCUS:
+                return requestKeyboardFocusForVirtualView(virtualViewId);
+            case AccessibilityNodeInfoCompat.ACTION_CLEAR_FOCUS:
+                return clearKeyboardFocusForVirtualView(virtualViewId);
+            default:
+                return onPerformActionForVirtualView(virtualViewId, action, arguments);
+        }
+    }
+
+    /**
+     * Computes whether the specified {@link Rect} intersects with the visible
+     * portion of its parent {@link View}. Modifies {@code localRect} to contain
+     * only the visible portion.
+     *
+     * @param localRect a rectangle in local (parent) coordinates
+     * @return whether the specified {@link Rect} is visible on the screen
+     */
+    private boolean isVisibleToUser(Rect localRect) {
+        // Missing or empty bounds mean this view is not visible.
+        if ((localRect == null) || localRect.isEmpty()) {
+            return false;
+        }
+
+        // Attached to invisible window means this view is not visible.
+        if (mHost.getWindowVisibility() != View.VISIBLE) {
+            return false;
+        }
+
+        // An invisible predecessor means that this view is not visible.
+        ViewParent viewParent = mHost.getParent();
+        while (viewParent instanceof View) {
+            final View view = (View) viewParent;
+            if ((view.getAlpha() <= 0) || (view.getVisibility() != View.VISIBLE)) {
+                return false;
+            }
+            viewParent = view.getParent();
+        }
+
+        // A null parent implies the view is not visible.
+        return viewParent != null;
+    }
+
+    /**
+     * Attempts to give accessibility focus to a virtual view.
+     * <p>
+     * A virtual view will not actually take focus if
+     * {@link AccessibilityManager#isEnabled()} returns false,
+     * {@link AccessibilityManager#isTouchExplorationEnabled()} returns false,
+     * or the view already has accessibility focus.
+     *
+     * @param virtualViewId the identifier of the virtual view on which to
+     *                      place accessibility focus
+     * @return whether this virtual view actually took accessibility focus
+     */
+    private boolean requestAccessibilityFocus(int virtualViewId) {
+        if (!mManager.isEnabled() || !mManager.isTouchExplorationEnabled()) {
+            return false;
+        }
+        // TODO: Check virtual view visibility.
+        if (mAccessibilityFocusedVirtualViewId != virtualViewId) {
+            // Clear focus from the previously focused view, if applicable.
+            if (mAccessibilityFocusedVirtualViewId != INVALID_ID) {
+                clearAccessibilityFocus(mAccessibilityFocusedVirtualViewId);
+            }
+
+            // Set focus on the new view.
+            mAccessibilityFocusedVirtualViewId = virtualViewId;
+
+            // TODO: Only invalidate virtual view bounds.
+            mHost.invalidate();
+            sendEventForVirtualView(virtualViewId,
+                    AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Attempts to clear accessibility focus from a virtual view.
+     *
+     * @param virtualViewId the identifier of the virtual view from which to
+     *                      clear accessibility focus
+     * @return whether this virtual view actually cleared accessibility focus
+     */
+    private boolean clearAccessibilityFocus(int virtualViewId) {
+        if (mAccessibilityFocusedVirtualViewId == virtualViewId) {
+            mAccessibilityFocusedVirtualViewId = INVALID_ID;
+            mHost.invalidate();
+            sendEventForVirtualView(virtualViewId,
+                    AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Attempts to give keyboard focus to a virtual view.
+     *
+     * @param virtualViewId the identifier of the virtual view on which to
+     *                      place keyboard focus
+     * @return whether this virtual view actually took keyboard focus
+     */
+    public final boolean requestKeyboardFocusForVirtualView(int virtualViewId) {
+        if (!mHost.isFocused() && !mHost.requestFocus()) {
+            // Host must have real keyboard focus.
+            return false;
+        }
+
+        if (mKeyboardFocusedVirtualViewId == virtualViewId) {
+            // The virtual view already has focus.
+            return false;
+        }
+
+        if (mKeyboardFocusedVirtualViewId != INVALID_ID) {
+            clearKeyboardFocusForVirtualView(mKeyboardFocusedVirtualViewId);
+        }
+
+        mKeyboardFocusedVirtualViewId = virtualViewId;
+
+        onVirtualViewKeyboardFocusChanged(virtualViewId, true);
+        sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_FOCUSED);
+
+        return true;
+    }
+
+    /**
+     * Attempts to clear keyboard focus from a virtual view.
+     *
+     * @param virtualViewId the identifier of the virtual view from which to
+     *                      clear keyboard focus
+     * @return whether this virtual view actually cleared keyboard focus
+     */
+    public final boolean clearKeyboardFocusForVirtualView(int virtualViewId) {
+        if (mKeyboardFocusedVirtualViewId != virtualViewId) {
+            // The virtual view is not focused.
+            return false;
+        }
+
+        mKeyboardFocusedVirtualViewId = INVALID_ID;
+
+        onVirtualViewKeyboardFocusChanged(virtualViewId, false);
+        sendEventForVirtualView(virtualViewId, AccessibilityEvent.TYPE_VIEW_FOCUSED);
+
+        return true;
+    }
+
+    /**
+     * Provides a mapping between view-relative coordinates and logical
+     * items.
+     *
+     * @param x The view-relative x coordinate
+     * @param y The view-relative y coordinate
+     * @return virtual view identifier for the logical item under
+     *         coordinates (x,y) or {@link #HOST_ID} if there is no item at
+     *         the given coordinates
+     */
+    protected abstract int getVirtualViewAt(float x, float y);
+
+    /**
+     * Populates a list with the view's visible items. The ordering of items
+     * within {@code virtualViewIds} specifies order of accessibility focus
+     * traversal.
+     *
+     * @param virtualViewIds The list to populate with visible items
+     */
+    protected abstract void getVisibleVirtualViews(List<Integer> virtualViewIds);
+
+    /**
+     * Populates an {@link AccessibilityEvent} with information about the
+     * specified item.
+     * <p>
+     * The helper class automatically populates the following fields based on
+     * the values set by
+     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)},
+     * but implementations may optionally override them:
+     * <ul>
+     * <li>event text, see {@link AccessibilityEvent#getText()}
+     * <li>content description, see
+     * {@link AccessibilityEvent#setContentDescription(CharSequence)}
+     * <li>scrollability, see {@link AccessibilityEvent#setScrollable(boolean)}
+     * <li>password state, see {@link AccessibilityEvent#setPassword(boolean)}
+     * <li>enabled state, see {@link AccessibilityEvent#setEnabled(boolean)}
+     * <li>checked state, see {@link AccessibilityEvent#setChecked(boolean)}
+     * </ul>
+     * <p>
+     * The following required fields are automatically populated by the
+     * helper class and may not be overridden:
+     * <ul>
+     * <li>item class name, set to the value used in
+     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}
+     * <li>package name, set to the package of the host view's
+     * {@link Context}, see {@link AccessibilityEvent#setPackageName}
+     * <li>event source, set to the host view and virtual view identifier,
+     * see {@link AccessibilityRecordCompat#setSource(AccessibilityRecord, View, int)}
+     * </ul>
+     *
+     * @param virtualViewId The virtual view id for the item for which to
+     *            populate the event
+     * @param event The event to populate
+     */
+    protected void onPopulateEventForVirtualView(int virtualViewId,
+            @NonNull AccessibilityEvent event) {
+        // Default implementation is no-op.
+    }
+
+    /**
+     * Populates an {@link AccessibilityEvent} with information about the host
+     * view.
+     * <p>
+     * The default implementation is a no-op.
+     *
+     * @param event the event to populate with information about the host view
+     */
+    protected void onPopulateEventForHost(@NonNull AccessibilityEvent event) {
+        // Default implementation is no-op.
+    }
+
+    /**
+     * Populates an {@link AccessibilityNodeInfoCompat} with information
+     * about the specified item.
+     * <p>
+     * Implementations <strong>must</strong> populate the following required
+     * fields:
+     * <ul>
+     * <li>event text, see
+     * {@link AccessibilityNodeInfoCompat#setText(CharSequence)} or
+     * {@link AccessibilityNodeInfoCompat#setContentDescription(CharSequence)}
+     * <li>bounds in parent coordinates, see
+     * {@link AccessibilityNodeInfoCompat#setBoundsInParent(Rect)}
+     * </ul>
+     * <p>
+     * The helper class automatically populates the following fields with
+     * default values, but implementations may optionally override them:
+     * <ul>
+     * <li>enabled state, set to {@code true}, see
+     * {@link AccessibilityNodeInfoCompat#setEnabled(boolean)}
+     * <li>keyboard focusability, set to {@code true}, see
+     * {@link AccessibilityNodeInfoCompat#setFocusable(boolean)}
+     * <li>item class name, set to {@code android.view.View}, see
+     * {@link AccessibilityNodeInfoCompat#setClassName(CharSequence)}
+     * </ul>
+     * <p>
+     * The following required fields are automatically populated by the
+     * helper class and may not be overridden:
+     * <ul>
+     * <li>package name, identical to the package name set by
+     * {@link #onPopulateEventForVirtualView(int, AccessibilityEvent)}, see
+     * {@link AccessibilityNodeInfoCompat#setPackageName}
+     * <li>node source, identical to the event source set in
+     * {@link #onPopulateEventForVirtualView(int, AccessibilityEvent)}, see
+     * {@link AccessibilityNodeInfoCompat#setSource(View, int)}
+     * <li>parent view, set to the host view, see
+     * {@link AccessibilityNodeInfoCompat#setParent(View)}
+     * <li>visibility, computed based on parent-relative bounds, see
+     * {@link AccessibilityNodeInfoCompat#setVisibleToUser(boolean)}
+     * <li>accessibility focus, computed based on internal helper state, see
+     * {@link AccessibilityNodeInfoCompat#setAccessibilityFocused(boolean)}
+     * <li>keyboard focus, computed based on internal helper state, see
+     * {@link AccessibilityNodeInfoCompat#setFocused(boolean)}
+     * <li>bounds in screen coordinates, computed based on host view bounds,
+     * see {@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)}
+     * </ul>
+     * <p>
+     * Additionally, the helper class automatically handles keyboard focus and
+     * accessibility focus management by adding the appropriate
+     * {@link AccessibilityNodeInfoCompat#ACTION_FOCUS},
+     * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_FOCUS},
+     * {@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS}, or
+     * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS}
+     * actions. Implementations must <strong>never</strong> manually add these
+     * actions.
+     * <p>
+     * The helper class also automatically modifies parent- and
+     * screen-relative bounds to reflect the portion of the item visible
+     * within its parent.
+     *
+     * @param virtualViewId The virtual view identifier of the item for
+     *            which to populate the node
+     * @param node The node to populate
+     */
+    protected abstract void onPopulateNodeForVirtualView(
+            int virtualViewId, @NonNull AccessibilityNodeInfoCompat node);
+
+    /**
+     * Populates an {@link AccessibilityNodeInfoCompat} with information
+     * about the host view.
+     * <p>
+     * The default implementation is a no-op.
+     *
+     * @param node the node to populate with information about the host view
+     */
+    protected void onPopulateNodeForHost(@NonNull AccessibilityNodeInfoCompat node) {
+        // Default implementation is no-op.
+    }
+
+    /**
+     * Performs the specified accessibility action on the item associated
+     * with the virtual view identifier. See
+     * {@link AccessibilityNodeInfoCompat#performAction(int, Bundle)} for
+     * more information.
+     * <p>
+     * Implementations <strong>must</strong> handle any actions added manually
+     * in
+     * {@link #onPopulateNodeForVirtualView(int, AccessibilityNodeInfoCompat)}.
+     * <p>
+     * The helper class automatically handles focus management resulting
+     * from {@link AccessibilityNodeInfoCompat#ACTION_ACCESSIBILITY_FOCUS}
+     * and
+     * {@link AccessibilityNodeInfoCompat#ACTION_CLEAR_ACCESSIBILITY_FOCUS}
+     * actions.
+     *
+     * @param virtualViewId The virtual view identifier of the item on which
+     *            to perform the action
+     * @param action The accessibility action to perform
+     * @param arguments (Optional) A bundle with additional arguments, or
+     *            null
+     * @return true if the action was performed
+     */
+    protected abstract boolean onPerformActionForVirtualView(
+            int virtualViewId, int action, @Nullable Bundle arguments);
+
+    /**
+     * Exposes a virtual view hierarchy to the accessibility framework.
+     */
+    private class MyNodeProvider extends AccessibilityNodeProviderCompat {
+        MyNodeProvider() {
+        }
+
+        @Override
+        public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) {
+            // The caller takes ownership of the node and is expected to
+            // recycle it when done, so always return a copy.
+            final AccessibilityNodeInfoCompat node =
+                    ExploreByTouchHelper.this.obtainAccessibilityNodeInfo(virtualViewId);
+            return AccessibilityNodeInfoCompat.obtain(node);
+        }
+
+        @Override
+        public boolean performAction(int virtualViewId, int action, Bundle arguments) {
+            return ExploreByTouchHelper.this.performAction(virtualViewId, action, arguments);
+        }
+
+        @Override
+        public AccessibilityNodeInfoCompat findFocus(int focusType) {
+            int focusedId = (focusType == AccessibilityNodeInfoCompat.FOCUS_ACCESSIBILITY)
+                    ? mAccessibilityFocusedVirtualViewId : mKeyboardFocusedVirtualViewId;
+            if (focusedId == INVALID_ID) {
+                return null;
+            }
+            return createAccessibilityNodeInfo(focusedId);
+        }
+    }
+}
diff --git a/customview/src/main/java/android/support/v4/widget/FocusStrategy.java b/customview/src/main/java/android/support/v4/widget/FocusStrategy.java
new file mode 100644
index 0000000..cf112bf
--- /dev/null
+++ b/customview/src/main/java/android/support/v4/widget/FocusStrategy.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.view.ViewCompat.FocusRealDirection;
+import android.support.v4.view.ViewCompat.FocusRelativeDirection;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Implements absolute and relative focus movement strategies. Adapted from
+ * android.view.FocusFinder to work with generic collections of bounded items.
+ */
+class FocusStrategy {
+    public static <L, T> T findNextFocusInRelativeDirection(@NonNull L focusables,
+            @NonNull CollectionAdapter<L, T> collectionAdapter, @NonNull BoundsAdapter<T> adapter,
+            @Nullable T focused, @FocusRelativeDirection int direction, boolean isLayoutRtl,
+            boolean wrap) {
+        final int count = collectionAdapter.size(focusables);
+        final ArrayList<T> sortedFocusables = new ArrayList<>(count);
+        for (int i = 0; i < count; i++) {
+            sortedFocusables.add(collectionAdapter.get(focusables, i));
+        }
+
+        final SequentialComparator<T> comparator = new SequentialComparator<>(isLayoutRtl, adapter);
+        Collections.sort(sortedFocusables, comparator);
+
+        switch (direction) {
+            case View.FOCUS_FORWARD:
+                return getNextFocusable(focused, sortedFocusables, wrap);
+            case View.FOCUS_BACKWARD:
+                return getPreviousFocusable(focused, sortedFocusables, wrap);
+            default:
+                throw new IllegalArgumentException("direction must be one of "
+                        + "{FOCUS_FORWARD, FOCUS_BACKWARD}.");
+        }
+    }
+
+    private static <T> T getNextFocusable(T focused, ArrayList<T> focusables, boolean wrap) {
+        final int count = focusables.size();
+
+        // The position of the next focusable item, which is the first item if
+        // no item is currently focused.
+        final int position = (focused == null ? -1 : focusables.lastIndexOf(focused)) + 1;
+        if (position < count) {
+            return focusables.get(position);
+        } else if (wrap && count > 0) {
+            return focusables.get(0);
+        } else {
+            return null;
+        }
+    }
+
+    private static <T> T getPreviousFocusable(T focused, ArrayList<T> focusables, boolean wrap) {
+        final int count = focusables.size();
+
+        // The position of the previous focusable item, which is the last item
+        // if no item is currently focused.
+        final int position = (focused == null ? count : focusables.indexOf(focused)) - 1;
+        if (position >= 0) {
+            return focusables.get(position);
+        } else if (wrap && count > 0) {
+            return focusables.get(count - 1);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Sorts views according to their visual layout and geometry for default tab order.
+     * This is used for sequential focus traversal.
+     */
+    private static class SequentialComparator<T> implements Comparator<T> {
+        private final Rect mTemp1 = new Rect();
+        private final Rect mTemp2 = new Rect();
+
+        private final boolean mIsLayoutRtl;
+        private final BoundsAdapter<T> mAdapter;
+
+        SequentialComparator(boolean isLayoutRtl, BoundsAdapter<T> adapter) {
+            mIsLayoutRtl = isLayoutRtl;
+            mAdapter = adapter;
+        }
+
+        @Override
+        public int compare(T first, T second) {
+            final Rect firstRect = mTemp1;
+            final Rect secondRect = mTemp2;
+
+            mAdapter.obtainBounds(first, firstRect);
+            mAdapter.obtainBounds(second, secondRect);
+
+            if (firstRect.top < secondRect.top) {
+                return -1;
+            } else if (firstRect.top > secondRect.top) {
+                return 1;
+            } else if (firstRect.left < secondRect.left) {
+                return mIsLayoutRtl ? 1 : -1;
+            } else if (firstRect.left > secondRect.left) {
+                return mIsLayoutRtl ? -1 : 1;
+            } else if (firstRect.bottom < secondRect.bottom) {
+                return -1;
+            } else if (firstRect.bottom > secondRect.bottom) {
+                return 1;
+            } else if (firstRect.right < secondRect.right) {
+                return mIsLayoutRtl ? 1 : -1;
+            } else if (firstRect.right > secondRect.right) {
+                return mIsLayoutRtl ? -1 : 1;
+            } else {
+                // The view are distinct but completely coincident so we
+                // consider them equal for our purposes. Since the sort is
+                // stable, this means that the views will retain their
+                // layout order relative to one another.
+                return 0;
+            }
+        }
+    }
+
+    public static <L, T> T findNextFocusInAbsoluteDirection(@NonNull L focusables,
+            @NonNull CollectionAdapter<L, T> collectionAdapter, @NonNull BoundsAdapter<T> adapter,
+            @Nullable T focused, @NonNull Rect focusedRect, int direction) {
+        // Initialize the best candidate to something impossible so that
+        // the first plausible view will become the best choice.
+        final Rect bestCandidateRect = new Rect(focusedRect);
+
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                bestCandidateRect.offset(focusedRect.width() + 1, 0);
+                break;
+            case View.FOCUS_RIGHT:
+                bestCandidateRect.offset(-(focusedRect.width() + 1), 0);
+                break;
+            case View.FOCUS_UP:
+                bestCandidateRect.offset(0, focusedRect.height() + 1);
+                break;
+            case View.FOCUS_DOWN:
+                bestCandidateRect.offset(0, -(focusedRect.height() + 1));
+                break;
+            default:
+                throw new IllegalArgumentException("direction must be one of "
+                        + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+        }
+
+        T closest = null;
+
+        final int count = collectionAdapter.size(focusables);
+        final Rect focusableRect = new Rect();
+        for (int i = 0; i < count; i++) {
+            final T focusable = collectionAdapter.get(focusables, i);
+            if (focusable == focused) {
+                continue;
+            }
+
+            // get focus bounds of other view
+            adapter.obtainBounds(focusable, focusableRect);
+            if (isBetterCandidate(direction, focusedRect, focusableRect, bestCandidateRect)) {
+                bestCandidateRect.set(focusableRect);
+                closest = focusable;
+            }
+        }
+
+        return closest;
+    }
+
+    /**
+     * Is candidate a better candidate than currentBest for a focus search
+     * in a particular direction from a source rect? This is the core
+     * routine that determines the order of focus searching.
+     *
+     * @param direction   the direction (up, down, left, right)
+     * @param source      the source from which we are searching
+     * @param candidate   the candidate rectangle
+     * @param currentBest the current best rectangle
+     * @return {@code true} if the candidate rectangle is a better than the
+     * current best rectangle, {@code false} otherwise
+     */
+    private static boolean isBetterCandidate(
+            @FocusRealDirection int direction, @NonNull Rect source,
+            @NonNull Rect candidate, @NonNull Rect currentBest) {
+        // To be a better candidate, need to at least be a candidate in the
+        // first place. :)
+        if (!isCandidate(source, candidate, direction)) {
+            return false;
+        }
+
+        // We know that candidateRect is a candidate. If currentBest is not
+        // a candidate, candidateRect is better.
+        if (!isCandidate(source, currentBest, direction)) {
+            return true;
+        }
+
+        // If candidateRect is better by beam, it wins.
+        if (beamBeats(direction, source, candidate, currentBest)) {
+            return true;
+        }
+
+        // If currentBest is better, then candidateRect cant' be. :)
+        if (beamBeats(direction, source, currentBest, candidate)) {
+            return false;
+        }
+
+        // Otherwise, do fudge-tastic comparison of the major and minor
+        // axis.
+        final int candidateDist = getWeightedDistanceFor(
+                majorAxisDistance(direction, source, candidate),
+                minorAxisDistance(direction, source, candidate));
+        final int currentBestDist = getWeightedDistanceFor(
+                majorAxisDistance(direction, source, currentBest),
+                minorAxisDistance(direction, source, currentBest));
+        return candidateDist < currentBestDist;
+    }
+
+    /**
+     * One rectangle may be another candidate than another by virtue of
+     * being exclusively in the beam of the source rect.
+     *
+     * @return whether rect1 is a better candidate than rect2 by virtue of
+     * it being in source's beam
+     */
+    private static boolean beamBeats(@FocusRealDirection int direction,
+            @NonNull Rect source, @NonNull Rect rect1, @NonNull Rect rect2) {
+        final boolean rect1InSrcBeam = beamsOverlap(direction, source, rect1);
+        final boolean rect2InSrcBeam = beamsOverlap(direction, source, rect2);
+
+        // If rect1 isn't exclusively in the src beam, it doesn't win.
+        if (rect2InSrcBeam || !rect1InSrcBeam) {
+            return false;
+        }
+
+        // We know rect1 is in the beam, and rect2 is not.
+
+        // If rect1 is to the direction of, and rect2 is not, rect1 wins.
+        // For example, for direction left, if rect1 is to the left of the
+        // source and rect2 is below, then we always prefer the in beam
+        // rect1, since rect2 could be reached by going down.
+        if (!isToDirectionOf(direction, source, rect2)) {
+            return true;
+        }
+
+        // For horizontal directions, being exclusively in beam always
+        // wins.
+        if (direction == View.FOCUS_LEFT || direction == View.FOCUS_RIGHT) {
+            return true;
+        }
+
+        // For vertical directions, beams only beat up to a point: now, as
+        // long as rect2 isn't completely closer, rect1 wins, e.g. for
+        // direction down, completely closer means for rect2's top edge to
+        // be closer to the source's top edge than rect1's bottom edge.
+        return majorAxisDistance(direction, source, rect1)
+                < majorAxisDistanceToFarEdge(direction, source, rect2);
+    }
+
+    /**
+     * Fudge-factor opportunity: how to calculate distance given major and
+     * minor axis distances.
+     * <p/>
+     * Warning: this fudge factor is finely tuned, be sure to run all focus
+     * tests if you dare tweak it.
+     */
+    private static int getWeightedDistanceFor(int majorAxisDistance, int minorAxisDistance) {
+        return 13 * majorAxisDistance * majorAxisDistance
+                + minorAxisDistance * minorAxisDistance;
+    }
+
+    /**
+     * Is destRect a candidate for the next focus given the direction? This
+     * checks whether the dest is at least partially to the direction of
+     * (e.g. left of) from source.
+     * <p/>
+     * Includes an edge case for an empty rect,which is used in some cases
+     * when searching from a point on the screen.
+     */
+    private static boolean isCandidate(@NonNull Rect srcRect, @NonNull Rect destRect,
+            @FocusRealDirection int direction) {
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                return (srcRect.right > destRect.right || srcRect.left >= destRect.right)
+                        && srcRect.left > destRect.left;
+            case View.FOCUS_RIGHT:
+                return (srcRect.left < destRect.left || srcRect.right <= destRect.left)
+                        && srcRect.right < destRect.right;
+            case View.FOCUS_UP:
+                return (srcRect.bottom > destRect.bottom || srcRect.top >= destRect.bottom)
+                        && srcRect.top > destRect.top;
+            case View.FOCUS_DOWN:
+                return (srcRect.top < destRect.top || srcRect.bottom <= destRect.top)
+                        && srcRect.bottom < destRect.bottom;
+        }
+        throw new IllegalArgumentException("direction must be one of "
+                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+    }
+
+
+    /**
+     * Do the "beams" w.r.t the given direction's axis of rect1 and rect2 overlap?
+     *
+     * @param direction the direction (up, down, left, right)
+     * @param rect1     the first rectangle
+     * @param rect2     the second rectangle
+     * @return whether the beams overlap
+     */
+    private static boolean beamsOverlap(@FocusRealDirection int direction,
+            @NonNull Rect rect1, @NonNull Rect rect2) {
+        switch (direction) {
+            case View.FOCUS_LEFT:
+            case View.FOCUS_RIGHT:
+                return (rect2.bottom >= rect1.top) && (rect2.top <= rect1.bottom);
+            case View.FOCUS_UP:
+            case View.FOCUS_DOWN:
+                return (rect2.right >= rect1.left) && (rect2.left <= rect1.right);
+        }
+        throw new IllegalArgumentException("direction must be one of "
+                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+    }
+
+    /**
+     * e.g for left, is 'to left of'
+     */
+    private static boolean isToDirectionOf(@FocusRealDirection int direction,
+            @NonNull Rect src, @NonNull Rect dest) {
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                return src.left >= dest.right;
+            case View.FOCUS_RIGHT:
+                return src.right <= dest.left;
+            case View.FOCUS_UP:
+                return src.top >= dest.bottom;
+            case View.FOCUS_DOWN:
+                return src.bottom <= dest.top;
+        }
+        throw new IllegalArgumentException("direction must be one of "
+                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+    }
+
+    /**
+     * @return the distance from the edge furthest in the given direction
+     * of source to the edge nearest in the given direction of
+     * dest. If the dest is not in the direction from source,
+     * returns 0.
+     */
+    private static int majorAxisDistance(@FocusRealDirection int direction,
+            @NonNull Rect source, @NonNull Rect dest) {
+        return Math.max(0, majorAxisDistanceRaw(direction, source, dest));
+    }
+
+    private static int majorAxisDistanceRaw(@FocusRealDirection int direction,
+            @NonNull Rect source, @NonNull Rect dest) {
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                return source.left - dest.right;
+            case View.FOCUS_RIGHT:
+                return dest.left - source.right;
+            case View.FOCUS_UP:
+                return source.top - dest.bottom;
+            case View.FOCUS_DOWN:
+                return dest.top - source.bottom;
+        }
+        throw new IllegalArgumentException("direction must be one of "
+                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+    }
+
+    /**
+     * @return the distance along the major axis w.r.t the direction from
+     * the edge of source to the far edge of dest. If the dest is
+     * not in the direction from source, returns 1 to break ties
+     * with {@link #majorAxisDistance}.
+     */
+    private static int majorAxisDistanceToFarEdge(@FocusRealDirection int direction,
+            @NonNull Rect source, @NonNull Rect dest) {
+        return Math.max(1, majorAxisDistanceToFarEdgeRaw(direction, source, dest));
+    }
+
+    private static int majorAxisDistanceToFarEdgeRaw(
+            @FocusRealDirection int direction, @NonNull Rect source,
+            @NonNull Rect dest) {
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                return source.left - dest.left;
+            case View.FOCUS_RIGHT:
+                return dest.right - source.right;
+            case View.FOCUS_UP:
+                return source.top - dest.top;
+            case View.FOCUS_DOWN:
+                return dest.bottom - source.bottom;
+        }
+        throw new IllegalArgumentException("direction must be one of "
+                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+    }
+
+    /**
+     * Finds the distance on the minor axis w.r.t the direction to the
+     * nearest edge of the destination rectangle.
+     *
+     * @param direction the direction (up, down, left, right)
+     * @param source the source rect
+     * @param dest the destination rect
+     * @return the distance
+     */
+    private static int minorAxisDistance(@FocusRealDirection int direction, @NonNull Rect source,
+            @NonNull Rect dest) {
+        switch (direction) {
+            case View.FOCUS_LEFT:
+            case View.FOCUS_RIGHT:
+                // the distance between the center verticals
+                return Math.abs(
+                        ((source.top + source.height() / 2) - ((dest.top + dest.height() / 2))));
+            case View.FOCUS_UP:
+            case View.FOCUS_DOWN:
+                // the distance between the center horizontals
+                return Math.abs(
+                        ((source.left + source.width() / 2) - ((dest.left + dest.width() / 2))));
+        }
+        throw new IllegalArgumentException("direction must be one of "
+                + "{FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT}.");
+    }
+
+    /**
+     * Adapter used to obtain bounds from a generic data type.
+     */
+    public interface BoundsAdapter<T> {
+        void obtainBounds(T data, Rect outBounds);
+    }
+
+    /**
+     * Adapter used to obtain items from a generic collection type.
+     */
+    public interface CollectionAdapter<T, V> {
+        V get(T collection, int index);
+        int size(T collection);
+    }
+}
diff --git a/core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java b/customview/src/main/java/android/support/v4/widget/ViewDragHelper.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/ViewDragHelper.java
rename to customview/src/main/java/android/support/v4/widget/ViewDragHelper.java
diff --git a/design/Android.mk b/design/Android.mk
deleted file mode 100644
index f856de6..0000000
--- a/design/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-design \
-#       android-support-transition \
-#       android-support-v7-appcompat \
-#       android-support-v7-recyclerview \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE := android-support-design
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,base) \
-    $(call all-java-files-under,lollipop) \
-    $(call all-java-files-under,src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-transition \
-    android-support-v7-appcompat \
-    android-support-v7-recyclerview \
-    android-support-compat \
-    android-support-media-compat \
-    android-support-core-utils \
-    android-support-core-ui \
-    android-support-fragment
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := \
-    --no-version-vectors \
-    --add-javadoc-annotation doconly
-LOCAL_EXPORT_PROGUARD_FLAG_FILES := proguard-rules.pro
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/design/AndroidManifest.xml b/design/AndroidManifest.xml
deleted file mode 100644
index 0eb8b85..0000000
--- a/design/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.design">
-    <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/design/api/26.0.0.txt b/design/api/26.0.0.txt
deleted file mode 100644
index 602ee48..0000000
--- a/design/api/26.0.0.txt
+++ /dev/null
@@ -1,618 +0,0 @@
-package android.support.design.widget {
-
-  public class AppBarLayout extends android.widget.LinearLayout {
-    ctor public AppBarLayout(android.content.Context);
-    ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
-    method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public deprecated float getTargetElevation();
-    method public final int getTotalScrollRange();
-    method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method public void setExpanded(boolean);
-    method public void setExpanded(boolean, boolean);
-    method public deprecated void setTargetElevation(float);
-  }
-
-  public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
-    ctor public AppBarLayout.Behavior();
-    ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int, int, int, int);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int, int);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int);
-    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
-  }
-
-  public static abstract class AppBarLayout.Behavior.DragCallback {
-    ctor public AppBarLayout.Behavior.DragCallback();
-    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
-  }
-
-  protected static class AppBarLayout.Behavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
-  }
-
-  public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
-    ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public AppBarLayout.LayoutParams(int, int);
-    ctor public AppBarLayout.LayoutParams(int, int, float);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
-    method public int getScrollFlags();
-    method public android.view.animation.Interpolator getScrollInterpolator();
-    method public void setScrollFlags(int);
-    method public void setScrollInterpolator(android.view.animation.Interpolator);
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
-    field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
-    field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
-    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
-  }
-
-  public static abstract interface AppBarLayout.OnOffsetChangedListener {
-    method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
-  }
-
-  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
-    ctor public AppBarLayout.ScrollingViewBehavior();
-    ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
-  }
-
-  public abstract class BaseTransientBottomBar<B extends android.support.design.widget.BaseTransientBottomBar<B>> {
-    ctor protected BaseTransientBottomBar(android.view.ViewGroup, android.view.View, android.support.design.widget.BaseTransientBottomBar.ContentViewCallback);
-    method public B addCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public void dismiss();
-    method public android.content.Context getContext();
-    method public int getDuration();
-    method public android.view.View getView();
-    method public boolean isShown();
-    method public boolean isShownOrQueued();
-    method public B removeCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public B setDuration(int);
-    method public void show();
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static abstract class BaseTransientBottomBar.BaseCallback<B> {
-    ctor public BaseTransientBottomBar.BaseCallback();
-    method public void onDismissed(B, int);
-    method public void onShown(B);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public static abstract interface BaseTransientBottomBar.ContentViewCallback {
-    method public abstract void animateContentIn(int, int);
-    method public abstract void animateContentOut(int, int);
-  }
-
-  public class BottomNavigationView extends android.widget.FrameLayout {
-    ctor public BottomNavigationView(android.content.Context);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public int getItemBackgroundResource();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public int getMaxItemCount();
-    method public android.view.Menu getMenu();
-    method public int getSelectedItemId();
-    method public void inflateMenu(int);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setOnNavigationItemReselectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemReselectedListener);
-    method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
-    method public void setSelectedItemId(int);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemReselectedListener {
-    method public abstract void onNavigationItemReselected(android.view.MenuItem);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public class BottomSheetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public BottomSheetBehavior();
-    ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
-    method public static <V extends android.view.View> android.support.design.widget.BottomSheetBehavior<V> from(V);
-    method public final int getPeekHeight();
-    method public boolean getSkipCollapsed();
-    method public final int getState();
-    method public boolean isHideable();
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void setBottomSheetCallback(android.support.design.widget.BottomSheetBehavior.BottomSheetCallback);
-    method public void setHideable(boolean);
-    method public final void setPeekHeight(int);
-    method public void setSkipCollapsed(boolean);
-    method public final void setState(int);
-    field public static final int PEEK_HEIGHT_AUTO = -1; // 0xffffffff
-    field public static final int STATE_COLLAPSED = 4; // 0x4
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_EXPANDED = 3; // 0x3
-    field public static final int STATE_HIDDEN = 5; // 0x5
-    field public static final int STATE_SETTLING = 2; // 0x2
-  }
-
-  public static abstract class BottomSheetBehavior.BottomSheetCallback {
-    ctor public BottomSheetBehavior.BottomSheetCallback();
-    method public abstract void onSlide(android.view.View, float);
-    method public abstract void onStateChanged(android.view.View, int);
-  }
-
-  protected static class BottomSheetBehavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
-  }
-
-  public class BottomSheetDialog extends android.support.v7.app.AppCompatDialog {
-    ctor public BottomSheetDialog(android.content.Context);
-    ctor public BottomSheetDialog(android.content.Context, int);
-    ctor protected BottomSheetDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-  }
-
-  public class BottomSheetDialogFragment extends android.support.v7.app.AppCompatDialogFragment {
-    ctor public BottomSheetDialogFragment();
-  }
-
-  public class CollapsingToolbarLayout extends android.widget.FrameLayout {
-    ctor public CollapsingToolbarLayout(android.content.Context);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
-    method protected android.support.design.widget.CollapsingToolbarLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.widget.FrameLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getCollapsedTitleGravity();
-    method public android.graphics.Typeface getCollapsedTitleTypeface();
-    method public android.graphics.drawable.Drawable getContentScrim();
-    method public int getExpandedTitleGravity();
-    method public int getExpandedTitleMarginBottom();
-    method public int getExpandedTitleMarginEnd();
-    method public int getExpandedTitleMarginStart();
-    method public int getExpandedTitleMarginTop();
-    method public android.graphics.Typeface getExpandedTitleTypeface();
-    method public long getScrimAnimationDuration();
-    method public int getScrimVisibleHeightTrigger();
-    method public android.graphics.drawable.Drawable getStatusBarScrim();
-    method public java.lang.CharSequence getTitle();
-    method public boolean isTitleEnabled();
-    method public void setCollapsedTitleGravity(int);
-    method public void setCollapsedTitleTextAppearance(int);
-    method public void setCollapsedTitleTextColor(int);
-    method public void setCollapsedTitleTextColor(android.content.res.ColorStateList);
-    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
-    method public void setContentScrim(android.graphics.drawable.Drawable);
-    method public void setContentScrimColor(int);
-    method public void setContentScrimResource(int);
-    method public void setExpandedTitleColor(int);
-    method public void setExpandedTitleGravity(int);
-    method public void setExpandedTitleMargin(int, int, int, int);
-    method public void setExpandedTitleMarginBottom(int);
-    method public void setExpandedTitleMarginEnd(int);
-    method public void setExpandedTitleMarginStart(int);
-    method public void setExpandedTitleMarginTop(int);
-    method public void setExpandedTitleTextAppearance(int);
-    method public void setExpandedTitleTextColor(android.content.res.ColorStateList);
-    method public void setExpandedTitleTypeface(android.graphics.Typeface);
-    method public void setScrimAnimationDuration(long);
-    method public void setScrimVisibleHeightTrigger(int);
-    method public void setScrimsShown(boolean);
-    method public void setScrimsShown(boolean, boolean);
-    method public void setStatusBarScrim(android.graphics.drawable.Drawable);
-    method public void setStatusBarScrimColor(int);
-    method public void setStatusBarScrimResource(int);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitleEnabled(boolean);
-  }
-
-  public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
-    ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
-    method public int getCollapseMode();
-    method public float getParallaxMultiplier();
-    method public void setCollapseMode(int);
-    method public void setParallaxMultiplier(float);
-    field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
-    field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
-    field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
-  }
-
-  public class CoordinatorLayout extends android.view.ViewGroup {
-    ctor public CoordinatorLayout(android.content.Context);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void dispatchDependentViewsChanged(android.view.View);
-    method public boolean doViewsOverlap(android.view.View, android.view.View);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public java.util.List<android.view.View> getDependencies(android.view.View);
-    method public java.util.List<android.view.View> getDependents(android.view.View);
-    method public android.graphics.drawable.Drawable getStatusBarBackground();
-    method public boolean isPointInChildBounds(android.view.View, int, int);
-    method public void onAttachedToWindow();
-    method public void onDetachedFromWindow();
-    method public void onDraw(android.graphics.Canvas);
-    method protected void onLayout(boolean, int, int, int, int);
-    method public void onLayoutChild(android.view.View, int);
-    method public void onMeasureChild(android.view.View, int, int, int, int);
-    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.view.View, int, int, int, int, int);
-    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
-    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.view.View, int);
-    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
-    method public void setStatusBarBackgroundColor(int);
-    method public void setStatusBarBackgroundResource(int);
-  }
-
-  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
-    ctor public CoordinatorLayout.Behavior();
-    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
-    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
-    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
-    method public static java.lang.Object getTag(android.view.View);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
-    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDetachedFromLayoutParams();
-    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
-    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
-    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
-    method public deprecated void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[], int);
-    method public deprecated void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int, int);
-    method public deprecated void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
-    method public deprecated boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public deprecated void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int);
-    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public static void setTag(android.view.View, java.lang.Object);
-  }
-
-  public static abstract class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
-  }
-
-  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public CoordinatorLayout.LayoutParams(int, int);
-    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getAnchorId();
-    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
-    method public void setAnchorId(int);
-    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
-    field public int anchorGravity;
-    field public int dodgeInsetEdges;
-    field public int gravity;
-    field public int insetEdge;
-    field public int keyline;
-  }
-
-  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
-  }
-
-  public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
-    ctor public FloatingActionButton(android.content.Context);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
-    method public float getCompatElevation();
-    method public android.graphics.drawable.Drawable getContentBackground();
-    method public boolean getContentRect(android.graphics.Rect);
-    method public int getRippleColor();
-    method public int getSize();
-    method public boolean getUseCompatPadding();
-    method public void hide();
-    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setCompatElevation(float);
-    method public void setRippleColor(int);
-    method public void setSize(int);
-    method public void setUseCompatPadding(boolean);
-    method public void show();
-    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    field public static final int SIZE_AUTO = -1; // 0xffffffff
-    field public static final int SIZE_MINI = 1; // 0x1
-    field public static final int SIZE_NORMAL = 0; // 0x0
-  }
-
-  public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public FloatingActionButton.Behavior();
-    ctor public FloatingActionButton.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect);
-    method public boolean isAutoHideEnabled();
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
-    method public void setAutoHideEnabled(boolean);
-  }
-
-  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
-    ctor public FloatingActionButton.OnVisibilityChangedListener();
-    method public void onHidden(android.support.design.widget.FloatingActionButton);
-    method public void onShown(android.support.design.widget.FloatingActionButton);
-  }
-
-   abstract class HeaderBehavior<V extends android.view.View> extends android.support.design.widget.ViewOffsetBehavior {
-    ctor public HeaderBehavior();
-    ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
-  }
-
-   abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
-    ctor public HeaderScrollingViewBehavior();
-    ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
-    method public final int getOverlayTop();
-    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
-    method public final void setOverlayTop(int);
-  }
-
-  public class NavigationView extends android.widget.FrameLayout {
-    ctor public NavigationView(android.content.Context);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public void addHeaderView(android.view.View);
-    method public int getHeaderCount();
-    method public android.view.View getHeaderView(int);
-    method public android.graphics.drawable.Drawable getItemBackground();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public android.view.Menu getMenu();
-    method public android.view.View inflateHeaderView(int);
-    method public void inflateMenu(int);
-    method public void removeHeaderView(android.view.View);
-    method public void setCheckedItem(int);
-    method public void setItemBackground(android.graphics.drawable.Drawable);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextAppearance(int);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
-  }
-
-  public static abstract interface NavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public static class NavigationView.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public NavigationView.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
-    field public android.os.Bundle menuState;
-  }
-
-  public final class Snackbar extends android.support.design.widget.BaseTransientBottomBar {
-    method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
-    method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
-    method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
-    method public android.support.design.widget.Snackbar setActionTextColor(int);
-    method public deprecated android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
-    method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
-    method public android.support.design.widget.Snackbar setText(int);
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static class Snackbar.Callback extends android.support.design.widget.BaseTransientBottomBar.BaseCallback {
-    ctor public Snackbar.Callback();
-    method public void onDismissed(android.support.design.widget.Snackbar, int);
-    method public void onShown(android.support.design.widget.Snackbar);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public class SwipeDismissBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public SwipeDismissBehavior();
-    method public boolean canSwipeDismissView(android.view.View);
-    method public int getDragState();
-    method public void setDragDismissDistance(float);
-    method public void setEndAlphaSwipeDistance(float);
-    method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
-    method public void setSensitivity(float);
-    method public void setStartAlphaSwipeDistance(float);
-    method public void setSwipeDirection(int);
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_IDLE = 0; // 0x0
-    field public static final int STATE_SETTLING = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
-    field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
-  }
-
-  public static abstract interface SwipeDismissBehavior.OnDismissListener {
-    method public abstract void onDismiss(android.view.View);
-    method public abstract void onDragStateChanged(int);
-  }
-
-  public final class TabItem extends android.view.View {
-    ctor public TabItem(android.content.Context);
-    ctor public TabItem(android.content.Context, android.util.AttributeSet);
-  }
-
-  public class TabLayout extends android.widget.HorizontalScrollView {
-    ctor public TabLayout(android.content.Context);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void addOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void addTab(android.support.design.widget.TabLayout.Tab);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
-    method public void clearOnTabSelectedListeners();
-    method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method public int getSelectedTabPosition();
-    method public android.support.design.widget.TabLayout.Tab getTabAt(int);
-    method public int getTabCount();
-    method public int getTabGravity();
-    method public int getTabMode();
-    method public android.content.res.ColorStateList getTabTextColors();
-    method public android.support.design.widget.TabLayout.Tab newTab();
-    method public void removeAllTabs();
-    method public void removeOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void removeTab(android.support.design.widget.TabLayout.Tab);
-    method public void removeTabAt(int);
-    method public deprecated void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void setScrollPosition(int, float, boolean);
-    method public void setSelectedTabIndicatorColor(int);
-    method public void setSelectedTabIndicatorHeight(int);
-    method public void setTabGravity(int);
-    method public void setTabMode(int);
-    method public void setTabTextColors(android.content.res.ColorStateList);
-    method public void setTabTextColors(int, int);
-    method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager, boolean);
-    field public static final int GRAVITY_CENTER = 1; // 0x1
-    field public static final int GRAVITY_FILL = 0; // 0x0
-    field public static final int MODE_FIXED = 1; // 0x1
-    field public static final int MODE_SCROLLABLE = 0; // 0x0
-  }
-
-  public static abstract interface TabLayout.OnTabSelectedListener {
-    method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public static final class TabLayout.Tab {
-    method public java.lang.CharSequence getContentDescription();
-    method public android.view.View getCustomView();
-    method public android.graphics.drawable.Drawable getIcon();
-    method public int getPosition();
-    method public java.lang.Object getTag();
-    method public java.lang.CharSequence getText();
-    method public boolean isSelected();
-    method public void select();
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(int);
-    method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
-    method public android.support.design.widget.TabLayout.Tab setIcon(int);
-    method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
-    method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setText(int);
-    field public static final int INVALID_POSITION = -1; // 0xffffffff
-  }
-
-  public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
-    ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
-    method public void onPageScrollStateChanged(int);
-    method public void onPageScrolled(int, float, int);
-    method public void onPageSelected(int);
-  }
-
-  public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
-    ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
-    method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public class TextInputEditText extends android.support.v7.widget.AppCompatEditText {
-    ctor public TextInputEditText(android.content.Context);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public class TextInputLayout extends android.widget.LinearLayout {
-    ctor public TextInputLayout(android.content.Context);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
-    method public int getCounterMaxLength();
-    method public android.widget.EditText getEditText();
-    method public java.lang.CharSequence getError();
-    method public java.lang.CharSequence getHint();
-    method public java.lang.CharSequence getPasswordVisibilityToggleContentDescription();
-    method public android.graphics.drawable.Drawable getPasswordVisibilityToggleDrawable();
-    method public android.graphics.Typeface getTypeface();
-    method public boolean isCounterEnabled();
-    method public boolean isErrorEnabled();
-    method public boolean isHintAnimationEnabled();
-    method public boolean isHintEnabled();
-    method public boolean isPasswordVisibilityToggleEnabled();
-    method public android.os.Parcelable onSaveInstanceState();
-    method public void setCounterEnabled(boolean);
-    method public void setCounterMaxLength(int);
-    method public void setError(java.lang.CharSequence);
-    method public void setErrorEnabled(boolean);
-    method public void setErrorTextAppearance(int);
-    method public void setHint(java.lang.CharSequence);
-    method public void setHintAnimationEnabled(boolean);
-    method public void setHintEnabled(boolean);
-    method public void setHintTextAppearance(int);
-    method public void setPasswordVisibilityToggleContentDescription(int);
-    method public void setPasswordVisibilityToggleContentDescription(java.lang.CharSequence);
-    method public void setPasswordVisibilityToggleDrawable(int);
-    method public void setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable);
-    method public void setPasswordVisibilityToggleEnabled(boolean);
-    method public void setPasswordVisibilityToggleTintList(android.content.res.ColorStateList);
-    method public void setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTypeface(android.graphics.Typeface);
-  }
-
-   class ViewOffsetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public ViewOffsetBehavior();
-    ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
-    method public int getLeftAndRightOffset();
-    method public int getTopAndBottomOffset();
-    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, V, int);
-    method public boolean setLeftAndRightOffset(int);
-    method public boolean setTopAndBottomOffset(int);
-  }
-
-   class VisibilityAwareImageButton extends android.widget.ImageButton {
-    ctor public VisibilityAwareImageButton(android.content.Context);
-    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
-    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
-  }
-
-}
-
diff --git a/design/api/26.1.0.txt b/design/api/26.1.0.txt
deleted file mode 100644
index 602ee48..0000000
--- a/design/api/26.1.0.txt
+++ /dev/null
@@ -1,618 +0,0 @@
-package android.support.design.widget {
-
-  public class AppBarLayout extends android.widget.LinearLayout {
-    ctor public AppBarLayout(android.content.Context);
-    ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
-    method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public deprecated float getTargetElevation();
-    method public final int getTotalScrollRange();
-    method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method public void setExpanded(boolean);
-    method public void setExpanded(boolean, boolean);
-    method public deprecated void setTargetElevation(float);
-  }
-
-  public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
-    ctor public AppBarLayout.Behavior();
-    ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int, int, int, int);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int, int);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int);
-    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
-  }
-
-  public static abstract class AppBarLayout.Behavior.DragCallback {
-    ctor public AppBarLayout.Behavior.DragCallback();
-    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
-  }
-
-  protected static class AppBarLayout.Behavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
-  }
-
-  public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
-    ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public AppBarLayout.LayoutParams(int, int);
-    ctor public AppBarLayout.LayoutParams(int, int, float);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
-    method public int getScrollFlags();
-    method public android.view.animation.Interpolator getScrollInterpolator();
-    method public void setScrollFlags(int);
-    method public void setScrollInterpolator(android.view.animation.Interpolator);
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
-    field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
-    field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
-    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
-  }
-
-  public static abstract interface AppBarLayout.OnOffsetChangedListener {
-    method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
-  }
-
-  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
-    ctor public AppBarLayout.ScrollingViewBehavior();
-    ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
-  }
-
-  public abstract class BaseTransientBottomBar<B extends android.support.design.widget.BaseTransientBottomBar<B>> {
-    ctor protected BaseTransientBottomBar(android.view.ViewGroup, android.view.View, android.support.design.widget.BaseTransientBottomBar.ContentViewCallback);
-    method public B addCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public void dismiss();
-    method public android.content.Context getContext();
-    method public int getDuration();
-    method public android.view.View getView();
-    method public boolean isShown();
-    method public boolean isShownOrQueued();
-    method public B removeCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public B setDuration(int);
-    method public void show();
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static abstract class BaseTransientBottomBar.BaseCallback<B> {
-    ctor public BaseTransientBottomBar.BaseCallback();
-    method public void onDismissed(B, int);
-    method public void onShown(B);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public static abstract interface BaseTransientBottomBar.ContentViewCallback {
-    method public abstract void animateContentIn(int, int);
-    method public abstract void animateContentOut(int, int);
-  }
-
-  public class BottomNavigationView extends android.widget.FrameLayout {
-    ctor public BottomNavigationView(android.content.Context);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public int getItemBackgroundResource();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public int getMaxItemCount();
-    method public android.view.Menu getMenu();
-    method public int getSelectedItemId();
-    method public void inflateMenu(int);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setOnNavigationItemReselectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemReselectedListener);
-    method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
-    method public void setSelectedItemId(int);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemReselectedListener {
-    method public abstract void onNavigationItemReselected(android.view.MenuItem);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public class BottomSheetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public BottomSheetBehavior();
-    ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
-    method public static <V extends android.view.View> android.support.design.widget.BottomSheetBehavior<V> from(V);
-    method public final int getPeekHeight();
-    method public boolean getSkipCollapsed();
-    method public final int getState();
-    method public boolean isHideable();
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void setBottomSheetCallback(android.support.design.widget.BottomSheetBehavior.BottomSheetCallback);
-    method public void setHideable(boolean);
-    method public final void setPeekHeight(int);
-    method public void setSkipCollapsed(boolean);
-    method public final void setState(int);
-    field public static final int PEEK_HEIGHT_AUTO = -1; // 0xffffffff
-    field public static final int STATE_COLLAPSED = 4; // 0x4
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_EXPANDED = 3; // 0x3
-    field public static final int STATE_HIDDEN = 5; // 0x5
-    field public static final int STATE_SETTLING = 2; // 0x2
-  }
-
-  public static abstract class BottomSheetBehavior.BottomSheetCallback {
-    ctor public BottomSheetBehavior.BottomSheetCallback();
-    method public abstract void onSlide(android.view.View, float);
-    method public abstract void onStateChanged(android.view.View, int);
-  }
-
-  protected static class BottomSheetBehavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
-  }
-
-  public class BottomSheetDialog extends android.support.v7.app.AppCompatDialog {
-    ctor public BottomSheetDialog(android.content.Context);
-    ctor public BottomSheetDialog(android.content.Context, int);
-    ctor protected BottomSheetDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-  }
-
-  public class BottomSheetDialogFragment extends android.support.v7.app.AppCompatDialogFragment {
-    ctor public BottomSheetDialogFragment();
-  }
-
-  public class CollapsingToolbarLayout extends android.widget.FrameLayout {
-    ctor public CollapsingToolbarLayout(android.content.Context);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
-    method protected android.support.design.widget.CollapsingToolbarLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.widget.FrameLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getCollapsedTitleGravity();
-    method public android.graphics.Typeface getCollapsedTitleTypeface();
-    method public android.graphics.drawable.Drawable getContentScrim();
-    method public int getExpandedTitleGravity();
-    method public int getExpandedTitleMarginBottom();
-    method public int getExpandedTitleMarginEnd();
-    method public int getExpandedTitleMarginStart();
-    method public int getExpandedTitleMarginTop();
-    method public android.graphics.Typeface getExpandedTitleTypeface();
-    method public long getScrimAnimationDuration();
-    method public int getScrimVisibleHeightTrigger();
-    method public android.graphics.drawable.Drawable getStatusBarScrim();
-    method public java.lang.CharSequence getTitle();
-    method public boolean isTitleEnabled();
-    method public void setCollapsedTitleGravity(int);
-    method public void setCollapsedTitleTextAppearance(int);
-    method public void setCollapsedTitleTextColor(int);
-    method public void setCollapsedTitleTextColor(android.content.res.ColorStateList);
-    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
-    method public void setContentScrim(android.graphics.drawable.Drawable);
-    method public void setContentScrimColor(int);
-    method public void setContentScrimResource(int);
-    method public void setExpandedTitleColor(int);
-    method public void setExpandedTitleGravity(int);
-    method public void setExpandedTitleMargin(int, int, int, int);
-    method public void setExpandedTitleMarginBottom(int);
-    method public void setExpandedTitleMarginEnd(int);
-    method public void setExpandedTitleMarginStart(int);
-    method public void setExpandedTitleMarginTop(int);
-    method public void setExpandedTitleTextAppearance(int);
-    method public void setExpandedTitleTextColor(android.content.res.ColorStateList);
-    method public void setExpandedTitleTypeface(android.graphics.Typeface);
-    method public void setScrimAnimationDuration(long);
-    method public void setScrimVisibleHeightTrigger(int);
-    method public void setScrimsShown(boolean);
-    method public void setScrimsShown(boolean, boolean);
-    method public void setStatusBarScrim(android.graphics.drawable.Drawable);
-    method public void setStatusBarScrimColor(int);
-    method public void setStatusBarScrimResource(int);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitleEnabled(boolean);
-  }
-
-  public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
-    ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
-    method public int getCollapseMode();
-    method public float getParallaxMultiplier();
-    method public void setCollapseMode(int);
-    method public void setParallaxMultiplier(float);
-    field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
-    field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
-    field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
-  }
-
-  public class CoordinatorLayout extends android.view.ViewGroup {
-    ctor public CoordinatorLayout(android.content.Context);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void dispatchDependentViewsChanged(android.view.View);
-    method public boolean doViewsOverlap(android.view.View, android.view.View);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public java.util.List<android.view.View> getDependencies(android.view.View);
-    method public java.util.List<android.view.View> getDependents(android.view.View);
-    method public android.graphics.drawable.Drawable getStatusBarBackground();
-    method public boolean isPointInChildBounds(android.view.View, int, int);
-    method public void onAttachedToWindow();
-    method public void onDetachedFromWindow();
-    method public void onDraw(android.graphics.Canvas);
-    method protected void onLayout(boolean, int, int, int, int);
-    method public void onLayoutChild(android.view.View, int);
-    method public void onMeasureChild(android.view.View, int, int, int, int);
-    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.view.View, int, int, int, int, int);
-    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
-    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.view.View, int);
-    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
-    method public void setStatusBarBackgroundColor(int);
-    method public void setStatusBarBackgroundResource(int);
-  }
-
-  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
-    ctor public CoordinatorLayout.Behavior();
-    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
-    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
-    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
-    method public static java.lang.Object getTag(android.view.View);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
-    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDetachedFromLayoutParams();
-    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
-    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
-    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
-    method public deprecated void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[], int);
-    method public deprecated void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int, int);
-    method public deprecated void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
-    method public deprecated boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public deprecated void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int);
-    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public static void setTag(android.view.View, java.lang.Object);
-  }
-
-  public static abstract class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
-  }
-
-  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public CoordinatorLayout.LayoutParams(int, int);
-    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getAnchorId();
-    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
-    method public void setAnchorId(int);
-    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
-    field public int anchorGravity;
-    field public int dodgeInsetEdges;
-    field public int gravity;
-    field public int insetEdge;
-    field public int keyline;
-  }
-
-  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
-  }
-
-  public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
-    ctor public FloatingActionButton(android.content.Context);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
-    method public float getCompatElevation();
-    method public android.graphics.drawable.Drawable getContentBackground();
-    method public boolean getContentRect(android.graphics.Rect);
-    method public int getRippleColor();
-    method public int getSize();
-    method public boolean getUseCompatPadding();
-    method public void hide();
-    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setCompatElevation(float);
-    method public void setRippleColor(int);
-    method public void setSize(int);
-    method public void setUseCompatPadding(boolean);
-    method public void show();
-    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    field public static final int SIZE_AUTO = -1; // 0xffffffff
-    field public static final int SIZE_MINI = 1; // 0x1
-    field public static final int SIZE_NORMAL = 0; // 0x0
-  }
-
-  public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public FloatingActionButton.Behavior();
-    ctor public FloatingActionButton.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect);
-    method public boolean isAutoHideEnabled();
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
-    method public void setAutoHideEnabled(boolean);
-  }
-
-  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
-    ctor public FloatingActionButton.OnVisibilityChangedListener();
-    method public void onHidden(android.support.design.widget.FloatingActionButton);
-    method public void onShown(android.support.design.widget.FloatingActionButton);
-  }
-
-   abstract class HeaderBehavior<V extends android.view.View> extends android.support.design.widget.ViewOffsetBehavior {
-    ctor public HeaderBehavior();
-    ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
-  }
-
-   abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
-    ctor public HeaderScrollingViewBehavior();
-    ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
-    method public final int getOverlayTop();
-    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
-    method public final void setOverlayTop(int);
-  }
-
-  public class NavigationView extends android.widget.FrameLayout {
-    ctor public NavigationView(android.content.Context);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public void addHeaderView(android.view.View);
-    method public int getHeaderCount();
-    method public android.view.View getHeaderView(int);
-    method public android.graphics.drawable.Drawable getItemBackground();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public android.view.Menu getMenu();
-    method public android.view.View inflateHeaderView(int);
-    method public void inflateMenu(int);
-    method public void removeHeaderView(android.view.View);
-    method public void setCheckedItem(int);
-    method public void setItemBackground(android.graphics.drawable.Drawable);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextAppearance(int);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
-  }
-
-  public static abstract interface NavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public static class NavigationView.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public NavigationView.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
-    field public android.os.Bundle menuState;
-  }
-
-  public final class Snackbar extends android.support.design.widget.BaseTransientBottomBar {
-    method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
-    method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
-    method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
-    method public android.support.design.widget.Snackbar setActionTextColor(int);
-    method public deprecated android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
-    method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
-    method public android.support.design.widget.Snackbar setText(int);
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static class Snackbar.Callback extends android.support.design.widget.BaseTransientBottomBar.BaseCallback {
-    ctor public Snackbar.Callback();
-    method public void onDismissed(android.support.design.widget.Snackbar, int);
-    method public void onShown(android.support.design.widget.Snackbar);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public class SwipeDismissBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public SwipeDismissBehavior();
-    method public boolean canSwipeDismissView(android.view.View);
-    method public int getDragState();
-    method public void setDragDismissDistance(float);
-    method public void setEndAlphaSwipeDistance(float);
-    method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
-    method public void setSensitivity(float);
-    method public void setStartAlphaSwipeDistance(float);
-    method public void setSwipeDirection(int);
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_IDLE = 0; // 0x0
-    field public static final int STATE_SETTLING = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
-    field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
-  }
-
-  public static abstract interface SwipeDismissBehavior.OnDismissListener {
-    method public abstract void onDismiss(android.view.View);
-    method public abstract void onDragStateChanged(int);
-  }
-
-  public final class TabItem extends android.view.View {
-    ctor public TabItem(android.content.Context);
-    ctor public TabItem(android.content.Context, android.util.AttributeSet);
-  }
-
-  public class TabLayout extends android.widget.HorizontalScrollView {
-    ctor public TabLayout(android.content.Context);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void addOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void addTab(android.support.design.widget.TabLayout.Tab);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
-    method public void clearOnTabSelectedListeners();
-    method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method public int getSelectedTabPosition();
-    method public android.support.design.widget.TabLayout.Tab getTabAt(int);
-    method public int getTabCount();
-    method public int getTabGravity();
-    method public int getTabMode();
-    method public android.content.res.ColorStateList getTabTextColors();
-    method public android.support.design.widget.TabLayout.Tab newTab();
-    method public void removeAllTabs();
-    method public void removeOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void removeTab(android.support.design.widget.TabLayout.Tab);
-    method public void removeTabAt(int);
-    method public deprecated void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void setScrollPosition(int, float, boolean);
-    method public void setSelectedTabIndicatorColor(int);
-    method public void setSelectedTabIndicatorHeight(int);
-    method public void setTabGravity(int);
-    method public void setTabMode(int);
-    method public void setTabTextColors(android.content.res.ColorStateList);
-    method public void setTabTextColors(int, int);
-    method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager, boolean);
-    field public static final int GRAVITY_CENTER = 1; // 0x1
-    field public static final int GRAVITY_FILL = 0; // 0x0
-    field public static final int MODE_FIXED = 1; // 0x1
-    field public static final int MODE_SCROLLABLE = 0; // 0x0
-  }
-
-  public static abstract interface TabLayout.OnTabSelectedListener {
-    method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public static final class TabLayout.Tab {
-    method public java.lang.CharSequence getContentDescription();
-    method public android.view.View getCustomView();
-    method public android.graphics.drawable.Drawable getIcon();
-    method public int getPosition();
-    method public java.lang.Object getTag();
-    method public java.lang.CharSequence getText();
-    method public boolean isSelected();
-    method public void select();
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(int);
-    method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
-    method public android.support.design.widget.TabLayout.Tab setIcon(int);
-    method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
-    method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setText(int);
-    field public static final int INVALID_POSITION = -1; // 0xffffffff
-  }
-
-  public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
-    ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
-    method public void onPageScrollStateChanged(int);
-    method public void onPageScrolled(int, float, int);
-    method public void onPageSelected(int);
-  }
-
-  public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
-    ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
-    method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public class TextInputEditText extends android.support.v7.widget.AppCompatEditText {
-    ctor public TextInputEditText(android.content.Context);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public class TextInputLayout extends android.widget.LinearLayout {
-    ctor public TextInputLayout(android.content.Context);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
-    method public int getCounterMaxLength();
-    method public android.widget.EditText getEditText();
-    method public java.lang.CharSequence getError();
-    method public java.lang.CharSequence getHint();
-    method public java.lang.CharSequence getPasswordVisibilityToggleContentDescription();
-    method public android.graphics.drawable.Drawable getPasswordVisibilityToggleDrawable();
-    method public android.graphics.Typeface getTypeface();
-    method public boolean isCounterEnabled();
-    method public boolean isErrorEnabled();
-    method public boolean isHintAnimationEnabled();
-    method public boolean isHintEnabled();
-    method public boolean isPasswordVisibilityToggleEnabled();
-    method public android.os.Parcelable onSaveInstanceState();
-    method public void setCounterEnabled(boolean);
-    method public void setCounterMaxLength(int);
-    method public void setError(java.lang.CharSequence);
-    method public void setErrorEnabled(boolean);
-    method public void setErrorTextAppearance(int);
-    method public void setHint(java.lang.CharSequence);
-    method public void setHintAnimationEnabled(boolean);
-    method public void setHintEnabled(boolean);
-    method public void setHintTextAppearance(int);
-    method public void setPasswordVisibilityToggleContentDescription(int);
-    method public void setPasswordVisibilityToggleContentDescription(java.lang.CharSequence);
-    method public void setPasswordVisibilityToggleDrawable(int);
-    method public void setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable);
-    method public void setPasswordVisibilityToggleEnabled(boolean);
-    method public void setPasswordVisibilityToggleTintList(android.content.res.ColorStateList);
-    method public void setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTypeface(android.graphics.Typeface);
-  }
-
-   class ViewOffsetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public ViewOffsetBehavior();
-    ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
-    method public int getLeftAndRightOffset();
-    method public int getTopAndBottomOffset();
-    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, V, int);
-    method public boolean setLeftAndRightOffset(int);
-    method public boolean setTopAndBottomOffset(int);
-  }
-
-   class VisibilityAwareImageButton extends android.widget.ImageButton {
-    ctor public VisibilityAwareImageButton(android.content.Context);
-    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
-    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
-  }
-
-}
-
diff --git a/design/api/27.0.0.ignore b/design/api/27.0.0.ignore
deleted file mode 100644
index d982dc1..0000000
--- a/design/api/27.0.0.ignore
+++ /dev/null
@@ -1,14 +0,0 @@
-a1fc27e
-197ce1d
-88bc57e
-9761c3e
-86b38bf
-c6abd5e
-cea5c29
-8bac7c2
-f02de9f
-1d50e39
-fb2d5b2
-4c9b1f0
-7da565d
-33c90df
diff --git a/design/api/27.0.0.txt b/design/api/27.0.0.txt
deleted file mode 100644
index 602ee48..0000000
--- a/design/api/27.0.0.txt
+++ /dev/null
@@ -1,618 +0,0 @@
-package android.support.design.widget {
-
-  public class AppBarLayout extends android.widget.LinearLayout {
-    ctor public AppBarLayout(android.content.Context);
-    ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
-    method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public deprecated float getTargetElevation();
-    method public final int getTotalScrollRange();
-    method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method public void setExpanded(boolean);
-    method public void setExpanded(boolean, boolean);
-    method public deprecated void setTargetElevation(float);
-  }
-
-  public static class AppBarLayout.Behavior extends android.support.design.widget.HeaderBehavior {
-    ctor public AppBarLayout.Behavior();
-    ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int, int, int, int);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int, int);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int);
-    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
-  }
-
-  public static abstract class AppBarLayout.Behavior.DragCallback {
-    ctor public AppBarLayout.Behavior.DragCallback();
-    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
-  }
-
-  protected static class AppBarLayout.Behavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
-  }
-
-  public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
-    ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public AppBarLayout.LayoutParams(int, int);
-    ctor public AppBarLayout.LayoutParams(int, int, float);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
-    method public int getScrollFlags();
-    method public android.view.animation.Interpolator getScrollInterpolator();
-    method public void setScrollFlags(int);
-    method public void setScrollInterpolator(android.view.animation.Interpolator);
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
-    field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
-    field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
-    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
-  }
-
-  public static abstract interface AppBarLayout.OnOffsetChangedListener {
-    method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
-  }
-
-  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.HeaderScrollingViewBehavior {
-    ctor public AppBarLayout.ScrollingViewBehavior();
-    ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
-  }
-
-  public abstract class BaseTransientBottomBar<B extends android.support.design.widget.BaseTransientBottomBar<B>> {
-    ctor protected BaseTransientBottomBar(android.view.ViewGroup, android.view.View, android.support.design.widget.BaseTransientBottomBar.ContentViewCallback);
-    method public B addCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public void dismiss();
-    method public android.content.Context getContext();
-    method public int getDuration();
-    method public android.view.View getView();
-    method public boolean isShown();
-    method public boolean isShownOrQueued();
-    method public B removeCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public B setDuration(int);
-    method public void show();
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static abstract class BaseTransientBottomBar.BaseCallback<B> {
-    ctor public BaseTransientBottomBar.BaseCallback();
-    method public void onDismissed(B, int);
-    method public void onShown(B);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public static abstract interface BaseTransientBottomBar.ContentViewCallback {
-    method public abstract void animateContentIn(int, int);
-    method public abstract void animateContentOut(int, int);
-  }
-
-  public class BottomNavigationView extends android.widget.FrameLayout {
-    ctor public BottomNavigationView(android.content.Context);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public int getItemBackgroundResource();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public int getMaxItemCount();
-    method public android.view.Menu getMenu();
-    method public int getSelectedItemId();
-    method public void inflateMenu(int);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setOnNavigationItemReselectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemReselectedListener);
-    method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
-    method public void setSelectedItemId(int);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemReselectedListener {
-    method public abstract void onNavigationItemReselected(android.view.MenuItem);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public class BottomSheetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public BottomSheetBehavior();
-    ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
-    method public static <V extends android.view.View> android.support.design.widget.BottomSheetBehavior<V> from(V);
-    method public final int getPeekHeight();
-    method public boolean getSkipCollapsed();
-    method public final int getState();
-    method public boolean isHideable();
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void setBottomSheetCallback(android.support.design.widget.BottomSheetBehavior.BottomSheetCallback);
-    method public void setHideable(boolean);
-    method public final void setPeekHeight(int);
-    method public void setSkipCollapsed(boolean);
-    method public final void setState(int);
-    field public static final int PEEK_HEIGHT_AUTO = -1; // 0xffffffff
-    field public static final int STATE_COLLAPSED = 4; // 0x4
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_EXPANDED = 3; // 0x3
-    field public static final int STATE_HIDDEN = 5; // 0x5
-    field public static final int STATE_SETTLING = 2; // 0x2
-  }
-
-  public static abstract class BottomSheetBehavior.BottomSheetCallback {
-    ctor public BottomSheetBehavior.BottomSheetCallback();
-    method public abstract void onSlide(android.view.View, float);
-    method public abstract void onStateChanged(android.view.View, int);
-  }
-
-  protected static class BottomSheetBehavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
-  }
-
-  public class BottomSheetDialog extends android.support.v7.app.AppCompatDialog {
-    ctor public BottomSheetDialog(android.content.Context);
-    ctor public BottomSheetDialog(android.content.Context, int);
-    ctor protected BottomSheetDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-  }
-
-  public class BottomSheetDialogFragment extends android.support.v7.app.AppCompatDialogFragment {
-    ctor public BottomSheetDialogFragment();
-  }
-
-  public class CollapsingToolbarLayout extends android.widget.FrameLayout {
-    ctor public CollapsingToolbarLayout(android.content.Context);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
-    method protected android.support.design.widget.CollapsingToolbarLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.widget.FrameLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getCollapsedTitleGravity();
-    method public android.graphics.Typeface getCollapsedTitleTypeface();
-    method public android.graphics.drawable.Drawable getContentScrim();
-    method public int getExpandedTitleGravity();
-    method public int getExpandedTitleMarginBottom();
-    method public int getExpandedTitleMarginEnd();
-    method public int getExpandedTitleMarginStart();
-    method public int getExpandedTitleMarginTop();
-    method public android.graphics.Typeface getExpandedTitleTypeface();
-    method public long getScrimAnimationDuration();
-    method public int getScrimVisibleHeightTrigger();
-    method public android.graphics.drawable.Drawable getStatusBarScrim();
-    method public java.lang.CharSequence getTitle();
-    method public boolean isTitleEnabled();
-    method public void setCollapsedTitleGravity(int);
-    method public void setCollapsedTitleTextAppearance(int);
-    method public void setCollapsedTitleTextColor(int);
-    method public void setCollapsedTitleTextColor(android.content.res.ColorStateList);
-    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
-    method public void setContentScrim(android.graphics.drawable.Drawable);
-    method public void setContentScrimColor(int);
-    method public void setContentScrimResource(int);
-    method public void setExpandedTitleColor(int);
-    method public void setExpandedTitleGravity(int);
-    method public void setExpandedTitleMargin(int, int, int, int);
-    method public void setExpandedTitleMarginBottom(int);
-    method public void setExpandedTitleMarginEnd(int);
-    method public void setExpandedTitleMarginStart(int);
-    method public void setExpandedTitleMarginTop(int);
-    method public void setExpandedTitleTextAppearance(int);
-    method public void setExpandedTitleTextColor(android.content.res.ColorStateList);
-    method public void setExpandedTitleTypeface(android.graphics.Typeface);
-    method public void setScrimAnimationDuration(long);
-    method public void setScrimVisibleHeightTrigger(int);
-    method public void setScrimsShown(boolean);
-    method public void setScrimsShown(boolean, boolean);
-    method public void setStatusBarScrim(android.graphics.drawable.Drawable);
-    method public void setStatusBarScrimColor(int);
-    method public void setStatusBarScrimResource(int);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitleEnabled(boolean);
-  }
-
-  public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
-    ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
-    method public int getCollapseMode();
-    method public float getParallaxMultiplier();
-    method public void setCollapseMode(int);
-    method public void setParallaxMultiplier(float);
-    field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
-    field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
-    field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
-  }
-
-  public class CoordinatorLayout extends android.view.ViewGroup {
-    ctor public CoordinatorLayout(android.content.Context);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void dispatchDependentViewsChanged(android.view.View);
-    method public boolean doViewsOverlap(android.view.View, android.view.View);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public java.util.List<android.view.View> getDependencies(android.view.View);
-    method public java.util.List<android.view.View> getDependents(android.view.View);
-    method public android.graphics.drawable.Drawable getStatusBarBackground();
-    method public boolean isPointInChildBounds(android.view.View, int, int);
-    method public void onAttachedToWindow();
-    method public void onDetachedFromWindow();
-    method public void onDraw(android.graphics.Canvas);
-    method protected void onLayout(boolean, int, int, int, int);
-    method public void onLayoutChild(android.view.View, int);
-    method public void onMeasureChild(android.view.View, int, int, int, int);
-    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.view.View, int, int, int, int, int);
-    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
-    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.view.View, int);
-    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
-    method public void setStatusBarBackgroundColor(int);
-    method public void setStatusBarBackgroundResource(int);
-  }
-
-  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
-    ctor public CoordinatorLayout.Behavior();
-    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
-    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
-    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
-    method public static java.lang.Object getTag(android.view.View);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
-    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onDetachedFromLayoutParams();
-    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
-    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
-    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
-    method public deprecated void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[], int);
-    method public deprecated void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int, int);
-    method public deprecated void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
-    method public deprecated boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
-    method public deprecated void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int);
-    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
-    method public static void setTag(android.view.View, java.lang.Object);
-  }
-
-  public static abstract class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
-  }
-
-  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
-    ctor public CoordinatorLayout.LayoutParams(int, int);
-    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getAnchorId();
-    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
-    method public void setAnchorId(int);
-    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
-    field public int anchorGravity;
-    field public int dodgeInsetEdges;
-    field public int gravity;
-    field public int insetEdge;
-    field public int keyline;
-  }
-
-  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
-  }
-
-  public class FloatingActionButton extends android.support.design.widget.VisibilityAwareImageButton {
-    ctor public FloatingActionButton(android.content.Context);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
-    method public float getCompatElevation();
-    method public android.graphics.drawable.Drawable getContentBackground();
-    method public boolean getContentRect(android.graphics.Rect);
-    method public int getRippleColor();
-    method public int getSize();
-    method public boolean getUseCompatPadding();
-    method public void hide();
-    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setCompatElevation(float);
-    method public void setRippleColor(int);
-    method public void setSize(int);
-    method public void setUseCompatPadding(boolean);
-    method public void show();
-    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    field public static final int SIZE_AUTO = -1; // 0xffffffff
-    field public static final int SIZE_MINI = 1; // 0x1
-    field public static final int SIZE_NORMAL = 0; // 0x0
-  }
-
-  public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public FloatingActionButton.Behavior();
-    ctor public FloatingActionButton.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect);
-    method public boolean isAutoHideEnabled();
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
-    method public void setAutoHideEnabled(boolean);
-  }
-
-  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
-    ctor public FloatingActionButton.OnVisibilityChangedListener();
-    method public void onHidden(android.support.design.widget.FloatingActionButton);
-    method public void onShown(android.support.design.widget.FloatingActionButton);
-  }
-
-   abstract class HeaderBehavior<V extends android.view.View> extends android.support.design.widget.ViewOffsetBehavior {
-    ctor public HeaderBehavior();
-    ctor public HeaderBehavior(android.content.Context, android.util.AttributeSet);
-  }
-
-   abstract class HeaderScrollingViewBehavior extends android.support.design.widget.ViewOffsetBehavior {
-    ctor public HeaderScrollingViewBehavior();
-    ctor public HeaderScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
-    method public final int getOverlayTop();
-    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, android.view.View, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.view.View, int, int, int, int);
-    method public final void setOverlayTop(int);
-  }
-
-  public class NavigationView extends android.widget.FrameLayout {
-    ctor public NavigationView(android.content.Context);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public void addHeaderView(android.view.View);
-    method public int getHeaderCount();
-    method public android.view.View getHeaderView(int);
-    method public android.graphics.drawable.Drawable getItemBackground();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public android.view.Menu getMenu();
-    method public android.view.View inflateHeaderView(int);
-    method public void inflateMenu(int);
-    method public void removeHeaderView(android.view.View);
-    method public void setCheckedItem(int);
-    method public void setItemBackground(android.graphics.drawable.Drawable);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextAppearance(int);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
-  }
-
-  public static abstract interface NavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public static class NavigationView.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public NavigationView.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
-    field public android.os.Bundle menuState;
-  }
-
-  public final class Snackbar extends android.support.design.widget.BaseTransientBottomBar {
-    method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
-    method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
-    method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
-    method public android.support.design.widget.Snackbar setActionTextColor(int);
-    method public deprecated android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
-    method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
-    method public android.support.design.widget.Snackbar setText(int);
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static class Snackbar.Callback extends android.support.design.widget.BaseTransientBottomBar.BaseCallback {
-    ctor public Snackbar.Callback();
-    method public void onDismissed(android.support.design.widget.Snackbar, int);
-    method public void onShown(android.support.design.widget.Snackbar);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public class SwipeDismissBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public SwipeDismissBehavior();
-    method public boolean canSwipeDismissView(android.view.View);
-    method public int getDragState();
-    method public void setDragDismissDistance(float);
-    method public void setEndAlphaSwipeDistance(float);
-    method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
-    method public void setSensitivity(float);
-    method public void setStartAlphaSwipeDistance(float);
-    method public void setSwipeDirection(int);
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_IDLE = 0; // 0x0
-    field public static final int STATE_SETTLING = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
-    field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
-  }
-
-  public static abstract interface SwipeDismissBehavior.OnDismissListener {
-    method public abstract void onDismiss(android.view.View);
-    method public abstract void onDragStateChanged(int);
-  }
-
-  public final class TabItem extends android.view.View {
-    ctor public TabItem(android.content.Context);
-    ctor public TabItem(android.content.Context, android.util.AttributeSet);
-  }
-
-  public class TabLayout extends android.widget.HorizontalScrollView {
-    ctor public TabLayout(android.content.Context);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void addOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void addTab(android.support.design.widget.TabLayout.Tab);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
-    method public void clearOnTabSelectedListeners();
-    method public android.widget.FrameLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method public int getSelectedTabPosition();
-    method public android.support.design.widget.TabLayout.Tab getTabAt(int);
-    method public int getTabCount();
-    method public int getTabGravity();
-    method public int getTabMode();
-    method public android.content.res.ColorStateList getTabTextColors();
-    method public android.support.design.widget.TabLayout.Tab newTab();
-    method public void removeAllTabs();
-    method public void removeOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void removeTab(android.support.design.widget.TabLayout.Tab);
-    method public void removeTabAt(int);
-    method public deprecated void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void setScrollPosition(int, float, boolean);
-    method public void setSelectedTabIndicatorColor(int);
-    method public void setSelectedTabIndicatorHeight(int);
-    method public void setTabGravity(int);
-    method public void setTabMode(int);
-    method public void setTabTextColors(android.content.res.ColorStateList);
-    method public void setTabTextColors(int, int);
-    method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager, boolean);
-    field public static final int GRAVITY_CENTER = 1; // 0x1
-    field public static final int GRAVITY_FILL = 0; // 0x0
-    field public static final int MODE_FIXED = 1; // 0x1
-    field public static final int MODE_SCROLLABLE = 0; // 0x0
-  }
-
-  public static abstract interface TabLayout.OnTabSelectedListener {
-    method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public static final class TabLayout.Tab {
-    method public java.lang.CharSequence getContentDescription();
-    method public android.view.View getCustomView();
-    method public android.graphics.drawable.Drawable getIcon();
-    method public int getPosition();
-    method public java.lang.Object getTag();
-    method public java.lang.CharSequence getText();
-    method public boolean isSelected();
-    method public void select();
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(int);
-    method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
-    method public android.support.design.widget.TabLayout.Tab setIcon(int);
-    method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
-    method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setText(int);
-    field public static final int INVALID_POSITION = -1; // 0xffffffff
-  }
-
-  public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
-    ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
-    method public void onPageScrollStateChanged(int);
-    method public void onPageScrolled(int, float, int);
-    method public void onPageSelected(int);
-  }
-
-  public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
-    ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
-    method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public class TextInputEditText extends android.support.v7.widget.AppCompatEditText {
-    ctor public TextInputEditText(android.content.Context);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public class TextInputLayout extends android.widget.LinearLayout {
-    ctor public TextInputLayout(android.content.Context);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
-    method public int getCounterMaxLength();
-    method public android.widget.EditText getEditText();
-    method public java.lang.CharSequence getError();
-    method public java.lang.CharSequence getHint();
-    method public java.lang.CharSequence getPasswordVisibilityToggleContentDescription();
-    method public android.graphics.drawable.Drawable getPasswordVisibilityToggleDrawable();
-    method public android.graphics.Typeface getTypeface();
-    method public boolean isCounterEnabled();
-    method public boolean isErrorEnabled();
-    method public boolean isHintAnimationEnabled();
-    method public boolean isHintEnabled();
-    method public boolean isPasswordVisibilityToggleEnabled();
-    method public android.os.Parcelable onSaveInstanceState();
-    method public void setCounterEnabled(boolean);
-    method public void setCounterMaxLength(int);
-    method public void setError(java.lang.CharSequence);
-    method public void setErrorEnabled(boolean);
-    method public void setErrorTextAppearance(int);
-    method public void setHint(java.lang.CharSequence);
-    method public void setHintAnimationEnabled(boolean);
-    method public void setHintEnabled(boolean);
-    method public void setHintTextAppearance(int);
-    method public void setPasswordVisibilityToggleContentDescription(int);
-    method public void setPasswordVisibilityToggleContentDescription(java.lang.CharSequence);
-    method public void setPasswordVisibilityToggleDrawable(int);
-    method public void setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable);
-    method public void setPasswordVisibilityToggleEnabled(boolean);
-    method public void setPasswordVisibilityToggleTintList(android.content.res.ColorStateList);
-    method public void setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTypeface(android.graphics.Typeface);
-  }
-
-   class ViewOffsetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public ViewOffsetBehavior();
-    ctor public ViewOffsetBehavior(android.content.Context, android.util.AttributeSet);
-    method public int getLeftAndRightOffset();
-    method public int getTopAndBottomOffset();
-    method protected void layoutChild(android.support.design.widget.CoordinatorLayout, V, int);
-    method public boolean setLeftAndRightOffset(int);
-    method public boolean setTopAndBottomOffset(int);
-  }
-
-   class VisibilityAwareImageButton extends android.widget.ImageButton {
-    ctor public VisibilityAwareImageButton(android.content.Context);
-    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet);
-    ctor public VisibilityAwareImageButton(android.content.Context, android.util.AttributeSet, int);
-  }
-
-}
-
diff --git a/design/api/current.txt b/design/api/current.txt
deleted file mode 100644
index 71de20a..0000000
--- a/design/api/current.txt
+++ /dev/null
@@ -1,499 +0,0 @@
-package android.support.design.widget {
-
-  public class AppBarLayout extends android.widget.LinearLayout {
-    ctor public AppBarLayout(android.content.Context);
-    ctor public AppBarLayout(android.content.Context, android.util.AttributeSet);
-    method public void addOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateDefaultLayoutParams();
-    method public android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
-    method protected android.support.design.widget.AppBarLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public deprecated float getTargetElevation();
-    method public final int getTotalScrollRange();
-    method public void removeOnOffsetChangedListener(android.support.design.widget.AppBarLayout.OnOffsetChangedListener);
-    method public void setExpanded(boolean);
-    method public void setExpanded(boolean, boolean);
-    method public deprecated void setTargetElevation(float);
-  }
-
-  public static class AppBarLayout.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public AppBarLayout.Behavior();
-    ctor public AppBarLayout.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int);
-    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, int, int, int, int);
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int[], int);
-    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int, int, int, int, int);
-    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.os.Parcelable);
-    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, android.view.View, int, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, android.support.design.widget.AppBarLayout, android.view.View, int);
-    method public void setDragCallback(android.support.design.widget.AppBarLayout.Behavior.DragCallback);
-  }
-
-  public static abstract class AppBarLayout.Behavior.DragCallback {
-    ctor public AppBarLayout.Behavior.DragCallback();
-    method public abstract boolean canDrag(android.support.design.widget.AppBarLayout);
-  }
-
-  protected static class AppBarLayout.Behavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public AppBarLayout.Behavior.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.AppBarLayout.Behavior.SavedState> CREATOR;
-  }
-
-  public static class AppBarLayout.LayoutParams extends android.widget.LinearLayout.LayoutParams {
-    ctor public AppBarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public AppBarLayout.LayoutParams(int, int);
-    ctor public AppBarLayout.LayoutParams(int, int, float);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.widget.LinearLayout.LayoutParams);
-    ctor public AppBarLayout.LayoutParams(android.support.design.widget.AppBarLayout.LayoutParams);
-    method public int getScrollFlags();
-    method public android.view.animation.Interpolator getScrollInterpolator();
-    method public void setScrollFlags(int);
-    method public void setScrollInterpolator(android.view.animation.Interpolator);
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS = 4; // 0x4
-    field public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 8; // 0x8
-    field public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 2; // 0x2
-    field public static final int SCROLL_FLAG_SCROLL = 1; // 0x1
-    field public static final int SCROLL_FLAG_SNAP = 16; // 0x10
-  }
-
-  public static abstract interface AppBarLayout.OnOffsetChangedListener {
-    method public abstract void onOffsetChanged(android.support.design.widget.AppBarLayout, int);
-  }
-
-  public static class AppBarLayout.ScrollingViewBehavior extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public AppBarLayout.ScrollingViewBehavior();
-    ctor public AppBarLayout.ScrollingViewBehavior(android.content.Context, android.util.AttributeSet);
-    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.view.View, android.view.View);
-    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, android.view.View, android.graphics.Rect, boolean);
-  }
-
-  public abstract class BaseTransientBottomBar<B extends android.support.design.widget.BaseTransientBottomBar<B>> {
-    ctor protected BaseTransientBottomBar(android.view.ViewGroup, android.view.View, android.support.design.widget.BaseTransientBottomBar.ContentViewCallback);
-    method public B addCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public void dismiss();
-    method public android.content.Context getContext();
-    method public int getDuration();
-    method public android.view.View getView();
-    method public boolean isShown();
-    method public boolean isShownOrQueued();
-    method public B removeCallback(android.support.design.widget.BaseTransientBottomBar.BaseCallback<B>);
-    method public B setDuration(int);
-    method public void show();
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static abstract class BaseTransientBottomBar.BaseCallback<B> {
-    ctor public BaseTransientBottomBar.BaseCallback();
-    method public void onDismissed(B, int);
-    method public void onShown(B);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public static abstract interface BaseTransientBottomBar.ContentViewCallback {
-    method public abstract void animateContentIn(int, int);
-    method public abstract void animateContentOut(int, int);
-  }
-
-  public class BottomNavigationView extends android.widget.FrameLayout {
-    ctor public BottomNavigationView(android.content.Context);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public BottomNavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public int getItemBackgroundResource();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public int getMaxItemCount();
-    method public android.view.Menu getMenu();
-    method public int getSelectedItemId();
-    method public void inflateMenu(int);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setOnNavigationItemReselectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemReselectedListener);
-    method public void setOnNavigationItemSelectedListener(android.support.design.widget.BottomNavigationView.OnNavigationItemSelectedListener);
-    method public void setSelectedItemId(int);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemReselectedListener {
-    method public abstract void onNavigationItemReselected(android.view.MenuItem);
-  }
-
-  public static abstract interface BottomNavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public class BottomSheetBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public BottomSheetBehavior();
-    ctor public BottomSheetBehavior(android.content.Context, android.util.AttributeSet);
-    method public static <V extends android.view.View> android.support.design.widget.BottomSheetBehavior<V> from(V);
-    method public final int getPeekHeight();
-    method public boolean getSkipCollapsed();
-    method public final int getState();
-    method public boolean isHideable();
-    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
-    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
-    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
-    method public void setBottomSheetCallback(android.support.design.widget.BottomSheetBehavior.BottomSheetCallback);
-    method public void setHideable(boolean);
-    method public final void setPeekHeight(int);
-    method public void setSkipCollapsed(boolean);
-    method public final void setState(int);
-    field public static final int PEEK_HEIGHT_AUTO = -1; // 0xffffffff
-    field public static final int STATE_COLLAPSED = 4; // 0x4
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_EXPANDED = 3; // 0x3
-    field public static final int STATE_HIDDEN = 5; // 0x5
-    field public static final int STATE_SETTLING = 2; // 0x2
-  }
-
-  public static abstract class BottomSheetBehavior.BottomSheetCallback {
-    ctor public BottomSheetBehavior.BottomSheetCallback();
-    method public abstract void onSlide(android.view.View, float);
-    method public abstract void onStateChanged(android.view.View, int);
-  }
-
-  protected static class BottomSheetBehavior.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public BottomSheetBehavior.SavedState(android.os.Parcelable, int);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.BottomSheetBehavior.SavedState> CREATOR;
-  }
-
-  public class BottomSheetDialog extends android.support.v7.app.AppCompatDialog {
-    ctor public BottomSheetDialog(android.content.Context);
-    ctor public BottomSheetDialog(android.content.Context, int);
-    ctor protected BottomSheetDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
-  }
-
-  public class BottomSheetDialogFragment extends android.support.v7.app.AppCompatDialogFragment {
-    ctor public BottomSheetDialogFragment();
-  }
-
-  public class CollapsingToolbarLayout extends android.widget.FrameLayout {
-    ctor public CollapsingToolbarLayout(android.content.Context);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout(android.content.Context, android.util.AttributeSet, int);
-    method protected android.support.design.widget.CollapsingToolbarLayout.LayoutParams generateDefaultLayoutParams();
-    method protected android.widget.FrameLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
-    method public int getCollapsedTitleGravity();
-    method public android.graphics.Typeface getCollapsedTitleTypeface();
-    method public android.graphics.drawable.Drawable getContentScrim();
-    method public int getExpandedTitleGravity();
-    method public int getExpandedTitleMarginBottom();
-    method public int getExpandedTitleMarginEnd();
-    method public int getExpandedTitleMarginStart();
-    method public int getExpandedTitleMarginTop();
-    method public android.graphics.Typeface getExpandedTitleTypeface();
-    method public long getScrimAnimationDuration();
-    method public int getScrimVisibleHeightTrigger();
-    method public android.graphics.drawable.Drawable getStatusBarScrim();
-    method public java.lang.CharSequence getTitle();
-    method public boolean isTitleEnabled();
-    method public void setCollapsedTitleGravity(int);
-    method public void setCollapsedTitleTextAppearance(int);
-    method public void setCollapsedTitleTextColor(int);
-    method public void setCollapsedTitleTextColor(android.content.res.ColorStateList);
-    method public void setCollapsedTitleTypeface(android.graphics.Typeface);
-    method public void setContentScrim(android.graphics.drawable.Drawable);
-    method public void setContentScrimColor(int);
-    method public void setContentScrimResource(int);
-    method public void setExpandedTitleColor(int);
-    method public void setExpandedTitleGravity(int);
-    method public void setExpandedTitleMargin(int, int, int, int);
-    method public void setExpandedTitleMarginBottom(int);
-    method public void setExpandedTitleMarginEnd(int);
-    method public void setExpandedTitleMarginStart(int);
-    method public void setExpandedTitleMarginTop(int);
-    method public void setExpandedTitleTextAppearance(int);
-    method public void setExpandedTitleTextColor(android.content.res.ColorStateList);
-    method public void setExpandedTitleTypeface(android.graphics.Typeface);
-    method public void setScrimAnimationDuration(long);
-    method public void setScrimVisibleHeightTrigger(int);
-    method public void setScrimsShown(boolean);
-    method public void setScrimsShown(boolean, boolean);
-    method public void setStatusBarScrim(android.graphics.drawable.Drawable);
-    method public void setStatusBarScrimColor(int);
-    method public void setStatusBarScrimResource(int);
-    method public void setTitle(java.lang.CharSequence);
-    method public void setTitleEnabled(boolean);
-  }
-
-  public static class CollapsingToolbarLayout.LayoutParams extends android.widget.FrameLayout.LayoutParams {
-    ctor public CollapsingToolbarLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(int, int, int);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
-    ctor public CollapsingToolbarLayout.LayoutParams(android.widget.FrameLayout.LayoutParams);
-    method public int getCollapseMode();
-    method public float getParallaxMultiplier();
-    method public void setCollapseMode(int);
-    method public void setParallaxMultiplier(float);
-    field public static final int COLLAPSE_MODE_OFF = 0; // 0x0
-    field public static final int COLLAPSE_MODE_PARALLAX = 2; // 0x2
-    field public static final int COLLAPSE_MODE_PIN = 1; // 0x1
-  }
-
-  public class FloatingActionButton extends android.widget.ImageButton {
-    ctor public FloatingActionButton(android.content.Context);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet);
-    ctor public FloatingActionButton(android.content.Context, android.util.AttributeSet, int);
-    method public float getCompatElevation();
-    method public android.graphics.drawable.Drawable getContentBackground();
-    method public boolean getContentRect(android.graphics.Rect);
-    method public int getCustomSize();
-    method public int getRippleColor();
-    method public int getSize();
-    method public boolean getUseCompatPadding();
-    method public void hide();
-    method public void hide(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
-    method public void setCompatElevation(float);
-    method public void setCustomSize(int);
-    method public void setRippleColor(int);
-    method public void setSize(int);
-    method public void setUseCompatPadding(boolean);
-    method public void show();
-    method public void show(android.support.design.widget.FloatingActionButton.OnVisibilityChangedListener);
-    field public static final int NO_CUSTOM_SIZE = 0; // 0x0
-    field public static final int SIZE_AUTO = -1; // 0xffffffff
-    field public static final int SIZE_MINI = 1; // 0x1
-    field public static final int SIZE_NORMAL = 0; // 0x0
-  }
-
-  public static class FloatingActionButton.Behavior extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public FloatingActionButton.Behavior();
-    ctor public FloatingActionButton.Behavior(android.content.Context, android.util.AttributeSet);
-    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.graphics.Rect);
-    method public boolean isAutoHideEnabled();
-    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, android.view.View);
-    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, android.support.design.widget.FloatingActionButton, int);
-    method public void setAutoHideEnabled(boolean);
-  }
-
-  public static abstract class FloatingActionButton.OnVisibilityChangedListener {
-    ctor public FloatingActionButton.OnVisibilityChangedListener();
-    method public void onHidden(android.support.design.widget.FloatingActionButton);
-    method public void onShown(android.support.design.widget.FloatingActionButton);
-  }
-
-  public class NavigationView extends android.widget.FrameLayout {
-    ctor public NavigationView(android.content.Context);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet);
-    ctor public NavigationView(android.content.Context, android.util.AttributeSet, int);
-    method public void addHeaderView(android.view.View);
-    method public int getHeaderCount();
-    method public android.view.View getHeaderView(int);
-    method public android.graphics.drawable.Drawable getItemBackground();
-    method public android.content.res.ColorStateList getItemIconTintList();
-    method public android.content.res.ColorStateList getItemTextColor();
-    method public android.view.Menu getMenu();
-    method public android.view.View inflateHeaderView(int);
-    method public void inflateMenu(int);
-    method public void removeHeaderView(android.view.View);
-    method public void setCheckedItem(int);
-    method public void setItemBackground(android.graphics.drawable.Drawable);
-    method public void setItemBackgroundResource(int);
-    method public void setItemIconTintList(android.content.res.ColorStateList);
-    method public void setItemTextAppearance(int);
-    method public void setItemTextColor(android.content.res.ColorStateList);
-    method public void setNavigationItemSelectedListener(android.support.design.widget.NavigationView.OnNavigationItemSelectedListener);
-  }
-
-  public static abstract interface NavigationView.OnNavigationItemSelectedListener {
-    method public abstract boolean onNavigationItemSelected(android.view.MenuItem);
-  }
-
-  public static class NavigationView.SavedState extends android.support.v4.view.AbsSavedState {
-    ctor public NavigationView.SavedState(android.os.Parcel, java.lang.ClassLoader);
-    ctor public NavigationView.SavedState(android.os.Parcelable);
-    field public static final android.os.Parcelable.Creator<android.support.design.widget.NavigationView.SavedState> CREATOR;
-    field public android.os.Bundle menuState;
-  }
-
-  public final class Snackbar extends android.support.design.widget.BaseTransientBottomBar {
-    method public static android.support.design.widget.Snackbar make(android.view.View, java.lang.CharSequence, int);
-    method public static android.support.design.widget.Snackbar make(android.view.View, int, int);
-    method public android.support.design.widget.Snackbar setAction(int, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setAction(java.lang.CharSequence, android.view.View.OnClickListener);
-    method public android.support.design.widget.Snackbar setActionTextColor(android.content.res.ColorStateList);
-    method public android.support.design.widget.Snackbar setActionTextColor(int);
-    method public deprecated android.support.design.widget.Snackbar setCallback(android.support.design.widget.Snackbar.Callback);
-    method public android.support.design.widget.Snackbar setText(java.lang.CharSequence);
-    method public android.support.design.widget.Snackbar setText(int);
-    field public static final int LENGTH_INDEFINITE = -2; // 0xfffffffe
-    field public static final int LENGTH_LONG = 0; // 0x0
-    field public static final int LENGTH_SHORT = -1; // 0xffffffff
-  }
-
-  public static class Snackbar.Callback extends android.support.design.widget.BaseTransientBottomBar.BaseCallback {
-    ctor public Snackbar.Callback();
-    method public void onDismissed(android.support.design.widget.Snackbar, int);
-    method public void onShown(android.support.design.widget.Snackbar);
-    field public static final int DISMISS_EVENT_ACTION = 1; // 0x1
-    field public static final int DISMISS_EVENT_CONSECUTIVE = 4; // 0x4
-    field public static final int DISMISS_EVENT_MANUAL = 3; // 0x3
-    field public static final int DISMISS_EVENT_SWIPE = 0; // 0x0
-    field public static final int DISMISS_EVENT_TIMEOUT = 2; // 0x2
-  }
-
-  public class SwipeDismissBehavior<V extends android.view.View> extends android.support.design.widget.CoordinatorLayout.Behavior {
-    ctor public SwipeDismissBehavior();
-    method public boolean canSwipeDismissView(android.view.View);
-    method public int getDragState();
-    method public void setDragDismissDistance(float);
-    method public void setEndAlphaSwipeDistance(float);
-    method public void setListener(android.support.design.widget.SwipeDismissBehavior.OnDismissListener);
-    method public void setSensitivity(float);
-    method public void setStartAlphaSwipeDistance(float);
-    method public void setSwipeDirection(int);
-    field public static final int STATE_DRAGGING = 1; // 0x1
-    field public static final int STATE_IDLE = 0; // 0x0
-    field public static final int STATE_SETTLING = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_ANY = 2; // 0x2
-    field public static final int SWIPE_DIRECTION_END_TO_START = 1; // 0x1
-    field public static final int SWIPE_DIRECTION_START_TO_END = 0; // 0x0
-  }
-
-  public static abstract interface SwipeDismissBehavior.OnDismissListener {
-    method public abstract void onDismiss(android.view.View);
-    method public abstract void onDragStateChanged(int);
-  }
-
-  public final class TabItem extends android.view.View {
-    ctor public TabItem(android.content.Context);
-    ctor public TabItem(android.content.Context, android.util.AttributeSet);
-  }
-
-  public class TabLayout extends android.widget.HorizontalScrollView {
-    ctor public TabLayout(android.content.Context);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TabLayout(android.content.Context, android.util.AttributeSet, int);
-    method public void addOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void addTab(android.support.design.widget.TabLayout.Tab);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, boolean);
-    method public void addTab(android.support.design.widget.TabLayout.Tab, int, boolean);
-    method public void clearOnTabSelectedListeners();
-    method public int getSelectedTabPosition();
-    method public android.support.design.widget.TabLayout.Tab getTabAt(int);
-    method public int getTabCount();
-    method public int getTabGravity();
-    method public int getTabMode();
-    method public android.content.res.ColorStateList getTabTextColors();
-    method public android.support.design.widget.TabLayout.Tab newTab();
-    method public void removeAllTabs();
-    method public void removeOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void removeTab(android.support.design.widget.TabLayout.Tab);
-    method public void removeTabAt(int);
-    method public deprecated void setOnTabSelectedListener(android.support.design.widget.TabLayout.OnTabSelectedListener);
-    method public void setScrollPosition(int, float, boolean);
-    method public void setSelectedTabIndicatorColor(int);
-    method public void setSelectedTabIndicatorHeight(int);
-    method public void setTabGravity(int);
-    method public void setTabMode(int);
-    method public void setTabTextColors(android.content.res.ColorStateList);
-    method public void setTabTextColors(int, int);
-    method public deprecated void setTabsFromPagerAdapter(android.support.v4.view.PagerAdapter);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager);
-    method public void setupWithViewPager(android.support.v4.view.ViewPager, boolean);
-    field public static final int GRAVITY_CENTER = 1; // 0x1
-    field public static final int GRAVITY_FILL = 0; // 0x0
-    field public static final int MODE_FIXED = 1; // 0x1
-    field public static final int MODE_SCROLLABLE = 0; // 0x0
-  }
-
-  public static abstract interface TabLayout.OnTabSelectedListener {
-    method public abstract void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public abstract void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public static final class TabLayout.Tab {
-    method public java.lang.CharSequence getContentDescription();
-    method public android.view.View getCustomView();
-    method public android.graphics.drawable.Drawable getIcon();
-    method public int getPosition();
-    method public java.lang.Object getTag();
-    method public java.lang.CharSequence getText();
-    method public boolean isSelected();
-    method public void select();
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(int);
-    method public android.support.design.widget.TabLayout.Tab setContentDescription(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(android.view.View);
-    method public android.support.design.widget.TabLayout.Tab setCustomView(int);
-    method public android.support.design.widget.TabLayout.Tab setIcon(android.graphics.drawable.Drawable);
-    method public android.support.design.widget.TabLayout.Tab setIcon(int);
-    method public android.support.design.widget.TabLayout.Tab setTag(java.lang.Object);
-    method public android.support.design.widget.TabLayout.Tab setText(java.lang.CharSequence);
-    method public android.support.design.widget.TabLayout.Tab setText(int);
-    field public static final int INVALID_POSITION = -1; // 0xffffffff
-  }
-
-  public static class TabLayout.TabLayoutOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
-    ctor public TabLayout.TabLayoutOnPageChangeListener(android.support.design.widget.TabLayout);
-    method public void onPageScrollStateChanged(int);
-    method public void onPageScrolled(int, float, int);
-    method public void onPageSelected(int);
-  }
-
-  public static class TabLayout.ViewPagerOnTabSelectedListener implements android.support.design.widget.TabLayout.OnTabSelectedListener {
-    ctor public TabLayout.ViewPagerOnTabSelectedListener(android.support.v4.view.ViewPager);
-    method public void onTabReselected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabSelected(android.support.design.widget.TabLayout.Tab);
-    method public void onTabUnselected(android.support.design.widget.TabLayout.Tab);
-  }
-
-  public class TextInputEditText extends android.support.v7.widget.AppCompatEditText {
-    ctor public TextInputEditText(android.content.Context);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputEditText(android.content.Context, android.util.AttributeSet, int);
-  }
-
-  public class TextInputLayout extends android.widget.LinearLayout implements android.support.v7.widget.WithHint {
-    ctor public TextInputLayout(android.content.Context);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet);
-    ctor public TextInputLayout(android.content.Context, android.util.AttributeSet, int);
-    method public int getCounterMaxLength();
-    method public android.widget.EditText getEditText();
-    method public java.lang.CharSequence getError();
-    method public java.lang.CharSequence getHint();
-    method public java.lang.CharSequence getPasswordVisibilityToggleContentDescription();
-    method public android.graphics.drawable.Drawable getPasswordVisibilityToggleDrawable();
-    method public android.graphics.Typeface getTypeface();
-    method public boolean isCounterEnabled();
-    method public boolean isErrorEnabled();
-    method public boolean isHintAnimationEnabled();
-    method public boolean isHintEnabled();
-    method public boolean isPasswordVisibilityToggleEnabled();
-    method public android.os.Parcelable onSaveInstanceState();
-    method public void setCounterEnabled(boolean);
-    method public void setCounterMaxLength(int);
-    method public void setError(java.lang.CharSequence);
-    method public void setErrorEnabled(boolean);
-    method public void setErrorTextAppearance(int);
-    method public void setHint(java.lang.CharSequence);
-    method public void setHintAnimationEnabled(boolean);
-    method public void setHintEnabled(boolean);
-    method public void setHintTextAppearance(int);
-    method public void setPasswordVisibilityToggleContentDescription(int);
-    method public void setPasswordVisibilityToggleContentDescription(java.lang.CharSequence);
-    method public void setPasswordVisibilityToggleDrawable(int);
-    method public void setPasswordVisibilityToggleDrawable(android.graphics.drawable.Drawable);
-    method public void setPasswordVisibilityToggleEnabled(boolean);
-    method public void setPasswordVisibilityToggleTintList(android.content.res.ColorStateList);
-    method public void setPasswordVisibilityToggleTintMode(android.graphics.PorterDuff.Mode);
-    method public void setTypeface(android.graphics.Typeface);
-  }
-
-}
-
diff --git a/design/base/android/support/design/widget/AnimationUtils.java b/design/base/android/support/design/widget/AnimationUtils.java
deleted file mode 100644
index 3613afd..0000000
--- a/design/base/android/support/design/widget/AnimationUtils.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.v4.view.animation.FastOutLinearInInterpolator;
-import android.support.v4.view.animation.FastOutSlowInInterpolator;
-import android.support.v4.view.animation.LinearOutSlowInInterpolator;
-import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-
-class AnimationUtils {
-
-    static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    static final Interpolator FAST_OUT_SLOW_IN_INTERPOLATOR = new FastOutSlowInInterpolator();
-    static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new FastOutLinearInInterpolator();
-    static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR = new LinearOutSlowInInterpolator();
-    static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator();
-
-    /**
-     * Linear interpolation between {@code startValue} and {@code endValue} by {@code fraction}.
-     */
-    static float lerp(float startValue, float endValue, float fraction) {
-        return startValue + (fraction * (endValue - startValue));
-    }
-
-    static int lerp(int startValue, int endValue, float fraction) {
-        return startValue + Math.round(fraction * (endValue - startValue));
-    }
-
-}
diff --git a/design/base/android/support/design/widget/CircularBorderDrawable.java b/design/base/android/support/design/widget/CircularBorderDrawable.java
deleted file mode 100644
index 617a501..0000000
--- a/design/base/android/support/design/widget/CircularBorderDrawable.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-import android.support.v4.graphics.ColorUtils;
-
-/**
- * A drawable which draws an oval 'border'.
- */
-class CircularBorderDrawable extends Drawable {
-
-    /**
-     * We actually draw the stroke wider than the border size given. This is to reduce any
-     * potential transparent space caused by anti-aliasing and padding rounding.
-     * This value defines the multiplier used to determine to draw stroke width.
-     */
-    private static final float DRAW_STROKE_WIDTH_MULTIPLE = 1.3333f;
-
-    final Paint mPaint;
-    final Rect mRect = new Rect();
-    final RectF mRectF = new RectF();
-
-    float mBorderWidth;
-
-    private int mTopOuterStrokeColor;
-    private int mTopInnerStrokeColor;
-    private int mBottomOuterStrokeColor;
-    private int mBottomInnerStrokeColor;
-
-    private ColorStateList mBorderTint;
-    private int mCurrentBorderTintColor;
-
-    private boolean mInvalidateShader = true;
-
-    private float mRotation;
-
-    public CircularBorderDrawable() {
-        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPaint.setStyle(Paint.Style.STROKE);
-    }
-
-    void setGradientColors(int topOuterStrokeColor, int topInnerStrokeColor,
-            int bottomOuterStrokeColor, int bottomInnerStrokeColor) {
-        mTopOuterStrokeColor = topOuterStrokeColor;
-        mTopInnerStrokeColor = topInnerStrokeColor;
-        mBottomOuterStrokeColor = bottomOuterStrokeColor;
-        mBottomInnerStrokeColor = bottomInnerStrokeColor;
-    }
-
-    /**
-     * Set the border width
-     */
-    void setBorderWidth(float width) {
-        if (mBorderWidth != width) {
-            mBorderWidth = width;
-            mPaint.setStrokeWidth(width * DRAW_STROKE_WIDTH_MULTIPLE);
-            mInvalidateShader = true;
-            invalidateSelf();
-        }
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        if (mInvalidateShader) {
-            mPaint.setShader(createGradientShader());
-            mInvalidateShader = false;
-        }
-
-        final float halfBorderWidth = mPaint.getStrokeWidth() / 2f;
-        final RectF rectF = mRectF;
-
-        // We need to inset the oval bounds by half the border width. This is because stroke draws
-        // the center of the border on the dimension. Whereas we want the stroke on the inside.
-        copyBounds(mRect);
-        rectF.set(mRect);
-        rectF.left += halfBorderWidth;
-        rectF.top += halfBorderWidth;
-        rectF.right -= halfBorderWidth;
-        rectF.bottom -= halfBorderWidth;
-
-        canvas.save();
-        canvas.rotate(mRotation, rectF.centerX(), rectF.centerY());
-        // Draw the oval
-        canvas.drawOval(rectF, mPaint);
-        canvas.restore();
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        final int borderWidth = Math.round(mBorderWidth);
-        padding.set(borderWidth, borderWidth, borderWidth, borderWidth);
-        return true;
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mPaint.setAlpha(alpha);
-        invalidateSelf();
-    }
-
-    void setBorderTint(ColorStateList tint) {
-        if (tint != null) {
-            mCurrentBorderTintColor = tint.getColorForState(getState(), mCurrentBorderTintColor);
-        }
-        mBorderTint = tint;
-        mInvalidateShader = true;
-        invalidateSelf();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter colorFilter) {
-        mPaint.setColorFilter(colorFilter);
-        invalidateSelf();
-    }
-
-    @Override
-    public int getOpacity() {
-        return mBorderWidth > 0 ? PixelFormat.TRANSLUCENT : PixelFormat.TRANSPARENT;
-    }
-
-    final void setRotation(float rotation) {
-        if (rotation != mRotation) {
-            mRotation = rotation;
-            invalidateSelf();
-        }
-    }
-
-    @Override
-    protected void onBoundsChange(Rect bounds) {
-        mInvalidateShader = true;
-    }
-
-    @Override
-    public boolean isStateful() {
-        return (mBorderTint != null && mBorderTint.isStateful()) || super.isStateful();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        if (mBorderTint != null) {
-            final int newColor = mBorderTint.getColorForState(state, mCurrentBorderTintColor);
-            if (newColor != mCurrentBorderTintColor) {
-                mInvalidateShader = true;
-                mCurrentBorderTintColor = newColor;
-            }
-        }
-        if (mInvalidateShader) {
-            invalidateSelf();
-        }
-        return mInvalidateShader;
-    }
-
-    /**
-     * Creates a vertical {@link LinearGradient}
-     * @return
-     */
-    private Shader createGradientShader() {
-        final Rect rect = mRect;
-        copyBounds(rect);
-
-        final float borderRatio = mBorderWidth / rect.height();
-
-        final int[] colors = new int[6];
-        colors[0] = ColorUtils.compositeColors(mTopOuterStrokeColor, mCurrentBorderTintColor);
-        colors[1] = ColorUtils.compositeColors(mTopInnerStrokeColor, mCurrentBorderTintColor);
-        colors[2] = ColorUtils.compositeColors(
-                ColorUtils.setAlphaComponent(mTopInnerStrokeColor, 0), mCurrentBorderTintColor);
-        colors[3] = ColorUtils.compositeColors(
-                ColorUtils.setAlphaComponent(mBottomInnerStrokeColor, 0), mCurrentBorderTintColor);
-        colors[4] = ColorUtils.compositeColors(mBottomInnerStrokeColor, mCurrentBorderTintColor);
-        colors[5] = ColorUtils.compositeColors(mBottomOuterStrokeColor, mCurrentBorderTintColor);
-
-        final float[] positions = new float[6];
-        positions[0] = 0f;
-        positions[1] = borderRatio;
-        positions[2] = 0.5f;
-        positions[3] = 0.5f;
-        positions[4] = 1f - borderRatio;
-        positions[5] = 1f;
-
-        return new LinearGradient(
-                0, rect.top,
-                0, rect.bottom,
-                colors, positions,
-                Shader.TileMode.CLAMP);
-    }
-}
diff --git a/design/base/android/support/design/widget/FloatingActionButtonImpl.java b/design/base/android/support/design/widget/FloatingActionButtonImpl.java
deleted file mode 100644
index 132cd81..0000000
--- a/design/base/android/support/design/widget/FloatingActionButtonImpl.java
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.design.R;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-import android.view.ViewTreeObserver;
-import android.view.animation.Interpolator;
-
-@RequiresApi(14)
-class FloatingActionButtonImpl {
-    static final Interpolator ANIM_INTERPOLATOR = AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR;
-    static final long PRESSED_ANIM_DURATION = 100;
-    static final long PRESSED_ANIM_DELAY = 100;
-
-    static final int ANIM_STATE_NONE = 0;
-    static final int ANIM_STATE_HIDING = 1;
-    static final int ANIM_STATE_SHOWING = 2;
-
-    int mAnimState = ANIM_STATE_NONE;
-
-    private final StateListAnimator mStateListAnimator;
-
-    ShadowDrawableWrapper mShadowDrawable;
-
-    private float mRotation;
-
-    Drawable mShapeDrawable;
-    Drawable mRippleDrawable;
-    CircularBorderDrawable mBorderDrawable;
-    Drawable mContentBackground;
-
-    float mElevation;
-    float mPressedTranslationZ;
-
-    interface InternalVisibilityChangedListener {
-        void onShown();
-        void onHidden();
-    }
-
-    static final int SHOW_HIDE_ANIM_DURATION = 200;
-
-    static final int[] PRESSED_ENABLED_STATE_SET = {android.R.attr.state_pressed,
-            android.R.attr.state_enabled};
-    static final int[] FOCUSED_ENABLED_STATE_SET = {android.R.attr.state_focused,
-            android.R.attr.state_enabled};
-    static final int[] ENABLED_STATE_SET = {android.R.attr.state_enabled};
-    static final int[] EMPTY_STATE_SET = new int[0];
-
-    final VisibilityAwareImageButton mView;
-    final ShadowViewDelegate mShadowViewDelegate;
-
-    private final Rect mTmpRect = new Rect();
-    private ViewTreeObserver.OnPreDrawListener mPreDrawListener;
-
-    FloatingActionButtonImpl(VisibilityAwareImageButton view,
-            ShadowViewDelegate shadowViewDelegate) {
-        mView = view;
-        mShadowViewDelegate = shadowViewDelegate;
-
-        mStateListAnimator = new StateListAnimator();
-
-        // Elevate with translationZ when pressed or focused
-        mStateListAnimator.addState(PRESSED_ENABLED_STATE_SET,
-                createAnimator(new ElevateToTranslationZAnimation()));
-        mStateListAnimator.addState(FOCUSED_ENABLED_STATE_SET,
-                createAnimator(new ElevateToTranslationZAnimation()));
-        // Reset back to elevation by default
-        mStateListAnimator.addState(ENABLED_STATE_SET,
-                createAnimator(new ResetElevationAnimation()));
-        // Set to 0 when disabled
-        mStateListAnimator.addState(EMPTY_STATE_SET,
-                createAnimator(new DisabledElevationAnimation()));
-
-        mRotation = mView.getRotation();
-    }
-
-    void setBackgroundDrawable(ColorStateList backgroundTint,
-            PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
-        // Now we need to tint the original background with the tint, using
-        // an InsetDrawable if we have a border width
-        mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
-        DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
-        if (backgroundTintMode != null) {
-            DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
-        }
-
-        // Now we created a mask Drawable which will be used for touch feedback.
-        GradientDrawable touchFeedbackShape = createShapeDrawable();
-
-        // We'll now wrap that touch feedback mask drawable with a ColorStateList. We do not need
-        // to inset for any border here as LayerDrawable will nest the padding for us
-        mRippleDrawable = DrawableCompat.wrap(touchFeedbackShape);
-        DrawableCompat.setTintList(mRippleDrawable, createColorStateList(rippleColor));
-
-        final Drawable[] layers;
-        if (borderWidth > 0) {
-            mBorderDrawable = createBorderDrawable(borderWidth, backgroundTint);
-            layers = new Drawable[] {mBorderDrawable, mShapeDrawable, mRippleDrawable};
-        } else {
-            mBorderDrawable = null;
-            layers = new Drawable[] {mShapeDrawable, mRippleDrawable};
-        }
-
-        mContentBackground = new LayerDrawable(layers);
-
-        mShadowDrawable = new ShadowDrawableWrapper(
-                mView.getContext(),
-                mContentBackground,
-                mShadowViewDelegate.getRadius(),
-                mElevation,
-                mElevation + mPressedTranslationZ);
-        mShadowDrawable.setAddPaddingForCorners(false);
-        mShadowViewDelegate.setBackgroundDrawable(mShadowDrawable);
-    }
-
-    void setBackgroundTintList(ColorStateList tint) {
-        if (mShapeDrawable != null) {
-            DrawableCompat.setTintList(mShapeDrawable, tint);
-        }
-        if (mBorderDrawable != null) {
-            mBorderDrawable.setBorderTint(tint);
-        }
-    }
-
-    void setBackgroundTintMode(PorterDuff.Mode tintMode) {
-        if (mShapeDrawable != null) {
-            DrawableCompat.setTintMode(mShapeDrawable, tintMode);
-        }
-    }
-
-
-    void setRippleColor(int rippleColor) {
-        if (mRippleDrawable != null) {
-            DrawableCompat.setTintList(mRippleDrawable, createColorStateList(rippleColor));
-        }
-    }
-
-    final void setElevation(float elevation) {
-        if (mElevation != elevation) {
-            mElevation = elevation;
-            onElevationsChanged(elevation, mPressedTranslationZ);
-        }
-    }
-
-    float getElevation() {
-        return mElevation;
-    }
-
-    final void setPressedTranslationZ(float translationZ) {
-        if (mPressedTranslationZ != translationZ) {
-            mPressedTranslationZ = translationZ;
-            onElevationsChanged(mElevation, translationZ);
-        }
-    }
-
-    void onElevationsChanged(float elevation, float pressedTranslationZ) {
-        if (mShadowDrawable != null) {
-            mShadowDrawable.setShadowSize(elevation, elevation + mPressedTranslationZ);
-            updatePadding();
-        }
-    }
-
-    void onDrawableStateChanged(int[] state) {
-        mStateListAnimator.setState(state);
-    }
-
-    void jumpDrawableToCurrentState() {
-        mStateListAnimator.jumpToCurrentState();
-    }
-
-    void hide(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
-        if (isOrWillBeHidden()) {
-            // We either are or will soon be hidden, skip the call
-            return;
-        }
-
-        mView.animate().cancel();
-
-        if (shouldAnimateVisibilityChange()) {
-            mAnimState = ANIM_STATE_HIDING;
-
-            mView.animate()
-                    .scaleX(0f)
-                    .scaleY(0f)
-                    .alpha(0f)
-                    .setDuration(SHOW_HIDE_ANIM_DURATION)
-                    .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
-                    .setListener(new AnimatorListenerAdapter() {
-                        private boolean mCancelled;
-
-                        @Override
-                        public void onAnimationStart(Animator animation) {
-                            mView.internalSetVisibility(View.VISIBLE, fromUser);
-                            mCancelled = false;
-                        }
-
-                        @Override
-                        public void onAnimationCancel(Animator animation) {
-                            mCancelled = true;
-                        }
-
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mAnimState = ANIM_STATE_NONE;
-
-                            if (!mCancelled) {
-                                mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE,
-                                        fromUser);
-                                if (listener != null) {
-                                    listener.onHidden();
-                                }
-                            }
-                        }
-                    });
-        } else {
-            // If the view isn't laid out, or we're in the editor, don't run the animation
-            mView.internalSetVisibility(fromUser ? View.GONE : View.INVISIBLE, fromUser);
-            if (listener != null) {
-                listener.onHidden();
-            }
-        }
-    }
-
-    void show(@Nullable final InternalVisibilityChangedListener listener, final boolean fromUser) {
-        if (isOrWillBeShown()) {
-            // We either are or will soon be visible, skip the call
-            return;
-        }
-
-        mView.animate().cancel();
-
-        if (shouldAnimateVisibilityChange()) {
-            mAnimState = ANIM_STATE_SHOWING;
-
-            if (mView.getVisibility() != View.VISIBLE) {
-                // If the view isn't visible currently, we'll animate it from a single pixel
-                mView.setAlpha(0f);
-                mView.setScaleY(0f);
-                mView.setScaleX(0f);
-            }
-
-            mView.animate()
-                    .scaleX(1f)
-                    .scaleY(1f)
-                    .alpha(1f)
-                    .setDuration(SHOW_HIDE_ANIM_DURATION)
-                    .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
-                    .setListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationStart(Animator animation) {
-                            mView.internalSetVisibility(View.VISIBLE, fromUser);
-                        }
-
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mAnimState = ANIM_STATE_NONE;
-                            if (listener != null) {
-                                listener.onShown();
-                            }
-                        }
-                    });
-        } else {
-            mView.internalSetVisibility(View.VISIBLE, fromUser);
-            mView.setAlpha(1f);
-            mView.setScaleY(1f);
-            mView.setScaleX(1f);
-            if (listener != null) {
-                listener.onShown();
-            }
-        }
-    }
-
-    final Drawable getContentBackground() {
-        return mContentBackground;
-    }
-
-    void onCompatShadowChanged() {
-        // Ignore pre-v21
-    }
-
-    final void updatePadding() {
-        Rect rect = mTmpRect;
-        getPadding(rect);
-        onPaddingUpdated(rect);
-        mShadowViewDelegate.setShadowPadding(rect.left, rect.top, rect.right, rect.bottom);
-    }
-
-    void getPadding(Rect rect) {
-        mShadowDrawable.getPadding(rect);
-    }
-
-    void onPaddingUpdated(Rect padding) {}
-
-    void onAttachedToWindow() {
-        if (requirePreDrawListener()) {
-            ensurePreDrawListener();
-            mView.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
-        }
-    }
-
-    void onDetachedFromWindow() {
-        if (mPreDrawListener != null) {
-            mView.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
-            mPreDrawListener = null;
-        }
-    }
-
-    boolean requirePreDrawListener() {
-        return true;
-    }
-
-    CircularBorderDrawable createBorderDrawable(int borderWidth, ColorStateList backgroundTint) {
-        final Context context = mView.getContext();
-        CircularBorderDrawable borderDrawable = newCircularDrawable();
-        borderDrawable.setGradientColors(
-                ContextCompat.getColor(context, R.color.design_fab_stroke_top_outer_color),
-                ContextCompat.getColor(context, R.color.design_fab_stroke_top_inner_color),
-                ContextCompat.getColor(context, R.color.design_fab_stroke_end_inner_color),
-                ContextCompat.getColor(context, R.color.design_fab_stroke_end_outer_color));
-        borderDrawable.setBorderWidth(borderWidth);
-        borderDrawable.setBorderTint(backgroundTint);
-        return borderDrawable;
-    }
-
-    CircularBorderDrawable newCircularDrawable() {
-        return new CircularBorderDrawable();
-    }
-
-    void onPreDraw() {
-        final float rotation = mView.getRotation();
-        if (mRotation != rotation) {
-            mRotation = rotation;
-            updateFromViewRotation();
-        }
-    }
-
-    private void ensurePreDrawListener() {
-        if (mPreDrawListener == null) {
-            mPreDrawListener = new ViewTreeObserver.OnPreDrawListener() {
-                @Override
-                public boolean onPreDraw() {
-                    FloatingActionButtonImpl.this.onPreDraw();
-                    return true;
-                }
-            };
-        }
-    }
-
-    GradientDrawable createShapeDrawable() {
-        GradientDrawable d = newGradientDrawableForShape();
-        d.setShape(GradientDrawable.OVAL);
-        d.setColor(Color.WHITE);
-        return d;
-    }
-
-    GradientDrawable newGradientDrawableForShape() {
-        return new GradientDrawable();
-    }
-
-    boolean isOrWillBeShown() {
-        if (mView.getVisibility() != View.VISIBLE) {
-            // If we not currently visible, return true if we're animating to be shown
-            return mAnimState == ANIM_STATE_SHOWING;
-        } else {
-            // Otherwise if we're visible, return true if we're not animating to be hidden
-            return mAnimState != ANIM_STATE_HIDING;
-        }
-    }
-
-    boolean isOrWillBeHidden() {
-        if (mView.getVisibility() == View.VISIBLE) {
-            // If we currently visible, return true if we're animating to be hidden
-            return mAnimState == ANIM_STATE_HIDING;
-        } else {
-            // Otherwise if we're not visible, return true if we're not animating to be shown
-            return mAnimState != ANIM_STATE_SHOWING;
-        }
-    }
-
-    private ValueAnimator createAnimator(@NonNull ShadowAnimatorImpl impl) {
-        final ValueAnimator animator = new ValueAnimator();
-        animator.setInterpolator(ANIM_INTERPOLATOR);
-        animator.setDuration(PRESSED_ANIM_DURATION);
-        animator.addListener(impl);
-        animator.addUpdateListener(impl);
-        animator.setFloatValues(0, 1);
-        return animator;
-    }
-
-    private abstract class ShadowAnimatorImpl extends AnimatorListenerAdapter
-            implements ValueAnimator.AnimatorUpdateListener {
-        private boolean mValidValues;
-        private float mShadowSizeStart;
-        private float mShadowSizeEnd;
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animator) {
-            if (!mValidValues) {
-                mShadowSizeStart = mShadowDrawable.getShadowSize();
-                mShadowSizeEnd = getTargetShadowSize();
-                mValidValues = true;
-            }
-
-            mShadowDrawable.setShadowSize(mShadowSizeStart
-                    + ((mShadowSizeEnd - mShadowSizeStart) * animator.getAnimatedFraction()));
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animator) {
-            mShadowDrawable.setShadowSize(mShadowSizeEnd);
-            mValidValues = false;
-        }
-
-        /**
-         * @return the shadow size we want to animate to.
-         */
-        protected abstract float getTargetShadowSize();
-    }
-
-    private class ResetElevationAnimation extends ShadowAnimatorImpl {
-        ResetElevationAnimation() {
-        }
-
-        @Override
-        protected float getTargetShadowSize() {
-            return mElevation;
-        }
-    }
-
-    private class ElevateToTranslationZAnimation extends ShadowAnimatorImpl {
-        ElevateToTranslationZAnimation() {
-        }
-
-        @Override
-        protected float getTargetShadowSize() {
-            return mElevation + mPressedTranslationZ;
-        }
-    }
-
-    private class DisabledElevationAnimation extends ShadowAnimatorImpl {
-        DisabledElevationAnimation() {
-        }
-
-        @Override
-        protected float getTargetShadowSize() {
-            return 0f;
-        }
-    }
-
-    private static ColorStateList createColorStateList(int selectedColor) {
-        final int[][] states = new int[3][];
-        final int[] colors = new int[3];
-        int i = 0;
-
-        states[i] = FOCUSED_ENABLED_STATE_SET;
-        colors[i] = selectedColor;
-        i++;
-
-        states[i] = PRESSED_ENABLED_STATE_SET;
-        colors[i] = selectedColor;
-        i++;
-
-        // Default enabled state
-        states[i] = new int[0];
-        colors[i] = Color.TRANSPARENT;
-        i++;
-
-        return new ColorStateList(states, colors);
-    }
-
-    private boolean shouldAnimateVisibilityChange() {
-        return ViewCompat.isLaidOut(mView) && !mView.isInEditMode();
-    }
-
-    private void updateFromViewRotation() {
-        if (Build.VERSION.SDK_INT == 19) {
-            // KitKat seems to have an issue with views which are rotated with angles which are
-            // not divisible by 90. Worked around by moving to software rendering in these cases.
-            if ((mRotation % 90) != 0) {
-                if (mView.getLayerType() != View.LAYER_TYPE_SOFTWARE) {
-                    mView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-                }
-            } else {
-                if (mView.getLayerType() != View.LAYER_TYPE_NONE) {
-                    mView.setLayerType(View.LAYER_TYPE_NONE, null);
-                }
-            }
-        }
-
-        // Offset any View rotation
-        if (mShadowDrawable != null) {
-            mShadowDrawable.setRotation(-mRotation);
-        }
-        if (mBorderDrawable != null) {
-            mBorderDrawable.setRotation(-mRotation);
-        }
-    }
-}
diff --git a/design/base/android/support/design/widget/ShadowDrawableWrapper.java b/design/base/android/support/design/widget/ShadowDrawableWrapper.java
deleted file mode 100644
index dfb8e1d..0000000
--- a/design/base/android/support/design/widget/ShadowDrawableWrapper.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PixelFormat;
-import android.graphics.RadialGradient;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-import android.support.design.R;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.graphics.drawable.DrawableWrapper;
-
-/**
- * A {@link android.graphics.drawable.Drawable} which wraps another drawable and
- * draws a shadow around it.
- */
-class ShadowDrawableWrapper extends DrawableWrapper {
-    // used to calculate content padding
-    static final double COS_45 = Math.cos(Math.toRadians(45));
-
-    static final float SHADOW_MULTIPLIER = 1.5f;
-
-    static final float SHADOW_TOP_SCALE = 0.25f;
-    static final float SHADOW_HORIZ_SCALE = 0.5f;
-    static final float SHADOW_BOTTOM_SCALE = 1f;
-
-    final Paint mCornerShadowPaint;
-    final Paint mEdgeShadowPaint;
-
-    final RectF mContentBounds;
-
-    float mCornerRadius;
-
-    Path mCornerShadowPath;
-
-    // updated value with inset
-    float mMaxShadowSize;
-    // actual value set by developer
-    float mRawMaxShadowSize;
-
-    // multiplied value to account for shadow offset
-    float mShadowSize;
-    // actual value set by developer
-    float mRawShadowSize;
-
-    private boolean mDirty = true;
-
-    private final int mShadowStartColor;
-    private final int mShadowMiddleColor;
-    private final int mShadowEndColor;
-
-    private boolean mAddPaddingForCorners = true;
-
-    private float mRotation;
-
-    /**
-     * If shadow size is set to a value above max shadow, we print a warning
-     */
-    private boolean mPrintedShadowClipWarning = false;
-
-    public ShadowDrawableWrapper(Context context, Drawable content, float radius,
-            float shadowSize, float maxShadowSize) {
-        super(content);
-
-        mShadowStartColor = ContextCompat.getColor(context, R.color.design_fab_shadow_start_color);
-        mShadowMiddleColor = ContextCompat.getColor(context, R.color.design_fab_shadow_mid_color);
-        mShadowEndColor = ContextCompat.getColor(context, R.color.design_fab_shadow_end_color);
-
-        mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
-        mCornerShadowPaint.setStyle(Paint.Style.FILL);
-        mCornerRadius = Math.round(radius);
-        mContentBounds = new RectF();
-        mEdgeShadowPaint = new Paint(mCornerShadowPaint);
-        mEdgeShadowPaint.setAntiAlias(false);
-        setShadowSize(shadowSize, maxShadowSize);
-    }
-
-    /**
-     * Casts the value to an even integer.
-     */
-    private static int toEven(float value) {
-        int i = Math.round(value);
-        return (i % 2 == 1) ? i - 1 : i;
-    }
-
-    public void setAddPaddingForCorners(boolean addPaddingForCorners) {
-        mAddPaddingForCorners = addPaddingForCorners;
-        invalidateSelf();
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        super.setAlpha(alpha);
-        mCornerShadowPaint.setAlpha(alpha);
-        mEdgeShadowPaint.setAlpha(alpha);
-    }
-
-    @Override
-    protected void onBoundsChange(Rect bounds) {
-        mDirty = true;
-    }
-
-    void setShadowSize(float shadowSize, float maxShadowSize) {
-        if (shadowSize < 0 || maxShadowSize < 0) {
-            throw new IllegalArgumentException("invalid shadow size");
-        }
-        shadowSize = toEven(shadowSize);
-        maxShadowSize = toEven(maxShadowSize);
-        if (shadowSize > maxShadowSize) {
-            shadowSize = maxShadowSize;
-            if (!mPrintedShadowClipWarning) {
-                mPrintedShadowClipWarning = true;
-            }
-        }
-        if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) {
-            return;
-        }
-        mRawShadowSize = shadowSize;
-        mRawMaxShadowSize = maxShadowSize;
-        mShadowSize = Math.round(shadowSize * SHADOW_MULTIPLIER);
-        mMaxShadowSize = maxShadowSize;
-        mDirty = true;
-        invalidateSelf();
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius,
-                mAddPaddingForCorners));
-        int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius,
-                mAddPaddingForCorners));
-        padding.set(hOffset, vOffset, hOffset, vOffset);
-        return true;
-    }
-
-    public static float calculateVerticalPadding(float maxShadowSize, float cornerRadius,
-            boolean addPaddingForCorners) {
-        if (addPaddingForCorners) {
-            return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius);
-        } else {
-            return maxShadowSize * SHADOW_MULTIPLIER;
-        }
-    }
-
-    public static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius,
-            boolean addPaddingForCorners) {
-        if (addPaddingForCorners) {
-            return (float) (maxShadowSize + (1 - COS_45) * cornerRadius);
-        } else {
-            return maxShadowSize;
-        }
-    }
-
-    @Override
-    public int getOpacity() {
-        return PixelFormat.TRANSLUCENT;
-    }
-
-    public void setCornerRadius(float radius) {
-        radius = Math.round(radius);
-        if (mCornerRadius == radius) {
-            return;
-        }
-        mCornerRadius = radius;
-        mDirty = true;
-        invalidateSelf();
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        if (mDirty) {
-            buildComponents(getBounds());
-            mDirty = false;
-        }
-        drawShadow(canvas);
-
-        super.draw(canvas);
-    }
-
-    final void setRotation(float rotation) {
-        if (mRotation != rotation) {
-            mRotation = rotation;
-            invalidateSelf();
-        }
-    }
-
-    private void drawShadow(Canvas canvas) {
-        final int rotateSaved = canvas.save();
-        canvas.rotate(mRotation, mContentBounds.centerX(), mContentBounds.centerY());
-
-        final float edgeShadowTop = -mCornerRadius - mShadowSize;
-        final float shadowOffset = mCornerRadius;
-        final boolean drawHorizontalEdges = mContentBounds.width() - 2 * shadowOffset > 0;
-        final boolean drawVerticalEdges = mContentBounds.height() - 2 * shadowOffset > 0;
-
-        final float shadowOffsetTop = mRawShadowSize - (mRawShadowSize * SHADOW_TOP_SCALE);
-        final float shadowOffsetHorizontal = mRawShadowSize - (mRawShadowSize * SHADOW_HORIZ_SCALE);
-        final float shadowOffsetBottom = mRawShadowSize - (mRawShadowSize * SHADOW_BOTTOM_SCALE);
-
-        final float shadowScaleHorizontal = shadowOffset / (shadowOffset + shadowOffsetHorizontal);
-        final float shadowScaleTop = shadowOffset / (shadowOffset + shadowOffsetTop);
-        final float shadowScaleBottom = shadowOffset / (shadowOffset + shadowOffsetBottom);
-
-        // LT
-        int saved = canvas.save();
-        canvas.translate(mContentBounds.left + shadowOffset, mContentBounds.top + shadowOffset);
-        canvas.scale(shadowScaleHorizontal, shadowScaleTop);
-        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
-        if (drawHorizontalEdges) {
-            // TE
-            canvas.scale(1f / shadowScaleHorizontal, 1f);
-            canvas.drawRect(0, edgeShadowTop,
-                    mContentBounds.width() - 2 * shadowOffset, -mCornerRadius,
-                    mEdgeShadowPaint);
-        }
-        canvas.restoreToCount(saved);
-        // RB
-        saved = canvas.save();
-        canvas.translate(mContentBounds.right - shadowOffset, mContentBounds.bottom - shadowOffset);
-        canvas.scale(shadowScaleHorizontal, shadowScaleBottom);
-        canvas.rotate(180f);
-        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
-        if (drawHorizontalEdges) {
-            // BE
-            canvas.scale(1f / shadowScaleHorizontal, 1f);
-            canvas.drawRect(0, edgeShadowTop,
-                    mContentBounds.width() - 2 * shadowOffset, -mCornerRadius + mShadowSize,
-                    mEdgeShadowPaint);
-        }
-        canvas.restoreToCount(saved);
-        // LB
-        saved = canvas.save();
-        canvas.translate(mContentBounds.left + shadowOffset, mContentBounds.bottom - shadowOffset);
-        canvas.scale(shadowScaleHorizontal, shadowScaleBottom);
-        canvas.rotate(270f);
-        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
-        if (drawVerticalEdges) {
-            // LE
-            canvas.scale(1f / shadowScaleBottom, 1f);
-            canvas.drawRect(0, edgeShadowTop,
-                    mContentBounds.height() - 2 * shadowOffset, -mCornerRadius, mEdgeShadowPaint);
-        }
-        canvas.restoreToCount(saved);
-        // RT
-        saved = canvas.save();
-        canvas.translate(mContentBounds.right - shadowOffset, mContentBounds.top + shadowOffset);
-        canvas.scale(shadowScaleHorizontal, shadowScaleTop);
-        canvas.rotate(90f);
-        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
-        if (drawVerticalEdges) {
-            // RE
-            canvas.scale(1f / shadowScaleTop, 1f);
-            canvas.drawRect(0, edgeShadowTop,
-                    mContentBounds.height() - 2 * shadowOffset, -mCornerRadius, mEdgeShadowPaint);
-        }
-        canvas.restoreToCount(saved);
-
-        canvas.restoreToCount(rotateSaved);
-    }
-
-    private void buildShadowCorners() {
-        RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius);
-        RectF outerBounds = new RectF(innerBounds);
-        outerBounds.inset(-mShadowSize, -mShadowSize);
-
-        if (mCornerShadowPath == null) {
-            mCornerShadowPath = new Path();
-        } else {
-            mCornerShadowPath.reset();
-        }
-        mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD);
-        mCornerShadowPath.moveTo(-mCornerRadius, 0);
-        mCornerShadowPath.rLineTo(-mShadowSize, 0);
-        // outer arc
-        mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false);
-        // inner arc
-        mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false);
-        mCornerShadowPath.close();
-
-        float shadowRadius = -outerBounds.top;
-        if (shadowRadius > 0f) {
-            float startRatio = mCornerRadius / shadowRadius;
-            float midRatio = startRatio + ((1f - startRatio) / 2f);
-            mCornerShadowPaint.setShader(new RadialGradient(0, 0, shadowRadius,
-                    new int[]{0, mShadowStartColor, mShadowMiddleColor, mShadowEndColor},
-                    new float[]{0f, startRatio, midRatio, 1f},
-                    Shader.TileMode.CLAMP));
-        }
-
-        // we offset the content shadowSize/2 pixels up to make it more realistic.
-        // this is why edge shadow shader has some extra space
-        // When drawing bottom edge shadow, we use that extra space.
-        mEdgeShadowPaint.setShader(new LinearGradient(0, innerBounds.top, 0, outerBounds.top,
-                new int[]{mShadowStartColor, mShadowMiddleColor, mShadowEndColor},
-                new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP));
-        mEdgeShadowPaint.setAntiAlias(false);
-    }
-
-    private void buildComponents(Rect bounds) {
-        // Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift.
-        // We could have different top-bottom offsets to avoid extra gap above but in that case
-        // center aligning Views inside the CardView would be problematic.
-        final float verticalOffset = mRawMaxShadowSize * SHADOW_MULTIPLIER;
-        mContentBounds.set(bounds.left + mRawMaxShadowSize, bounds.top + verticalOffset,
-                bounds.right - mRawMaxShadowSize, bounds.bottom - verticalOffset);
-
-        getWrappedDrawable().setBounds((int) mContentBounds.left, (int) mContentBounds.top,
-                (int) mContentBounds.right, (int) mContentBounds.bottom);
-
-        buildShadowCorners();
-    }
-
-    public float getCornerRadius() {
-        return mCornerRadius;
-    }
-
-    public void setShadowSize(float size) {
-        setShadowSize(size, mRawMaxShadowSize);
-    }
-
-    public void setMaxShadowSize(float size) {
-        setShadowSize(mRawShadowSize, size);
-    }
-
-    public float getShadowSize() {
-        return mRawShadowSize;
-    }
-
-    public float getMaxShadowSize() {
-        return mRawMaxShadowSize;
-    }
-
-    public float getMinWidth() {
-        final float content = 2 *
-                Math.max(mRawMaxShadowSize, mCornerRadius + mRawMaxShadowSize / 2);
-        return content + mRawMaxShadowSize * 2;
-    }
-
-    public float getMinHeight() {
-        final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius
-                + mRawMaxShadowSize * SHADOW_MULTIPLIER / 2);
-        return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER) * 2;
-    }
-}
diff --git a/design/base/android/support/design/widget/ShadowViewDelegate.java b/design/base/android/support/design/widget/ShadowViewDelegate.java
deleted file mode 100644
index 83a3a7a..0000000
--- a/design/base/android/support/design/widget/ShadowViewDelegate.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.graphics.drawable.Drawable;
-
-interface ShadowViewDelegate {
-    float getRadius();
-    void setShadowPadding(int left, int top, int right, int bottom);
-    void setBackgroundDrawable(Drawable background);
-    boolean isCompatPaddingEnabled();
-}
diff --git a/design/base/android/support/design/widget/StateListAnimator.java b/design/base/android/support/design/widget/StateListAnimator.java
deleted file mode 100644
index aef24be..0000000
--- a/design/base/android/support/design/widget/StateListAnimator.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.util.StateSet;
-
-import java.util.ArrayList;
-
-final class StateListAnimator {
-
-    private final ArrayList<Tuple> mTuples = new ArrayList<>();
-
-    private Tuple mLastMatch = null;
-    ValueAnimator mRunningAnimator = null;
-
-    private final ValueAnimator.AnimatorListener mAnimationListener =
-            new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animator) {
-                    if (mRunningAnimator == animator) {
-                        mRunningAnimator = null;
-                    }
-                }
-            };
-
-    /**
-     * Associates the given Animation with the provided drawable state specs so that it will be run
-     * when the View's drawable state matches the specs.
-     *
-     * @param specs    The drawable state specs to match against
-     * @param animator The animator to run when the specs match
-     */
-    public void addState(int[] specs, ValueAnimator animator) {
-        Tuple tuple = new Tuple(specs, animator);
-        animator.addListener(mAnimationListener);
-        mTuples.add(tuple);
-    }
-
-    /**
-     * Called by View
-     */
-    void setState(int[] state) {
-        Tuple match = null;
-        final int count = mTuples.size();
-        for (int i = 0; i < count; i++) {
-            final Tuple tuple = mTuples.get(i);
-            if (StateSet.stateSetMatches(tuple.mSpecs, state)) {
-                match = tuple;
-                break;
-            }
-        }
-        if (match == mLastMatch) {
-            return;
-        }
-        if (mLastMatch != null) {
-            cancel();
-        }
-
-        mLastMatch = match;
-
-        if (match != null) {
-            start(match);
-        }
-    }
-
-    private void start(Tuple match) {
-        mRunningAnimator = match.mAnimator;
-        mRunningAnimator.start();
-    }
-
-    private void cancel() {
-        if (mRunningAnimator != null) {
-            mRunningAnimator.cancel();
-            mRunningAnimator = null;
-        }
-    }
-
-    /**
-     * If there is an animation running for a recent state change, ends it.
-     *
-     * <p>This causes the animation to assign the end value(s) to the View.</p>
-     */
-    public void jumpToCurrentState() {
-        if (mRunningAnimator != null) {
-            mRunningAnimator.end();
-            mRunningAnimator = null;
-        }
-    }
-
-    static class Tuple {
-        final int[] mSpecs;
-        final ValueAnimator mAnimator;
-
-        Tuple(int[] specs, ValueAnimator animator) {
-            mSpecs = specs;
-            mAnimator = animator;
-        }
-    }
-}
\ No newline at end of file
diff --git a/design/base/android/support/design/widget/VisibilityAwareImageButton.java b/design/base/android/support/design/widget/VisibilityAwareImageButton.java
deleted file mode 100644
index d7a0b13..0000000
--- a/design/base/android/support/design/widget/VisibilityAwareImageButton.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.widget.ImageButton;
-
-class VisibilityAwareImageButton extends ImageButton {
-
-    private int mUserSetVisibility;
-
-    public VisibilityAwareImageButton(Context context) {
-        this(context, null);
-    }
-
-    public VisibilityAwareImageButton(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public VisibilityAwareImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        mUserSetVisibility = getVisibility();
-    }
-
-    @Override
-    public void setVisibility(int visibility) {
-        internalSetVisibility(visibility, true);
-    }
-
-    final void internalSetVisibility(int visibility, boolean fromUser) {
-        super.setVisibility(visibility);
-        if (fromUser) {
-            mUserSetVisibility = visibility;
-        }
-    }
-
-    final int getUserSetVisibility() {
-        return mUserSetVisibility;
-    }
-}
diff --git a/design/build.gradle b/design/build.gradle
deleted file mode 100644
index baa94ea..0000000
--- a/design/build.gradle
+++ /dev/null
@@ -1,67 +0,0 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-
-plugins {
-    id("SupportAndroidLibraryPlugin")
-}
-
-dependencies {
-    api(project(":support-v4"))
-    api(project(":appcompat-v7"))
-    api(project(":recyclerview-v7"))
-    api(project(":transition"))
-
-    androidTestImplementation(TEST_RUNNER)
-    androidTestImplementation(ESPRESSO_CORE)
-    androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
-    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils')
-}
-
-android {
-    defaultConfig {
-        // This disables the builds tools automatic vector -> PNG generation
-        generatedDensities = []
-    }
-
-    sourceSets {
-        main.java.srcDirs = [
-                'base',
-                'gingerbread',
-                'ics',
-                'lollipop',
-                'src'
-        ]
-        main.res.srcDirs = [
-                'res',
-                'res-public'
-        ]
-        main.resources.srcDir 'src'
-    }
-
-    buildTypes.all {
-        consumerProguardFiles 'proguard-rules.pro'
-    }
-
-    aaptOptions {
-        additionalParameters "--no-version-vectors"
-    }
-
-    buildTypes {
-        debug {
-            pseudoLocalesEnabled true
-        }
-    }
-}
-
-supportLibrary {
-    name = "Android Design Support Library"
-    publish = true
-    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
-    mavenGroup = LibraryGroups.SUPPORT
-    inceptionYear = "2015"
-    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
-    legacySourceLocation = true
-}
diff --git a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java b/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
deleted file mode 100644
index 8008404..0000000
--- a/design/lollipop/android/support/design/widget/CircularBorderDrawableLollipop.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.graphics.Outline;
-import android.support.annotation.RequiresApi;
-
-/**
- * Lollipop version of {@link CircularBorderDrawable}.
- */
-@RequiresApi(21)
-class CircularBorderDrawableLollipop extends CircularBorderDrawable {
-
-    @Override
-    public void getOutline(Outline outline) {
-        copyBounds(mRect);
-        outline.setOval(mRect);
-    }
-
-}
diff --git a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java b/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
deleted file mode 100644
index 0df83da..0000000
--- a/design/lollipop/android/support/design/widget/FloatingActionButtonLollipop.java
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.StateListAnimator;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.InsetDrawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.RippleDrawable;
-import android.os.Build;
-import android.support.annotation.RequiresApi;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.view.View;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RequiresApi(21)
-class FloatingActionButtonLollipop extends FloatingActionButtonImpl {
-
-    private InsetDrawable mInsetDrawable;
-
-    FloatingActionButtonLollipop(VisibilityAwareImageButton view,
-            ShadowViewDelegate shadowViewDelegate) {
-        super(view, shadowViewDelegate);
-    }
-
-    @Override
-    void setBackgroundDrawable(ColorStateList backgroundTint,
-            PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
-        // Now we need to tint the shape background with the tint
-        mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
-        DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
-        if (backgroundTintMode != null) {
-            DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
-        }
-
-        final Drawable rippleContent;
-        if (borderWidth > 0) {
-            mBorderDrawable = createBorderDrawable(borderWidth, backgroundTint);
-            rippleContent = new LayerDrawable(new Drawable[]{mBorderDrawable, mShapeDrawable});
-        } else {
-            mBorderDrawable = null;
-            rippleContent = mShapeDrawable;
-        }
-
-        mRippleDrawable = new RippleDrawable(ColorStateList.valueOf(rippleColor),
-                rippleContent, null);
-
-        mContentBackground = mRippleDrawable;
-
-        mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable);
-    }
-
-    @Override
-    void setRippleColor(int rippleColor) {
-        if (mRippleDrawable instanceof RippleDrawable) {
-            ((RippleDrawable) mRippleDrawable).setColor(ColorStateList.valueOf(rippleColor));
-        } else {
-            super.setRippleColor(rippleColor);
-        }
-    }
-
-    @Override
-    void onElevationsChanged(final float elevation, final float pressedTranslationZ) {
-        if (Build.VERSION.SDK_INT == 21) {
-            // Animations produce NPE in version 21. Bluntly set the values instead (matching the
-            // logic in the animations below).
-            if (mView.isEnabled()) {
-                mView.setElevation(elevation);
-                if (mView.isFocused() || mView.isPressed()) {
-                    mView.setTranslationZ(pressedTranslationZ);
-                } else {
-                    mView.setTranslationZ(0);
-                }
-            } else {
-                mView.setElevation(0);
-                mView.setTranslationZ(0);
-            }
-        } else {
-            final StateListAnimator stateListAnimator = new StateListAnimator();
-
-            // Animate elevation and translationZ to our values when pressed
-            AnimatorSet set = new AnimatorSet();
-            set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0))
-                    .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ)
-                            .setDuration(PRESSED_ANIM_DURATION));
-            set.setInterpolator(ANIM_INTERPOLATOR);
-            stateListAnimator.addState(PRESSED_ENABLED_STATE_SET, set);
-
-            // Same deal for when we're focused
-            set = new AnimatorSet();
-            set.play(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0))
-                    .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, pressedTranslationZ)
-                            .setDuration(PRESSED_ANIM_DURATION));
-            set.setInterpolator(ANIM_INTERPOLATOR);
-            stateListAnimator.addState(FOCUSED_ENABLED_STATE_SET, set);
-
-            // Animate translationZ to 0 if not pressed
-            set = new AnimatorSet();
-            List<Animator> animators = new ArrayList<>();
-            animators.add(ObjectAnimator.ofFloat(mView, "elevation", elevation).setDuration(0));
-            if (Build.VERSION.SDK_INT >= 22 && Build.VERSION.SDK_INT <= 24) {
-                // This is a no-op animation which exists here only for introducing the duration
-                // because setting the delay (on the next animation) via "setDelay" or "after"
-                // can trigger a NPE between android versions 22 and 24 (due to a framework
-                // bug). The issue has been fixed in version 25.
-                animators.add(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z,
-                        mView.getTranslationZ()).setDuration(PRESSED_ANIM_DELAY));
-            }
-            animators.add(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f)
-                    .setDuration(PRESSED_ANIM_DURATION));
-            set.playSequentially(animators.toArray(new ObjectAnimator[0]));
-            set.setInterpolator(ANIM_INTERPOLATOR);
-            stateListAnimator.addState(ENABLED_STATE_SET, set);
-
-            // Animate everything to 0 when disabled
-            set = new AnimatorSet();
-            set.play(ObjectAnimator.ofFloat(mView, "elevation", 0f).setDuration(0))
-                    .with(ObjectAnimator.ofFloat(mView, View.TRANSLATION_Z, 0f).setDuration(0));
-            set.setInterpolator(ANIM_INTERPOLATOR);
-            stateListAnimator.addState(EMPTY_STATE_SET, set);
-
-            mView.setStateListAnimator(stateListAnimator);
-        }
-
-        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
-            updatePadding();
-        }
-    }
-
-    @Override
-    public float getElevation() {
-        return mView.getElevation();
-    }
-
-    @Override
-    void onCompatShadowChanged() {
-        updatePadding();
-    }
-
-    @Override
-    void onPaddingUpdated(Rect padding) {
-        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
-            mInsetDrawable = new InsetDrawable(mRippleDrawable,
-                    padding.left, padding.top, padding.right, padding.bottom);
-            mShadowViewDelegate.setBackgroundDrawable(mInsetDrawable);
-        } else {
-            mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable);
-        }
-    }
-
-    @Override
-    void onDrawableStateChanged(int[] state) {
-        // no-op
-    }
-
-    @Override
-    void jumpDrawableToCurrentState() {
-        // no-op
-    }
-
-    @Override
-    boolean requirePreDrawListener() {
-        return false;
-    }
-
-    @Override
-    CircularBorderDrawable newCircularDrawable() {
-        return new CircularBorderDrawableLollipop();
-    }
-
-    @Override
-    GradientDrawable newGradientDrawableForShape() {
-        return new AlwaysStatefulGradientDrawable();
-    }
-
-    @Override
-    void getPadding(Rect rect) {
-        if (mShadowViewDelegate.isCompatPaddingEnabled()) {
-            final float radius = mShadowViewDelegate.getRadius();
-            final float maxShadowSize = getElevation() + mPressedTranslationZ;
-            final int hPadding = (int) Math.ceil(
-                    ShadowDrawableWrapper.calculateHorizontalPadding(maxShadowSize, radius, false));
-            final int vPadding = (int) Math.ceil(
-                    ShadowDrawableWrapper.calculateVerticalPadding(maxShadowSize, radius, false));
-            rect.set(hPadding, vPadding, hPadding, vPadding);
-        } else {
-            rect.set(0, 0, 0, 0);
-        }
-    }
-
-    /**
-     * LayerDrawable on L+ caches its isStateful() state and doesn't refresh it,
-     * meaning that if we apply a tint to one of its children, the parent doesn't become
-     * stateful and the tint doesn't work for state changes. We workaround it by saying that we
-     * are always stateful. If we don't have a stateful tint, the change is ignored anyway.
-     */
-    static class AlwaysStatefulGradientDrawable extends GradientDrawable {
-        @Override
-        public boolean isStateful() {
-            return true;
-        }
-    }
-}
diff --git a/design/lollipop/android/support/design/widget/ViewUtilsLollipop.java b/design/lollipop/android/support/design/widget/ViewUtilsLollipop.java
deleted file mode 100644
index 5927e9b..0000000
--- a/design/lollipop/android/support/design/widget/ViewUtilsLollipop.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.animation.AnimatorInflater;
-import android.animation.ObjectAnimator;
-import android.animation.StateListAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.annotation.RequiresApi;
-import android.support.design.R;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-
-@RequiresApi(21)
-class ViewUtilsLollipop {
-
-    private static final int[] STATE_LIST_ANIM_ATTRS = new int[] {android.R.attr.stateListAnimator};
-
-    static void setBoundsViewOutlineProvider(View view) {
-        view.setOutlineProvider(ViewOutlineProvider.BOUNDS);
-    }
-
-    static void setStateListAnimatorFromAttrs(View view, AttributeSet attrs,
-           int defStyleAttr,  int defStyleRes) {
-        final Context context = view.getContext();
-        final TypedArray a = context.obtainStyledAttributes(attrs, STATE_LIST_ANIM_ATTRS,
-                defStyleAttr, defStyleRes);
-        try {
-            if (a.hasValue(0)) {
-                StateListAnimator sla = AnimatorInflater.loadStateListAnimator(context,
-                        a.getResourceId(0, 0));
-                view.setStateListAnimator(sla);
-            }
-        } finally {
-            a.recycle();
-        }
-    }
-
-    /**
-     * Creates and sets a {@link StateListAnimator} with a custom elevation value
-     */
-    static void setDefaultAppBarLayoutStateListAnimator(final View view, final float elevation) {
-        final int dur = view.getResources().getInteger(R.integer.app_bar_elevation_anim_duration);
-
-        final StateListAnimator sla = new StateListAnimator();
-
-        // Enabled and collapsible, but not collapsed means not elevated
-        sla.addState(new int[]{android.R.attr.enabled, R.attr.state_collapsible,
-                        -R.attr.state_collapsed},
-                ObjectAnimator.ofFloat(view, "elevation", 0f).setDuration(dur));
-
-        // Default enabled state
-        sla.addState(new int[]{android.R.attr.enabled},
-                ObjectAnimator.ofFloat(view, "elevation", elevation).setDuration(dur));
-
-        // Disabled state
-        sla.addState(new int[0],
-                ObjectAnimator.ofFloat(view, "elevation", 0).setDuration(0));
-
-        view.setStateListAnimator(sla);
-    }
-
-}
diff --git a/design/proguard-rules.pro b/design/proguard-rules.pro
deleted file mode 100644
index 96e2ee0..0000000
--- a/design/proguard-rules.pro
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# CoordinatorLayout resolves the behaviors of its child components with reflection.
--keep public class * extends android.support.design.widget.CoordinatorLayout$Behavior {
-    public <init>(android.content.Context, android.util.AttributeSet);
-    public <init>();
-}
-
-# Make sure we keep annotations for CoordinatorLayout's DefaultBehavior
--keepattributes *Annotation*
diff --git a/design/res-public/values/public_attrs.xml b/design/res-public/values/public_attrs.xml
deleted file mode 100644
index 9afe981..0000000
--- a/design/res-public/values/public_attrs.xml
+++ /dev/null
@@ -1,83 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Definitions of attributes to be exposed as public -->
-<resources>
-    <public type="attr" name="backgroundTint"/>
-    <public type="attr" name="backgroundTintMode"/>
-    <public type="attr" name="behavior_hideable"/>
-    <public type="attr" name="behavior_overlapTop"/>
-    <public type="attr" name="behavior_peekHeight"/>
-    <public type="attr" name="borderWidth"/>
-    <public type="attr" name="bottomSheetDialogTheme"/>
-    <public type="attr" name="bottomSheetStyle"/>
-    <public type="attr" name="collapsedTitleGravity"/>
-    <public type="attr" name="collapsedTitleTextAppearance"/>
-    <public type="attr" name="contentScrim"/>
-    <public type="attr" name="counterEnabled"/>
-    <public type="attr" name="counterMaxLength"/>
-    <public type="attr" name="counterOverflowTextAppearance"/>
-    <public type="attr" name="counterTextAppearance"/>
-    <public type="attr" name="elevation"/>
-    <public type="attr" name="errorEnabled"/>
-    <public type="attr" name="errorTextAppearance"/>
-    <public type="attr" name="expanded"/>
-    <public type="attr" name="expandedTitleGravity"/>
-    <public type="attr" name="expandedTitleMargin"/>
-    <public type="attr" name="expandedTitleMarginBottom"/>
-    <public type="attr" name="expandedTitleMarginEnd"/>
-    <public type="attr" name="expandedTitleMarginStart"/>
-    <public type="attr" name="expandedTitleMarginTop"/>
-    <public type="attr" name="expandedTitleTextAppearance"/>
-    <public type="attr" name="fabSize"/>
-    <public type="attr" name="headerLayout"/>
-    <public type="attr" name="hintAnimationEnabled"/>
-    <public type="attr" name="hintEnabled"/>
-    <public type="attr" name="hintTextAppearance"/>
-    <public type="attr" name="itemBackground"/>
-    <public type="attr" name="itemIconTint"/>
-    <public type="attr" name="itemTextAppearance"/>
-    <public type="attr" name="itemTextColor"/>
-    <public type="attr" name="layout_collapseMode"/>
-    <public type="attr" name="layout_collapseParallaxMultiplier"/>
-    <public type="attr" name="layout_scrollFlags"/>
-    <public type="attr" name="layout_scrollInterpolator"/>
-    <public type="attr" name="menu"/>
-    <public type="attr" name="pressedTranslationZ"/>
-    <public type="attr" name="rippleColor"/>
-    <public type="attr" name="statusBarScrim"/>
-    <public type="attr" name="tabBackground"/>
-    <public type="attr" name="tabContentStart"/>
-    <public type="attr" name="tabGravity"/>
-    <public type="attr" name="tabIndicatorColor"/>
-    <public type="attr" name="tabIndicatorHeight"/>
-    <public type="attr" name="tabMaxWidth"/>
-    <public type="attr" name="tabMinWidth"/>
-    <public type="attr" name="tabMode"/>
-    <public type="attr" name="tabPadding"/>
-    <public type="attr" name="tabPaddingBottom"/>
-    <public type="attr" name="tabPaddingEnd"/>
-    <public type="attr" name="tabPaddingStart"/>
-    <public type="attr" name="tabPaddingTop"/>
-    <public type="attr" name="tabSelectedTextColor"/>
-    <public type="attr" name="tabTextAppearance"/>
-    <public type="attr" name="tabTextColor"/>
-    <public type="attr" name="textColorError"/>
-    <public type="attr" name="title"/>
-    <public type="attr" name="titleEnabled"/>
-    <public type="attr" name="toolbarId"/>
-    <public type="attr" name="useCompatPadding"/>
-</resources>
diff --git a/design/res-public/values/public_strings.xml b/design/res-public/values/public_strings.xml
deleted file mode 100644
index 29f4155..0000000
--- a/design/res-public/values/public_strings.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Definitions of styles to be exposed as public -->
-<resources>
-    <public type="string" name="appbar_scrolling_view_behavior"/>
-    <public type="string" name="bottom_sheet_behavior"/>
-</resources>
diff --git a/design/res-public/values/public_styles.xml b/design/res-public/values/public_styles.xml
deleted file mode 100644
index 0dcde45..0000000
--- a/design/res-public/values/public_styles.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Definitions of styles to be exposed as public -->
-<resources>
-    <public type="style" name="TextAppearance.Design.CollapsingToolbar.Expanded"/>
-    <public type="style" name="TextAppearance.Design.Counter"/>
-    <public type="style" name="TextAppearance.Design.Counter.Overflow"/>
-    <public type="style" name="TextAppearance.Design.Error"/>
-    <public type="style" name="TextAppearance.Design.Hint"/>
-    <public type="style" name="TextAppearance.Design.Snackbar.Message"/>
-    <public type="style" name="TextAppearance.Design.Tab"/>
-    <public type="style" name="Theme.Design"/>
-    <public type="style" name="Theme.Design.BottomNavigationView"/>
-    <public type="style" name="Theme.Design.BottomSheetDialog"/>
-    <public type="style" name="Theme.Design.Light"/>
-    <public type="style" name="Theme.Design.Light.BottomSheetDialog"/>
-    <public type="style" name="Theme.Design.Light.NoActionBar"/>
-    <public type="style" name="Theme.Design.NoActionBar"/>
-    <public type="style" name="Widget.Design.AppBarLayout"/>
-    <public type="style" name="Widget.Design.BottomSheet.Modal"/>
-    <public type="style" name="Widget.Design.CollapsingToolbar"/>
-    <public type="style" name="Widget.Design.CoordinatorLayout"/>
-    <public type="style" name="Widget.Design.FloatingActionButton"/>
-    <public type="style" name="Widget.Design.NavigationView"/>
-    <public type="style" name="Widget.Design.Snackbar"/>
-    <public type="style" name="Widget.Design.TabLayout"/>
-    <public type="style" name="Widget.Design.TextInputLayout"/>
-</resources>
diff --git a/design/res/anim-v21/design_bottom_sheet_slide_in.xml b/design/res/anim-v21/design_bottom_sheet_slide_in.xml
deleted file mode 100644
index b5960a3..0000000
--- a/design/res/anim-v21/design_bottom_sheet_slide_in.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:duration="@integer/bottom_sheet_slide_duration"
-     android:interpolator="@android:interpolator/fast_out_linear_in">
-
-    <translate
-            android:fromYDelta="20%p"
-            android:toYDelta="0"/>
-
-    <alpha
-            android:fromAlpha="0.0"
-            android:toAlpha="1.0"/>
-
-</set>
diff --git a/design/res/anim-v21/design_bottom_sheet_slide_out.xml b/design/res/anim-v21/design_bottom_sheet_slide_out.xml
deleted file mode 100644
index d680abe..0000000
--- a/design/res/anim-v21/design_bottom_sheet_slide_out.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:duration="@integer/bottom_sheet_slide_duration"
-     android:interpolator="@android:interpolator/fast_out_slow_in">
-
-    <translate
-            android:fromYDelta="0"
-            android:toYDelta="20%p"/>
-
-    <alpha
-            android:fromAlpha="1.0"
-            android:toAlpha="0.0"/>
-
-</set>
diff --git a/design/res/anim/design_bottom_sheet_slide_in.xml b/design/res/anim/design_bottom_sheet_slide_in.xml
deleted file mode 100644
index 7cbae08..0000000
--- a/design/res/anim/design_bottom_sheet_slide_in.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:duration="@integer/bottom_sheet_slide_duration"
-     android:interpolator="@android:anim/accelerate_decelerate_interpolator">
-
-    <translate
-            android:fromYDelta="20%p"
-            android:toYDelta="0"/>
-
-    <alpha
-            android:fromAlpha="0.0"
-            android:toAlpha="1.0"/>
-
-</set>
diff --git a/design/res/anim/design_bottom_sheet_slide_out.xml b/design/res/anim/design_bottom_sheet_slide_out.xml
deleted file mode 100644
index 2e30963..0000000
--- a/design/res/anim/design_bottom_sheet_slide_out.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:duration="@integer/bottom_sheet_slide_duration"
-     android:interpolator="@android:anim/accelerate_interpolator">
-
-    <translate
-            android:fromYDelta="0"
-            android:toYDelta="20%p"/>
-
-    <alpha
-            android:fromAlpha="1.0"
-            android:toAlpha="0.0"/>
-
-</set>
diff --git a/design/res/anim/design_snackbar_in.xml b/design/res/anim/design_snackbar_in.xml
deleted file mode 100644
index a40524c..0000000
--- a/design/res/anim/design_snackbar_in.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<translate xmlns:android="http://schemas.android.com/apk/res/android"
-           android:fromYDelta="100%"
-           android:toYDelta="0"/>
diff --git a/design/res/anim/design_snackbar_out.xml b/design/res/anim/design_snackbar_out.xml
deleted file mode 100644
index eb55cc0..0000000
--- a/design/res/anim/design_snackbar_out.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<translate xmlns:android="http://schemas.android.com/apk/res/android"
-           android:fromYDelta="0"
-           android:toYDelta="100%"/>
\ No newline at end of file
diff --git a/design/res/animator-v21/design_appbar_state_list_animator.xml b/design/res/animator-v21/design_appbar_state_list_animator.xml
deleted file mode 100644
index a8a98e5..0000000
--- a/design/res/animator-v21/design_appbar_state_list_animator.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:app="http://schemas.android.com/apk/res-auto">
-
-    <item android:state_enabled="true" app:state_collapsed="false" app:state_collapsible="true">
-        <objectAnimator android:duration="@integer/app_bar_elevation_anim_duration"
-                        android:propertyName="elevation"
-                        android:valueTo="0dp"
-                        android:valueType="floatType"/>
-    </item>
-
-    <item android:state_enabled="true">
-        <objectAnimator android:duration="@integer/app_bar_elevation_anim_duration"
-                        android:propertyName="elevation"
-                        android:valueTo="@dimen/design_appbar_elevation"
-                        android:valueType="floatType"/>
-    </item>
-
-    <item>
-        <objectAnimator android:duration="0"
-                        android:propertyName="elevation"
-                        android:valueTo="0"
-                        android:valueType="floatType"/>
-    </item>
-
-</selector>
\ No newline at end of file
diff --git a/design/res/color-v23/design_tint_password_toggle.xml b/design/res/color-v23/design_tint_password_toggle.xml
deleted file mode 100644
index b728ccf..0000000
--- a/design/res/color-v23/design_tint_password_toggle.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?android:attr/colorForeground" android:alpha="0.54"/>
-</selector>
\ No newline at end of file
diff --git a/design/res/color/design_error.xml b/design/res/color/design_error.xml
deleted file mode 100644
index e28602f..0000000
--- a/design/res/color/design_error.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="?android:attr/textColorTertiary"/>
-    <item android:color="?attr/textColorError"/>
-</selector>
\ No newline at end of file
diff --git a/design/res/color/design_tint_password_toggle.xml b/design/res/color/design_tint_password_toggle.xml
deleted file mode 100644
index 13beffd..0000000
--- a/design/res/color/design_tint_password_toggle.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item android:color="?android:attr/colorForeground" app:alpha="0.54"/>
-</selector>
\ No newline at end of file
diff --git a/design/res/drawable-anydpi-v21/design_ic_visibility.xml b/design/res/drawable-anydpi-v21/design_ic_visibility.xml
deleted file mode 100644
index 123acd2..0000000
--- a/design/res/drawable-anydpi-v21/design_ic_visibility.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="@string/path_password_eye"/>
-
-</vector>
\ No newline at end of file
diff --git a/design/res/drawable-anydpi-v21/design_ic_visibility_off.xml b/design/res/drawable-anydpi-v21/design_ic_visibility_off.xml
deleted file mode 100644
index a8b47f0..0000000
--- a/design/res/drawable-anydpi-v21/design_ic_visibility_off.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportHeight="24"
-        android:viewportWidth="24">
-
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/>
-
-</vector>
\ No newline at end of file
diff --git a/design/res/drawable-hdpi/design_ic_visibility.png b/design/res/drawable-hdpi/design_ic_visibility.png
deleted file mode 100644
index 329e617..0000000
--- a/design/res/drawable-hdpi/design_ic_visibility.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-hdpi/design_ic_visibility_off.png b/design/res/drawable-hdpi/design_ic_visibility_off.png
deleted file mode 100644
index b21a686..0000000
--- a/design/res/drawable-hdpi/design_ic_visibility_off.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-mdpi/design_ic_visibility.png b/design/res/drawable-mdpi/design_ic_visibility.png
deleted file mode 100644
index 58597e9..0000000
--- a/design/res/drawable-mdpi/design_ic_visibility.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-mdpi/design_ic_visibility_off.png b/design/res/drawable-mdpi/design_ic_visibility_off.png
deleted file mode 100644
index 3efdf49..0000000
--- a/design/res/drawable-mdpi/design_ic_visibility_off.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-v21/avd_hide_password.xml b/design/res/drawable-v21/avd_hide_password.xml
deleted file mode 100644
index 8c6ed1c..0000000
--- a/design/res/drawable-v21/avd_hide_password.xml
+++ /dev/null
@@ -1,86 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt">
-
-    <aapt:attr name="android:drawable">
-
-        <vector
-            android:width="24dp"
-            android:height="24dp"
-            android:viewportHeight="24"
-            android:viewportWidth="24">
-
-            <path
-                android:name="strike_through"
-                android:pathData="@string/path_password_strike_through"
-                android:strokeColor="@android:color/white"
-                android:strokeLineCap="square"
-                android:strokeWidth="1.8"
-                android:trimPathEnd="0"/>
-
-            <group>
-
-                <clip-path
-                    android:name="eye_mask"
-                    android:pathData="@string/path_password_eye_mask_visible"/>
-
-                <path
-                    android:name="eye"
-                    android:fillColor="@android:color/white"
-                    android:pathData="@string/path_password_eye"/>
-
-            </group>
-
-        </vector>
-
-    </aapt:attr>
-
-    <target android:name="eye_mask">
-
-        <aapt:attr name="android:animation">
-
-            <objectAnimator
-                android:duration="@integer/hide_password_duration"
-                android:interpolator="@android:interpolator/fast_out_slow_in"
-                android:propertyName="pathData"
-                android:valueFrom="@string/path_password_eye_mask_visible"
-                android:valueTo="@string/path_password_eye_mask_strike_through"
-                android:valueType="pathType"/>
-
-        </aapt:attr>
-
-    </target>
-
-    <target android:name="strike_through">
-
-        <aapt:attr name="android:animation">
-
-            <objectAnimator
-                android:duration="@integer/hide_password_duration"
-                android:interpolator="@android:interpolator/fast_out_slow_in"
-                android:propertyName="trimPathEnd"
-                android:valueFrom="0"
-                android:valueTo="1"/>
-
-        </aapt:attr>
-
-    </target>
-
-</animated-vector>
diff --git a/design/res/drawable-v21/avd_show_password.xml b/design/res/drawable-v21/avd_show_password.xml
deleted file mode 100644
index 5b205d7..0000000
--- a/design/res/drawable-v21/avd_show_password.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<animated-vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:aapt="http://schemas.android.com/aapt">
-
-    <aapt:attr name="android:drawable">
-
-        <vector
-            android:width="24dp"
-            android:height="24dp"
-            android:viewportHeight="24"
-            android:viewportWidth="24">
-
-            <path
-                android:name="strike_through"
-                android:pathData="@string/path_password_strike_through"
-                android:strokeColor="@android:color/white"
-                android:strokeLineCap="square"
-                android:strokeWidth="1.8"/>
-
-            <group>
-
-                <clip-path
-                    android:name="eye_mask"
-                    android:pathData="@string/path_password_eye_mask_strike_through"/>
-
-                <path
-                    android:name="eye"
-                    android:fillColor="@android:color/white"
-                    android:pathData="@string/path_password_eye"/>
-
-            </group>
-
-        </vector>
-
-    </aapt:attr>
-
-    <target android:name="eye_mask">
-
-        <aapt:attr name="android:animation">
-
-            <objectAnimator
-                android:duration="@integer/show_password_duration"
-                android:interpolator="@android:interpolator/fast_out_linear_in"
-                android:propertyName="pathData"
-                android:valueFrom="@string/path_password_eye_mask_strike_through"
-                android:valueTo="@string/path_password_eye_mask_visible"
-                android:valueType="pathType"/>
-
-        </aapt:attr>
-
-    </target>
-
-    <target android:name="strike_through">
-
-        <aapt:attr name="android:animation">
-
-            <objectAnimator
-                android:duration="@integer/show_password_duration"
-                android:interpolator="@android:interpolator/fast_out_linear_in"
-                android:propertyName="trimPathEnd"
-                android:valueFrom="1"
-                android:valueTo="0"/>
-
-        </aapt:attr>
-
-    </target>
-
-</animated-vector>
diff --git a/design/res/drawable-v21/design_bottom_navigation_item_background.xml b/design/res/drawable-v21/design_bottom_navigation_item_background.xml
deleted file mode 100644
index f30f08b..0000000
--- a/design/res/drawable-v21/design_bottom_navigation_item_background.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
-        android:color="?attr/colorPrimary" />
\ No newline at end of file
diff --git a/design/res/drawable-v21/design_password_eye.xml b/design/res/drawable-v21/design_password_eye.xml
deleted file mode 100644
index 1bffaf4..0000000
--- a/design/res/drawable-v21/design_password_eye.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:id="@+id/visible"
-        android:drawable="@drawable/design_ic_visibility"
-        android:state_checked="true"/>
-
-    <item
-        android:id="@+id/masked"
-        android:drawable="@drawable/design_ic_visibility_off"/>
-
-    <transition
-        android:drawable="@drawable/avd_show_password"
-        android:fromId="@id/masked"
-        android:toId="@id/visible"/>
-
-    <transition
-        android:drawable="@drawable/avd_hide_password"
-        android:fromId="@id/visible"
-        android:toId="@id/masked"/>
-
-</animated-selector>
\ No newline at end of file
diff --git a/design/res/drawable-xhdpi/design_ic_visibility.png b/design/res/drawable-xhdpi/design_ic_visibility.png
deleted file mode 100644
index 1f7b4cc..0000000
--- a/design/res/drawable-xhdpi/design_ic_visibility.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-xhdpi/design_ic_visibility_off.png b/design/res/drawable-xhdpi/design_ic_visibility_off.png
deleted file mode 100644
index 46bf0c9..0000000
--- a/design/res/drawable-xhdpi/design_ic_visibility_off.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-xxhdpi/design_ic_visibility.png b/design/res/drawable-xxhdpi/design_ic_visibility.png
deleted file mode 100644
index c816ab4..0000000
--- a/design/res/drawable-xxhdpi/design_ic_visibility.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-xxhdpi/design_ic_visibility_off.png b/design/res/drawable-xxhdpi/design_ic_visibility_off.png
deleted file mode 100644
index 13eb65d..0000000
--- a/design/res/drawable-xxhdpi/design_ic_visibility_off.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-xxxhdpi/design_ic_visibility.png b/design/res/drawable-xxxhdpi/design_ic_visibility.png
deleted file mode 100644
index e005b97..0000000
--- a/design/res/drawable-xxxhdpi/design_ic_visibility.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable-xxxhdpi/design_ic_visibility_off.png b/design/res/drawable-xxxhdpi/design_ic_visibility_off.png
deleted file mode 100644
index ce3c9d8..0000000
--- a/design/res/drawable-xxxhdpi/design_ic_visibility_off.png
+++ /dev/null
Binary files differ
diff --git a/design/res/drawable/design_bottom_navigation_item_background.xml b/design/res/drawable/design_bottom_navigation_item_background.xml
deleted file mode 100644
index 7674f42..0000000
--- a/design/res/drawable/design_bottom_navigation_item_background.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true">
-        <shape android:shape="rectangle">
-            <solid android:color="#ff0000"/>
-        </shape>
-    </item>
-    <item>
-        <shape android:shape="rectangle">
-            <solid android:color="#ffffff"/>
-        </shape>
-    </item>
-</selector>
\ No newline at end of file
diff --git a/design/res/drawable/design_fab_background.xml b/design/res/drawable/design_fab_background.xml
deleted file mode 100644
index 43afd5c..0000000
--- a/design/res/drawable/design_fab_background.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-        android:shape="oval">
-    <solid android:color="@android:color/white" />
-</shape>
\ No newline at end of file
diff --git a/design/res/drawable/design_password_eye.xml b/design/res/drawable/design_password_eye.xml
deleted file mode 100644
index b5185f1..0000000
--- a/design/res/drawable/design_password_eye.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item
-        android:drawable="@drawable/design_ic_visibility"
-        android:state_checked="true"/>
-
-    <item
-        android:drawable="@drawable/design_ic_visibility_off"/>
-
-</selector>
\ No newline at end of file
diff --git a/design/res/drawable/design_snackbar_background.xml b/design/res/drawable/design_snackbar_background.xml
deleted file mode 100644
index e82441c..0000000
--- a/design/res/drawable/design_snackbar_background.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <corners android:radius="@dimen/design_snackbar_background_corner_radius"/>
-    <solid android:color="@color/design_snackbar_background_color"/>
-</shape>
\ No newline at end of file
diff --git a/design/res/drawable/navigation_empty_icon.xml b/design/res/drawable/navigation_empty_icon.xml
deleted file mode 100644
index 799bd94..0000000
--- a/design/res/drawable/navigation_empty_icon.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <solid android:color="@android:color/transparent"/>
-    <size
-        android:width="@dimen/design_navigation_icon_size"
-        android:height="@dimen/design_navigation_icon_size" />
-</shape>
diff --git a/design/res/layout-sw600dp/design_layout_snackbar.xml b/design/res/layout-sw600dp/design_layout_snackbar.xml
deleted file mode 100644
index 28835e5..0000000
--- a/design/res/layout-sw600dp/design_layout_snackbar.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<view xmlns:android="http://schemas.android.com/apk/res/android"
-      class="android.support.design.widget.Snackbar$SnackbarLayout"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_gravity="bottom|center_horizontal"
-      android:theme="@style/ThemeOverlay.AppCompat.Dark"
-      style="@style/Widget.Design.Snackbar" />
\ No newline at end of file
diff --git a/design/res/layout/design_bottom_navigation_item.xml b/design/res/layout/design_bottom_navigation_item.xml
deleted file mode 100644
index f6212cf..0000000
--- a/design/res/layout/design_bottom_navigation_item.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <ImageView
-        android:id="@+id/icon"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginTop="@dimen/design_bottom_navigation_margin"
-        android:layout_marginBottom="@dimen/design_bottom_navigation_margin"
-        android:duplicateParentState="true" />
-    <android.support.design.internal.BaselineLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="bottom|center_horizontal"
-        android:clipToPadding="false"
-        android:paddingBottom="10dp"
-        android:duplicateParentState="true">
-        <TextView
-            android:id="@+id/smallLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textSize="@dimen/design_bottom_navigation_text_size"
-            android:singleLine="true"
-            android:duplicateParentState="true" />
-        <TextView
-            android:id="@+id/largeLabel"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:visibility="invisible"
-            android:textSize="@dimen/design_bottom_navigation_active_text_size"
-            android:singleLine="true"
-            android:duplicateParentState="true" />
-    </android.support.design.internal.BaselineLayout>
-</merge>
\ No newline at end of file
diff --git a/design/res/layout/design_bottom_sheet_dialog.xml b/design/res/layout/design_bottom_sheet_dialog.xml
deleted file mode 100644
index 28e023c..0000000
--- a/design/res/layout/design_bottom_sheet_dialog.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:id="@+id/container"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.CoordinatorLayout
-        android:id="@+id/coordinator"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:fitsSystemWindows="true">
-
-        <View
-            android:id="@+id/touch_outside"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:importantForAccessibility="no"
-            android:soundEffectsEnabled="false"
-            tools:ignore="UnusedAttribute"/>
-
-        <FrameLayout
-            android:id="@+id/design_bottom_sheet"
-            style="?attr/bottomSheetStyle"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_horizontal|top"
-            app:layout_behavior="@string/bottom_sheet_behavior"/>
-
-    </android.support.design.widget.CoordinatorLayout>
-
-</FrameLayout>
diff --git a/design/res/layout/design_layout_snackbar.xml b/design/res/layout/design_layout_snackbar.xml
deleted file mode 100644
index 8f3f0d6..0000000
--- a/design/res/layout/design_layout_snackbar.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<view xmlns:android="http://schemas.android.com/apk/res/android"
-      class="android.support.design.widget.Snackbar$SnackbarLayout"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:layout_gravity="bottom"
-      android:theme="@style/ThemeOverlay.AppCompat.Dark"
-      style="@style/Widget.Design.Snackbar" />
\ No newline at end of file
diff --git a/design/res/layout/design_layout_snackbar_include.xml b/design/res/layout/design_layout_snackbar_include.xml
deleted file mode 100644
index fe11d8e..0000000
--- a/design/res/layout/design_layout_snackbar_include.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<view
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    class="android.support.design.internal.SnackbarContentLayout"
-    android:theme="@style/ThemeOverlay.AppCompat.Dark"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="bottom">
-
-    <TextView
-        android:id="@+id/snackbar_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:paddingTop="@dimen/design_snackbar_padding_vertical"
-        android:paddingBottom="@dimen/design_snackbar_padding_vertical"
-        android:paddingLeft="@dimen/design_snackbar_padding_horizontal"
-        android:paddingRight="@dimen/design_snackbar_padding_horizontal"
-        android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
-        android:maxLines="@integer/design_snackbar_text_max_lines"
-        android:layout_gravity="center_vertical|left|start"
-        android:ellipsize="end"
-        android:textAlignment="viewStart"/>
-
-    <Button
-        android:id="@+id/snackbar_action"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginLeft="@dimen/design_snackbar_extra_spacing_horizontal"
-        android:layout_marginStart="@dimen/design_snackbar_extra_spacing_horizontal"
-        android:layout_gravity="center_vertical|right|end"
-        android:minWidth="48dp"
-        android:visibility="gone"
-        android:textColor="?attr/colorAccent"
-        style="?attr/borderlessButtonStyle"/>
-
-</view>
\ No newline at end of file
diff --git a/design/res/layout/design_layout_tab_icon.xml b/design/res/layout/design_layout_tab_icon.xml
deleted file mode 100644
index 5dcfa11..0000000
--- a/design/res/layout/design_layout_tab_icon.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
-           android:layout_width="24dp"
-           android:layout_height="24dp"
-           android:scaleType="centerInside"/>
\ No newline at end of file
diff --git a/design/res/layout/design_layout_tab_text.xml b/design/res/layout/design_layout_tab_text.xml
deleted file mode 100644
index a83bb3d..0000000
--- a/design/res/layout/design_layout_tab_text.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:ellipsize="end"
-          android:gravity="center"
-          android:maxLines="2"/>
\ No newline at end of file
diff --git a/design/res/layout/design_menu_item_action_area.xml b/design/res/layout/design_menu_item_action_area.xml
deleted file mode 100644
index ba8141d..0000000
--- a/design/res/layout/design_menu_item_action_area.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="wrap_content"
-             android:layout_height="match_parent"/>
diff --git a/design/res/layout/design_navigation_item.xml b/design/res/layout/design_navigation_item.xml
deleted file mode 100644
index ccd42de..0000000
--- a/design/res/layout/design_navigation_item.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<android.support.design.internal.NavigationMenuItemView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="?attr/listPreferredItemHeightSmall"
-        android:paddingLeft="?attr/listPreferredItemPaddingLeft"
-        android:paddingRight="?attr/listPreferredItemPaddingRight"
-        android:foreground="?attr/selectableItemBackground"
-        android:focusable="true"/>
diff --git a/design/res/layout/design_navigation_item_header.xml b/design/res/layout/design_navigation_item_header.xml
deleted file mode 100644
index 8d03f69..0000000
--- a/design/res/layout/design_navigation_item_header.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-      android:id="@+id/navigation_header_container"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:orientation="vertical"
-      android:paddingBottom="@dimen/design_navigation_separator_vertical_padding" />
diff --git a/design/res/layout/design_navigation_item_separator.xml b/design/res/layout/design_navigation_item_separator.xml
deleted file mode 100644
index 938a3fb..0000000
--- a/design/res/layout/design_navigation_item_separator.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="match_parent"
-             android:layout_height="wrap_content">
-
-    <View android:layout_width="match_parent"
-          android:layout_height="1dp"
-          android:background="?android:attr/listDivider"/>
-
-</FrameLayout>
diff --git a/design/res/layout/design_navigation_item_subheader.xml b/design/res/layout/design_navigation_item_subheader.xml
deleted file mode 100644
index 707ec6a..0000000
--- a/design/res/layout/design_navigation_item_subheader.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
-          android:layout_width="match_parent"
-          android:layout_height="?attr/listPreferredItemHeightSmall"
-          android:gravity="center_vertical|start"
-          android:maxLines="1"
-          android:paddingLeft="?attr/listPreferredItemPaddingLeft"
-          android:paddingRight="?attr/listPreferredItemPaddingRight"
-          android:textAppearance="@style/TextAppearance.AppCompat.Body2"
-          android:textColor="?android:textColorSecondary"/>
diff --git a/design/res/layout/design_navigation_menu.xml b/design/res/layout/design_navigation_menu.xml
deleted file mode 100644
index b6a0ad5..0000000
--- a/design/res/layout/design_navigation_menu.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<android.support.design.internal.NavigationMenuView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:id="@+id/design_navigation_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:paddingBottom="@dimen/design_navigation_padding_bottom"
-        android:clipToPadding="false"
-        android:scrollbars="vertical"/>
diff --git a/design/res/layout/design_navigation_menu_item.xml b/design/res/layout/design_navigation_menu_item.xml
deleted file mode 100644
index 91104bb..0000000
--- a/design/res/layout/design_navigation_menu_item.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <CheckedTextView
-            android:id="@+id/design_menu_item_text"
-            android:layout_width="0dp"
-            android:layout_height="match_parent"
-            android:layout_weight="1"
-            android:drawablePadding="@dimen/design_navigation_icon_padding"
-            android:gravity="center_vertical|start"
-            android:maxLines="1"
-            android:textAppearance="@style/TextAppearance.AppCompat.Body2"/>
-
-    <ViewStub
-            android:id="@+id/design_menu_item_action_area_stub"
-            android:inflatedId="@+id/design_menu_item_action_area"
-            android:layout="@layout/design_menu_item_action_area"
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"/>
-
-</merge>
diff --git a/design/res/layout/design_text_input_password_icon.xml b/design/res/layout/design_text_input_password_icon.xml
deleted file mode 100644
index ca1cd09..0000000
--- a/design/res/layout/design_text_input_password_icon.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<android.support.design.widget.CheckableImageButton
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/text_input_password_toggle"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center_vertical|end|right"
-    android:background="?attr/selectableItemBackgroundBorderless"
-    android:minHeight="48dp"
-    android:minWidth="48dp"/>
\ No newline at end of file
diff --git a/design/res/values-land/styles.xml b/design/res/values-land/styles.xml
deleted file mode 100644
index 622a5e3..0000000
--- a/design/res/values-land/styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-
-    <style name="Widget.Design.TabLayout" parent="Base.Widget.Design.TabLayout">
-        <item name="tabGravity">center</item>
-        <item name="tabMode">fixed</item>
-    </style>
-
-</resources>
-
diff --git a/design/res/values-sw600dp/config.xml b/design/res/values-sw600dp/config.xml
deleted file mode 100644
index 58b6207..0000000
--- a/design/res/values-sw600dp/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<resources>
-
-    <integer name="design_snackbar_text_max_lines">1</integer>
-
-</resources>
\ No newline at end of file
diff --git a/design/res/values-sw600dp/dimens.xml b/design/res/values-sw600dp/dimens.xml
deleted file mode 100644
index 9d61f00..0000000
--- a/design/res/values-sw600dp/dimens.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<resources>
-
-    <dimen name="design_tab_scrollable_min_width">160dp</dimen>
-
-    <dimen name="design_snackbar_min_width">320dp</dimen>
-    <dimen name="design_snackbar_max_width">576dp</dimen>
-    <dimen name="design_snackbar_padding_vertical_2lines">@dimen/design_snackbar_padding_vertical</dimen>
-    <dimen name="design_snackbar_extra_spacing_horizontal">24dp</dimen>
-    <dimen name="design_snackbar_background_corner_radius">2dp</dimen>
-    <dimen name="design_snackbar_action_inline_max_width">0dp</dimen>
-
-    <!-- 5 * standard increment (64dp on tablets) -->
-    <dimen name="design_navigation_max_width">320dp</dimen>
-
-</resources>
\ No newline at end of file
diff --git a/design/res/values-sw600dp/styles.xml b/design/res/values-sw600dp/styles.xml
deleted file mode 100644
index 622a5e3..0000000
--- a/design/res/values-sw600dp/styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-
-    <style name="Widget.Design.TabLayout" parent="Base.Widget.Design.TabLayout">
-        <item name="tabGravity">center</item>
-        <item name="tabMode">fixed</item>
-    </style>
-
-</resources>
-
diff --git a/design/res/values-v21/styles.xml b/design/res/values-v21/styles.xml
deleted file mode 100644
index c692579..0000000
--- a/design/res/values-v21/styles.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-
-    <style name="Base.Widget.Design.AppBarLayout" parent="Base.V21.Widget.Design.AppBarLayout" />
-
-    <style name="Base.V21.Widget.Design.AppBarLayout" parent="Base.V14.Widget.Design.AppBarLayout">
-        <item name="android:stateListAnimator">@animator/design_appbar_state_list_animator</item>
-    </style>
-
-</resources>
-
diff --git a/design/res/values-v26/styles.xml b/design/res/values-v26/styles.xml
deleted file mode 100644
index f20a058..0000000
--- a/design/res/values-v26/styles.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<resources>
-
-    <style name="Base.Widget.Design.AppBarLayout" parent="Base.V26.Widget.Design.AppBarLayout" />
-
-    <style name="Base.V26.Widget.Design.AppBarLayout" parent="Base.V21.Widget.Design.AppBarLayout">
-        <item name="android:keyboardNavigationCluster">true</item>
-        <item name="android:touchscreenBlocksFocus">true</item>
-    </style>
-
-</resources>
\ No newline at end of file
diff --git a/design/res/values/attrs.xml b/design/res/values/attrs.xml
deleted file mode 100644
index 8c3536f..0000000
--- a/design/res/values/attrs.xml
+++ /dev/null
@@ -1,379 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-
-    <declare-styleable name="FloatingActionButton">
-        <!-- Background for the FloatingActionButton -->
-        <attr name="backgroundTint"/>
-        <attr name="backgroundTintMode"/>
-
-        <!-- Ripple color for the FAB. -->
-        <attr name="rippleColor" format="color"/>
-        <!-- Size for the FAB. If fabCustomSize is set, this will be ignored. -->
-        <attr name="fabSize">
-            <!-- A size which will change based on the window size. -->
-            <enum name="auto" value="-1"/>
-            <!-- The normal sized button. -->
-            <enum name="normal" value="0"/>
-            <!-- The mini sized button. -->
-            <enum name="mini" value="1"/>
-        </attr>
-        <!-- Custom size for the FAB. If this is set, fabSize will be ignored. -->
-        <attr name="fabCustomSize" format="dimension"/>
-        <!-- Elevation value for the FAB -->
-        <attr name="elevation"/>
-        <!-- TranslationZ value for the FAB when pressed-->
-        <attr name="pressedTranslationZ" format="dimension"/>
-        <!-- The width of the border around the FAB. -->
-        <attr name="borderWidth" format="dimension"/>
-        <!-- Enable compat padding. -->
-        <attr name="useCompatPadding" format="boolean"/>
-    </declare-styleable>
-
-    <declare-styleable name="FloatingActionButton_Behavior_Layout">
-        <!-- Whether the FAB should automatically hide when there is no space for it. -->
-        <attr name="behavior_autoHide" format="boolean"/>
-    </declare-styleable>
-
-    <declare-styleable name="ScrimInsetsFrameLayout">
-        <attr name="insetForeground" format="color|reference"/>
-    </declare-styleable>
-
-    <declare-styleable name="NavigationView">
-        <attr name="android:background"/>
-        <attr name="android:fitsSystemWindows"/>
-        <attr name="android:maxWidth"/>
-        <attr name="elevation"/>
-        <!-- The menu resource to inflate and populate items from. -->
-        <attr name="menu" format="reference"/>
-        <attr name="itemIconTint" format="color"/>
-        <attr name="itemTextColor" format="color"/>
-        <attr name="itemBackground" format="reference"/>
-        <attr name="itemTextAppearance" format="reference"/>
-        <!-- Layout resource to inflate as the header -->
-        <attr name="headerLayout" format="reference"/>
-    </declare-styleable>
-
-    <declare-styleable name="ForegroundLinearLayout">
-        <attr name="android:foreground" />
-        <attr name="android:foregroundGravity" />
-        <attr name="foregroundInsidePadding" format="boolean" />
-    </declare-styleable>
-
-    <declare-styleable name="TabLayout">
-        <!-- Color of the indicator used to show the currently selected tab. -->
-        <attr name="tabIndicatorColor" format="color"/>
-        <!-- Height of the indicator used to show the currently selected tab. -->
-        <attr name="tabIndicatorHeight" format="dimension"/>
-        <!-- Position in the Y axis from the starting edge that tabs should be positioned from. -->
-        <attr name="tabContentStart" format="dimension"/>
-        <!-- Reference to a background to be applied to tabs. -->
-        <attr name="tabBackground" format="reference"/>
-        <!-- The behavior mode for the Tabs in this layout -->
-        <attr name="tabMode">
-            <enum name="scrollable" value="0"/>
-            <enum name="fixed" value="1"/>
-        </attr>
-        <!-- Gravity constant for tabs. -->
-        <attr name="tabGravity">
-            <enum name="fill" value="0"/>
-            <enum name="center" value="1"/>
-        </attr>
-        <!-- The minimum width for tabs. -->
-        <attr name="tabMinWidth" format="dimension"/>
-        <!-- The maximum width for tabs. -->
-        <attr name="tabMaxWidth" format="dimension"/>
-        <!-- A reference to a TextAppearance style to be applied to tabs. -->
-        <attr name="tabTextAppearance" format="reference"/>
-        <!-- The default text color to be applied to tabs. -->
-        <attr name="tabTextColor" format="color"/>
-        <!-- The text color to be applied to the currently selected tab. -->
-        <attr name="tabSelectedTextColor" format="color"/>
-        <!-- The preferred padding along the start edge of tabs. -->
-        <attr name="tabPaddingStart" format="dimension"/>
-        <!-- The preferred padding along the top edge of tabs. -->
-        <attr name="tabPaddingTop" format="dimension"/>
-        <!-- The preferred padding along the end edge of tabs. -->
-        <attr name="tabPaddingEnd" format="dimension"/>
-        <!-- The preferred padding along the bottom edge of tabs. -->
-        <attr name="tabPaddingBottom" format="dimension"/>
-        <!-- The preferred padding along all edges of tabs. -->
-        <attr name="tabPadding" format="dimension"/>
-    </declare-styleable>
-
-    <declare-styleable name="TabItem">
-        <!-- Text to display in the tab. -->
-        <attr name="android:text" />
-        <!-- Icon to display in the tab. -->
-        <attr name="android:icon" />
-        <!-- A reference to a layout resource to be displayed in the tab. -->
-        <attr name="android:layout" />
-    </declare-styleable>
-
-    <declare-styleable name="TextInputLayout">
-        <attr name="hintTextAppearance" format="reference"/>
-        <!-- The hint to display in the floating label. -->
-        <attr name="android:hint"/>
-        <!-- Whether the layout's floating label functionality is enabled. -->
-        <attr name="hintEnabled" format="boolean"/>
-        <!-- Whether the layout is laid out as if an error will be displayed. -->
-        <attr name="errorEnabled" format="boolean"/>
-        <!-- TextAppearance of any error message displayed. -->
-        <attr name="errorTextAppearance" format="reference"/>
-        <!-- Whether the layout is laid out as if the character counter will be displayed. -->
-        <attr name="counterEnabled" format="boolean"/>
-        <!-- The max length to display in the character counter. -->
-        <attr name="counterMaxLength" format="integer" />
-        <!-- TextAppearance of the character counter. -->
-        <attr name="counterTextAppearance" format="reference"/>
-        <!-- TextAppearance of the character counter when the text is longer than the max. -->
-        <attr name="counterOverflowTextAppearance" format="reference"/>
-        <attr name="android:textColorHint"/>
-        <!-- Whether to animate hint state changes. -->
-        <attr name="hintAnimationEnabled" format="boolean"/>
-        <!-- Whether the view will display a toggle when the EditText has a password. -->
-        <attr name="passwordToggleEnabled" format="boolean"/>
-        <!-- Drawable to use as the password input visibility toggle icon. -->
-        <attr name="passwordToggleDrawable" format="reference"/>
-        <!-- Text to set as the content description for the password input visibility toggle. -->
-        <attr name="passwordToggleContentDescription" format="string"/>
-        <!-- Icon to use for the password input visibility toggle -->
-        <attr name="passwordToggleTint" format="color"/>
-        <!-- Blending mode used to apply the background tint. -->
-        <attr name="passwordToggleTintMode">
-            <!-- The tint is drawn on top of the drawable.
-                 [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
-            <enum name="src_over" value="3" />
-            <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
-                 color channels are thrown out. [Sa * Da, Sc * Da] -->
-            <enum name="src_in" value="5" />
-            <!-- The tint is drawn above the drawable, but with the drawable’s alpha
-                 channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
-            <enum name="src_atop" value="9" />
-            <!-- Multiplies the color and alpha channels of the drawable with those of
-                 the tint. [Sa * Da, Sc * Dc] -->
-            <enum name="multiply" value="14" />
-            <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
-            <enum name="screen" value="15" />
-        </attr>
-    </declare-styleable>
-
-    <declare-styleable name="SnackbarLayout">
-        <attr name="android:maxWidth"/>
-        <attr name="elevation"/>
-        <attr name="maxActionInlineWidth" format="dimension"/>
-    </declare-styleable>
-
-    <declare-styleable name="AppBarLayout">
-        <!-- Deprecated. Elevation is now controlled via a state list animator. -->
-        <attr name="elevation" />
-        <attr name="android:background" />
-        <!-- The initial expanded state for the AppBarLayout. This only takes effect when this
-             view is a direct child of a CoordinatorLayout. -->
-        <attr name="expanded" format="boolean" />
-        <attr name="android:keyboardNavigationCluster" />
-        <attr name="android:touchscreenBlocksFocus" />
-    </declare-styleable>
-
-    <declare-styleable name="AppBarLayoutStates">
-        <!-- State value for {@link android.support.design.widget.AppBarLayout} set when the view
-             has been collapsed. -->
-        <attr name="state_collapsed" format="boolean" />
-        <!-- State value for {@link android.support.design.widget.AppBarLayout} set when the view
-             has children which are capable of being collapsed. -->
-        <attr name="state_collapsible" format="boolean" />
-    </declare-styleable>
-
-    <declare-styleable name="AppBarLayout_Layout">
-        <attr name="layout_scrollFlags">
-            <!-- The view will be scroll in direct relation to scroll events. This flag needs to be
-                 set for any of the other flags to take effect. If any sibling views
-                 before this one do not have this flag, then this value has no effect. -->
-            <flag name="scroll" value="0x1"/>
-
-            <!-- When exiting (scrolling off screen) the view will be scrolled until it is
-                 'collapsed'. The collapsed height is defined by the view's minimum height. -->
-            <flag name="exitUntilCollapsed" value="0x2"/>
-
-            <!-- When entering (scrolling on screen) the view will scroll on any downwards
-                 scroll event, regardless of whether the scrolling view is also scrolling. This
-                 is commonly referred to as the 'quick return' pattern. -->
-            <flag name="enterAlways" value="0x4"/>
-
-            <!-- An additional flag for 'enterAlways' which modifies the returning view to
-                 only initially scroll back to it's collapsed height. Once the scrolling view has
-                 reached the end of it's scroll range, the remainder of this view will be scrolled
-                 into view. -->
-            <flag name="enterAlwaysCollapsed" value="0x8"/>
-
-            <!-- Upon a scroll ending, if the view is only partially visible then it will be
-                 snapped and scrolled to it's closest edge. -->
-            <flag name="snap" value="0x10"/>
-        </attr>
-
-        <!-- An interpolator to use when scrolling this View. Only takes effect when View
-             is scrollable. -->
-        <attr name="layout_scrollInterpolator" format="reference" />
-    </declare-styleable>
-
-    <declare-styleable name="ScrollingViewBehavior_Layout">
-        <!-- The amount that the scrolling view should overlap the bottom of any AppBarLayout -->
-        <attr name="behavior_overlapTop" format="dimension" />
-    </declare-styleable>
-
-    <declare-styleable name="CollapsingToolbarLayout">
-        <!--  Specifies extra space on the start, top, end and bottom
-              sides of the the expanded title text. Margin values should be positive. -->
-        <attr name="expandedTitleMargin" format="dimension"/>
-        <!--  Specifies extra space on the start side of the the expanded title text.
-              Margin values should be positive. -->
-        <attr name="expandedTitleMarginStart" format="dimension"/>
-        <!--  Specifies extra space on the top side of the the expanded title text.
-              Margin values should be positive. -->
-        <attr name="expandedTitleMarginTop" format="dimension"/>
-        <!--  Specifies extra space on the end side of the the expanded title text.
-              Margin values should be positive. -->
-        <attr name="expandedTitleMarginEnd" format="dimension"/>
-        <!--  Specifies extra space on the bottom side of the the expanded title text.
-              Margin values should be positive. -->
-        <attr name="expandedTitleMarginBottom" format="dimension"/>
-        <!-- The text appearance of the CollapsingToolbarLayout's title when it is fully
-             'expanded' -->
-        <attr name="expandedTitleTextAppearance" format="reference"/>
-        <!-- The text appearance of the CollapsingToolbarLayouts title when it is fully
-             'collapsed' -->
-        <attr name="collapsedTitleTextAppearance" format="reference"/>
-        <!-- The drawable to use as a scrim on top of the CollapsingToolbarLayouts content when
-             it has been scrolled sufficiently off screen. -->
-        <attr name="contentScrim" format="color"/>
-        <!-- The drawable to use as a scrim for the status bar content when the
-             CollapsingToolbarLayout has been scrolled sufficiently off screen. Only works on
-             Lollipop with the correct setup. -->
-        <attr name="statusBarScrim" format="color" />
-        <!-- The id of the primary Toolbar child that you wish to use for the purpose of collapsing.
-             This Toolbar descendant view does not need to be a direct child of the layout.
-             If you do not set this, the first direct Toolbar child found will be used. -->
-        <attr name="toolbarId" format="reference"/>
-        <!-- Specifies the amount of visible height in pixels used to define when to trigger a
-             scrim visibility change. -->
-        <attr name="scrimVisibleHeightTrigger" format="dimension"/>
-        <!-- Specifies the duration used for scrim visibility animations. -->
-        <attr name="scrimAnimationDuration" format="integer"/>
-
-        <!-- Specifies how the title should be positioned when collapsed. -->
-        <attr name="collapsedTitleGravity">
-            <!-- Push title to the top of its container, not changing its size. -->
-            <flag name="top" value="0x30"/>
-            <!-- Push title to the bottom of its container, not changing its size. -->
-            <flag name="bottom" value="0x50"/>
-            <!-- Push title to the left of its container, not changing its size. -->
-            <flag name="left" value="0x03"/>
-            <!-- Push title to the right of its container, not changing its size. -->
-            <flag name="right" value="0x05"/>
-            <!-- Place title in the vertical center of its container, not changing its size. -->
-            <flag name="center_vertical" value="0x10"/>
-            <!-- Grow the vertical size of the title if needed so it completely fills its container. -->
-            <flag name="fill_vertical" value="0x70"/>
-            <!-- Place title in the horizontal center of its container, not changing its size. -->
-            <flag name="center_horizontal" value="0x01"/>
-            <!-- Place the title in the center of its container in both the vertical and horizontal axis, not changing its size. -->
-            <flag name="center" value="0x11"/>
-            <!-- Push title to the beginning of its container, not changing its size. -->
-            <flag name="start" value="0x00800003"/>
-            <!-- Push title to the end of its container, not changing its size. -->
-            <flag name="end" value="0x00800005"/>
-        </attr>
-
-        <!-- Specifies how the title should be positioned when expanded. -->
-        <attr name="expandedTitleGravity">
-            <!-- Push title to the top of its container, not changing its size. -->
-            <flag name="top" value="0x30"/>
-            <!-- Push title to the bottom of its container, not changing its size. -->
-            <flag name="bottom" value="0x50"/>
-            <!-- Push title to the left of its container, not changing its size. -->
-            <flag name="left" value="0x03"/>
-            <!-- Push title to the right of its container, not changing its size. -->
-            <flag name="right" value="0x05"/>
-            <!-- Place title in the vertical center of its container, not changing its size. -->
-            <flag name="center_vertical" value="0x10"/>
-            <!-- Grow the vertical size of the title if needed so it completely fills its container. -->
-            <flag name="fill_vertical" value="0x70"/>
-            <!-- Place title in the horizontal center of its container, not changing its size. -->
-            <flag name="center_horizontal" value="0x01"/>
-            <!-- Place the title in the center of its container in both the vertical and horizontal axis, not changing its size. -->
-            <flag name="center" value="0x11"/>
-            <!-- Push title to the beginning of its container, not changing its size. -->
-            <flag name="start" value="0x00800003"/>
-            <!-- Push title to the end of its container, not changing its size. -->
-            <flag name="end" value="0x00800005"/>
-        </attr>
-
-        <!-- Whether the CollapsingToolbarLayout should draw its own shrinking/growing title. -->
-        <attr name="titleEnabled" format="boolean"/>
-        <!-- The title to show when titleEnabled is set to true. -->
-        <attr name="title"/>
-    </declare-styleable>
-
-    <declare-styleable name="CollapsingToolbarLayout_Layout">
-        <attr name="layout_collapseMode">
-            <!-- The view will act as normal with no collapsing behavior. -->
-            <enum name="none" value="0"/>
-            <!-- The view will pin in place. -->
-            <enum name="pin" value="1"/>
-            <!-- The view will scroll in a parallax fashion. See the
-                 layout_collapseParallaxMultiplier attribute to change the multiplier. -->
-            <enum name="parallax" value="2"/>
-        </attr>
-
-        <!-- The multiplier used when layout_collapseMode is set to 'parallax'. The value should
-             be between 0.0 and 1.0. -->
-        <attr name="layout_collapseParallaxMultiplier" format="float"/>
-    </declare-styleable>
-
-    <declare-styleable name="BottomSheetBehavior_Layout">
-        <!-- The height of the bottom sheet when it is collapsed. -->
-        <attr name="behavior_peekHeight" format="dimension">
-            <!-- Peek at the 16:9 ratio keyline of its parent -->
-            <enum name="auto" value="-1"/>
-        </attr>
-        <!-- Whether this bottom sheet can be hidden by dragging it further downwards -->
-        <attr name="behavior_hideable" format="boolean"/>
-        <!-- Skip the collapsed state once expanded; no effect unless it is hideable -->
-        <attr name="behavior_skipCollapsed" format="boolean"/>
-    </declare-styleable>
-
-    <declare-styleable name="DesignTheme">
-        <!-- Theme to use for modal bottom sheet dialogs spawned from this theme. -->
-        <attr name="bottomSheetDialogTheme" format="reference" />
-        <!-- Style to use for modal bottom sheets in this theme. -->
-        <attr name="bottomSheetStyle" format="reference" />
-
-        <!-- Text color used to indicate an error has occurred. -->
-        <!-- {@deprecated Use colorError} -->
-        <attr name="textColorError" format="reference|color" />
-    </declare-styleable>
-
-    <declare-styleable name="BottomNavigationView">
-        <!-- The menu resource to inflate and populate items from. -->
-        <attr name="menu"/>
-        <attr name="itemIconTint"/>
-        <attr name="itemTextColor"/>
-        <attr name="itemBackground"/>
-        <attr name="elevation"/>
-    </declare-styleable>
-
-</resources>
diff --git a/design/res/values/colors.xml b/design/res/values/colors.xml
deleted file mode 100644
index 88fe630..0000000
--- a/design/res/values/colors.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<resources>
-
-    <!-- Color for the top outer pixels in the stroke: 18% white (these are multiplied) -->
-    <color name="design_fab_stroke_top_outer_color">#2EFFFFFF</color>
-    <!-- Color for the top inner pixels in the stroke: 10% white (these are multiplied) -->
-    <color name="design_fab_stroke_top_inner_color">#1AFFFFFF</color>
-    <!-- Color for the bottom outer pixels in the stroke: 6% black (these are multiplied) -->
-    <color name="design_fab_stroke_end_outer_color">#0F000000</color>
-    <!-- Color for the bottom inner pixels in the stroke: 4% black (these are multiplied) -->
-    <color name="design_fab_stroke_end_inner_color">#0A000000</color>
-
-    <!-- Shadow color for the first pixels of a shadow -->
-    <color name="design_fab_shadow_start_color">#44000000</color>
-    <!-- Shadow color for the middle pixels of a shadow -->
-    <color name="design_fab_shadow_mid_color">#14000000</color>
-    <!-- Shadow color for the furthest pixels of a shadow -->
-    <color name="design_fab_shadow_end_color">@android:color/transparent</color>
-
-    <color name="design_snackbar_background_color">#323232</color>
-
-    <color name="design_bottom_navigation_shadow_color">#14000000</color>
-
-</resources>
\ No newline at end of file
diff --git a/design/res/values/config.xml b/design/res/values/config.xml
deleted file mode 100644
index 67635a8..0000000
--- a/design/res/values/config.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<resources>
-
-    <integer name="design_snackbar_text_max_lines">2</integer>
-
-</resources>
\ No newline at end of file
diff --git a/design/res/values/dimens.xml b/design/res/values/dimens.xml
deleted file mode 100644
index de715ce..0000000
--- a/design/res/values/dimens.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-
-    <dimen name="design_fab_elevation">6dp</dimen>
-    <dimen name="design_fab_translation_z_pressed">6dp</dimen>
-    <dimen name="design_fab_image_size">24dp</dimen>
-    <dimen name="design_fab_size_normal">56dp</dimen>
-    <dimen name="design_fab_size_mini">40dp</dimen>
-    <dimen name="design_fab_border_width">0.5dp</dimen>
-
-    <!-- 5 * standard increment (56dp) -->
-    <dimen name="design_navigation_max_width">280dp</dimen>
-    <dimen name="design_navigation_elevation">16dp</dimen>
-    <dimen name="design_navigation_icon_padding">32dp</dimen>
-    <dimen name="design_navigation_icon_size">24dp</dimen>
-    <dimen name="design_navigation_separator_vertical_padding">8dp</dimen>
-    <dimen name="design_navigation_padding_bottom">8dp</dimen>
-
-    <dimen name="design_tab_scrollable_min_width">72dp</dimen>
-    <dimen name="design_tab_max_width">264dp</dimen>
-    <dimen name="design_tab_text_size">14sp</dimen>
-    <dimen name="design_tab_text_size_2line">12sp</dimen>
-
-    <dimen name="design_snackbar_min_width">-1px</dimen>
-    <dimen name="design_snackbar_max_width">-1px</dimen>
-    <dimen name="design_snackbar_elevation">6dp</dimen>
-    <dimen name="design_snackbar_background_corner_radius">0dp</dimen>
-
-    <dimen name="design_snackbar_padding_horizontal">12dp</dimen>
-    <dimen name="design_snackbar_padding_vertical">14dp</dimen>
-    <dimen name="design_snackbar_padding_vertical_2lines">24dp</dimen>
-
-    <!-- Extra spacing between the action and message views -->
-    <dimen name="design_snackbar_extra_spacing_horizontal">0dp</dimen>
-    <!-- The maximum width for a Snackbar's inline action. If the view is width than this then
-         the Snackbar will change to vertical stacking -->
-    <dimen name="design_snackbar_action_inline_max_width">128dp</dimen>
-
-    <dimen name="design_snackbar_text_size">14sp</dimen>
-
-    <dimen name="design_appbar_elevation">4dp</dimen>
-
-    <dimen name="design_bottom_sheet_modal_elevation">16dp</dimen>
-    <dimen name="design_bottom_sheet_peek_height_min">64dp</dimen>
-
-    <dimen name="design_bottom_navigation_height">56dp</dimen>
-    <dimen name="design_bottom_navigation_elevation">8dp</dimen>
-    <dimen name="design_bottom_navigation_shadow_height">1dp</dimen>
-    <dimen name="design_bottom_navigation_text_size">12sp</dimen>
-    <dimen name="design_bottom_navigation_active_text_size">14sp</dimen>
-    <dimen name="design_bottom_navigation_margin">8dp</dimen>
-    <dimen name="design_bottom_navigation_item_min_width">56dp</dimen>
-    <dimen name="design_bottom_navigation_item_max_width">96dp</dimen>
-    <dimen name="design_bottom_navigation_active_item_max_width">168dp</dimen>
-
-</resources>
diff --git a/design/res/values/ids.xml b/design/res/values/ids.xml
deleted file mode 100644
index ca90284..0000000
--- a/design/res/values/ids.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-
-    <item name="view_offset_helper" type="id" />
-
-    <item name="textinput_error" type="id" />
-    <item name="textinput_counter" type="id" />
-
-</resources>
-
diff --git a/design/res/values/integers.xml b/design/res/values/integers.xml
deleted file mode 100644
index a0d6fc7..0000000
--- a/design/res/values/integers.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-    <integer name="bottom_sheet_slide_duration">150</integer>
-    <integer name="app_bar_elevation_anim_duration">150</integer>
-</resources>
diff --git a/design/res/values/password_visibility.xml b/design/res/values/password_visibility.xml
deleted file mode 100644
index 1c85c1a..0000000
--- a/design/res/values/password_visibility.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<resources>
-
-    <!-- Resources used in the password visibility anim, see @drawable/design_password_eye -->
-    <string name="path_password_eye_mask_visible" translatable="false">M2,4.27 L2,4.27 L4.54,1.73 L4.54,1.73 L4.54,1 L23,1 L23,23 L1,23 L1,4.27 Z</string>
-    <string name="path_password_eye_mask_strike_through" translatable="false">M2,4.27 L19.73,22 L22.27,19.46 L4.54,1.73 L4.54,1 L23,1 L23,23 L1,23 L1,4.27 Z</string>
-    <string name="path_password_eye" translatable="false">M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z</string>
-    <string name="path_password_strike_through" translatable="false">M3.27,4.27 L19.74,20.74</string>
-    <integer name="show_password_duration">200</integer>
-    <integer name="hide_password_duration">320</integer>
-
-</resources>
diff --git a/design/res/values/strings.xml b/design/res/values/strings.xml
deleted file mode 100644
index 43a84cd..0000000
--- a/design/res/values/strings.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-    <!-- The class name to the ScrollingChildBehavior required for AppBarLayout -->
-    <string name="appbar_scrolling_view_behavior" translatable="false">android.support.design.widget.AppBarLayout$ScrollingViewBehavior</string>
-    <!-- The class name to the BottomSheetBehavior -->
-    <string name="bottom_sheet_behavior" translatable="false">android.support.design.widget.BottomSheetBehavior</string>
-    <!-- The text pattern for the character counter -->
-    <string name="character_counter_pattern" translatable="false">%1$d / %2$d</string>
-    <!-- Content description for the password visibility toggle button. [CHAR LIMIT=NONE] -->
-    <string name="password_toggle_content_description">Toggle password visibility</string>
-</resources>
-
diff --git a/design/res/values/styles.xml b/design/res/values/styles.xml
deleted file mode 100644
index bbb200d..0000000
--- a/design/res/values/styles.xml
+++ /dev/null
@@ -1,142 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources xmlns:tools="http://schemas.android.com/tools">
-
-    <style name="Widget.Design.FloatingActionButton" parent="android:Widget">
-        <item name="android:background">@drawable/design_fab_background</item>
-        <item name="backgroundTint">?attr/colorAccent</item>
-        <item name="fabSize">auto</item>
-        <item name="elevation">@dimen/design_fab_elevation</item>
-        <item name="pressedTranslationZ">@dimen/design_fab_translation_z_pressed</item>
-        <item name="rippleColor">?attr/colorControlHighlight</item>
-        <item name="borderWidth">@dimen/design_fab_border_width</item>
-    </style>
-
-    <style name="Widget.Design.ScrimInsetsFrameLayout" parent="">
-        <item name="insetForeground">#4000</item>
-    </style>
-
-    <style name="Widget.Design.NavigationView" parent="">
-        <item name="elevation">@dimen/design_navigation_elevation</item>
-        <item name="android:background">?android:attr/windowBackground</item>
-        <item name="android:fitsSystemWindows">true</item>
-        <item name="android:maxWidth">@dimen/design_navigation_max_width</item>
-    </style>
-
-    <style name="Widget.Design.TabLayout" parent="Base.Widget.Design.TabLayout">
-        <item name="tabGravity">fill</item>
-        <item name="tabMode">fixed</item>
-    </style>
-
-    <style name="Widget.Design.BottomNavigationView" parent="">
-        <item name="itemBackground">?attr/selectableItemBackgroundBorderless</item>
-        <item name="elevation">@dimen/design_bottom_navigation_elevation</item>
-    </style>
-
-    <style name="Base.Widget.Design.TabLayout" parent="android:Widget">
-        <item name="tabMaxWidth">@dimen/design_tab_max_width</item>
-        <item name="tabIndicatorColor">?attr/colorAccent</item>
-        <item name="tabIndicatorHeight">2dp</item>
-        <item name="tabPaddingStart">12dp</item>
-        <item name="tabPaddingEnd">12dp</item>
-        <item name="tabBackground">?attr/selectableItemBackground</item>
-        <item name="tabTextAppearance">@style/TextAppearance.Design.Tab</item>
-        <item name="tabSelectedTextColor">?android:textColorPrimary</item>
-    </style>
-
-    <style name="TextAppearance.Design.Tab" parent="TextAppearance.AppCompat.Button">
-        <item name="android:textSize">@dimen/design_tab_text_size</item>
-        <item name="android:textColor">?android:textColorSecondary</item>
-        <item name="textAllCaps">true</item>
-    </style>
-
-    <style name="Widget.Design.TextInputLayout" parent="android:Widget">
-        <item name="hintTextAppearance">@style/TextAppearance.Design.Hint</item>
-        <item name="errorTextAppearance">@style/TextAppearance.Design.Error</item>
-        <item name="counterTextAppearance">@style/TextAppearance.Design.Counter</item>
-        <item name="counterOverflowTextAppearance">@style/TextAppearance.Design.Counter.Overflow</item>
-        <item name="passwordToggleDrawable">@drawable/design_password_eye</item>
-        <item name="passwordToggleTint">@color/design_tint_password_toggle</item>
-        <item name="passwordToggleContentDescription">@string/password_toggle_content_description</item>
-    </style>
-
-    <style name="TextAppearance.Design.Hint" parent="TextAppearance.AppCompat.Caption">
-        <item name="android:textColor">?attr/colorControlActivated</item>
-    </style>
-
-    <style name="TextAppearance.Design.Error" parent="TextAppearance.AppCompat.Caption">
-        <item name="android:textColor">@color/design_error</item>
-    </style>
-
-    <style name="TextAppearance.Design.Counter" parent="TextAppearance.AppCompat.Caption"/>
-
-    <style name="TextAppearance.Design.Counter.Overflow" parent="TextAppearance.AppCompat.Caption">
-        <item name="android:textColor">@color/design_error</item>
-    </style>
-
-    <style name="TextAppearance.Design.Snackbar.Message" parent="android:TextAppearance">
-        <item name="android:textSize">@dimen/design_snackbar_text_size</item>
-        <item name="android:textColor">?android:textColorPrimary</item>
-    </style>
-
-    <style name="Widget.Design.Snackbar" parent="android:Widget">
-        <item name="android:minWidth">@dimen/design_snackbar_min_width</item>
-        <item name="android:maxWidth">@dimen/design_snackbar_max_width</item>
-        <item name="android:background">@drawable/design_snackbar_background</item>
-        <item name="android:paddingLeft">@dimen/design_snackbar_padding_horizontal</item>
-        <item name="android:paddingRight">@dimen/design_snackbar_padding_horizontal</item>
-        <item name="elevation">@dimen/design_snackbar_elevation</item>
-        <item name="maxActionInlineWidth">@dimen/design_snackbar_action_inline_max_width</item>
-    </style>
-
-    <style name="Widget.Design.CollapsingToolbar" parent="android:Widget">
-        <item name="expandedTitleMargin">32dp</item>
-        <item name="statusBarScrim">?attr/colorPrimaryDark</item>
-    </style>
-
-    <style name="Base.Widget.Design.AppBarLayout" parent="Base.V14.Widget.Design.AppBarLayout" />
-
-    <style name="Base.V14.Widget.Design.AppBarLayout" parent="android:Widget">
-        <item name="android:background">?attr/colorPrimary</item>
-    </style>
-
-    <style name="Widget.Design.AppBarLayout" parent="Base.Widget.Design.AppBarLayout">
-    </style>
-
-    <style name="Widget.Design.CoordinatorLayout" parent="@style/Widget.Support.CoordinatorLayout">
-        <item name="statusBarBackground">?attr/colorPrimaryDark</item>
-    </style>
-
-    <style name="TextAppearance.Design.CollapsingToolbar.Expanded" parent="TextAppearance.AppCompat.Display1">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-
-    <style name="Animation.Design.BottomSheetDialog" parent="Animation.AppCompat.Dialog">
-        <item name="android:windowEnterAnimation">@anim/design_bottom_sheet_slide_in</item>
-        <item name="android:windowExitAnimation">@anim/design_bottom_sheet_slide_out</item>
-    </style>
-
-    <style name="Widget.Design.BottomSheet.Modal" parent="android:Widget">
-        <item name="android:background">?android:attr/colorBackground</item>
-        <item tools:ignore="NewApi" name="android:elevation">@dimen/design_bottom_sheet_modal_elevation</item>
-        <item name="behavior_peekHeight">auto</item>
-        <item name="behavior_hideable">true</item>
-        <item name="behavior_skipCollapsed">false</item>
-    </style>
-
-</resources>
-
diff --git a/design/res/values/themes.xml b/design/res/values/themes.xml
deleted file mode 100644
index aa4c876..0000000
--- a/design/res/values/themes.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-<resources>
-
-    <style name="Theme.Design.BottomSheetDialog" parent="Theme.AppCompat.Dialog">
-        <item name="android:windowBackground">@android:color/transparent</item>
-        <item name="android:windowAnimationStyle">@style/Animation.Design.BottomSheetDialog</item>
-        <item name="bottomSheetStyle">@style/Widget.Design.BottomSheet.Modal</item>
-    </style>
-
-    <style name="Theme.Design.Light.BottomSheetDialog" parent="Theme.AppCompat.Light.Dialog">
-        <item name="android:windowBackground">@android:color/transparent</item>
-        <item name="android:windowAnimationStyle">@style/Animation.Design.BottomSheetDialog</item>
-        <item name="bottomSheetStyle">@style/Widget.Design.BottomSheet.Modal</item>
-    </style>
-
-    <style name="Theme.Design" parent="Theme.AppCompat">
-        <item name="textColorError">?attr/colorError</item>
-        <item name="coordinatorLayoutStyle">@style/Widget.Design.CoordinatorLayout</item>
-    </style>
-
-    <style name="Theme.Design.Light" parent="Theme.AppCompat.Light">
-        <item name="textColorError">?attr/colorError</item>
-        <item name="coordinatorLayoutStyle">@style/Widget.Design.CoordinatorLayout</item>
-    </style>
-
-    <style name="Theme.Design.NoActionBar">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
-    </style>
-
-    <style name="Theme.Design.Light.NoActionBar">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
-    </style>
-
-</resources>
diff --git a/design/src/android/support/design/internal/BaselineLayout.java b/design/src/android/support/design/internal/BaselineLayout.java
deleted file mode 100644
index 0bfdf24..0000000
--- a/design/src/android/support/design/internal/BaselineLayout.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * A simple ViewGroup that aligns all the views inside on a baseline. Note: bottom padding for this
- * view will be measured starting from the baseline.
- *
- * @hide
- */
-public class BaselineLayout extends ViewGroup {
-    private int mBaseline = -1;
-
-    public BaselineLayout(Context context) {
-        super(context, null, 0);
-    }
-
-    public BaselineLayout(Context context, AttributeSet attrs) {
-        super(context, attrs, 0);
-    }
-
-    public BaselineLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int count = getChildCount();
-        int maxWidth = 0;
-        int maxHeight = 0;
-        int maxChildBaseline = -1;
-        int maxChildDescent = -1;
-        int childState = 0;
-
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-
-            measureChild(child, widthMeasureSpec, heightMeasureSpec);
-            final int baseline = child.getBaseline();
-            if (baseline != -1) {
-                maxChildBaseline = Math.max(maxChildBaseline, baseline);
-                maxChildDescent = Math.max(maxChildDescent, child.getMeasuredHeight() - baseline);
-            }
-            maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
-            maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
-            childState = View.combineMeasuredStates(childState, child.getMeasuredState());
-        }
-        if (maxChildBaseline != -1) {
-            maxChildDescent = Math.max(maxChildDescent, getPaddingBottom());
-            maxHeight = Math.max(maxHeight, maxChildBaseline + maxChildDescent);
-            mBaseline = maxChildBaseline;
-        }
-        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
-        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
-        setMeasuredDimension(
-                View.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
-                View.resolveSizeAndState(maxHeight, heightMeasureSpec,
-                        childState << MEASURED_HEIGHT_STATE_SHIFT));
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        final int count = getChildCount();
-        final int parentLeft = getPaddingLeft();
-        final int parentRight = right - left - getPaddingRight();
-        final int parentContentWidth = parentRight - parentLeft;
-        final int parentTop = getPaddingTop();
-
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-
-            final int width = child.getMeasuredWidth();
-            final int height = child.getMeasuredHeight();
-
-            final int childLeft = parentLeft + (parentContentWidth - width) / 2;
-            final int childTop;
-            if (mBaseline != -1 && child.getBaseline() != -1) {
-                childTop = parentTop + mBaseline - child.getBaseline();
-            } else {
-                childTop = parentTop;
-            }
-
-            child.layout(childLeft, childTop, childLeft + width, childTop + height);
-        }
-    }
-
-    @Override
-    public int getBaseline() {
-        return mBaseline;
-    }
-}
diff --git a/design/src/android/support/design/internal/BottomNavigationItemView.java b/design/src/android/support/design/internal/BottomNavigationItemView.java
deleted file mode 100644
index fe5e636..0000000
--- a/design/src/android/support/design/internal/BottomNavigationItemView.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.design.R;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.PointerIconCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.view.menu.MenuView;
-import android.support.v7.widget.TooltipCompat;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class BottomNavigationItemView extends FrameLayout implements MenuView.ItemView {
-    public static final int INVALID_ITEM_POSITION = -1;
-
-    private static final int[] CHECKED_STATE_SET = { android.R.attr.state_checked };
-
-    private final int mDefaultMargin;
-    private final int mShiftAmount;
-    private final float mScaleUpFactor;
-    private final float mScaleDownFactor;
-
-    private boolean mShiftingMode;
-
-    private ImageView mIcon;
-    private final TextView mSmallLabel;
-    private final TextView mLargeLabel;
-    private int mItemPosition = INVALID_ITEM_POSITION;
-
-    private MenuItemImpl mItemData;
-
-    private ColorStateList mIconTint;
-
-    public BottomNavigationItemView(@NonNull Context context) {
-        this(context, null);
-    }
-
-    public BottomNavigationItemView(@NonNull Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public BottomNavigationItemView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        final Resources res = getResources();
-        int inactiveLabelSize =
-                res.getDimensionPixelSize(R.dimen.design_bottom_navigation_text_size);
-        int activeLabelSize = res.getDimensionPixelSize(
-                R.dimen.design_bottom_navigation_active_text_size);
-        mDefaultMargin = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_margin);
-        mShiftAmount = inactiveLabelSize - activeLabelSize;
-        mScaleUpFactor = 1f * activeLabelSize / inactiveLabelSize;
-        mScaleDownFactor = 1f * inactiveLabelSize / activeLabelSize;
-
-        LayoutInflater.from(context).inflate(R.layout.design_bottom_navigation_item, this, true);
-        setBackgroundResource(R.drawable.design_bottom_navigation_item_background);
-        mIcon = findViewById(R.id.icon);
-        mSmallLabel = findViewById(R.id.smallLabel);
-        mLargeLabel = findViewById(R.id.largeLabel);
-    }
-
-    @Override
-    public void initialize(MenuItemImpl itemData, int menuType) {
-        mItemData = itemData;
-        setCheckable(itemData.isCheckable());
-        setChecked(itemData.isChecked());
-        setEnabled(itemData.isEnabled());
-        setIcon(itemData.getIcon());
-        setTitle(itemData.getTitle());
-        setId(itemData.getItemId());
-        setContentDescription(itemData.getContentDescription());
-        TooltipCompat.setTooltipText(this, itemData.getTooltipText());
-    }
-
-    public void setItemPosition(int position) {
-        mItemPosition = position;
-    }
-
-    public int getItemPosition() {
-        return mItemPosition;
-    }
-
-    public void setShiftingMode(boolean enabled) {
-        mShiftingMode = enabled;
-    }
-
-    @Override
-    public MenuItemImpl getItemData() {
-        return mItemData;
-    }
-
-    @Override
-    public void setTitle(CharSequence title) {
-        mSmallLabel.setText(title);
-        mLargeLabel.setText(title);
-    }
-
-    @Override
-    public void setCheckable(boolean checkable) {
-        refreshDrawableState();
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-        mLargeLabel.setPivotX(mLargeLabel.getWidth() / 2);
-        mLargeLabel.setPivotY(mLargeLabel.getBaseline());
-        mSmallLabel.setPivotX(mSmallLabel.getWidth() / 2);
-        mSmallLabel.setPivotY(mSmallLabel.getBaseline());
-        if (mShiftingMode) {
-            if (checked) {
-                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
-                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
-                iconParams.topMargin = mDefaultMargin;
-                mIcon.setLayoutParams(iconParams);
-                mLargeLabel.setVisibility(VISIBLE);
-                mLargeLabel.setScaleX(1f);
-                mLargeLabel.setScaleY(1f);
-            } else {
-                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
-                iconParams.gravity = Gravity.CENTER;
-                iconParams.topMargin = mDefaultMargin;
-                mIcon.setLayoutParams(iconParams);
-                mLargeLabel.setVisibility(INVISIBLE);
-                mLargeLabel.setScaleX(0.5f);
-                mLargeLabel.setScaleY(0.5f);
-            }
-            mSmallLabel.setVisibility(INVISIBLE);
-        } else {
-            if (checked) {
-                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
-                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
-                iconParams.topMargin = mDefaultMargin + mShiftAmount;
-                mIcon.setLayoutParams(iconParams);
-                mLargeLabel.setVisibility(VISIBLE);
-                mSmallLabel.setVisibility(INVISIBLE);
-
-                mLargeLabel.setScaleX(1f);
-                mLargeLabel.setScaleY(1f);
-                mSmallLabel.setScaleX(mScaleUpFactor);
-                mSmallLabel.setScaleY(mScaleUpFactor);
-            } else {
-                LayoutParams iconParams = (LayoutParams) mIcon.getLayoutParams();
-                iconParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
-                iconParams.topMargin = mDefaultMargin;
-                mIcon.setLayoutParams(iconParams);
-                mLargeLabel.setVisibility(INVISIBLE);
-                mSmallLabel.setVisibility(VISIBLE);
-
-                mLargeLabel.setScaleX(mScaleDownFactor);
-                mLargeLabel.setScaleY(mScaleDownFactor);
-                mSmallLabel.setScaleX(1f);
-                mSmallLabel.setScaleY(1f);
-            }
-        }
-
-        refreshDrawableState();
-    }
-
-    @Override
-    public void setEnabled(boolean enabled) {
-        super.setEnabled(enabled);
-        mSmallLabel.setEnabled(enabled);
-        mLargeLabel.setEnabled(enabled);
-        mIcon.setEnabled(enabled);
-
-        if (enabled) {
-            ViewCompat.setPointerIcon(this,
-                    PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));
-        } else {
-            ViewCompat.setPointerIcon(this, null);
-        }
-
-    }
-
-    @Override
-    public int[] onCreateDrawableState(final int extraSpace) {
-        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
-        if (mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) {
-            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
-        }
-        return drawableState;
-    }
-
-    @Override
-    public void setShortcut(boolean showShortcut, char shortcutKey) {
-    }
-
-    @Override
-    public void setIcon(Drawable icon) {
-        if (icon != null) {
-            Drawable.ConstantState state = icon.getConstantState();
-            icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate();
-            DrawableCompat.setTintList(icon, mIconTint);
-        }
-        mIcon.setImageDrawable(icon);
-    }
-
-    @Override
-    public boolean prefersCondensedTitle() {
-        return false;
-    }
-
-    @Override
-    public boolean showsIcon() {
-        return true;
-    }
-
-    public void setIconTintList(ColorStateList tint) {
-        mIconTint = tint;
-        if (mItemData != null) {
-            // Update the icon so that the tint takes effect
-            setIcon(mItemData.getIcon());
-        }
-    }
-
-    public void setTextColor(ColorStateList color) {
-        mSmallLabel.setTextColor(color);
-        mLargeLabel.setTextColor(color);
-    }
-
-    public void setItemBackground(int background) {
-        Drawable backgroundDrawable = background == 0
-                ? null : ContextCompat.getDrawable(getContext(), background);
-        ViewCompat.setBackground(this, backgroundDrawable);
-    }
-}
diff --git a/design/src/android/support/design/internal/BottomNavigationMenu.java b/design/src/android/support/design/internal/BottomNavigationMenu.java
deleted file mode 100644
index a86d2ad..0000000
--- a/design/src/android/support/design/internal/BottomNavigationMenu.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.support.annotation.RestrictTo;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.view.MenuItem;
-import android.view.SubMenu;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public final class BottomNavigationMenu extends MenuBuilder {
-    public static final int MAX_ITEM_COUNT = 5;
-
-    public BottomNavigationMenu(Context context) {
-        super(context);
-    }
-
-    @Override
-    public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
-        throw new UnsupportedOperationException("BottomNavigationView does not support submenus");
-    }
-
-    @Override
-    protected MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
-        if (size() + 1 > MAX_ITEM_COUNT) {
-            throw new IllegalArgumentException(
-                    "Maximum number of items supported by BottomNavigationView is " + MAX_ITEM_COUNT
-                            + ". Limit can be checked with BottomNavigationView#getMaxItemCount()");
-        }
-        stopDispatchingItemsChanged();
-        final MenuItem item = super.addInternal(group, id, categoryOrder, title);
-        if (item instanceof MenuItemImpl) {
-            ((MenuItemImpl) item).setExclusiveCheckable(true);
-        }
-        startDispatchingItemsChanged();
-        return item;
-    }
-}
diff --git a/design/src/android/support/design/internal/BottomNavigationMenuView.java b/design/src/android/support/design/internal/BottomNavigationMenuView.java
deleted file mode 100644
index bf33454..0000000
--- a/design/src/android/support/design/internal/BottomNavigationMenuView.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.design.R;
-import android.support.transition.AutoTransition;
-import android.support.transition.TransitionManager;
-import android.support.transition.TransitionSet;
-import android.support.v4.util.Pools;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.animation.FastOutSlowInInterpolator;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.view.menu.MenuView;
-import android.util.AttributeSet;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * @hide For internal use only.
- */
-@RestrictTo(LIBRARY_GROUP)
-public class BottomNavigationMenuView extends ViewGroup implements MenuView {
-    private static final long ACTIVE_ANIMATION_DURATION_MS = 115L;
-
-    private final TransitionSet mSet;
-    private final int mInactiveItemMaxWidth;
-    private final int mInactiveItemMinWidth;
-    private final int mActiveItemMaxWidth;
-    private final int mItemHeight;
-    private final OnClickListener mOnClickListener;
-    private final Pools.Pool<BottomNavigationItemView> mItemPool = new Pools.SynchronizedPool<>(5);
-
-    private boolean mShiftingMode = true;
-
-    private BottomNavigationItemView[] mButtons;
-    private int mSelectedItemId = 0;
-    private int mSelectedItemPosition = 0;
-    private ColorStateList mItemIconTint;
-    private ColorStateList mItemTextColor;
-    private int mItemBackgroundRes;
-    private int[] mTempChildWidths;
-
-    private BottomNavigationPresenter mPresenter;
-    private MenuBuilder mMenu;
-
-    public BottomNavigationMenuView(Context context) {
-        this(context, null);
-    }
-
-    public BottomNavigationMenuView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        final Resources res = getResources();
-        mInactiveItemMaxWidth = res.getDimensionPixelSize(
-                R.dimen.design_bottom_navigation_item_max_width);
-        mInactiveItemMinWidth = res.getDimensionPixelSize(
-                R.dimen.design_bottom_navigation_item_min_width);
-        mActiveItemMaxWidth = res.getDimensionPixelSize(
-                R.dimen.design_bottom_navigation_active_item_max_width);
-        mItemHeight = res.getDimensionPixelSize(R.dimen.design_bottom_navigation_height);
-
-        mSet = new AutoTransition();
-        mSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
-        mSet.setDuration(ACTIVE_ANIMATION_DURATION_MS);
-        mSet.setInterpolator(new FastOutSlowInInterpolator());
-        mSet.addTransition(new TextScale());
-
-        mOnClickListener = new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                final BottomNavigationItemView itemView = (BottomNavigationItemView) v;
-                MenuItem item = itemView.getItemData();
-                if (!mMenu.performItemAction(item, mPresenter, 0)) {
-                    item.setChecked(true);
-                }
-            }
-        };
-        mTempChildWidths = new int[BottomNavigationMenu.MAX_ITEM_COUNT];
-    }
-
-    @Override
-    public void initialize(MenuBuilder menu) {
-        mMenu = menu;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int width = MeasureSpec.getSize(widthMeasureSpec);
-        final int count = getChildCount();
-
-        final int heightSpec = MeasureSpec.makeMeasureSpec(mItemHeight, MeasureSpec.EXACTLY);
-
-        if (mShiftingMode) {
-            final int inactiveCount = count - 1;
-            final int activeMaxAvailable = width - inactiveCount * mInactiveItemMinWidth;
-            final int activeWidth = Math.min(activeMaxAvailable, mActiveItemMaxWidth);
-            final int inactiveMaxAvailable = (width - activeWidth) / inactiveCount;
-            final int inactiveWidth = Math.min(inactiveMaxAvailable, mInactiveItemMaxWidth);
-            int extra = width - activeWidth - inactiveWidth * inactiveCount;
-            for (int i = 0; i < count; i++) {
-                mTempChildWidths[i] = (i == mSelectedItemPosition) ? activeWidth : inactiveWidth;
-                if (extra > 0) {
-                    mTempChildWidths[i]++;
-                    extra--;
-                }
-            }
-        } else {
-            final int maxAvailable = width / (count == 0 ? 1 : count);
-            final int childWidth = Math.min(maxAvailable, mActiveItemMaxWidth);
-            int extra = width - childWidth * count;
-            for (int i = 0; i < count; i++) {
-                mTempChildWidths[i] = childWidth;
-                if (extra > 0) {
-                    mTempChildWidths[i]++;
-                    extra--;
-                }
-            }
-        }
-
-        int totalWidth = 0;
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-            child.measure(MeasureSpec.makeMeasureSpec(mTempChildWidths[i], MeasureSpec.EXACTLY),
-                    heightSpec);
-            ViewGroup.LayoutParams params = child.getLayoutParams();
-            params.width = child.getMeasuredWidth();
-            totalWidth += child.getMeasuredWidth();
-        }
-        setMeasuredDimension(
-                View.resolveSizeAndState(totalWidth,
-                        MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), 0),
-                View.resolveSizeAndState(mItemHeight, heightSpec, 0));
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        final int count = getChildCount();
-        final int width = right - left;
-        final int height = bottom - top;
-        int used = 0;
-        for (int i = 0; i < count; i++) {
-            final View child = getChildAt(i);
-            if (child.getVisibility() == GONE) {
-                continue;
-            }
-            if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
-                child.layout(width - used - child.getMeasuredWidth(), 0, width - used, height);
-            } else {
-                child.layout(used, 0, child.getMeasuredWidth() + used, height);
-            }
-            used += child.getMeasuredWidth();
-        }
-    }
-
-    @Override
-    public int getWindowAnimations() {
-        return 0;
-    }
-
-    /**
-     * Sets the tint which is applied to the menu items' icons.
-     *
-     * @param tint the tint to apply
-     */
-    public void setIconTintList(ColorStateList tint) {
-        mItemIconTint = tint;
-        if (mButtons == null) return;
-        for (BottomNavigationItemView item : mButtons) {
-            item.setIconTintList(tint);
-        }
-    }
-
-    /**
-     * Returns the tint which is applied to menu items' icons.
-     *
-     * @return the ColorStateList that is used to tint menu items' icons
-     */
-    @Nullable
-    public ColorStateList getIconTintList() {
-        return mItemIconTint;
-    }
-
-    /**
-     * Sets the text color to be used on menu items.
-     *
-     * @param color the ColorStateList used for menu items' text.
-     */
-    public void setItemTextColor(ColorStateList color) {
-        mItemTextColor = color;
-        if (mButtons == null) return;
-        for (BottomNavigationItemView item : mButtons) {
-            item.setTextColor(color);
-        }
-    }
-
-    /**
-     * Returns the text color used on menu items.
-     *
-     * @return the ColorStateList used for menu items' text
-     */
-    public ColorStateList getItemTextColor() {
-        return mItemTextColor;
-    }
-
-    /**
-     * Sets the resource ID to be used for item background.
-     *
-     * @param background the resource ID of the background
-     */
-    public void setItemBackgroundRes(int background) {
-        mItemBackgroundRes = background;
-        if (mButtons == null) return;
-        for (BottomNavigationItemView item : mButtons) {
-            item.setItemBackground(background);
-        }
-    }
-
-    /**
-     * Returns the resource ID for the background of the menu items.
-     *
-     * @return the resource ID for the background
-     */
-    public int getItemBackgroundRes() {
-        return mItemBackgroundRes;
-    }
-
-    public void setPresenter(BottomNavigationPresenter presenter) {
-        mPresenter = presenter;
-    }
-
-    public void buildMenuView() {
-        removeAllViews();
-        if (mButtons != null) {
-            for (BottomNavigationItemView item : mButtons) {
-                mItemPool.release(item);
-            }
-        }
-        if (mMenu.size() == 0) {
-            mSelectedItemId = 0;
-            mSelectedItemPosition = 0;
-            mButtons = null;
-            return;
-        }
-        mButtons = new BottomNavigationItemView[mMenu.size()];
-        mShiftingMode = mMenu.size() > 3;
-        for (int i = 0; i < mMenu.size(); i++) {
-            mPresenter.setUpdateSuspended(true);
-            mMenu.getItem(i).setCheckable(true);
-            mPresenter.setUpdateSuspended(false);
-            BottomNavigationItemView child = getNewItem();
-            mButtons[i] = child;
-            child.setIconTintList(mItemIconTint);
-            child.setTextColor(mItemTextColor);
-            child.setItemBackground(mItemBackgroundRes);
-            child.setShiftingMode(mShiftingMode);
-            child.initialize((MenuItemImpl) mMenu.getItem(i), 0);
-            child.setItemPosition(i);
-            child.setOnClickListener(mOnClickListener);
-            addView(child);
-        }
-        mSelectedItemPosition = Math.min(mMenu.size() - 1, mSelectedItemPosition);
-        mMenu.getItem(mSelectedItemPosition).setChecked(true);
-    }
-
-    public void updateMenuView() {
-        final int menuSize = mMenu.size();
-        if (menuSize != mButtons.length) {
-            // The size has changed. Rebuild menu view from scratch.
-            buildMenuView();
-            return;
-        }
-        int previousSelectedId = mSelectedItemId;
-
-        for (int i = 0; i < menuSize; i++) {
-            MenuItem item = mMenu.getItem(i);
-            if (item.isChecked()) {
-                mSelectedItemId = item.getItemId();
-                mSelectedItemPosition = i;
-            }
-        }
-        if (previousSelectedId != mSelectedItemId) {
-            // Note: this has to be called before BottomNavigationItemView#initialize().
-            TransitionManager.beginDelayedTransition(this, mSet);
-        }
-
-        for (int i = 0; i < menuSize; i++) {
-            mPresenter.setUpdateSuspended(true);
-            mButtons[i].initialize((MenuItemImpl) mMenu.getItem(i), 0);
-            mPresenter.setUpdateSuspended(false);
-        }
-
-    }
-
-    private BottomNavigationItemView getNewItem() {
-        BottomNavigationItemView item = mItemPool.acquire();
-        if (item == null) {
-            item = new BottomNavigationItemView(getContext());
-        }
-        return item;
-    }
-
-    public int getSelectedItemId() {
-        return mSelectedItemId;
-    }
-
-    void tryRestoreSelectedItemId(int itemId) {
-        final int size = mMenu.size();
-        for (int i = 0; i < size; i++) {
-            MenuItem item = mMenu.getItem(i);
-            if (itemId == item.getItemId()) {
-                mSelectedItemId = itemId;
-                mSelectedItemPosition = i;
-                item.setChecked(true);
-                break;
-            }
-        }
-    }
-}
diff --git a/design/src/android/support/design/internal/BottomNavigationPresenter.java b/design/src/android/support/design/internal/BottomNavigationPresenter.java
deleted file mode 100644
index 1343a4b..0000000
--- a/design/src/android/support/design/internal/BottomNavigationPresenter.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.view.menu.MenuPresenter;
-import android.support.v7.view.menu.MenuView;
-import android.support.v7.view.menu.SubMenuBuilder;
-import android.view.ViewGroup;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class BottomNavigationPresenter implements MenuPresenter {
-    private MenuBuilder mMenu;
-    private BottomNavigationMenuView mMenuView;
-    private boolean mUpdateSuspended = false;
-    private int mId;
-
-    public void setBottomNavigationMenuView(BottomNavigationMenuView menuView) {
-        mMenuView = menuView;
-    }
-
-    @Override
-    public void initForMenu(Context context, MenuBuilder menu) {
-        mMenuView.initialize(mMenu);
-        mMenu = menu;
-    }
-
-    @Override
-    public MenuView getMenuView(ViewGroup root) {
-        return mMenuView;
-    }
-
-    @Override
-    public void updateMenuView(boolean cleared) {
-        if (mUpdateSuspended) return;
-        if (cleared) {
-            mMenuView.buildMenuView();
-        } else {
-            mMenuView.updateMenuView();
-        }
-    }
-
-    @Override
-    public void setCallback(Callback cb) {}
-
-    @Override
-    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
-        return false;
-    }
-
-    @Override
-    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {}
-
-    @Override
-    public boolean flagActionItems() {
-        return false;
-    }
-
-    @Override
-    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
-        return false;
-    }
-
-    @Override
-    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
-        return false;
-    }
-
-    public void setId(int id) {
-        mId = id;
-    }
-
-    @Override
-    public int getId() {
-        return mId;
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        SavedState savedState = new SavedState();
-        savedState.selectedItemId = mMenuView.getSelectedItemId();
-        return savedState;
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        if (state instanceof SavedState) {
-            mMenuView.tryRestoreSelectedItemId(((SavedState) state).selectedItemId);
-        }
-    }
-
-    public void setUpdateSuspended(boolean updateSuspended) {
-        mUpdateSuspended = updateSuspended;
-    }
-
-    static class SavedState implements Parcelable {
-        int selectedItemId;
-
-        SavedState() {}
-
-        SavedState(Parcel in) {
-            selectedItemId = in.readInt();
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(@NonNull Parcel out, int flags) {
-            out.writeInt(selectedItemId);
-        }
-
-        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-}
diff --git a/design/src/android/support/design/internal/ForegroundLinearLayout.java b/design/src/android/support/design/internal/ForegroundLinearLayout.java
deleted file mode 100644
index 6d90503..0000000
--- a/design/src/android/support/design/internal/ForegroundLinearLayout.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.design.R;
-import android.support.v7.widget.LinearLayoutCompat;
-import android.util.AttributeSet;
-import android.view.Gravity;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class ForegroundLinearLayout extends LinearLayoutCompat {
-
-    private Drawable mForeground;
-
-    private final Rect mSelfBounds = new Rect();
-
-    private final Rect mOverlayBounds = new Rect();
-
-    private int mForegroundGravity = Gravity.FILL;
-
-    protected boolean mForegroundInPadding = true;
-
-    boolean mForegroundBoundsChanged = false;
-
-    public ForegroundLinearLayout(Context context) {
-        this(context, null);
-    }
-
-    public ForegroundLinearLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public ForegroundLinearLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundLinearLayout,
-                defStyle, 0);
-
-        mForegroundGravity = a.getInt(
-                R.styleable.ForegroundLinearLayout_android_foregroundGravity, mForegroundGravity);
-
-        final Drawable d = a.getDrawable(R.styleable.ForegroundLinearLayout_android_foreground);
-        if (d != null) {
-            setForeground(d);
-        }
-
-        mForegroundInPadding = a.getBoolean(
-                R.styleable.ForegroundLinearLayout_foregroundInsidePadding, true);
-
-        a.recycle();
-    }
-
-    /**
-     * Describes how the foreground is positioned.
-     *
-     * @return foreground gravity.
-     * @see #setForegroundGravity(int)
-     */
-    @Override
-    public int getForegroundGravity() {
-        return mForegroundGravity;
-    }
-
-    /**
-     * Describes how the foreground is positioned. Defaults to START and TOP.
-     *
-     * @param foregroundGravity See {@link android.view.Gravity}
-     * @see #getForegroundGravity()
-     */
-    @Override
-    public void setForegroundGravity(int foregroundGravity) {
-        if (mForegroundGravity != foregroundGravity) {
-            if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
-                foregroundGravity |= Gravity.START;
-            }
-
-            if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
-                foregroundGravity |= Gravity.TOP;
-            }
-
-            mForegroundGravity = foregroundGravity;
-
-            if (mForegroundGravity == Gravity.FILL && mForeground != null) {
-                Rect padding = new Rect();
-                mForeground.getPadding(padding);
-            }
-
-            requestLayout();
-        }
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || (who == mForeground);
-    }
-
-    @RequiresApi(11)
-    @Override
-    public void jumpDrawablesToCurrentState() {
-        super.jumpDrawablesToCurrentState();
-        if (mForeground != null) {
-            mForeground.jumpToCurrentState();
-        }
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-        if (mForeground != null && mForeground.isStateful()) {
-            mForeground.setState(getDrawableState());
-        }
-    }
-
-    /**
-     * Supply a Drawable that is to be rendered on top of all of the child
-     * views in the frame layout.  Any padding in the Drawable will be taken
-     * into account by ensuring that the children are inset to be placed
-     * inside of the padding area.
-     *
-     * @param drawable The Drawable to be drawn on top of the children.
-     */
-    @Override
-    public void setForeground(Drawable drawable) {
-        if (mForeground != drawable) {
-            if (mForeground != null) {
-                mForeground.setCallback(null);
-                unscheduleDrawable(mForeground);
-            }
-
-            mForeground = drawable;
-
-            if (drawable != null) {
-                setWillNotDraw(false);
-                drawable.setCallback(this);
-                if (drawable.isStateful()) {
-                    drawable.setState(getDrawableState());
-                }
-                if (mForegroundGravity == Gravity.FILL) {
-                    Rect padding = new Rect();
-                    drawable.getPadding(padding);
-                }
-            } else {
-                setWillNotDraw(true);
-            }
-            requestLayout();
-            invalidate();
-        }
-    }
-
-    /**
-     * Returns the drawable used as the foreground of this FrameLayout. The
-     * foreground drawable, if non-null, is always drawn on top of the children.
-     *
-     * @return A Drawable or null if no foreground was set.
-     */
-    @Override
-    public Drawable getForeground() {
-        return mForeground;
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        mForegroundBoundsChanged |= changed;
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        mForegroundBoundsChanged = true;
-    }
-
-    @Override
-    public void draw(@NonNull Canvas canvas) {
-        super.draw(canvas);
-
-        if (mForeground != null) {
-            final Drawable foreground = mForeground;
-
-            if (mForegroundBoundsChanged) {
-                mForegroundBoundsChanged = false;
-                final Rect selfBounds = mSelfBounds;
-                final Rect overlayBounds = mOverlayBounds;
-
-                final int w = getRight() - getLeft();
-                final int h = getBottom() - getTop();
-
-                if (mForegroundInPadding) {
-                    selfBounds.set(0, 0, w, h);
-                } else {
-                    selfBounds.set(getPaddingLeft(), getPaddingTop(),
-                            w - getPaddingRight(), h - getPaddingBottom());
-                }
-
-                Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
-                        foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
-                foreground.setBounds(overlayBounds);
-            }
-
-            foreground.draw(canvas);
-        }
-    }
-
-    @RequiresApi(21)
-    @Override
-    public void drawableHotspotChanged(float x, float y) {
-        super.drawableHotspotChanged(x, y);
-        if (mForeground != null) {
-            mForeground.setHotspot(x, y);
-        }
-    }
-
-}
diff --git a/design/src/android/support/design/internal/NavigationMenu.java b/design/src/android/support/design/internal/NavigationMenu.java
deleted file mode 100644
index a0ec5e0..0000000
--- a/design/src/android/support/design/internal/NavigationMenu.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.support.annotation.RestrictTo;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.view.menu.SubMenuBuilder;
-import android.view.SubMenu;
-
-/**
- * This is a {@link MenuBuilder} that returns an instance of {@link NavigationSubMenu} instead of
- * {@link SubMenuBuilder} when a sub menu is created.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class NavigationMenu extends MenuBuilder {
-
-    public NavigationMenu(Context context) {
-        super(context);
-    }
-
-    @Override
-    public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
-        final MenuItemImpl item = (MenuItemImpl) addInternal(group, id, categoryOrder, title);
-        final SubMenuBuilder subMenu = new NavigationSubMenu(getContext(), this, item);
-        item.setSubMenu(subMenu);
-        return subMenu;
-    }
-
-}
diff --git a/design/src/android/support/design/internal/NavigationMenuItemView.java b/design/src/android/support/design/internal/NavigationMenuItemView.java
deleted file mode 100644
index eea9e90..0000000
--- a/design/src/android/support/design/internal/NavigationMenuItemView.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
-import android.support.annotation.RestrictTo;
-import android.support.design.R;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.TextViewCompat;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.view.menu.MenuView;
-import android.support.v7.widget.TooltipCompat;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewStub;
-import android.widget.CheckedTextView;
-import android.widget.FrameLayout;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class NavigationMenuItemView extends ForegroundLinearLayout implements MenuView.ItemView {
-
-    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
-
-    private final int mIconSize;
-
-    private boolean mNeedsEmptyIcon;
-
-    boolean mCheckable;
-
-    private final CheckedTextView mTextView;
-
-    private FrameLayout mActionArea;
-
-    private MenuItemImpl mItemData;
-
-    private ColorStateList mIconTintList;
-
-    private boolean mHasIconTintList;
-
-    private Drawable mEmptyDrawable;
-
-    private final AccessibilityDelegateCompat mAccessibilityDelegate
-            = new AccessibilityDelegateCompat() {
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host,
-                AccessibilityNodeInfoCompat info) {
-            super.onInitializeAccessibilityNodeInfo(host, info);
-            info.setCheckable(mCheckable);
-        }
-
-    };
-
-    public NavigationMenuItemView(Context context) {
-        this(context, null);
-    }
-
-    public NavigationMenuItemView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NavigationMenuItemView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        setOrientation(HORIZONTAL);
-        LayoutInflater.from(context).inflate(R.layout.design_navigation_menu_item, this, true);
-        mIconSize = context.getResources().getDimensionPixelSize(
-                R.dimen.design_navigation_icon_size);
-        mTextView = findViewById(R.id.design_menu_item_text);
-        mTextView.setDuplicateParentStateEnabled(true);
-        ViewCompat.setAccessibilityDelegate(mTextView, mAccessibilityDelegate);
-    }
-
-    @Override
-    public void initialize(MenuItemImpl itemData, int menuType) {
-        mItemData = itemData;
-
-        setVisibility(itemData.isVisible() ? VISIBLE : GONE);
-
-        if (getBackground() == null) {
-            ViewCompat.setBackground(this, createDefaultBackground());
-        }
-
-        setCheckable(itemData.isCheckable());
-        setChecked(itemData.isChecked());
-        setEnabled(itemData.isEnabled());
-        setTitle(itemData.getTitle());
-        setIcon(itemData.getIcon());
-        setActionView(itemData.getActionView());
-        setContentDescription(itemData.getContentDescription());
-        TooltipCompat.setTooltipText(this, itemData.getTooltipText());
-        adjustAppearance();
-    }
-
-    private boolean shouldExpandActionArea() {
-        return mItemData.getTitle() == null &&
-                mItemData.getIcon() == null &&
-                mItemData.getActionView() != null;
-    }
-
-    private void adjustAppearance() {
-        if (shouldExpandActionArea()) {
-            // Expand the actionView area
-            mTextView.setVisibility(View.GONE);
-            if (mActionArea != null) {
-                LayoutParams params = (LayoutParams) mActionArea.getLayoutParams();
-                params.width = LayoutParams.MATCH_PARENT;
-                mActionArea.setLayoutParams(params);
-            }
-        } else {
-            mTextView.setVisibility(View.VISIBLE);
-            if (mActionArea != null) {
-                LayoutParams params = (LayoutParams) mActionArea.getLayoutParams();
-                params.width = LayoutParams.WRAP_CONTENT;
-                mActionArea.setLayoutParams(params);
-            }
-        }
-    }
-
-    public void recycle() {
-        if (mActionArea != null) {
-            mActionArea.removeAllViews();
-        }
-        mTextView.setCompoundDrawables(null, null, null, null);
-    }
-
-    private void setActionView(View actionView) {
-        if (actionView != null) {
-            if (mActionArea == null) {
-                mActionArea = (FrameLayout) ((ViewStub) findViewById(
-                        R.id.design_menu_item_action_area_stub)).inflate();
-            }
-            mActionArea.removeAllViews();
-            mActionArea.addView(actionView);
-        }
-    }
-
-    private StateListDrawable createDefaultBackground() {
-        TypedValue value = new TypedValue();
-        if (getContext().getTheme().resolveAttribute(
-                android.support.v7.appcompat.R.attr.colorControlHighlight, value, true)) {
-            StateListDrawable drawable = new StateListDrawable();
-            drawable.addState(CHECKED_STATE_SET, new ColorDrawable(value.data));
-            drawable.addState(EMPTY_STATE_SET, new ColorDrawable(Color.TRANSPARENT));
-            return drawable;
-        }
-        return null;
-    }
-
-    @Override
-    public MenuItemImpl getItemData() {
-        return mItemData;
-    }
-
-    @Override
-    public void setTitle(CharSequence title) {
-        mTextView.setText(title);
-    }
-
-    @Override
-    public void setCheckable(boolean checkable) {
-        refreshDrawableState();
-        if (mCheckable != checkable) {
-            mCheckable = checkable;
-            mAccessibilityDelegate.sendAccessibilityEvent(mTextView,
-                    AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED);
-        }
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-        refreshDrawableState();
-        mTextView.setChecked(checked);
-    }
-
-    @Override
-    public void setShortcut(boolean showShortcut, char shortcutKey) {
-    }
-
-    @Override
-    public void setIcon(Drawable icon) {
-        if (icon != null) {
-            if (mHasIconTintList) {
-                Drawable.ConstantState state = icon.getConstantState();
-                icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate();
-                DrawableCompat.setTintList(icon, mIconTintList);
-            }
-            icon.setBounds(0, 0, mIconSize, mIconSize);
-        } else if (mNeedsEmptyIcon) {
-            if (mEmptyDrawable == null) {
-                mEmptyDrawable = ResourcesCompat.getDrawable(getResources(),
-                        R.drawable.navigation_empty_icon, getContext().getTheme());
-                if (mEmptyDrawable != null) {
-                    mEmptyDrawable.setBounds(0, 0, mIconSize, mIconSize);
-                }
-            }
-            icon = mEmptyDrawable;
-        }
-        TextViewCompat.setCompoundDrawablesRelative(mTextView, icon, null, null, null);
-    }
-
-    @Override
-    public boolean prefersCondensedTitle() {
-        return false;
-    }
-
-    @Override
-    public boolean showsIcon() {
-        return true;
-    }
-
-    @Override
-    protected int[] onCreateDrawableState(int extraSpace) {
-        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
-        if (mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) {
-            mergeDrawableStates(drawableState, CHECKED_STATE_SET);
-        }
-        return drawableState;
-    }
-
-    void setIconTintList(ColorStateList tintList) {
-        mIconTintList = tintList;
-        mHasIconTintList = mIconTintList != null;
-        if (mItemData != null) {
-            // Update the icon so that the tint takes effect
-            setIcon(mItemData.getIcon());
-        }
-    }
-
-    public void setTextAppearance(int textAppearance) {
-        TextViewCompat.setTextAppearance(mTextView, textAppearance);
-    }
-
-    public void setTextColor(ColorStateList colors) {
-        mTextView.setTextColor(colors);
-    }
-
-    public void setNeedsEmptyIcon(boolean needsEmptyIcon) {
-        mNeedsEmptyIcon = needsEmptyIcon;
-    }
-
-}
diff --git a/design/src/android/support/design/internal/NavigationMenuPresenter.java b/design/src/android/support/design/internal/NavigationMenuPresenter.java
deleted file mode 100644
index 98ad468..0000000
--- a/design/src/android/support/design/internal/NavigationMenuPresenter.java
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.StyleRes;
-import android.support.design.R;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.view.menu.MenuPresenter;
-import android.support.v7.view.menu.MenuView;
-import android.support.v7.view.menu.SubMenuBuilder;
-import android.support.v7.widget.RecyclerView;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.SubMenu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class NavigationMenuPresenter implements MenuPresenter {
-
-    private static final String STATE_HIERARCHY = "android:menu:list";
-    private static final String STATE_ADAPTER = "android:menu:adapter";
-    private static final String STATE_HEADER = "android:menu:header";
-
-    private NavigationMenuView mMenuView;
-    LinearLayout mHeaderLayout;
-
-    private Callback mCallback;
-    MenuBuilder mMenu;
-    private int mId;
-
-    NavigationMenuAdapter mAdapter;
-    LayoutInflater mLayoutInflater;
-
-    int mTextAppearance;
-    boolean mTextAppearanceSet;
-    ColorStateList mTextColor;
-    ColorStateList mIconTintList;
-    Drawable mItemBackground;
-
-    /**
-     * Padding to be inserted at the top of the list to avoid the first menu item
-     * from being placed underneath the status bar.
-     */
-    private int mPaddingTopDefault;
-
-    /**
-     * Padding for separators between items
-     */
-    int mPaddingSeparator;
-
-    @Override
-    public void initForMenu(Context context, MenuBuilder menu) {
-        mLayoutInflater = LayoutInflater.from(context);
-        mMenu = menu;
-        Resources res = context.getResources();
-        mPaddingSeparator = res.getDimensionPixelOffset(
-                R.dimen.design_navigation_separator_vertical_padding);
-    }
-
-    @Override
-    public MenuView getMenuView(ViewGroup root) {
-        if (mMenuView == null) {
-            mMenuView = (NavigationMenuView) mLayoutInflater.inflate(
-                    R.layout.design_navigation_menu, root, false);
-            if (mAdapter == null) {
-                mAdapter = new NavigationMenuAdapter();
-            }
-            mHeaderLayout = (LinearLayout) mLayoutInflater
-                    .inflate(R.layout.design_navigation_item_header,
-                            mMenuView, false);
-            mMenuView.setAdapter(mAdapter);
-        }
-        return mMenuView;
-    }
-
-    @Override
-    public void updateMenuView(boolean cleared) {
-        if (mAdapter != null) {
-            mAdapter.update();
-        }
-    }
-
-    @Override
-    public void setCallback(Callback cb) {
-        mCallback = cb;
-    }
-
-    @Override
-    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
-        return false;
-    }
-
-    @Override
-    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
-        if (mCallback != null) {
-            mCallback.onCloseMenu(menu, allMenusAreClosing);
-        }
-    }
-
-    @Override
-    public boolean flagActionItems() {
-        return false;
-    }
-
-    @Override
-    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
-        return false;
-    }
-
-    @Override
-    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
-        return false;
-    }
-
-    @Override
-    public int getId() {
-        return mId;
-    }
-
-    public void setId(int id) {
-        mId = id;
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        if (Build.VERSION.SDK_INT >= 11) {
-            // API 9-10 does not support ClassLoaderCreator, therefore things can crash if they're
-            // loaded via different loaders. Rather than crash we just won't save state on those
-            // platforms
-            final Bundle state = new Bundle();
-            if (mMenuView != null) {
-                SparseArray<Parcelable> hierarchy = new SparseArray<>();
-                mMenuView.saveHierarchyState(hierarchy);
-                state.putSparseParcelableArray(STATE_HIERARCHY, hierarchy);
-            }
-            if (mAdapter != null) {
-                state.putBundle(STATE_ADAPTER, mAdapter.createInstanceState());
-            }
-            if (mHeaderLayout != null) {
-                SparseArray<Parcelable> header = new SparseArray<>();
-                mHeaderLayout.saveHierarchyState(header);
-                state.putSparseParcelableArray(STATE_HEADER, header);
-            }
-            return state;
-        }
-        return null;
-    }
-
-    @Override
-    public void onRestoreInstanceState(final Parcelable parcelable) {
-        if (parcelable instanceof Bundle) {
-            Bundle state = (Bundle) parcelable;
-            SparseArray<Parcelable> hierarchy = state.getSparseParcelableArray(STATE_HIERARCHY);
-            if (hierarchy != null) {
-                mMenuView.restoreHierarchyState(hierarchy);
-            }
-            Bundle adapterState = state.getBundle(STATE_ADAPTER);
-            if (adapterState != null) {
-                mAdapter.restoreInstanceState(adapterState);
-            }
-            SparseArray<Parcelable> header = state.getSparseParcelableArray(STATE_HEADER);
-            if (header != null) {
-                mHeaderLayout.restoreHierarchyState(header);
-            }
-        }
-    }
-
-    public void setCheckedItem(MenuItemImpl item) {
-        mAdapter.setCheckedItem(item);
-    }
-
-    public View inflateHeaderView(@LayoutRes int res) {
-        View view = mLayoutInflater.inflate(res, mHeaderLayout, false);
-        addHeaderView(view);
-        return view;
-    }
-
-    public void addHeaderView(@NonNull View view) {
-        mHeaderLayout.addView(view);
-        // The padding on top should be cleared.
-        mMenuView.setPadding(0, 0, 0, mMenuView.getPaddingBottom());
-    }
-
-    public void removeHeaderView(@NonNull View view) {
-        mHeaderLayout.removeView(view);
-        if (mHeaderLayout.getChildCount() == 0) {
-            mMenuView.setPadding(0, mPaddingTopDefault, 0, mMenuView.getPaddingBottom());
-        }
-    }
-
-    public int getHeaderCount() {
-        return mHeaderLayout.getChildCount();
-    }
-
-    public View getHeaderView(int index) {
-        return mHeaderLayout.getChildAt(index);
-    }
-
-    @Nullable
-    public ColorStateList getItemTintList() {
-        return mIconTintList;
-    }
-
-    public void setItemIconTintList(@Nullable ColorStateList tint) {
-        mIconTintList = tint;
-        updateMenuView(false);
-    }
-
-    @Nullable
-    public ColorStateList getItemTextColor() {
-        return mTextColor;
-    }
-
-    public void setItemTextColor(@Nullable ColorStateList textColor) {
-        mTextColor = textColor;
-        updateMenuView(false);
-    }
-
-    public void setItemTextAppearance(@StyleRes int resId) {
-        mTextAppearance = resId;
-        mTextAppearanceSet = true;
-        updateMenuView(false);
-    }
-
-    @Nullable
-    public Drawable getItemBackground() {
-        return mItemBackground;
-    }
-
-    public void setItemBackground(@Nullable Drawable itemBackground) {
-        mItemBackground = itemBackground;
-        updateMenuView(false);
-    }
-
-    public void setUpdateSuspended(boolean updateSuspended) {
-        if (mAdapter != null) {
-            mAdapter.setUpdateSuspended(updateSuspended);
-        }
-    }
-
-    public void dispatchApplyWindowInsets(WindowInsetsCompat insets) {
-        int top = insets.getSystemWindowInsetTop();
-        if (mPaddingTopDefault != top) {
-            mPaddingTopDefault = top;
-            if (mHeaderLayout.getChildCount() == 0) {
-                mMenuView.setPadding(0, mPaddingTopDefault, 0, mMenuView.getPaddingBottom());
-            }
-        }
-        ViewCompat.dispatchApplyWindowInsets(mHeaderLayout, insets);
-    }
-
-    private abstract static class ViewHolder extends RecyclerView.ViewHolder {
-
-        public ViewHolder(View itemView) {
-            super(itemView);
-        }
-
-    }
-
-    private static class NormalViewHolder extends ViewHolder {
-
-        public NormalViewHolder(LayoutInflater inflater, ViewGroup parent,
-                View.OnClickListener listener) {
-            super(inflater.inflate(R.layout.design_navigation_item, parent, false));
-            itemView.setOnClickListener(listener);
-        }
-
-    }
-
-    private static class SubheaderViewHolder extends ViewHolder {
-
-        public SubheaderViewHolder(LayoutInflater inflater, ViewGroup parent) {
-            super(inflater.inflate(R.layout.design_navigation_item_subheader, parent, false));
-        }
-
-    }
-
-    private static class SeparatorViewHolder extends ViewHolder {
-
-        public SeparatorViewHolder(LayoutInflater inflater, ViewGroup parent) {
-            super(inflater.inflate(R.layout.design_navigation_item_separator, parent, false));
-        }
-
-    }
-
-    private static class HeaderViewHolder extends ViewHolder {
-
-        public HeaderViewHolder(View itemView) {
-            super(itemView);
-        }
-
-    }
-
-    /**
-     * Handles click events for the menu items. The items has to be {@link NavigationMenuItemView}.
-     */
-    final View.OnClickListener mOnClickListener = new View.OnClickListener() {
-
-        @Override
-        public void onClick(View v) {
-            NavigationMenuItemView itemView = (NavigationMenuItemView) v;
-            setUpdateSuspended(true);
-            MenuItemImpl item = itemView.getItemData();
-            boolean result = mMenu.performItemAction(item, NavigationMenuPresenter.this, 0);
-            if (item != null && item.isCheckable() && result) {
-                mAdapter.setCheckedItem(item);
-            }
-            setUpdateSuspended(false);
-            updateMenuView(false);
-        }
-
-    };
-
-    private class NavigationMenuAdapter extends RecyclerView.Adapter<ViewHolder> {
-
-        private static final String STATE_CHECKED_ITEM = "android:menu:checked";
-
-        private static final String STATE_ACTION_VIEWS = "android:menu:action_views";
-        private static final int VIEW_TYPE_NORMAL = 0;
-        private static final int VIEW_TYPE_SUBHEADER = 1;
-        private static final int VIEW_TYPE_SEPARATOR = 2;
-        private static final int VIEW_TYPE_HEADER = 3;
-
-        private final ArrayList<NavigationMenuItem> mItems = new ArrayList<>();
-        private MenuItemImpl mCheckedItem;
-        private boolean mUpdateSuspended;
-
-        NavigationMenuAdapter() {
-            prepareMenuItems();
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return position;
-        }
-
-        @Override
-        public int getItemCount() {
-            return mItems.size();
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            NavigationMenuItem item = mItems.get(position);
-            if (item instanceof NavigationMenuSeparatorItem) {
-                return VIEW_TYPE_SEPARATOR;
-            } else if (item instanceof NavigationMenuHeaderItem) {
-                return VIEW_TYPE_HEADER;
-            } else if (item instanceof NavigationMenuTextItem) {
-                NavigationMenuTextItem textItem = (NavigationMenuTextItem) item;
-                if (textItem.getMenuItem().hasSubMenu()) {
-                    return VIEW_TYPE_SUBHEADER;
-                } else {
-                    return VIEW_TYPE_NORMAL;
-                }
-            }
-            throw new RuntimeException("Unknown item type.");
-        }
-
-        @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            switch (viewType) {
-                case VIEW_TYPE_NORMAL:
-                    return new NormalViewHolder(mLayoutInflater, parent, mOnClickListener);
-                case VIEW_TYPE_SUBHEADER:
-                    return new SubheaderViewHolder(mLayoutInflater, parent);
-                case VIEW_TYPE_SEPARATOR:
-                    return new SeparatorViewHolder(mLayoutInflater, parent);
-                case VIEW_TYPE_HEADER:
-                    return new HeaderViewHolder(mHeaderLayout);
-            }
-            return null;
-        }
-
-        @Override
-        public void onBindViewHolder(ViewHolder holder, int position) {
-            switch (getItemViewType(position)) {
-                case VIEW_TYPE_NORMAL: {
-                    NavigationMenuItemView itemView = (NavigationMenuItemView) holder.itemView;
-                    itemView.setIconTintList(mIconTintList);
-                    if (mTextAppearanceSet) {
-                        itemView.setTextAppearance(mTextAppearance);
-                    }
-                    if (mTextColor != null) {
-                        itemView.setTextColor(mTextColor);
-                    }
-                    ViewCompat.setBackground(itemView, mItemBackground != null ?
-                            mItemBackground.getConstantState().newDrawable() : null);
-                    NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
-                    itemView.setNeedsEmptyIcon(item.needsEmptyIcon);
-                    itemView.initialize(item.getMenuItem(), 0);
-                    break;
-                }
-                case VIEW_TYPE_SUBHEADER: {
-                    TextView subHeader = (TextView) holder.itemView;
-                    NavigationMenuTextItem item = (NavigationMenuTextItem) mItems.get(position);
-                    subHeader.setText(item.getMenuItem().getTitle());
-                    break;
-                }
-                case VIEW_TYPE_SEPARATOR: {
-                    NavigationMenuSeparatorItem item =
-                            (NavigationMenuSeparatorItem) mItems.get(position);
-                    holder.itemView.setPadding(0, item.getPaddingTop(), 0,
-                            item.getPaddingBottom());
-                    break;
-                }
-                case VIEW_TYPE_HEADER: {
-                    break;
-                }
-            }
-
-        }
-
-        @Override
-        public void onViewRecycled(ViewHolder holder) {
-            if (holder instanceof NormalViewHolder) {
-                ((NavigationMenuItemView) holder.itemView).recycle();
-            }
-        }
-
-        public void update() {
-            prepareMenuItems();
-            notifyDataSetChanged();
-        }
-
-        /**
-         * Flattens the visible menu items of {@link #mMenu} into {@link #mItems},
-         * while inserting separators between items when necessary.
-         */
-        private void prepareMenuItems() {
-            if (mUpdateSuspended) {
-                return;
-            }
-            mUpdateSuspended = true;
-            mItems.clear();
-            mItems.add(new NavigationMenuHeaderItem());
-
-            int currentGroupId = -1;
-            int currentGroupStart = 0;
-            boolean currentGroupHasIcon = false;
-            for (int i = 0, totalSize = mMenu.getVisibleItems().size(); i < totalSize; i++) {
-                MenuItemImpl item = mMenu.getVisibleItems().get(i);
-                if (item.isChecked()) {
-                    setCheckedItem(item);
-                }
-                if (item.isCheckable()) {
-                    item.setExclusiveCheckable(false);
-                }
-                if (item.hasSubMenu()) {
-                    SubMenu subMenu = item.getSubMenu();
-                    if (subMenu.hasVisibleItems()) {
-                        if (i != 0) {
-                            mItems.add(new NavigationMenuSeparatorItem(mPaddingSeparator, 0));
-                        }
-                        mItems.add(new NavigationMenuTextItem(item));
-                        boolean subMenuHasIcon = false;
-                        int subMenuStart = mItems.size();
-                        for (int j = 0, size = subMenu.size(); j < size; j++) {
-                            MenuItemImpl subMenuItem = (MenuItemImpl) subMenu.getItem(j);
-                            if (subMenuItem.isVisible()) {
-                                if (!subMenuHasIcon && subMenuItem.getIcon() != null) {
-                                    subMenuHasIcon = true;
-                                }
-                                if (subMenuItem.isCheckable()) {
-                                    subMenuItem.setExclusiveCheckable(false);
-                                }
-                                if (item.isChecked()) {
-                                    setCheckedItem(item);
-                                }
-                                mItems.add(new NavigationMenuTextItem(subMenuItem));
-                            }
-                        }
-                        if (subMenuHasIcon) {
-                            appendTransparentIconIfMissing(subMenuStart, mItems.size());
-                        }
-                    }
-                } else {
-                    int groupId = item.getGroupId();
-                    if (groupId != currentGroupId) { // first item in group
-                        currentGroupStart = mItems.size();
-                        currentGroupHasIcon = item.getIcon() != null;
-                        if (i != 0) {
-                            currentGroupStart++;
-                            mItems.add(new NavigationMenuSeparatorItem(
-                                    mPaddingSeparator, mPaddingSeparator));
-                        }
-                    } else if (!currentGroupHasIcon && item.getIcon() != null) {
-                        currentGroupHasIcon = true;
-                        appendTransparentIconIfMissing(currentGroupStart, mItems.size());
-                    }
-                    NavigationMenuTextItem textItem = new NavigationMenuTextItem(item);
-                    textItem.needsEmptyIcon = currentGroupHasIcon;
-                    mItems.add(textItem);
-                    currentGroupId = groupId;
-                }
-            }
-            mUpdateSuspended = false;
-        }
-
-        private void appendTransparentIconIfMissing(int startIndex, int endIndex) {
-            for (int i = startIndex; i < endIndex; i++) {
-                NavigationMenuTextItem textItem = (NavigationMenuTextItem) mItems.get(i);
-                textItem.needsEmptyIcon = true;
-            }
-        }
-
-        public void setCheckedItem(MenuItemImpl checkedItem) {
-            if (mCheckedItem == checkedItem || !checkedItem.isCheckable()) {
-                return;
-            }
-            if (mCheckedItem != null) {
-                mCheckedItem.setChecked(false);
-            }
-            mCheckedItem = checkedItem;
-            checkedItem.setChecked(true);
-        }
-
-        public Bundle createInstanceState() {
-            Bundle state = new Bundle();
-            if (mCheckedItem != null) {
-                state.putInt(STATE_CHECKED_ITEM, mCheckedItem.getItemId());
-            }
-            // Store the states of the action views.
-            SparseArray<ParcelableSparseArray> actionViewStates = new SparseArray<>();
-            for (int i = 0, size = mItems.size(); i < size; i++) {
-                NavigationMenuItem navigationMenuItem = mItems.get(i);
-                if (navigationMenuItem instanceof NavigationMenuTextItem) {
-                    MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
-                    View actionView = item != null ? item.getActionView() : null;
-                    if (actionView != null) {
-                        ParcelableSparseArray container = new ParcelableSparseArray();
-                        actionView.saveHierarchyState(container);
-                        actionViewStates.put(item.getItemId(), container);
-                    }
-                }
-            }
-            state.putSparseParcelableArray(STATE_ACTION_VIEWS, actionViewStates);
-            return state;
-        }
-
-        public void restoreInstanceState(Bundle state) {
-            int checkedItem = state.getInt(STATE_CHECKED_ITEM, 0);
-            if (checkedItem != 0) {
-                mUpdateSuspended = true;
-                for (int i = 0, size = mItems.size(); i < size; i++) {
-                    NavigationMenuItem item = mItems.get(i);
-                    if (item instanceof NavigationMenuTextItem) {
-                        MenuItemImpl menuItem = ((NavigationMenuTextItem) item).getMenuItem();
-                        if (menuItem != null && menuItem.getItemId() == checkedItem) {
-                            setCheckedItem(menuItem);
-                            break;
-                        }
-                    }
-                }
-                mUpdateSuspended = false;
-                prepareMenuItems();
-            }
-            // Restore the states of the action views.
-            SparseArray<ParcelableSparseArray> actionViewStates = state
-                    .getSparseParcelableArray(STATE_ACTION_VIEWS);
-            if (actionViewStates != null) {
-                for (int i = 0, size = mItems.size(); i < size; i++) {
-                    NavigationMenuItem navigationMenuItem = mItems.get(i);
-                    if (!(navigationMenuItem instanceof NavigationMenuTextItem)) {
-                        continue;
-                    }
-                    MenuItemImpl item = ((NavigationMenuTextItem) navigationMenuItem).getMenuItem();
-                    if (item == null) {
-                        continue;
-                    }
-                    View actionView = item.getActionView();
-                    if (actionView == null) {
-                        continue;
-                    }
-                    ParcelableSparseArray container = actionViewStates.get(item.getItemId());
-                    if (container == null) {
-                        continue;
-                    }
-                    actionView.restoreHierarchyState(container);
-                }
-            }
-        }
-
-        public void setUpdateSuspended(boolean updateSuspended) {
-            mUpdateSuspended = updateSuspended;
-        }
-
-    }
-
-    /**
-     * Unified data model for all sorts of navigation menu items.
-     */
-    private interface NavigationMenuItem {
-    }
-
-    /**
-     * Normal or subheader items.
-     */
-    private static class NavigationMenuTextItem implements NavigationMenuItem {
-
-        private final MenuItemImpl mMenuItem;
-
-        boolean needsEmptyIcon;
-
-        NavigationMenuTextItem(MenuItemImpl item) {
-            mMenuItem = item;
-        }
-
-        public MenuItemImpl getMenuItem() {
-            return mMenuItem;
-        }
-
-    }
-
-    /**
-     * Separator items.
-     */
-    private static class NavigationMenuSeparatorItem implements NavigationMenuItem {
-
-        private final int mPaddingTop;
-
-        private final int mPaddingBottom;
-
-        public NavigationMenuSeparatorItem(int paddingTop, int paddingBottom) {
-            mPaddingTop = paddingTop;
-            mPaddingBottom = paddingBottom;
-        }
-
-        public int getPaddingTop() {
-            return mPaddingTop;
-        }
-
-        public int getPaddingBottom() {
-            return mPaddingBottom;
-        }
-
-    }
-
-    /**
-     * Header (not subheader) items.
-     */
-    private static class NavigationMenuHeaderItem implements NavigationMenuItem {
-        NavigationMenuHeaderItem() {
-        }
-        // The actual content is hold by NavigationMenuPresenter#mHeaderLayout.
-    }
-
-}
diff --git a/design/src/android/support/design/internal/NavigationMenuView.java b/design/src/android/support/design/internal/NavigationMenuView.java
deleted file mode 100644
index 711f71e..0000000
--- a/design/src/android/support/design/internal/NavigationMenuView.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.support.annotation.RestrictTo;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuView;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.util.AttributeSet;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class NavigationMenuView extends RecyclerView implements MenuView {
-
-    public NavigationMenuView(Context context) {
-        this(context, null);
-    }
-
-    public NavigationMenuView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NavigationMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
-    }
-
-    @Override
-    public void initialize(MenuBuilder menu) {
-
-    }
-
-    @Override
-    public int getWindowAnimations() {
-        return 0;
-    }
-
-}
diff --git a/design/src/android/support/design/internal/NavigationSubMenu.java b/design/src/android/support/design/internal/NavigationSubMenu.java
deleted file mode 100644
index 1ff1e4f..0000000
--- a/design/src/android/support/design/internal/NavigationSubMenu.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.support.annotation.RestrictTo;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.view.menu.SubMenuBuilder;
-
-/**
- * This is a {@link SubMenuBuilder} that it notifies the parent {@link NavigationMenu} of its menu
- * updates.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class NavigationSubMenu extends SubMenuBuilder {
-
-    public NavigationSubMenu(Context context, NavigationMenu menu, MenuItemImpl item) {
-        super(context, menu, item);
-    }
-
-    @Override
-    public void onItemsChanged(boolean structureChanged) {
-        super.onItemsChanged(structureChanged);
-        ((MenuBuilder) getParentMenu()).onItemsChanged(structureChanged);
-    }
-
-}
diff --git a/design/src/android/support/design/internal/ParcelableSparseArray.java b/design/src/android/support/design/internal/ParcelableSparseArray.java
deleted file mode 100644
index b29000e..0000000
--- a/design/src/android/support/design/internal/ParcelableSparseArray.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.RestrictTo;
-import android.util.SparseArray;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class ParcelableSparseArray extends SparseArray<Parcelable> implements Parcelable {
-
-    public ParcelableSparseArray() {
-        super();
-    }
-
-    public ParcelableSparseArray(Parcel source, ClassLoader loader) {
-        super();
-        int size = source.readInt();
-        int[] keys = new int[size];
-        source.readIntArray(keys);
-        Parcelable[] values = source.readParcelableArray(loader);
-        for (int i = 0; i < size; ++i) {
-            put(keys[i], values[i]);
-        }
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        int size = size();
-        int[] keys = new int[size];
-        Parcelable[] values = new Parcelable[size];
-        for (int i = 0; i < size; ++i) {
-            keys[i] = keyAt(i);
-            values[i] = valueAt(i);
-        }
-        parcel.writeInt(size);
-        parcel.writeIntArray(keys);
-        parcel.writeParcelableArray(values, flags);
-    }
-
-    public static final Creator<ParcelableSparseArray> CREATOR =
-            new ClassLoaderCreator<ParcelableSparseArray>() {
-                @Override
-                public ParcelableSparseArray createFromParcel(Parcel source, ClassLoader loader) {
-                    return new ParcelableSparseArray(source, loader);
-                }
-
-                @Override
-                public ParcelableSparseArray createFromParcel(Parcel source) {
-                    return new ParcelableSparseArray(source, null);
-                }
-
-                @Override
-                public ParcelableSparseArray[] newArray(int size) {
-                    return new ParcelableSparseArray[size];
-                }
-            };
-}
diff --git a/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java b/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
deleted file mode 100644
index 38f5b29..0000000
--- a/design/src/android/support/design/internal/ScrimInsetsFrameLayout.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.design.R;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.FrameLayout;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class ScrimInsetsFrameLayout extends FrameLayout {
-
-    Drawable mInsetForeground;
-
-    Rect mInsets;
-
-    private Rect mTempRect = new Rect();
-
-    public ScrimInsetsFrameLayout(Context context) {
-        this(context, null);
-    }
-
-    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        final TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.ScrimInsetsFrameLayout, defStyleAttr,
-                R.style.Widget_Design_ScrimInsetsFrameLayout);
-        mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsFrameLayout_insetForeground);
-        a.recycle();
-        setWillNotDraw(true); // No need to draw until the insets are adjusted
-
-        ViewCompat.setOnApplyWindowInsetsListener(this,
-                new android.support.v4.view.OnApplyWindowInsetsListener() {
-                    @Override
-                    public WindowInsetsCompat onApplyWindowInsets(View v,
-                            WindowInsetsCompat insets) {
-                        if (null == mInsets) {
-                            mInsets = new Rect();
-                        }
-                        mInsets.set(insets.getSystemWindowInsetLeft(),
-                                insets.getSystemWindowInsetTop(),
-                                insets.getSystemWindowInsetRight(),
-                                insets.getSystemWindowInsetBottom());
-                        onInsetsChanged(insets);
-                        setWillNotDraw(!insets.hasSystemWindowInsets() || mInsetForeground == null);
-                        ViewCompat.postInvalidateOnAnimation(ScrimInsetsFrameLayout.this);
-                        return insets.consumeSystemWindowInsets();
-                    }
-                });
-    }
-
-    @Override
-    public void draw(@NonNull Canvas canvas) {
-        super.draw(canvas);
-
-        int width = getWidth();
-        int height = getHeight();
-        if (mInsets != null && mInsetForeground != null) {
-            int sc = canvas.save();
-            canvas.translate(getScrollX(), getScrollY());
-
-            // Top
-            mTempRect.set(0, 0, width, mInsets.top);
-            mInsetForeground.setBounds(mTempRect);
-            mInsetForeground.draw(canvas);
-
-            // Bottom
-            mTempRect.set(0, height - mInsets.bottom, width, height);
-            mInsetForeground.setBounds(mTempRect);
-            mInsetForeground.draw(canvas);
-
-            // Left
-            mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
-            mInsetForeground.setBounds(mTempRect);
-            mInsetForeground.draw(canvas);
-
-            // Right
-            mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
-            mInsetForeground.setBounds(mTempRect);
-            mInsetForeground.draw(canvas);
-
-            canvas.restoreToCount(sc);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mInsetForeground != null) {
-            mInsetForeground.setCallback(this);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mInsetForeground != null) {
-            mInsetForeground.setCallback(null);
-        }
-    }
-
-    protected void onInsetsChanged(WindowInsetsCompat insets) {
-    }
-
-}
diff --git a/design/src/android/support/design/internal/SnackbarContentLayout.java b/design/src/android/support/design/internal/SnackbarContentLayout.java
deleted file mode 100644
index 2abf012..0000000
--- a/design/src/android/support/design/internal/SnackbarContentLayout.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.annotation.RestrictTo;
-import android.support.design.R;
-import android.support.design.widget.BaseTransientBottomBar;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class SnackbarContentLayout extends LinearLayout implements
-        BaseTransientBottomBar.ContentViewCallback {
-    private TextView mMessageView;
-    private Button mActionView;
-
-    private int mMaxWidth;
-    private int mMaxInlineActionWidth;
-
-    public SnackbarContentLayout(Context context) {
-        this(context, null);
-    }
-
-    public SnackbarContentLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SnackbarLayout);
-        mMaxWidth = a.getDimensionPixelSize(R.styleable.SnackbarLayout_android_maxWidth, -1);
-        mMaxInlineActionWidth = a.getDimensionPixelSize(
-                R.styleable.SnackbarLayout_maxActionInlineWidth, -1);
-        a.recycle();
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mMessageView = findViewById(R.id.snackbar_text);
-        mActionView = findViewById(R.id.snackbar_action);
-    }
-
-    public TextView getMessageView() {
-        return mMessageView;
-    }
-
-    public Button getActionView() {
-        return mActionView;
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        if (mMaxWidth > 0 && getMeasuredWidth() > mMaxWidth) {
-            widthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY);
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-
-        final int multiLineVPadding = getResources().getDimensionPixelSize(
-                R.dimen.design_snackbar_padding_vertical_2lines);
-        final int singleLineVPadding = getResources().getDimensionPixelSize(
-                R.dimen.design_snackbar_padding_vertical);
-        final boolean isMultiLine = mMessageView.getLayout().getLineCount() > 1;
-
-        boolean remeasure = false;
-        if (isMultiLine && mMaxInlineActionWidth > 0
-                && mActionView.getMeasuredWidth() > mMaxInlineActionWidth) {
-            if (updateViewsWithinLayout(VERTICAL, multiLineVPadding,
-                    multiLineVPadding - singleLineVPadding)) {
-                remeasure = true;
-            }
-        } else {
-            final int messagePadding = isMultiLine ? multiLineVPadding : singleLineVPadding;
-            if (updateViewsWithinLayout(HORIZONTAL, messagePadding, messagePadding)) {
-                remeasure = true;
-            }
-        }
-
-        if (remeasure) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-    }
-
-    private boolean updateViewsWithinLayout(final int orientation,
-            final int messagePadTop, final int messagePadBottom) {
-        boolean changed = false;
-        if (orientation != getOrientation()) {
-            setOrientation(orientation);
-            changed = true;
-        }
-        if (mMessageView.getPaddingTop() != messagePadTop
-                || mMessageView.getPaddingBottom() != messagePadBottom) {
-            updateTopBottomPadding(mMessageView, messagePadTop, messagePadBottom);
-            changed = true;
-        }
-        return changed;
-    }
-
-    private static void updateTopBottomPadding(View view, int topPadding, int bottomPadding) {
-        if (ViewCompat.isPaddingRelative(view)) {
-            ViewCompat.setPaddingRelative(view,
-                    ViewCompat.getPaddingStart(view), topPadding,
-                    ViewCompat.getPaddingEnd(view), bottomPadding);
-        } else {
-            view.setPadding(view.getPaddingLeft(), topPadding,
-                    view.getPaddingRight(), bottomPadding);
-        }
-    }
-
-    @Override
-    public void animateContentIn(int delay, int duration) {
-        mMessageView.setAlpha(0f);
-        mMessageView.animate().alpha(1f).setDuration(duration)
-                .setStartDelay(delay).start();
-
-        if (mActionView.getVisibility() == VISIBLE) {
-            mActionView.setAlpha(0f);
-            mActionView.animate().alpha(1f).setDuration(duration)
-                    .setStartDelay(delay).start();
-        }
-    }
-
-    @Override
-    public void animateContentOut(int delay, int duration) {
-        mMessageView.setAlpha(1f);
-        mMessageView.animate().alpha(0f).setDuration(duration)
-                .setStartDelay(delay).start();
-
-        if (mActionView.getVisibility() == VISIBLE) {
-            mActionView.setAlpha(1f);
-            mActionView.animate().alpha(0f).setDuration(duration)
-                    .setStartDelay(delay).start();
-        }
-    }
-}
diff --git a/design/src/android/support/design/internal/TextScale.java b/design/src/android/support/design/internal/TextScale.java
deleted file mode 100644
index 06c9472..0000000
--- a/design/src/android/support/design/internal/TextScale.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.internal;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.transition.Transition;
-import android.support.transition.TransitionValues;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import java.util.Map;
-
-/**
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-@RequiresApi(14)
-public class TextScale extends Transition {
-    private static final String PROPNAME_SCALE = "android:textscale:scale";
-
-    @Override
-    public void captureStartValues(TransitionValues transitionValues) {
-        captureValues(transitionValues);
-    }
-
-    @Override
-    public void captureEndValues(TransitionValues transitionValues) {
-        captureValues(transitionValues);
-    }
-
-    private void captureValues(TransitionValues transitionValues) {
-        if (transitionValues.view instanceof TextView) {
-            TextView textview = (TextView) transitionValues.view;
-            transitionValues.values.put(PROPNAME_SCALE, textview.getScaleX());
-        }
-    }
-
-    @Override
-    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-            TransitionValues endValues) {
-        if (startValues == null || endValues == null || !(startValues.view instanceof TextView)
-                || !(endValues.view instanceof TextView)) {
-            return null;
-        }
-        final TextView view = (TextView) endValues.view;
-        Map<String, Object> startVals = startValues.values;
-        Map<String, Object> endVals = endValues.values;
-        final float startSize = startVals.get(PROPNAME_SCALE) != null ? (float) startVals.get(
-                PROPNAME_SCALE) : 1f;
-        final float endSize = endVals.get(PROPNAME_SCALE) != null ? (float) endVals.get(
-                PROPNAME_SCALE) : 1f;
-        if (startSize == endSize) {
-            return null;
-        }
-
-        ValueAnimator animator = ValueAnimator.ofFloat(startSize, endSize);
-
-        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                float animatedValue = (float) valueAnimator.getAnimatedValue();
-                view.setScaleX(animatedValue);
-                view.setScaleY(animatedValue);
-            }
-        });
-        return animator;
-    }
-}
diff --git a/design/src/android/support/design/internal/package-info.java b/design/src/android/support/design/internal/package-info.java
deleted file mode 100644
index 6b6f7bb..0000000
--- a/design/src/android/support/design/internal/package-info.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-package android.support.design.internal;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.RestrictTo;
diff --git a/design/src/android/support/design/widget/AppBarLayout.java b/design/src/android/support/design/widget/AppBarLayout.java
deleted file mode 100644
index 8304cd6..0000000
--- a/design/src/android/support/design/widget/AppBarLayout.java
+++ /dev/null
@@ -1,1474 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
-import android.support.design.R;
-import android.support.v4.math.MathUtils;
-import android.support.v4.util.ObjectsCompat;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-import android.widget.LinearLayout;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * AppBarLayout is a vertical {@link LinearLayout} which implements many of the features of
- * material designs app bar concept, namely scrolling gestures.
- * <p>
- * Children should provide their desired scrolling behavior through
- * {@link LayoutParams#setScrollFlags(int)} and the associated layout xml attribute:
- * {@code app:layout_scrollFlags}.
- *
- * <p>
- * This view depends heavily on being used as a direct child within a {@link CoordinatorLayout}.
- * If you use AppBarLayout within a different {@link ViewGroup}, most of it's functionality will
- * not work.
- * <p>
- * AppBarLayout also requires a separate scrolling sibling in order to know when to scroll.
- * The binding is done through the {@link ScrollingViewBehavior} behavior class, meaning that you
- * should set your scrolling view's behavior to be an instance of {@link ScrollingViewBehavior}.
- * A string resource containing the full class name is available.
- *
- * <pre>
- * &lt;android.support.design.widget.CoordinatorLayout
- *         xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
- *         xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
- *         android:layout_width=&quot;match_parent&quot;
- *         android:layout_height=&quot;match_parent&quot;&gt;
- *
- *     &lt;android.support.v4.widget.NestedScrollView
- *             android:layout_width=&quot;match_parent&quot;
- *             android:layout_height=&quot;match_parent&quot;
- *             app:layout_behavior=&quot;@string/appbar_scrolling_view_behavior&quot;&gt;
- *
- *         &lt;!-- Your scrolling content --&gt;
- *
- *     &lt;/android.support.v4.widget.NestedScrollView&gt;
- *
- *     &lt;android.support.design.widget.AppBarLayout
- *             android:layout_height=&quot;wrap_content&quot;
- *             android:layout_width=&quot;match_parent&quot;&gt;
- *
- *         &lt;android.support.v7.widget.Toolbar
- *                 ...
- *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
- *
- *         &lt;android.support.design.widget.TabLayout
- *                 ...
- *                 app:layout_scrollFlags=&quot;scroll|enterAlways&quot;/&gt;
- *
- *     &lt;/android.support.design.widget.AppBarLayout&gt;
- *
- * &lt;/android.support.design.widget.CoordinatorLayout&gt;
- * </pre>
- *
- * @see <a href="http://www.google.com/design/spec/layout/structure.html#structure-app-bar">
- *     http://www.google.com/design/spec/layout/structure.html#structure-app-bar</a>
- */
-@CoordinatorLayout.DefaultBehavior(AppBarLayout.Behavior.class)
-public class AppBarLayout extends LinearLayout {
-
-    static final int PENDING_ACTION_NONE = 0x0;
-    static final int PENDING_ACTION_EXPANDED = 0x1;
-    static final int PENDING_ACTION_COLLAPSED = 0x2;
-    static final int PENDING_ACTION_ANIMATE_ENABLED = 0x4;
-    static final int PENDING_ACTION_FORCE = 0x8;
-
-    /**
-     * Interface definition for a callback to be invoked when an {@link AppBarLayout}'s vertical
-     * offset changes.
-     */
-    public interface OnOffsetChangedListener {
-        /**
-         * Called when the {@link AppBarLayout}'s layout offset has been changed. This allows
-         * child views to implement custom behavior based on the offset (for instance pinning a
-         * view at a certain y value).
-         *
-         * @param appBarLayout the {@link AppBarLayout} which offset has changed
-         * @param verticalOffset the vertical offset for the parent {@link AppBarLayout}, in px
-         */
-        void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset);
-    }
-
-    private static final int INVALID_SCROLL_RANGE = -1;
-
-    private int mTotalScrollRange = INVALID_SCROLL_RANGE;
-    private int mDownPreScrollRange = INVALID_SCROLL_RANGE;
-    private int mDownScrollRange = INVALID_SCROLL_RANGE;
-
-    private boolean mHaveChildWithInterpolator;
-
-    private int mPendingAction = PENDING_ACTION_NONE;
-
-    private WindowInsetsCompat mLastInsets;
-
-    private List<OnOffsetChangedListener> mListeners;
-
-    private boolean mCollapsible;
-    private boolean mCollapsed;
-
-    private int[] mTmpStatesArray;
-
-    public AppBarLayout(Context context) {
-        this(context, null);
-    }
-
-    public AppBarLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        setOrientation(VERTICAL);
-
-        ThemeUtils.checkAppCompatTheme(context);
-
-        if (Build.VERSION.SDK_INT >= 21) {
-            // Use the bounds view outline provider so that we cast a shadow, even without a
-            // background
-            ViewUtilsLollipop.setBoundsViewOutlineProvider(this);
-
-            // If we're running on API 21+, we should reset any state list animator from our
-            // default style
-            ViewUtilsLollipop.setStateListAnimatorFromAttrs(this, attrs, 0,
-                    R.style.Widget_Design_AppBarLayout);
-        }
-
-        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AppBarLayout,
-                0, R.style.Widget_Design_AppBarLayout);
-        ViewCompat.setBackground(this, a.getDrawable(R.styleable.AppBarLayout_android_background));
-        if (a.hasValue(R.styleable.AppBarLayout_expanded)) {
-            setExpanded(a.getBoolean(R.styleable.AppBarLayout_expanded, false), false, false);
-        }
-        if (Build.VERSION.SDK_INT >= 21 && a.hasValue(R.styleable.AppBarLayout_elevation)) {
-            ViewUtilsLollipop.setDefaultAppBarLayoutStateListAnimator(
-                    this, a.getDimensionPixelSize(R.styleable.AppBarLayout_elevation, 0));
-        }
-        if (Build.VERSION.SDK_INT >= 26) {
-            // In O+, we have these values set in the style. Since there is no defStyleAttr for
-            // AppBarLayout at the AppCompat level, check for these attributes here.
-            if (a.hasValue(R.styleable.AppBarLayout_android_keyboardNavigationCluster)) {
-                this.setKeyboardNavigationCluster(a.getBoolean(
-                        R.styleable.AppBarLayout_android_keyboardNavigationCluster, false));
-            }
-            if (a.hasValue(R.styleable.AppBarLayout_android_touchscreenBlocksFocus)) {
-                this.setTouchscreenBlocksFocus(a.getBoolean(
-                        R.styleable.AppBarLayout_android_touchscreenBlocksFocus, false));
-            }
-        }
-        a.recycle();
-
-        ViewCompat.setOnApplyWindowInsetsListener(this,
-                new android.support.v4.view.OnApplyWindowInsetsListener() {
-                    @Override
-                    public WindowInsetsCompat onApplyWindowInsets(View v,
-                            WindowInsetsCompat insets) {
-                        return onWindowInsetChanged(insets);
-                    }
-                });
-    }
-
-    /**
-     * Add a listener that will be called when the offset of this {@link AppBarLayout} changes.
-     *
-     * @param listener The listener that will be called when the offset changes.]
-     *
-     * @see #removeOnOffsetChangedListener(OnOffsetChangedListener)
-     */
-    public void addOnOffsetChangedListener(OnOffsetChangedListener listener) {
-        if (mListeners == null) {
-            mListeners = new ArrayList<>();
-        }
-        if (listener != null && !mListeners.contains(listener)) {
-            mListeners.add(listener);
-        }
-    }
-
-    /**
-     * Remove the previously added {@link OnOffsetChangedListener}.
-     *
-     * @param listener the listener to remove.
-     */
-    public void removeOnOffsetChangedListener(OnOffsetChangedListener listener) {
-        if (mListeners != null && listener != null) {
-            mListeners.remove(listener);
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        invalidateScrollRanges();
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        super.onLayout(changed, l, t, r, b);
-        invalidateScrollRanges();
-
-        mHaveChildWithInterpolator = false;
-        for (int i = 0, z = getChildCount(); i < z; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
-            final Interpolator interpolator = childLp.getScrollInterpolator();
-
-            if (interpolator != null) {
-                mHaveChildWithInterpolator = true;
-                break;
-            }
-        }
-
-        updateCollapsible();
-    }
-
-    private void updateCollapsible() {
-        boolean haveCollapsibleChild = false;
-        for (int i = 0, z = getChildCount(); i < z; i++) {
-            if (((LayoutParams) getChildAt(i).getLayoutParams()).isCollapsible()) {
-                haveCollapsibleChild = true;
-                break;
-            }
-        }
-        setCollapsibleState(haveCollapsibleChild);
-    }
-
-    private void invalidateScrollRanges() {
-        // Invalidate the scroll ranges
-        mTotalScrollRange = INVALID_SCROLL_RANGE;
-        mDownPreScrollRange = INVALID_SCROLL_RANGE;
-        mDownScrollRange = INVALID_SCROLL_RANGE;
-    }
-
-    @Override
-    public void setOrientation(int orientation) {
-        if (orientation != VERTICAL) {
-            throw new IllegalArgumentException("AppBarLayout is always vertical and does"
-                    + " not support horizontal orientation");
-        }
-        super.setOrientation(orientation);
-    }
-
-    /**
-     * Sets whether this {@link AppBarLayout} is expanded or not, animating if it has already
-     * been laid out.
-     *
-     * <p>As with {@link AppBarLayout}'s scrolling, this method relies on this layout being a
-     * direct child of a {@link CoordinatorLayout}.</p>
-     *
-     * @param expanded true if the layout should be fully expanded, false if it should
-     *                 be fully collapsed
-     *
-     * @attr ref android.support.design.R.styleable#AppBarLayout_expanded
-     */
-    public void setExpanded(boolean expanded) {
-        setExpanded(expanded, ViewCompat.isLaidOut(this));
-    }
-
-    /**
-     * Sets whether this {@link AppBarLayout} is expanded or not.
-     *
-     * <p>As with {@link AppBarLayout}'s scrolling, this method relies on this layout being a
-     * direct child of a {@link CoordinatorLayout}.</p>
-     *
-     * @param expanded true if the layout should be fully expanded, false if it should
-     *                 be fully collapsed
-     * @param animate Whether to animate to the new state
-     *
-     * @attr ref android.support.design.R.styleable#AppBarLayout_expanded
-     */
-    public void setExpanded(boolean expanded, boolean animate) {
-        setExpanded(expanded, animate, true);
-    }
-
-    private void setExpanded(boolean expanded, boolean animate, boolean force) {
-        mPendingAction = (expanded ? PENDING_ACTION_EXPANDED : PENDING_ACTION_COLLAPSED)
-                | (animate ? PENDING_ACTION_ANIMATE_ENABLED : 0)
-                | (force ? PENDING_ACTION_FORCE : 0);
-        requestLayout();
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    @Override
-    protected LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
-    }
-
-    @Override
-    public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        if (Build.VERSION.SDK_INT >= 19 && p instanceof LinearLayout.LayoutParams) {
-            return new LayoutParams((LinearLayout.LayoutParams) p);
-        } else if (p instanceof MarginLayoutParams) {
-            return new LayoutParams((MarginLayoutParams) p);
-        }
-        return new LayoutParams(p);
-    }
-
-    boolean hasChildWithInterpolator() {
-        return mHaveChildWithInterpolator;
-    }
-
-    /**
-     * Returns the scroll range of all children.
-     *
-     * @return the scroll range in px
-     */
-    public final int getTotalScrollRange() {
-        if (mTotalScrollRange != INVALID_SCROLL_RANGE) {
-            return mTotalScrollRange;
-        }
-
-        int range = 0;
-        for (int i = 0, z = getChildCount(); i < z; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final int childHeight = child.getMeasuredHeight();
-            final int flags = lp.mScrollFlags;
-
-            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
-                // We're set to scroll so add the child's height
-                range += childHeight + lp.topMargin + lp.bottomMargin;
-
-                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
-                    // For a collapsing scroll, we to take the collapsed height into account.
-                    // We also break straight away since later views can't scroll beneath
-                    // us
-                    range -= ViewCompat.getMinimumHeight(child);
-                    break;
-                }
-            } else {
-                // As soon as a view doesn't have the scroll flag, we end the range calculation.
-                // This is because views below can not scroll under a fixed view.
-                break;
-            }
-        }
-        return mTotalScrollRange = Math.max(0, range - getTopInset());
-    }
-
-    boolean hasScrollableChildren() {
-        return getTotalScrollRange() != 0;
-    }
-
-    /**
-     * Return the scroll range when scrolling up from a nested pre-scroll.
-     */
-    int getUpNestedPreScrollRange() {
-        return getTotalScrollRange();
-    }
-
-    /**
-     * Return the scroll range when scrolling down from a nested pre-scroll.
-     */
-    int getDownNestedPreScrollRange() {
-        if (mDownPreScrollRange != INVALID_SCROLL_RANGE) {
-            // If we already have a valid value, return it
-            return mDownPreScrollRange;
-        }
-
-        int range = 0;
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            final int childHeight = child.getMeasuredHeight();
-            final int flags = lp.mScrollFlags;
-
-            if ((flags & LayoutParams.FLAG_QUICK_RETURN) == LayoutParams.FLAG_QUICK_RETURN) {
-                // First take the margin into account
-                range += lp.topMargin + lp.bottomMargin;
-                // The view has the quick return flag combination...
-                if ((flags & LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED) != 0) {
-                    // If they're set to enter collapsed, use the minimum height
-                    range += ViewCompat.getMinimumHeight(child);
-                } else if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
-                    // Only enter by the amount of the collapsed height
-                    range += childHeight - ViewCompat.getMinimumHeight(child);
-                } else {
-                    // Else use the full height (minus the top inset)
-                    range += childHeight - getTopInset();
-                }
-            } else if (range > 0) {
-                // If we've hit an non-quick return scrollable view, and we've already hit a
-                // quick return view, return now
-                break;
-            }
-        }
-        return mDownPreScrollRange = Math.max(0, range);
-    }
-
-    /**
-     * Return the scroll range when scrolling down from a nested scroll.
-     */
-    int getDownNestedScrollRange() {
-        if (mDownScrollRange != INVALID_SCROLL_RANGE) {
-            // If we already have a valid value, return it
-            return mDownScrollRange;
-        }
-
-        int range = 0;
-        for (int i = 0, z = getChildCount(); i < z; i++) {
-            final View child = getChildAt(i);
-            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-            int childHeight = child.getMeasuredHeight();
-            childHeight += lp.topMargin + lp.bottomMargin;
-
-            final int flags = lp.mScrollFlags;
-
-            if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
-                // We're set to scroll so add the child's height
-                range += childHeight;
-
-                if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
-                    // For a collapsing exit scroll, we to take the collapsed height into account.
-                    // We also break the range straight away since later views can't scroll
-                    // beneath us
-                    range -= ViewCompat.getMinimumHeight(child) + getTopInset();
-                    break;
-                }
-            } else {
-                // As soon as a view doesn't have the scroll flag, we end the range calculation.
-                // This is because views below can not scroll under a fixed view.
-                break;
-            }
-        }
-        return mDownScrollRange = Math.max(0, range);
-    }
-
-    void dispatchOffsetUpdates(int offset) {
-        // Iterate backwards through the list so that most recently added listeners
-        // get the first chance to decide
-        if (mListeners != null) {
-            for (int i = 0, z = mListeners.size(); i < z; i++) {
-                final OnOffsetChangedListener listener = mListeners.get(i);
-                if (listener != null) {
-                    listener.onOffsetChanged(this, offset);
-                }
-            }
-        }
-    }
-
-    final int getMinimumHeightForVisibleOverlappingContent() {
-        final int topInset = getTopInset();
-        final int minHeight = ViewCompat.getMinimumHeight(this);
-        if (minHeight != 0) {
-            // If this layout has a min height, use it (doubled)
-            return (minHeight * 2) + topInset;
-        }
-
-        // Otherwise, we'll use twice the min height of our last child
-        final int childCount = getChildCount();
-        final int lastChildMinHeight = childCount >= 1
-                ? ViewCompat.getMinimumHeight(getChildAt(childCount - 1)) : 0;
-        if (lastChildMinHeight != 0) {
-            return (lastChildMinHeight * 2) + topInset;
-        }
-
-        // If we reach here then we don't have a min height explicitly set. Instead we'll take a
-        // guess at 1/3 of our height being visible
-        return getHeight() / 3;
-    }
-
-    @Override
-    protected int[] onCreateDrawableState(int extraSpace) {
-        if (mTmpStatesArray == null) {
-            // Note that we can't allocate this at the class level (in declaration) since
-            // some paths in super View constructor are going to call this method before
-            // that
-            mTmpStatesArray = new int[2];
-        }
-        final int[] extraStates = mTmpStatesArray;
-        final int[] states = super.onCreateDrawableState(extraSpace + extraStates.length);
-
-        extraStates[0] = mCollapsible ? R.attr.state_collapsible : -R.attr.state_collapsible;
-        extraStates[1] = mCollapsible && mCollapsed
-                ? R.attr.state_collapsed : -R.attr.state_collapsed;
-
-        return mergeDrawableStates(states, extraStates);
-    }
-
-    /**
-     * Sets whether the AppBarLayout has collapsible children or not.
-     *
-     * @return true if the collapsible state changed
-     */
-    private boolean setCollapsibleState(boolean collapsible) {
-        if (mCollapsible != collapsible) {
-            mCollapsible = collapsible;
-            refreshDrawableState();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Sets whether the AppBarLayout is in a collapsed state or not.
-     *
-     * @return true if the collapsed state changed
-     */
-    boolean setCollapsedState(boolean collapsed) {
-        if (mCollapsed != collapsed) {
-            mCollapsed = collapsed;
-            refreshDrawableState();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @deprecated target elevation is now deprecated. AppBarLayout's elevation is now
-     * controlled via a {@link android.animation.StateListAnimator}. If a target
-     * elevation is set, either by this method or the {@code app:elevation} attribute,
-     * a new state list animator is created which uses the given {@code elevation} value.
-     *
-     * @attr ref android.support.design.R.styleable#AppBarLayout_elevation
-     */
-    @Deprecated
-    public void setTargetElevation(float elevation) {
-        if (Build.VERSION.SDK_INT >= 21) {
-            ViewUtilsLollipop.setDefaultAppBarLayoutStateListAnimator(this, elevation);
-        }
-    }
-
-    /**
-     * @deprecated target elevation is now deprecated. AppBarLayout's elevation is now
-     * controlled via a {@link android.animation.StateListAnimator}. This method now
-     * always returns 0.
-     */
-    @Deprecated
-    public float getTargetElevation() {
-        return 0;
-    }
-
-    int getPendingAction() {
-        return mPendingAction;
-    }
-
-    void resetPendingAction() {
-        mPendingAction = PENDING_ACTION_NONE;
-    }
-
-    @VisibleForTesting
-    final int getTopInset() {
-        return mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
-    }
-
-    WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
-        WindowInsetsCompat newInsets = null;
-
-        if (ViewCompat.getFitsSystemWindows(this)) {
-            // If we're set to fit system windows, keep the insets
-            newInsets = insets;
-        }
-
-        // If our insets have changed, keep them and invalidate the scroll ranges...
-        if (!ObjectsCompat.equals(mLastInsets, newInsets)) {
-            mLastInsets = newInsets;
-            invalidateScrollRanges();
-        }
-
-        return insets;
-    }
-
-    public static class LayoutParams extends LinearLayout.LayoutParams {
-
-        /** @hide */
-        @RestrictTo(LIBRARY_GROUP)
-        @IntDef(flag=true, value={
-                SCROLL_FLAG_SCROLL,
-                SCROLL_FLAG_EXIT_UNTIL_COLLAPSED,
-                SCROLL_FLAG_ENTER_ALWAYS,
-                SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED,
-                SCROLL_FLAG_SNAP
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface ScrollFlags {}
-
-        /**
-         * The view will be scroll in direct relation to scroll events. This flag needs to be
-         * set for any of the other flags to take effect. If any sibling views
-         * before this one do not have this flag, then this value has no effect.
-         */
-        public static final int SCROLL_FLAG_SCROLL = 0x1;
-
-        /**
-         * When exiting (scrolling off screen) the view will be scrolled until it is
-         * 'collapsed'. The collapsed height is defined by the view's minimum height.
-         *
-         * @see ViewCompat#getMinimumHeight(View)
-         * @see View#setMinimumHeight(int)
-         */
-        public static final int SCROLL_FLAG_EXIT_UNTIL_COLLAPSED = 0x2;
-
-        /**
-         * When entering (scrolling on screen) the view will scroll on any downwards
-         * scroll event, regardless of whether the scrolling view is also scrolling. This
-         * is commonly referred to as the 'quick return' pattern.
-         */
-        public static final int SCROLL_FLAG_ENTER_ALWAYS = 0x4;
-
-        /**
-         * An additional flag for 'enterAlways' which modifies the returning view to
-         * only initially scroll back to it's collapsed height. Once the scrolling view has
-         * reached the end of it's scroll range, the remainder of this view will be scrolled
-         * into view. The collapsed height is defined by the view's minimum height.
-         *
-         * @see ViewCompat#getMinimumHeight(View)
-         * @see View#setMinimumHeight(int)
-         */
-        public static final int SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED = 0x8;
-
-        /**
-         * Upon a scroll ending, if the view is only partially visible then it will be snapped
-         * and scrolled to it's closest edge. For example, if the view only has it's bottom 25%
-         * displayed, it will be scrolled off screen completely. Conversely, if it's bottom 75%
-         * is visible then it will be scrolled fully into view.
-         */
-        public static final int SCROLL_FLAG_SNAP = 0x10;
-
-        /**
-         * Internal flags which allows quick checking features
-         */
-        static final int FLAG_QUICK_RETURN = SCROLL_FLAG_SCROLL | SCROLL_FLAG_ENTER_ALWAYS;
-        static final int FLAG_SNAP = SCROLL_FLAG_SCROLL | SCROLL_FLAG_SNAP;
-        static final int COLLAPSIBLE_FLAGS = SCROLL_FLAG_EXIT_UNTIL_COLLAPSED
-                | SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED;
-
-        int mScrollFlags = SCROLL_FLAG_SCROLL;
-        Interpolator mScrollInterpolator;
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.AppBarLayout_Layout);
-            mScrollFlags = a.getInt(R.styleable.AppBarLayout_Layout_layout_scrollFlags, 0);
-            if (a.hasValue(R.styleable.AppBarLayout_Layout_layout_scrollInterpolator)) {
-                int resId = a.getResourceId(
-                        R.styleable.AppBarLayout_Layout_layout_scrollInterpolator, 0);
-                mScrollInterpolator = android.view.animation.AnimationUtils.loadInterpolator(
-                        c, resId);
-            }
-            a.recycle();
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(int width, int height, float weight) {
-            super(width, height, weight);
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams p) {
-            super(p);
-        }
-
-        public LayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-
-        @RequiresApi(19)
-        public LayoutParams(LinearLayout.LayoutParams source) {
-            // The copy constructor called here only exists on API 19+.
-            super(source);
-        }
-
-        @RequiresApi(19)
-        public LayoutParams(LayoutParams source) {
-            // The copy constructor called here only exists on API 19+.
-            super(source);
-            mScrollFlags = source.mScrollFlags;
-            mScrollInterpolator = source.mScrollInterpolator;
-        }
-
-        /**
-         * Set the scrolling flags.
-         *
-         * @param flags bitwise int of {@link #SCROLL_FLAG_SCROLL},
-         *             {@link #SCROLL_FLAG_EXIT_UNTIL_COLLAPSED}, {@link #SCROLL_FLAG_ENTER_ALWAYS},
-         *             {@link #SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED} and {@link #SCROLL_FLAG_SNAP }.
-         *
-         * @see #getScrollFlags()
-         *
-         * @attr ref android.support.design.R.styleable#AppBarLayout_Layout_layout_scrollFlags
-         */
-        public void setScrollFlags(@ScrollFlags int flags) {
-            mScrollFlags = flags;
-        }
-
-        /**
-         * Returns the scrolling flags.
-         *
-         * @see #setScrollFlags(int)
-         *
-         * @attr ref android.support.design.R.styleable#AppBarLayout_Layout_layout_scrollFlags
-         */
-        @ScrollFlags
-        public int getScrollFlags() {
-            return mScrollFlags;
-        }
-
-        /**
-         * Set the interpolator to when scrolling the view associated with this
-         * {@link LayoutParams}.
-         *
-         * @param interpolator the interpolator to use, or null to use normal 1-to-1 scrolling.
-         *
-         * @attr ref android.support.design.R.styleable#AppBarLayout_Layout_layout_scrollInterpolator
-         * @see #getScrollInterpolator()
-         */
-        public void setScrollInterpolator(Interpolator interpolator) {
-            mScrollInterpolator = interpolator;
-        }
-
-        /**
-         * Returns the {@link Interpolator} being used for scrolling the view associated with this
-         * {@link LayoutParams}. Null indicates 'normal' 1-to-1 scrolling.
-         *
-         * @attr ref android.support.design.R.styleable#AppBarLayout_Layout_layout_scrollInterpolator
-         * @see #setScrollInterpolator(Interpolator)
-         */
-        public Interpolator getScrollInterpolator() {
-            return mScrollInterpolator;
-        }
-
-        /**
-         * Returns true if the scroll flags are compatible for 'collapsing'
-         */
-        boolean isCollapsible() {
-            return (mScrollFlags & SCROLL_FLAG_SCROLL) == SCROLL_FLAG_SCROLL
-                    && (mScrollFlags & COLLAPSIBLE_FLAGS) != 0;
-        }
-    }
-
-    /**
-     * The default {@link Behavior} for {@link AppBarLayout}. Implements the necessary nested
-     * scroll handling with offsetting.
-     */
-    public static class Behavior extends HeaderBehavior<AppBarLayout> {
-        private static final int MAX_OFFSET_ANIMATION_DURATION = 600; // ms
-        private static final int INVALID_POSITION = -1;
-
-        /**
-         * Callback to allow control over any {@link AppBarLayout} dragging.
-         */
-        public static abstract class DragCallback {
-            /**
-             * Allows control over whether the given {@link AppBarLayout} can be dragged or not.
-             *
-             * <p>Dragging is defined as a direct touch on the AppBarLayout with movement. This
-             * call does not affect any nested scrolling.</p>
-             *
-             * @return true if we are in a position to scroll the AppBarLayout via a drag, false
-             *         if not.
-             */
-            public abstract boolean canDrag(@NonNull AppBarLayout appBarLayout);
-        }
-
-        private int mOffsetDelta;
-        private ValueAnimator mOffsetAnimator;
-
-        private int mOffsetToChildIndexOnLayout = INVALID_POSITION;
-        private boolean mOffsetToChildIndexOnLayoutIsMinHeight;
-        private float mOffsetToChildIndexOnLayoutPerc;
-
-        private WeakReference<View> mLastNestedScrollingChildRef;
-        private DragCallback mOnDragCallback;
-
-        public Behavior() {}
-
-        public Behavior(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        @Override
-        public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child,
-                View directTargetChild, View target, int nestedScrollAxes, int type) {
-            // Return true if we're nested scrolling vertically, and we have scrollable children
-            // and the scrolling view is big enough to scroll
-            final boolean started = (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0
-                    && child.hasScrollableChildren()
-                    && parent.getHeight() - directTargetChild.getHeight() <= child.getHeight();
-
-            if (started && mOffsetAnimator != null) {
-                // Cancel any offset animation
-                mOffsetAnimator.cancel();
-            }
-
-            // A new nested scroll has started so clear out the previous ref
-            mLastNestedScrollingChildRef = null;
-
-            return started;
-        }
-
-        @Override
-        public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
-                View target, int dx, int dy, int[] consumed, int type) {
-            if (dy != 0) {
-                int min, max;
-                if (dy < 0) {
-                    // We're scrolling down
-                    min = -child.getTotalScrollRange();
-                    max = min + child.getDownNestedPreScrollRange();
-                } else {
-                    // We're scrolling up
-                    min = -child.getUpNestedPreScrollRange();
-                    max = 0;
-                }
-                if (min != max) {
-                    consumed[1] = scroll(coordinatorLayout, child, dy, min, max);
-                }
-            }
-        }
-
-        @Override
-        public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
-                View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed,
-                int type) {
-            if (dyUnconsumed < 0) {
-                // If the scrolling view is scrolling down but not consuming, it's probably be at
-                // the top of it's content
-                scroll(coordinatorLayout, child, dyUnconsumed,
-                        -child.getDownNestedScrollRange(), 0);
-            }
-        }
-
-        @Override
-        public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout abl,
-                View target, int type) {
-            if (type == ViewCompat.TYPE_TOUCH) {
-                // If we haven't been flung then let's see if the current view has been set to snap
-                snapToChildIfNeeded(coordinatorLayout, abl);
-            }
-
-            // Keep a reference to the previous nested scrolling child
-            mLastNestedScrollingChildRef = new WeakReference<>(target);
-        }
-
-        /**
-         * Set a callback to control any {@link AppBarLayout} dragging.
-         *
-         * @param callback the callback to use, or {@code null} to use the default behavior.
-         */
-        public void setDragCallback(@Nullable DragCallback callback) {
-            mOnDragCallback = callback;
-        }
-
-        private void animateOffsetTo(final CoordinatorLayout coordinatorLayout,
-                final AppBarLayout child, final int offset, float velocity) {
-            final int distance = Math.abs(getTopBottomOffsetForScrollingSibling() - offset);
-
-            final int duration;
-            velocity = Math.abs(velocity);
-            if (velocity > 0) {
-                duration = 3 * Math.round(1000 * (distance / velocity));
-            } else {
-                final float distanceRatio = (float) distance / child.getHeight();
-                duration = (int) ((distanceRatio + 1) * 150);
-            }
-
-            animateOffsetWithDuration(coordinatorLayout, child, offset, duration);
-        }
-
-        private void animateOffsetWithDuration(final CoordinatorLayout coordinatorLayout,
-                final AppBarLayout child, final int offset, final int duration) {
-            final int currentOffset = getTopBottomOffsetForScrollingSibling();
-            if (currentOffset == offset) {
-                if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) {
-                    mOffsetAnimator.cancel();
-                }
-                return;
-            }
-
-            if (mOffsetAnimator == null) {
-                mOffsetAnimator = new ValueAnimator();
-                mOffsetAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
-                mOffsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animation) {
-                        setHeaderTopBottomOffset(coordinatorLayout, child,
-                                (int) animation.getAnimatedValue());
-                    }
-                });
-            } else {
-                mOffsetAnimator.cancel();
-            }
-
-            mOffsetAnimator.setDuration(Math.min(duration, MAX_OFFSET_ANIMATION_DURATION));
-            mOffsetAnimator.setIntValues(currentOffset, offset);
-            mOffsetAnimator.start();
-        }
-
-        private int getChildIndexOnOffset(AppBarLayout abl, final int offset) {
-            for (int i = 0, count = abl.getChildCount(); i < count; i++) {
-                View child = abl.getChildAt(i);
-                if (child.getTop() <= -offset && child.getBottom() >= -offset) {
-                    return i;
-                }
-            }
-            return -1;
-        }
-
-        private void snapToChildIfNeeded(CoordinatorLayout coordinatorLayout, AppBarLayout abl) {
-            final int offset = getTopBottomOffsetForScrollingSibling();
-            final int offsetChildIndex = getChildIndexOnOffset(abl, offset);
-            if (offsetChildIndex >= 0) {
-                final View offsetChild = abl.getChildAt(offsetChildIndex);
-                final LayoutParams lp = (LayoutParams) offsetChild.getLayoutParams();
-                final int flags = lp.getScrollFlags();
-
-                if ((flags & LayoutParams.FLAG_SNAP) == LayoutParams.FLAG_SNAP) {
-                    // We're set the snap, so animate the offset to the nearest edge
-                    int snapTop = -offsetChild.getTop();
-                    int snapBottom = -offsetChild.getBottom();
-
-                    if (offsetChildIndex == abl.getChildCount() - 1) {
-                        // If this is the last child, we need to take the top inset into account
-                        snapBottom += abl.getTopInset();
-                    }
-
-                    if (checkFlag(flags, LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED)) {
-                        // If the view is set only exit until it is collapsed, we'll abide by that
-                        snapBottom += ViewCompat.getMinimumHeight(offsetChild);
-                    } else if (checkFlag(flags, LayoutParams.FLAG_QUICK_RETURN
-                            | LayoutParams.SCROLL_FLAG_ENTER_ALWAYS)) {
-                        // If it's set to always enter collapsed, it actually has two states. We
-                        // select the state and then snap within the state
-                        final int seam = snapBottom + ViewCompat.getMinimumHeight(offsetChild);
-                        if (offset < seam) {
-                            snapTop = seam;
-                        } else {
-                            snapBottom = seam;
-                        }
-                    }
-
-                    final int newOffset = offset < (snapBottom + snapTop) / 2
-                            ? snapBottom
-                            : snapTop;
-                    animateOffsetTo(coordinatorLayout, abl,
-                            MathUtils.clamp(newOffset, -abl.getTotalScrollRange(), 0), 0);
-                }
-            }
-        }
-
-        private static boolean checkFlag(final int flags, final int check) {
-            return (flags & check) == check;
-        }
-
-        @Override
-        public boolean onMeasureChild(CoordinatorLayout parent, AppBarLayout child,
-                int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec,
-                int heightUsed) {
-            final CoordinatorLayout.LayoutParams lp =
-                    (CoordinatorLayout.LayoutParams) child.getLayoutParams();
-            if (lp.height == CoordinatorLayout.LayoutParams.WRAP_CONTENT) {
-                // If the view is set to wrap on it's height, CoordinatorLayout by default will
-                // cap the view at the CoL's height. Since the AppBarLayout can scroll, this isn't
-                // what we actually want, so we measure it ourselves with an unspecified spec to
-                // allow the child to be larger than it's parent
-                parent.onMeasureChild(child, parentWidthMeasureSpec, widthUsed,
-                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightUsed);
-                return true;
-            }
-
-            // Let the parent handle it as normal
-            return super.onMeasureChild(parent, child, parentWidthMeasureSpec, widthUsed,
-                    parentHeightMeasureSpec, heightUsed);
-        }
-
-        @Override
-        public boolean onLayoutChild(CoordinatorLayout parent, AppBarLayout abl,
-                int layoutDirection) {
-            boolean handled = super.onLayoutChild(parent, abl, layoutDirection);
-
-            // The priority for for actions here is (first which is true wins):
-            // 1. forced pending actions
-            // 2. offsets for restorations
-            // 3. non-forced pending actions
-            final int pendingAction = abl.getPendingAction();
-            if (mOffsetToChildIndexOnLayout >= 0 && (pendingAction & PENDING_ACTION_FORCE) == 0) {
-                View child = abl.getChildAt(mOffsetToChildIndexOnLayout);
-                int offset = -child.getBottom();
-                if (mOffsetToChildIndexOnLayoutIsMinHeight) {
-                    offset += ViewCompat.getMinimumHeight(child) + abl.getTopInset();
-                } else {
-                    offset += Math.round(child.getHeight() * mOffsetToChildIndexOnLayoutPerc);
-                }
-                setHeaderTopBottomOffset(parent, abl, offset);
-            } else if (pendingAction != PENDING_ACTION_NONE) {
-                final boolean animate = (pendingAction & PENDING_ACTION_ANIMATE_ENABLED) != 0;
-                if ((pendingAction & PENDING_ACTION_COLLAPSED) != 0) {
-                    final int offset = -abl.getUpNestedPreScrollRange();
-                    if (animate) {
-                        animateOffsetTo(parent, abl, offset, 0);
-                    } else {
-                        setHeaderTopBottomOffset(parent, abl, offset);
-                    }
-                } else if ((pendingAction & PENDING_ACTION_EXPANDED) != 0) {
-                    if (animate) {
-                        animateOffsetTo(parent, abl, 0, 0);
-                    } else {
-                        setHeaderTopBottomOffset(parent, abl, 0);
-                    }
-                }
-            }
-
-            // Finally reset any pending states
-            abl.resetPendingAction();
-            mOffsetToChildIndexOnLayout = INVALID_POSITION;
-
-            // We may have changed size, so let's constrain the top and bottom offset correctly,
-            // just in case we're out of the bounds
-            setTopAndBottomOffset(
-                    MathUtils.clamp(getTopAndBottomOffset(), -abl.getTotalScrollRange(), 0));
-
-            // Update the AppBarLayout's drawable state for any elevation changes.
-            // This is needed so that the elevation is set in the first layout, so that
-            // we don't get a visual elevation jump pre-N (due to the draw dispatch skip)
-            updateAppBarLayoutDrawableState(parent, abl, getTopAndBottomOffset(), 0, true);
-
-            // Make sure we dispatch the offset update
-            abl.dispatchOffsetUpdates(getTopAndBottomOffset());
-
-            return handled;
-        }
-
-        @Override
-        boolean canDragView(AppBarLayout view) {
-            if (mOnDragCallback != null) {
-                // If there is a drag callback set, it's in control
-                return mOnDragCallback.canDrag(view);
-            }
-
-            // Else we'll use the default behaviour of seeing if it can scroll down
-            if (mLastNestedScrollingChildRef != null) {
-                // If we have a reference to a scrolling view, check it
-                final View scrollingView = mLastNestedScrollingChildRef.get();
-                return scrollingView != null && scrollingView.isShown()
-                        && !scrollingView.canScrollVertically(-1);
-            } else {
-                // Otherwise we assume that the scrolling view hasn't been scrolled and can drag.
-                return true;
-            }
-        }
-
-        @Override
-        void onFlingFinished(CoordinatorLayout parent, AppBarLayout layout) {
-            // At the end of a manual fling, check to see if we need to snap to the edge-child
-            snapToChildIfNeeded(parent, layout);
-        }
-
-        @Override
-        int getMaxDragOffset(AppBarLayout view) {
-            return -view.getDownNestedScrollRange();
-        }
-
-        @Override
-        int getScrollRangeForDragFling(AppBarLayout view) {
-            return view.getTotalScrollRange();
-        }
-
-        @Override
-        int setHeaderTopBottomOffset(CoordinatorLayout coordinatorLayout,
-                AppBarLayout appBarLayout, int newOffset, int minOffset, int maxOffset) {
-            final int curOffset = getTopBottomOffsetForScrollingSibling();
-            int consumed = 0;
-
-            if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
-                // If we have some scrolling range, and we're currently within the min and max
-                // offsets, calculate a new offset
-                newOffset = MathUtils.clamp(newOffset, minOffset, maxOffset);
-                if (curOffset != newOffset) {
-                    final int interpolatedOffset = appBarLayout.hasChildWithInterpolator()
-                            ? interpolateOffset(appBarLayout, newOffset)
-                            : newOffset;
-
-                    final boolean offsetChanged = setTopAndBottomOffset(interpolatedOffset);
-
-                    // Update how much dy we have consumed
-                    consumed = curOffset - newOffset;
-                    // Update the stored sibling offset
-                    mOffsetDelta = newOffset - interpolatedOffset;
-
-                    if (!offsetChanged && appBarLayout.hasChildWithInterpolator()) {
-                        // If the offset hasn't changed and we're using an interpolated scroll
-                        // then we need to keep any dependent views updated. CoL will do this for
-                        // us when we move, but we need to do it manually when we don't (as an
-                        // interpolated scroll may finish early).
-                        coordinatorLayout.dispatchDependentViewsChanged(appBarLayout);
-                    }
-
-                    // Dispatch the updates to any listeners
-                    appBarLayout.dispatchOffsetUpdates(getTopAndBottomOffset());
-
-                    // Update the AppBarLayout's drawable state (for any elevation changes)
-                    updateAppBarLayoutDrawableState(coordinatorLayout, appBarLayout, newOffset,
-                            newOffset < curOffset ? -1 : 1, false);
-                }
-            } else {
-                // Reset the offset delta
-                mOffsetDelta = 0;
-            }
-
-            return consumed;
-        }
-
-        @VisibleForTesting
-        boolean isOffsetAnimatorRunning() {
-            return mOffsetAnimator != null && mOffsetAnimator.isRunning();
-        }
-
-        private int interpolateOffset(AppBarLayout layout, final int offset) {
-            final int absOffset = Math.abs(offset);
-
-            for (int i = 0, z = layout.getChildCount(); i < z; i++) {
-                final View child = layout.getChildAt(i);
-                final AppBarLayout.LayoutParams childLp = (LayoutParams) child.getLayoutParams();
-                final Interpolator interpolator = childLp.getScrollInterpolator();
-
-                if (absOffset >= child.getTop() && absOffset <= child.getBottom()) {
-                    if (interpolator != null) {
-                        int childScrollableHeight = 0;
-                        final int flags = childLp.getScrollFlags();
-                        if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
-                            // We're set to scroll so add the child's height plus margin
-                            childScrollableHeight += child.getHeight() + childLp.topMargin
-                                    + childLp.bottomMargin;
-
-                            if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
-                                // For a collapsing scroll, we to take the collapsed height
-                                // into account.
-                                childScrollableHeight -= ViewCompat.getMinimumHeight(child);
-                            }
-                        }
-
-                        if (ViewCompat.getFitsSystemWindows(child)) {
-                            childScrollableHeight -= layout.getTopInset();
-                        }
-
-                        if (childScrollableHeight > 0) {
-                            final int offsetForView = absOffset - child.getTop();
-                            final int interpolatedDiff = Math.round(childScrollableHeight *
-                                    interpolator.getInterpolation(
-                                            offsetForView / (float) childScrollableHeight));
-
-                            return Integer.signum(offset) * (child.getTop() + interpolatedDiff);
-                        }
-                    }
-
-                    // If we get to here then the view on the offset isn't suitable for interpolated
-                    // scrolling. So break out of the loop
-                    break;
-                }
-            }
-
-            return offset;
-        }
-
-        private void updateAppBarLayoutDrawableState(final CoordinatorLayout parent,
-                final AppBarLayout layout, final int offset, final int direction,
-                final boolean forceJump) {
-            final View child = getAppBarChildOnOffset(layout, offset);
-            if (child != null) {
-                final AppBarLayout.LayoutParams childLp = (LayoutParams) child.getLayoutParams();
-                final int flags = childLp.getScrollFlags();
-                boolean collapsed = false;
-
-                if ((flags & LayoutParams.SCROLL_FLAG_SCROLL) != 0) {
-                    final int minHeight = ViewCompat.getMinimumHeight(child);
-
-                    if (direction > 0 && (flags & (LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
-                            | LayoutParams.SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED)) != 0) {
-                        // We're set to enter always collapsed so we are only collapsed when
-                        // being scrolled down, and in a collapsed offset
-                        collapsed = -offset >= child.getBottom() - minHeight - layout.getTopInset();
-                    } else if ((flags & LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED) != 0) {
-                        // We're set to exit until collapsed, so any offset which results in
-                        // the minimum height (or less) being shown is collapsed
-                        collapsed = -offset >= child.getBottom() - minHeight - layout.getTopInset();
-                    }
-                }
-
-                final boolean changed = layout.setCollapsedState(collapsed);
-
-                if (Build.VERSION.SDK_INT >= 11 && (forceJump
-                        || (changed && shouldJumpElevationState(parent, layout)))) {
-                    // If the collapsed state changed, we may need to
-                    // jump to the current state if we have an overlapping view
-                    layout.jumpDrawablesToCurrentState();
-                }
-            }
-        }
-
-        private boolean shouldJumpElevationState(CoordinatorLayout parent, AppBarLayout layout) {
-            // We should jump the elevated state if we have a dependent scrolling view which has
-            // an overlapping top (i.e. overlaps us)
-            final List<View> dependencies = parent.getDependents(layout);
-            for (int i = 0, size = dependencies.size(); i < size; i++) {
-                final View dependency = dependencies.get(i);
-                final CoordinatorLayout.LayoutParams lp =
-                        (CoordinatorLayout.LayoutParams) dependency.getLayoutParams();
-                final CoordinatorLayout.Behavior behavior = lp.getBehavior();
-
-                if (behavior instanceof ScrollingViewBehavior) {
-                    return ((ScrollingViewBehavior) behavior).getOverlayTop() != 0;
-                }
-            }
-            return false;
-        }
-
-        private static View getAppBarChildOnOffset(final AppBarLayout layout, final int offset) {
-            final int absOffset = Math.abs(offset);
-            for (int i = 0, z = layout.getChildCount(); i < z; i++) {
-                final View child = layout.getChildAt(i);
-                if (absOffset >= child.getTop() && absOffset <= child.getBottom()) {
-                    return child;
-                }
-            }
-            return null;
-        }
-
-        @Override
-        int getTopBottomOffsetForScrollingSibling() {
-            return getTopAndBottomOffset() + mOffsetDelta;
-        }
-
-        @Override
-        public Parcelable onSaveInstanceState(CoordinatorLayout parent, AppBarLayout abl) {
-            final Parcelable superState = super.onSaveInstanceState(parent, abl);
-            final int offset = getTopAndBottomOffset();
-
-            // Try and find the first visible child...
-            for (int i = 0, count = abl.getChildCount(); i < count; i++) {
-                View child = abl.getChildAt(i);
-                final int visBottom = child.getBottom() + offset;
-
-                if (child.getTop() + offset <= 0 && visBottom >= 0) {
-                    final SavedState ss = new SavedState(superState);
-                    ss.firstVisibleChildIndex = i;
-                    ss.firstVisibleChildAtMinimumHeight =
-                            visBottom == (ViewCompat.getMinimumHeight(child) + abl.getTopInset());
-                    ss.firstVisibleChildPercentageShown = visBottom / (float) child.getHeight();
-                    return ss;
-                }
-            }
-
-            // Else we'll just return the super state
-            return superState;
-        }
-
-        @Override
-        public void onRestoreInstanceState(CoordinatorLayout parent, AppBarLayout appBarLayout,
-                Parcelable state) {
-            if (state instanceof SavedState) {
-                final SavedState ss = (SavedState) state;
-                super.onRestoreInstanceState(parent, appBarLayout, ss.getSuperState());
-                mOffsetToChildIndexOnLayout = ss.firstVisibleChildIndex;
-                mOffsetToChildIndexOnLayoutPerc = ss.firstVisibleChildPercentageShown;
-                mOffsetToChildIndexOnLayoutIsMinHeight = ss.firstVisibleChildAtMinimumHeight;
-            } else {
-                super.onRestoreInstanceState(parent, appBarLayout, state);
-                mOffsetToChildIndexOnLayout = INVALID_POSITION;
-            }
-        }
-
-        protected static class SavedState extends AbsSavedState {
-            int firstVisibleChildIndex;
-            float firstVisibleChildPercentageShown;
-            boolean firstVisibleChildAtMinimumHeight;
-
-            public SavedState(Parcel source, ClassLoader loader) {
-                super(source, loader);
-                firstVisibleChildIndex = source.readInt();
-                firstVisibleChildPercentageShown = source.readFloat();
-                firstVisibleChildAtMinimumHeight = source.readByte() != 0;
-            }
-
-            public SavedState(Parcelable superState) {
-                super(superState);
-            }
-
-            @Override
-            public void writeToParcel(Parcel dest, int flags) {
-                super.writeToParcel(dest, flags);
-                dest.writeInt(firstVisibleChildIndex);
-                dest.writeFloat(firstVisibleChildPercentageShown);
-                dest.writeByte((byte) (firstVisibleChildAtMinimumHeight ? 1 : 0));
-            }
-
-            public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
-                @Override
-                public SavedState createFromParcel(Parcel source, ClassLoader loader) {
-                    return new SavedState(source, loader);
-                }
-
-                @Override
-                public SavedState createFromParcel(Parcel source) {
-                    return new SavedState(source, null);
-                }
-
-                @Override
-                public SavedState[] newArray(int size) {
-                    return new SavedState[size];
-                }
-            };
-        }
-    }
-
-    /**
-     * Behavior which should be used by {@link View}s which can scroll vertically and support
-     * nested scrolling to automatically scroll any {@link AppBarLayout} siblings.
-     */
-    public static class ScrollingViewBehavior extends HeaderScrollingViewBehavior {
-
-        public ScrollingViewBehavior() {}
-
-        public ScrollingViewBehavior(Context context, AttributeSet attrs) {
-            super(context, attrs);
-
-            final TypedArray a = context.obtainStyledAttributes(attrs,
-                    R.styleable.ScrollingViewBehavior_Layout);
-            setOverlayTop(a.getDimensionPixelSize(
-                    R.styleable.ScrollingViewBehavior_Layout_behavior_overlapTop, 0));
-            a.recycle();
-        }
-
-        @Override
-        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
-            // We depend on any AppBarLayouts
-            return dependency instanceof AppBarLayout;
-        }
-
-        @Override
-        public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
-                View dependency) {
-            offsetChildAsNeeded(parent, child, dependency);
-            return false;
-        }
-
-        @Override
-        public boolean onRequestChildRectangleOnScreen(CoordinatorLayout parent, View child,
-                Rect rectangle, boolean immediate) {
-            final AppBarLayout header = findFirstDependency(parent.getDependencies(child));
-            if (header != null) {
-                // Offset the rect by the child's left/top
-                rectangle.offset(child.getLeft(), child.getTop());
-
-                final Rect parentRect = mTempRect1;
-                parentRect.set(0, 0, parent.getWidth(), parent.getHeight());
-
-                if (!parentRect.contains(rectangle)) {
-                    // If the rectangle can not be fully seen the visible bounds, collapse
-                    // the AppBarLayout
-                    header.setExpanded(false, !immediate);
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        private void offsetChildAsNeeded(CoordinatorLayout parent, View child, View dependency) {
-            final CoordinatorLayout.Behavior behavior =
-                    ((CoordinatorLayout.LayoutParams) dependency.getLayoutParams()).getBehavior();
-            if (behavior instanceof Behavior) {
-                // Offset the child, pinning it to the bottom the header-dependency, maintaining
-                // any vertical gap and overlap
-                final Behavior ablBehavior = (Behavior) behavior;
-                ViewCompat.offsetTopAndBottom(child, (dependency.getBottom() - child.getTop())
-                        + ablBehavior.mOffsetDelta
-                        + getVerticalLayoutGap()
-                        - getOverlapPixelsForOffset(dependency));
-            }
-        }
-
-        @Override
-        float getOverlapRatioForOffset(final View header) {
-            if (header instanceof AppBarLayout) {
-                final AppBarLayout abl = (AppBarLayout) header;
-                final int totalScrollRange = abl.getTotalScrollRange();
-                final int preScrollDown = abl.getDownNestedPreScrollRange();
-                final int offset = getAppBarLayoutOffset(abl);
-
-                if (preScrollDown != 0 && (totalScrollRange + offset) <= preScrollDown) {
-                    // If we're in a pre-scroll down. Don't use the offset at all.
-                    return 0;
-                } else {
-                    final int availScrollRange = totalScrollRange - preScrollDown;
-                    if (availScrollRange != 0) {
-                        // Else we'll use a interpolated ratio of the overlap, depending on offset
-                        return 1f + (offset / (float) availScrollRange);
-                    }
-                }
-            }
-            return 0f;
-        }
-
-        private static int getAppBarLayoutOffset(AppBarLayout abl) {
-            final CoordinatorLayout.Behavior behavior =
-                    ((CoordinatorLayout.LayoutParams) abl.getLayoutParams()).getBehavior();
-            if (behavior instanceof Behavior) {
-                return ((Behavior) behavior).getTopBottomOffsetForScrollingSibling();
-            }
-            return 0;
-        }
-
-        @Override
-        AppBarLayout findFirstDependency(List<View> views) {
-            for (int i = 0, z = views.size(); i < z; i++) {
-                View view = views.get(i);
-                if (view instanceof AppBarLayout) {
-                    return (AppBarLayout) view;
-                }
-            }
-            return null;
-        }
-
-        @Override
-        int getScrollRange(View v) {
-            if (v instanceof AppBarLayout) {
-                return ((AppBarLayout) v).getTotalScrollRange();
-            } else {
-                return super.getScrollRange(v);
-            }
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/BaseTransientBottomBar.java b/design/src/android/support/design/widget/BaseTransientBottomBar.java
deleted file mode 100644
index 18c9ef9..0000000
--- a/design/src/android/support/design/widget/BaseTransientBottomBar.java
+++ /dev/null
@@ -1,753 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-import static android.support.design.widget.AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.design.R;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityManager;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
-import android.widget.FrameLayout;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Base class for lightweight transient bars that are displayed along the bottom edge of the
- * application window.
- *
- * @param <B> The transient bottom bar subclass.
- */
-public abstract class BaseTransientBottomBar<B extends BaseTransientBottomBar<B>> {
-    /**
-     * Base class for {@link BaseTransientBottomBar} callbacks.
-     *
-     * @param <B> The transient bottom bar subclass.
-     * @see BaseTransientBottomBar#addCallback(BaseCallback)
-     */
-    public abstract static class BaseCallback<B> {
-        /** Indicates that the Snackbar was dismissed via a swipe.*/
-        public static final int DISMISS_EVENT_SWIPE = 0;
-        /** Indicates that the Snackbar was dismissed via an action click.*/
-        public static final int DISMISS_EVENT_ACTION = 1;
-        /** Indicates that the Snackbar was dismissed via a timeout.*/
-        public static final int DISMISS_EVENT_TIMEOUT = 2;
-        /** Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}.*/
-        public static final int DISMISS_EVENT_MANUAL = 3;
-        /** Indicates that the Snackbar was dismissed from a new Snackbar being shown.*/
-        public static final int DISMISS_EVENT_CONSECUTIVE = 4;
-
-        /** @hide */
-        @RestrictTo(LIBRARY_GROUP)
-        @IntDef({DISMISS_EVENT_SWIPE, DISMISS_EVENT_ACTION, DISMISS_EVENT_TIMEOUT,
-                DISMISS_EVENT_MANUAL, DISMISS_EVENT_CONSECUTIVE})
-        @Retention(RetentionPolicy.SOURCE)
-        public @interface DismissEvent {}
-
-        /**
-         * Called when the given {@link BaseTransientBottomBar} has been dismissed, either
-         * through a time-out, having been manually dismissed, or an action being clicked.
-         *
-         * @param transientBottomBar The transient bottom bar which has been dismissed.
-         * @param event The event which caused the dismissal. One of either:
-         *              {@link #DISMISS_EVENT_SWIPE}, {@link #DISMISS_EVENT_ACTION},
-         *              {@link #DISMISS_EVENT_TIMEOUT}, {@link #DISMISS_EVENT_MANUAL} or
-         *              {@link #DISMISS_EVENT_CONSECUTIVE}.
-         *
-         * @see BaseTransientBottomBar#dismiss()
-         */
-        public void onDismissed(B transientBottomBar, @DismissEvent int event) {
-            // empty
-        }
-
-        /**
-         * Called when the given {@link BaseTransientBottomBar} is visible.
-         *
-         * @param transientBottomBar The transient bottom bar which is now visible.
-         * @see BaseTransientBottomBar#show()
-         */
-        public void onShown(B transientBottomBar) {
-            // empty
-        }
-    }
-
-    /**
-     * Interface that defines the behavior of the main content of a transient bottom bar.
-     */
-    public interface ContentViewCallback {
-        /**
-         * Animates the content of the transient bottom bar in.
-         *
-         * @param delay Animation delay.
-         * @param duration Animation duration.
-         */
-        void animateContentIn(int delay, int duration);
-
-        /**
-         * Animates the content of the transient bottom bar out.
-         *
-         * @param delay Animation delay.
-         * @param duration Animation duration.
-         */
-        void animateContentOut(int delay, int duration);
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    @IntDef({LENGTH_INDEFINITE, LENGTH_SHORT, LENGTH_LONG})
-    @IntRange(from = 1)
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Duration {}
-
-    /**
-     * Show the Snackbar indefinitely. This means that the Snackbar will be displayed from the time
-     * that is {@link #show() shown} until either it is dismissed, or another Snackbar is shown.
-     *
-     * @see #setDuration
-     */
-    public static final int LENGTH_INDEFINITE = -2;
-
-    /**
-     * Show the Snackbar for a short period of time.
-     *
-     * @see #setDuration
-     */
-    public static final int LENGTH_SHORT = -1;
-
-    /**
-     * Show the Snackbar for a long period of time.
-     *
-     * @see #setDuration
-     */
-    public static final int LENGTH_LONG = 0;
-
-    static final int ANIMATION_DURATION = 250;
-    static final int ANIMATION_FADE_DURATION = 180;
-
-    static final Handler sHandler;
-    static final int MSG_SHOW = 0;
-    static final int MSG_DISMISS = 1;
-
-    // On JB/KK versions of the platform sometimes View.setTranslationY does not
-    // result in layout / draw pass, and CoordinatorLayout relies on a draw pass to
-    // happen to sync vertical positioning of all its child views
-    private static final boolean USE_OFFSET_API = (Build.VERSION.SDK_INT >= 16)
-            && (Build.VERSION.SDK_INT <= 19);
-
-    static {
-        sHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
-            @Override
-            public boolean handleMessage(Message message) {
-                switch (message.what) {
-                    case MSG_SHOW:
-                        ((BaseTransientBottomBar) message.obj).showView();
-                        return true;
-                    case MSG_DISMISS:
-                        ((BaseTransientBottomBar) message.obj).hideView(message.arg1);
-                        return true;
-                }
-                return false;
-            }
-        });
-    }
-
-    private final ViewGroup mTargetParent;
-    private final Context mContext;
-    final SnackbarBaseLayout mView;
-    private final ContentViewCallback mContentViewCallback;
-    private int mDuration;
-
-    private List<BaseCallback<B>> mCallbacks;
-
-    private final AccessibilityManager mAccessibilityManager;
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    interface OnLayoutChangeListener {
-        void onLayoutChange(View view, int left, int top, int right, int bottom);
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    interface OnAttachStateChangeListener {
-        void onViewAttachedToWindow(View v);
-        void onViewDetachedFromWindow(View v);
-    }
-
-    /**
-     * Constructor for the transient bottom bar.
-     *
-     * @param parent The parent for this transient bottom bar.
-     * @param content The content view for this transient bottom bar.
-     * @param contentViewCallback The content view callback for this transient bottom bar.
-     */
-    protected BaseTransientBottomBar(@NonNull ViewGroup parent, @NonNull View content,
-            @NonNull ContentViewCallback contentViewCallback) {
-        if (parent == null) {
-            throw new IllegalArgumentException("Transient bottom bar must have non-null parent");
-        }
-        if (content == null) {
-            throw new IllegalArgumentException("Transient bottom bar must have non-null content");
-        }
-        if (contentViewCallback == null) {
-            throw new IllegalArgumentException("Transient bottom bar must have non-null callback");
-        }
-
-        mTargetParent = parent;
-        mContentViewCallback = contentViewCallback;
-        mContext = parent.getContext();
-
-        ThemeUtils.checkAppCompatTheme(mContext);
-
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        // Note that for backwards compatibility reasons we inflate a layout that is defined
-        // in the extending Snackbar class. This is to prevent breakage of apps that have custom
-        // coordinator layout behaviors that depend on that layout.
-        mView = (SnackbarBaseLayout) inflater.inflate(
-                R.layout.design_layout_snackbar, mTargetParent, false);
-        mView.addView(content);
-
-        ViewCompat.setAccessibilityLiveRegion(mView,
-                ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
-        ViewCompat.setImportantForAccessibility(mView,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-
-        // Make sure that we fit system windows and have a listener to apply any insets
-        ViewCompat.setFitsSystemWindows(mView, true);
-        ViewCompat.setOnApplyWindowInsetsListener(mView,
-                new android.support.v4.view.OnApplyWindowInsetsListener() {
-                    @Override
-                    public WindowInsetsCompat onApplyWindowInsets(View v,
-                            WindowInsetsCompat insets) {
-                        // Copy over the bottom inset as padding so that we're displayed
-                        // above the navigation bar
-                        v.setPadding(v.getPaddingLeft(), v.getPaddingTop(),
-                                v.getPaddingRight(), insets.getSystemWindowInsetBottom());
-                        return insets;
-                    }
-                });
-
-        mAccessibilityManager = (AccessibilityManager)
-                mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
-    }
-
-    /**
-     * Set how long to show the view for.
-     *
-     * @param duration either be one of the predefined lengths:
-     *                 {@link #LENGTH_SHORT}, {@link #LENGTH_LONG}, or a custom duration
-     *                 in milliseconds.
-     */
-    @NonNull
-    public B setDuration(@Duration int duration) {
-        mDuration = duration;
-        return (B) this;
-    }
-
-    /**
-     * Return the duration.
-     *
-     * @see #setDuration
-     */
-    @Duration
-    public int getDuration() {
-        return mDuration;
-    }
-
-    /**
-     * Returns the {@link BaseTransientBottomBar}'s context.
-     */
-    @NonNull
-    public Context getContext() {
-        return mContext;
-    }
-
-    /**
-     * Returns the {@link BaseTransientBottomBar}'s view.
-     */
-    @NonNull
-    public View getView() {
-        return mView;
-    }
-
-    /**
-     * Show the {@link BaseTransientBottomBar}.
-     */
-    public void show() {
-        SnackbarManager.getInstance().show(mDuration, mManagerCallback);
-    }
-
-    /**
-     * Dismiss the {@link BaseTransientBottomBar}.
-     */
-    public void dismiss() {
-        dispatchDismiss(BaseCallback.DISMISS_EVENT_MANUAL);
-    }
-
-    void dispatchDismiss(@BaseCallback.DismissEvent int event) {
-        SnackbarManager.getInstance().dismiss(mManagerCallback, event);
-    }
-
-    /**
-     * Adds the specified callback to the list of callbacks that will be notified of transient
-     * bottom bar events.
-     *
-     * @param callback Callback to notify when transient bottom bar events occur.
-     * @see #removeCallback(BaseCallback)
-     */
-    @NonNull
-    public B addCallback(@NonNull BaseCallback<B> callback) {
-        if (callback == null) {
-            return (B) this;
-        }
-        if (mCallbacks == null) {
-            mCallbacks = new ArrayList<BaseCallback<B>>();
-        }
-        mCallbacks.add(callback);
-        return (B) this;
-    }
-
-    /**
-     * Removes the specified callback from the list of callbacks that will be notified of transient
-     * bottom bar events.
-     *
-     * @param callback Callback to remove from being notified of transient bottom bar events
-     * @see #addCallback(BaseCallback)
-     */
-    @NonNull
-    public B removeCallback(@NonNull BaseCallback<B> callback) {
-        if (callback == null) {
-            return (B) this;
-        }
-        if (mCallbacks == null) {
-            // This can happen if this method is called before the first call to addCallback
-            return (B) this;
-        }
-        mCallbacks.remove(callback);
-        return (B) this;
-    }
-
-    /**
-     * Return whether this {@link BaseTransientBottomBar} is currently being shown.
-     */
-    public boolean isShown() {
-        return SnackbarManager.getInstance().isCurrent(mManagerCallback);
-    }
-
-    /**
-     * Returns whether this {@link BaseTransientBottomBar} is currently being shown, or is queued
-     * to be shown next.
-     */
-    public boolean isShownOrQueued() {
-        return SnackbarManager.getInstance().isCurrentOrNext(mManagerCallback);
-    }
-
-    final SnackbarManager.Callback mManagerCallback = new SnackbarManager.Callback() {
-        @Override
-        public void show() {
-            sHandler.sendMessage(sHandler.obtainMessage(MSG_SHOW, BaseTransientBottomBar.this));
-        }
-
-        @Override
-        public void dismiss(int event) {
-            sHandler.sendMessage(sHandler.obtainMessage(MSG_DISMISS, event, 0,
-                    BaseTransientBottomBar.this));
-        }
-    };
-
-    final void showView() {
-        if (mView.getParent() == null) {
-            final ViewGroup.LayoutParams lp = mView.getLayoutParams();
-
-            if (lp instanceof CoordinatorLayout.LayoutParams) {
-                // If our LayoutParams are from a CoordinatorLayout, we'll setup our Behavior
-                final CoordinatorLayout.LayoutParams clp = (CoordinatorLayout.LayoutParams) lp;
-
-                final Behavior behavior = new Behavior();
-                behavior.setStartAlphaSwipeDistance(0.1f);
-                behavior.setEndAlphaSwipeDistance(0.6f);
-                behavior.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_START_TO_END);
-                behavior.setListener(new SwipeDismissBehavior.OnDismissListener() {
-                    @Override
-                    public void onDismiss(View view) {
-                        view.setVisibility(View.GONE);
-                        dispatchDismiss(BaseCallback.DISMISS_EVENT_SWIPE);
-                    }
-
-                    @Override
-                    public void onDragStateChanged(int state) {
-                        switch (state) {
-                            case SwipeDismissBehavior.STATE_DRAGGING:
-                            case SwipeDismissBehavior.STATE_SETTLING:
-                                // If the view is being dragged or settling, pause the timeout
-                                SnackbarManager.getInstance().pauseTimeout(mManagerCallback);
-                                break;
-                            case SwipeDismissBehavior.STATE_IDLE:
-                                // If the view has been released and is idle, restore the timeout
-                                SnackbarManager.getInstance()
-                                        .restoreTimeoutIfPaused(mManagerCallback);
-                                break;
-                        }
-                    }
-                });
-                clp.setBehavior(behavior);
-                // Also set the inset edge so that views can dodge the bar correctly
-                clp.insetEdge = Gravity.BOTTOM;
-            }
-
-            mTargetParent.addView(mView);
-        }
-
-        mView.setOnAttachStateChangeListener(
-                new BaseTransientBottomBar.OnAttachStateChangeListener() {
-                @Override
-                public void onViewAttachedToWindow(View v) {}
-
-                @Override
-                public void onViewDetachedFromWindow(View v) {
-                    if (isShownOrQueued()) {
-                        // If we haven't already been dismissed then this event is coming from a
-                        // non-user initiated action. Hence we need to make sure that we callback
-                        // and keep our state up to date. We need to post the call since
-                        // removeView() will call through to onDetachedFromWindow and thus overflow.
-                        sHandler.post(new Runnable() {
-                            @Override
-                            public void run() {
-                                onViewHidden(BaseCallback.DISMISS_EVENT_MANUAL);
-                            }
-                        });
-                    }
-                }
-            });
-
-        if (ViewCompat.isLaidOut(mView)) {
-            if (shouldAnimate()) {
-                // If animations are enabled, animate it in
-                animateViewIn();
-            } else {
-                // Else if anims are disabled just call back now
-                onViewShown();
-            }
-        } else {
-            // Otherwise, add one of our layout change listeners and show it in when laid out
-            mView.setOnLayoutChangeListener(new BaseTransientBottomBar.OnLayoutChangeListener() {
-                @Override
-                public void onLayoutChange(View view, int left, int top, int right, int bottom) {
-                    mView.setOnLayoutChangeListener(null);
-
-                    if (shouldAnimate()) {
-                        // If animations are enabled, animate it in
-                        animateViewIn();
-                    } else {
-                        // Else if anims are disabled just call back now
-                        onViewShown();
-                    }
-                }
-            });
-        }
-    }
-
-    void animateViewIn() {
-        if (Build.VERSION.SDK_INT >= 12) {
-            final int viewHeight = mView.getHeight();
-            if (USE_OFFSET_API) {
-                ViewCompat.offsetTopAndBottom(mView, viewHeight);
-            } else {
-                mView.setTranslationY(viewHeight);
-            }
-            final ValueAnimator animator = new ValueAnimator();
-            animator.setIntValues(viewHeight, 0);
-            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
-            animator.setDuration(ANIMATION_DURATION);
-            animator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animator) {
-                    mContentViewCallback.animateContentIn(
-                            ANIMATION_DURATION - ANIMATION_FADE_DURATION,
-                            ANIMATION_FADE_DURATION);
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animator) {
-                    onViewShown();
-                }
-            });
-            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                private int mPreviousAnimatedIntValue = viewHeight;
-
-                @Override
-                public void onAnimationUpdate(ValueAnimator animator) {
-                    int currentAnimatedIntValue = (int) animator.getAnimatedValue();
-                    if (USE_OFFSET_API) {
-                        ViewCompat.offsetTopAndBottom(mView,
-                                currentAnimatedIntValue - mPreviousAnimatedIntValue);
-                    } else {
-                        mView.setTranslationY(currentAnimatedIntValue);
-                    }
-                    mPreviousAnimatedIntValue = currentAnimatedIntValue;
-                }
-            });
-            animator.start();
-        } else {
-            final Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
-                    R.anim.design_snackbar_in);
-            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
-            anim.setDuration(ANIMATION_DURATION);
-            anim.setAnimationListener(new Animation.AnimationListener() {
-                @Override
-                public void onAnimationEnd(Animation animation) {
-                    onViewShown();
-                }
-
-                @Override
-                public void onAnimationStart(Animation animation) {}
-
-                @Override
-                public void onAnimationRepeat(Animation animation) {}
-            });
-            mView.startAnimation(anim);
-        }
-    }
-
-    private void animateViewOut(final int event) {
-        if (Build.VERSION.SDK_INT >= 12) {
-            final ValueAnimator animator = new ValueAnimator();
-            animator.setIntValues(0, mView.getHeight());
-            animator.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
-            animator.setDuration(ANIMATION_DURATION);
-            animator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animator) {
-                    mContentViewCallback.animateContentOut(0, ANIMATION_FADE_DURATION);
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animator) {
-                    onViewHidden(event);
-                }
-            });
-            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                private int mPreviousAnimatedIntValue = 0;
-
-                @Override
-                public void onAnimationUpdate(ValueAnimator animator) {
-                    int currentAnimatedIntValue = (int) animator.getAnimatedValue();
-                    if (USE_OFFSET_API) {
-                        ViewCompat.offsetTopAndBottom(mView,
-                                currentAnimatedIntValue - mPreviousAnimatedIntValue);
-                    } else {
-                        mView.setTranslationY(currentAnimatedIntValue);
-                    }
-                    mPreviousAnimatedIntValue = currentAnimatedIntValue;
-                }
-            });
-            animator.start();
-        } else {
-            final Animation anim = AnimationUtils.loadAnimation(mView.getContext(),
-                    R.anim.design_snackbar_out);
-            anim.setInterpolator(FAST_OUT_SLOW_IN_INTERPOLATOR);
-            anim.setDuration(ANIMATION_DURATION);
-            anim.setAnimationListener(new Animation.AnimationListener() {
-                @Override
-                public void onAnimationEnd(Animation animation) {
-                    onViewHidden(event);
-                }
-
-                @Override
-                public void onAnimationStart(Animation animation) {}
-
-                @Override
-                public void onAnimationRepeat(Animation animation) {}
-            });
-            mView.startAnimation(anim);
-        }
-    }
-
-    final void hideView(@BaseCallback.DismissEvent final int event) {
-        if (shouldAnimate() && mView.getVisibility() == View.VISIBLE) {
-            animateViewOut(event);
-        } else {
-            // If anims are disabled or the view isn't visible, just call back now
-            onViewHidden(event);
-        }
-    }
-
-    void onViewShown() {
-        SnackbarManager.getInstance().onShown(mManagerCallback);
-        if (mCallbacks != null) {
-            // Notify the callbacks. Do that from the end of the list so that if a callback
-            // removes itself as the result of being called, it won't mess up with our iteration
-            int callbackCount = mCallbacks.size();
-            for (int i = callbackCount - 1; i >= 0; i--) {
-                mCallbacks.get(i).onShown((B) this);
-            }
-        }
-    }
-
-    void onViewHidden(int event) {
-        // First tell the SnackbarManager that it has been dismissed
-        SnackbarManager.getInstance().onDismissed(mManagerCallback);
-        if (mCallbacks != null) {
-            // Notify the callbacks. Do that from the end of the list so that if a callback
-            // removes itself as the result of being called, it won't mess up with our iteration
-            int callbackCount = mCallbacks.size();
-            for (int i = callbackCount - 1; i >= 0; i--) {
-                mCallbacks.get(i).onDismissed((B) this, event);
-            }
-        }
-        if (Build.VERSION.SDK_INT < 11) {
-            // We need to hide the Snackbar on pre-v11 since it uses an old style Animation.
-            // ViewGroup has special handling in removeView() when getAnimation() != null in
-            // that it waits. This then means that the calculated insets are wrong and the
-            // any dodging views do not return. We workaround it by setting the view to gone while
-            // ViewGroup actually gets around to removing it.
-            mView.setVisibility(View.GONE);
-        }
-        // Lastly, hide and remove the view from the parent (if attached)
-        final ViewParent parent = mView.getParent();
-        if (parent instanceof ViewGroup) {
-            ((ViewGroup) parent).removeView(mView);
-        }
-    }
-
-    /**
-     * Returns true if we should animate the Snackbar view in/out.
-     */
-    boolean shouldAnimate() {
-        return !mAccessibilityManager.isEnabled();
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    static class SnackbarBaseLayout extends FrameLayout {
-        private BaseTransientBottomBar.OnLayoutChangeListener mOnLayoutChangeListener;
-        private BaseTransientBottomBar.OnAttachStateChangeListener mOnAttachStateChangeListener;
-
-        SnackbarBaseLayout(Context context) {
-            this(context, null);
-        }
-
-        SnackbarBaseLayout(Context context, AttributeSet attrs) {
-            super(context, attrs);
-            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SnackbarLayout);
-            if (a.hasValue(R.styleable.SnackbarLayout_elevation)) {
-                ViewCompat.setElevation(this, a.getDimensionPixelSize(
-                        R.styleable.SnackbarLayout_elevation, 0));
-            }
-            a.recycle();
-
-            setClickable(true);
-        }
-
-        @Override
-        protected void onLayout(boolean changed, int l, int t, int r, int b) {
-            super.onLayout(changed, l, t, r, b);
-            if (mOnLayoutChangeListener != null) {
-                mOnLayoutChangeListener.onLayoutChange(this, l, t, r, b);
-            }
-        }
-
-        @Override
-        protected void onAttachedToWindow() {
-            super.onAttachedToWindow();
-            if (mOnAttachStateChangeListener != null) {
-                mOnAttachStateChangeListener.onViewAttachedToWindow(this);
-            }
-
-            ViewCompat.requestApplyInsets(this);
-        }
-
-        @Override
-        protected void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            if (mOnAttachStateChangeListener != null) {
-                mOnAttachStateChangeListener.onViewDetachedFromWindow(this);
-            }
-        }
-
-        void setOnLayoutChangeListener(
-                BaseTransientBottomBar.OnLayoutChangeListener onLayoutChangeListener) {
-            mOnLayoutChangeListener = onLayoutChangeListener;
-        }
-
-        void setOnAttachStateChangeListener(
-                BaseTransientBottomBar.OnAttachStateChangeListener listener) {
-            mOnAttachStateChangeListener = listener;
-        }
-    }
-
-    final class Behavior extends SwipeDismissBehavior<SnackbarBaseLayout> {
-        @Override
-        public boolean canSwipeDismissView(View child) {
-            return child instanceof SnackbarBaseLayout;
-        }
-
-        @Override
-        public boolean onInterceptTouchEvent(CoordinatorLayout parent, SnackbarBaseLayout child,
-                MotionEvent event) {
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN:
-                    // We want to make sure that we disable any Snackbar timeouts if the user is
-                    // currently touching the Snackbar. We restore the timeout when complete
-                    if (parent.isPointInChildBounds(child, (int) event.getX(),
-                            (int) event.getY())) {
-                        SnackbarManager.getInstance().pauseTimeout(mManagerCallback);
-                    }
-                    break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    SnackbarManager.getInstance().restoreTimeoutIfPaused(mManagerCallback);
-                    break;
-            }
-            return super.onInterceptTouchEvent(parent, child, event);
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/BottomNavigationView.java b/design/src/android/support/design/widget/BottomNavigationView.java
deleted file mode 100644
index 61dba87..0000000
--- a/design/src/android/support/design/widget/BottomNavigationView.java
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IdRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.R;
-import android.support.design.internal.BottomNavigationMenu;
-import android.support.design.internal.BottomNavigationMenuView;
-import android.support.design.internal.BottomNavigationPresenter;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.content.res.AppCompatResources;
-import android.support.v7.view.SupportMenuInflater;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.widget.TintTypedArray;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-/**
- * <p>
- * Represents a standard bottom navigation bar for application. It is an implementation of
- * <a href="https://material.google.com/components/bottom-navigation.html">material design bottom
- * navigation</a>.
- * </p>
- *
- * <p>
- * Bottom navigation bars make it easy for users to explore and switch between top-level views in
- * a single tap. It should be used when application has three to five top-level destinations.
- * </p>
- *
- * <p>
- * The bar contents can be populated by specifying a menu resource file. Each menu item title, icon
- * and enabled state will be used for displaying bottom navigation bar items. Menu items can also be
- * used for programmatically selecting which destination is currently active. It can be done using
- * {@code MenuItem#setChecked(true)}
- * </p>
- *
- * <pre>
- * layout resource file:
- * &lt;android.support.design.widget.BottomNavigationView
- *     xmlns:android="http://schemas.android.com/apk/res/android"
- *     xmlns:app="http://schemas.android.com/apk/res-auto"
- *     android:id="@+id/navigation"
- *     android:layout_width="match_parent"
- *     android:layout_height="56dp"
- *     android:layout_gravity="start"
- *     app:menu="@menu/my_navigation_items" /&gt;
- *
- * res/menu/my_navigation_items.xml:
- * &lt;menu xmlns:android="http://schemas.android.com/apk/res/android"&gt;
- *     &lt;item android:id="@+id/action_search"
- *          android:title="@string/menu_search"
- *          android:icon="@drawable/ic_search" /&gt;
- *     &lt;item android:id="@+id/action_settings"
- *          android:title="@string/menu_settings"
- *          android:icon="@drawable/ic_add" /&gt;
- *     &lt;item android:id="@+id/action_navigation"
- *          android:title="@string/menu_navigation"
- *          android:icon="@drawable/ic_action_navigation_menu" /&gt;
- * &lt;/menu&gt;
- * </pre>
- */
-public class BottomNavigationView extends FrameLayout {
-
-    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
-    private static final int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled};
-
-    private static final int MENU_PRESENTER_ID = 1;
-
-    private final MenuBuilder mMenu;
-    private final BottomNavigationMenuView mMenuView;
-    private final BottomNavigationPresenter mPresenter = new BottomNavigationPresenter();
-    private MenuInflater mMenuInflater;
-
-    private OnNavigationItemSelectedListener mSelectedListener;
-    private OnNavigationItemReselectedListener mReselectedListener;
-
-    public BottomNavigationView(Context context) {
-        this(context, null);
-    }
-
-    public BottomNavigationView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public BottomNavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        ThemeUtils.checkAppCompatTheme(context);
-
-        // Create the menu
-        mMenu = new BottomNavigationMenu(context);
-
-        mMenuView = new BottomNavigationMenuView(context);
-        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-        params.gravity = Gravity.CENTER;
-        mMenuView.setLayoutParams(params);
-
-        mPresenter.setBottomNavigationMenuView(mMenuView);
-        mPresenter.setId(MENU_PRESENTER_ID);
-        mMenuView.setPresenter(mPresenter);
-        mMenu.addMenuPresenter(mPresenter);
-        mPresenter.initForMenu(getContext(), mMenu);
-
-        // Custom attributes
-        TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
-                R.styleable.BottomNavigationView, defStyleAttr,
-                R.style.Widget_Design_BottomNavigationView);
-
-        if (a.hasValue(R.styleable.BottomNavigationView_itemIconTint)) {
-            mMenuView.setIconTintList(
-                    a.getColorStateList(R.styleable.BottomNavigationView_itemIconTint));
-        } else {
-            mMenuView.setIconTintList(
-                    createDefaultColorStateList(android.R.attr.textColorSecondary));
-        }
-        if (a.hasValue(R.styleable.BottomNavigationView_itemTextColor)) {
-            mMenuView.setItemTextColor(
-                    a.getColorStateList(R.styleable.BottomNavigationView_itemTextColor));
-        } else {
-            mMenuView.setItemTextColor(
-                    createDefaultColorStateList(android.R.attr.textColorSecondary));
-        }
-        if (a.hasValue(R.styleable.BottomNavigationView_elevation)) {
-            ViewCompat.setElevation(this, a.getDimensionPixelSize(
-                    R.styleable.BottomNavigationView_elevation, 0));
-        }
-
-        int itemBackground = a.getResourceId(R.styleable.BottomNavigationView_itemBackground, 0);
-        mMenuView.setItemBackgroundRes(itemBackground);
-
-        if (a.hasValue(R.styleable.BottomNavigationView_menu)) {
-            inflateMenu(a.getResourceId(R.styleable.BottomNavigationView_menu, 0));
-        }
-        a.recycle();
-
-        addView(mMenuView, params);
-        if (Build.VERSION.SDK_INT < 21) {
-            addCompatibilityTopDivider(context);
-        }
-
-        mMenu.setCallback(new MenuBuilder.Callback() {
-            @Override
-            public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
-                if (mReselectedListener != null && item.getItemId() == getSelectedItemId()) {
-                    mReselectedListener.onNavigationItemReselected(item);
-                    return true; // item is already selected
-                }
-                return mSelectedListener != null
-                        && !mSelectedListener.onNavigationItemSelected(item);
-            }
-
-            @Override
-            public void onMenuModeChange(MenuBuilder menu) {}
-        });
-    }
-
-    /**
-     * Set a listener that will be notified when a bottom navigation item is selected. This listener
-     * will also be notified when the currently selected item is reselected, unless an
-     * {@link OnNavigationItemReselectedListener} has also been set.
-     *
-     * @param listener The listener to notify
-     *
-     * @see #setOnNavigationItemReselectedListener(OnNavigationItemReselectedListener)
-     */
-    public void setOnNavigationItemSelectedListener(
-            @Nullable OnNavigationItemSelectedListener listener) {
-        mSelectedListener = listener;
-    }
-
-    /**
-     * Set a listener that will be notified when the currently selected bottom navigation item is
-     * reselected. This does not require an {@link OnNavigationItemSelectedListener} to be set.
-     *
-     * @param listener The listener to notify
-     *
-     * @see #setOnNavigationItemSelectedListener(OnNavigationItemSelectedListener)
-     */
-    public void setOnNavigationItemReselectedListener(
-            @Nullable OnNavigationItemReselectedListener listener) {
-        mReselectedListener = listener;
-    }
-
-    /**
-     * Returns the {@link Menu} instance associated with this bottom navigation bar.
-     */
-    @NonNull
-    public Menu getMenu() {
-        return mMenu;
-    }
-
-    /**
-     * Inflate a menu resource into this navigation view.
-     *
-     * <p>Existing items in the menu will not be modified or removed.</p>
-     *
-     * @param resId ID of a menu resource to inflate
-     */
-    public void inflateMenu(int resId) {
-        mPresenter.setUpdateSuspended(true);
-        getMenuInflater().inflate(resId, mMenu);
-        mPresenter.setUpdateSuspended(false);
-        mPresenter.updateMenuView(true);
-    }
-
-    /**
-     * @return The maximum number of items that can be shown in BottomNavigationView.
-     */
-    public int getMaxItemCount() {
-        return BottomNavigationMenu.MAX_ITEM_COUNT;
-    }
-
-    /**
-     * Returns the tint which is applied to our menu items' icons.
-     *
-     * @see #setItemIconTintList(ColorStateList)
-     *
-     * @attr ref R.styleable#BottomNavigationView_itemIconTint
-     */
-    @Nullable
-    public ColorStateList getItemIconTintList() {
-        return mMenuView.getIconTintList();
-    }
-
-    /**
-     * Set the tint which is applied to our menu items' icons.
-     *
-     * @param tint the tint to apply.
-     *
-     * @attr ref R.styleable#BottomNavigationView_itemIconTint
-     */
-    public void setItemIconTintList(@Nullable ColorStateList tint) {
-        mMenuView.setIconTintList(tint);
-    }
-
-    /**
-     * Returns colors used for the different states (normal, selected, focused, etc.) of the menu
-     * item text.
-     *
-     * @see #setItemTextColor(ColorStateList)
-     *
-     * @return the ColorStateList of colors used for the different states of the menu items text.
-     *
-     * @attr ref R.styleable#BottomNavigationView_itemTextColor
-     */
-    @Nullable
-    public ColorStateList getItemTextColor() {
-        return mMenuView.getItemTextColor();
-    }
-
-    /**
-     * Set the colors to use for the different states (normal, selected, focused, etc.) of the menu
-     * item text.
-     *
-     * @see #getItemTextColor()
-     *
-     * @attr ref R.styleable#BottomNavigationView_itemTextColor
-     */
-    public void setItemTextColor(@Nullable ColorStateList textColor) {
-        mMenuView.setItemTextColor(textColor);
-    }
-
-    /**
-     * Returns the background resource of the menu items.
-     *
-     * @see #setItemBackgroundResource(int)
-     *
-     * @attr ref R.styleable#BottomNavigationView_itemBackground
-     */
-    @DrawableRes
-    public int getItemBackgroundResource() {
-        return mMenuView.getItemBackgroundRes();
-    }
-
-    /**
-     * Set the background of our menu items to the given resource.
-     *
-     * @param resId The identifier of the resource.
-     *
-     * @attr ref R.styleable#BottomNavigationView_itemBackground
-     */
-    public void setItemBackgroundResource(@DrawableRes int resId) {
-        mMenuView.setItemBackgroundRes(resId);
-    }
-
-    /**
-     * Returns the currently selected menu item ID, or zero if there is no menu.
-     *
-     * @see #setSelectedItemId(int)
-     */
-    @IdRes
-    public int getSelectedItemId() {
-        return mMenuView.getSelectedItemId();
-    }
-
-    /**
-     * Set the selected menu item ID. This behaves the same as tapping on an item.
-     *
-     * @param itemId The menu item ID. If no item has this ID, the current selection is unchanged.
-     *
-     * @see #getSelectedItemId()
-     */
-    public void setSelectedItemId(@IdRes int itemId) {
-        MenuItem item = mMenu.findItem(itemId);
-        if (item != null) {
-            if (!mMenu.performItemAction(item, mPresenter, 0)) {
-                item.setChecked(true);
-            }
-        }
-    }
-
-    /**
-     * Listener for handling selection events on bottom navigation items.
-     */
-    public interface OnNavigationItemSelectedListener {
-
-        /**
-         * Called when an item in the bottom navigation menu is selected.
-         *
-         * @param item The selected item
-         *
-         * @return true to display the item as the selected item and false if the item should not
-         *         be selected. Consider setting non-selectable items as disabled preemptively to
-         *         make them appear non-interactive.
-         */
-        boolean onNavigationItemSelected(@NonNull MenuItem item);
-    }
-
-    /**
-     * Listener for handling reselection events on bottom navigation items.
-     */
-    public interface OnNavigationItemReselectedListener {
-
-        /**
-         * Called when the currently selected item in the bottom navigation menu is selected again.
-         *
-         * @param item The selected item
-         */
-        void onNavigationItemReselected(@NonNull MenuItem item);
-    }
-
-    private void addCompatibilityTopDivider(Context context) {
-        View divider = new View(context);
-        divider.setBackgroundColor(
-                ContextCompat.getColor(context, R.color.design_bottom_navigation_shadow_color));
-        FrameLayout.LayoutParams dividerParams = new FrameLayout.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                getResources().getDimensionPixelSize(
-                        R.dimen.design_bottom_navigation_shadow_height));
-        divider.setLayoutParams(dividerParams);
-        addView(divider);
-    }
-
-    private MenuInflater getMenuInflater() {
-        if (mMenuInflater == null) {
-            mMenuInflater = new SupportMenuInflater(getContext());
-        }
-        return mMenuInflater;
-    }
-
-    private ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {
-        final TypedValue value = new TypedValue();
-        if (!getContext().getTheme().resolveAttribute(baseColorThemeAttr, value, true)) {
-            return null;
-        }
-        ColorStateList baseColor = AppCompatResources.getColorStateList(
-                getContext(), value.resourceId);
-        if (!getContext().getTheme().resolveAttribute(
-                android.support.v7.appcompat.R.attr.colorPrimary, value, true)) {
-            return null;
-        }
-        int colorPrimary = value.data;
-        int defaultColor = baseColor.getDefaultColor();
-        return new ColorStateList(new int[][]{
-                DISABLED_STATE_SET,
-                CHECKED_STATE_SET,
-                EMPTY_STATE_SET
-        }, new int[]{
-                baseColor.getColorForState(DISABLED_STATE_SET, defaultColor),
-                colorPrimary,
-                defaultColor
-        });
-    }
-
-    @Override
-    protected Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState savedState = new SavedState(superState);
-        savedState.menuPresenterState = new Bundle();
-        mMenu.savePresenterStates(savedState.menuPresenterState);
-        return savedState;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState savedState = (SavedState) state;
-        super.onRestoreInstanceState(savedState.getSuperState());
-        mMenu.restorePresenterStates(savedState.menuPresenterState);
-    }
-
-    static class SavedState extends AbsSavedState {
-        Bundle menuPresenterState;
-
-        public SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        public SavedState(Parcel source, ClassLoader loader) {
-            super(source, loader);
-            readFromParcel(source, loader);
-        }
-
-        @Override
-        public void writeToParcel(@NonNull Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeBundle(menuPresenterState);
-        }
-
-        private void readFromParcel(Parcel in, ClassLoader loader) {
-            menuPresenterState = in.readBundle(loader);
-        }
-
-        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                return new SavedState(in, loader);
-            }
-
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in, null);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-}
diff --git a/design/src/android/support/design/widget/BottomSheetBehavior.java b/design/src/android/support/design/widget/BottomSheetBehavior.java
deleted file mode 100644
index 00ce8f9..0000000
--- a/design/src/android/support/design/widget/BottomSheetBehavior.java
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
-import android.support.design.R;
-import android.support.v4.math.MathUtils;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.ViewDragHelper;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-
-
-/**
- * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
- * a bottom sheet.
- */
-public class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
-
-    /**
-     * Callback for monitoring events about bottom sheets.
-     */
-    public abstract static class BottomSheetCallback {
-
-        /**
-         * Called when the bottom sheet changes its state.
-         *
-         * @param bottomSheet The bottom sheet view.
-         * @param newState    The new state. This will be one of {@link #STATE_DRAGGING},
-         *                    {@link #STATE_SETTLING}, {@link #STATE_EXPANDED},
-         *                    {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}.
-         */
-        public abstract void onStateChanged(@NonNull View bottomSheet, @State int newState);
-
-        /**
-         * Called when the bottom sheet is being dragged.
-         *
-         * @param bottomSheet The bottom sheet view.
-         * @param slideOffset The new offset of this bottom sheet within [-1,1] range. Offset
-         *                    increases as this bottom sheet is moving upward. From 0 to 1 the sheet
-         *                    is between collapsed and expanded states and from -1 to 0 it is
-         *                    between hidden and collapsed states.
-         */
-        public abstract void onSlide(@NonNull View bottomSheet, float slideOffset);
-    }
-
-    /**
-     * The bottom sheet is dragging.
-     */
-    public static final int STATE_DRAGGING = 1;
-
-    /**
-     * The bottom sheet is settling.
-     */
-    public static final int STATE_SETTLING = 2;
-
-    /**
-     * The bottom sheet is expanded.
-     */
-    public static final int STATE_EXPANDED = 3;
-
-    /**
-     * The bottom sheet is collapsed.
-     */
-    public static final int STATE_COLLAPSED = 4;
-
-    /**
-     * The bottom sheet is hidden.
-     */
-    public static final int STATE_HIDDEN = 5;
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface State {}
-
-    /**
-     * Peek at the 16:9 ratio keyline of its parent.
-     *
-     * <p>This can be used as a parameter for {@link #setPeekHeight(int)}.
-     * {@link #getPeekHeight()} will return this when the value is set.</p>
-     */
-    public static final int PEEK_HEIGHT_AUTO = -1;
-
-    private static final float HIDE_THRESHOLD = 0.5f;
-
-    private static final float HIDE_FRICTION = 0.1f;
-
-    private float mMaximumVelocity;
-
-    private int mPeekHeight;
-
-    private boolean mPeekHeightAuto;
-
-    private int mPeekHeightMin;
-
-    int mMinOffset;
-
-    int mMaxOffset;
-
-    boolean mHideable;
-
-    private boolean mSkipCollapsed;
-
-    @State
-    int mState = STATE_COLLAPSED;
-
-    ViewDragHelper mViewDragHelper;
-
-    private boolean mIgnoreEvents;
-
-    private int mLastNestedScrollDy;
-
-    private boolean mNestedScrolled;
-
-    int mParentHeight;
-
-    WeakReference<V> mViewRef;
-
-    WeakReference<View> mNestedScrollingChildRef;
-
-    private BottomSheetCallback mCallback;
-
-    private VelocityTracker mVelocityTracker;
-
-    int mActivePointerId;
-
-    private int mInitialY;
-
-    boolean mTouchingScrollingChild;
-
-    /**
-     * Default constructor for instantiating BottomSheetBehaviors.
-     */
-    public BottomSheetBehavior() {
-    }
-
-    /**
-     * Default constructor for inflating BottomSheetBehaviors from layout.
-     *
-     * @param context The {@link Context}.
-     * @param attrs   The {@link AttributeSet}.
-     */
-    public BottomSheetBehavior(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.BottomSheetBehavior_Layout);
-        TypedValue value = a.peekValue(R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight);
-        if (value != null && value.data == PEEK_HEIGHT_AUTO) {
-            setPeekHeight(value.data);
-        } else {
-            setPeekHeight(a.getDimensionPixelSize(
-                    R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, PEEK_HEIGHT_AUTO));
-        }
-        setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideable, false));
-        setSkipCollapsed(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed,
-                false));
-        a.recycle();
-        ViewConfiguration configuration = ViewConfiguration.get(context);
-        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
-        return new SavedState(super.onSaveInstanceState(parent, child), mState);
-    }
-
-    @Override
-    public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(parent, child, ss.getSuperState());
-        // Intermediate states are restored as collapsed state
-        if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) {
-            mState = STATE_COLLAPSED;
-        } else {
-            mState = ss.state;
-        }
-    }
-
-    @Override
-    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
-        if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
-            ViewCompat.setFitsSystemWindows(child, true);
-        }
-        int savedTop = child.getTop();
-        // First let the parent lay it out
-        parent.onLayoutChild(child, layoutDirection);
-        // Offset the bottom sheet
-        mParentHeight = parent.getHeight();
-        int peekHeight;
-        if (mPeekHeightAuto) {
-            if (mPeekHeightMin == 0) {
-                mPeekHeightMin = parent.getResources().getDimensionPixelSize(
-                        R.dimen.design_bottom_sheet_peek_height_min);
-            }
-            peekHeight = Math.max(mPeekHeightMin, mParentHeight - parent.getWidth() * 9 / 16);
-        } else {
-            peekHeight = mPeekHeight;
-        }
-        mMinOffset = Math.max(0, mParentHeight - child.getHeight());
-        mMaxOffset = Math.max(mParentHeight - peekHeight, mMinOffset);
-        if (mState == STATE_EXPANDED) {
-            ViewCompat.offsetTopAndBottom(child, mMinOffset);
-        } else if (mHideable && mState == STATE_HIDDEN) {
-            ViewCompat.offsetTopAndBottom(child, mParentHeight);
-        } else if (mState == STATE_COLLAPSED) {
-            ViewCompat.offsetTopAndBottom(child, mMaxOffset);
-        } else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
-            ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());
-        }
-        if (mViewDragHelper == null) {
-            mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
-        }
-        mViewRef = new WeakReference<>(child);
-        mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
-        return true;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
-        if (!child.isShown()) {
-            mIgnoreEvents = true;
-            return false;
-        }
-        int action = event.getActionMasked();
-        // Record the velocity
-        if (action == MotionEvent.ACTION_DOWN) {
-            reset();
-        }
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(event);
-        switch (action) {
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mTouchingScrollingChild = false;
-                mActivePointerId = MotionEvent.INVALID_POINTER_ID;
-                // Reset the ignore flag
-                if (mIgnoreEvents) {
-                    mIgnoreEvents = false;
-                    return false;
-                }
-                break;
-            case MotionEvent.ACTION_DOWN:
-                int initialX = (int) event.getX();
-                mInitialY = (int) event.getY();
-                View scroll = mNestedScrollingChildRef != null
-                        ? mNestedScrollingChildRef.get() : null;
-                if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) {
-                    mActivePointerId = event.getPointerId(event.getActionIndex());
-                    mTouchingScrollingChild = true;
-                }
-                mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID &&
-                        !parent.isPointInChildBounds(child, initialX, mInitialY);
-                break;
-        }
-        if (!mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event)) {
-            return true;
-        }
-        // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because
-        // it is not the top most view of its parent. This is not necessary when the touch event is
-        // happening over the scrolling content as nested scrolling logic handles that case.
-        View scroll = mNestedScrollingChildRef.get();
-        return action == MotionEvent.ACTION_MOVE && scroll != null &&
-                !mIgnoreEvents && mState != STATE_DRAGGING &&
-                !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) &&
-                Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop();
-    }
-
-    @Override
-    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
-        if (!child.isShown()) {
-            return false;
-        }
-        int action = event.getActionMasked();
-        if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {
-            return true;
-        }
-        if (mViewDragHelper != null) {
-            mViewDragHelper.processTouchEvent(event);
-        }
-        // Record the velocity
-        if (action == MotionEvent.ACTION_DOWN) {
-            reset();
-        }
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-        mVelocityTracker.addMovement(event);
-        // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
-        // to capture the bottom sheet in case it is not captured and the touch slop is passed.
-        if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents) {
-            if (Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop()) {
-                mViewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));
-            }
-        }
-        return !mIgnoreEvents;
-    }
-
-    @Override
-    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child,
-            View directTargetChild, View target, int nestedScrollAxes) {
-        mLastNestedScrollDy = 0;
-        mNestedScrolled = false;
-        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
-    }
-
-    @Override
-    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
-            int dy, int[] consumed) {
-        View scrollingChild = mNestedScrollingChildRef.get();
-        if (target != scrollingChild) {
-            return;
-        }
-        int currentTop = child.getTop();
-        int newTop = currentTop - dy;
-        if (dy > 0) { // Upward
-            if (newTop < mMinOffset) {
-                consumed[1] = currentTop - mMinOffset;
-                ViewCompat.offsetTopAndBottom(child, -consumed[1]);
-                setStateInternal(STATE_EXPANDED);
-            } else {
-                consumed[1] = dy;
-                ViewCompat.offsetTopAndBottom(child, -dy);
-                setStateInternal(STATE_DRAGGING);
-            }
-        } else if (dy < 0) { // Downward
-            if (!target.canScrollVertically(-1)) {
-                if (newTop <= mMaxOffset || mHideable) {
-                    consumed[1] = dy;
-                    ViewCompat.offsetTopAndBottom(child, -dy);
-                    setStateInternal(STATE_DRAGGING);
-                } else {
-                    consumed[1] = currentTop - mMaxOffset;
-                    ViewCompat.offsetTopAndBottom(child, -consumed[1]);
-                    setStateInternal(STATE_COLLAPSED);
-                }
-            }
-        }
-        dispatchOnSlide(child.getTop());
-        mLastNestedScrollDy = dy;
-        mNestedScrolled = true;
-    }
-
-    @Override
-    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
-        if (child.getTop() == mMinOffset) {
-            setStateInternal(STATE_EXPANDED);
-            return;
-        }
-        if (mNestedScrollingChildRef == null || target != mNestedScrollingChildRef.get()
-                || !mNestedScrolled) {
-            return;
-        }
-        int top;
-        int targetState;
-        if (mLastNestedScrollDy > 0) {
-            top = mMinOffset;
-            targetState = STATE_EXPANDED;
-        } else if (mHideable && shouldHide(child, getYVelocity())) {
-            top = mParentHeight;
-            targetState = STATE_HIDDEN;
-        } else if (mLastNestedScrollDy == 0) {
-            int currentTop = child.getTop();
-            if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
-                top = mMinOffset;
-                targetState = STATE_EXPANDED;
-            } else {
-                top = mMaxOffset;
-                targetState = STATE_COLLAPSED;
-            }
-        } else {
-            top = mMaxOffset;
-            targetState = STATE_COLLAPSED;
-        }
-        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
-            setStateInternal(STATE_SETTLING);
-            ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
-        } else {
-            setStateInternal(targetState);
-        }
-        mNestedScrolled = false;
-    }
-
-    @Override
-    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,
-            float velocityX, float velocityY) {
-        return target == mNestedScrollingChildRef.get() &&
-                (mState != STATE_EXPANDED ||
-                        super.onNestedPreFling(coordinatorLayout, child, target,
-                                velocityX, velocityY));
-    }
-
-    /**
-     * Sets the height of the bottom sheet when it is collapsed.
-     *
-     * @param peekHeight The height of the collapsed bottom sheet in pixels, or
-     *                   {@link #PEEK_HEIGHT_AUTO} to configure the sheet to peek automatically
-     *                   at 16:9 ratio keyline.
-     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
-     */
-    public final void setPeekHeight(int peekHeight) {
-        boolean layout = false;
-        if (peekHeight == PEEK_HEIGHT_AUTO) {
-            if (!mPeekHeightAuto) {
-                mPeekHeightAuto = true;
-                layout = true;
-            }
-        } else if (mPeekHeightAuto || mPeekHeight != peekHeight) {
-            mPeekHeightAuto = false;
-            mPeekHeight = Math.max(0, peekHeight);
-            mMaxOffset = mParentHeight - peekHeight;
-            layout = true;
-        }
-        if (layout && mState == STATE_COLLAPSED && mViewRef != null) {
-            V view = mViewRef.get();
-            if (view != null) {
-                view.requestLayout();
-            }
-        }
-    }
-
-    /**
-     * Gets the height of the bottom sheet when it is collapsed.
-     *
-     * @return The height of the collapsed bottom sheet in pixels, or {@link #PEEK_HEIGHT_AUTO}
-     *         if the sheet is configured to peek automatically at 16:9 ratio keyline
-     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
-     */
-    public final int getPeekHeight() {
-        return mPeekHeightAuto ? PEEK_HEIGHT_AUTO : mPeekHeight;
-    }
-
-    /**
-     * Sets whether this bottom sheet can hide when it is swiped down.
-     *
-     * @param hideable {@code true} to make this bottom sheet hideable.
-     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
-     */
-    public void setHideable(boolean hideable) {
-        mHideable = hideable;
-    }
-
-    /**
-     * Gets whether this bottom sheet can hide when it is swiped down.
-     *
-     * @return {@code true} if this bottom sheet can hide.
-     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
-     */
-    public boolean isHideable() {
-        return mHideable;
-    }
-
-    /**
-     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
-     * after it is expanded once. Setting this to true has no effect unless the sheet is hideable.
-     *
-     * @param skipCollapsed True if the bottom sheet should skip the collapsed state.
-     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
-     */
-    public void setSkipCollapsed(boolean skipCollapsed) {
-        mSkipCollapsed = skipCollapsed;
-    }
-
-    /**
-     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
-     * after it is expanded once.
-     *
-     * @return Whether the bottom sheet should skip the collapsed state.
-     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
-     */
-    public boolean getSkipCollapsed() {
-        return mSkipCollapsed;
-    }
-
-    /**
-     * Sets a callback to be notified of bottom sheet events.
-     *
-     * @param callback The callback to notify when bottom sheet events occur.
-     */
-    public void setBottomSheetCallback(BottomSheetCallback callback) {
-        mCallback = callback;
-    }
-
-    /**
-     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
-     * animation.
-     *
-     * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or
-     *              {@link #STATE_HIDDEN}.
-     */
-    public final void setState(final @State int state) {
-        if (state == mState) {
-            return;
-        }
-        if (mViewRef == null) {
-            // The view is not laid out yet; modify mState and let onLayoutChild handle it later
-            if (state == STATE_COLLAPSED || state == STATE_EXPANDED ||
-                    (mHideable && state == STATE_HIDDEN)) {
-                mState = state;
-            }
-            return;
-        }
-        final V child = mViewRef.get();
-        if (child == null) {
-            return;
-        }
-        // Start the animation; wait until a pending layout if there is one.
-        ViewParent parent = child.getParent();
-        if (parent != null && parent.isLayoutRequested() && ViewCompat.isAttachedToWindow(child)) {
-            child.post(new Runnable() {
-                @Override
-                public void run() {
-                    startSettlingAnimation(child, state);
-                }
-            });
-        } else {
-            startSettlingAnimation(child, state);
-        }
-    }
-
-    /**
-     * Gets the current state of the bottom sheet.
-     *
-     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
-     * {@link #STATE_SETTLING}, and {@link #STATE_HIDDEN}.
-     */
-    @State
-    public final int getState() {
-        return mState;
-    }
-
-    void setStateInternal(@State int state) {
-        if (mState == state) {
-            return;
-        }
-        mState = state;
-        View bottomSheet = mViewRef.get();
-        if (bottomSheet != null && mCallback != null) {
-            mCallback.onStateChanged(bottomSheet, state);
-        }
-    }
-
-    private void reset() {
-        mActivePointerId = ViewDragHelper.INVALID_POINTER;
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-            mVelocityTracker = null;
-        }
-    }
-
-    boolean shouldHide(View child, float yvel) {
-        if (mSkipCollapsed) {
-            return true;
-        }
-        if (child.getTop() < mMaxOffset) {
-            // It should not hide, but collapse.
-            return false;
-        }
-        final float newTop = child.getTop() + yvel * HIDE_FRICTION;
-        return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD;
-    }
-
-    @VisibleForTesting
-    View findScrollingChild(View view) {
-        if (ViewCompat.isNestedScrollingEnabled(view)) {
-            return view;
-        }
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-            for (int i = 0, count = group.getChildCount(); i < count; i++) {
-                View scrollingChild = findScrollingChild(group.getChildAt(i));
-                if (scrollingChild != null) {
-                    return scrollingChild;
-                }
-            }
-        }
-        return null;
-    }
-
-    private float getYVelocity() {
-        mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-        return mVelocityTracker.getYVelocity(mActivePointerId);
-    }
-
-    void startSettlingAnimation(View child, int state) {
-        int top;
-        if (state == STATE_COLLAPSED) {
-            top = mMaxOffset;
-        } else if (state == STATE_EXPANDED) {
-            top = mMinOffset;
-        } else if (mHideable && state == STATE_HIDDEN) {
-            top = mParentHeight;
-        } else {
-            throw new IllegalArgumentException("Illegal state argument: " + state);
-        }
-        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
-            setStateInternal(STATE_SETTLING);
-            ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
-        } else {
-            setStateInternal(state);
-        }
-    }
-
-    private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
-
-        @Override
-        public boolean tryCaptureView(View child, int pointerId) {
-            if (mState == STATE_DRAGGING) {
-                return false;
-            }
-            if (mTouchingScrollingChild) {
-                return false;
-            }
-            if (mState == STATE_EXPANDED && mActivePointerId == pointerId) {
-                View scroll = mNestedScrollingChildRef.get();
-                if (scroll != null && scroll.canScrollVertically(-1)) {
-                    // Let the content scroll up
-                    return false;
-                }
-            }
-            return mViewRef != null && mViewRef.get() == child;
-        }
-
-        @Override
-        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
-            dispatchOnSlide(top);
-        }
-
-        @Override
-        public void onViewDragStateChanged(int state) {
-            if (state == ViewDragHelper.STATE_DRAGGING) {
-                setStateInternal(STATE_DRAGGING);
-            }
-        }
-
-        @Override
-        public void onViewReleased(View releasedChild, float xvel, float yvel) {
-            int top;
-            @State int targetState;
-            if (yvel < 0) { // Moving up
-                top = mMinOffset;
-                targetState = STATE_EXPANDED;
-            } else if (mHideable && shouldHide(releasedChild, yvel)) {
-                top = mParentHeight;
-                targetState = STATE_HIDDEN;
-            } else if (yvel == 0.f) {
-                int currentTop = releasedChild.getTop();
-                if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
-                    top = mMinOffset;
-                    targetState = STATE_EXPANDED;
-                } else {
-                    top = mMaxOffset;
-                    targetState = STATE_COLLAPSED;
-                }
-            } else {
-                top = mMaxOffset;
-                targetState = STATE_COLLAPSED;
-            }
-            if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
-                setStateInternal(STATE_SETTLING);
-                ViewCompat.postOnAnimation(releasedChild,
-                        new SettleRunnable(releasedChild, targetState));
-            } else {
-                setStateInternal(targetState);
-            }
-        }
-
-        @Override
-        public int clampViewPositionVertical(View child, int top, int dy) {
-            return MathUtils.clamp(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
-        }
-
-        @Override
-        public int clampViewPositionHorizontal(View child, int left, int dx) {
-            return child.getLeft();
-        }
-
-        @Override
-        public int getViewVerticalDragRange(View child) {
-            if (mHideable) {
-                return mParentHeight - mMinOffset;
-            } else {
-                return mMaxOffset - mMinOffset;
-            }
-        }
-    };
-
-    void dispatchOnSlide(int top) {
-        View bottomSheet = mViewRef.get();
-        if (bottomSheet != null && mCallback != null) {
-            if (top > mMaxOffset) {
-                mCallback.onSlide(bottomSheet, (float) (mMaxOffset - top) /
-                        (mParentHeight - mMaxOffset));
-            } else {
-                mCallback.onSlide(bottomSheet,
-                        (float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset)));
-            }
-        }
-    }
-
-    @VisibleForTesting
-    int getPeekHeightMin() {
-        return mPeekHeightMin;
-    }
-
-    private class SettleRunnable implements Runnable {
-
-        private final View mView;
-
-        @State
-        private final int mTargetState;
-
-        SettleRunnable(View view, @State int targetState) {
-            mView = view;
-            mTargetState = targetState;
-        }
-
-        @Override
-        public void run() {
-            if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
-                ViewCompat.postOnAnimation(mView, this);
-            } else {
-                setStateInternal(mTargetState);
-            }
-        }
-    }
-
-    protected static class SavedState extends AbsSavedState {
-        @State
-        final int state;
-
-        public SavedState(Parcel source) {
-            this(source, null);
-        }
-
-        public SavedState(Parcel source, ClassLoader loader) {
-            super(source, loader);
-            //noinspection ResourceType
-            state = source.readInt();
-        }
-
-        public SavedState(Parcelable superState, @State int state) {
-            super(superState);
-            this.state = state;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            super.writeToParcel(out, flags);
-            out.writeInt(state);
-        }
-
-        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                return new SavedState(in, loader);
-            }
-
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in, null);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    /**
-     * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.
-     *
-     * @param view The {@link View} with {@link BottomSheetBehavior}.
-     * @return The {@link BottomSheetBehavior} associated with the {@code view}.
-     */
-    @SuppressWarnings("unchecked")
-    public static <V extends View> BottomSheetBehavior<V> from(V view) {
-        ViewGroup.LayoutParams params = view.getLayoutParams();
-        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
-            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
-        }
-        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
-                .getBehavior();
-        if (!(behavior instanceof BottomSheetBehavior)) {
-            throw new IllegalArgumentException(
-                    "The view is not associated with BottomSheetBehavior");
-        }
-        return (BottomSheetBehavior<V>) behavior;
-    }
-
-}
diff --git a/design/src/android/support/design/widget/BottomSheetDialog.java b/design/src/android/support/design/widget/BottomSheetDialog.java
deleted file mode 100644
index 19b5782..0000000
--- a/design/src/android/support/design/widget/BottomSheetDialog.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.StyleRes;
-import android.support.design.R;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.app.AppCompatDialog;
-import android.util.TypedValue;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-
-/**
- * Base class for {@link android.app.Dialog}s styled as a bottom sheet.
- */
-public class BottomSheetDialog extends AppCompatDialog {
-
-    private BottomSheetBehavior<FrameLayout> mBehavior;
-
-    boolean mCancelable = true;
-    private boolean mCanceledOnTouchOutside = true;
-    private boolean mCanceledOnTouchOutsideSet;
-
-    public BottomSheetDialog(@NonNull Context context) {
-        this(context, 0);
-    }
-
-    public BottomSheetDialog(@NonNull Context context, @StyleRes int theme) {
-        super(context, getThemeResId(context, theme));
-        // We hide the title bar for any style configuration. Otherwise, there will be a gap
-        // above the bottom sheet when it is expanded.
-        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
-    }
-
-    protected BottomSheetDialog(@NonNull Context context, boolean cancelable,
-            OnCancelListener cancelListener) {
-        super(context, cancelable, cancelListener);
-        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
-        mCancelable = cancelable;
-    }
-
-    @Override
-    public void setContentView(@LayoutRes int layoutResId) {
-        super.setContentView(wrapInBottomSheet(layoutResId, null, null));
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        Window window = getWindow();
-        if (window != null) {
-            if (Build.VERSION.SDK_INT >= 21) {
-                window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-            }
-            window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
-                    ViewGroup.LayoutParams.MATCH_PARENT);
-        }
-    }
-
-    @Override
-    public void setContentView(View view) {
-        super.setContentView(wrapInBottomSheet(0, view, null));
-    }
-
-    @Override
-    public void setContentView(View view, ViewGroup.LayoutParams params) {
-        super.setContentView(wrapInBottomSheet(0, view, params));
-    }
-
-    @Override
-    public void setCancelable(boolean cancelable) {
-        super.setCancelable(cancelable);
-        if (mCancelable != cancelable) {
-            mCancelable = cancelable;
-            if (mBehavior != null) {
-                mBehavior.setHideable(cancelable);
-            }
-        }
-    }
-
-    @Override
-    protected void onStart() {
-        super.onStart();
-        if (mBehavior != null) {
-            mBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
-        }
-    }
-
-    @Override
-    public void setCanceledOnTouchOutside(boolean cancel) {
-        super.setCanceledOnTouchOutside(cancel);
-        if (cancel && !mCancelable) {
-            mCancelable = true;
-        }
-        mCanceledOnTouchOutside = cancel;
-        mCanceledOnTouchOutsideSet = true;
-    }
-
-    private View wrapInBottomSheet(int layoutResId, View view, ViewGroup.LayoutParams params) {
-        final FrameLayout container = (FrameLayout) View.inflate(getContext(),
-                R.layout.design_bottom_sheet_dialog, null);
-        final CoordinatorLayout coordinator =
-                (CoordinatorLayout) container.findViewById(R.id.coordinator);
-        if (layoutResId != 0 && view == null) {
-            view = getLayoutInflater().inflate(layoutResId, coordinator, false);
-        }
-        FrameLayout bottomSheet = (FrameLayout) coordinator.findViewById(R.id.design_bottom_sheet);
-        mBehavior = BottomSheetBehavior.from(bottomSheet);
-        mBehavior.setBottomSheetCallback(mBottomSheetCallback);
-        mBehavior.setHideable(mCancelable);
-        if (params == null) {
-            bottomSheet.addView(view);
-        } else {
-            bottomSheet.addView(view, params);
-        }
-        // We treat the CoordinatorLayout as outside the dialog though it is technically inside
-        coordinator.findViewById(R.id.touch_outside).setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                if (mCancelable && isShowing() && shouldWindowCloseOnTouchOutside()) {
-                    cancel();
-                }
-            }
-        });
-        // Handle accessibility events
-        ViewCompat.setAccessibilityDelegate(bottomSheet, new AccessibilityDelegateCompat() {
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host,
-                    AccessibilityNodeInfoCompat info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                if (mCancelable) {
-                    info.addAction(AccessibilityNodeInfoCompat.ACTION_DISMISS);
-                    info.setDismissable(true);
-                } else {
-                    info.setDismissable(false);
-                }
-            }
-
-            @Override
-            public boolean performAccessibilityAction(View host, int action, Bundle args) {
-                if (action == AccessibilityNodeInfoCompat.ACTION_DISMISS && mCancelable) {
-                    cancel();
-                    return true;
-                }
-                return super.performAccessibilityAction(host, action, args);
-            }
-        });
-        bottomSheet.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View view, MotionEvent event) {
-                // Consume the event and prevent it from falling through
-                return true;
-            }
-        });
-        return container;
-    }
-
-    boolean shouldWindowCloseOnTouchOutside() {
-        if (!mCanceledOnTouchOutsideSet) {
-            if (Build.VERSION.SDK_INT < 11) {
-                mCanceledOnTouchOutside = true;
-            } else {
-                TypedArray a = getContext().obtainStyledAttributes(
-                        new int[]{android.R.attr.windowCloseOnTouchOutside});
-                mCanceledOnTouchOutside = a.getBoolean(0, true);
-                a.recycle();
-            }
-            mCanceledOnTouchOutsideSet = true;
-        }
-        return mCanceledOnTouchOutside;
-    }
-
-    private static int getThemeResId(Context context, int themeId) {
-        if (themeId == 0) {
-            // If the provided theme is 0, then retrieve the dialogTheme from our theme
-            TypedValue outValue = new TypedValue();
-            if (context.getTheme().resolveAttribute(
-                    R.attr.bottomSheetDialogTheme, outValue, true)) {
-                themeId = outValue.resourceId;
-            } else {
-                // bottomSheetDialogTheme is not provided; we default to our light theme
-                themeId = R.style.Theme_Design_Light_BottomSheetDialog;
-            }
-        }
-        return themeId;
-    }
-
-    private BottomSheetBehavior.BottomSheetCallback mBottomSheetCallback
-            = new BottomSheetBehavior.BottomSheetCallback() {
-        @Override
-        public void onStateChanged(@NonNull View bottomSheet,
-                @BottomSheetBehavior.State int newState) {
-            if (newState == BottomSheetBehavior.STATE_HIDDEN) {
-                cancel();
-            }
-        }
-
-        @Override
-        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
-        }
-    };
-
-}
diff --git a/design/src/android/support/design/widget/BottomSheetDialogFragment.java b/design/src/android/support/design/widget/BottomSheetDialogFragment.java
deleted file mode 100644
index 8842988..0000000
--- a/design/src/android/support/design/widget/BottomSheetDialogFragment.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.app.Dialog;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.app.AppCompatDialogFragment;
-
-/**
- * Modal bottom sheet. This is a version of {@link DialogFragment} that shows a bottom sheet
- * using {@link BottomSheetDialog} instead of a floating dialog.
- */
-public class BottomSheetDialogFragment extends AppCompatDialogFragment {
-
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        return new BottomSheetDialog(getContext(), getTheme());
-    }
-
-}
diff --git a/design/src/android/support/design/widget/CheckableImageButton.java b/design/src/android/support/design/widget/CheckableImageButton.java
deleted file mode 100644
index f274581..0000000
--- a/design/src/android/support/design/widget/CheckableImageButton.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.support.annotation.RestrictTo;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.widget.AppCompatImageButton;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.Checkable;
-
-/**
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class CheckableImageButton extends AppCompatImageButton implements Checkable {
-
-    private static final int[] DRAWABLE_STATE_CHECKED = new int[]{android.R.attr.state_checked};
-
-    private boolean mChecked;
-
-    public CheckableImageButton(Context context) {
-        this(context, null);
-    }
-
-    public CheckableImageButton(Context context, AttributeSet attrs) {
-        this(context, attrs, android.support.v7.appcompat.R.attr.imageButtonStyle);
-    }
-
-    public CheckableImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegateCompat() {
-            @Override
-            public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-                super.onInitializeAccessibilityEvent(host, event);
-                event.setChecked(isChecked());
-            }
-
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host,
-                    AccessibilityNodeInfoCompat info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                info.setCheckable(true);
-                info.setChecked(isChecked());
-            }
-        });
-    }
-
-    @Override
-    public void setChecked(boolean checked) {
-        if (mChecked != checked) {
-            mChecked = checked;
-            refreshDrawableState();
-            sendAccessibilityEvent(
-                    AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED);
-        }
-    }
-
-    @Override
-    public boolean isChecked() {
-        return mChecked;
-    }
-
-    @Override
-    public void toggle() {
-        setChecked(!mChecked);
-    }
-
-    @Override
-    public int[] onCreateDrawableState(int extraSpace) {
-        if (mChecked) {
-            return mergeDrawableStates(
-                    super.onCreateDrawableState(extraSpace + DRAWABLE_STATE_CHECKED.length),
-                    DRAWABLE_STATE_CHECKED);
-        } else {
-            return super.onCreateDrawableState(extraSpace);
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/CollapsingTextHelper.java b/design/src/android/support/design/widget/CollapsingTextHelper.java
deleted file mode 100644
index a33cabc..0000000
--- a/design/src/android/support/design/widget/CollapsingTextHelper.java
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.os.Build;
-import android.support.annotation.ColorInt;
-import android.support.v4.math.MathUtils;
-import android.support.v4.text.TextDirectionHeuristicsCompat;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.TintTypedArray;
-import android.text.TextPaint;
-import android.text.TextUtils;
-import android.view.Gravity;
-import android.view.View;
-import android.view.animation.Interpolator;
-
-final class CollapsingTextHelper {
-
-    // Pre-JB-MR2 doesn't support HW accelerated canvas scaled text so we will workaround it
-    // by using our own texture
-    private static final boolean USE_SCALING_TEXTURE = Build.VERSION.SDK_INT < 18;
-
-    private static final boolean DEBUG_DRAW = false;
-    private static final Paint DEBUG_DRAW_PAINT;
-    static {
-        DEBUG_DRAW_PAINT = DEBUG_DRAW ? new Paint() : null;
-        if (DEBUG_DRAW_PAINT != null) {
-            DEBUG_DRAW_PAINT.setAntiAlias(true);
-            DEBUG_DRAW_PAINT.setColor(Color.MAGENTA);
-        }
-    }
-
-    private final View mView;
-
-    private boolean mDrawTitle;
-    private float mExpandedFraction;
-
-    private final Rect mExpandedBounds;
-    private final Rect mCollapsedBounds;
-    private final RectF mCurrentBounds;
-    private int mExpandedTextGravity = Gravity.CENTER_VERTICAL;
-    private int mCollapsedTextGravity = Gravity.CENTER_VERTICAL;
-    private float mExpandedTextSize = 15;
-    private float mCollapsedTextSize = 15;
-    private ColorStateList mExpandedTextColor;
-    private ColorStateList mCollapsedTextColor;
-
-    private float mExpandedDrawY;
-    private float mCollapsedDrawY;
-    private float mExpandedDrawX;
-    private float mCollapsedDrawX;
-    private float mCurrentDrawX;
-    private float mCurrentDrawY;
-    private Typeface mCollapsedTypeface;
-    private Typeface mExpandedTypeface;
-    private Typeface mCurrentTypeface;
-
-    private CharSequence mText;
-    private CharSequence mTextToDraw;
-    private boolean mIsRtl;
-
-    private boolean mUseTexture;
-    private Bitmap mExpandedTitleTexture;
-    private Paint mTexturePaint;
-    private float mTextureAscent;
-    private float mTextureDescent;
-
-    private float mScale;
-    private float mCurrentTextSize;
-
-    private int[] mState;
-
-    private boolean mBoundsChanged;
-
-    private final TextPaint mTextPaint;
-
-    private Interpolator mPositionInterpolator;
-    private Interpolator mTextSizeInterpolator;
-
-    private float mCollapsedShadowRadius, mCollapsedShadowDx, mCollapsedShadowDy;
-    private int mCollapsedShadowColor;
-
-    private float mExpandedShadowRadius, mExpandedShadowDx, mExpandedShadowDy;
-    private int mExpandedShadowColor;
-
-    public CollapsingTextHelper(View view) {
-        mView = view;
-
-        mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.SUBPIXEL_TEXT_FLAG);
-
-        mCollapsedBounds = new Rect();
-        mExpandedBounds = new Rect();
-        mCurrentBounds = new RectF();
-    }
-
-    void setTextSizeInterpolator(Interpolator interpolator) {
-        mTextSizeInterpolator = interpolator;
-        recalculate();
-    }
-
-    void setPositionInterpolator(Interpolator interpolator) {
-        mPositionInterpolator = interpolator;
-        recalculate();
-    }
-
-    void setExpandedTextSize(float textSize) {
-        if (mExpandedTextSize != textSize) {
-            mExpandedTextSize = textSize;
-            recalculate();
-        }
-    }
-
-    void setCollapsedTextSize(float textSize) {
-        if (mCollapsedTextSize != textSize) {
-            mCollapsedTextSize = textSize;
-            recalculate();
-        }
-    }
-
-    void setCollapsedTextColor(ColorStateList textColor) {
-        if (mCollapsedTextColor != textColor) {
-            mCollapsedTextColor = textColor;
-            recalculate();
-        }
-    }
-
-    void setExpandedTextColor(ColorStateList textColor) {
-        if (mExpandedTextColor != textColor) {
-            mExpandedTextColor = textColor;
-            recalculate();
-        }
-    }
-
-    void setExpandedBounds(int left, int top, int right, int bottom) {
-        if (!rectEquals(mExpandedBounds, left, top, right, bottom)) {
-            mExpandedBounds.set(left, top, right, bottom);
-            mBoundsChanged = true;
-            onBoundsChanged();
-        }
-    }
-
-    void setCollapsedBounds(int left, int top, int right, int bottom) {
-        if (!rectEquals(mCollapsedBounds, left, top, right, bottom)) {
-            mCollapsedBounds.set(left, top, right, bottom);
-            mBoundsChanged = true;
-            onBoundsChanged();
-        }
-    }
-
-    void onBoundsChanged() {
-        mDrawTitle = mCollapsedBounds.width() > 0 && mCollapsedBounds.height() > 0
-                && mExpandedBounds.width() > 0 && mExpandedBounds.height() > 0;
-    }
-
-    void setExpandedTextGravity(int gravity) {
-        if (mExpandedTextGravity != gravity) {
-            mExpandedTextGravity = gravity;
-            recalculate();
-        }
-    }
-
-    int getExpandedTextGravity() {
-        return mExpandedTextGravity;
-    }
-
-    void setCollapsedTextGravity(int gravity) {
-        if (mCollapsedTextGravity != gravity) {
-            mCollapsedTextGravity = gravity;
-            recalculate();
-        }
-    }
-
-    int getCollapsedTextGravity() {
-        return mCollapsedTextGravity;
-    }
-
-    void setCollapsedTextAppearance(int resId) {
-        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), resId,
-                android.support.v7.appcompat.R.styleable.TextAppearance);
-        if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor)) {
-            mCollapsedTextColor = a.getColorStateList(
-                    android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor);
-        }
-        if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize)) {
-            mCollapsedTextSize = a.getDimensionPixelSize(
-                    android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize,
-                    (int) mCollapsedTextSize);
-        }
-        mCollapsedShadowColor = a.getInt(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowColor, 0);
-        mCollapsedShadowDx = a.getFloat(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDx, 0);
-        mCollapsedShadowDy = a.getFloat(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDy, 0);
-        mCollapsedShadowRadius = a.getFloat(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowRadius, 0);
-        a.recycle();
-
-        if (Build.VERSION.SDK_INT >= 16) {
-            mCollapsedTypeface = readFontFamilyTypeface(resId);
-        }
-
-        recalculate();
-    }
-
-    void setExpandedTextAppearance(int resId) {
-        TintTypedArray a = TintTypedArray.obtainStyledAttributes(mView.getContext(), resId,
-                android.support.v7.appcompat.R.styleable.TextAppearance);
-        if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor)) {
-            mExpandedTextColor = a.getColorStateList(
-                    android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor);
-        }
-        if (a.hasValue(android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize)) {
-            mExpandedTextSize = a.getDimensionPixelSize(
-                    android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize,
-                    (int) mExpandedTextSize);
-        }
-        mExpandedShadowColor = a.getInt(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowColor, 0);
-        mExpandedShadowDx = a.getFloat(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDx, 0);
-        mExpandedShadowDy = a.getFloat(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowDy, 0);
-        mExpandedShadowRadius = a.getFloat(
-                android.support.v7.appcompat.R.styleable.TextAppearance_android_shadowRadius, 0);
-        a.recycle();
-
-        if (Build.VERSION.SDK_INT >= 16) {
-            mExpandedTypeface = readFontFamilyTypeface(resId);
-        }
-
-        recalculate();
-    }
-
-    private Typeface readFontFamilyTypeface(int resId) {
-        final TypedArray a = mView.getContext().obtainStyledAttributes(resId,
-                new int[]{android.R.attr.fontFamily});
-        try {
-            final String family = a.getString(0);
-            if (family != null) {
-                return Typeface.create(family, Typeface.NORMAL);
-            }
-        } finally {
-            a.recycle();
-        }
-        return null;
-    }
-
-    void setCollapsedTypeface(Typeface typeface) {
-        if (areTypefacesDifferent(mCollapsedTypeface, typeface)) {
-            mCollapsedTypeface = typeface;
-            recalculate();
-        }
-    }
-
-    void setExpandedTypeface(Typeface typeface) {
-        if (areTypefacesDifferent(mExpandedTypeface, typeface)) {
-            mExpandedTypeface = typeface;
-            recalculate();
-        }
-    }
-
-    void setTypefaces(Typeface typeface) {
-        mCollapsedTypeface = mExpandedTypeface = typeface;
-        recalculate();
-    }
-
-    Typeface getCollapsedTypeface() {
-        return mCollapsedTypeface != null ? mCollapsedTypeface : Typeface.DEFAULT;
-    }
-
-    Typeface getExpandedTypeface() {
-        return mExpandedTypeface != null ? mExpandedTypeface : Typeface.DEFAULT;
-    }
-
-    /**
-     * Set the value indicating the current scroll value. This decides how much of the
-     * background will be displayed, as well as the title metrics/positioning.
-     *
-     * A value of {@code 0.0} indicates that the layout is fully expanded.
-     * A value of {@code 1.0} indicates that the layout is fully collapsed.
-     */
-    void setExpansionFraction(float fraction) {
-        fraction = MathUtils.clamp(fraction, 0f, 1f);
-
-        if (fraction != mExpandedFraction) {
-            mExpandedFraction = fraction;
-            calculateCurrentOffsets();
-        }
-    }
-
-    final boolean setState(final int[] state) {
-        mState = state;
-
-        if (isStateful()) {
-            recalculate();
-            return true;
-        }
-
-        return false;
-    }
-
-    final boolean isStateful() {
-        return (mCollapsedTextColor != null && mCollapsedTextColor.isStateful())
-                || (mExpandedTextColor != null && mExpandedTextColor.isStateful());
-    }
-
-    float getExpansionFraction() {
-        return mExpandedFraction;
-    }
-
-    float getCollapsedTextSize() {
-        return mCollapsedTextSize;
-    }
-
-    float getExpandedTextSize() {
-        return mExpandedTextSize;
-    }
-
-    private void calculateCurrentOffsets() {
-        calculateOffsets(mExpandedFraction);
-    }
-
-    private void calculateOffsets(final float fraction) {
-        interpolateBounds(fraction);
-        mCurrentDrawX = lerp(mExpandedDrawX, mCollapsedDrawX, fraction,
-                mPositionInterpolator);
-        mCurrentDrawY = lerp(mExpandedDrawY, mCollapsedDrawY, fraction,
-                mPositionInterpolator);
-
-        setInterpolatedTextSize(lerp(mExpandedTextSize, mCollapsedTextSize,
-                fraction, mTextSizeInterpolator));
-
-        if (mCollapsedTextColor != mExpandedTextColor) {
-            // If the collapsed and expanded text colors are different, blend them based on the
-            // fraction
-            mTextPaint.setColor(blendColors(
-                    getCurrentExpandedTextColor(), getCurrentCollapsedTextColor(), fraction));
-        } else {
-            mTextPaint.setColor(getCurrentCollapsedTextColor());
-        }
-
-        mTextPaint.setShadowLayer(
-                lerp(mExpandedShadowRadius, mCollapsedShadowRadius, fraction, null),
-                lerp(mExpandedShadowDx, mCollapsedShadowDx, fraction, null),
-                lerp(mExpandedShadowDy, mCollapsedShadowDy, fraction, null),
-                blendColors(mExpandedShadowColor, mCollapsedShadowColor, fraction));
-
-        ViewCompat.postInvalidateOnAnimation(mView);
-    }
-
-    @ColorInt
-    private int getCurrentExpandedTextColor() {
-        if (mState != null) {
-            return mExpandedTextColor.getColorForState(mState, 0);
-        } else {
-            return mExpandedTextColor.getDefaultColor();
-        }
-    }
-
-    @ColorInt
-    private int getCurrentCollapsedTextColor() {
-        if (mState != null) {
-            return mCollapsedTextColor.getColorForState(mState, 0);
-        } else {
-            return mCollapsedTextColor.getDefaultColor();
-        }
-    }
-
-    private void calculateBaseOffsets() {
-        final float currentTextSize = mCurrentTextSize;
-
-        // We then calculate the collapsed text size, using the same logic
-        calculateUsingTextSize(mCollapsedTextSize);
-        float width = mTextToDraw != null ?
-                mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0;
-        final int collapsedAbsGravity = GravityCompat.getAbsoluteGravity(mCollapsedTextGravity,
-                mIsRtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR);
-        switch (collapsedAbsGravity & Gravity.VERTICAL_GRAVITY_MASK) {
-            case Gravity.BOTTOM:
-                mCollapsedDrawY = mCollapsedBounds.bottom;
-                break;
-            case Gravity.TOP:
-                mCollapsedDrawY = mCollapsedBounds.top - mTextPaint.ascent();
-                break;
-            case Gravity.CENTER_VERTICAL:
-            default:
-                float textHeight = mTextPaint.descent() - mTextPaint.ascent();
-                float textOffset = (textHeight / 2) - mTextPaint.descent();
-                mCollapsedDrawY = mCollapsedBounds.centerY() + textOffset;
-                break;
-        }
-        switch (collapsedAbsGravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.CENTER_HORIZONTAL:
-                mCollapsedDrawX = mCollapsedBounds.centerX() - (width / 2);
-                break;
-            case Gravity.RIGHT:
-                mCollapsedDrawX = mCollapsedBounds.right - width;
-                break;
-            case Gravity.LEFT:
-            default:
-                mCollapsedDrawX = mCollapsedBounds.left;
-                break;
-        }
-
-        calculateUsingTextSize(mExpandedTextSize);
-        width = mTextToDraw != null
-                ? mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()) : 0;
-        final int expandedAbsGravity = GravityCompat.getAbsoluteGravity(mExpandedTextGravity,
-                mIsRtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR);
-        switch (expandedAbsGravity & Gravity.VERTICAL_GRAVITY_MASK) {
-            case Gravity.BOTTOM:
-                mExpandedDrawY = mExpandedBounds.bottom;
-                break;
-            case Gravity.TOP:
-                mExpandedDrawY = mExpandedBounds.top - mTextPaint.ascent();
-                break;
-            case Gravity.CENTER_VERTICAL:
-            default:
-                float textHeight = mTextPaint.descent() - mTextPaint.ascent();
-                float textOffset = (textHeight / 2) - mTextPaint.descent();
-                mExpandedDrawY = mExpandedBounds.centerY() + textOffset;
-                break;
-        }
-        switch (expandedAbsGravity & GravityCompat.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
-            case Gravity.CENTER_HORIZONTAL:
-                mExpandedDrawX = mExpandedBounds.centerX() - (width / 2);
-                break;
-            case Gravity.RIGHT:
-                mExpandedDrawX = mExpandedBounds.right - width;
-                break;
-            case Gravity.LEFT:
-            default:
-                mExpandedDrawX = mExpandedBounds.left;
-                break;
-        }
-
-        // The bounds have changed so we need to clear the texture
-        clearTexture();
-        // Now reset the text size back to the original
-        setInterpolatedTextSize(currentTextSize);
-    }
-
-    private void interpolateBounds(float fraction) {
-        mCurrentBounds.left = lerp(mExpandedBounds.left, mCollapsedBounds.left,
-                fraction, mPositionInterpolator);
-        mCurrentBounds.top = lerp(mExpandedDrawY, mCollapsedDrawY,
-                fraction, mPositionInterpolator);
-        mCurrentBounds.right = lerp(mExpandedBounds.right, mCollapsedBounds.right,
-                fraction, mPositionInterpolator);
-        mCurrentBounds.bottom = lerp(mExpandedBounds.bottom, mCollapsedBounds.bottom,
-                fraction, mPositionInterpolator);
-    }
-
-    public void draw(Canvas canvas) {
-        final int saveCount = canvas.save();
-
-        if (mTextToDraw != null && mDrawTitle) {
-            float x = mCurrentDrawX;
-            float y = mCurrentDrawY;
-
-            final boolean drawTexture = mUseTexture && mExpandedTitleTexture != null;
-
-            final float ascent;
-            final float descent;
-            if (drawTexture) {
-                ascent = mTextureAscent * mScale;
-                descent = mTextureDescent * mScale;
-            } else {
-                ascent = mTextPaint.ascent() * mScale;
-                descent = mTextPaint.descent() * mScale;
-            }
-
-            if (DEBUG_DRAW) {
-                // Just a debug tool, which drawn a magenta rect in the text bounds
-                canvas.drawRect(mCurrentBounds.left, y + ascent, mCurrentBounds.right, y + descent,
-                        DEBUG_DRAW_PAINT);
-            }
-
-            if (drawTexture) {
-                y += ascent;
-            }
-
-            if (mScale != 1f) {
-                canvas.scale(mScale, mScale, x, y);
-            }
-
-            if (drawTexture) {
-                // If we should use a texture, draw it instead of text
-                canvas.drawBitmap(mExpandedTitleTexture, x, y, mTexturePaint);
-            } else {
-                canvas.drawText(mTextToDraw, 0, mTextToDraw.length(), x, y, mTextPaint);
-            }
-        }
-
-        canvas.restoreToCount(saveCount);
-    }
-
-    private boolean calculateIsRtl(CharSequence text) {
-        final boolean defaultIsRtl = ViewCompat.getLayoutDirection(mView)
-                == ViewCompat.LAYOUT_DIRECTION_RTL;
-        return (defaultIsRtl
-                ? TextDirectionHeuristicsCompat.FIRSTSTRONG_RTL
-                : TextDirectionHeuristicsCompat.FIRSTSTRONG_LTR).isRtl(text, 0, text.length());
-    }
-
-    private void setInterpolatedTextSize(float textSize) {
-        calculateUsingTextSize(textSize);
-
-        // Use our texture if the scale isn't 1.0
-        mUseTexture = USE_SCALING_TEXTURE && mScale != 1f;
-
-        if (mUseTexture) {
-            // Make sure we have an expanded texture if needed
-            ensureExpandedTexture();
-        }
-
-        ViewCompat.postInvalidateOnAnimation(mView);
-    }
-
-    private boolean areTypefacesDifferent(Typeface first, Typeface second) {
-        return (first != null && !first.equals(second)) || (first == null && second != null);
-    }
-
-    private void calculateUsingTextSize(final float textSize) {
-        if (mText == null) return;
-
-        final float collapsedWidth = mCollapsedBounds.width();
-        final float expandedWidth = mExpandedBounds.width();
-
-        final float availableWidth;
-        final float newTextSize;
-        boolean updateDrawText = false;
-
-        if (isClose(textSize, mCollapsedTextSize)) {
-            newTextSize = mCollapsedTextSize;
-            mScale = 1f;
-            if (areTypefacesDifferent(mCurrentTypeface, mCollapsedTypeface)) {
-                mCurrentTypeface = mCollapsedTypeface;
-                updateDrawText = true;
-            }
-            availableWidth = collapsedWidth;
-        } else {
-            newTextSize = mExpandedTextSize;
-            if (areTypefacesDifferent(mCurrentTypeface, mExpandedTypeface)) {
-                mCurrentTypeface = mExpandedTypeface;
-                updateDrawText = true;
-            }
-            if (isClose(textSize, mExpandedTextSize)) {
-                // If we're close to the expanded text size, snap to it and use a scale of 1
-                mScale = 1f;
-            } else {
-                // Else, we'll scale down from the expanded text size
-                mScale = textSize / mExpandedTextSize;
-            }
-
-            final float textSizeRatio = mCollapsedTextSize / mExpandedTextSize;
-            // This is the size of the expanded bounds when it is scaled to match the
-            // collapsed text size
-            final float scaledDownWidth = expandedWidth * textSizeRatio;
-
-            if (scaledDownWidth > collapsedWidth) {
-                // If the scaled down size is larger than the actual collapsed width, we need to
-                // cap the available width so that when the expanded text scales down, it matches
-                // the collapsed width
-                availableWidth = Math.min(collapsedWidth / textSizeRatio, expandedWidth);
-            } else {
-                // Otherwise we'll just use the expanded width
-                availableWidth = expandedWidth;
-            }
-        }
-
-        if (availableWidth > 0) {
-            updateDrawText = (mCurrentTextSize != newTextSize) || mBoundsChanged || updateDrawText;
-            mCurrentTextSize = newTextSize;
-            mBoundsChanged = false;
-        }
-
-        if (mTextToDraw == null || updateDrawText) {
-            mTextPaint.setTextSize(mCurrentTextSize);
-            mTextPaint.setTypeface(mCurrentTypeface);
-            // Use linear text scaling if we're scaling the canvas
-            mTextPaint.setLinearText(mScale != 1f);
-
-            // If we don't currently have text to draw, or the text size has changed, ellipsize...
-            final CharSequence title = TextUtils.ellipsize(mText, mTextPaint,
-                    availableWidth, TextUtils.TruncateAt.END);
-            if (!TextUtils.equals(title, mTextToDraw)) {
-                mTextToDraw = title;
-                mIsRtl = calculateIsRtl(mTextToDraw);
-            }
-        }
-    }
-
-    private void ensureExpandedTexture() {
-        if (mExpandedTitleTexture != null || mExpandedBounds.isEmpty()
-                || TextUtils.isEmpty(mTextToDraw)) {
-            return;
-        }
-
-        calculateOffsets(0f);
-        mTextureAscent = mTextPaint.ascent();
-        mTextureDescent = mTextPaint.descent();
-
-        final int w = Math.round(mTextPaint.measureText(mTextToDraw, 0, mTextToDraw.length()));
-        final int h = Math.round(mTextureDescent - mTextureAscent);
-
-        if (w <= 0 || h <= 0) {
-            return; // If the width or height are 0, return
-        }
-
-        mExpandedTitleTexture = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
-
-        Canvas c = new Canvas(mExpandedTitleTexture);
-        c.drawText(mTextToDraw, 0, mTextToDraw.length(), 0, h - mTextPaint.descent(), mTextPaint);
-
-        if (mTexturePaint == null) {
-            // Make sure we have a paint
-            mTexturePaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
-        }
-    }
-
-    public void recalculate() {
-        if (mView.getHeight() > 0 && mView.getWidth() > 0) {
-            // If we've already been laid out, calculate everything now otherwise we'll wait
-            // until a layout
-            calculateBaseOffsets();
-            calculateCurrentOffsets();
-        }
-    }
-
-    /**
-     * Set the title to display
-     *
-     * @param text
-     */
-    void setText(CharSequence text) {
-        if (text == null || !text.equals(mText)) {
-            mText = text;
-            mTextToDraw = null;
-            clearTexture();
-            recalculate();
-        }
-    }
-
-    CharSequence getText() {
-        return mText;
-    }
-
-    private void clearTexture() {
-        if (mExpandedTitleTexture != null) {
-            mExpandedTitleTexture.recycle();
-            mExpandedTitleTexture = null;
-        }
-    }
-
-    /**
-     * Returns true if {@code value} is 'close' to it's closest decimal value. Close is currently
-     * defined as it's difference being < 0.001.
-     */
-    private static boolean isClose(float value, float targetValue) {
-        return Math.abs(value - targetValue) < 0.001f;
-    }
-
-    ColorStateList getExpandedTextColor() {
-        return mExpandedTextColor;
-    }
-
-    ColorStateList getCollapsedTextColor() {
-        return mCollapsedTextColor;
-    }
-
-    /**
-     * Blend {@code color1} and {@code color2} using the given ratio.
-     *
-     * @param ratio of which to blend. 0.0 will return {@code color1}, 0.5 will give an even blend,
-     *              1.0 will return {@code color2}.
-     */
-    private static int blendColors(int color1, int color2, float ratio) {
-        final float inverseRatio = 1f - ratio;
-        float a = (Color.alpha(color1) * inverseRatio) + (Color.alpha(color2) * ratio);
-        float r = (Color.red(color1) * inverseRatio) + (Color.red(color2) * ratio);
-        float g = (Color.green(color1) * inverseRatio) + (Color.green(color2) * ratio);
-        float b = (Color.blue(color1) * inverseRatio) + (Color.blue(color2) * ratio);
-        return Color.argb((int) a, (int) r, (int) g, (int) b);
-    }
-
-    private static float lerp(float startValue, float endValue, float fraction,
-            Interpolator interpolator) {
-        if (interpolator != null) {
-            fraction = interpolator.getInterpolation(fraction);
-        }
-        return AnimationUtils.lerp(startValue, endValue, fraction);
-    }
-
-    private static boolean rectEquals(Rect r, int left, int top, int right, int bottom) {
-        return !(r.left != left || r.top != top || r.right != right || r.bottom != bottom);
-    }
-}
diff --git a/design/src/android/support/design/widget/CollapsingToolbarLayout.java b/design/src/android/support/design/widget/CollapsingToolbarLayout.java
deleted file mode 100644
index 8c9b7d4..0000000
--- a/design/src/android/support/design/widget/CollapsingToolbarLayout.java
+++ /dev/null
@@ -1,1308 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.IntRange;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.StyleRes;
-import android.support.design.R;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.math.MathUtils;
-import android.support.v4.util.ObjectsCompat;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.support.v4.widget.ViewGroupUtils;
-import android.support.v7.widget.Toolbar;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.FrameLayout;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * CollapsingToolbarLayout is a wrapper for {@link Toolbar} which implements a collapsing app bar.
- * It is designed to be used as a direct child of a {@link AppBarLayout}.
- * CollapsingToolbarLayout contains the following features:
- *
- * <h4>Collapsing title</h4>
- * A title which is larger when the layout is fully visible but collapses and becomes smaller as
- * the layout is scrolled off screen. You can set the title to display via
- * {@link #setTitle(CharSequence)}. The title appearance can be tweaked via the
- * {@code collapsedTextAppearance} and {@code expandedTextAppearance} attributes.
- *
- * <h4>Content scrim</h4>
- * A full-bleed scrim which is show or hidden when the scroll position has hit a certain threshold.
- * You can change this via {@link #setContentScrim(Drawable)}.
- *
- * <h4>Status bar scrim</h4>
- * A scrim which is show or hidden behind the status bar when the scroll position has hit a certain
- * threshold. You can change this via {@link #setStatusBarScrim(Drawable)}. This only works
- * on {@link android.os.Build.VERSION_CODES#LOLLIPOP LOLLIPOP} devices when we set to fit system
- * windows.
- *
- * <h4>Parallax scrolling children</h4>
- * Child views can opt to be scrolled within this layout in a parallax fashion.
- * See {@link LayoutParams#COLLAPSE_MODE_PARALLAX} and
- * {@link LayoutParams#setParallaxMultiplier(float)}.
- *
- * <h4>Pinned position children</h4>
- * Child views can opt to be pinned in space globally. This is useful when implementing a
- * collapsing as it allows the {@link Toolbar} to be fixed in place even though this layout is
- * moving. See {@link LayoutParams#COLLAPSE_MODE_PIN}.
- *
- * <p><strong>Do not manually add views to the Toolbar at run time</strong>.
- * We will add a 'dummy view' to the Toolbar which allows us to work out the available space
- * for the title. This can interfere with any views which you add.</p>
- *
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_collapsedTitleTextAppearance
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleTextAppearance
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_contentScrim
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMargin
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginStart
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginEnd
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginBottom
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_statusBarScrim
- * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_toolbarId
- */
-public class CollapsingToolbarLayout extends FrameLayout {
-
-    private static final int DEFAULT_SCRIM_ANIMATION_DURATION = 600;
-
-    private boolean mRefreshToolbar = true;
-    private int mToolbarId;
-    private Toolbar mToolbar;
-    private View mToolbarDirectChild;
-    private View mDummyView;
-
-    private int mExpandedMarginStart;
-    private int mExpandedMarginTop;
-    private int mExpandedMarginEnd;
-    private int mExpandedMarginBottom;
-
-    private final Rect mTmpRect = new Rect();
-    final CollapsingTextHelper mCollapsingTextHelper;
-    private boolean mCollapsingTitleEnabled;
-    private boolean mDrawCollapsingTitle;
-
-    private Drawable mContentScrim;
-    Drawable mStatusBarScrim;
-    private int mScrimAlpha;
-    private boolean mScrimsAreShown;
-    private ValueAnimator mScrimAnimator;
-    private long mScrimAnimationDuration;
-    private int mScrimVisibleHeightTrigger = -1;
-
-    private AppBarLayout.OnOffsetChangedListener mOnOffsetChangedListener;
-
-    int mCurrentOffset;
-
-    WindowInsetsCompat mLastInsets;
-
-    public CollapsingToolbarLayout(Context context) {
-        this(context, null);
-    }
-
-    public CollapsingToolbarLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CollapsingToolbarLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        ThemeUtils.checkAppCompatTheme(context);
-
-        mCollapsingTextHelper = new CollapsingTextHelper(this);
-        mCollapsingTextHelper.setTextSizeInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
-
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.CollapsingToolbarLayout, defStyleAttr,
-                R.style.Widget_Design_CollapsingToolbar);
-
-        mCollapsingTextHelper.setExpandedTextGravity(
-                a.getInt(R.styleable.CollapsingToolbarLayout_expandedTitleGravity,
-                        GravityCompat.START | Gravity.BOTTOM));
-        mCollapsingTextHelper.setCollapsedTextGravity(
-                a.getInt(R.styleable.CollapsingToolbarLayout_collapsedTitleGravity,
-                        GravityCompat.START | Gravity.CENTER_VERTICAL));
-
-        mExpandedMarginStart = mExpandedMarginTop = mExpandedMarginEnd = mExpandedMarginBottom =
-                a.getDimensionPixelSize(R.styleable.CollapsingToolbarLayout_expandedTitleMargin, 0);
-
-        if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginStart)) {
-            mExpandedMarginStart = a.getDimensionPixelSize(
-                    R.styleable.CollapsingToolbarLayout_expandedTitleMarginStart, 0);
-        }
-        if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginEnd)) {
-            mExpandedMarginEnd = a.getDimensionPixelSize(
-                    R.styleable.CollapsingToolbarLayout_expandedTitleMarginEnd, 0);
-        }
-        if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginTop)) {
-            mExpandedMarginTop = a.getDimensionPixelSize(
-                    R.styleable.CollapsingToolbarLayout_expandedTitleMarginTop, 0);
-        }
-        if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleMarginBottom)) {
-            mExpandedMarginBottom = a.getDimensionPixelSize(
-                    R.styleable.CollapsingToolbarLayout_expandedTitleMarginBottom, 0);
-        }
-
-        mCollapsingTitleEnabled = a.getBoolean(
-                R.styleable.CollapsingToolbarLayout_titleEnabled, true);
-        setTitle(a.getText(R.styleable.CollapsingToolbarLayout_title));
-
-        // First load the default text appearances
-        mCollapsingTextHelper.setExpandedTextAppearance(
-                R.style.TextAppearance_Design_CollapsingToolbar_Expanded);
-        mCollapsingTextHelper.setCollapsedTextAppearance(
-                android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Widget_ActionBar_Title);
-
-        // Now overlay any custom text appearances
-        if (a.hasValue(R.styleable.CollapsingToolbarLayout_expandedTitleTextAppearance)) {
-            mCollapsingTextHelper.setExpandedTextAppearance(
-                    a.getResourceId(
-                            R.styleable.CollapsingToolbarLayout_expandedTitleTextAppearance, 0));
-        }
-        if (a.hasValue(R.styleable.CollapsingToolbarLayout_collapsedTitleTextAppearance)) {
-            mCollapsingTextHelper.setCollapsedTextAppearance(
-                    a.getResourceId(
-                            R.styleable.CollapsingToolbarLayout_collapsedTitleTextAppearance, 0));
-        }
-
-        mScrimVisibleHeightTrigger = a.getDimensionPixelSize(
-                R.styleable.CollapsingToolbarLayout_scrimVisibleHeightTrigger, -1);
-
-        mScrimAnimationDuration = a.getInt(
-                R.styleable.CollapsingToolbarLayout_scrimAnimationDuration,
-                DEFAULT_SCRIM_ANIMATION_DURATION);
-
-        setContentScrim(a.getDrawable(R.styleable.CollapsingToolbarLayout_contentScrim));
-        setStatusBarScrim(a.getDrawable(R.styleable.CollapsingToolbarLayout_statusBarScrim));
-
-        mToolbarId = a.getResourceId(R.styleable.CollapsingToolbarLayout_toolbarId, -1);
-
-        a.recycle();
-
-        setWillNotDraw(false);
-
-        ViewCompat.setOnApplyWindowInsetsListener(this,
-                new android.support.v4.view.OnApplyWindowInsetsListener() {
-                    @Override
-                    public WindowInsetsCompat onApplyWindowInsets(View v,
-                            WindowInsetsCompat insets) {
-                        return onWindowInsetChanged(insets);
-                    }
-                });
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        // Add an OnOffsetChangedListener if possible
-        final ViewParent parent = getParent();
-        if (parent instanceof AppBarLayout) {
-            // Copy over from the ABL whether we should fit system windows
-            ViewCompat.setFitsSystemWindows(this, ViewCompat.getFitsSystemWindows((View) parent));
-
-            if (mOnOffsetChangedListener == null) {
-                mOnOffsetChangedListener = new OffsetUpdateListener();
-            }
-            ((AppBarLayout) parent).addOnOffsetChangedListener(mOnOffsetChangedListener);
-
-            // We're attached, so lets request an inset dispatch
-            ViewCompat.requestApplyInsets(this);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        // Remove our OnOffsetChangedListener if possible and it exists
-        final ViewParent parent = getParent();
-        if (mOnOffsetChangedListener != null && parent instanceof AppBarLayout) {
-            ((AppBarLayout) parent).removeOnOffsetChangedListener(mOnOffsetChangedListener);
-        }
-
-        super.onDetachedFromWindow();
-    }
-
-    WindowInsetsCompat onWindowInsetChanged(final WindowInsetsCompat insets) {
-        WindowInsetsCompat newInsets = null;
-
-        if (ViewCompat.getFitsSystemWindows(this)) {
-            // If we're set to fit system windows, keep the insets
-            newInsets = insets;
-        }
-
-        // If our insets have changed, keep them and invalidate the scroll ranges...
-        if (!ObjectsCompat.equals(mLastInsets, newInsets)) {
-            mLastInsets = newInsets;
-            requestLayout();
-        }
-
-        // Consume the insets. This is done so that child views with fitSystemWindows=true do not
-        // get the default padding functionality from View
-        return insets.consumeSystemWindowInsets();
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        // If we don't have a toolbar, the scrim will be not be drawn in drawChild() below.
-        // Instead, we draw it here, before our collapsing text.
-        ensureToolbar();
-        if (mToolbar == null && mContentScrim != null && mScrimAlpha > 0) {
-            mContentScrim.mutate().setAlpha(mScrimAlpha);
-            mContentScrim.draw(canvas);
-        }
-
-        // Let the collapsing text helper draw its text
-        if (mCollapsingTitleEnabled && mDrawCollapsingTitle) {
-            mCollapsingTextHelper.draw(canvas);
-        }
-
-        // Now draw the status bar scrim
-        if (mStatusBarScrim != null && mScrimAlpha > 0) {
-            final int topInset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
-            if (topInset > 0) {
-                mStatusBarScrim.setBounds(0, -mCurrentOffset, getWidth(),
-                        topInset - mCurrentOffset);
-                mStatusBarScrim.mutate().setAlpha(mScrimAlpha);
-                mStatusBarScrim.draw(canvas);
-            }
-        }
-    }
-
-    @Override
-    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
-        // This is a little weird. Our scrim needs to be behind the Toolbar (if it is present),
-        // but in front of any other children which are behind it. To do this we intercept the
-        // drawChild() call, and draw our scrim just before the Toolbar is drawn
-        boolean invalidated = false;
-        if (mContentScrim != null && mScrimAlpha > 0 && isToolbarChild(child)) {
-            mContentScrim.mutate().setAlpha(mScrimAlpha);
-            mContentScrim.draw(canvas);
-            invalidated = true;
-        }
-        return super.drawChild(canvas, child, drawingTime) || invalidated;
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        if (mContentScrim != null) {
-            mContentScrim.setBounds(0, 0, w, h);
-        }
-    }
-
-    private void ensureToolbar() {
-        if (!mRefreshToolbar) {
-            return;
-        }
-
-        // First clear out the current Toolbar
-        mToolbar = null;
-        mToolbarDirectChild = null;
-
-        if (mToolbarId != -1) {
-            // If we have an ID set, try and find it and it's direct parent to us
-            mToolbar = findViewById(mToolbarId);
-            if (mToolbar != null) {
-                mToolbarDirectChild = findDirectChild(mToolbar);
-            }
-        }
-
-        if (mToolbar == null) {
-            // If we don't have an ID, or couldn't find a Toolbar with the correct ID, try and find
-            // one from our direct children
-            Toolbar toolbar = null;
-            for (int i = 0, count = getChildCount(); i < count; i++) {
-                final View child = getChildAt(i);
-                if (child instanceof Toolbar) {
-                    toolbar = (Toolbar) child;
-                    break;
-                }
-            }
-            mToolbar = toolbar;
-        }
-
-        updateDummyView();
-        mRefreshToolbar = false;
-    }
-
-    private boolean isToolbarChild(View child) {
-        return (mToolbarDirectChild == null || mToolbarDirectChild == this)
-                ? child == mToolbar
-                : child == mToolbarDirectChild;
-    }
-
-    /**
-     * Returns the direct child of this layout, which itself is the ancestor of the
-     * given view.
-     */
-    private View findDirectChild(final View descendant) {
-        View directChild = descendant;
-        for (ViewParent p = descendant.getParent(); p != this && p != null; p = p.getParent()) {
-            if (p instanceof View) {
-                directChild = (View) p;
-            }
-        }
-        return directChild;
-    }
-
-    private void updateDummyView() {
-        if (!mCollapsingTitleEnabled && mDummyView != null) {
-            // If we have a dummy view and we have our title disabled, remove it from its parent
-            final ViewParent parent = mDummyView.getParent();
-            if (parent instanceof ViewGroup) {
-                ((ViewGroup) parent).removeView(mDummyView);
-            }
-        }
-        if (mCollapsingTitleEnabled && mToolbar != null) {
-            if (mDummyView == null) {
-                mDummyView = new View(getContext());
-            }
-            if (mDummyView.getParent() == null) {
-                mToolbar.addView(mDummyView, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-            }
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        ensureToolbar();
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        final int mode = MeasureSpec.getMode(heightMeasureSpec);
-        final int topInset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
-        if (mode == MeasureSpec.UNSPECIFIED && topInset > 0) {
-            // If we have a top inset and we're set to wrap_content height we need to make sure
-            // we add the top inset to our height, therefore we re-measure
-            heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                    getMeasuredHeight() + topInset, MeasureSpec.EXACTLY);
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-
-        if (mLastInsets != null) {
-            // Shift down any views which are not set to fit system windows
-            final int insetTop = mLastInsets.getSystemWindowInsetTop();
-            for (int i = 0, z = getChildCount(); i < z; i++) {
-                final View child = getChildAt(i);
-                if (!ViewCompat.getFitsSystemWindows(child)) {
-                    if (child.getTop() < insetTop) {
-                        // If the child isn't set to fit system windows but is drawing within
-                        // the inset offset it down
-                        ViewCompat.offsetTopAndBottom(child, insetTop);
-                    }
-                }
-            }
-        }
-
-        // Update the collapsed bounds by getting it's transformed bounds
-        if (mCollapsingTitleEnabled && mDummyView != null) {
-            // We only draw the title if the dummy view is being displayed (Toolbar removes
-            // views if there is no space)
-            mDrawCollapsingTitle = ViewCompat.isAttachedToWindow(mDummyView)
-                    && mDummyView.getVisibility() == VISIBLE;
-
-            if (mDrawCollapsingTitle) {
-                final boolean isRtl = ViewCompat.getLayoutDirection(this)
-                        == ViewCompat.LAYOUT_DIRECTION_RTL;
-
-                // Update the collapsed bounds
-                final int maxOffset = getMaxOffsetForPinChild(
-                        mToolbarDirectChild != null ? mToolbarDirectChild : mToolbar);
-                ViewGroupUtils.getDescendantRect(this, mDummyView, mTmpRect);
-                mCollapsingTextHelper.setCollapsedBounds(
-                        mTmpRect.left + (isRtl
-                                ? mToolbar.getTitleMarginEnd()
-                                : mToolbar.getTitleMarginStart()),
-                        mTmpRect.top + maxOffset + mToolbar.getTitleMarginTop(),
-                        mTmpRect.right + (isRtl
-                                ? mToolbar.getTitleMarginStart()
-                                : mToolbar.getTitleMarginEnd()),
-                        mTmpRect.bottom + maxOffset - mToolbar.getTitleMarginBottom());
-
-                // Update the expanded bounds
-                mCollapsingTextHelper.setExpandedBounds(
-                        isRtl ? mExpandedMarginEnd : mExpandedMarginStart,
-                        mTmpRect.top + mExpandedMarginTop,
-                        right - left - (isRtl ? mExpandedMarginStart : mExpandedMarginEnd),
-                        bottom - top - mExpandedMarginBottom);
-                // Now recalculate using the new bounds
-                mCollapsingTextHelper.recalculate();
-            }
-        }
-
-        // Update our child view offset helpers. This needs to be done after the title has been
-        // setup, so that any Toolbars are in their original position
-        for (int i = 0, z = getChildCount(); i < z; i++) {
-            getViewOffsetHelper(getChildAt(i)).onViewLayout();
-        }
-
-        // Finally, set our minimum height to enable proper AppBarLayout collapsing
-        if (mToolbar != null) {
-            if (mCollapsingTitleEnabled && TextUtils.isEmpty(mCollapsingTextHelper.getText())) {
-                // If we do not currently have a title, try and grab it from the Toolbar
-                mCollapsingTextHelper.setText(mToolbar.getTitle());
-            }
-            if (mToolbarDirectChild == null || mToolbarDirectChild == this) {
-                setMinimumHeight(getHeightWithMargins(mToolbar));
-            } else {
-                setMinimumHeight(getHeightWithMargins(mToolbarDirectChild));
-            }
-        }
-
-        updateScrimVisibility();
-    }
-
-    private static int getHeightWithMargins(@NonNull final View view) {
-        final ViewGroup.LayoutParams lp = view.getLayoutParams();
-        if (lp instanceof MarginLayoutParams) {
-            final MarginLayoutParams mlp = (MarginLayoutParams) lp;
-            return view.getHeight() + mlp.topMargin + mlp.bottomMargin;
-        }
-        return view.getHeight();
-    }
-
-    static ViewOffsetHelper getViewOffsetHelper(View view) {
-        ViewOffsetHelper offsetHelper = (ViewOffsetHelper) view.getTag(R.id.view_offset_helper);
-        if (offsetHelper == null) {
-            offsetHelper = new ViewOffsetHelper(view);
-            view.setTag(R.id.view_offset_helper, offsetHelper);
-        }
-        return offsetHelper;
-    }
-
-    /**
-     * Sets the title to be displayed by this view, if enabled.
-     *
-     * @see #setTitleEnabled(boolean)
-     * @see #getTitle()
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_title
-     */
-    public void setTitle(@Nullable CharSequence title) {
-        mCollapsingTextHelper.setText(title);
-    }
-
-    /**
-     * Returns the title currently being displayed by this view. If the title is not enabled, then
-     * this will return {@code null}.
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_title
-     */
-    @Nullable
-    public CharSequence getTitle() {
-        return mCollapsingTitleEnabled ? mCollapsingTextHelper.getText() : null;
-    }
-
-    /**
-     * Sets whether this view should display its own title.
-     *
-     * <p>The title displayed by this view will shrink and grow based on the scroll offset.</p>
-     *
-     * @see #setTitle(CharSequence)
-     * @see #isTitleEnabled()
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_titleEnabled
-     */
-    public void setTitleEnabled(boolean enabled) {
-        if (enabled != mCollapsingTitleEnabled) {
-            mCollapsingTitleEnabled = enabled;
-            updateDummyView();
-            requestLayout();
-        }
-    }
-
-    /**
-     * Returns whether this view is currently displaying its own title.
-     *
-     * @see #setTitleEnabled(boolean)
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_titleEnabled
-     */
-    public boolean isTitleEnabled() {
-        return mCollapsingTitleEnabled;
-    }
-
-    /**
-     * Set whether the content scrim and/or status bar scrim should be shown or not. Any change
-     * in the vertical scroll may overwrite this value. Any visibility change will be animated if
-     * this view has already been laid out.
-     *
-     * @param shown whether the scrims should be shown
-     *
-     * @see #getStatusBarScrim()
-     * @see #getContentScrim()
-     */
-    public void setScrimsShown(boolean shown) {
-        setScrimsShown(shown, ViewCompat.isLaidOut(this) && !isInEditMode());
-    }
-
-    /**
-     * Set whether the content scrim and/or status bar scrim should be shown or not. Any change
-     * in the vertical scroll may overwrite this value.
-     *
-     * @param shown whether the scrims should be shown
-     * @param animate whether to animate the visibility change
-     *
-     * @see #getStatusBarScrim()
-     * @see #getContentScrim()
-     */
-    public void setScrimsShown(boolean shown, boolean animate) {
-        if (mScrimsAreShown != shown) {
-            if (animate) {
-                animateScrim(shown ? 0xFF : 0x0);
-            } else {
-                setScrimAlpha(shown ? 0xFF : 0x0);
-            }
-            mScrimsAreShown = shown;
-        }
-    }
-
-    private void animateScrim(int targetAlpha) {
-        ensureToolbar();
-        if (mScrimAnimator == null) {
-            mScrimAnimator = new ValueAnimator();
-            mScrimAnimator.setDuration(mScrimAnimationDuration);
-            mScrimAnimator.setInterpolator(
-                    targetAlpha > mScrimAlpha
-                            ? AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR
-                            : AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR);
-            mScrimAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animator) {
-                    setScrimAlpha((int) animator.getAnimatedValue());
-                }
-            });
-        } else if (mScrimAnimator.isRunning()) {
-            mScrimAnimator.cancel();
-        }
-
-        mScrimAnimator.setIntValues(mScrimAlpha, targetAlpha);
-        mScrimAnimator.start();
-    }
-
-    void setScrimAlpha(int alpha) {
-        if (alpha != mScrimAlpha) {
-            final Drawable contentScrim = mContentScrim;
-            if (contentScrim != null && mToolbar != null) {
-                ViewCompat.postInvalidateOnAnimation(mToolbar);
-            }
-            mScrimAlpha = alpha;
-            ViewCompat.postInvalidateOnAnimation(CollapsingToolbarLayout.this);
-        }
-    }
-
-    int getScrimAlpha() {
-        return mScrimAlpha;
-    }
-
-    /**
-     * Set the drawable to use for the content scrim from resources. Providing null will disable
-     * the scrim functionality.
-     *
-     * @param drawable the drawable to display
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_contentScrim
-     * @see #getContentScrim()
-     */
-    public void setContentScrim(@Nullable Drawable drawable) {
-        if (mContentScrim != drawable) {
-            if (mContentScrim != null) {
-                mContentScrim.setCallback(null);
-            }
-            mContentScrim = drawable != null ? drawable.mutate() : null;
-            if (mContentScrim != null) {
-                mContentScrim.setBounds(0, 0, getWidth(), getHeight());
-                mContentScrim.setCallback(this);
-                mContentScrim.setAlpha(mScrimAlpha);
-            }
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    /**
-     * Set the color to use for the content scrim.
-     *
-     * @param color the color to display
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_contentScrim
-     * @see #getContentScrim()
-     */
-    public void setContentScrimColor(@ColorInt int color) {
-        setContentScrim(new ColorDrawable(color));
-    }
-
-    /**
-     * Set the drawable to use for the content scrim from resources.
-     *
-     * @param resId drawable resource id
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_contentScrim
-     * @see #getContentScrim()
-     */
-    public void setContentScrimResource(@DrawableRes int resId) {
-        setContentScrim(ContextCompat.getDrawable(getContext(), resId));
-
-    }
-
-    /**
-     * Returns the drawable which is used for the foreground scrim.
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_contentScrim
-     * @see #setContentScrim(Drawable)
-     */
-    @Nullable
-    public Drawable getContentScrim() {
-        return mContentScrim;
-    }
-
-    /**
-     * Set the drawable to use for the status bar scrim from resources.
-     * Providing null will disable the scrim functionality.
-     *
-     * <p>This scrim is only shown when we have been given a top system inset.</p>
-     *
-     * @param drawable the drawable to display
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_statusBarScrim
-     * @see #getStatusBarScrim()
-     */
-    public void setStatusBarScrim(@Nullable Drawable drawable) {
-        if (mStatusBarScrim != drawable) {
-            if (mStatusBarScrim != null) {
-                mStatusBarScrim.setCallback(null);
-            }
-            mStatusBarScrim = drawable != null ? drawable.mutate() : null;
-            if (mStatusBarScrim != null) {
-                if (mStatusBarScrim.isStateful()) {
-                    mStatusBarScrim.setState(getDrawableState());
-                }
-                DrawableCompat.setLayoutDirection(mStatusBarScrim,
-                        ViewCompat.getLayoutDirection(this));
-                mStatusBarScrim.setVisible(getVisibility() == VISIBLE, false);
-                mStatusBarScrim.setCallback(this);
-                mStatusBarScrim.setAlpha(mScrimAlpha);
-            }
-            ViewCompat.postInvalidateOnAnimation(this);
-        }
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-
-        final int[] state = getDrawableState();
-        boolean changed = false;
-
-        Drawable d = mStatusBarScrim;
-        if (d != null && d.isStateful()) {
-            changed |= d.setState(state);
-        }
-        d = mContentScrim;
-        if (d != null && d.isStateful()) {
-            changed |= d.setState(state);
-        }
-        if (mCollapsingTextHelper != null) {
-            changed |= mCollapsingTextHelper.setState(state);
-        }
-
-        if (changed) {
-            invalidate();
-        }
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == mContentScrim || who == mStatusBarScrim;
-    }
-
-    @Override
-    public void setVisibility(int visibility) {
-        super.setVisibility(visibility);
-
-        final boolean visible = visibility == VISIBLE;
-        if (mStatusBarScrim != null && mStatusBarScrim.isVisible() != visible) {
-            mStatusBarScrim.setVisible(visible, false);
-        }
-        if (mContentScrim != null && mContentScrim.isVisible() != visible) {
-            mContentScrim.setVisible(visible, false);
-        }
-    }
-
-    /**
-     * Set the color to use for the status bar scrim.
-     *
-     * <p>This scrim is only shown when we have been given a top system inset.</p>
-     *
-     * @param color the color to display
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_statusBarScrim
-     * @see #getStatusBarScrim()
-     */
-    public void setStatusBarScrimColor(@ColorInt int color) {
-        setStatusBarScrim(new ColorDrawable(color));
-    }
-
-    /**
-     * Set the drawable to use for the content scrim from resources.
-     *
-     * @param resId drawable resource id
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_statusBarScrim
-     * @see #getStatusBarScrim()
-     */
-    public void setStatusBarScrimResource(@DrawableRes int resId) {
-        setStatusBarScrim(ContextCompat.getDrawable(getContext(), resId));
-    }
-
-    /**
-     * Returns the drawable which is used for the status bar scrim.
-     *
-     * @attr ref R.styleable#CollapsingToolbarLayout_statusBarScrim
-     * @see #setStatusBarScrim(Drawable)
-     */
-    @Nullable
-    public Drawable getStatusBarScrim() {
-        return mStatusBarScrim;
-    }
-
-    /**
-     * Sets the text color and size for the collapsed title from the specified
-     * TextAppearance resource.
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_collapsedTitleTextAppearance
-     */
-    public void setCollapsedTitleTextAppearance(@StyleRes int resId) {
-        mCollapsingTextHelper.setCollapsedTextAppearance(resId);
-    }
-
-    /**
-     * Sets the text color of the collapsed title.
-     *
-     * @param color The new text color in ARGB format
-     */
-    public void setCollapsedTitleTextColor(@ColorInt int color) {
-        setCollapsedTitleTextColor(ColorStateList.valueOf(color));
-    }
-
-    /**
-     * Sets the text colors of the collapsed title.
-     *
-     * @param colors ColorStateList containing the new text colors
-     */
-    public void setCollapsedTitleTextColor(@NonNull ColorStateList colors) {
-        mCollapsingTextHelper.setCollapsedTextColor(colors);
-    }
-
-    /**
-     * Sets the horizontal alignment of the collapsed title and the vertical gravity that will
-     * be used when there is extra space in the collapsed bounds beyond what is required for
-     * the title itself.
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_collapsedTitleGravity
-     */
-    public void setCollapsedTitleGravity(int gravity) {
-        mCollapsingTextHelper.setCollapsedTextGravity(gravity);
-    }
-
-    /**
-     * Returns the horizontal and vertical alignment for title when collapsed.
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_collapsedTitleGravity
-     */
-    public int getCollapsedTitleGravity() {
-        return mCollapsingTextHelper.getCollapsedTextGravity();
-    }
-
-    /**
-     * Sets the text color and size for the expanded title from the specified
-     * TextAppearance resource.
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleTextAppearance
-     */
-    public void setExpandedTitleTextAppearance(@StyleRes int resId) {
-        mCollapsingTextHelper.setExpandedTextAppearance(resId);
-    }
-
-    /**
-     * Sets the text color of the expanded title.
-     *
-     * @param color The new text color in ARGB format
-     */
-    public void setExpandedTitleColor(@ColorInt int color) {
-        setExpandedTitleTextColor(ColorStateList.valueOf(color));
-    }
-
-    /**
-     * Sets the text colors of the expanded title.
-     *
-     * @param colors ColorStateList containing the new text colors
-     */
-    public void setExpandedTitleTextColor(@NonNull ColorStateList colors) {
-        mCollapsingTextHelper.setExpandedTextColor(colors);
-    }
-
-    /**
-     * Sets the horizontal alignment of the expanded title and the vertical gravity that will
-     * be used when there is extra space in the expanded bounds beyond what is required for
-     * the title itself.
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleGravity
-     */
-    public void setExpandedTitleGravity(int gravity) {
-        mCollapsingTextHelper.setExpandedTextGravity(gravity);
-    }
-
-    /**
-     * Returns the horizontal and vertical alignment for title when expanded.
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleGravity
-     */
-    public int getExpandedTitleGravity() {
-        return mCollapsingTextHelper.getExpandedTextGravity();
-    }
-
-    /**
-     * Set the typeface to use for the collapsed title.
-     *
-     * @param typeface typeface to use, or {@code null} to use the default.
-     */
-    public void setCollapsedTitleTypeface(@Nullable Typeface typeface) {
-        mCollapsingTextHelper.setCollapsedTypeface(typeface);
-    }
-
-    /**
-     * Returns the typeface used for the collapsed title.
-     */
-    @NonNull
-    public Typeface getCollapsedTitleTypeface() {
-        return mCollapsingTextHelper.getCollapsedTypeface();
-    }
-
-    /**
-     * Set the typeface to use for the expanded title.
-     *
-     * @param typeface typeface to use, or {@code null} to use the default.
-     */
-    public void setExpandedTitleTypeface(@Nullable Typeface typeface) {
-        mCollapsingTextHelper.setExpandedTypeface(typeface);
-    }
-
-    /**
-     * Returns the typeface used for the expanded title.
-     */
-    @NonNull
-    public Typeface getExpandedTitleTypeface() {
-        return mCollapsingTextHelper.getExpandedTypeface();
-    }
-
-    /**
-     * Sets the expanded title margins.
-     *
-     * @param start the starting title margin in pixels
-     * @param top the top title margin in pixels
-     * @param end the ending title margin in pixels
-     * @param bottom the bottom title margin in pixels
-     *
-     * @see #getExpandedTitleMarginStart()
-     * @see #getExpandedTitleMarginTop()
-     * @see #getExpandedTitleMarginEnd()
-     * @see #getExpandedTitleMarginBottom()
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMargin
-     */
-    public void setExpandedTitleMargin(int start, int top, int end, int bottom) {
-        mExpandedMarginStart = start;
-        mExpandedMarginTop = top;
-        mExpandedMarginEnd = end;
-        mExpandedMarginBottom = bottom;
-        requestLayout();
-    }
-
-    /**
-     * @return the starting expanded title margin in pixels
-     *
-     * @see #setExpandedTitleMarginStart(int)
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginStart
-     */
-    public int getExpandedTitleMarginStart() {
-        return mExpandedMarginStart;
-    }
-
-    /**
-     * Sets the starting expanded title margin in pixels.
-     *
-     * @param margin the starting title margin in pixels
-     * @see #getExpandedTitleMarginStart()
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginStart
-     */
-    public void setExpandedTitleMarginStart(int margin) {
-        mExpandedMarginStart = margin;
-        requestLayout();
-    }
-
-    /**
-     * @return the top expanded title margin in pixels
-     * @see #setExpandedTitleMarginTop(int)
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginTop
-     */
-    public int getExpandedTitleMarginTop() {
-        return mExpandedMarginTop;
-    }
-
-    /**
-     * Sets the top expanded title margin in pixels.
-     *
-     * @param margin the top title margin in pixels
-     * @see #getExpandedTitleMarginTop()
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginTop
-     */
-    public void setExpandedTitleMarginTop(int margin) {
-        mExpandedMarginTop = margin;
-        requestLayout();
-    }
-
-    /**
-     * @return the ending expanded title margin in pixels
-     * @see #setExpandedTitleMarginEnd(int)
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginEnd
-     */
-    public int getExpandedTitleMarginEnd() {
-        return mExpandedMarginEnd;
-    }
-
-    /**
-     * Sets the ending expanded title margin in pixels.
-     *
-     * @param margin the ending title margin in pixels
-     * @see #getExpandedTitleMarginEnd()
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginEnd
-     */
-    public void setExpandedTitleMarginEnd(int margin) {
-        mExpandedMarginEnd = margin;
-        requestLayout();
-    }
-
-    /**
-     * @return the bottom expanded title margin in pixels
-     * @see #setExpandedTitleMarginBottom(int)
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginBottom
-     */
-    public int getExpandedTitleMarginBottom() {
-        return mExpandedMarginBottom;
-    }
-
-    /**
-     * Sets the bottom expanded title margin in pixels.
-     *
-     * @param margin the bottom title margin in pixels
-     * @see #getExpandedTitleMarginBottom()
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_expandedTitleMarginBottom
-     */
-    public void setExpandedTitleMarginBottom(int margin) {
-        mExpandedMarginBottom = margin;
-        requestLayout();
-    }
-
-    /**
-     * Set the amount of visible height in pixels used to define when to trigger a scrim
-     * visibility change.
-     *
-     * <p>If the visible height of this view is less than the given value, the scrims will be
-     * made visible, otherwise they are hidden.</p>
-     *
-     * @param height value in pixels used to define when to trigger a scrim visibility change
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_scrimVisibleHeightTrigger
-     */
-    public void setScrimVisibleHeightTrigger(@IntRange(from = 0) final int height) {
-        if (mScrimVisibleHeightTrigger != height) {
-            mScrimVisibleHeightTrigger = height;
-            // Update the scrim visibility
-            updateScrimVisibility();
-        }
-    }
-
-    /**
-     * Returns the amount of visible height in pixels used to define when to trigger a scrim
-     * visibility change.
-     *
-     * @see #setScrimVisibleHeightTrigger(int)
-     */
-    public int getScrimVisibleHeightTrigger() {
-        if (mScrimVisibleHeightTrigger >= 0) {
-            // If we have one explicitly set, return it
-            return mScrimVisibleHeightTrigger;
-        }
-
-        // Otherwise we'll use the default computed value
-        final int insetTop = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
-
-        final int minHeight = ViewCompat.getMinimumHeight(this);
-        if (minHeight > 0) {
-            // If we have a minHeight set, lets use 2 * minHeight (capped at our height)
-            return Math.min((minHeight * 2) + insetTop, getHeight());
-        }
-
-        // If we reach here then we don't have a min height set. Instead we'll take a
-        // guess at 1/3 of our height being visible
-        return getHeight() / 3;
-    }
-
-    /**
-     * Set the duration used for scrim visibility animations.
-     *
-     * @param duration the duration to use in milliseconds
-     *
-     * @attr ref android.support.design.R.styleable#CollapsingToolbarLayout_scrimAnimationDuration
-     */
-    public void setScrimAnimationDuration(@IntRange(from = 0) final long duration) {
-        mScrimAnimationDuration = duration;
-    }
-
-    /**
-     * Returns the duration in milliseconds used for scrim visibility animations.
-     */
-    public long getScrimAnimationDuration() {
-        return mScrimAnimationDuration;
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof LayoutParams;
-    }
-
-    @Override
-    protected LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-    }
-
-    @Override
-    public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new LayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected FrameLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new LayoutParams(p);
-    }
-
-    public static class LayoutParams extends FrameLayout.LayoutParams {
-
-        private static final float DEFAULT_PARALLAX_MULTIPLIER = 0.5f;
-
-        /** @hide */
-        @RestrictTo(LIBRARY_GROUP)
-        @IntDef({
-                COLLAPSE_MODE_OFF,
-                COLLAPSE_MODE_PIN,
-                COLLAPSE_MODE_PARALLAX
-        })
-        @Retention(RetentionPolicy.SOURCE)
-        @interface CollapseMode {}
-
-        /**
-         * The view will act as normal with no collapsing behavior.
-         */
-        public static final int COLLAPSE_MODE_OFF = 0;
-
-        /**
-         * The view will pin in place until it reaches the bottom of the
-         * {@link CollapsingToolbarLayout}.
-         */
-        public static final int COLLAPSE_MODE_PIN = 1;
-
-        /**
-         * The view will scroll in a parallax fashion. See {@link #setParallaxMultiplier(float)}
-         * to change the multiplier used.
-         */
-        public static final int COLLAPSE_MODE_PARALLAX = 2;
-
-        int mCollapseMode = COLLAPSE_MODE_OFF;
-        float mParallaxMult = DEFAULT_PARALLAX_MULTIPLIER;
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-
-            TypedArray a = c.obtainStyledAttributes(attrs,
-                    R.styleable.CollapsingToolbarLayout_Layout);
-            mCollapseMode = a.getInt(
-                    R.styleable.CollapsingToolbarLayout_Layout_layout_collapseMode,
-                    COLLAPSE_MODE_OFF);
-            setParallaxMultiplier(a.getFloat(
-                    R.styleable.CollapsingToolbarLayout_Layout_layout_collapseParallaxMultiplier,
-                    DEFAULT_PARALLAX_MULTIPLIER));
-            a.recycle();
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(int width, int height, int gravity) {
-            super(width, height, gravity);
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams p) {
-            super(p);
-        }
-
-        public LayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-
-        @RequiresApi(19)
-        public LayoutParams(FrameLayout.LayoutParams source) {
-            // The copy constructor called here only exists on API 19+.
-            super(source);
-        }
-
-        /**
-         * Set the collapse mode.
-         *
-         * @param collapseMode one of {@link #COLLAPSE_MODE_OFF}, {@link #COLLAPSE_MODE_PIN}
-         *                     or {@link #COLLAPSE_MODE_PARALLAX}.
-         */
-        public void setCollapseMode(@CollapseMode int collapseMode) {
-            mCollapseMode = collapseMode;
-        }
-
-        /**
-         * Returns the requested collapse mode.
-         *
-         * @return the current mode. One of {@link #COLLAPSE_MODE_OFF}, {@link #COLLAPSE_MODE_PIN}
-         * or {@link #COLLAPSE_MODE_PARALLAX}.
-         */
-        @CollapseMode
-        public int getCollapseMode() {
-            return mCollapseMode;
-        }
-
-        /**
-         * Set the parallax scroll multiplier used in conjunction with
-         * {@link #COLLAPSE_MODE_PARALLAX}. A value of {@code 0.0} indicates no movement at all,
-         * {@code 1.0f} indicates normal scroll movement.
-         *
-         * @param multiplier the multiplier.
-         *
-         * @see #getParallaxMultiplier()
-         */
-        public void setParallaxMultiplier(float multiplier) {
-            mParallaxMult = multiplier;
-        }
-
-        /**
-         * Returns the parallax scroll multiplier used in conjunction with
-         * {@link #COLLAPSE_MODE_PARALLAX}.
-         *
-         * @see #setParallaxMultiplier(float)
-         */
-        public float getParallaxMultiplier() {
-            return mParallaxMult;
-        }
-    }
-
-    /**
-     * Show or hide the scrims if needed
-     */
-    final void updateScrimVisibility() {
-        if (mContentScrim != null || mStatusBarScrim != null) {
-            setScrimsShown(getHeight() + mCurrentOffset < getScrimVisibleHeightTrigger());
-        }
-    }
-
-    final int getMaxOffsetForPinChild(View child) {
-        final ViewOffsetHelper offsetHelper = getViewOffsetHelper(child);
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        return getHeight()
-                - offsetHelper.getLayoutTop()
-                - child.getHeight()
-                - lp.bottomMargin;
-    }
-
-    private class OffsetUpdateListener implements AppBarLayout.OnOffsetChangedListener {
-        OffsetUpdateListener() {
-        }
-
-        @Override
-        public void onOffsetChanged(AppBarLayout layout, int verticalOffset) {
-            mCurrentOffset = verticalOffset;
-
-            final int insetTop = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
-
-            for (int i = 0, z = getChildCount(); i < z; i++) {
-                final View child = getChildAt(i);
-                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                final ViewOffsetHelper offsetHelper = getViewOffsetHelper(child);
-
-                switch (lp.mCollapseMode) {
-                    case LayoutParams.COLLAPSE_MODE_PIN:
-                        offsetHelper.setTopAndBottomOffset(MathUtils.clamp(
-                                -verticalOffset, 0, getMaxOffsetForPinChild(child)));
-                        break;
-                    case LayoutParams.COLLAPSE_MODE_PARALLAX:
-                        offsetHelper.setTopAndBottomOffset(
-                                Math.round(-verticalOffset * lp.mParallaxMult));
-                        break;
-                }
-            }
-
-            // Show or hide the scrims if needed
-            updateScrimVisibility();
-
-            if (mStatusBarScrim != null && insetTop > 0) {
-                ViewCompat.postInvalidateOnAnimation(CollapsingToolbarLayout.this);
-            }
-
-            // Update the collapsing text's fraction
-            final int expandRange = getHeight() - ViewCompat.getMinimumHeight(
-                    CollapsingToolbarLayout.this) - insetTop;
-            mCollapsingTextHelper.setExpansionFraction(
-                    Math.abs(verticalOffset) / (float) expandRange);
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/DrawableUtils.java b/design/src/android/support/design/widget/DrawableUtils.java
deleted file mode 100644
index df1c04b..0000000
--- a/design/src/android/support/design/widget/DrawableUtils.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.DrawableContainer;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-
-/**
- * Caution. Gross hacks ahead.
- */
-class DrawableUtils {
-
-    private static final String LOG_TAG = "DrawableUtils";
-
-    private static Method sSetConstantStateMethod;
-    private static boolean sSetConstantStateMethodFetched;
-
-    private DrawableUtils() {}
-
-    static boolean setContainerConstantState(DrawableContainer drawable,
-            Drawable.ConstantState constantState) {
-        // We can use getDeclaredMethod() on v9+
-        return setContainerConstantStateV9(drawable, constantState);
-    }
-
-    private static boolean setContainerConstantStateV9(DrawableContainer drawable,
-            Drawable.ConstantState constantState) {
-        if (!sSetConstantStateMethodFetched) {
-            try {
-                sSetConstantStateMethod = DrawableContainer.class.getDeclaredMethod(
-                        "setConstantState", DrawableContainer.DrawableContainerState.class);
-                sSetConstantStateMethod.setAccessible(true);
-            } catch (NoSuchMethodException e) {
-                Log.e(LOG_TAG, "Could not fetch setConstantState(). Oh well.");
-            }
-            sSetConstantStateMethodFetched = true;
-        }
-        if (sSetConstantStateMethod != null) {
-            try {
-                sSetConstantStateMethod.invoke(drawable, constantState);
-                return true;
-            } catch (Exception e) {
-                Log.e(LOG_TAG, "Could not invoke setConstantState(). Oh well.");
-            }
-        }
-        return false;
-    }
-}
diff --git a/design/src/android/support/design/widget/FloatingActionButton.java b/design/src/android/support/design/widget/FloatingActionButton.java
deleted file mode 100644
index f37b379..0000000
--- a/design/src/android/support/design/widget/FloatingActionButton.java
+++ /dev/null
@@ -1,870 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.VisibleForTesting;
-import android.support.design.R;
-import android.support.design.widget.FloatingActionButtonImpl.InternalVisibilityChangedListener;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.ViewGroupUtils;
-import android.support.v7.widget.AppCompatImageHelper;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * Floating action buttons are used for a special type of promoted action. They are distinguished
- * by a circled icon floating above the UI and have special motion behaviors related to morphing,
- * launching, and the transferring anchor point.
- *
- * <p>Floating action buttons come in two sizes: the default and the mini. The size can be
- * controlled with the {@code fabSize} attribute.</p>
- *
- * <p>As this class descends from {@link ImageView}, you can control the icon which is displayed
- * via {@link #setImageDrawable(Drawable)}.</p>
- *
- * <p>The background color of this view defaults to the your theme's {@code colorAccent}. If you
- * wish to change this at runtime then you can do so via
- * {@link #setBackgroundTintList(ColorStateList)}.</p>
- */
-@CoordinatorLayout.DefaultBehavior(FloatingActionButton.Behavior.class)
-public class FloatingActionButton extends VisibilityAwareImageButton {
-
-    private static final String LOG_TAG = "FloatingActionButton";
-
-    /**
-     * Callback to be invoked when the visibility of a FloatingActionButton changes.
-     */
-    public abstract static class OnVisibilityChangedListener {
-        /**
-         * Called when a FloatingActionButton has been
-         * {@link #show(OnVisibilityChangedListener) shown}.
-         *
-         * @param fab the FloatingActionButton that was shown.
-         */
-        public void onShown(FloatingActionButton fab) {}
-
-        /**
-         * Called when a FloatingActionButton has been
-         * {@link #hide(OnVisibilityChangedListener) hidden}.
-         *
-         * @param fab the FloatingActionButton that was hidden.
-         */
-        public void onHidden(FloatingActionButton fab) {}
-    }
-
-    // These values must match those in the attrs declaration
-
-    /**
-     * The mini sized button. Will always been smaller than {@link #SIZE_NORMAL}.
-     *
-     * @see #setSize(int)
-     */
-    public static final int SIZE_MINI = 1;
-
-    /**
-     * The normal sized button. Will always been larger than {@link #SIZE_MINI}.
-     *
-     * @see #setSize(int)
-     */
-    public static final int SIZE_NORMAL = 0;
-
-    /**
-     * Size which will change based on the window size. For small sized windows
-     * (largest screen dimension < 470dp) this will select a small sized button, and for
-     * larger sized windows it will select a larger size.
-     *
-     * @see #setSize(int)
-     */
-    public static final int SIZE_AUTO = -1;
-
-    /**
-     * Indicates that FloatingActionButton should not have a custom size.
-     */
-    public static final int NO_CUSTOM_SIZE = 0;
-
-    /**
-     * The switch point for the largest screen edge where SIZE_AUTO switches from mini to normal.
-     */
-    private static final int AUTO_MINI_LARGEST_SCREEN_WIDTH = 470;
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({SIZE_MINI, SIZE_NORMAL, SIZE_AUTO})
-    public @interface Size {}
-
-    private ColorStateList mBackgroundTint;
-    private PorterDuff.Mode mBackgroundTintMode;
-
-    private int mBorderWidth;
-    private int mRippleColor;
-    private int mSize;
-    private int mCustomSize;
-    int mImagePadding;
-    private int mMaxImageSize;
-
-    boolean mCompatPadding;
-    final Rect mShadowPadding = new Rect();
-    private final Rect mTouchArea = new Rect();
-
-    private AppCompatImageHelper mImageHelper;
-
-    private FloatingActionButtonImpl mImpl;
-
-    public FloatingActionButton(Context context) {
-        this(context, null);
-    }
-
-    public FloatingActionButton(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        ThemeUtils.checkAppCompatTheme(context);
-
-        TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.FloatingActionButton, defStyleAttr,
-                R.style.Widget_Design_FloatingActionButton);
-        mBackgroundTint = a.getColorStateList(R.styleable.FloatingActionButton_backgroundTint);
-        mBackgroundTintMode = ViewUtils.parseTintMode(a.getInt(
-                R.styleable.FloatingActionButton_backgroundTintMode, -1), null);
-        mRippleColor = a.getColor(R.styleable.FloatingActionButton_rippleColor, 0);
-        mSize = a.getInt(R.styleable.FloatingActionButton_fabSize, SIZE_AUTO);
-        mCustomSize = a.getDimensionPixelSize(R.styleable.FloatingActionButton_fabCustomSize,
-                    0);
-        mBorderWidth = a.getDimensionPixelSize(R.styleable.FloatingActionButton_borderWidth, 0);
-        final float elevation = a.getDimension(R.styleable.FloatingActionButton_elevation, 0f);
-        final float pressedTranslationZ = a.getDimension(
-                R.styleable.FloatingActionButton_pressedTranslationZ, 0f);
-        mCompatPadding = a.getBoolean(R.styleable.FloatingActionButton_useCompatPadding, false);
-        a.recycle();
-
-        mImageHelper = new AppCompatImageHelper(this);
-        mImageHelper.loadFromAttributes(attrs, defStyleAttr);
-
-        mMaxImageSize = (int) getResources().getDimension(R.dimen.design_fab_image_size);
-
-        getImpl().setBackgroundDrawable(mBackgroundTint, mBackgroundTintMode,
-                mRippleColor, mBorderWidth);
-        getImpl().setElevation(elevation);
-        getImpl().setPressedTranslationZ(pressedTranslationZ);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int preferredSize = getSizeDimension();
-
-        mImagePadding = (preferredSize - mMaxImageSize) / 2;
-        getImpl().updatePadding();
-
-        final int w = resolveAdjustedSize(preferredSize, widthMeasureSpec);
-        final int h = resolveAdjustedSize(preferredSize, heightMeasureSpec);
-
-        // As we want to stay circular, we set both dimensions to be the
-        // smallest resolved dimension
-        final int d = Math.min(w, h);
-
-        // We add the shadow's padding to the measured dimension
-        setMeasuredDimension(
-                d + mShadowPadding.left + mShadowPadding.right,
-                d + mShadowPadding.top + mShadowPadding.bottom);
-    }
-
-    /**
-     * Returns the ripple color for this button.
-     *
-     * @return the ARGB color used for the ripple
-     * @see #setRippleColor(int)
-     */
-    @ColorInt
-    public int getRippleColor() {
-        return mRippleColor;
-    }
-
-    /**
-     * Sets the ripple color for this button.
-     *
-     * <p>When running on devices with KitKat or below, we draw this color as a filled circle
-     * rather than a ripple.</p>
-     *
-     * @param color ARGB color to use for the ripple
-     * @attr ref android.support.design.R.styleable#FloatingActionButton_rippleColor
-     * @see #getRippleColor()
-     */
-    public void setRippleColor(@ColorInt int color) {
-        if (mRippleColor != color) {
-            mRippleColor = color;
-            getImpl().setRippleColor(color);
-        }
-    }
-
-    /**
-     * Returns the tint applied to the background drawable, if specified.
-     *
-     * @return the tint applied to the background drawable
-     * @see #setBackgroundTintList(ColorStateList)
-     */
-    @Nullable
-    @Override
-    public ColorStateList getBackgroundTintList() {
-        return mBackgroundTint;
-    }
-
-    /**
-     * Applies a tint to the background drawable. Does not modify the current tint
-     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
-     *
-     * @param tint the tint to apply, may be {@code null} to clear tint
-     */
-    @Override
-    public void setBackgroundTintList(@Nullable ColorStateList tint) {
-        if (mBackgroundTint != tint) {
-            mBackgroundTint = tint;
-            getImpl().setBackgroundTintList(tint);
-        }
-    }
-
-    /**
-     * Returns the blending mode used to apply the tint to the background
-     * drawable, if specified.
-     *
-     * @return the blending mode used to apply the tint to the background
-     *         drawable
-     * @see #setBackgroundTintMode(PorterDuff.Mode)
-     */
-    @Nullable
-    @Override
-    public PorterDuff.Mode getBackgroundTintMode() {
-        return mBackgroundTintMode;
-    }
-
-    /**
-     * Specifies the blending mode used to apply the tint specified by
-     * {@link #setBackgroundTintList(ColorStateList)}} to the background
-     * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
-     *
-     * @param tintMode the blending mode used to apply the tint, may be
-     *                 {@code null} to clear tint
-     */
-    @Override
-    public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
-        if (mBackgroundTintMode != tintMode) {
-            mBackgroundTintMode = tintMode;
-            getImpl().setBackgroundTintMode(tintMode);
-        }
-    }
-
-    @Override
-    public void setBackgroundDrawable(Drawable background) {
-        Log.i(LOG_TAG, "Setting a custom background is not supported.");
-    }
-
-    @Override
-    public void setBackgroundResource(int resid) {
-        Log.i(LOG_TAG, "Setting a custom background is not supported.");
-    }
-
-    @Override
-    public void setBackgroundColor(int color) {
-        Log.i(LOG_TAG, "Setting a custom background is not supported.");
-    }
-
-    @Override
-    public void setImageResource(@DrawableRes int resId) {
-        // Intercept this call and instead retrieve the Drawable via the image helper
-        mImageHelper.setImageResource(resId);
-    }
-
-    /**
-     * Shows the button.
-     * <p>This method will animate the button show if the view has already been laid out.</p>
-     */
-    public void show() {
-        show(null);
-    }
-
-    /**
-     * Shows the button.
-     * <p>This method will animate the button show if the view has already been laid out.</p>
-     *
-     * @param listener the listener to notify when this view is shown
-     */
-    public void show(@Nullable final OnVisibilityChangedListener listener) {
-        show(listener, true);
-    }
-
-    void show(OnVisibilityChangedListener listener, boolean fromUser) {
-        getImpl().show(wrapOnVisibilityChangedListener(listener), fromUser);
-    }
-
-    /**
-     * Hides the button.
-     * <p>This method will animate the button hide if the view has already been laid out.</p>
-     */
-    public void hide() {
-        hide(null);
-    }
-
-    /**
-     * Hides the button.
-     * <p>This method will animate the button hide if the view has already been laid out.</p>
-     *
-     * @param listener the listener to notify when this view is hidden
-     */
-    public void hide(@Nullable OnVisibilityChangedListener listener) {
-        hide(listener, true);
-    }
-
-    void hide(@Nullable OnVisibilityChangedListener listener, boolean fromUser) {
-        getImpl().hide(wrapOnVisibilityChangedListener(listener), fromUser);
-    }
-
-    /**
-     * Set whether FloatingActionButton should add inner padding on platforms Lollipop and after,
-     * to ensure consistent dimensions on all platforms.
-     *
-     * @param useCompatPadding true if FloatingActionButton is adding inner padding on platforms
-     *                         Lollipop and after, to ensure consistent dimensions on all platforms.
-     *
-     * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding
-     * @see #getUseCompatPadding()
-     */
-    public void setUseCompatPadding(boolean useCompatPadding) {
-        if (mCompatPadding != useCompatPadding) {
-            mCompatPadding = useCompatPadding;
-            getImpl().onCompatShadowChanged();
-        }
-    }
-
-    /**
-     * Returns whether FloatingActionButton will add inner padding on platforms Lollipop and after.
-     *
-     * @return true if FloatingActionButton is adding inner padding on platforms Lollipop and after,
-     * to ensure consistent dimensions on all platforms.
-     *
-     * @attr ref android.support.design.R.styleable#FloatingActionButton_useCompatPadding
-     * @see #setUseCompatPadding(boolean)
-     */
-    public boolean getUseCompatPadding() {
-        return mCompatPadding;
-    }
-
-    /**
-     * Sets the size of the button.
-     *
-     * <p>The options relate to the options available on the material design specification.
-     * {@link #SIZE_NORMAL} is larger than {@link #SIZE_MINI}. {@link #SIZE_AUTO} will choose
-     * an appropriate size based on the screen size.</p>
-     *
-     * @param size one of {@link #SIZE_NORMAL}, {@link #SIZE_MINI} or {@link #SIZE_AUTO}
-     *
-     * @attr ref android.support.design.R.styleable#FloatingActionButton_fabSize
-     */
-    public void setSize(@Size int size) {
-        if (size != mSize) {
-            mSize = size;
-            requestLayout();
-        }
-    }
-
-    /**
-     * Returns the chosen size for this button.
-     *
-     * @return one of {@link #SIZE_NORMAL}, {@link #SIZE_MINI} or {@link #SIZE_AUTO}
-     * @see #setSize(int)
-     */
-    @Size
-    public int getSize() {
-        return mSize;
-    }
-
-    @Nullable
-    private InternalVisibilityChangedListener wrapOnVisibilityChangedListener(
-            @Nullable final OnVisibilityChangedListener listener) {
-        if (listener == null) {
-            return null;
-        }
-
-        return new InternalVisibilityChangedListener() {
-            @Override
-            public void onShown() {
-                listener.onShown(FloatingActionButton.this);
-            }
-
-            @Override
-            public void onHidden() {
-                listener.onHidden(FloatingActionButton.this);
-            }
-        };
-    }
-
-    /**
-     * Sets the size of the button to be a custom value in pixels. If set to
-     * {@link #NO_CUSTOM_SIZE}, custom size will not be used and size will be calculated according
-     * to {@link #setSize(int)} method.
-     *
-     * @param size preferred size in pixels, or zero
-     *
-     * @attr ref android.support.design.R.styleable#FloatingActionButton_fabCustomSize
-     */
-    public void setCustomSize(int size) {
-        if (size < 0) {
-            throw new IllegalArgumentException("Custom size should be non-negative.");
-        }
-        mCustomSize = size;
-    }
-
-    /**
-     * Returns the custom size for this button.
-     *
-     * @return size in pixels, or {@link #NO_CUSTOM_SIZE}
-     */
-    public int getCustomSize() {
-        return mCustomSize;
-    }
-
-    int getSizeDimension() {
-        return getSizeDimension(mSize);
-    }
-
-    private int getSizeDimension(@Size final int size) {
-        final Resources res = getResources();
-        // If custom size is set, return it
-        if (mCustomSize != NO_CUSTOM_SIZE) {
-            return mCustomSize;
-        }
-        switch (size) {
-            case SIZE_AUTO:
-                // If we're set to auto, grab the size from resources and refresh
-                final int width = res.getConfiguration().screenWidthDp;
-                final int height = res.getConfiguration().screenHeightDp;
-                return Math.max(width, height) < AUTO_MINI_LARGEST_SCREEN_WIDTH
-                        ? getSizeDimension(SIZE_MINI)
-                        : getSizeDimension(SIZE_NORMAL);
-            case SIZE_MINI:
-                return res.getDimensionPixelSize(R.dimen.design_fab_size_mini);
-            case SIZE_NORMAL:
-            default:
-                return res.getDimensionPixelSize(R.dimen.design_fab_size_normal);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        getImpl().onAttachedToWindow();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        getImpl().onDetachedFromWindow();
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-        getImpl().onDrawableStateChanged(getDrawableState());
-    }
-
-    @Override
-    public void jumpDrawablesToCurrentState() {
-        super.jumpDrawablesToCurrentState();
-        getImpl().jumpDrawableToCurrentState();
-    }
-
-    /**
-     * Return in {@code rect} the bounds of the actual floating action button content in view-local
-     * coordinates. This is defined as anything within any visible shadow.
-     *
-     * @return true if this view actually has been laid out and has a content rect, else false.
-     */
-    public boolean getContentRect(@NonNull Rect rect) {
-        if (ViewCompat.isLaidOut(this)) {
-            rect.set(0, 0, getWidth(), getHeight());
-            rect.left += mShadowPadding.left;
-            rect.top += mShadowPadding.top;
-            rect.right -= mShadowPadding.right;
-            rect.bottom -= mShadowPadding.bottom;
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Returns the FloatingActionButton's background, minus any compatible shadow implementation.
-     */
-    @NonNull
-    public Drawable getContentBackground() {
-        return getImpl().getContentBackground();
-    }
-
-    private static int resolveAdjustedSize(int desiredSize, int measureSpec) {
-        int result = desiredSize;
-        int specMode = MeasureSpec.getMode(measureSpec);
-        int specSize = MeasureSpec.getSize(measureSpec);
-        switch (specMode) {
-            case MeasureSpec.UNSPECIFIED:
-                // Parent says we can be as big as we want. Just don't be larger
-                // than max size imposed on ourselves.
-                result = desiredSize;
-                break;
-            case MeasureSpec.AT_MOST:
-                // Parent says we can be as big as we want, up to specSize.
-                // Don't be larger than specSize, and don't be larger than
-                // the max size imposed on ourselves.
-                result = Math.min(desiredSize, specSize);
-                break;
-            case MeasureSpec.EXACTLY:
-                // No choice. Do what we are told.
-                result = specSize;
-                break;
-        }
-        return result;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        switch (ev.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-                // Skipping the gesture if it doesn't start in in the FAB 'content' area
-                if (getContentRect(mTouchArea)
-                        && !mTouchArea.contains((int) ev.getX(), (int) ev.getY())) {
-                    return false;
-                }
-                break;
-        }
-        return super.onTouchEvent(ev);
-    }
-
-    /**
-     * Behavior designed for use with {@link FloatingActionButton} instances. Its main function
-     * is to move {@link FloatingActionButton} views so that any displayed {@link Snackbar}s do
-     * not cover them.
-     */
-    public static class Behavior extends CoordinatorLayout.Behavior<FloatingActionButton> {
-        private static final boolean AUTO_HIDE_DEFAULT = true;
-
-        private Rect mTmpRect;
-        private OnVisibilityChangedListener mInternalAutoHideListener;
-        private boolean mAutoHideEnabled;
-
-        public Behavior() {
-            super();
-            mAutoHideEnabled = AUTO_HIDE_DEFAULT;
-        }
-
-        public Behavior(Context context, AttributeSet attrs) {
-            super(context, attrs);
-            TypedArray a = context.obtainStyledAttributes(attrs,
-                    R.styleable.FloatingActionButton_Behavior_Layout);
-            mAutoHideEnabled = a.getBoolean(
-                    R.styleable.FloatingActionButton_Behavior_Layout_behavior_autoHide,
-                    AUTO_HIDE_DEFAULT);
-            a.recycle();
-        }
-
-        /**
-         * Sets whether the associated FloatingActionButton automatically hides when there is
-         * not enough space to be displayed. This works with {@link AppBarLayout}
-         * and {@link BottomSheetBehavior}.
-         *
-         * @attr ref android.support.design.R.styleable#FloatingActionButton_Behavior_Layout_behavior_autoHide
-         * @param autoHide true to enable automatic hiding
-         */
-        public void setAutoHideEnabled(boolean autoHide) {
-            mAutoHideEnabled = autoHide;
-        }
-
-        /**
-         * Returns whether the associated FloatingActionButton automatically hides when there is
-         * not enough space to be displayed.
-         *
-         * @attr ref android.support.design.R.styleable#FloatingActionButton_Behavior_Layout_behavior_autoHide
-         * @return true if enabled
-         */
-        public boolean isAutoHideEnabled() {
-            return mAutoHideEnabled;
-        }
-
-        @Override
-        public void onAttachedToLayoutParams(@NonNull CoordinatorLayout.LayoutParams lp) {
-            if (lp.dodgeInsetEdges == Gravity.NO_GRAVITY) {
-                // If the developer hasn't set dodgeInsetEdges, lets set it to BOTTOM so that
-                // we dodge any Snackbars
-                lp.dodgeInsetEdges = Gravity.BOTTOM;
-            }
-        }
-
-        @Override
-        public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child,
-                View dependency) {
-            if (dependency instanceof AppBarLayout) {
-                // If we're depending on an AppBarLayout we will show/hide it automatically
-                // if the FAB is anchored to the AppBarLayout
-                updateFabVisibilityForAppBarLayout(parent, (AppBarLayout) dependency, child);
-            } else if (isBottomSheet(dependency)) {
-                updateFabVisibilityForBottomSheet(dependency, child);
-            }
-            return false;
-        }
-
-        private static boolean isBottomSheet(@NonNull View view) {
-            final ViewGroup.LayoutParams lp = view.getLayoutParams();
-            if (lp instanceof CoordinatorLayout.LayoutParams) {
-                return ((CoordinatorLayout.LayoutParams) lp)
-                        .getBehavior() instanceof BottomSheetBehavior;
-            }
-            return false;
-        }
-
-        @VisibleForTesting
-        void setInternalAutoHideListener(OnVisibilityChangedListener listener) {
-            mInternalAutoHideListener = listener;
-        }
-
-        private boolean shouldUpdateVisibility(View dependency, FloatingActionButton child) {
-            final CoordinatorLayout.LayoutParams lp =
-                    (CoordinatorLayout.LayoutParams) child.getLayoutParams();
-            if (!mAutoHideEnabled) {
-                return false;
-            }
-
-            if (lp.getAnchorId() != dependency.getId()) {
-                // The anchor ID doesn't match the dependency, so we won't automatically
-                // show/hide the FAB
-                return false;
-            }
-
-            //noinspection RedundantIfStatement
-            if (child.getUserSetVisibility() != VISIBLE) {
-                // The view isn't set to be visible so skip changing its visibility
-                return false;
-            }
-
-            return true;
-        }
-
-        private boolean updateFabVisibilityForAppBarLayout(CoordinatorLayout parent,
-                AppBarLayout appBarLayout, FloatingActionButton child) {
-            if (!shouldUpdateVisibility(appBarLayout, child)) {
-                return false;
-            }
-
-            if (mTmpRect == null) {
-                mTmpRect = new Rect();
-            }
-
-            // First, let's get the visible rect of the dependency
-            final Rect rect = mTmpRect;
-            ViewGroupUtils.getDescendantRect(parent, appBarLayout, rect);
-
-            if (rect.bottom <= appBarLayout.getMinimumHeightForVisibleOverlappingContent()) {
-                // If the anchor's bottom is below the seam, we'll animate our FAB out
-                child.hide(mInternalAutoHideListener, false);
-            } else {
-                // Else, we'll animate our FAB back in
-                child.show(mInternalAutoHideListener, false);
-            }
-            return true;
-        }
-
-        private boolean updateFabVisibilityForBottomSheet(View bottomSheet,
-                FloatingActionButton child) {
-            if (!shouldUpdateVisibility(bottomSheet, child)) {
-                return false;
-            }
-            CoordinatorLayout.LayoutParams lp =
-                    (CoordinatorLayout.LayoutParams) child.getLayoutParams();
-            if (bottomSheet.getTop() < child.getHeight() / 2 + lp.topMargin) {
-                child.hide(mInternalAutoHideListener, false);
-            } else {
-                child.show(mInternalAutoHideListener, false);
-            }
-            return true;
-        }
-
-        @Override
-        public boolean onLayoutChild(CoordinatorLayout parent, FloatingActionButton child,
-                int layoutDirection) {
-            // First, let's make sure that the visibility of the FAB is consistent
-            final List<View> dependencies = parent.getDependencies(child);
-            for (int i = 0, count = dependencies.size(); i < count; i++) {
-                final View dependency = dependencies.get(i);
-                if (dependency instanceof AppBarLayout) {
-                    if (updateFabVisibilityForAppBarLayout(
-                            parent, (AppBarLayout) dependency, child)) {
-                        break;
-                    }
-                } else if (isBottomSheet(dependency)) {
-                    if (updateFabVisibilityForBottomSheet(dependency, child)) {
-                        break;
-                    }
-                }
-            }
-            // Now let the CoordinatorLayout lay out the FAB
-            parent.onLayoutChild(child, layoutDirection);
-            // Now offset it if needed
-            offsetIfNeeded(parent, child);
-            return true;
-        }
-
-        @Override
-        public boolean getInsetDodgeRect(@NonNull CoordinatorLayout parent,
-                @NonNull FloatingActionButton child, @NonNull Rect rect) {
-            // Since we offset so that any internal shadow padding isn't shown, we need to make
-            // sure that the shadow isn't used for any dodge inset calculations
-            final Rect shadowPadding = child.mShadowPadding;
-            rect.set(child.getLeft() + shadowPadding.left,
-                    child.getTop() + shadowPadding.top,
-                    child.getRight() - shadowPadding.right,
-                    child.getBottom() - shadowPadding.bottom);
-            return true;
-        }
-
-        /**
-         * Pre-Lollipop we use padding so that the shadow has enough space to be drawn. This method
-         * offsets our layout position so that we're positioned correctly if we're on one of
-         * our parent's edges.
-         */
-        private void offsetIfNeeded(CoordinatorLayout parent, FloatingActionButton fab) {
-            final Rect padding = fab.mShadowPadding;
-
-            if (padding != null && padding.centerX() > 0 && padding.centerY() > 0) {
-                final CoordinatorLayout.LayoutParams lp =
-                        (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
-
-                int offsetTB = 0, offsetLR = 0;
-
-                if (fab.getRight() >= parent.getWidth() - lp.rightMargin) {
-                    // If we're on the right edge, shift it the right
-                    offsetLR = padding.right;
-                } else if (fab.getLeft() <= lp.leftMargin) {
-                    // If we're on the left edge, shift it the left
-                    offsetLR = -padding.left;
-                }
-                if (fab.getBottom() >= parent.getHeight() - lp.bottomMargin) {
-                    // If we're on the bottom edge, shift it down
-                    offsetTB = padding.bottom;
-                } else if (fab.getTop() <= lp.topMargin) {
-                    // If we're on the top edge, shift it up
-                    offsetTB = -padding.top;
-                }
-
-                if (offsetTB != 0) {
-                    ViewCompat.offsetTopAndBottom(fab, offsetTB);
-                }
-                if (offsetLR != 0) {
-                    ViewCompat.offsetLeftAndRight(fab, offsetLR);
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns the backward compatible elevation of the FloatingActionButton.
-     *
-     * @return the backward compatible elevation in pixels.
-     * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation
-     * @see #setCompatElevation(float)
-     */
-    public float getCompatElevation() {
-        return getImpl().getElevation();
-    }
-
-    /**
-     * Updates the backward compatible elevation of the FloatingActionButton.
-     *
-     * @param elevation The backward compatible elevation in pixels.
-     * @attr ref android.support.design.R.styleable#FloatingActionButton_elevation
-     * @see #getCompatElevation()
-     * @see #setUseCompatPadding(boolean)
-     */
-    public void setCompatElevation(float elevation) {
-        getImpl().setElevation(elevation);
-    }
-
-    private FloatingActionButtonImpl getImpl() {
-        if (mImpl == null) {
-            mImpl = createImpl();
-        }
-        return mImpl;
-    }
-
-    private FloatingActionButtonImpl createImpl() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            return new FloatingActionButtonLollipop(this, new ShadowDelegateImpl());
-        } else {
-            return new FloatingActionButtonImpl(this, new ShadowDelegateImpl());
-        }
-    }
-
-    private class ShadowDelegateImpl implements ShadowViewDelegate {
-        ShadowDelegateImpl() {
-        }
-
-        @Override
-        public float getRadius() {
-            return getSizeDimension() / 2f;
-        }
-
-        @Override
-        public void setShadowPadding(int left, int top, int right, int bottom) {
-            mShadowPadding.set(left, top, right, bottom);
-            setPadding(left + mImagePadding, top + mImagePadding,
-                    right + mImagePadding, bottom + mImagePadding);
-        }
-
-        @Override
-        public void setBackgroundDrawable(Drawable background) {
-            FloatingActionButton.super.setBackgroundDrawable(background);
-        }
-
-        @Override
-        public boolean isCompatPaddingEnabled() {
-            return mCompatPadding;
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/HeaderBehavior.java b/design/src/android/support/design/widget/HeaderBehavior.java
deleted file mode 100644
index a5d0edf..0000000
--- a/design/src/android/support/design/widget/HeaderBehavior.java
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.support.design.widget.CoordinatorLayout.Behavior;
-import android.support.v4.math.MathUtils;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.widget.OverScroller;
-
-/**
- * The {@link Behavior} for a view that sits vertically above scrolling a view.
- * See {@link HeaderScrollingViewBehavior}.
- */
-abstract class HeaderBehavior<V extends View> extends ViewOffsetBehavior<V> {
-
-    private static final int INVALID_POINTER = -1;
-
-    private Runnable mFlingRunnable;
-    OverScroller mScroller;
-
-    private boolean mIsBeingDragged;
-    private int mActivePointerId = INVALID_POINTER;
-    private int mLastMotionY;
-    private int mTouchSlop = -1;
-    private VelocityTracker mVelocityTracker;
-
-    public HeaderBehavior() {}
-
-    public HeaderBehavior(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
-        if (mTouchSlop < 0) {
-            mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
-        }
-
-        final int action = ev.getAction();
-
-        // Shortcut since we're being dragged
-        if (action == MotionEvent.ACTION_MOVE && mIsBeingDragged) {
-            return true;
-        }
-
-        switch (ev.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN: {
-                mIsBeingDragged = false;
-                final int x = (int) ev.getX();
-                final int y = (int) ev.getY();
-                if (canDragView(child) && parent.isPointInChildBounds(child, x, y)) {
-                    mLastMotionY = y;
-                    mActivePointerId = ev.getPointerId(0);
-                    ensureVelocityTracker();
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_MOVE: {
-                final int activePointerId = mActivePointerId;
-                if (activePointerId == INVALID_POINTER) {
-                    // If we don't have a valid id, the touch down wasn't on content.
-                    break;
-                }
-                final int pointerIndex = ev.findPointerIndex(activePointerId);
-                if (pointerIndex == -1) {
-                    break;
-                }
-
-                final int y = (int) ev.getY(pointerIndex);
-                final int yDiff = Math.abs(y - mLastMotionY);
-                if (yDiff > mTouchSlop) {
-                    mIsBeingDragged = true;
-                    mLastMotionY = y;
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP: {
-                mIsBeingDragged = false;
-                mActivePointerId = INVALID_POINTER;
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.recycle();
-                    mVelocityTracker = null;
-                }
-                break;
-            }
-        }
-
-        if (mVelocityTracker != null) {
-            mVelocityTracker.addMovement(ev);
-        }
-
-        return mIsBeingDragged;
-    }
-
-    @Override
-    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev) {
-        if (mTouchSlop < 0) {
-            mTouchSlop = ViewConfiguration.get(parent.getContext()).getScaledTouchSlop();
-        }
-
-        switch (ev.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN: {
-                final int x = (int) ev.getX();
-                final int y = (int) ev.getY();
-
-                if (parent.isPointInChildBounds(child, x, y) && canDragView(child)) {
-                    mLastMotionY = y;
-                    mActivePointerId = ev.getPointerId(0);
-                    ensureVelocityTracker();
-                } else {
-                    return false;
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_MOVE: {
-                final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
-                if (activePointerIndex == -1) {
-                    return false;
-                }
-
-                final int y = (int) ev.getY(activePointerIndex);
-                int dy = mLastMotionY - y;
-
-                if (!mIsBeingDragged && Math.abs(dy) > mTouchSlop) {
-                    mIsBeingDragged = true;
-                    if (dy > 0) {
-                        dy -= mTouchSlop;
-                    } else {
-                        dy += mTouchSlop;
-                    }
-                }
-
-                if (mIsBeingDragged) {
-                    mLastMotionY = y;
-                    // We're being dragged so scroll the ABL
-                    scroll(parent, child, dy, getMaxDragOffset(child), 0);
-                }
-                break;
-            }
-
-            case MotionEvent.ACTION_UP:
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.addMovement(ev);
-                    mVelocityTracker.computeCurrentVelocity(1000);
-                    float yvel = mVelocityTracker.getYVelocity(mActivePointerId);
-                    fling(parent, child, -getScrollRangeForDragFling(child), 0, yvel);
-                }
-                // $FALLTHROUGH
-            case MotionEvent.ACTION_CANCEL: {
-                mIsBeingDragged = false;
-                mActivePointerId = INVALID_POINTER;
-                if (mVelocityTracker != null) {
-                    mVelocityTracker.recycle();
-                    mVelocityTracker = null;
-                }
-                break;
-            }
-        }
-
-        if (mVelocityTracker != null) {
-            mVelocityTracker.addMovement(ev);
-        }
-
-        return true;
-    }
-
-    int setHeaderTopBottomOffset(CoordinatorLayout parent, V header, int newOffset) {
-        return setHeaderTopBottomOffset(parent, header, newOffset,
-                Integer.MIN_VALUE, Integer.MAX_VALUE);
-    }
-
-    int setHeaderTopBottomOffset(CoordinatorLayout parent, V header, int newOffset,
-            int minOffset, int maxOffset) {
-        final int curOffset = getTopAndBottomOffset();
-        int consumed = 0;
-
-        if (minOffset != 0 && curOffset >= minOffset && curOffset <= maxOffset) {
-            // If we have some scrolling range, and we're currently within the min and max
-            // offsets, calculate a new offset
-            newOffset = MathUtils.clamp(newOffset, minOffset, maxOffset);
-
-            if (curOffset != newOffset) {
-                setTopAndBottomOffset(newOffset);
-                // Update how much dy we have consumed
-                consumed = curOffset - newOffset;
-            }
-        }
-
-        return consumed;
-    }
-
-    int getTopBottomOffsetForScrollingSibling() {
-        return getTopAndBottomOffset();
-    }
-
-    final int scroll(CoordinatorLayout coordinatorLayout, V header,
-            int dy, int minOffset, int maxOffset) {
-        return setHeaderTopBottomOffset(coordinatorLayout, header,
-                getTopBottomOffsetForScrollingSibling() - dy, minOffset, maxOffset);
-    }
-
-    final boolean fling(CoordinatorLayout coordinatorLayout, V layout, int minOffset,
-            int maxOffset, float velocityY) {
-        if (mFlingRunnable != null) {
-            layout.removeCallbacks(mFlingRunnable);
-            mFlingRunnable = null;
-        }
-
-        if (mScroller == null) {
-            mScroller = new OverScroller(layout.getContext());
-        }
-
-        mScroller.fling(
-                0, getTopAndBottomOffset(), // curr
-                0, Math.round(velocityY), // velocity.
-                0, 0, // x
-                minOffset, maxOffset); // y
-
-        if (mScroller.computeScrollOffset()) {
-            mFlingRunnable = new FlingRunnable(coordinatorLayout, layout);
-            ViewCompat.postOnAnimation(layout, mFlingRunnable);
-            return true;
-        } else {
-            onFlingFinished(coordinatorLayout, layout);
-            return false;
-        }
-    }
-
-    /**
-     * Called when a fling has finished, or the fling was initiated but there wasn't enough
-     * velocity to start it.
-     */
-    void onFlingFinished(CoordinatorLayout parent, V layout) {
-        // no-op
-    }
-
-    /**
-     * Return true if the view can be dragged.
-     */
-    boolean canDragView(V view) {
-        return false;
-    }
-
-    /**
-     * Returns the maximum px offset when {@code view} is being dragged.
-     */
-    int getMaxDragOffset(V view) {
-        return -view.getHeight();
-    }
-
-    int getScrollRangeForDragFling(V view) {
-        return view.getHeight();
-    }
-
-    private void ensureVelocityTracker() {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-    }
-
-    private class FlingRunnable implements Runnable {
-        private final CoordinatorLayout mParent;
-        private final V mLayout;
-
-        FlingRunnable(CoordinatorLayout parent, V layout) {
-            mParent = parent;
-            mLayout = layout;
-        }
-
-        @Override
-        public void run() {
-            if (mLayout != null && mScroller != null) {
-                if (mScroller.computeScrollOffset()) {
-                    setHeaderTopBottomOffset(mParent, mLayout, mScroller.getCurrY());
-                    // Post ourselves so that we run on the next animation
-                    ViewCompat.postOnAnimation(mLayout, this);
-                } else {
-                    onFlingFinished(mParent, mLayout);
-                }
-            }
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java b/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java
deleted file mode 100644
index 81ddde5..0000000
--- a/design/src/android/support/design/widget/HeaderScrollingViewBehavior.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.support.design.widget.CoordinatorLayout.Behavior;
-import android.support.v4.math.MathUtils;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.List;
-
-/**
- * The {@link Behavior} for a scrolling view that is positioned vertically below another view.
- * See {@link HeaderBehavior}.
- */
-abstract class HeaderScrollingViewBehavior extends ViewOffsetBehavior<View> {
-
-    final Rect mTempRect1 = new Rect();
-    final Rect mTempRect2 = new Rect();
-
-    private int mVerticalLayoutGap = 0;
-    private int mOverlayTop;
-
-    public HeaderScrollingViewBehavior() {}
-
-    public HeaderScrollingViewBehavior(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    public boolean onMeasureChild(CoordinatorLayout parent, View child,
-            int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec,
-            int heightUsed) {
-        final int childLpHeight = child.getLayoutParams().height;
-        if (childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
-                || childLpHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
-            // If the menu's height is set to match_parent/wrap_content then measure it
-            // with the maximum visible height
-
-            final List<View> dependencies = parent.getDependencies(child);
-            final View header = findFirstDependency(dependencies);
-            if (header != null) {
-                if (ViewCompat.getFitsSystemWindows(header)
-                        && !ViewCompat.getFitsSystemWindows(child)) {
-                    // If the header is fitting system windows then we need to also,
-                    // otherwise we'll get CoL's compatible measuring
-                    ViewCompat.setFitsSystemWindows(child, true);
-
-                    if (ViewCompat.getFitsSystemWindows(child)) {
-                        // If the set succeeded, trigger a new layout and return true
-                        child.requestLayout();
-                        return true;
-                    }
-                }
-
-                int availableHeight = View.MeasureSpec.getSize(parentHeightMeasureSpec);
-                if (availableHeight == 0) {
-                    // If the measure spec doesn't specify a size, use the current height
-                    availableHeight = parent.getHeight();
-                }
-
-                final int height = availableHeight - header.getMeasuredHeight()
-                        + getScrollRange(header);
-                final int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height,
-                        childLpHeight == ViewGroup.LayoutParams.MATCH_PARENT
-                                ? View.MeasureSpec.EXACTLY
-                                : View.MeasureSpec.AT_MOST);
-
-                // Now measure the scrolling view with the correct height
-                parent.onMeasureChild(child, parentWidthMeasureSpec,
-                        widthUsed, heightMeasureSpec, heightUsed);
-
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected void layoutChild(final CoordinatorLayout parent, final View child,
-            final int layoutDirection) {
-        final List<View> dependencies = parent.getDependencies(child);
-        final View header = findFirstDependency(dependencies);
-
-        if (header != null) {
-            final CoordinatorLayout.LayoutParams lp =
-                    (CoordinatorLayout.LayoutParams) child.getLayoutParams();
-            final Rect available = mTempRect1;
-            available.set(parent.getPaddingLeft() + lp.leftMargin,
-                    header.getBottom() + lp.topMargin,
-                    parent.getWidth() - parent.getPaddingRight() - lp.rightMargin,
-                    parent.getHeight() + header.getBottom()
-                            - parent.getPaddingBottom() - lp.bottomMargin);
-
-            final WindowInsetsCompat parentInsets = parent.getLastWindowInsets();
-            if (parentInsets != null && ViewCompat.getFitsSystemWindows(parent)
-                    && !ViewCompat.getFitsSystemWindows(child)) {
-                // If we're set to handle insets but this child isn't, then it has been measured as
-                // if there are no insets. We need to lay it out to match horizontally.
-                // Top and bottom and already handled in the logic above
-                available.left += parentInsets.getSystemWindowInsetLeft();
-                available.right -= parentInsets.getSystemWindowInsetRight();
-            }
-
-            final Rect out = mTempRect2;
-            GravityCompat.apply(resolveGravity(lp.gravity), child.getMeasuredWidth(),
-                    child.getMeasuredHeight(), available, out, layoutDirection);
-
-            final int overlap = getOverlapPixelsForOffset(header);
-
-            child.layout(out.left, out.top - overlap, out.right, out.bottom - overlap);
-            mVerticalLayoutGap = out.top - header.getBottom();
-        } else {
-            // If we don't have a dependency, let super handle it
-            super.layoutChild(parent, child, layoutDirection);
-            mVerticalLayoutGap = 0;
-        }
-    }
-
-    float getOverlapRatioForOffset(final View header) {
-        return 1f;
-    }
-
-    final int getOverlapPixelsForOffset(final View header) {
-        return mOverlayTop == 0 ? 0 : MathUtils.clamp(
-                (int) (getOverlapRatioForOffset(header) * mOverlayTop), 0, mOverlayTop);
-    }
-
-    private static int resolveGravity(int gravity) {
-        return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
-    }
-
-    abstract View findFirstDependency(List<View> views);
-
-    int getScrollRange(View v) {
-        return v.getMeasuredHeight();
-    }
-
-    /**
-     * The gap between the top of the scrolling view and the bottom of the header layout in pixels.
-     */
-    final int getVerticalLayoutGap() {
-        return mVerticalLayoutGap;
-    }
-
-    /**
-     * Set the distance that this view should overlap any {@link AppBarLayout}.
-     *
-     * @param overlayTop the distance in px
-     */
-    public final void setOverlayTop(int overlayTop) {
-        mOverlayTop = overlayTop;
-    }
-
-    /**
-     * Returns the distance that this view should overlap any {@link AppBarLayout}.
-     */
-    public final int getOverlayTop() {
-        return mOverlayTop;
-    }
-}
\ No newline at end of file
diff --git a/design/src/android/support/design/widget/NavigationView.java b/design/src/android/support/design/widget/NavigationView.java
deleted file mode 100644
index 8fc8c76..0000000
--- a/design/src/android/support/design/widget/NavigationView.java
+++ /dev/null
@@ -1,494 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IdRes;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.StyleRes;
-import android.support.design.R;
-import android.support.design.internal.NavigationMenu;
-import android.support.design.internal.NavigationMenuPresenter;
-import android.support.design.internal.ScrimInsetsFrameLayout;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.WindowInsetsCompat;
-import android.support.v7.content.res.AppCompatResources;
-import android.support.v7.view.SupportMenuInflater;
-import android.support.v7.view.menu.MenuBuilder;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.support.v7.widget.TintTypedArray;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-
-/**
- * Represents a standard navigation menu for application. The menu contents can be populated
- * by a menu resource file.
- * <p>NavigationView is typically placed inside a {@link android.support.v4.widget.DrawerLayout}.
- * </p>
- * <pre>
- * &lt;android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
- *     xmlns:app="http://schemas.android.com/apk/res-auto"
- *     android:id="@+id/drawer_layout"
- *     android:layout_width="match_parent"
- *     android:layout_height="match_parent"
- *     android:fitsSystemWindows="true"&gt;
- *
- *     &lt;!-- Your contents --&gt;
- *
- *     &lt;android.support.design.widget.NavigationView
- *         android:id="@+id/navigation"
- *         android:layout_width="wrap_content"
- *         android:layout_height="match_parent"
- *         android:layout_gravity="start"
- *         app:menu="@menu/my_navigation_items" /&gt;
- * &lt;/android.support.v4.widget.DrawerLayout&gt;
- * </pre>
- */
-public class NavigationView extends ScrimInsetsFrameLayout {
-
-    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
-    private static final int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled};
-
-    private static final int PRESENTER_NAVIGATION_VIEW_ID = 1;
-
-    private final NavigationMenu mMenu;
-    private final NavigationMenuPresenter mPresenter = new NavigationMenuPresenter();
-
-    OnNavigationItemSelectedListener mListener;
-    private int mMaxWidth;
-
-    private MenuInflater mMenuInflater;
-
-    public NavigationView(Context context) {
-        this(context, null);
-    }
-
-    public NavigationView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NavigationView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        ThemeUtils.checkAppCompatTheme(context);
-
-        // Create the menu
-        mMenu = new NavigationMenu(context);
-
-        // Custom attributes
-        TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
-                R.styleable.NavigationView, defStyleAttr,
-                R.style.Widget_Design_NavigationView);
-
-        ViewCompat.setBackground(
-                this, a.getDrawable(R.styleable.NavigationView_android_background));
-        if (a.hasValue(R.styleable.NavigationView_elevation)) {
-            ViewCompat.setElevation(this, a.getDimensionPixelSize(
-                    R.styleable.NavigationView_elevation, 0));
-        }
-        ViewCompat.setFitsSystemWindows(this,
-                a.getBoolean(R.styleable.NavigationView_android_fitsSystemWindows, false));
-
-        mMaxWidth = a.getDimensionPixelSize(R.styleable.NavigationView_android_maxWidth, 0);
-
-        final ColorStateList itemIconTint;
-        if (a.hasValue(R.styleable.NavigationView_itemIconTint)) {
-            itemIconTint = a.getColorStateList(R.styleable.NavigationView_itemIconTint);
-        } else {
-            itemIconTint = createDefaultColorStateList(android.R.attr.textColorSecondary);
-        }
-
-        boolean textAppearanceSet = false;
-        int textAppearance = 0;
-        if (a.hasValue(R.styleable.NavigationView_itemTextAppearance)) {
-            textAppearance = a.getResourceId(R.styleable.NavigationView_itemTextAppearance, 0);
-            textAppearanceSet = true;
-        }
-
-        ColorStateList itemTextColor = null;
-        if (a.hasValue(R.styleable.NavigationView_itemTextColor)) {
-            itemTextColor = a.getColorStateList(R.styleable.NavigationView_itemTextColor);
-        }
-
-        if (!textAppearanceSet && itemTextColor == null) {
-            // If there isn't a text appearance set, we'll use a default text color
-            itemTextColor = createDefaultColorStateList(android.R.attr.textColorPrimary);
-        }
-
-        final Drawable itemBackground = a.getDrawable(R.styleable.NavigationView_itemBackground);
-
-        mMenu.setCallback(new MenuBuilder.Callback() {
-            @Override
-            public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
-                return mListener != null && mListener.onNavigationItemSelected(item);
-            }
-
-            @Override
-            public void onMenuModeChange(MenuBuilder menu) {}
-        });
-        mPresenter.setId(PRESENTER_NAVIGATION_VIEW_ID);
-        mPresenter.initForMenu(context, mMenu);
-        mPresenter.setItemIconTintList(itemIconTint);
-        if (textAppearanceSet) {
-            mPresenter.setItemTextAppearance(textAppearance);
-        }
-        mPresenter.setItemTextColor(itemTextColor);
-        mPresenter.setItemBackground(itemBackground);
-        mMenu.addMenuPresenter(mPresenter);
-        addView((View) mPresenter.getMenuView(this));
-
-        if (a.hasValue(R.styleable.NavigationView_menu)) {
-            inflateMenu(a.getResourceId(R.styleable.NavigationView_menu, 0));
-        }
-
-        if (a.hasValue(R.styleable.NavigationView_headerLayout)) {
-            inflateHeaderView(a.getResourceId(R.styleable.NavigationView_headerLayout, 0));
-        }
-
-        a.recycle();
-    }
-
-    @Override
-    protected Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState state = new SavedState(superState);
-        state.menuState = new Bundle();
-        mMenu.savePresenterStates(state.menuState);
-        return state;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable savedState) {
-        if (!(savedState instanceof SavedState)) {
-            super.onRestoreInstanceState(savedState);
-            return;
-        }
-        SavedState state = (SavedState) savedState;
-        super.onRestoreInstanceState(state.getSuperState());
-        mMenu.restorePresenterStates(state.menuState);
-    }
-
-    /**
-     * Set a listener that will be notified when a menu item is selected.
-     *
-     * @param listener The listener to notify
-     */
-    public void setNavigationItemSelectedListener(
-            @Nullable OnNavigationItemSelectedListener listener) {
-        mListener = listener;
-    }
-
-    @Override
-    protected void onMeasure(int widthSpec, int heightSpec) {
-        switch (MeasureSpec.getMode(widthSpec)) {
-            case MeasureSpec.EXACTLY:
-                // Nothing to do
-                break;
-            case MeasureSpec.AT_MOST:
-                widthSpec = MeasureSpec.makeMeasureSpec(
-                        Math.min(MeasureSpec.getSize(widthSpec), mMaxWidth), MeasureSpec.EXACTLY);
-                break;
-            case MeasureSpec.UNSPECIFIED:
-                widthSpec = MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY);
-                break;
-        }
-        // Let super sort out the height
-        super.onMeasure(widthSpec, heightSpec);
-    }
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    @Override
-    protected void onInsetsChanged(WindowInsetsCompat insets) {
-        mPresenter.dispatchApplyWindowInsets(insets);
-    }
-
-    /**
-     * Inflate a menu resource into this navigation view.
-     *
-     * <p>Existing items in the menu will not be modified or removed.</p>
-     *
-     * @param resId ID of a menu resource to inflate
-     */
-    public void inflateMenu(int resId) {
-        mPresenter.setUpdateSuspended(true);
-        getMenuInflater().inflate(resId, mMenu);
-        mPresenter.setUpdateSuspended(false);
-        mPresenter.updateMenuView(false);
-    }
-
-    /**
-     * Returns the {@link Menu} instance associated with this navigation view.
-     */
-    public Menu getMenu() {
-        return mMenu;
-    }
-
-    /**
-     * Inflates a View and add it as a header of the navigation menu.
-     *
-     * @param res The layout resource ID.
-     * @return a newly inflated View.
-     */
-    public View inflateHeaderView(@LayoutRes int res) {
-        return mPresenter.inflateHeaderView(res);
-    }
-
-    /**
-     * Adds a View as a header of the navigation menu.
-     *
-     * @param view The view to be added as a header of the navigation menu.
-     */
-    public void addHeaderView(@NonNull View view) {
-        mPresenter.addHeaderView(view);
-    }
-
-    /**
-     * Removes a previously-added header view.
-     *
-     * @param view The view to remove
-     */
-    public void removeHeaderView(@NonNull View view) {
-        mPresenter.removeHeaderView(view);
-    }
-
-    /**
-     * Gets the number of headers in this NavigationView.
-     *
-     * @return A positive integer representing the number of headers.
-     */
-    public int getHeaderCount() {
-        return mPresenter.getHeaderCount();
-    }
-
-    /**
-     * Gets the header view at the specified position.
-     *
-     * @param index The position at which to get the view from.
-     * @return The header view the specified position or null if the position does not exist in this
-     * NavigationView.
-     */
-    public View getHeaderView(int index) {
-        return mPresenter.getHeaderView(index);
-    }
-
-    /**
-     * Returns the tint which is applied to our menu items' icons.
-     *
-     * @see #setItemIconTintList(ColorStateList)
-     *
-     * @attr ref R.styleable#NavigationView_itemIconTint
-     */
-    @Nullable
-    public ColorStateList getItemIconTintList() {
-        return mPresenter.getItemTintList();
-    }
-
-    /**
-     * Set the tint which is applied to our menu items' icons.
-     *
-     * @param tint the tint to apply.
-     *
-     * @attr ref R.styleable#NavigationView_itemIconTint
-     */
-    public void setItemIconTintList(@Nullable ColorStateList tint) {
-        mPresenter.setItemIconTintList(tint);
-    }
-
-    /**
-     * Returns the tint which is applied to our menu items' icons.
-     *
-     * @see #setItemTextColor(ColorStateList)
-     *
-     * @attr ref R.styleable#NavigationView_itemTextColor
-     */
-    @Nullable
-    public ColorStateList getItemTextColor() {
-        return mPresenter.getItemTextColor();
-    }
-
-    /**
-     * Set the text color to be used on our menu items.
-     *
-     * @see #getItemTextColor()
-     *
-     * @attr ref R.styleable#NavigationView_itemTextColor
-     */
-    public void setItemTextColor(@Nullable ColorStateList textColor) {
-        mPresenter.setItemTextColor(textColor);
-    }
-
-    /**
-     * Returns the background drawable for our menu items.
-     *
-     * @see #setItemBackgroundResource(int)
-     *
-     * @attr ref R.styleable#NavigationView_itemBackground
-     */
-    @Nullable
-    public Drawable getItemBackground() {
-        return mPresenter.getItemBackground();
-    }
-
-    /**
-     * Set the background of our menu items to the given resource.
-     *
-     * @param resId The identifier of the resource.
-     *
-     * @attr ref R.styleable#NavigationView_itemBackground
-     */
-    public void setItemBackgroundResource(@DrawableRes int resId) {
-        setItemBackground(ContextCompat.getDrawable(getContext(), resId));
-    }
-
-    /**
-     * Set the background of our menu items to a given resource. The resource should refer to
-     * a Drawable object or null to use the default background set on this navigation menu.
-     *
-     * @attr ref R.styleable#NavigationView_itemBackground
-     */
-    public void setItemBackground(@Nullable Drawable itemBackground) {
-        mPresenter.setItemBackground(itemBackground);
-    }
-
-    /**
-     * Sets the currently checked item in this navigation menu.
-     *
-     * @param id The item ID of the currently checked item.
-     */
-    public void setCheckedItem(@IdRes int id) {
-        MenuItem item = mMenu.findItem(id);
-        if (item != null) {
-            mPresenter.setCheckedItem((MenuItemImpl) item);
-        }
-    }
-
-    /**
-     * Set the text appearance of the menu items to a given resource.
-     *
-     * @attr ref R.styleable#NavigationView_itemTextAppearance
-     */
-    public void setItemTextAppearance(@StyleRes int resId) {
-        mPresenter.setItemTextAppearance(resId);
-    }
-
-    private MenuInflater getMenuInflater() {
-        if (mMenuInflater == null) {
-            mMenuInflater = new SupportMenuInflater(getContext());
-        }
-        return mMenuInflater;
-    }
-
-    private ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {
-        final TypedValue value = new TypedValue();
-        if (!getContext().getTheme().resolveAttribute(baseColorThemeAttr, value, true)) {
-            return null;
-        }
-        ColorStateList baseColor = AppCompatResources.getColorStateList(
-                getContext(), value.resourceId);
-        if (!getContext().getTheme().resolveAttribute(
-                    android.support.v7.appcompat.R.attr.colorPrimary, value, true)) {
-            return null;
-        }
-        int colorPrimary = value.data;
-        int defaultColor = baseColor.getDefaultColor();
-        return new ColorStateList(new int[][]{
-                DISABLED_STATE_SET,
-                CHECKED_STATE_SET,
-                EMPTY_STATE_SET
-        }, new int[]{
-                baseColor.getColorForState(DISABLED_STATE_SET, defaultColor),
-                colorPrimary,
-                defaultColor
-        });
-    }
-
-    /**
-     * Listener for handling events on navigation items.
-     */
-    public interface OnNavigationItemSelectedListener {
-
-        /**
-         * Called when an item in the navigation menu is selected.
-         *
-         * @param item The selected item
-         *
-         * @return true to display the item as the selected item
-         */
-        public boolean onNavigationItemSelected(@NonNull MenuItem item);
-    }
-
-    /**
-     * User interface state that is stored by NavigationView for implementing
-     * onSaveInstanceState().
-     */
-    public static class SavedState extends AbsSavedState {
-        public Bundle menuState;
-
-        public SavedState(Parcel in, ClassLoader loader) {
-            super(in, loader);
-            menuState = in.readBundle(loader);
-        }
-
-        public SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        @Override
-        public void writeToParcel(@NonNull Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeBundle(menuState);
-        }
-
-        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                return new SavedState(in, loader);
-            }
-
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in, null);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-}
diff --git a/design/src/android/support/design/widget/Snackbar.java b/design/src/android/support/design/widget/Snackbar.java
deleted file mode 100644
index bd5ffba..0000000
--- a/design/src/android/support/design/widget/Snackbar.java
+++ /dev/null
@@ -1,353 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.StringRes;
-import android.support.design.R;
-import android.support.design.internal.SnackbarContentLayout;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-/**
- * Snackbars provide lightweight feedback about an operation. They show a brief message at the
- * bottom of the screen on mobile and lower left on larger devices. Snackbars appear above all other
- * elements on screen and only one can be displayed at a time.
- * <p>
- * They automatically disappear after a timeout or after user interaction elsewhere on the screen,
- * particularly after interactions that summon a new surface or activity. Snackbars can be swiped
- * off screen.
- * <p>
- * Snackbars can contain an action which is set via
- * {@link #setAction(CharSequence, android.view.View.OnClickListener)}.
- * <p>
- * To be notified when a snackbar has been shown or dismissed, you can provide a {@link Callback}
- * via {@link BaseTransientBottomBar#addCallback(BaseCallback)}.</p>
- */
-public final class Snackbar extends BaseTransientBottomBar<Snackbar> {
-
-    /**
-     * Show the Snackbar indefinitely. This means that the Snackbar will be displayed from the time
-     * that is {@link #show() shown} until either it is dismissed, or another Snackbar is shown.
-     *
-     * @see #setDuration
-     */
-    public static final int LENGTH_INDEFINITE = BaseTransientBottomBar.LENGTH_INDEFINITE;
-
-    /**
-     * Show the Snackbar for a short period of time.
-     *
-     * @see #setDuration
-     */
-    public static final int LENGTH_SHORT = BaseTransientBottomBar.LENGTH_SHORT;
-
-    /**
-     * Show the Snackbar for a long period of time.
-     *
-     * @see #setDuration
-     */
-    public static final int LENGTH_LONG = BaseTransientBottomBar.LENGTH_LONG;
-
-    /**
-     * Callback class for {@link Snackbar} instances.
-     *
-     * Note: this class is here to provide backwards-compatible way for apps written before
-     * the existence of the base {@link BaseTransientBottomBar} class.
-     *
-     * @see BaseTransientBottomBar#addCallback(BaseCallback)
-     */
-    public static class Callback extends BaseCallback<Snackbar> {
-        /** Indicates that the Snackbar was dismissed via a swipe.*/
-        public static final int DISMISS_EVENT_SWIPE = BaseCallback.DISMISS_EVENT_SWIPE;
-        /** Indicates that the Snackbar was dismissed via an action click.*/
-        public static final int DISMISS_EVENT_ACTION = BaseCallback.DISMISS_EVENT_ACTION;
-        /** Indicates that the Snackbar was dismissed via a timeout.*/
-        public static final int DISMISS_EVENT_TIMEOUT = BaseCallback.DISMISS_EVENT_TIMEOUT;
-        /** Indicates that the Snackbar was dismissed via a call to {@link #dismiss()}.*/
-        public static final int DISMISS_EVENT_MANUAL = BaseCallback.DISMISS_EVENT_MANUAL;
-        /** Indicates that the Snackbar was dismissed from a new Snackbar being shown.*/
-        public static final int DISMISS_EVENT_CONSECUTIVE = BaseCallback.DISMISS_EVENT_CONSECUTIVE;
-
-        @Override
-        public void onShown(Snackbar sb) {
-            // Stub implementation to make API check happy.
-        }
-
-        @Override
-        public void onDismissed(Snackbar transientBottomBar, @DismissEvent int event) {
-            // Stub implementation to make API check happy.
-        }
-    }
-
-    @Nullable private BaseCallback<Snackbar> mCallback;
-
-    private Snackbar(ViewGroup parent, View content, ContentViewCallback contentViewCallback) {
-        super(parent, content, contentViewCallback);
-    }
-
-    /**
-     * Make a Snackbar to display a message
-     *
-     * <p>Snackbar will try and find a parent view to hold Snackbar's view from the value given
-     * to {@code view}. Snackbar will walk up the view tree trying to find a suitable parent,
-     * which is defined as a {@link CoordinatorLayout} or the window decor's content view,
-     * whichever comes first.
-     *
-     * <p>Having a {@link CoordinatorLayout} in your view hierarchy allows Snackbar to enable
-     * certain features, such as swipe-to-dismiss and automatically moving of widgets like
-     * {@link FloatingActionButton}.
-     *
-     * @param view     The view to find a parent from.
-     * @param text     The text to show.  Can be formatted text.
-     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or {@link
-     *                 #LENGTH_LONG}
-     */
-    @NonNull
-    public static Snackbar make(@NonNull View view, @NonNull CharSequence text,
-            @Duration int duration) {
-        final ViewGroup parent = findSuitableParent(view);
-        if (parent == null) {
-            throw new IllegalArgumentException("No suitable parent found from the given view. "
-                    + "Please provide a valid view.");
-        }
-
-        final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
-        final SnackbarContentLayout content =
-                (SnackbarContentLayout) inflater.inflate(
-                        R.layout.design_layout_snackbar_include, parent, false);
-        final Snackbar snackbar = new Snackbar(parent, content, content);
-        snackbar.setText(text);
-        snackbar.setDuration(duration);
-        return snackbar;
-    }
-
-    /**
-     * Make a Snackbar to display a message.
-     *
-     * <p>Snackbar will try and find a parent view to hold Snackbar's view from the value given
-     * to {@code view}. Snackbar will walk up the view tree trying to find a suitable parent,
-     * which is defined as a {@link CoordinatorLayout} or the window decor's content view,
-     * whichever comes first.
-     *
-     * <p>Having a {@link CoordinatorLayout} in your view hierarchy allows Snackbar to enable
-     * certain features, such as swipe-to-dismiss and automatically moving of widgets like
-     * {@link FloatingActionButton}.
-     *
-     * @param view     The view to find a parent from.
-     * @param resId    The resource id of the string resource to use. Can be formatted text.
-     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or {@link
-     *                 #LENGTH_LONG}
-     */
-    @NonNull
-    public static Snackbar make(@NonNull View view, @StringRes int resId, @Duration int duration) {
-        return make(view, view.getResources().getText(resId), duration);
-    }
-
-    private static ViewGroup findSuitableParent(View view) {
-        ViewGroup fallback = null;
-        do {
-            if (view instanceof CoordinatorLayout) {
-                // We've found a CoordinatorLayout, use it
-                return (ViewGroup) view;
-            } else if (view instanceof FrameLayout) {
-                if (view.getId() == android.R.id.content) {
-                    // If we've hit the decor content view, then we didn't find a CoL in the
-                    // hierarchy, so use it.
-                    return (ViewGroup) view;
-                } else {
-                    // It's not the content view but we'll use it as our fallback
-                    fallback = (ViewGroup) view;
-                }
-            }
-
-            if (view != null) {
-                // Else, we will loop and crawl up the view hierarchy and try to find a parent
-                final ViewParent parent = view.getParent();
-                view = parent instanceof View ? (View) parent : null;
-            }
-        } while (view != null);
-
-        // If we reach here then we didn't find a CoL or a suitable content view so we'll fallback
-        return fallback;
-    }
-
-    /**
-     * Update the text in this {@link Snackbar}.
-     *
-     * @param message The new text for this {@link BaseTransientBottomBar}.
-     */
-    @NonNull
-    public Snackbar setText(@NonNull CharSequence message) {
-        final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);
-        final TextView tv = contentLayout.getMessageView();
-        tv.setText(message);
-        return this;
-    }
-
-    /**
-     * Update the text in this {@link Snackbar}.
-     *
-     * @param resId The new text for this {@link BaseTransientBottomBar}.
-     */
-    @NonNull
-    public Snackbar setText(@StringRes int resId) {
-        return setText(getContext().getText(resId));
-    }
-
-    /**
-     * Set the action to be displayed in this {@link BaseTransientBottomBar}.
-     *
-     * @param resId    String resource to display for the action
-     * @param listener callback to be invoked when the action is clicked
-     */
-    @NonNull
-    public Snackbar setAction(@StringRes int resId, View.OnClickListener listener) {
-        return setAction(getContext().getText(resId), listener);
-    }
-
-    /**
-     * Set the action to be displayed in this {@link BaseTransientBottomBar}.
-     *
-     * @param text     Text to display for the action
-     * @param listener callback to be invoked when the action is clicked
-     */
-    @NonNull
-    public Snackbar setAction(CharSequence text, final View.OnClickListener listener) {
-        final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);
-        final TextView tv = contentLayout.getActionView();
-
-        if (TextUtils.isEmpty(text) || listener == null) {
-            tv.setVisibility(View.GONE);
-            tv.setOnClickListener(null);
-        } else {
-            tv.setVisibility(View.VISIBLE);
-            tv.setText(text);
-            tv.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View view) {
-                    listener.onClick(view);
-                    // Now dismiss the Snackbar
-                    dispatchDismiss(BaseCallback.DISMISS_EVENT_ACTION);
-                }
-            });
-        }
-        return this;
-    }
-
-    /**
-     * Sets the text color of the action specified in
-     * {@link #setAction(CharSequence, View.OnClickListener)}.
-     */
-    @NonNull
-    public Snackbar setActionTextColor(ColorStateList colors) {
-        final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);
-        final TextView tv = contentLayout.getActionView();
-        tv.setTextColor(colors);
-        return this;
-    }
-
-    /**
-     * Sets the text color of the action specified in
-     * {@link #setAction(CharSequence, View.OnClickListener)}.
-     */
-    @NonNull
-    public Snackbar setActionTextColor(@ColorInt int color) {
-        final SnackbarContentLayout contentLayout = (SnackbarContentLayout) mView.getChildAt(0);
-        final TextView tv = contentLayout.getActionView();
-        tv.setTextColor(color);
-        return this;
-    }
-
-    /**
-     * Set a callback to be called when this the visibility of this {@link Snackbar}
-     * changes. Note that this method is deprecated
-     * and you should use {@link #addCallback(BaseCallback)} to add a callback and
-     * {@link #removeCallback(BaseCallback)} to remove a registered callback.
-     *
-     * @param callback Callback to notify when transient bottom bar events occur.
-     * @deprecated Use {@link #addCallback(BaseCallback)}
-     * @see Callback
-     * @see #addCallback(BaseCallback)
-     * @see #removeCallback(BaseCallback)
-     */
-    @Deprecated
-    @NonNull
-    public Snackbar setCallback(Callback callback) {
-        // The logic in this method emulates what we had before support for multiple
-        // registered callbacks.
-        if (mCallback != null) {
-            removeCallback(mCallback);
-        }
-        if (callback != null) {
-            addCallback(callback);
-        }
-        // Update the deprecated field so that we can remove the passed callback the next
-        // time we're called
-        mCallback = callback;
-        return this;
-    }
-
-    /**
-     * @hide
-     *
-     * Note: this class is here to provide backwards-compatible way for apps written before
-     * the existence of the base {@link BaseTransientBottomBar} class.
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public static final class SnackbarLayout extends BaseTransientBottomBar.SnackbarBaseLayout {
-        public SnackbarLayout(Context context) {
-            super(context);
-        }
-
-        public SnackbarLayout(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            // Work around our backwards-compatible refactoring of Snackbar and inner content
-            // being inflated against snackbar's parent (instead of against the snackbar itself).
-            // Every child that is width=MATCH_PARENT is remeasured again and given the full width
-            // minus the paddings.
-            int childCount = getChildCount();
-            int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
-            for (int i = 0; i < childCount; i++) {
-                View child = getChildAt(i);
-                if (child.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT) {
-                    child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY),
-                            MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
-                                    MeasureSpec.EXACTLY));
-                }
-            }
-        }
-    }
-}
-
diff --git a/design/src/android/support/design/widget/SnackbarManager.java b/design/src/android/support/design/widget/SnackbarManager.java
deleted file mode 100644
index 43892d3..0000000
--- a/design/src/android/support/design/widget/SnackbarManager.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Manages {@link Snackbar}s.
- */
-class SnackbarManager {
-
-    static final int MSG_TIMEOUT = 0;
-
-    private static final int SHORT_DURATION_MS = 1500;
-    private static final int LONG_DURATION_MS = 2750;
-
-    private static SnackbarManager sSnackbarManager;
-
-    static SnackbarManager getInstance() {
-        if (sSnackbarManager == null) {
-            sSnackbarManager = new SnackbarManager();
-        }
-        return sSnackbarManager;
-    }
-
-    private final Object mLock;
-    private final Handler mHandler;
-
-    private SnackbarRecord mCurrentSnackbar;
-    private SnackbarRecord mNextSnackbar;
-
-    private SnackbarManager() {
-        mLock = new Object();
-        mHandler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
-            @Override
-            public boolean handleMessage(Message message) {
-                switch (message.what) {
-                    case MSG_TIMEOUT:
-                        handleTimeout((SnackbarRecord) message.obj);
-                        return true;
-                }
-                return false;
-            }
-        });
-    }
-
-    interface Callback {
-        void show();
-        void dismiss(int event);
-    }
-
-    public void show(int duration, Callback callback) {
-        synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback)) {
-                // Means that the callback is already in the queue. We'll just update the duration
-                mCurrentSnackbar.duration = duration;
-
-                // If this is the Snackbar currently being shown, call re-schedule it's
-                // timeout
-                mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
-                scheduleTimeoutLocked(mCurrentSnackbar);
-                return;
-            } else if (isNextSnackbarLocked(callback)) {
-                // We'll just update the duration
-                mNextSnackbar.duration = duration;
-            } else {
-                // Else, we need to create a new record and queue it
-                mNextSnackbar = new SnackbarRecord(duration, callback);
-            }
-
-            if (mCurrentSnackbar != null && cancelSnackbarLocked(mCurrentSnackbar,
-                    Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE)) {
-                // If we currently have a Snackbar, try and cancel it and wait in line
-                return;
-            } else {
-                // Clear out the current snackbar
-                mCurrentSnackbar = null;
-                // Otherwise, just show it now
-                showNextSnackbarLocked();
-            }
-        }
-    }
-
-    public void dismiss(Callback callback, int event) {
-        synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback)) {
-                cancelSnackbarLocked(mCurrentSnackbar, event);
-            } else if (isNextSnackbarLocked(callback)) {
-                cancelSnackbarLocked(mNextSnackbar, event);
-            }
-        }
-    }
-
-    /**
-     * Should be called when a Snackbar is no longer displayed. This is after any exit
-     * animation has finished.
-     */
-    public void onDismissed(Callback callback) {
-        synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback)) {
-                // If the callback is from a Snackbar currently show, remove it and show a new one
-                mCurrentSnackbar = null;
-                if (mNextSnackbar != null) {
-                    showNextSnackbarLocked();
-                }
-            }
-        }
-    }
-
-    /**
-     * Should be called when a Snackbar is being shown. This is after any entrance animation has
-     * finished.
-     */
-    public void onShown(Callback callback) {
-        synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback)) {
-                scheduleTimeoutLocked(mCurrentSnackbar);
-            }
-        }
-    }
-
-    public void pauseTimeout(Callback callback) {
-        synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback) && !mCurrentSnackbar.paused) {
-                mCurrentSnackbar.paused = true;
-                mHandler.removeCallbacksAndMessages(mCurrentSnackbar);
-            }
-        }
-    }
-
-    public void restoreTimeoutIfPaused(Callback callback) {
-        synchronized (mLock) {
-            if (isCurrentSnackbarLocked(callback) && mCurrentSnackbar.paused) {
-                mCurrentSnackbar.paused = false;
-                scheduleTimeoutLocked(mCurrentSnackbar);
-            }
-        }
-    }
-
-    public boolean isCurrent(Callback callback) {
-        synchronized (mLock) {
-            return isCurrentSnackbarLocked(callback);
-        }
-    }
-
-    public boolean isCurrentOrNext(Callback callback) {
-        synchronized (mLock) {
-            return isCurrentSnackbarLocked(callback) || isNextSnackbarLocked(callback);
-        }
-    }
-
-    private static class SnackbarRecord {
-        final WeakReference<Callback> callback;
-        int duration;
-        boolean paused;
-
-        SnackbarRecord(int duration, Callback callback) {
-            this.callback = new WeakReference<>(callback);
-            this.duration = duration;
-        }
-
-        boolean isSnackbar(Callback callback) {
-            return callback != null && this.callback.get() == callback;
-        }
-    }
-
-    private void showNextSnackbarLocked() {
-        if (mNextSnackbar != null) {
-            mCurrentSnackbar = mNextSnackbar;
-            mNextSnackbar = null;
-
-            final Callback callback = mCurrentSnackbar.callback.get();
-            if (callback != null) {
-                callback.show();
-            } else {
-                // The callback doesn't exist any more, clear out the Snackbar
-                mCurrentSnackbar = null;
-            }
-        }
-    }
-
-    private boolean cancelSnackbarLocked(SnackbarRecord record, int event) {
-        final Callback callback = record.callback.get();
-        if (callback != null) {
-            // Make sure we remove any timeouts for the SnackbarRecord
-            mHandler.removeCallbacksAndMessages(record);
-            callback.dismiss(event);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean isCurrentSnackbarLocked(Callback callback) {
-        return mCurrentSnackbar != null && mCurrentSnackbar.isSnackbar(callback);
-    }
-
-    private boolean isNextSnackbarLocked(Callback callback) {
-        return mNextSnackbar != null && mNextSnackbar.isSnackbar(callback);
-    }
-
-    private void scheduleTimeoutLocked(SnackbarRecord r) {
-        if (r.duration == Snackbar.LENGTH_INDEFINITE) {
-            // If we're set to indefinite, we don't want to set a timeout
-            return;
-        }
-
-        int durationMs = LONG_DURATION_MS;
-        if (r.duration > 0) {
-            durationMs = r.duration;
-        } else if (r.duration == Snackbar.LENGTH_SHORT) {
-            durationMs = SHORT_DURATION_MS;
-        }
-        mHandler.removeCallbacksAndMessages(r);
-        mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_TIMEOUT, r), durationMs);
-    }
-
-    void handleTimeout(SnackbarRecord record) {
-        synchronized (mLock) {
-            if (mCurrentSnackbar == record || mNextSnackbar == record) {
-                cancelSnackbarLocked(record, Snackbar.Callback.DISMISS_EVENT_TIMEOUT);
-            }
-        }
-    }
-
-}
diff --git a/design/src/android/support/design/widget/SwipeDismissBehavior.java b/design/src/android/support/design/widget/SwipeDismissBehavior.java
deleted file mode 100644
index d857334..0000000
--- a/design/src/android/support/design/widget/SwipeDismissBehavior.java
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.IntDef;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.ViewDragHelper;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * An interaction behavior plugin for child views of {@link CoordinatorLayout} to provide support
- * for the 'swipe-to-dismiss' gesture.
- */
-public class SwipeDismissBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
-
-    /**
-     * A view is not currently being dragged or animating as a result of a fling/snap.
-     */
-    public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
-
-    /**
-     * A view is currently being dragged. The position is currently changing as a result
-     * of user input or simulated user input.
-     */
-    public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
-
-    /**
-     * A view is currently settling into place as a result of a fling or
-     * predefined non-interactive motion.
-     */
-    public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
-
-    /** @hide */
-    @RestrictTo(LIBRARY_GROUP)
-    @IntDef({SWIPE_DIRECTION_START_TO_END, SWIPE_DIRECTION_END_TO_START, SWIPE_DIRECTION_ANY})
-    @Retention(RetentionPolicy.SOURCE)
-    private @interface SwipeDirection {}
-
-    /**
-     * Swipe direction that only allows swiping in the direction of start-to-end. That is
-     * left-to-right in LTR, or right-to-left in RTL.
-     */
-    public static final int SWIPE_DIRECTION_START_TO_END = 0;
-
-    /**
-     * Swipe direction that only allows swiping in the direction of end-to-start. That is
-     * right-to-left in LTR or left-to-right in RTL.
-     */
-    public static final int SWIPE_DIRECTION_END_TO_START = 1;
-
-    /**
-     * Swipe direction which allows swiping in either direction.
-     */
-    public static final int SWIPE_DIRECTION_ANY = 2;
-
-    private static final float DEFAULT_DRAG_DISMISS_THRESHOLD = 0.5f;
-    private static final float DEFAULT_ALPHA_START_DISTANCE = 0f;
-    private static final float DEFAULT_ALPHA_END_DISTANCE = DEFAULT_DRAG_DISMISS_THRESHOLD;
-
-    ViewDragHelper mViewDragHelper;
-    OnDismissListener mListener;
-    private boolean mInterceptingEvents;
-
-    private float mSensitivity = 0f;
-    private boolean mSensitivitySet;
-
-    int mSwipeDirection = SWIPE_DIRECTION_ANY;
-    float mDragDismissThreshold = DEFAULT_DRAG_DISMISS_THRESHOLD;
-    float mAlphaStartSwipeDistance = DEFAULT_ALPHA_START_DISTANCE;
-    float mAlphaEndSwipeDistance = DEFAULT_ALPHA_END_DISTANCE;
-
-    /**
-     * Callback interface used to notify the application that the view has been dismissed.
-     */
-    public interface OnDismissListener {
-        /**
-         * Called when {@code view} has been dismissed via swiping.
-         */
-        public void onDismiss(View view);
-
-        /**
-         * Called when the drag state has changed.
-         *
-         * @param state the new state. One of
-         * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
-         */
-        public void onDragStateChanged(int state);
-    }
-
-    /**
-     * Set the listener to be used when a dismiss event occurs.
-     *
-     * @param listener the listener to use.
-     */
-    public void setListener(OnDismissListener listener) {
-        mListener = listener;
-    }
-
-    /**
-     * Sets the swipe direction for this behavior.
-     *
-     * @param direction one of the {@link #SWIPE_DIRECTION_START_TO_END},
-     *                  {@link #SWIPE_DIRECTION_END_TO_START} or {@link #SWIPE_DIRECTION_ANY}
-     */
-    public void setSwipeDirection(@SwipeDirection int direction) {
-        mSwipeDirection = direction;
-    }
-
-    /**
-     * Set the threshold for telling if a view has been dragged enough to be dismissed.
-     *
-     * @param distance a ratio of a view's width, values are clamped to 0 >= x <= 1f;
-     */
-    public void setDragDismissDistance(float distance) {
-        mDragDismissThreshold = clamp(0f, distance, 1f);
-    }
-
-    /**
-     * The minimum swipe distance before the view's alpha is modified.
-     *
-     * @param fraction the distance as a fraction of the view's width.
-     */
-    public void setStartAlphaSwipeDistance(float fraction) {
-        mAlphaStartSwipeDistance = clamp(0f, fraction, 1f);
-    }
-
-    /**
-     * The maximum swipe distance for the view's alpha is modified.
-     *
-     * @param fraction the distance as a fraction of the view's width.
-     */
-    public void setEndAlphaSwipeDistance(float fraction) {
-        mAlphaEndSwipeDistance = clamp(0f, fraction, 1f);
-    }
-
-    /**
-     * Set the sensitivity used for detecting the start of a swipe. This only takes effect if
-     * no touch handling has occured yet.
-     *
-     * @param sensitivity Multiplier for how sensitive we should be about detecting
-     *                    the start of a drag. Larger values are more sensitive. 1.0f is normal.
-     */
-    public void setSensitivity(float sensitivity) {
-        mSensitivity = sensitivity;
-        mSensitivitySet = true;
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
-        boolean dispatchEventToHelper = mInterceptingEvents;
-
-        switch (event.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                mInterceptingEvents = parent.isPointInChildBounds(child,
-                        (int) event.getX(), (int) event.getY());
-                dispatchEventToHelper = mInterceptingEvents;
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                // Reset the ignore flag for next time
-                mInterceptingEvents = false;
-                break;
-        }
-
-        if (dispatchEventToHelper) {
-            ensureViewDragHelper(parent);
-            return mViewDragHelper.shouldInterceptTouchEvent(event);
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
-        if (mViewDragHelper != null) {
-            mViewDragHelper.processTouchEvent(event);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Called when the user's input indicates that they want to swipe the given view.
-     *
-     * @param view View the user is attempting to swipe
-     * @return true if the view can be dismissed via swiping, false otherwise
-     */
-    public boolean canSwipeDismissView(@NonNull View view) {
-        return true;
-    }
-
-    private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
-        private static final int INVALID_POINTER_ID = -1;
-
-        private int mOriginalCapturedViewLeft;
-        private int mActivePointerId = INVALID_POINTER_ID;
-
-        @Override
-        public boolean tryCaptureView(View child, int pointerId) {
-            // Only capture if we don't already have an active pointer id
-            return mActivePointerId == INVALID_POINTER_ID && canSwipeDismissView(child);
-        }
-
-        @Override
-        public void onViewCaptured(View capturedChild, int activePointerId) {
-            mActivePointerId = activePointerId;
-            mOriginalCapturedViewLeft = capturedChild.getLeft();
-
-            // The view has been captured, and thus a drag is about to start so stop any parents
-            // intercepting
-            final ViewParent parent = capturedChild.getParent();
-            if (parent != null) {
-                parent.requestDisallowInterceptTouchEvent(true);
-            }
-        }
-
-        @Override
-        public void onViewDragStateChanged(int state) {
-            if (mListener != null) {
-                mListener.onDragStateChanged(state);
-            }
-        }
-
-        @Override
-        public void onViewReleased(View child, float xvel, float yvel) {
-            // Reset the active pointer ID
-            mActivePointerId = INVALID_POINTER_ID;
-
-            final int childWidth = child.getWidth();
-            int targetLeft;
-            boolean dismiss = false;
-
-            if (shouldDismiss(child, xvel)) {
-                targetLeft = child.getLeft() < mOriginalCapturedViewLeft
-                        ? mOriginalCapturedViewLeft - childWidth
-                        : mOriginalCapturedViewLeft + childWidth;
-                dismiss = true;
-            } else {
-                // Else, reset back to the original left
-                targetLeft = mOriginalCapturedViewLeft;
-            }
-
-            if (mViewDragHelper.settleCapturedViewAt(targetLeft, child.getTop())) {
-                ViewCompat.postOnAnimation(child, new SettleRunnable(child, dismiss));
-            } else if (dismiss && mListener != null) {
-                mListener.onDismiss(child);
-            }
-        }
-
-        private boolean shouldDismiss(View child, float xvel) {
-            if (xvel != 0f) {
-                final boolean isRtl = ViewCompat.getLayoutDirection(child)
-                        == ViewCompat.LAYOUT_DIRECTION_RTL;
-
-                if (mSwipeDirection == SWIPE_DIRECTION_ANY) {
-                    // We don't care about the direction so return true
-                    return true;
-                } else if (mSwipeDirection == SWIPE_DIRECTION_START_TO_END) {
-                    // We only allow start-to-end swiping, so the fling needs to be in the
-                    // correct direction
-                    return isRtl ? xvel < 0f : xvel > 0f;
-                } else if (mSwipeDirection == SWIPE_DIRECTION_END_TO_START) {
-                    // We only allow end-to-start swiping, so the fling needs to be in the
-                    // correct direction
-                    return isRtl ? xvel > 0f : xvel < 0f;
-                }
-            } else {
-                final int distance = child.getLeft() - mOriginalCapturedViewLeft;
-                final int thresholdDistance = Math.round(child.getWidth() * mDragDismissThreshold);
-                return Math.abs(distance) >= thresholdDistance;
-            }
-
-            return false;
-        }
-
-        @Override
-        public int getViewHorizontalDragRange(View child) {
-            return child.getWidth();
-        }
-
-        @Override
-        public int clampViewPositionHorizontal(View child, int left, int dx) {
-            final boolean isRtl = ViewCompat.getLayoutDirection(child)
-                    == ViewCompat.LAYOUT_DIRECTION_RTL;
-            int min, max;
-
-            if (mSwipeDirection == SWIPE_DIRECTION_START_TO_END) {
-                if (isRtl) {
-                    min = mOriginalCapturedViewLeft - child.getWidth();
-                    max = mOriginalCapturedViewLeft;
-                } else {
-                    min = mOriginalCapturedViewLeft;
-                    max = mOriginalCapturedViewLeft + child.getWidth();
-                }
-            } else if (mSwipeDirection == SWIPE_DIRECTION_END_TO_START) {
-                if (isRtl) {
-                    min = mOriginalCapturedViewLeft;
-                    max = mOriginalCapturedViewLeft + child.getWidth();
-                } else {
-                    min = mOriginalCapturedViewLeft - child.getWidth();
-                    max = mOriginalCapturedViewLeft;
-                }
-            } else {
-                min = mOriginalCapturedViewLeft - child.getWidth();
-                max = mOriginalCapturedViewLeft + child.getWidth();
-            }
-
-            return clamp(min, left, max);
-        }
-
-        @Override
-        public int clampViewPositionVertical(View child, int top, int dy) {
-            return child.getTop();
-        }
-
-        @Override
-        public void onViewPositionChanged(View child, int left, int top, int dx, int dy) {
-            final float startAlphaDistance = mOriginalCapturedViewLeft
-                    + child.getWidth() * mAlphaStartSwipeDistance;
-            final float endAlphaDistance = mOriginalCapturedViewLeft
-                    + child.getWidth() * mAlphaEndSwipeDistance;
-
-            if (left <= startAlphaDistance) {
-                child.setAlpha(1f);
-            } else if (left >= endAlphaDistance) {
-                child.setAlpha(0f);
-            } else {
-                // We're between the start and end distances
-                final float distance = fraction(startAlphaDistance, endAlphaDistance, left);
-                child.setAlpha(clamp(0f, 1f - distance, 1f));
-            }
-        }
-    };
-
-    private void ensureViewDragHelper(ViewGroup parent) {
-        if (mViewDragHelper == null) {
-            mViewDragHelper = mSensitivitySet
-                    ? ViewDragHelper.create(parent, mSensitivity, mDragCallback)
-                    : ViewDragHelper.create(parent, mDragCallback);
-        }
-    }
-
-    private class SettleRunnable implements Runnable {
-        private final View mView;
-        private final boolean mDismiss;
-
-        SettleRunnable(View view, boolean dismiss) {
-            mView = view;
-            mDismiss = dismiss;
-        }
-
-        @Override
-        public void run() {
-            if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
-                ViewCompat.postOnAnimation(mView, this);
-            } else {
-                if (mDismiss && mListener != null) {
-                    mListener.onDismiss(mView);
-                }
-            }
-        }
-    }
-
-    static float clamp(float min, float value, float max) {
-        return Math.min(Math.max(min, value), max);
-    }
-
-    static int clamp(int min, int value, int max) {
-        return Math.min(Math.max(min, value), max);
-    }
-
-    /**
-     * Retrieve the current drag state of this behavior. This will return one of
-     * {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
-     *
-     * @return The current drag state
-     */
-    public int getDragState() {
-        return mViewDragHelper != null ? mViewDragHelper.getViewDragState() : STATE_IDLE;
-    }
-
-    /**
-     * The fraction that {@code value} is between {@code startValue} and {@code endValue}.
-     */
-    static float fraction(float startValue, float endValue, float value) {
-        return (value - startValue) / (endValue - startValue);
-    }
-}
\ No newline at end of file
diff --git a/design/src/android/support/design/widget/TabItem.java b/design/src/android/support/design/widget/TabItem.java
deleted file mode 100644
index 09b01db..0000000
--- a/design/src/android/support/design/widget/TabItem.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.design.R;
-import android.support.v7.widget.TintTypedArray;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * TabItem is a special 'view' which allows you to declare tab items for a {@link TabLayout}
- * within a layout. This view is not actually added to TabLayout, it is just a dummy which allows
- * setting of a tab items's text, icon and custom layout. See TabLayout for more information on how
- * to use it.
- *
- * @attr ref android.support.design.R.styleable#TabItem_android_icon
- * @attr ref android.support.design.R.styleable#TabItem_android_text
- * @attr ref android.support.design.R.styleable#TabItem_android_layout
- *
- * @see TabLayout
- */
-public final class TabItem extends View {
-    final CharSequence mText;
-    final Drawable mIcon;
-    final int mCustomLayout;
-
-    public TabItem(Context context) {
-        this(context, null);
-    }
-
-    public TabItem(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
-                R.styleable.TabItem);
-        mText = a.getText(R.styleable.TabItem_android_text);
-        mIcon = a.getDrawable(R.styleable.TabItem_android_icon);
-        mCustomLayout = a.getResourceId(R.styleable.TabItem_android_layout, 0);
-        a.recycle();
-    }
-}
\ No newline at end of file
diff --git a/design/src/android/support/design/widget/TabLayout.java b/design/src/android/support/design/widget/TabLayout.java
deleted file mode 100755
index 9b81465..0000000
--- a/design/src/android/support/design/widget/TabLayout.java
+++ /dev/null
@@ -1,2217 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-import static android.support.v4.view.ViewPager.SCROLL_STATE_DRAGGING;
-import static android.support.v4.view.ViewPager.SCROLL_STATE_IDLE;
-import static android.support.v4.view.ViewPager.SCROLL_STATE_SETTLING;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.database.DataSetObserver;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IntDef;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.annotation.StringRes;
-import android.support.design.R;
-import android.support.v4.util.Pools;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.PointerIconCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.ViewPager;
-import android.support.v4.widget.TextViewCompat;
-import android.support.v7.app.ActionBar;
-import android.support.v7.content.res.AppCompatResources;
-import android.support.v7.widget.TooltipCompat;
-import android.text.Layout;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.SoundEffectConstants;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.HorizontalScrollView;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * TabLayout provides a horizontal layout to display tabs.
- *
- * <p>Population of the tabs to display is
- * done through {@link Tab} instances. You create tabs via {@link #newTab()}. From there you can
- * change the tab's label or icon via {@link Tab#setText(int)} and {@link Tab#setIcon(int)}
- * respectively. To display the tab, you need to add it to the layout via one of the
- * {@link #addTab(Tab)} methods. For example:
- * <pre>
- * TabLayout tabLayout = ...;
- * tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));
- * tabLayout.addTab(tabLayout.newTab().setText("Tab 2"));
- * tabLayout.addTab(tabLayout.newTab().setText("Tab 3"));
- * </pre>
- * You should set a listener via {@link #setOnTabSelectedListener(OnTabSelectedListener)} to be
- * notified when any tab's selection state has been changed.
- *
- * <p>You can also add items to TabLayout in your layout through the use of {@link TabItem}.
- * An example usage is like so:</p>
- *
- * <pre>
- * &lt;android.support.design.widget.TabLayout
- *         android:layout_height=&quot;wrap_content&quot;
- *         android:layout_width=&quot;match_parent&quot;&gt;
- *
- *     &lt;android.support.design.widget.TabItem
- *             android:text=&quot;@string/tab_text&quot;/&gt;
- *
- *     &lt;android.support.design.widget.TabItem
- *             android:icon=&quot;@drawable/ic_android&quot;/&gt;
- *
- * &lt;/android.support.design.widget.TabLayout&gt;
- * </pre>
- *
- * <h3>ViewPager integration</h3>
- * <p>
- * If you're using a {@link android.support.v4.view.ViewPager} together
- * with this layout, you can call {@link #setupWithViewPager(ViewPager)} to link the two together.
- * This layout will be automatically populated from the {@link PagerAdapter}'s page titles.</p>
- *
- * <p>
- * This view also supports being used as part of a ViewPager's decor, and can be added
- * directly to the ViewPager in a layout resource file like so:</p>
- *
- * <pre>
- * &lt;android.support.v4.view.ViewPager
- *     android:layout_width=&quot;match_parent&quot;
- *     android:layout_height=&quot;match_parent&quot;&gt;
- *
- *     &lt;android.support.design.widget.TabLayout
- *         android:layout_width=&quot;match_parent&quot;
- *         android:layout_height=&quot;wrap_content&quot;
- *         android:layout_gravity=&quot;top&quot; /&gt;
- *
- * &lt;/android.support.v4.view.ViewPager&gt;
- * </pre>
- *
- * @see <a href="http://www.google.com/design/spec/components/tabs.html">Tabs</a>
- *
- * @attr ref android.support.design.R.styleable#TabLayout_tabPadding
- * @attr ref android.support.design.R.styleable#TabLayout_tabPaddingStart
- * @attr ref android.support.design.R.styleable#TabLayout_tabPaddingTop
- * @attr ref android.support.design.R.styleable#TabLayout_tabPaddingEnd
- * @attr ref android.support.design.R.styleable#TabLayout_tabPaddingBottom
- * @attr ref android.support.design.R.styleable#TabLayout_tabContentStart
- * @attr ref android.support.design.R.styleable#TabLayout_tabBackground
- * @attr ref android.support.design.R.styleable#TabLayout_tabMinWidth
- * @attr ref android.support.design.R.styleable#TabLayout_tabMaxWidth
- * @attr ref android.support.design.R.styleable#TabLayout_tabTextAppearance
- */
-@ViewPager.DecorView
-public class TabLayout extends HorizontalScrollView {
-
-    private static final int DEFAULT_HEIGHT_WITH_TEXT_ICON = 72; // dps
-    static final int DEFAULT_GAP_TEXT_ICON = 8; // dps
-    private static final int INVALID_WIDTH = -1;
-    private static final int DEFAULT_HEIGHT = 48; // dps
-    private static final int TAB_MIN_WIDTH_MARGIN = 56; //dps
-    static final int FIXED_WRAP_GUTTER_MIN = 16; //dps
-    static final int MOTION_NON_ADJACENT_OFFSET = 24;
-
-    private static final int ANIMATION_DURATION = 300;
-
-    private static final Pools.Pool<Tab> sTabPool = new Pools.SynchronizedPool<>(16);
-
-    /**
-     * Scrollable tabs display a subset of tabs at any given moment, and can contain longer tab
-     * labels and a larger number of tabs. They are best used for browsing contexts in touch
-     * interfaces when users don’t need to directly compare the tab labels.
-     *
-     * @see #setTabMode(int)
-     * @see #getTabMode()
-     */
-    public static final int MODE_SCROLLABLE = 0;
-
-    /**
-     * Fixed tabs display all tabs concurrently and are best used with content that benefits from
-     * quick pivots between tabs. The maximum number of tabs is limited by the view’s width.
-     * Fixed tabs have equal width, based on the widest tab label.
-     *
-     * @see #setTabMode(int)
-     * @see #getTabMode()
-     */
-    public static final int MODE_FIXED = 1;
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    @IntDef(value = {MODE_SCROLLABLE, MODE_FIXED})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Mode {}
-
-    /**
-     * Gravity used to fill the {@link TabLayout} as much as possible. This option only takes effect
-     * when used with {@link #MODE_FIXED}.
-     *
-     * @see #setTabGravity(int)
-     * @see #getTabGravity()
-     */
-    public static final int GRAVITY_FILL = 0;
-
-    /**
-     * Gravity used to lay out the tabs in the center of the {@link TabLayout}.
-     *
-     * @see #setTabGravity(int)
-     * @see #getTabGravity()
-     */
-    public static final int GRAVITY_CENTER = 1;
-
-    /**
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    @IntDef(flag = true, value = {GRAVITY_FILL, GRAVITY_CENTER})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface TabGravity {}
-
-    /**
-     * Callback interface invoked when a tab's selection state changes.
-     */
-    public interface OnTabSelectedListener {
-
-        /**
-         * Called when a tab enters the selected state.
-         *
-         * @param tab The tab that was selected
-         */
-        public void onTabSelected(Tab tab);
-
-        /**
-         * Called when a tab exits the selected state.
-         *
-         * @param tab The tab that was unselected
-         */
-        public void onTabUnselected(Tab tab);
-
-        /**
-         * Called when a tab that is already selected is chosen again by the user. Some applications
-         * may use this action to return to the top level of a category.
-         *
-         * @param tab The tab that was reselected.
-         */
-        public void onTabReselected(Tab tab);
-    }
-
-    private final ArrayList<Tab> mTabs = new ArrayList<>();
-    private Tab mSelectedTab;
-
-    private final SlidingTabStrip mTabStrip;
-
-    int mTabPaddingStart;
-    int mTabPaddingTop;
-    int mTabPaddingEnd;
-    int mTabPaddingBottom;
-
-    int mTabTextAppearance;
-    ColorStateList mTabTextColors;
-    float mTabTextSize;
-    float mTabTextMultiLineSize;
-
-    final int mTabBackgroundResId;
-
-    int mTabMaxWidth = Integer.MAX_VALUE;
-    private final int mRequestedTabMinWidth;
-    private final int mRequestedTabMaxWidth;
-    private final int mScrollableTabMinWidth;
-
-    private int mContentInsetStart;
-
-    int mTabGravity;
-    int mMode;
-
-    private OnTabSelectedListener mSelectedListener;
-    private final ArrayList<OnTabSelectedListener> mSelectedListeners = new ArrayList<>();
-    private OnTabSelectedListener mCurrentVpSelectedListener;
-
-    private ValueAnimator mScrollAnimator;
-
-    ViewPager mViewPager;
-    private PagerAdapter mPagerAdapter;
-    private DataSetObserver mPagerAdapterObserver;
-    private TabLayoutOnPageChangeListener mPageChangeListener;
-    private AdapterChangeListener mAdapterChangeListener;
-    private boolean mSetupViewPagerImplicitly;
-
-    // Pool we use as a simple RecyclerBin
-    private final Pools.Pool<TabView> mTabViewPool = new Pools.SimplePool<>(12);
-
-    public TabLayout(Context context) {
-        this(context, null);
-    }
-
-    public TabLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        ThemeUtils.checkAppCompatTheme(context);
-
-        // Disable the Scroll Bar
-        setHorizontalScrollBarEnabled(false);
-
-        // Add the TabStrip
-        mTabStrip = new SlidingTabStrip(context);
-        super.addView(mTabStrip, 0, new HorizontalScrollView.LayoutParams(
-                LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabLayout,
-                defStyleAttr, R.style.Widget_Design_TabLayout);
-
-        mTabStrip.setSelectedIndicatorHeight(
-                a.getDimensionPixelSize(R.styleable.TabLayout_tabIndicatorHeight, 0));
-        mTabStrip.setSelectedIndicatorColor(a.getColor(R.styleable.TabLayout_tabIndicatorColor, 0));
-
-        mTabPaddingStart = mTabPaddingTop = mTabPaddingEnd = mTabPaddingBottom = a
-                .getDimensionPixelSize(R.styleable.TabLayout_tabPadding, 0);
-        mTabPaddingStart = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingStart,
-                mTabPaddingStart);
-        mTabPaddingTop = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingTop,
-                mTabPaddingTop);
-        mTabPaddingEnd = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingEnd,
-                mTabPaddingEnd);
-        mTabPaddingBottom = a.getDimensionPixelSize(R.styleable.TabLayout_tabPaddingBottom,
-                mTabPaddingBottom);
-
-        mTabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
-                R.style.TextAppearance_Design_Tab);
-
-        // Text colors/sizes come from the text appearance first
-        final TypedArray ta = context.obtainStyledAttributes(mTabTextAppearance,
-                android.support.v7.appcompat.R.styleable.TextAppearance);
-        try {
-            mTabTextSize = ta.getDimensionPixelSize(
-                    android.support.v7.appcompat.R.styleable.TextAppearance_android_textSize, 0);
-            mTabTextColors = ta.getColorStateList(
-                    android.support.v7.appcompat.R.styleable.TextAppearance_android_textColor);
-        } finally {
-            ta.recycle();
-        }
-
-        if (a.hasValue(R.styleable.TabLayout_tabTextColor)) {
-            // If we have an explicit text color set, use it instead
-            mTabTextColors = a.getColorStateList(R.styleable.TabLayout_tabTextColor);
-        }
-
-        if (a.hasValue(R.styleable.TabLayout_tabSelectedTextColor)) {
-            // We have an explicit selected text color set, so we need to make merge it with the
-            // current colors. This is exposed so that developers can use theme attributes to set
-            // this (theme attrs in ColorStateLists are Lollipop+)
-            final int selected = a.getColor(R.styleable.TabLayout_tabSelectedTextColor, 0);
-            mTabTextColors = createColorStateList(mTabTextColors.getDefaultColor(), selected);
-        }
-
-        mRequestedTabMinWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMinWidth,
-                INVALID_WIDTH);
-        mRequestedTabMaxWidth = a.getDimensionPixelSize(R.styleable.TabLayout_tabMaxWidth,
-                INVALID_WIDTH);
-        mTabBackgroundResId = a.getResourceId(R.styleable.TabLayout_tabBackground, 0);
-        mContentInsetStart = a.getDimensionPixelSize(R.styleable.TabLayout_tabContentStart, 0);
-        mMode = a.getInt(R.styleable.TabLayout_tabMode, MODE_FIXED);
-        mTabGravity = a.getInt(R.styleable.TabLayout_tabGravity, GRAVITY_FILL);
-        a.recycle();
-
-        // TODO add attr for these
-        final Resources res = getResources();
-        mTabTextMultiLineSize = res.getDimensionPixelSize(R.dimen.design_tab_text_size_2line);
-        mScrollableTabMinWidth = res.getDimensionPixelSize(R.dimen.design_tab_scrollable_min_width);
-
-        // Now apply the tab mode and gravity
-        applyModeAndGravity();
-    }
-
-    /**
-     * Sets the tab indicator's color for the currently selected tab.
-     *
-     * @param color color to use for the indicator
-     *
-     * @attr ref android.support.design.R.styleable#TabLayout_tabIndicatorColor
-     */
-    public void setSelectedTabIndicatorColor(@ColorInt int color) {
-        mTabStrip.setSelectedIndicatorColor(color);
-    }
-
-    /**
-     * Sets the tab indicator's height for the currently selected tab.
-     *
-     * @param height height to use for the indicator in pixels
-     *
-     * @attr ref android.support.design.R.styleable#TabLayout_tabIndicatorHeight
-     */
-    public void setSelectedTabIndicatorHeight(int height) {
-        mTabStrip.setSelectedIndicatorHeight(height);
-    }
-
-    /**
-     * Set the scroll position of the tabs. This is useful for when the tabs are being displayed as
-     * part of a scrolling container such as {@link android.support.v4.view.ViewPager}.
-     * <p>
-     * Calling this method does not update the selected tab, it is only used for drawing purposes.
-     *
-     * @param position current scroll position
-     * @param positionOffset Value from [0, 1) indicating the offset from {@code position}.
-     * @param updateSelectedText Whether to update the text's selected state.
-     */
-    public void setScrollPosition(int position, float positionOffset, boolean updateSelectedText) {
-        setScrollPosition(position, positionOffset, updateSelectedText, true);
-    }
-
-    void setScrollPosition(int position, float positionOffset, boolean updateSelectedText,
-            boolean updateIndicatorPosition) {
-        final int roundedPosition = Math.round(position + positionOffset);
-        if (roundedPosition < 0 || roundedPosition >= mTabStrip.getChildCount()) {
-            return;
-        }
-
-        // Set the indicator position, if enabled
-        if (updateIndicatorPosition) {
-            mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset);
-        }
-
-        // Now update the scroll position, canceling any running animation
-        if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
-            mScrollAnimator.cancel();
-        }
-        scrollTo(calculateScrollXForTab(position, positionOffset), 0);
-
-        // Update the 'selected state' view as we scroll, if enabled
-        if (updateSelectedText) {
-            setSelectedTabView(roundedPosition);
-        }
-    }
-
-    private float getScrollPosition() {
-        return mTabStrip.getIndicatorPosition();
-    }
-
-    /**
-     * Add a tab to this layout. The tab will be added at the end of the list.
-     * If this is the first tab to be added it will become the selected tab.
-     *
-     * @param tab Tab to add
-     */
-    public void addTab(@NonNull Tab tab) {
-        addTab(tab, mTabs.isEmpty());
-    }
-
-    /**
-     * Add a tab to this layout. The tab will be inserted at <code>position</code>.
-     * If this is the first tab to be added it will become the selected tab.
-     *
-     * @param tab The tab to add
-     * @param position The new position of the tab
-     */
-    public void addTab(@NonNull Tab tab, int position) {
-        addTab(tab, position, mTabs.isEmpty());
-    }
-
-    /**
-     * Add a tab to this layout. The tab will be added at the end of the list.
-     *
-     * @param tab Tab to add
-     * @param setSelected True if the added tab should become the selected tab.
-     */
-    public void addTab(@NonNull Tab tab, boolean setSelected) {
-        addTab(tab, mTabs.size(), setSelected);
-    }
-
-    /**
-     * Add a tab to this layout. The tab will be inserted at <code>position</code>.
-     *
-     * @param tab The tab to add
-     * @param position The new position of the tab
-     * @param setSelected True if the added tab should become the selected tab.
-     */
-    public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
-        if (tab.mParent != this) {
-            throw new IllegalArgumentException("Tab belongs to a different TabLayout.");
-        }
-        configureTab(tab, position);
-        addTabView(tab);
-
-        if (setSelected) {
-            tab.select();
-        }
-    }
-
-    private void addTabFromItemView(@NonNull TabItem item) {
-        final Tab tab = newTab();
-        if (item.mText != null) {
-            tab.setText(item.mText);
-        }
-        if (item.mIcon != null) {
-            tab.setIcon(item.mIcon);
-        }
-        if (item.mCustomLayout != 0) {
-            tab.setCustomView(item.mCustomLayout);
-        }
-        if (!TextUtils.isEmpty(item.getContentDescription())) {
-            tab.setContentDescription(item.getContentDescription());
-        }
-        addTab(tab);
-    }
-
-    /**
-     * @deprecated Use {@link #addOnTabSelectedListener(OnTabSelectedListener)} and
-     * {@link #removeOnTabSelectedListener(OnTabSelectedListener)}.
-     */
-    @Deprecated
-    public void setOnTabSelectedListener(@Nullable OnTabSelectedListener listener) {
-        // The logic in this method emulates what we had before support for multiple
-        // registered listeners.
-        if (mSelectedListener != null) {
-            removeOnTabSelectedListener(mSelectedListener);
-        }
-        // Update the deprecated field so that we can remove the passed listener the next
-        // time we're called
-        mSelectedListener = listener;
-        if (listener != null) {
-            addOnTabSelectedListener(listener);
-        }
-    }
-
-    /**
-     * Add a {@link TabLayout.OnTabSelectedListener} that will be invoked when tab selection
-     * changes.
-     *
-     * <p>Components that add a listener should take care to remove it when finished via
-     * {@link #removeOnTabSelectedListener(OnTabSelectedListener)}.</p>
-     *
-     * @param listener listener to add
-     */
-    public void addOnTabSelectedListener(@NonNull OnTabSelectedListener listener) {
-        if (!mSelectedListeners.contains(listener)) {
-            mSelectedListeners.add(listener);
-        }
-    }
-
-    /**
-     * Remove the given {@link TabLayout.OnTabSelectedListener} that was previously added via
-     * {@link #addOnTabSelectedListener(OnTabSelectedListener)}.
-     *
-     * @param listener listener to remove
-     */
-    public void removeOnTabSelectedListener(@NonNull OnTabSelectedListener listener) {
-        mSelectedListeners.remove(listener);
-    }
-
-    /**
-     * Remove all previously added {@link TabLayout.OnTabSelectedListener}s.
-     */
-    public void clearOnTabSelectedListeners() {
-        mSelectedListeners.clear();
-    }
-
-    /**
-     * Create and return a new {@link Tab}. You need to manually add this using
-     * {@link #addTab(Tab)} or a related method.
-     *
-     * @return A new Tab
-     * @see #addTab(Tab)
-     */
-    @NonNull
-    public Tab newTab() {
-        Tab tab = sTabPool.acquire();
-        if (tab == null) {
-            tab = new Tab();
-        }
-        tab.mParent = this;
-        tab.mView = createTabView(tab);
-        return tab;
-    }
-
-    /**
-     * Returns the number of tabs currently registered with the action bar.
-     *
-     * @return Tab count
-     */
-    public int getTabCount() {
-        return mTabs.size();
-    }
-
-    /**
-     * Returns the tab at the specified index.
-     */
-    @Nullable
-    public Tab getTabAt(int index) {
-        return (index < 0 || index >= getTabCount()) ? null : mTabs.get(index);
-    }
-
-    /**
-     * Returns the position of the current selected tab.
-     *
-     * @return selected tab position, or {@code -1} if there isn't a selected tab.
-     */
-    public int getSelectedTabPosition() {
-        return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
-    }
-
-    /**
-     * Remove a tab from the layout. If the removed tab was selected it will be deselected
-     * and another tab will be selected if present.
-     *
-     * @param tab The tab to remove
-     */
-    public void removeTab(Tab tab) {
-        if (tab.mParent != this) {
-            throw new IllegalArgumentException("Tab does not belong to this TabLayout.");
-        }
-
-        removeTabAt(tab.getPosition());
-    }
-
-    /**
-     * Remove a tab from the layout. If the removed tab was selected it will be deselected
-     * and another tab will be selected if present.
-     *
-     * @param position Position of the tab to remove
-     */
-    public void removeTabAt(int position) {
-        final int selectedTabPosition = mSelectedTab != null ? mSelectedTab.getPosition() : 0;
-        removeTabViewAt(position);
-
-        final Tab removedTab = mTabs.remove(position);
-        if (removedTab != null) {
-            removedTab.reset();
-            sTabPool.release(removedTab);
-        }
-
-        final int newTabCount = mTabs.size();
-        for (int i = position; i < newTabCount; i++) {
-            mTabs.get(i).setPosition(i);
-        }
-
-        if (selectedTabPosition == position) {
-            selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
-        }
-    }
-
-    /**
-     * Remove all tabs from the action bar and deselect the current tab.
-     */
-    public void removeAllTabs() {
-        // Remove all the views
-        for (int i = mTabStrip.getChildCount() - 1; i >= 0; i--) {
-            removeTabViewAt(i);
-        }
-
-        for (final Iterator<Tab> i = mTabs.iterator(); i.hasNext();) {
-            final Tab tab = i.next();
-            i.remove();
-            tab.reset();
-            sTabPool.release(tab);
-        }
-
-        mSelectedTab = null;
-    }
-
-    /**
-     * Set the behavior mode for the Tabs in this layout. The valid input options are:
-     * <ul>
-     * <li>{@link #MODE_FIXED}: Fixed tabs display all tabs concurrently and are best used
-     * with content that benefits from quick pivots between tabs.</li>
-     * <li>{@link #MODE_SCROLLABLE}: Scrollable tabs display a subset of tabs at any given moment,
-     * and can contain longer tab labels and a larger number of tabs. They are best used for
-     * browsing contexts in touch interfaces when users don’t need to directly compare the tab
-     * labels. This mode is commonly used with a {@link android.support.v4.view.ViewPager}.</li>
-     * </ul>
-     *
-     * @param mode one of {@link #MODE_FIXED} or {@link #MODE_SCROLLABLE}.
-     *
-     * @attr ref android.support.design.R.styleable#TabLayout_tabMode
-     */
-    public void setTabMode(@Mode int mode) {
-        if (mode != mMode) {
-            mMode = mode;
-            applyModeAndGravity();
-        }
-    }
-
-    /**
-     * Returns the current mode used by this {@link TabLayout}.
-     *
-     * @see #setTabMode(int)
-     */
-    @Mode
-    public int getTabMode() {
-        return mMode;
-    }
-
-    /**
-     * Set the gravity to use when laying out the tabs.
-     *
-     * @param gravity one of {@link #GRAVITY_CENTER} or {@link #GRAVITY_FILL}.
-     *
-     * @attr ref android.support.design.R.styleable#TabLayout_tabGravity
-     */
-    public void setTabGravity(@TabGravity int gravity) {
-        if (mTabGravity != gravity) {
-            mTabGravity = gravity;
-            applyModeAndGravity();
-        }
-    }
-
-    /**
-     * The current gravity used for laying out tabs.
-     *
-     * @return one of {@link #GRAVITY_CENTER} or {@link #GRAVITY_FILL}.
-     */
-    @TabGravity
-    public int getTabGravity() {
-        return mTabGravity;
-    }
-
-    /**
-     * Sets the text colors for the different states (normal, selected) used for the tabs.
-     *
-     * @see #getTabTextColors()
-     */
-    public void setTabTextColors(@Nullable ColorStateList textColor) {
-        if (mTabTextColors != textColor) {
-            mTabTextColors = textColor;
-            updateAllTabs();
-        }
-    }
-
-    /**
-     * Gets the text colors for the different states (normal, selected) used for the tabs.
-     */
-    @Nullable
-    public ColorStateList getTabTextColors() {
-        return mTabTextColors;
-    }
-
-    /**
-     * Sets the text colors for the different states (normal, selected) used for the tabs.
-     *
-     * @attr ref android.support.design.R.styleable#TabLayout_tabTextColor
-     * @attr ref android.support.design.R.styleable#TabLayout_tabSelectedTextColor
-     */
-    public void setTabTextColors(int normalColor, int selectedColor) {
-        setTabTextColors(createColorStateList(normalColor, selectedColor));
-    }
-
-    /**
-     * The one-stop shop for setting up this {@link TabLayout} with a {@link ViewPager}.
-     *
-     * <p>This is the same as calling {@link #setupWithViewPager(ViewPager, boolean)} with
-     * auto-refresh enabled.</p>
-     *
-     * @param viewPager the ViewPager to link to, or {@code null} to clear any previous link
-     */
-    public void setupWithViewPager(@Nullable ViewPager viewPager) {
-        setupWithViewPager(viewPager, true);
-    }
-
-    /**
-     * The one-stop shop for setting up this {@link TabLayout} with a {@link ViewPager}.
-     *
-     * <p>This method will link the given ViewPager and this TabLayout together so that
-     * changes in one are automatically reflected in the other. This includes scroll state changes
-     * and clicks. The tabs displayed in this layout will be populated
-     * from the ViewPager adapter's page titles.</p>
-     *
-     * <p>If {@code autoRefresh} is {@code true}, any changes in the {@link PagerAdapter} will
-     * trigger this layout to re-populate itself from the adapter's titles.</p>
-     *
-     * <p>If the given ViewPager is non-null, it needs to already have a
-     * {@link PagerAdapter} set.</p>
-     *
-     * @param viewPager   the ViewPager to link to, or {@code null} to clear any previous link
-     * @param autoRefresh whether this layout should refresh its contents if the given ViewPager's
-     *                    content changes
-     */
-    public void setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh) {
-        setupWithViewPager(viewPager, autoRefresh, false);
-    }
-
-    private void setupWithViewPager(@Nullable final ViewPager viewPager, boolean autoRefresh,
-            boolean implicitSetup) {
-        if (mViewPager != null) {
-            // If we've already been setup with a ViewPager, remove us from it
-            if (mPageChangeListener != null) {
-                mViewPager.removeOnPageChangeListener(mPageChangeListener);
-            }
-            if (mAdapterChangeListener != null) {
-                mViewPager.removeOnAdapterChangeListener(mAdapterChangeListener);
-            }
-        }
-
-        if (mCurrentVpSelectedListener != null) {
-            // If we already have a tab selected listener for the ViewPager, remove it
-            removeOnTabSelectedListener(mCurrentVpSelectedListener);
-            mCurrentVpSelectedListener = null;
-        }
-
-        if (viewPager != null) {
-            mViewPager = viewPager;
-
-            // Add our custom OnPageChangeListener to the ViewPager
-            if (mPageChangeListener == null) {
-                mPageChangeListener = new TabLayoutOnPageChangeListener(this);
-            }
-            mPageChangeListener.reset();
-            viewPager.addOnPageChangeListener(mPageChangeListener);
-
-            // Now we'll add a tab selected listener to set ViewPager's current item
-            mCurrentVpSelectedListener = new ViewPagerOnTabSelectedListener(viewPager);
-            addOnTabSelectedListener(mCurrentVpSelectedListener);
-
-            final PagerAdapter adapter = viewPager.getAdapter();
-            if (adapter != null) {
-                // Now we'll populate ourselves from the pager adapter, adding an observer if
-                // autoRefresh is enabled
-                setPagerAdapter(adapter, autoRefresh);
-            }
-
-            // Add a listener so that we're notified of any adapter changes
-            if (mAdapterChangeListener == null) {
-                mAdapterChangeListener = new AdapterChangeListener();
-            }
-            mAdapterChangeListener.setAutoRefresh(autoRefresh);
-            viewPager.addOnAdapterChangeListener(mAdapterChangeListener);
-
-            // Now update the scroll position to match the ViewPager's current item
-            setScrollPosition(viewPager.getCurrentItem(), 0f, true);
-        } else {
-            // We've been given a null ViewPager so we need to clear out the internal state,
-            // listeners and observers
-            mViewPager = null;
-            setPagerAdapter(null, false);
-        }
-
-        mSetupViewPagerImplicitly = implicitSetup;
-    }
-
-    /**
-     * @deprecated Use {@link #setupWithViewPager(ViewPager)} to link a TabLayout with a ViewPager
-     *             together. When that method is used, the TabLayout will be automatically updated
-     *             when the {@link PagerAdapter} is changed.
-     */
-    @Deprecated
-    public void setTabsFromPagerAdapter(@Nullable final PagerAdapter adapter) {
-        setPagerAdapter(adapter, false);
-    }
-
-    @Override
-    public boolean shouldDelayChildPressedState() {
-        // Only delay the pressed state if the tabs can scroll
-        return getTabScrollRange() > 0;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        if (mViewPager == null) {
-            // If we don't have a ViewPager already, check if our parent is a ViewPager to
-            // setup with it automatically
-            final ViewParent vp = getParent();
-            if (vp instanceof ViewPager) {
-                // If we have a ViewPager parent and we've been added as part of its decor, let's
-                // assume that we should automatically setup to display any titles
-                setupWithViewPager((ViewPager) vp, true, true);
-            }
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        if (mSetupViewPagerImplicitly) {
-            // If we've been setup with a ViewPager implicitly, let's clear out any listeners, etc
-            setupWithViewPager(null);
-            mSetupViewPagerImplicitly = false;
-        }
-    }
-
-    private int getTabScrollRange() {
-        return Math.max(0, mTabStrip.getWidth() - getWidth() - getPaddingLeft()
-                - getPaddingRight());
-    }
-
-    void setPagerAdapter(@Nullable final PagerAdapter adapter, final boolean addObserver) {
-        if (mPagerAdapter != null && mPagerAdapterObserver != null) {
-            // If we already have a PagerAdapter, unregister our observer
-            mPagerAdapter.unregisterDataSetObserver(mPagerAdapterObserver);
-        }
-
-        mPagerAdapter = adapter;
-
-        if (addObserver && adapter != null) {
-            // Register our observer on the new adapter
-            if (mPagerAdapterObserver == null) {
-                mPagerAdapterObserver = new PagerAdapterObserver();
-            }
-            adapter.registerDataSetObserver(mPagerAdapterObserver);
-        }
-
-        // Finally make sure we reflect the new adapter
-        populateFromPagerAdapter();
-    }
-
-    void populateFromPagerAdapter() {
-        removeAllTabs();
-
-        if (mPagerAdapter != null) {
-            final int adapterCount = mPagerAdapter.getCount();
-            for (int i = 0; i < adapterCount; i++) {
-                addTab(newTab().setText(mPagerAdapter.getPageTitle(i)), false);
-            }
-
-            // Make sure we reflect the currently set ViewPager item
-            if (mViewPager != null && adapterCount > 0) {
-                final int curItem = mViewPager.getCurrentItem();
-                if (curItem != getSelectedTabPosition() && curItem < getTabCount()) {
-                    selectTab(getTabAt(curItem));
-                }
-            }
-        }
-    }
-
-    private void updateAllTabs() {
-        for (int i = 0, z = mTabs.size(); i < z; i++) {
-            mTabs.get(i).updateView();
-        }
-    }
-
-    private TabView createTabView(@NonNull final Tab tab) {
-        TabView tabView = mTabViewPool != null ? mTabViewPool.acquire() : null;
-        if (tabView == null) {
-            tabView = new TabView(getContext());
-        }
-        tabView.setTab(tab);
-        tabView.setFocusable(true);
-        tabView.setMinimumWidth(getTabMinWidth());
-        return tabView;
-    }
-
-    private void configureTab(Tab tab, int position) {
-        tab.setPosition(position);
-        mTabs.add(position, tab);
-
-        final int count = mTabs.size();
-        for (int i = position + 1; i < count; i++) {
-            mTabs.get(i).setPosition(i);
-        }
-    }
-
-    private void addTabView(Tab tab) {
-        final TabView tabView = tab.mView;
-        mTabStrip.addView(tabView, tab.getPosition(), createLayoutParamsForTabs());
-    }
-
-    @Override
-    public void addView(View child) {
-        addViewInternal(child);
-    }
-
-    @Override
-    public void addView(View child, int index) {
-        addViewInternal(child);
-    }
-
-    @Override
-    public void addView(View child, ViewGroup.LayoutParams params) {
-        addViewInternal(child);
-    }
-
-    @Override
-    public void addView(View child, int index, ViewGroup.LayoutParams params) {
-        addViewInternal(child);
-    }
-
-    private void addViewInternal(final View child) {
-        if (child instanceof TabItem) {
-            addTabFromItemView((TabItem) child);
-        } else {
-            throw new IllegalArgumentException("Only TabItem instances can be added to TabLayout");
-        }
-    }
-
-    private LinearLayout.LayoutParams createLayoutParamsForTabs() {
-        final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
-                LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
-        updateTabViewLayoutParams(lp);
-        return lp;
-    }
-
-    private void updateTabViewLayoutParams(LinearLayout.LayoutParams lp) {
-        if (mMode == MODE_FIXED && mTabGravity == GRAVITY_FILL) {
-            lp.width = 0;
-            lp.weight = 1;
-        } else {
-            lp.width = LinearLayout.LayoutParams.WRAP_CONTENT;
-            lp.weight = 0;
-        }
-    }
-
-    int dpToPx(int dps) {
-        return Math.round(getResources().getDisplayMetrics().density * dps);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // If we have a MeasureSpec which allows us to decide our height, try and use the default
-        // height
-        final int idealHeight = dpToPx(getDefaultHeight()) + getPaddingTop() + getPaddingBottom();
-        switch (MeasureSpec.getMode(heightMeasureSpec)) {
-            case MeasureSpec.AT_MOST:
-                heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        Math.min(idealHeight, MeasureSpec.getSize(heightMeasureSpec)),
-                        MeasureSpec.EXACTLY);
-                break;
-            case MeasureSpec.UNSPECIFIED:
-                heightMeasureSpec = MeasureSpec.makeMeasureSpec(idealHeight, MeasureSpec.EXACTLY);
-                break;
-        }
-
-        final int specWidth = MeasureSpec.getSize(widthMeasureSpec);
-        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
-            // If we don't have an unspecified width spec, use the given size to calculate
-            // the max tab width
-            mTabMaxWidth = mRequestedTabMaxWidth > 0
-                    ? mRequestedTabMaxWidth
-                    : specWidth - dpToPx(TAB_MIN_WIDTH_MARGIN);
-        }
-
-        // Now super measure itself using the (possibly) modified height spec
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        if (getChildCount() == 1) {
-            // If we're in fixed mode then we need to make the tab strip is the same width as us
-            // so we don't scroll
-            final View child = getChildAt(0);
-            boolean remeasure = false;
-
-            switch (mMode) {
-                case MODE_SCROLLABLE:
-                    // We only need to resize the child if it's smaller than us. This is similar
-                    // to fillViewport
-                    remeasure = child.getMeasuredWidth() < getMeasuredWidth();
-                    break;
-                case MODE_FIXED:
-                    // Resize the child so that it doesn't scroll
-                    remeasure = child.getMeasuredWidth() != getMeasuredWidth();
-                    break;
-            }
-
-            if (remeasure) {
-                // Re-measure the child with a widthSpec set to be exactly our measure width
-                int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTop()
-                        + getPaddingBottom(), child.getLayoutParams().height);
-                int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        getMeasuredWidth(), MeasureSpec.EXACTLY);
-                child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-            }
-        }
-    }
-
-    private void removeTabViewAt(int position) {
-        final TabView view = (TabView) mTabStrip.getChildAt(position);
-        mTabStrip.removeViewAt(position);
-        if (view != null) {
-            view.reset();
-            mTabViewPool.release(view);
-        }
-        requestLayout();
-    }
-
-    private void animateToTab(int newPosition) {
-        if (newPosition == Tab.INVALID_POSITION) {
-            return;
-        }
-
-        if (getWindowToken() == null || !ViewCompat.isLaidOut(this)
-                || mTabStrip.childrenNeedLayout()) {
-            // If we don't have a window token, or we haven't been laid out yet just draw the new
-            // position now
-            setScrollPosition(newPosition, 0f, true);
-            return;
-        }
-
-        final int startScrollX = getScrollX();
-        final int targetScrollX = calculateScrollXForTab(newPosition, 0);
-
-        if (startScrollX != targetScrollX) {
-            ensureScrollAnimator();
-
-            mScrollAnimator.setIntValues(startScrollX, targetScrollX);
-            mScrollAnimator.start();
-        }
-
-        // Now animate the indicator
-        mTabStrip.animateIndicatorToPosition(newPosition, ANIMATION_DURATION);
-    }
-
-    private void ensureScrollAnimator() {
-        if (mScrollAnimator == null) {
-            mScrollAnimator = new ValueAnimator();
-            mScrollAnimator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
-            mScrollAnimator.setDuration(ANIMATION_DURATION);
-            mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animator) {
-                    scrollTo((int) animator.getAnimatedValue(), 0);
-                }
-            });
-        }
-    }
-
-    void setScrollAnimatorListener(Animator.AnimatorListener listener) {
-        ensureScrollAnimator();
-        mScrollAnimator.addListener(listener);
-    }
-
-    private void setSelectedTabView(int position) {
-        final int tabCount = mTabStrip.getChildCount();
-        if (position < tabCount) {
-            for (int i = 0; i < tabCount; i++) {
-                final View child = mTabStrip.getChildAt(i);
-                child.setSelected(i == position);
-            }
-        }
-    }
-
-    void selectTab(Tab tab) {
-        selectTab(tab, true);
-    }
-
-    void selectTab(final Tab tab, boolean updateIndicator) {
-        final Tab currentTab = mSelectedTab;
-
-        if (currentTab == tab) {
-            if (currentTab != null) {
-                dispatchTabReselected(tab);
-                animateToTab(tab.getPosition());
-            }
-        } else {
-            final int newPosition = tab != null ? tab.getPosition() : Tab.INVALID_POSITION;
-            if (updateIndicator) {
-                if ((currentTab == null || currentTab.getPosition() == Tab.INVALID_POSITION)
-                        && newPosition != Tab.INVALID_POSITION) {
-                    // If we don't currently have a tab, just draw the indicator
-                    setScrollPosition(newPosition, 0f, true);
-                } else {
-                    animateToTab(newPosition);
-                }
-                if (newPosition != Tab.INVALID_POSITION) {
-                    setSelectedTabView(newPosition);
-                }
-            }
-            if (currentTab != null) {
-                dispatchTabUnselected(currentTab);
-            }
-            mSelectedTab = tab;
-            if (tab != null) {
-                dispatchTabSelected(tab);
-            }
-        }
-    }
-
-    private void dispatchTabSelected(@NonNull final Tab tab) {
-        for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {
-            mSelectedListeners.get(i).onTabSelected(tab);
-        }
-    }
-
-    private void dispatchTabUnselected(@NonNull final Tab tab) {
-        for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {
-            mSelectedListeners.get(i).onTabUnselected(tab);
-        }
-    }
-
-    private void dispatchTabReselected(@NonNull final Tab tab) {
-        for (int i = mSelectedListeners.size() - 1; i >= 0; i--) {
-            mSelectedListeners.get(i).onTabReselected(tab);
-        }
-    }
-
-    private int calculateScrollXForTab(int position, float positionOffset) {
-        if (mMode == MODE_SCROLLABLE) {
-            final View selectedChild = mTabStrip.getChildAt(position);
-            final View nextChild = position + 1 < mTabStrip.getChildCount()
-                    ? mTabStrip.getChildAt(position + 1)
-                    : null;
-            final int selectedWidth = selectedChild != null ? selectedChild.getWidth() : 0;
-            final int nextWidth = nextChild != null ? nextChild.getWidth() : 0;
-
-            // base scroll amount: places center of tab in center of parent
-            int scrollBase = selectedChild.getLeft() + (selectedWidth / 2) - (getWidth() / 2);
-            // offset amount: fraction of the distance between centers of tabs
-            int scrollOffset = (int) ((selectedWidth + nextWidth) * 0.5f * positionOffset);
-
-            return (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_LTR)
-                    ? scrollBase + scrollOffset
-                    : scrollBase - scrollOffset;
-        }
-        return 0;
-    }
-
-    private void applyModeAndGravity() {
-        int paddingStart = 0;
-        if (mMode == MODE_SCROLLABLE) {
-            // If we're scrollable, or fixed at start, inset using padding
-            paddingStart = Math.max(0, mContentInsetStart - mTabPaddingStart);
-        }
-        ViewCompat.setPaddingRelative(mTabStrip, paddingStart, 0, 0, 0);
-
-        switch (mMode) {
-            case MODE_FIXED:
-                mTabStrip.setGravity(Gravity.CENTER_HORIZONTAL);
-                break;
-            case MODE_SCROLLABLE:
-                mTabStrip.setGravity(GravityCompat.START);
-                break;
-        }
-
-        updateTabViews(true);
-    }
-
-    void updateTabViews(final boolean requestLayout) {
-        for (int i = 0; i < mTabStrip.getChildCount(); i++) {
-            View child = mTabStrip.getChildAt(i);
-            child.setMinimumWidth(getTabMinWidth());
-            updateTabViewLayoutParams((LinearLayout.LayoutParams) child.getLayoutParams());
-            if (requestLayout) {
-                child.requestLayout();
-            }
-        }
-    }
-
-    /**
-     * A tab in this layout. Instances can be created via {@link #newTab()}.
-     */
-    public static final class Tab {
-
-        /**
-         * An invalid position for a tab.
-         *
-         * @see #getPosition()
-         */
-        public static final int INVALID_POSITION = -1;
-
-        private Object mTag;
-        private Drawable mIcon;
-        private CharSequence mText;
-        private CharSequence mContentDesc;
-        private int mPosition = INVALID_POSITION;
-        private View mCustomView;
-
-        TabLayout mParent;
-        TabView mView;
-
-        Tab() {
-            // Private constructor
-        }
-
-        /**
-         * @return This Tab's tag object.
-         */
-        @Nullable
-        public Object getTag() {
-            return mTag;
-        }
-
-        /**
-         * Give this Tab an arbitrary object to hold for later use.
-         *
-         * @param tag Object to store
-         * @return The current instance for call chaining
-         */
-        @NonNull
-        public Tab setTag(@Nullable Object tag) {
-            mTag = tag;
-            return this;
-        }
-
-
-        /**
-         * Returns the custom view used for this tab.
-         *
-         * @see #setCustomView(View)
-         * @see #setCustomView(int)
-         */
-        @Nullable
-        public View getCustomView() {
-            return mCustomView;
-        }
-
-        /**
-         * Set a custom view to be used for this tab.
-         * <p>
-         * If the provided view contains a {@link TextView} with an ID of
-         * {@link android.R.id#text1} then that will be updated with the value given
-         * to {@link #setText(CharSequence)}. Similarly, if this layout contains an
-         * {@link ImageView} with ID {@link android.R.id#icon} then it will be updated with
-         * the value given to {@link #setIcon(Drawable)}.
-         * </p>
-         *
-         * @param view Custom view to be used as a tab.
-         * @return The current instance for call chaining
-         */
-        @NonNull
-        public Tab setCustomView(@Nullable View view) {
-            mCustomView = view;
-            updateView();
-            return this;
-        }
-
-        /**
-         * Set a custom view to be used for this tab.
-         * <p>
-         * If the inflated layout contains a {@link TextView} with an ID of
-         * {@link android.R.id#text1} then that will be updated with the value given
-         * to {@link #setText(CharSequence)}. Similarly, if this layout contains an
-         * {@link ImageView} with ID {@link android.R.id#icon} then it will be updated with
-         * the value given to {@link #setIcon(Drawable)}.
-         * </p>
-         *
-         * @param resId A layout resource to inflate and use as a custom tab view
-         * @return The current instance for call chaining
-         */
-        @NonNull
-        public Tab setCustomView(@LayoutRes int resId) {
-            final LayoutInflater inflater = LayoutInflater.from(mView.getContext());
-            return setCustomView(inflater.inflate(resId, mView, false));
-        }
-
-        /**
-         * Return the icon associated with this tab.
-         *
-         * @return The tab's icon
-         */
-        @Nullable
-        public Drawable getIcon() {
-            return mIcon;
-        }
-
-        /**
-         * Return the current position of this tab in the action bar.
-         *
-         * @return Current position, or {@link #INVALID_POSITION} if this tab is not currently in
-         * the action bar.
-         */
-        public int getPosition() {
-            return mPosition;
-        }
-
-        void setPosition(int position) {
-            mPosition = position;
-        }
-
-        /**
-         * Return the text of this tab.
-         *
-         * @return The tab's text
-         */
-        @Nullable
-        public CharSequence getText() {
-            return mText;
-        }
-
-        /**
-         * Set the icon displayed on this tab.
-         *
-         * @param icon The drawable to use as an icon
-         * @return The current instance for call chaining
-         */
-        @NonNull
-        public Tab setIcon(@Nullable Drawable icon) {
-            mIcon = icon;
-            updateView();
-            return this;
-        }
-
-        /**
-         * Set the icon displayed on this tab.
-         *
-         * @param resId A resource ID referring to the icon that should be displayed
-         * @return The current instance for call chaining
-         */
-        @NonNull
-        public Tab setIcon(@DrawableRes int resId) {
-            if (mParent == null) {
-                throw new IllegalArgumentException("Tab not attached to a TabLayout");
-            }
-            return setIcon(AppCompatResources.getDrawable(mParent.getContext(), resId));
-        }
-
-        /**
-         * Set the text displayed on this tab. Text may be truncated if there is not room to display
-         * the entire string.
-         *
-         * @param text The text to display
-         * @return The current instance for call chaining
-         */
-        @NonNull
-        public Tab setText(@Nullable CharSequence text) {
-            mText = text;
-            updateView();
-            return this;
-        }
-
-        /**
-         * Set the text displayed on this tab. Text may be truncated if there is not room to display
-         * the entire string.
-         *
-         * @param resId A resource ID referring to the text that should be displayed
-         * @return The current instance for call chaining
-         */
-        @NonNull
-        public Tab setText(@StringRes int resId) {
-            if (mParent == null) {
-                throw new IllegalArgumentException("Tab not attached to a TabLayout");
-            }
-            return setText(mParent.getResources().getText(resId));
-        }
-
-        /**
-         * Select this tab. Only valid if the tab has been added to the action bar.
-         */
-        public void select() {
-            if (mParent == null) {
-                throw new IllegalArgumentException("Tab not attached to a TabLayout");
-            }
-            mParent.selectTab(this);
-        }
-
-        /**
-         * Returns true if this tab is currently selected.
-         */
-        public boolean isSelected() {
-            if (mParent == null) {
-                throw new IllegalArgumentException("Tab not attached to a TabLayout");
-            }
-            return mParent.getSelectedTabPosition() == mPosition;
-        }
-
-        /**
-         * Set a description of this tab's content for use in accessibility support. If no content
-         * description is provided the title will be used.
-         *
-         * @param resId A resource ID referring to the description text
-         * @return The current instance for call chaining
-         * @see #setContentDescription(CharSequence)
-         * @see #getContentDescription()
-         */
-        @NonNull
-        public Tab setContentDescription(@StringRes int resId) {
-            if (mParent == null) {
-                throw new IllegalArgumentException("Tab not attached to a TabLayout");
-            }
-            return setContentDescription(mParent.getResources().getText(resId));
-        }
-
-        /**
-         * Set a description of this tab's content for use in accessibility support. If no content
-         * description is provided the title will be used.
-         *
-         * @param contentDesc Description of this tab's content
-         * @return The current instance for call chaining
-         * @see #setContentDescription(int)
-         * @see #getContentDescription()
-         */
-        @NonNull
-        public Tab setContentDescription(@Nullable CharSequence contentDesc) {
-            mContentDesc = contentDesc;
-            updateView();
-            return this;
-        }
-
-        /**
-         * Gets a brief description of this tab's content for use in accessibility support.
-         *
-         * @return Description of this tab's content
-         * @see #setContentDescription(CharSequence)
-         * @see #setContentDescription(int)
-         */
-        @Nullable
-        public CharSequence getContentDescription() {
-            return mContentDesc;
-        }
-
-        void updateView() {
-            if (mView != null) {
-                mView.update();
-            }
-        }
-
-        void reset() {
-            mParent = null;
-            mView = null;
-            mTag = null;
-            mIcon = null;
-            mText = null;
-            mContentDesc = null;
-            mPosition = INVALID_POSITION;
-            mCustomView = null;
-        }
-    }
-
-    class TabView extends LinearLayout {
-        private Tab mTab;
-        private TextView mTextView;
-        private ImageView mIconView;
-
-        private View mCustomView;
-        private TextView mCustomTextView;
-        private ImageView mCustomIconView;
-
-        private int mDefaultMaxLines = 2;
-
-        public TabView(Context context) {
-            super(context);
-            if (mTabBackgroundResId != 0) {
-                ViewCompat.setBackground(
-                        this, AppCompatResources.getDrawable(context, mTabBackgroundResId));
-            }
-            ViewCompat.setPaddingRelative(this, mTabPaddingStart, mTabPaddingTop,
-                    mTabPaddingEnd, mTabPaddingBottom);
-            setGravity(Gravity.CENTER);
-            setOrientation(VERTICAL);
-            setClickable(true);
-            ViewCompat.setPointerIcon(this,
-                    PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));
-        }
-
-        @Override
-        public boolean performClick() {
-            final boolean handled = super.performClick();
-
-            if (mTab != null) {
-                if (!handled) {
-                    playSoundEffect(SoundEffectConstants.CLICK);
-                }
-                mTab.select();
-                return true;
-            } else {
-                return handled;
-            }
-        }
-
-        @Override
-        public void setSelected(final boolean selected) {
-            final boolean changed = isSelected() != selected;
-
-            super.setSelected(selected);
-
-            if (changed && selected && Build.VERSION.SDK_INT < 16) {
-                // Pre-JB we need to manually send the TYPE_VIEW_SELECTED event
-                sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-            }
-
-            // Always dispatch this to the child views, regardless of whether the value has
-            // changed
-            if (mTextView != null) {
-                mTextView.setSelected(selected);
-            }
-            if (mIconView != null) {
-                mIconView.setSelected(selected);
-            }
-            if (mCustomView != null) {
-                mCustomView.setSelected(selected);
-            }
-        }
-
-        @Override
-        public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
-            super.onInitializeAccessibilityEvent(event);
-            // This view masquerades as an action bar tab.
-            event.setClassName(ActionBar.Tab.class.getName());
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(info);
-            // This view masquerades as an action bar tab.
-            info.setClassName(ActionBar.Tab.class.getName());
-        }
-
-        @Override
-        public void onMeasure(final int origWidthMeasureSpec, final int origHeightMeasureSpec) {
-            final int specWidthSize = MeasureSpec.getSize(origWidthMeasureSpec);
-            final int specWidthMode = MeasureSpec.getMode(origWidthMeasureSpec);
-            final int maxWidth = getTabMaxWidth();
-
-            final int widthMeasureSpec;
-            final int heightMeasureSpec = origHeightMeasureSpec;
-
-            if (maxWidth > 0 && (specWidthMode == MeasureSpec.UNSPECIFIED
-                    || specWidthSize > maxWidth)) {
-                // If we have a max width and a given spec which is either unspecified or
-                // larger than the max width, update the width spec using the same mode
-                widthMeasureSpec = MeasureSpec.makeMeasureSpec(mTabMaxWidth, MeasureSpec.AT_MOST);
-            } else {
-                // Else, use the original width spec
-                widthMeasureSpec = origWidthMeasureSpec;
-            }
-
-            // Now lets measure
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-            // We need to switch the text size based on whether the text is spanning 2 lines or not
-            if (mTextView != null) {
-                final Resources res = getResources();
-                float textSize = mTabTextSize;
-                int maxLines = mDefaultMaxLines;
-
-                if (mIconView != null && mIconView.getVisibility() == VISIBLE) {
-                    // If the icon view is being displayed, we limit the text to 1 line
-                    maxLines = 1;
-                } else if (mTextView != null && mTextView.getLineCount() > 1) {
-                    // Otherwise when we have text which wraps we reduce the text size
-                    textSize = mTabTextMultiLineSize;
-                }
-
-                final float curTextSize = mTextView.getTextSize();
-                final int curLineCount = mTextView.getLineCount();
-                final int curMaxLines = TextViewCompat.getMaxLines(mTextView);
-
-                if (textSize != curTextSize || (curMaxLines >= 0 && maxLines != curMaxLines)) {
-                    // We've got a new text size and/or max lines...
-                    boolean updateTextView = true;
-
-                    if (mMode == MODE_FIXED && textSize > curTextSize && curLineCount == 1) {
-                        // If we're in fixed mode, going up in text size and currently have 1 line
-                        // then it's very easy to get into an infinite recursion.
-                        // To combat that we check to see if the change in text size
-                        // will cause a line count change. If so, abort the size change and stick
-                        // to the smaller size.
-                        final Layout layout = mTextView.getLayout();
-                        if (layout == null || approximateLineWidth(layout, 0, textSize)
-                                > getMeasuredWidth() - getPaddingLeft() - getPaddingRight()) {
-                            updateTextView = false;
-                        }
-                    }
-
-                    if (updateTextView) {
-                        mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
-                        mTextView.setMaxLines(maxLines);
-                        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-                    }
-                }
-            }
-        }
-
-        void setTab(@Nullable final Tab tab) {
-            if (tab != mTab) {
-                mTab = tab;
-                update();
-            }
-        }
-
-        void reset() {
-            setTab(null);
-            setSelected(false);
-        }
-
-        final void update() {
-            final Tab tab = mTab;
-            final View custom = tab != null ? tab.getCustomView() : null;
-            if (custom != null) {
-                final ViewParent customParent = custom.getParent();
-                if (customParent != this) {
-                    if (customParent != null) {
-                        ((ViewGroup) customParent).removeView(custom);
-                    }
-                    addView(custom);
-                }
-                mCustomView = custom;
-                if (mTextView != null) {
-                    mTextView.setVisibility(GONE);
-                }
-                if (mIconView != null) {
-                    mIconView.setVisibility(GONE);
-                    mIconView.setImageDrawable(null);
-                }
-
-                mCustomTextView = (TextView) custom.findViewById(android.R.id.text1);
-                if (mCustomTextView != null) {
-                    mDefaultMaxLines = TextViewCompat.getMaxLines(mCustomTextView);
-                }
-                mCustomIconView = (ImageView) custom.findViewById(android.R.id.icon);
-            } else {
-                // We do not have a custom view. Remove one if it already exists
-                if (mCustomView != null) {
-                    removeView(mCustomView);
-                    mCustomView = null;
-                }
-                mCustomTextView = null;
-                mCustomIconView = null;
-            }
-
-            if (mCustomView == null) {
-                // If there isn't a custom view, we'll us our own in-built layouts
-                if (mIconView == null) {
-                    ImageView iconView = (ImageView) LayoutInflater.from(getContext())
-                            .inflate(R.layout.design_layout_tab_icon, this, false);
-                    addView(iconView, 0);
-                    mIconView = iconView;
-                }
-                if (mTextView == null) {
-                    TextView textView = (TextView) LayoutInflater.from(getContext())
-                            .inflate(R.layout.design_layout_tab_text, this, false);
-                    addView(textView);
-                    mTextView = textView;
-                    mDefaultMaxLines = TextViewCompat.getMaxLines(mTextView);
-                }
-                TextViewCompat.setTextAppearance(mTextView, mTabTextAppearance);
-                if (mTabTextColors != null) {
-                    mTextView.setTextColor(mTabTextColors);
-                }
-                updateTextAndIcon(mTextView, mIconView);
-            } else {
-                // Else, we'll see if there is a TextView or ImageView present and update them
-                if (mCustomTextView != null || mCustomIconView != null) {
-                    updateTextAndIcon(mCustomTextView, mCustomIconView);
-                }
-            }
-
-            // Finally update our selected state
-            setSelected(tab != null && tab.isSelected());
-        }
-
-        private void updateTextAndIcon(@Nullable final TextView textView,
-                @Nullable final ImageView iconView) {
-            final Drawable icon = mTab != null ? mTab.getIcon() : null;
-            final CharSequence text = mTab != null ? mTab.getText() : null;
-            final CharSequence contentDesc = mTab != null ? mTab.getContentDescription() : null;
-
-            if (iconView != null) {
-                if (icon != null) {
-                    iconView.setImageDrawable(icon);
-                    iconView.setVisibility(VISIBLE);
-                    setVisibility(VISIBLE);
-                } else {
-                    iconView.setVisibility(GONE);
-                    iconView.setImageDrawable(null);
-                }
-                iconView.setContentDescription(contentDesc);
-            }
-
-            final boolean hasText = !TextUtils.isEmpty(text);
-            if (textView != null) {
-                if (hasText) {
-                    textView.setText(text);
-                    textView.setVisibility(VISIBLE);
-                    setVisibility(VISIBLE);
-                } else {
-                    textView.setVisibility(GONE);
-                    textView.setText(null);
-                }
-                textView.setContentDescription(contentDesc);
-            }
-
-            if (iconView != null) {
-                MarginLayoutParams lp = ((MarginLayoutParams) iconView.getLayoutParams());
-                int bottomMargin = 0;
-                if (hasText && iconView.getVisibility() == VISIBLE) {
-                    // If we're showing both text and icon, add some margin bottom to the icon
-                    bottomMargin = dpToPx(DEFAULT_GAP_TEXT_ICON);
-                }
-                if (bottomMargin != lp.bottomMargin) {
-                    lp.bottomMargin = bottomMargin;
-                    iconView.requestLayout();
-                }
-            }
-            TooltipCompat.setTooltipText(this, hasText ? null : contentDesc);
-        }
-
-        public Tab getTab() {
-            return mTab;
-        }
-
-        /**
-         * Approximates a given lines width with the new provided text size.
-         */
-        private float approximateLineWidth(Layout layout, int line, float textSize) {
-            return layout.getLineWidth(line) * (textSize / layout.getPaint().getTextSize());
-        }
-    }
-
-    private class SlidingTabStrip extends LinearLayout {
-        private int mSelectedIndicatorHeight;
-        private final Paint mSelectedIndicatorPaint;
-
-        int mSelectedPosition = -1;
-        float mSelectionOffset;
-
-        private int mLayoutDirection = -1;
-
-        private int mIndicatorLeft = -1;
-        private int mIndicatorRight = -1;
-
-        private ValueAnimator mIndicatorAnimator;
-
-        SlidingTabStrip(Context context) {
-            super(context);
-            setWillNotDraw(false);
-            mSelectedIndicatorPaint = new Paint();
-        }
-
-        void setSelectedIndicatorColor(int color) {
-            if (mSelectedIndicatorPaint.getColor() != color) {
-                mSelectedIndicatorPaint.setColor(color);
-                ViewCompat.postInvalidateOnAnimation(this);
-            }
-        }
-
-        void setSelectedIndicatorHeight(int height) {
-            if (mSelectedIndicatorHeight != height) {
-                mSelectedIndicatorHeight = height;
-                ViewCompat.postInvalidateOnAnimation(this);
-            }
-        }
-
-        boolean childrenNeedLayout() {
-            for (int i = 0, z = getChildCount(); i < z; i++) {
-                final View child = getChildAt(i);
-                if (child.getWidth() <= 0) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        void setIndicatorPositionFromTabPosition(int position, float positionOffset) {
-            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
-                mIndicatorAnimator.cancel();
-            }
-
-            mSelectedPosition = position;
-            mSelectionOffset = positionOffset;
-            updateIndicatorPosition();
-        }
-
-        float getIndicatorPosition() {
-            return mSelectedPosition + mSelectionOffset;
-        }
-
-        @Override
-        public void onRtlPropertiesChanged(int layoutDirection) {
-            super.onRtlPropertiesChanged(layoutDirection);
-
-            // Workaround for a bug before Android M where LinearLayout did not relayout itself when
-            // layout direction changed.
-            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
-                //noinspection WrongConstant
-                if (mLayoutDirection != layoutDirection) {
-                    requestLayout();
-                    mLayoutDirection = layoutDirection;
-                }
-            }
-        }
-
-        @Override
-        protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-            if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) {
-                // HorizontalScrollView will first measure use with UNSPECIFIED, and then with
-                // EXACTLY. Ignore the first call since anything we do will be overwritten anyway
-                return;
-            }
-
-            if (mMode == MODE_FIXED && mTabGravity == GRAVITY_CENTER) {
-                final int count = getChildCount();
-
-                // First we'll find the widest tab
-                int largestTabWidth = 0;
-                for (int i = 0, z = count; i < z; i++) {
-                    View child = getChildAt(i);
-                    if (child.getVisibility() == VISIBLE) {
-                        largestTabWidth = Math.max(largestTabWidth, child.getMeasuredWidth());
-                    }
-                }
-
-                if (largestTabWidth <= 0) {
-                    // If we don't have a largest child yet, skip until the next measure pass
-                    return;
-                }
-
-                final int gutter = dpToPx(FIXED_WRAP_GUTTER_MIN);
-                boolean remeasure = false;
-
-                if (largestTabWidth * count <= getMeasuredWidth() - gutter * 2) {
-                    // If the tabs fit within our width minus gutters, we will set all tabs to have
-                    // the same width
-                    for (int i = 0; i < count; i++) {
-                        final LinearLayout.LayoutParams lp =
-                                (LayoutParams) getChildAt(i).getLayoutParams();
-                        if (lp.width != largestTabWidth || lp.weight != 0) {
-                            lp.width = largestTabWidth;
-                            lp.weight = 0;
-                            remeasure = true;
-                        }
-                    }
-                } else {
-                    // If the tabs will wrap to be larger than the width minus gutters, we need
-                    // to switch to GRAVITY_FILL
-                    mTabGravity = GRAVITY_FILL;
-                    updateTabViews(false);
-                    remeasure = true;
-                }
-
-                if (remeasure) {
-                    // Now re-measure after our changes
-                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-                }
-            }
-        }
-
-        @Override
-        protected void onLayout(boolean changed, int l, int t, int r, int b) {
-            super.onLayout(changed, l, t, r, b);
-
-            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
-                // If we're currently running an animation, lets cancel it and start a
-                // new animation with the remaining duration
-                mIndicatorAnimator.cancel();
-                final long duration = mIndicatorAnimator.getDuration();
-                animateIndicatorToPosition(mSelectedPosition,
-                        Math.round((1f - mIndicatorAnimator.getAnimatedFraction()) * duration));
-            } else {
-                // If we've been layed out, update the indicator position
-                updateIndicatorPosition();
-            }
-        }
-
-        private void updateIndicatorPosition() {
-            final View selectedTitle = getChildAt(mSelectedPosition);
-            int left, right;
-
-            if (selectedTitle != null && selectedTitle.getWidth() > 0) {
-                left = selectedTitle.getLeft();
-                right = selectedTitle.getRight();
-
-                if (mSelectionOffset > 0f && mSelectedPosition < getChildCount() - 1) {
-                    // Draw the selection partway between the tabs
-                    View nextTitle = getChildAt(mSelectedPosition + 1);
-                    left = (int) (mSelectionOffset * nextTitle.getLeft() +
-                            (1.0f - mSelectionOffset) * left);
-                    right = (int) (mSelectionOffset * nextTitle.getRight() +
-                            (1.0f - mSelectionOffset) * right);
-                }
-            } else {
-                left = right = -1;
-            }
-
-            setIndicatorPosition(left, right);
-        }
-
-        void setIndicatorPosition(int left, int right) {
-            if (left != mIndicatorLeft || right != mIndicatorRight) {
-                // If the indicator's left/right has changed, invalidate
-                mIndicatorLeft = left;
-                mIndicatorRight = right;
-                ViewCompat.postInvalidateOnAnimation(this);
-            }
-        }
-
-        void animateIndicatorToPosition(final int position, int duration) {
-            if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) {
-                mIndicatorAnimator.cancel();
-            }
-
-            final boolean isRtl = ViewCompat.getLayoutDirection(this)
-                    == ViewCompat.LAYOUT_DIRECTION_RTL;
-
-            final View targetView = getChildAt(position);
-            if (targetView == null) {
-                // If we don't have a view, just update the position now and return
-                updateIndicatorPosition();
-                return;
-            }
-
-            final int targetLeft = targetView.getLeft();
-            final int targetRight = targetView.getRight();
-            final int startLeft;
-            final int startRight;
-
-            if (Math.abs(position - mSelectedPosition) <= 1) {
-                // If the views are adjacent, we'll animate from edge-to-edge
-                startLeft = mIndicatorLeft;
-                startRight = mIndicatorRight;
-            } else {
-                // Else, we'll just grow from the nearest edge
-                final int offset = dpToPx(MOTION_NON_ADJACENT_OFFSET);
-                if (position < mSelectedPosition) {
-                    // We're going end-to-start
-                    if (isRtl) {
-                        startLeft = startRight = targetLeft - offset;
-                    } else {
-                        startLeft = startRight = targetRight + offset;
-                    }
-                } else {
-                    // We're going start-to-end
-                    if (isRtl) {
-                        startLeft = startRight = targetRight + offset;
-                    } else {
-                        startLeft = startRight = targetLeft - offset;
-                    }
-                }
-            }
-
-            if (startLeft != targetLeft || startRight != targetRight) {
-                ValueAnimator animator = mIndicatorAnimator = new ValueAnimator();
-                animator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
-                animator.setDuration(duration);
-                animator.setFloatValues(0, 1);
-                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                    @Override
-                    public void onAnimationUpdate(ValueAnimator animator) {
-                        final float fraction = animator.getAnimatedFraction();
-                        setIndicatorPosition(
-                                AnimationUtils.lerp(startLeft, targetLeft, fraction),
-                                AnimationUtils.lerp(startRight, targetRight, fraction));
-                    }
-                });
-                animator.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animator) {
-                        mSelectedPosition = position;
-                        mSelectionOffset = 0f;
-                    }
-                });
-                animator.start();
-            }
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            super.draw(canvas);
-
-            // Thick colored underline below the current selection
-            if (mIndicatorLeft >= 0 && mIndicatorRight > mIndicatorLeft) {
-                canvas.drawRect(mIndicatorLeft, getHeight() - mSelectedIndicatorHeight,
-                        mIndicatorRight, getHeight(), mSelectedIndicatorPaint);
-            }
-        }
-    }
-
-    private static ColorStateList createColorStateList(int defaultColor, int selectedColor) {
-        final int[][] states = new int[2][];
-        final int[] colors = new int[2];
-        int i = 0;
-
-        states[i] = SELECTED_STATE_SET;
-        colors[i] = selectedColor;
-        i++;
-
-        // Default enabled state
-        states[i] = EMPTY_STATE_SET;
-        colors[i] = defaultColor;
-        i++;
-
-        return new ColorStateList(states, colors);
-    }
-
-    private int getDefaultHeight() {
-        boolean hasIconAndText = false;
-        for (int i = 0, count = mTabs.size(); i < count; i++) {
-            Tab tab = mTabs.get(i);
-            if (tab != null && tab.getIcon() != null && !TextUtils.isEmpty(tab.getText())) {
-                hasIconAndText = true;
-                break;
-            }
-        }
-        return hasIconAndText ? DEFAULT_HEIGHT_WITH_TEXT_ICON : DEFAULT_HEIGHT;
-    }
-
-    private int getTabMinWidth() {
-        if (mRequestedTabMinWidth != INVALID_WIDTH) {
-            // If we have been given a min width, use it
-            return mRequestedTabMinWidth;
-        }
-        // Else, we'll use the default value
-        return mMode == MODE_SCROLLABLE ? mScrollableTabMinWidth : 0;
-    }
-
-    @Override
-    public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        // We don't care about the layout params of any views added to us, since we don't actually
-        // add them. The only view we add is the SlidingTabStrip, which is done manually.
-        // We return the default layout params so that we don't blow up if we're given a TabItem
-        // without android:layout_* values.
-        return generateDefaultLayoutParams();
-    }
-
-    int getTabMaxWidth() {
-        return mTabMaxWidth;
-    }
-
-    /**
-     * A {@link ViewPager.OnPageChangeListener} class which contains the
-     * necessary calls back to the provided {@link TabLayout} so that the tab position is
-     * kept in sync.
-     *
-     * <p>This class stores the provided TabLayout weakly, meaning that you can use
-     * {@link ViewPager#addOnPageChangeListener(ViewPager.OnPageChangeListener)
-     * addOnPageChangeListener(OnPageChangeListener)} without removing the listener and
-     * not cause a leak.
-     */
-    public static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener {
-        private final WeakReference<TabLayout> mTabLayoutRef;
-        private int mPreviousScrollState;
-        private int mScrollState;
-
-        public TabLayoutOnPageChangeListener(TabLayout tabLayout) {
-            mTabLayoutRef = new WeakReference<>(tabLayout);
-        }
-
-        @Override
-        public void onPageScrollStateChanged(final int state) {
-            mPreviousScrollState = mScrollState;
-            mScrollState = state;
-        }
-
-        @Override
-        public void onPageScrolled(final int position, final float positionOffset,
-                final int positionOffsetPixels) {
-            final TabLayout tabLayout = mTabLayoutRef.get();
-            if (tabLayout != null) {
-                // Only update the text selection if we're not settling, or we are settling after
-                // being dragged
-                final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
-                        mPreviousScrollState == SCROLL_STATE_DRAGGING;
-                // Update the indicator if we're not settling after being idle. This is caused
-                // from a setCurrentItem() call and will be handled by an animation from
-                // onPageSelected() instead.
-                final boolean updateIndicator = !(mScrollState == SCROLL_STATE_SETTLING
-                        && mPreviousScrollState == SCROLL_STATE_IDLE);
-                tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
-            }
-        }
-
-        @Override
-        public void onPageSelected(final int position) {
-            final TabLayout tabLayout = mTabLayoutRef.get();
-            if (tabLayout != null && tabLayout.getSelectedTabPosition() != position
-                    && position < tabLayout.getTabCount()) {
-                // Select the tab, only updating the indicator if we're not being dragged/settled
-                // (since onPageScrolled will handle that).
-                final boolean updateIndicator = mScrollState == SCROLL_STATE_IDLE
-                        || (mScrollState == SCROLL_STATE_SETTLING
-                        && mPreviousScrollState == SCROLL_STATE_IDLE);
-                tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
-            }
-        }
-
-        void reset() {
-            mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
-        }
-    }
-
-    /**
-     * A {@link TabLayout.OnTabSelectedListener} class which contains the necessary calls back
-     * to the provided {@link ViewPager} so that the tab position is kept in sync.
-     */
-    public static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
-        private final ViewPager mViewPager;
-
-        public ViewPagerOnTabSelectedListener(ViewPager viewPager) {
-            mViewPager = viewPager;
-        }
-
-        @Override
-        public void onTabSelected(TabLayout.Tab tab) {
-            mViewPager.setCurrentItem(tab.getPosition());
-        }
-
-        @Override
-        public void onTabUnselected(TabLayout.Tab tab) {
-            // No-op
-        }
-
-        @Override
-        public void onTabReselected(TabLayout.Tab tab) {
-            // No-op
-        }
-    }
-
-    private class PagerAdapterObserver extends DataSetObserver {
-        PagerAdapterObserver() {
-        }
-
-        @Override
-        public void onChanged() {
-            populateFromPagerAdapter();
-        }
-
-        @Override
-        public void onInvalidated() {
-            populateFromPagerAdapter();
-        }
-    }
-
-    private class AdapterChangeListener implements ViewPager.OnAdapterChangeListener {
-        private boolean mAutoRefresh;
-
-        AdapterChangeListener() {
-        }
-
-        @Override
-        public void onAdapterChanged(@NonNull ViewPager viewPager,
-                @Nullable PagerAdapter oldAdapter, @Nullable PagerAdapter newAdapter) {
-            if (mViewPager == viewPager) {
-                setPagerAdapter(newAdapter, mAutoRefresh);
-            }
-        }
-
-        void setAutoRefresh(boolean autoRefresh) {
-            mAutoRefresh = autoRefresh;
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/TextInputEditText.java b/design/src/android/support/design/widget/TextInputEditText.java
deleted file mode 100644
index ee6c32c..0000000
--- a/design/src/android/support/design/widget/TextInputEditText.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.support.v7.widget.AppCompatEditText;
-import android.support.v7.widget.WithHint;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewParent;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-
-/**
- * A special sub-class of {@link android.widget.EditText} designed for use as a child of
- * {@link TextInputLayout}.
- *
- * <p>Using this class allows us to display a hint in the IME when in 'extract' mode.</p>
- */
-public class TextInputEditText extends AppCompatEditText {
-
-    public TextInputEditText(Context context) {
-        super(context);
-    }
-
-    public TextInputEditText(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public TextInputEditText(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-        final InputConnection ic = super.onCreateInputConnection(outAttrs);
-        if (ic != null && outAttrs.hintText == null) {
-            // If we don't have a hint and our parent implements WithHint, use its hint for the
-            // EditorInfo. This allows us to display a hint in 'extract mode'.
-            ViewParent parent = getParent();
-            while (parent instanceof View) {
-                if (parent instanceof WithHint) {
-                    outAttrs.hintText = ((WithHint) parent).getHint();
-                    break;
-                }
-                parent = parent.getParent();
-            }
-        }
-        return ic;
-    }
-}
diff --git a/design/src/android/support/design/widget/TextInputLayout.java b/design/src/android/support/design/widget/TextInputLayout.java
deleted file mode 100644
index 0540678..0000000
--- a/design/src/android/support/design/widget/TextInputLayout.java
+++ /dev/null
@@ -1,1530 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.ColorStateList;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.DrawableContainer;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.StringRes;
-import android.support.annotation.StyleRes;
-import android.support.annotation.VisibleForTesting;
-import android.support.design.R;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.AbsSavedState;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v4.widget.Space;
-import android.support.v4.widget.TextViewCompat;
-import android.support.v4.widget.ViewGroupUtils;
-import android.support.v7.content.res.AppCompatResources;
-import android.support.v7.widget.AppCompatDrawableManager;
-import android.support.v7.widget.AppCompatTextView;
-import android.support.v7.widget.TintTypedArray;
-import android.support.v7.widget.WithHint;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.text.method.PasswordTransformationMethod;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStructure;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AccelerateInterpolator;
-import android.widget.EditText;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-/**
- * Layout which wraps an {@link android.widget.EditText} (or descendant) to show a floating label
- * when the hint is hidden due to the user inputting text.
- *
- * <p>Also supports showing an error via {@link #setErrorEnabled(boolean)} and
- * {@link #setError(CharSequence)}, and a character counter via
- * {@link #setCounterEnabled(boolean)}.</p>
- *
- * <p>Password visibility toggling is also supported via the
- * {@link #setPasswordVisibilityToggleEnabled(boolean)} API and related attribute.
- * If enabled, a button is displayed to toggle between the password being displayed as plain-text
- * or disguised, when your EditText is set to display a password.</p>
- *
- * <p><strong>Note:</strong> When using the password toggle functionality, the 'end' compound
- * drawable of the EditText will be overridden while the toggle is enabled. To ensure that any
- * existing drawables are restored correctly, you should set those compound drawables relatively
- * (start/end), opposed to absolutely (left/right).</p>
- *
- * The {@link TextInputEditText} class is provided to be used as a child of this layout. Using
- * TextInputEditText allows TextInputLayout greater control over the visual aspects of any
- * text input. An example usage is as so:
- *
- * <pre>
- * &lt;android.support.design.widget.TextInputLayout
- *         android:layout_width=&quot;match_parent&quot;
- *         android:layout_height=&quot;wrap_content&quot;&gt;
- *
- *     &lt;android.support.design.widget.TextInputEditText
- *             android:layout_width=&quot;match_parent&quot;
- *             android:layout_height=&quot;wrap_content&quot;
- *             android:hint=&quot;@string/form_username&quot;/&gt;
- *
- * &lt;/android.support.design.widget.TextInputLayout&gt;
- * </pre>
- *
- * <p><strong>Note:</strong> The actual view hierarchy present under TextInputLayout is
- * <strong>NOT</strong> guaranteed to match the view hierarchy as written in XML. As a result,
- * calls to getParent() on children of the TextInputLayout -- such as an TextInputEditText --
- * may not return the TextInputLayout itself, but rather an intermediate View. If you need
- * to access a View directly, set an {@code android:id} and use {@link View#findViewById(int)}.
- */
-public class TextInputLayout extends LinearLayout implements WithHint {
-
-    private static final int ANIMATION_DURATION = 200;
-    private static final int INVALID_MAX_LENGTH = -1;
-
-    private static final String LOG_TAG = "TextInputLayout";
-
-    private final FrameLayout mInputFrame;
-    EditText mEditText;
-    private CharSequence mOriginalHint;
-
-    private boolean mHintEnabled;
-    private CharSequence mHint;
-
-    private Paint mTmpPaint;
-    private final Rect mTmpRect = new Rect();
-
-    private LinearLayout mIndicatorArea;
-    private int mIndicatorsAdded;
-
-    private Typeface mTypeface;
-
-    private boolean mErrorEnabled;
-    TextView mErrorView;
-    private int mErrorTextAppearance;
-    private boolean mErrorShown;
-    private CharSequence mError;
-
-    boolean mCounterEnabled;
-    private TextView mCounterView;
-    private int mCounterMaxLength;
-    private int mCounterTextAppearance;
-    private int mCounterOverflowTextAppearance;
-    private boolean mCounterOverflowed;
-
-    private boolean mPasswordToggleEnabled;
-    private Drawable mPasswordToggleDrawable;
-    private CharSequence mPasswordToggleContentDesc;
-    private CheckableImageButton mPasswordToggleView;
-    private boolean mPasswordToggledVisible;
-    private Drawable mPasswordToggleDummyDrawable;
-    private Drawable mOriginalEditTextEndDrawable;
-
-    private ColorStateList mPasswordToggleTintList;
-    private boolean mHasPasswordToggleTintList;
-    private PorterDuff.Mode mPasswordToggleTintMode;
-    private boolean mHasPasswordToggleTintMode;
-
-    private ColorStateList mDefaultTextColor;
-    private ColorStateList mFocusedTextColor;
-
-    // Only used for testing
-    private boolean mHintExpanded;
-
-    final CollapsingTextHelper mCollapsingTextHelper = new CollapsingTextHelper(this);
-
-    private boolean mHintAnimationEnabled;
-    private ValueAnimator mAnimator;
-
-    private boolean mHasReconstructedEditTextBackground;
-    private boolean mInDrawableStateChanged;
-
-    private boolean mRestoringSavedState;
-
-    public TextInputLayout(Context context) {
-        this(context, null);
-    }
-
-    public TextInputLayout(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public TextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-        // Can't call through to super(Context, AttributeSet, int) since it doesn't exist on API 10
-        super(context, attrs);
-
-        ThemeUtils.checkAppCompatTheme(context);
-
-        setOrientation(VERTICAL);
-        setWillNotDraw(false);
-        setAddStatesFromChildren(true);
-
-        mInputFrame = new FrameLayout(context);
-        mInputFrame.setAddStatesFromChildren(true);
-        addView(mInputFrame);
-
-        mCollapsingTextHelper.setTextSizeInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR);
-        mCollapsingTextHelper.setPositionInterpolator(new AccelerateInterpolator());
-        mCollapsingTextHelper.setCollapsedTextGravity(Gravity.TOP | GravityCompat.START);
-
-        final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,
-                R.styleable.TextInputLayout, defStyleAttr, R.style.Widget_Design_TextInputLayout);
-        mHintEnabled = a.getBoolean(R.styleable.TextInputLayout_hintEnabled, true);
-        setHint(a.getText(R.styleable.TextInputLayout_android_hint));
-        mHintAnimationEnabled = a.getBoolean(
-                R.styleable.TextInputLayout_hintAnimationEnabled, true);
-
-        if (a.hasValue(R.styleable.TextInputLayout_android_textColorHint)) {
-            mDefaultTextColor = mFocusedTextColor =
-                    a.getColorStateList(R.styleable.TextInputLayout_android_textColorHint);
-        }
-
-        final int hintAppearance = a.getResourceId(
-                R.styleable.TextInputLayout_hintTextAppearance, -1);
-        if (hintAppearance != -1) {
-            setHintTextAppearance(
-                    a.getResourceId(R.styleable.TextInputLayout_hintTextAppearance, 0));
-        }
-
-        mErrorTextAppearance = a.getResourceId(R.styleable.TextInputLayout_errorTextAppearance, 0);
-        final boolean errorEnabled = a.getBoolean(R.styleable.TextInputLayout_errorEnabled, false);
-
-        final boolean counterEnabled = a.getBoolean(
-                R.styleable.TextInputLayout_counterEnabled, false);
-        setCounterMaxLength(
-                a.getInt(R.styleable.TextInputLayout_counterMaxLength, INVALID_MAX_LENGTH));
-        mCounterTextAppearance = a.getResourceId(
-                R.styleable.TextInputLayout_counterTextAppearance, 0);
-        mCounterOverflowTextAppearance = a.getResourceId(
-                R.styleable.TextInputLayout_counterOverflowTextAppearance, 0);
-
-        mPasswordToggleEnabled = a.getBoolean(
-                R.styleable.TextInputLayout_passwordToggleEnabled, false);
-        mPasswordToggleDrawable = a.getDrawable(R.styleable.TextInputLayout_passwordToggleDrawable);
-        mPasswordToggleContentDesc = a.getText(
-                R.styleable.TextInputLayout_passwordToggleContentDescription);
-        if (a.hasValue(R.styleable.TextInputLayout_passwordToggleTint)) {
-            mHasPasswordToggleTintList = true;
-            mPasswordToggleTintList = a.getColorStateList(
-                    R.styleable.TextInputLayout_passwordToggleTint);
-        }
-        if (a.hasValue(R.styleable.TextInputLayout_passwordToggleTintMode)) {
-            mHasPasswordToggleTintMode = true;
-            mPasswordToggleTintMode = ViewUtils.parseTintMode(
-                    a.getInt(R.styleable.TextInputLayout_passwordToggleTintMode, -1), null);
-        }
-
-        a.recycle();
-
-        setErrorEnabled(errorEnabled);
-        setCounterEnabled(counterEnabled);
-        applyPasswordToggleTint();
-
-        if (ViewCompat.getImportantForAccessibility(this)
-                == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-            // Make sure we're important for accessibility if we haven't been explicitly not
-            ViewCompat.setImportantForAccessibility(this,
-                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        }
-
-        ViewCompat.setAccessibilityDelegate(this, new TextInputAccessibilityDelegate());
-    }
-
-    @Override
-    public void addView(View child, int index, final ViewGroup.LayoutParams params) {
-        if (child instanceof EditText) {
-            // Make sure that the EditText is vertically at the bottom, so that it sits on the
-            // EditText's underline
-            FrameLayout.LayoutParams flp = new FrameLayout.LayoutParams(params);
-            flp.gravity = Gravity.CENTER_VERTICAL | (flp.gravity & ~Gravity.VERTICAL_GRAVITY_MASK);
-            mInputFrame.addView(child, flp);
-
-            // Now use the EditText's LayoutParams as our own and update them to make enough space
-            // for the label
-            mInputFrame.setLayoutParams(params);
-            updateInputLayoutMargins();
-
-            setEditText((EditText) child);
-        } else {
-            // Carry on adding the View...
-            super.addView(child, index, params);
-        }
-    }
-
-    /**
-     * Set the typeface to use for the hint and any label views (such as counter and error views).
-     *
-     * @param typeface typeface to use, or {@code null} to use the default.
-     */
-    public void setTypeface(@Nullable Typeface typeface) {
-        if ((mTypeface != null && !mTypeface.equals(typeface))
-                || (mTypeface == null && typeface != null)) {
-            mTypeface = typeface;
-
-            mCollapsingTextHelper.setTypefaces(typeface);
-            if (mCounterView != null) {
-                mCounterView.setTypeface(typeface);
-            }
-            if (mErrorView != null) {
-                mErrorView.setTypeface(typeface);
-            }
-        }
-    }
-
-    /**
-     * Returns the typeface used for the hint and any label views (such as counter and error views).
-     */
-    @NonNull
-    public Typeface getTypeface() {
-        return mTypeface;
-    }
-
-    @Override
-    public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
-        if (mOriginalHint == null || mEditText == null) {
-            super.dispatchProvideAutofillStructure(structure, flags);
-            return;
-        }
-
-        // Temporarily sets child's hint to its original value so it is properly set in the
-        // child's ViewStructure.
-        final CharSequence hint = mEditText.getHint();
-        mEditText.setHint(mOriginalHint);
-        try {
-            super.dispatchProvideAutofillStructure(structure, flags);
-        } finally {
-            mEditText.setHint(hint);
-        }
-    }
-
-    private void setEditText(EditText editText) {
-        // If we already have an EditText, throw an exception
-        if (mEditText != null) {
-            throw new IllegalArgumentException("We already have an EditText, can only have one");
-        }
-
-        if (!(editText instanceof TextInputEditText)) {
-            Log.i(LOG_TAG, "EditText added is not a TextInputEditText. Please switch to using that"
-                    + " class instead.");
-        }
-
-        mEditText = editText;
-
-        final boolean hasPasswordTransformation = hasPasswordTransformation();
-
-        // Use the EditText's typeface, and it's text size for our expanded text
-        if (!hasPasswordTransformation) {
-            // We don't want a monospace font just because we have a password field
-            mCollapsingTextHelper.setTypefaces(mEditText.getTypeface());
-        }
-        mCollapsingTextHelper.setExpandedTextSize(mEditText.getTextSize());
-
-        final int editTextGravity = mEditText.getGravity();
-        mCollapsingTextHelper.setCollapsedTextGravity(
-                Gravity.TOP | (editTextGravity & ~Gravity.VERTICAL_GRAVITY_MASK));
-        mCollapsingTextHelper.setExpandedTextGravity(editTextGravity);
-
-        // Add a TextWatcher so that we know when the text input has changed
-        mEditText.addTextChangedListener(new TextWatcher() {
-            @Override
-            public void afterTextChanged(Editable s) {
-                updateLabelState(!mRestoringSavedState);
-                if (mCounterEnabled) {
-                    updateCounter(s.length());
-                }
-            }
-
-            @Override
-            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
-
-            @Override
-            public void onTextChanged(CharSequence s, int start, int before, int count) {}
-        });
-
-        // Use the EditText's hint colors if we don't have one set
-        if (mDefaultTextColor == null) {
-            mDefaultTextColor = mEditText.getHintTextColors();
-        }
-
-        // If we do not have a valid hint, try and retrieve it from the EditText, if enabled
-        if (mHintEnabled && TextUtils.isEmpty(mHint)) {
-            // Save the hint so it can be restored on dispatchProvideAutofillStructure();
-            mOriginalHint = mEditText.getHint();
-            setHint(mOriginalHint);
-            // Clear the EditText's hint as we will display it ourselves
-            mEditText.setHint(null);
-        }
-
-        if (mCounterView != null) {
-            updateCounter(mEditText.getText().length());
-        }
-
-        if (mIndicatorArea != null) {
-            adjustIndicatorPadding();
-        }
-
-        updatePasswordToggleView();
-
-        // Update the label visibility with no animation, but force a state change
-        updateLabelState(false, true);
-    }
-
-    private void updateInputLayoutMargins() {
-        // Create/update the LayoutParams so that we can add enough top margin
-        // to the EditText so make room for the label
-        final LayoutParams lp = (LayoutParams) mInputFrame.getLayoutParams();
-        final int newTopMargin;
-
-        if (mHintEnabled) {
-            if (mTmpPaint == null) {
-                mTmpPaint = new Paint();
-            }
-            mTmpPaint.setTypeface(mCollapsingTextHelper.getCollapsedTypeface());
-            mTmpPaint.setTextSize(mCollapsingTextHelper.getCollapsedTextSize());
-            newTopMargin = (int) -mTmpPaint.ascent();
-        } else {
-            newTopMargin = 0;
-        }
-
-        if (newTopMargin != lp.topMargin) {
-            lp.topMargin = newTopMargin;
-            mInputFrame.requestLayout();
-        }
-    }
-
-    void updateLabelState(boolean animate) {
-        updateLabelState(animate, false);
-    }
-
-    void updateLabelState(final boolean animate, final boolean force) {
-        final boolean isEnabled = isEnabled();
-        final boolean hasText = mEditText != null && !TextUtils.isEmpty(mEditText.getText());
-        final boolean isFocused = arrayContains(getDrawableState(), android.R.attr.state_focused);
-        final boolean isErrorShowing = !TextUtils.isEmpty(getError());
-
-        if (mDefaultTextColor != null) {
-            mCollapsingTextHelper.setExpandedTextColor(mDefaultTextColor);
-        }
-
-        if (isEnabled && mCounterOverflowed && mCounterView != null) {
-            mCollapsingTextHelper.setCollapsedTextColor(mCounterView.getTextColors());
-        } else if (isEnabled && isFocused && mFocusedTextColor != null) {
-            mCollapsingTextHelper.setCollapsedTextColor(mFocusedTextColor);
-        } else if (mDefaultTextColor != null) {
-            mCollapsingTextHelper.setCollapsedTextColor(mDefaultTextColor);
-        }
-
-        if (hasText || (isEnabled() && (isFocused || isErrorShowing))) {
-            // We should be showing the label so do so if it isn't already
-            if (force || mHintExpanded) {
-                collapseHint(animate);
-            }
-        } else {
-            // We should not be showing the label so hide it
-            if (force || !mHintExpanded) {
-                expandHint(animate);
-            }
-        }
-    }
-
-    /**
-     * Returns the {@link android.widget.EditText} used for text input.
-     */
-    @Nullable
-    public EditText getEditText() {
-        return mEditText;
-    }
-
-    /**
-     * Set the hint to be displayed in the floating label, if enabled.
-     *
-     * @see #setHintEnabled(boolean)
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
-     */
-    public void setHint(@Nullable CharSequence hint) {
-        if (mHintEnabled) {
-            setHintInternal(hint);
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
-        }
-    }
-
-    private void setHintInternal(CharSequence hint) {
-        mHint = hint;
-        mCollapsingTextHelper.setText(hint);
-    }
-
-    /**
-     * Returns the hint which is displayed in the floating label, if enabled.
-     *
-     * @return the hint, or null if there isn't one set, or the hint is not enabled.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_android_hint
-     */
-    @Override
-    @Nullable
-    public CharSequence getHint() {
-        return mHintEnabled ? mHint : null;
-    }
-
-    /**
-     * Sets whether the floating label functionality is enabled or not in this layout.
-     *
-     * <p>If enabled, any non-empty hint in the child EditText will be moved into the floating
-     * hint, and its existing hint will be cleared. If disabled, then any non-empty floating hint
-     * in this layout will be moved into the EditText, and this layout's hint will be cleared.</p>
-     *
-     * @see #setHint(CharSequence)
-     * @see #isHintEnabled()
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
-     */
-    public void setHintEnabled(boolean enabled) {
-        if (enabled != mHintEnabled) {
-            mHintEnabled = enabled;
-
-            final CharSequence editTextHint = mEditText.getHint();
-            if (!mHintEnabled) {
-                if (!TextUtils.isEmpty(mHint) && TextUtils.isEmpty(editTextHint)) {
-                    // If the hint is disabled, but we have a hint set, and the EditText doesn't,
-                    // pass it through...
-                    mEditText.setHint(mHint);
-                }
-                // Now clear out any set hint
-                setHintInternal(null);
-            } else {
-                if (!TextUtils.isEmpty(editTextHint)) {
-                    // If the hint is now enabled and the EditText has one set, we'll use it if
-                    // we don't already have one, and clear the EditText's
-                    if (TextUtils.isEmpty(mHint)) {
-                        setHint(editTextHint);
-                    }
-                    mEditText.setHint(null);
-                }
-            }
-
-            // Now update the EditText top margin
-            if (mEditText != null) {
-                updateInputLayoutMargins();
-            }
-        }
-    }
-
-    /**
-     * Returns whether the floating label functionality is enabled or not in this layout.
-     *
-     * @see #setHintEnabled(boolean)
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_hintEnabled
-     */
-    public boolean isHintEnabled() {
-        return mHintEnabled;
-    }
-
-    /**
-     * Sets the hint text color, size, style from the specified TextAppearance resource.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_hintTextAppearance
-     */
-    public void setHintTextAppearance(@StyleRes int resId) {
-        mCollapsingTextHelper.setCollapsedTextAppearance(resId);
-        mFocusedTextColor = mCollapsingTextHelper.getCollapsedTextColor();
-
-        if (mEditText != null) {
-            updateLabelState(false);
-            // Text size might have changed so update the top margin
-            updateInputLayoutMargins();
-        }
-    }
-
-    private void addIndicator(TextView indicator, int index) {
-        if (mIndicatorArea == null) {
-            mIndicatorArea = new LinearLayout(getContext());
-            mIndicatorArea.setOrientation(LinearLayout.HORIZONTAL);
-            addView(mIndicatorArea, LinearLayout.LayoutParams.MATCH_PARENT,
-                    LinearLayout.LayoutParams.WRAP_CONTENT);
-
-            // Add a flexible spacer in the middle so that the left/right views stay pinned
-            final Space spacer = new Space(getContext());
-            final LinearLayout.LayoutParams spacerLp = new LinearLayout.LayoutParams(0, 0, 1f);
-            mIndicatorArea.addView(spacer, spacerLp);
-
-            if (mEditText != null) {
-                adjustIndicatorPadding();
-            }
-        }
-        mIndicatorArea.setVisibility(View.VISIBLE);
-        mIndicatorArea.addView(indicator, index);
-        mIndicatorsAdded++;
-    }
-
-    private void adjustIndicatorPadding() {
-        // Add padding to the error and character counter so that they match the EditText
-        ViewCompat.setPaddingRelative(mIndicatorArea, ViewCompat.getPaddingStart(mEditText),
-                0, ViewCompat.getPaddingEnd(mEditText), mEditText.getPaddingBottom());
-    }
-
-    private void removeIndicator(TextView indicator) {
-        if (mIndicatorArea != null) {
-            mIndicatorArea.removeView(indicator);
-            if (--mIndicatorsAdded == 0) {
-                mIndicatorArea.setVisibility(View.GONE);
-            }
-        }
-    }
-
-    /**
-     * Whether the error functionality is enabled or not in this layout. Enabling this
-     * functionality before setting an error message via {@link #setError(CharSequence)}, will mean
-     * that this layout will not change size when an error is displayed.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_errorEnabled
-     */
-    public void setErrorEnabled(boolean enabled) {
-        if (mErrorEnabled != enabled) {
-            if (mErrorView != null) {
-                mErrorView.animate().cancel();
-            }
-
-            if (enabled) {
-                mErrorView = new AppCompatTextView(getContext());
-                mErrorView.setId(R.id.textinput_error);
-                if (mTypeface != null) {
-                    mErrorView.setTypeface(mTypeface);
-                }
-                boolean useDefaultColor = false;
-                try {
-                    TextViewCompat.setTextAppearance(mErrorView, mErrorTextAppearance);
-
-                    if (Build.VERSION.SDK_INT >= 23
-                            && mErrorView.getTextColors().getDefaultColor() == Color.MAGENTA) {
-                        // Caused by our theme not extending from Theme.Design*. On API 23 and
-                        // above, unresolved theme attrs result in MAGENTA rather than an exception.
-                        // Flag so that we use a decent default
-                        useDefaultColor = true;
-                    }
-                } catch (Exception e) {
-                    // Caused by our theme not extending from Theme.Design*. Flag so that we use
-                    // a decent default
-                    useDefaultColor = true;
-                }
-                if (useDefaultColor) {
-                    // Probably caused by our theme not extending from Theme.Design*. Instead
-                    // we manually set something appropriate
-                    TextViewCompat.setTextAppearance(mErrorView,
-                            android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Caption);
-                    mErrorView.setTextColor(ContextCompat.getColor(getContext(),
-                            android.support.v7.appcompat.R.color.error_color_material));
-                }
-                mErrorView.setVisibility(INVISIBLE);
-                ViewCompat.setAccessibilityLiveRegion(mErrorView,
-                        ViewCompat.ACCESSIBILITY_LIVE_REGION_POLITE);
-                addIndicator(mErrorView, 0);
-            } else {
-                mErrorShown = false;
-                updateEditTextBackground();
-                removeIndicator(mErrorView);
-                mErrorView = null;
-            }
-            mErrorEnabled = enabled;
-        }
-    }
-
-    /**
-     * Sets the text color and size for the error message from the specified
-     * TextAppearance resource.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_errorTextAppearance
-     */
-    public void setErrorTextAppearance(@StyleRes int resId) {
-        mErrorTextAppearance = resId;
-        if (mErrorView != null) {
-            TextViewCompat.setTextAppearance(mErrorView, resId);
-        }
-    }
-
-    /**
-     * Returns whether the error functionality is enabled or not in this layout.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_errorEnabled
-     *
-     * @see #setErrorEnabled(boolean)
-     */
-    public boolean isErrorEnabled() {
-        return mErrorEnabled;
-    }
-
-    /**
-     * Sets an error message that will be displayed below our {@link EditText}. If the
-     * {@code error} is {@code null}, the error message will be cleared.
-     * <p>
-     * If the error functionality has not been enabled via {@link #setErrorEnabled(boolean)}, then
-     * it will be automatically enabled if {@code error} is not empty.
-     *
-     * @param error Error message to display, or null to clear
-     *
-     * @see #getError()
-     */
-    public void setError(@Nullable final CharSequence error) {
-        // Only animate if we're enabled, laid out, and we have a different error message
-        setError(error, ViewCompat.isLaidOut(this) && isEnabled()
-                && (mErrorView == null || !TextUtils.equals(mErrorView.getText(), error)));
-    }
-
-    private void setError(@Nullable final CharSequence error, final boolean animate) {
-        mError = error;
-
-        if (!mErrorEnabled) {
-            if (TextUtils.isEmpty(error)) {
-                // If error isn't enabled, and the error is empty, just return
-                return;
-            }
-            // Else, we'll assume that they want to enable the error functionality
-            setErrorEnabled(true);
-        }
-
-        mErrorShown = !TextUtils.isEmpty(error);
-
-        // Cancel any on-going animation
-        mErrorView.animate().cancel();
-
-        if (mErrorShown) {
-            mErrorView.setText(error);
-            mErrorView.setVisibility(VISIBLE);
-
-            if (animate) {
-                if (mErrorView.getAlpha() == 1f) {
-                    // If it's currently 100% show, we'll animate it from 0
-                    mErrorView.setAlpha(0f);
-                }
-                mErrorView.animate()
-                        .alpha(1f)
-                        .setDuration(ANIMATION_DURATION)
-                        .setInterpolator(AnimationUtils.LINEAR_OUT_SLOW_IN_INTERPOLATOR)
-                        .setListener(new AnimatorListenerAdapter() {
-                            @Override
-                            public void onAnimationStart(Animator animator) {
-                                mErrorView.setVisibility(VISIBLE);
-                            }
-                        }).start();
-            } else {
-                // Set alpha to 1f, just in case
-                mErrorView.setAlpha(1f);
-            }
-        } else {
-            if (mErrorView.getVisibility() == VISIBLE) {
-                if (animate) {
-                    mErrorView.animate()
-                            .alpha(0f)
-                            .setDuration(ANIMATION_DURATION)
-                            .setInterpolator(AnimationUtils.FAST_OUT_LINEAR_IN_INTERPOLATOR)
-                            .setListener(new AnimatorListenerAdapter() {
-                                @Override
-                                public void onAnimationEnd(Animator animator) {
-                                    mErrorView.setText(error);
-                                    mErrorView.setVisibility(INVISIBLE);
-                                }
-                            }).start();
-                } else {
-                    mErrorView.setText(error);
-                    mErrorView.setVisibility(INVISIBLE);
-                }
-            }
-        }
-
-        updateEditTextBackground();
-        updateLabelState(animate);
-    }
-
-    /**
-     * Whether the character counter functionality is enabled or not in this layout.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_counterEnabled
-     */
-    public void setCounterEnabled(boolean enabled) {
-        if (mCounterEnabled != enabled) {
-            if (enabled) {
-                mCounterView = new AppCompatTextView(getContext());
-                mCounterView.setId(R.id.textinput_counter);
-                if (mTypeface != null) {
-                    mCounterView.setTypeface(mTypeface);
-                }
-                mCounterView.setMaxLines(1);
-                try {
-                    TextViewCompat.setTextAppearance(mCounterView, mCounterTextAppearance);
-                } catch (Exception e) {
-                    // Probably caused by our theme not extending from Theme.Design*. Instead
-                    // we manually set something appropriate
-                    TextViewCompat.setTextAppearance(mCounterView,
-                            android.support.v7.appcompat.R.style.TextAppearance_AppCompat_Caption);
-                    mCounterView.setTextColor(ContextCompat.getColor(getContext(),
-                            android.support.v7.appcompat.R.color.error_color_material));
-                }
-                addIndicator(mCounterView, -1);
-                if (mEditText == null) {
-                    updateCounter(0);
-                } else {
-                    updateCounter(mEditText.getText().length());
-                }
-            } else {
-                removeIndicator(mCounterView);
-                mCounterView = null;
-            }
-            mCounterEnabled = enabled;
-        }
-    }
-
-    /**
-     * Returns whether the character counter functionality is enabled or not in this layout.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_counterEnabled
-     *
-     * @see #setCounterEnabled(boolean)
-     */
-    public boolean isCounterEnabled() {
-        return mCounterEnabled;
-    }
-
-    /**
-     * Sets the max length to display at the character counter.
-     *
-     * @param maxLength maxLength to display. Any value less than or equal to 0 will not be shown.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_counterMaxLength
-     */
-    public void setCounterMaxLength(int maxLength) {
-        if (mCounterMaxLength != maxLength) {
-            if (maxLength > 0) {
-                mCounterMaxLength = maxLength;
-            } else {
-                mCounterMaxLength = INVALID_MAX_LENGTH;
-            }
-            if (mCounterEnabled) {
-                updateCounter(mEditText == null ? 0 : mEditText.getText().length());
-            }
-        }
-    }
-
-    @Override
-    public void setEnabled(boolean enabled) {
-        // Since we're set to addStatesFromChildren, we need to make sure that we set all
-        // children to enabled/disabled otherwise any enabled children will wipe out our disabled
-        // drawable state
-        recursiveSetEnabled(this, enabled);
-        super.setEnabled(enabled);
-    }
-
-    private static void recursiveSetEnabled(final ViewGroup vg, final boolean enabled) {
-        for (int i = 0, count = vg.getChildCount(); i < count; i++) {
-            final View child = vg.getChildAt(i);
-            child.setEnabled(enabled);
-            if (child instanceof ViewGroup) {
-                recursiveSetEnabled((ViewGroup) child, enabled);
-            }
-        }
-    }
-
-    /**
-     * Returns the max length shown at the character counter.
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_counterMaxLength
-     */
-    public int getCounterMaxLength() {
-        return mCounterMaxLength;
-    }
-
-    void updateCounter(int length) {
-        boolean wasCounterOverflowed = mCounterOverflowed;
-        if (mCounterMaxLength == INVALID_MAX_LENGTH) {
-            mCounterView.setText(String.valueOf(length));
-            mCounterOverflowed = false;
-        } else {
-            mCounterOverflowed = length > mCounterMaxLength;
-            if (wasCounterOverflowed != mCounterOverflowed) {
-                TextViewCompat.setTextAppearance(mCounterView, mCounterOverflowed
-                        ? mCounterOverflowTextAppearance : mCounterTextAppearance);
-            }
-            mCounterView.setText(getContext().getString(R.string.character_counter_pattern,
-                    length, mCounterMaxLength));
-        }
-        if (mEditText != null && wasCounterOverflowed != mCounterOverflowed) {
-            updateLabelState(false);
-            updateEditTextBackground();
-        }
-    }
-
-    private void updateEditTextBackground() {
-        if (mEditText == null) {
-            return;
-        }
-
-        Drawable editTextBackground = mEditText.getBackground();
-        if (editTextBackground == null) {
-            return;
-        }
-
-        ensureBackgroundDrawableStateWorkaround();
-
-        if (android.support.v7.widget.DrawableUtils.canSafelyMutateDrawable(editTextBackground)) {
-            editTextBackground = editTextBackground.mutate();
-        }
-
-        if (mErrorShown && mErrorView != null) {
-            // Set a color filter of the error color
-            editTextBackground.setColorFilter(
-                    AppCompatDrawableManager.getPorterDuffColorFilter(
-                            mErrorView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
-        } else if (mCounterOverflowed && mCounterView != null) {
-            // Set a color filter of the counter color
-            editTextBackground.setColorFilter(
-                    AppCompatDrawableManager.getPorterDuffColorFilter(
-                            mCounterView.getCurrentTextColor(), PorterDuff.Mode.SRC_IN));
-        } else {
-            // Else reset the color filter and refresh the drawable state so that the
-            // normal tint is used
-            DrawableCompat.clearColorFilter(editTextBackground);
-            mEditText.refreshDrawableState();
-        }
-    }
-
-    private void ensureBackgroundDrawableStateWorkaround() {
-        final int sdk = Build.VERSION.SDK_INT;
-        if (sdk != 21 && sdk != 22) {
-            // The workaround is only required on API 21-22
-            return;
-        }
-        final Drawable bg = mEditText.getBackground();
-        if (bg == null) {
-            return;
-        }
-
-        if (!mHasReconstructedEditTextBackground) {
-            // This is gross. There is an issue in the platform which affects container Drawables
-            // where the first drawable retrieved from resources will propagate any changes
-            // (like color filter) to all instances from the cache. We'll try to workaround it...
-
-            final Drawable newBg = bg.getConstantState().newDrawable();
-
-            if (bg instanceof DrawableContainer) {
-                // If we have a Drawable container, we can try and set it's constant state via
-                // reflection from the new Drawable
-                mHasReconstructedEditTextBackground =
-                        DrawableUtils.setContainerConstantState(
-                                (DrawableContainer) bg, newBg.getConstantState());
-            }
-
-            if (!mHasReconstructedEditTextBackground) {
-                // If we reach here then we just need to set a brand new instance of the Drawable
-                // as the background. This has the unfortunate side-effect of wiping out any
-                // user set padding, but I'd hope that use of custom padding on an EditText
-                // is limited.
-                ViewCompat.setBackground(mEditText, newBg);
-                mHasReconstructedEditTextBackground = true;
-            }
-        }
-    }
-
-    static class SavedState extends AbsSavedState {
-        CharSequence error;
-        boolean isPasswordToggledVisible;
-
-        SavedState(Parcelable superState) {
-            super(superState);
-        }
-
-        SavedState(Parcel source, ClassLoader loader) {
-            super(source, loader);
-            error = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-            isPasswordToggledVisible = (source.readInt() == 1);
-
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            TextUtils.writeToParcel(error, dest, flags);
-            dest.writeInt(isPasswordToggledVisible ? 1 : 0);
-        }
-
-        @Override
-        public String toString() {
-            return "TextInputLayout.SavedState{"
-                    + Integer.toHexString(System.identityHashCode(this))
-                    + " error=" + error + "}";
-        }
-
-        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
-            @Override
-            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
-                return new SavedState(in, loader);
-            }
-
-            @Override
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in, null);
-            }
-
-            @Override
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        Parcelable superState = super.onSaveInstanceState();
-        SavedState ss = new SavedState(superState);
-        if (mErrorShown) {
-            ss.error = getError();
-        }
-        ss.isPasswordToggledVisible = mPasswordToggledVisible;
-        return ss;
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            super.onRestoreInstanceState(state);
-            return;
-        }
-        SavedState ss = (SavedState) state;
-        super.onRestoreInstanceState(ss.getSuperState());
-        setError(ss.error);
-        if (ss.isPasswordToggledVisible) {
-            passwordVisibilityToggleRequested(true);
-        }
-        requestLayout();
-    }
-
-    @Override
-    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
-        mRestoringSavedState = true;
-        super.dispatchRestoreInstanceState(container);
-        mRestoringSavedState = false;
-    }
-
-    /**
-     * Returns the error message that was set to be displayed with
-     * {@link #setError(CharSequence)}, or <code>null</code> if no error was set
-     * or if error displaying is not enabled.
-     *
-     * @see #setError(CharSequence)
-     */
-    @Nullable
-    public CharSequence getError() {
-        return mErrorEnabled ? mError : null;
-    }
-
-    /**
-     * Returns whether any hint state changes, due to being focused or non-empty text, are
-     * animated.
-     *
-     * @see #setHintAnimationEnabled(boolean)
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_hintAnimationEnabled
-     */
-    public boolean isHintAnimationEnabled() {
-        return mHintAnimationEnabled;
-    }
-
-    /**
-     * Set whether any hint state changes, due to being focused or non-empty text, are
-     * animated.
-     *
-     * @see #isHintAnimationEnabled()
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_hintAnimationEnabled
-     */
-    public void setHintAnimationEnabled(boolean enabled) {
-        mHintAnimationEnabled = enabled;
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        if (mHintEnabled) {
-            mCollapsingTextHelper.draw(canvas);
-        }
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        updatePasswordToggleView();
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-    }
-
-    private void updatePasswordToggleView() {
-        if (mEditText == null) {
-            // If there is no EditText, there is nothing to update
-            return;
-        }
-
-        if (shouldShowPasswordIcon()) {
-            if (mPasswordToggleView == null) {
-                mPasswordToggleView = (CheckableImageButton) LayoutInflater.from(getContext())
-                        .inflate(R.layout.design_text_input_password_icon, mInputFrame, false);
-                mPasswordToggleView.setImageDrawable(mPasswordToggleDrawable);
-                mPasswordToggleView.setContentDescription(mPasswordToggleContentDesc);
-                mInputFrame.addView(mPasswordToggleView);
-
-                mPasswordToggleView.setOnClickListener(new View.OnClickListener() {
-                    @Override
-                    public void onClick(View view) {
-                        passwordVisibilityToggleRequested(false);
-                    }
-                });
-            }
-
-            if (mEditText != null && ViewCompat.getMinimumHeight(mEditText) <= 0) {
-                // We should make sure that the EditText has the same min-height as the password
-                // toggle view. This ensure focus works properly, and there is no visual jump
-                // if the password toggle is enabled/disabled.
-                mEditText.setMinimumHeight(ViewCompat.getMinimumHeight(mPasswordToggleView));
-            }
-
-            mPasswordToggleView.setVisibility(VISIBLE);
-            mPasswordToggleView.setChecked(mPasswordToggledVisible);
-
-            // We need to add a dummy drawable as the end compound drawable so that the text is
-            // indented and doesn't display below the toggle view
-            if (mPasswordToggleDummyDrawable == null) {
-                mPasswordToggleDummyDrawable = new ColorDrawable();
-            }
-            mPasswordToggleDummyDrawable.setBounds(0, 0, mPasswordToggleView.getMeasuredWidth(), 1);
-
-            final Drawable[] compounds = TextViewCompat.getCompoundDrawablesRelative(mEditText);
-            // Store the user defined end compound drawable so that we can restore it later
-            if (compounds[2] != mPasswordToggleDummyDrawable) {
-                mOriginalEditTextEndDrawable = compounds[2];
-            }
-            TextViewCompat.setCompoundDrawablesRelative(mEditText, compounds[0], compounds[1],
-                    mPasswordToggleDummyDrawable, compounds[3]);
-
-            // Copy over the EditText's padding so that we match
-            mPasswordToggleView.setPadding(mEditText.getPaddingLeft(),
-                    mEditText.getPaddingTop(), mEditText.getPaddingRight(),
-                    mEditText.getPaddingBottom());
-        } else {
-            if (mPasswordToggleView != null && mPasswordToggleView.getVisibility() == VISIBLE) {
-                mPasswordToggleView.setVisibility(View.GONE);
-            }
-
-            if (mPasswordToggleDummyDrawable != null) {
-                // Make sure that we remove the dummy end compound drawable if it exists, and then
-                // clear it
-                final Drawable[] compounds = TextViewCompat.getCompoundDrawablesRelative(mEditText);
-                if (compounds[2] == mPasswordToggleDummyDrawable) {
-                    TextViewCompat.setCompoundDrawablesRelative(mEditText, compounds[0],
-                            compounds[1], mOriginalEditTextEndDrawable, compounds[3]);
-                    mPasswordToggleDummyDrawable = null;
-                }
-            }
-        }
-    }
-
-    /**
-     * Set the icon to use for the password visibility toggle button.
-     *
-     * <p>If you use an icon you should also set a description for its action
-     * using {@link #setPasswordVisibilityToggleContentDescription(CharSequence)}.
-     * This is used for accessibility.</p>
-     *
-     * @param resId resource id of the drawable to set, or 0 to clear the icon
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleDrawable
-     */
-    public void setPasswordVisibilityToggleDrawable(@DrawableRes int resId) {
-        setPasswordVisibilityToggleDrawable(resId != 0
-                ? AppCompatResources.getDrawable(getContext(), resId)
-                : null);
-    }
-
-    /**
-     * Set the icon to use for the password visibility toggle button.
-     *
-     * <p>If you use an icon you should also set a description for its action
-     * using {@link #setPasswordVisibilityToggleContentDescription(CharSequence)}.
-     * This is used for accessibility.</p>
-     *
-     * @param icon Drawable to set, may be null to clear the icon
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleDrawable
-     */
-    public void setPasswordVisibilityToggleDrawable(@Nullable Drawable icon) {
-        mPasswordToggleDrawable = icon;
-        if (mPasswordToggleView != null) {
-            mPasswordToggleView.setImageDrawable(icon);
-        }
-    }
-
-    /**
-     * Set a content description for the navigation button if one is present.
-     *
-     * <p>The content description will be read via screen readers or other accessibility
-     * systems to explain the action of the password visibility toggle.</p>
-     *
-     * @param resId Resource ID of a content description string to set,
-     *              or 0 to clear the description
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleContentDescription
-     */
-    public void setPasswordVisibilityToggleContentDescription(@StringRes int resId) {
-        setPasswordVisibilityToggleContentDescription(
-                resId != 0 ? getResources().getText(resId) : null);
-    }
-
-    /**
-     * Set a content description for the navigation button if one is present.
-     *
-     * <p>The content description will be read via screen readers or other accessibility
-     * systems to explain the action of the password visibility toggle.</p>
-     *
-     * @param description Content description to set, or null to clear the content description
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleContentDescription
-     */
-    public void setPasswordVisibilityToggleContentDescription(@Nullable CharSequence description) {
-        mPasswordToggleContentDesc = description;
-        if (mPasswordToggleView != null) {
-            mPasswordToggleView.setContentDescription(description);
-        }
-    }
-
-    /**
-     * Returns the icon currently used for the password visibility toggle button.
-     *
-     * @see #setPasswordVisibilityToggleDrawable(Drawable)
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleDrawable
-     */
-    @Nullable
-    public Drawable getPasswordVisibilityToggleDrawable() {
-        return mPasswordToggleDrawable;
-    }
-
-    /**
-     * Returns the currently configured content description for the password visibility
-     * toggle button.
-     *
-     * <p>This will be used to describe the navigation action to users through mechanisms
-     * such as screen readers.</p>
-     */
-    @Nullable
-    public CharSequence getPasswordVisibilityToggleContentDescription() {
-        return mPasswordToggleContentDesc;
-    }
-
-    /**
-     * Returns whether the password visibility toggle functionality is currently enabled.
-     *
-     * @see #setPasswordVisibilityToggleEnabled(boolean)
-     */
-    public boolean isPasswordVisibilityToggleEnabled() {
-        return mPasswordToggleEnabled;
-    }
-
-    /**
-     * Returns whether the password visibility toggle functionality is enabled or not.
-     *
-     * <p>When enabled, a button is placed at the end of the EditText which enables the user
-     * to switch between the field's input being visibly disguised or not.</p>
-     *
-     * @param enabled true to enable the functionality
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleEnabled
-     */
-    public void setPasswordVisibilityToggleEnabled(final boolean enabled) {
-        if (mPasswordToggleEnabled != enabled) {
-            mPasswordToggleEnabled = enabled;
-
-            if (!enabled && mPasswordToggledVisible && mEditText != null) {
-                // If the toggle is no longer enabled, but we remove the PasswordTransformation
-                // to make the password visible, add it back
-                mEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());
-            }
-
-            // Reset the visibility tracking flag
-            mPasswordToggledVisible = false;
-
-            updatePasswordToggleView();
-        }
-    }
-
-    /**
-     * Applies a tint to the the password visibility toggle drawable. Does not modify the current
-     * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
-     *
-     * <p>Subsequent calls to {@link #setPasswordVisibilityToggleDrawable(Drawable)} will
-     * automatically mutate the drawable and apply the specified tint and tint mode using
-     * {@link DrawableCompat#setTintList(Drawable, ColorStateList)}.</p>
-     *
-     * @param tintList the tint to apply, may be null to clear tint
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleTint
-     */
-    public void setPasswordVisibilityToggleTintList(@Nullable ColorStateList tintList) {
-        mPasswordToggleTintList = tintList;
-        mHasPasswordToggleTintList = true;
-        applyPasswordToggleTint();
-    }
-
-    /**
-     * Specifies the blending mode used to apply the tint specified by
-     * {@link #setPasswordVisibilityToggleTintList(ColorStateList)} to the password
-     * visibility toggle drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.</p>
-     *
-     * @param mode the blending mode used to apply the tint, may be null to clear tint
-     *
-     * @attr ref android.support.design.R.styleable#TextInputLayout_passwordToggleTintMode
-     */
-    public void setPasswordVisibilityToggleTintMode(@Nullable PorterDuff.Mode mode) {
-        mPasswordToggleTintMode = mode;
-        mHasPasswordToggleTintMode = true;
-        applyPasswordToggleTint();
-    }
-
-    private void passwordVisibilityToggleRequested(boolean shouldSkipAnimations) {
-        if (mPasswordToggleEnabled) {
-            // Store the current cursor position
-            final int selection = mEditText.getSelectionEnd();
-
-            if (hasPasswordTransformation()) {
-                mEditText.setTransformationMethod(null);
-                mPasswordToggledVisible = true;
-            } else {
-                mEditText.setTransformationMethod(PasswordTransformationMethod.getInstance());
-                mPasswordToggledVisible = false;
-            }
-
-            mPasswordToggleView.setChecked(mPasswordToggledVisible);
-            if (shouldSkipAnimations) {
-                mPasswordToggleView.jumpDrawablesToCurrentState();
-            }
-
-            // And restore the cursor position
-            mEditText.setSelection(selection);
-        }
-    }
-
-    private boolean hasPasswordTransformation() {
-        return mEditText != null
-                && mEditText.getTransformationMethod() instanceof PasswordTransformationMethod;
-    }
-
-    private boolean shouldShowPasswordIcon() {
-        return mPasswordToggleEnabled && (hasPasswordTransformation() || mPasswordToggledVisible);
-    }
-
-    private void applyPasswordToggleTint() {
-        if (mPasswordToggleDrawable != null
-                && (mHasPasswordToggleTintList || mHasPasswordToggleTintMode)) {
-            mPasswordToggleDrawable = DrawableCompat.wrap(mPasswordToggleDrawable).mutate();
-
-            if (mHasPasswordToggleTintList) {
-                DrawableCompat.setTintList(mPasswordToggleDrawable, mPasswordToggleTintList);
-            }
-            if (mHasPasswordToggleTintMode) {
-                DrawableCompat.setTintMode(mPasswordToggleDrawable, mPasswordToggleTintMode);
-            }
-
-            if (mPasswordToggleView != null
-                    && mPasswordToggleView.getDrawable() != mPasswordToggleDrawable) {
-                mPasswordToggleView.setImageDrawable(mPasswordToggleDrawable);
-            }
-        }
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-
-        if (mHintEnabled && mEditText != null) {
-            final Rect rect = mTmpRect;
-            ViewGroupUtils.getDescendantRect(this, mEditText, rect);
-
-            final int l = rect.left + mEditText.getCompoundPaddingLeft();
-            final int r = rect.right - mEditText.getCompoundPaddingRight();
-
-            mCollapsingTextHelper.setExpandedBounds(
-                    l, rect.top + mEditText.getCompoundPaddingTop(),
-                    r, rect.bottom - mEditText.getCompoundPaddingBottom());
-
-            // Set the collapsed bounds to be the the full height (minus padding) to match the
-            // EditText's editable area
-            mCollapsingTextHelper.setCollapsedBounds(l, getPaddingTop(),
-                    r, bottom - top - getPaddingBottom());
-
-            mCollapsingTextHelper.recalculate();
-        }
-    }
-
-    private void collapseHint(boolean animate) {
-        if (mAnimator != null && mAnimator.isRunning()) {
-            mAnimator.cancel();
-        }
-        if (animate && mHintAnimationEnabled) {
-            animateToExpansionFraction(1f);
-        } else {
-            mCollapsingTextHelper.setExpansionFraction(1f);
-        }
-        mHintExpanded = false;
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        if (mInDrawableStateChanged) {
-            // Some of the calls below will update the drawable state of child views. Since we're
-            // using addStatesFromChildren we can get into infinite recursion, hence we'll just
-            // exit in this instance
-            return;
-        }
-
-        mInDrawableStateChanged = true;
-
-        super.drawableStateChanged();
-
-        final int[] state = getDrawableState();
-        boolean changed = false;
-
-        // Drawable state has changed so see if we need to update the label
-        updateLabelState(ViewCompat.isLaidOut(this) && isEnabled());
-
-        updateEditTextBackground();
-
-        if (mCollapsingTextHelper != null) {
-            changed |= mCollapsingTextHelper.setState(state);
-        }
-
-        if (changed) {
-            invalidate();
-        }
-
-        mInDrawableStateChanged = false;
-    }
-
-    private void expandHint(boolean animate) {
-        if (mAnimator != null && mAnimator.isRunning()) {
-            mAnimator.cancel();
-        }
-        if (animate && mHintAnimationEnabled) {
-            animateToExpansionFraction(0f);
-        } else {
-            mCollapsingTextHelper.setExpansionFraction(0f);
-        }
-        mHintExpanded = true;
-    }
-
-    @VisibleForTesting
-    void animateToExpansionFraction(final float target) {
-        if (mCollapsingTextHelper.getExpansionFraction() == target) {
-            return;
-        }
-        if (mAnimator == null) {
-            mAnimator = new ValueAnimator();
-            mAnimator.setInterpolator(AnimationUtils.LINEAR_INTERPOLATOR);
-            mAnimator.setDuration(ANIMATION_DURATION);
-            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animator) {
-                    mCollapsingTextHelper.setExpansionFraction((float) animator.getAnimatedValue());
-                }
-            });
-        }
-        mAnimator.setFloatValues(mCollapsingTextHelper.getExpansionFraction(), target);
-        mAnimator.start();
-    }
-
-    @VisibleForTesting
-    final boolean isHintExpanded() {
-        return mHintExpanded;
-    }
-
-    private class TextInputAccessibilityDelegate extends AccessibilityDelegateCompat {
-        TextInputAccessibilityDelegate() {
-        }
-
-        @Override
-        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-            super.onInitializeAccessibilityEvent(host, event);
-            event.setClassName(TextInputLayout.class.getSimpleName());
-        }
-
-        @Override
-        public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
-            super.onPopulateAccessibilityEvent(host, event);
-
-            final CharSequence text = mCollapsingTextHelper.getText();
-            if (!TextUtils.isEmpty(text)) {
-                event.getText().add(text);
-            }
-        }
-
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
-            super.onInitializeAccessibilityNodeInfo(host, info);
-            info.setClassName(TextInputLayout.class.getSimpleName());
-
-            final CharSequence text = mCollapsingTextHelper.getText();
-            if (!TextUtils.isEmpty(text)) {
-                info.setText(text);
-            }
-            if (mEditText != null) {
-                info.setLabelFor(mEditText);
-            }
-            final CharSequence error = mErrorView != null ? mErrorView.getText() : null;
-            if (!TextUtils.isEmpty(error)) {
-                info.setContentInvalid(true);
-                info.setError(error);
-            }
-        }
-    }
-
-    private static boolean arrayContains(int[] array, int value) {
-        for (int v : array) {
-            if (v == value) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/design/src/android/support/design/widget/ThemeUtils.java b/design/src/android/support/design/widget/ThemeUtils.java
deleted file mode 100644
index 821dcb6..0000000
--- a/design/src/android/support/design/widget/ThemeUtils.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-
-class ThemeUtils {
-
-    private static final int[] APPCOMPAT_CHECK_ATTRS = {
-            android.support.v7.appcompat.R.attr.colorPrimary
-    };
-
-    static void checkAppCompatTheme(Context context) {
-        TypedArray a = context.obtainStyledAttributes(APPCOMPAT_CHECK_ATTRS);
-        final boolean failed = !a.hasValue(0);
-        a.recycle();
-        if (failed) {
-            throw new IllegalArgumentException("You need to use a Theme.AppCompat theme "
-                    + "(or descendant) with the design library.");
-        }
-    }
-}
diff --git a/design/src/android/support/design/widget/ViewOffsetBehavior.java b/design/src/android/support/design/widget/ViewOffsetBehavior.java
deleted file mode 100644
index 541de69..0000000
--- a/design/src/android/support/design/widget/ViewOffsetBehavior.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-
-/**
- * Behavior will automatically sets up a {@link ViewOffsetHelper} on a {@link View}.
- */
-class ViewOffsetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
-
-    private ViewOffsetHelper mViewOffsetHelper;
-
-    private int mTempTopBottomOffset = 0;
-    private int mTempLeftRightOffset = 0;
-
-    public ViewOffsetBehavior() {}
-
-    public ViewOffsetBehavior(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
-        // First let lay the child out
-        layoutChild(parent, child, layoutDirection);
-
-        if (mViewOffsetHelper == null) {
-            mViewOffsetHelper = new ViewOffsetHelper(child);
-        }
-        mViewOffsetHelper.onViewLayout();
-
-        if (mTempTopBottomOffset != 0) {
-            mViewOffsetHelper.setTopAndBottomOffset(mTempTopBottomOffset);
-            mTempTopBottomOffset = 0;
-        }
-        if (mTempLeftRightOffset != 0) {
-            mViewOffsetHelper.setLeftAndRightOffset(mTempLeftRightOffset);
-            mTempLeftRightOffset = 0;
-        }
-
-        return true;
-    }
-
-    protected void layoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
-        // Let the parent lay it out by default
-        parent.onLayoutChild(child, layoutDirection);
-    }
-
-    public boolean setTopAndBottomOffset(int offset) {
-        if (mViewOffsetHelper != null) {
-            return mViewOffsetHelper.setTopAndBottomOffset(offset);
-        } else {
-            mTempTopBottomOffset = offset;
-        }
-        return false;
-    }
-
-    public boolean setLeftAndRightOffset(int offset) {
-        if (mViewOffsetHelper != null) {
-            return mViewOffsetHelper.setLeftAndRightOffset(offset);
-        } else {
-            mTempLeftRightOffset = offset;
-        }
-        return false;
-    }
-
-    public int getTopAndBottomOffset() {
-        return mViewOffsetHelper != null ? mViewOffsetHelper.getTopAndBottomOffset() : 0;
-    }
-
-    public int getLeftAndRightOffset() {
-        return mViewOffsetHelper != null ? mViewOffsetHelper.getLeftAndRightOffset() : 0;
-    }
-}
\ No newline at end of file
diff --git a/design/src/android/support/design/widget/ViewOffsetHelper.java b/design/src/android/support/design/widget/ViewOffsetHelper.java
deleted file mode 100644
index 088430a..0000000
--- a/design/src/android/support/design/widget/ViewOffsetHelper.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-
-/**
- * Utility helper for moving a {@link android.view.View} around using
- * {@link android.view.View#offsetLeftAndRight(int)} and
- * {@link android.view.View#offsetTopAndBottom(int)}.
- * <p>
- * Also the setting of absolute offsets (similar to translationX/Y), rather than additive
- * offsets.
- */
-class ViewOffsetHelper {
-
-    private final View mView;
-
-    private int mLayoutTop;
-    private int mLayoutLeft;
-    private int mOffsetTop;
-    private int mOffsetLeft;
-
-    public ViewOffsetHelper(View view) {
-        mView = view;
-    }
-
-    public void onViewLayout() {
-        // Now grab the intended top
-        mLayoutTop = mView.getTop();
-        mLayoutLeft = mView.getLeft();
-
-        // And offset it as needed
-        updateOffsets();
-    }
-
-    private void updateOffsets() {
-        ViewCompat.offsetTopAndBottom(mView, mOffsetTop - (mView.getTop() - mLayoutTop));
-        ViewCompat.offsetLeftAndRight(mView, mOffsetLeft - (mView.getLeft() - mLayoutLeft));
-    }
-
-    /**
-     * Set the top and bottom offset for this {@link ViewOffsetHelper}'s view.
-     *
-     * @param offset the offset in px.
-     * @return true if the offset has changed
-     */
-    public boolean setTopAndBottomOffset(int offset) {
-        if (mOffsetTop != offset) {
-            mOffsetTop = offset;
-            updateOffsets();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Set the left and right offset for this {@link ViewOffsetHelper}'s view.
-     *
-     * @param offset the offset in px.
-     * @return true if the offset has changed
-     */
-    public boolean setLeftAndRightOffset(int offset) {
-        if (mOffsetLeft != offset) {
-            mOffsetLeft = offset;
-            updateOffsets();
-            return true;
-        }
-        return false;
-    }
-
-    public int getTopAndBottomOffset() {
-        return mOffsetTop;
-    }
-
-    public int getLeftAndRightOffset() {
-        return mOffsetLeft;
-    }
-
-    public int getLayoutTop() {
-        return mLayoutTop;
-    }
-
-    public int getLayoutLeft() {
-        return mLayoutLeft;
-    }
-}
\ No newline at end of file
diff --git a/design/src/android/support/design/widget/ViewUtils.java b/design/src/android/support/design/widget/ViewUtils.java
deleted file mode 100644
index c09eac1..0000000
--- a/design/src/android/support/design/widget/ViewUtils.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.graphics.PorterDuff;
-
-class ViewUtils {
-    static PorterDuff.Mode parseTintMode(int value, PorterDuff.Mode defaultMode) {
-        switch (value) {
-            case 3:
-                return PorterDuff.Mode.SRC_OVER;
-            case 5:
-                return PorterDuff.Mode.SRC_IN;
-            case 9:
-                return PorterDuff.Mode.SRC_ATOP;
-            case 14:
-                return PorterDuff.Mode.MULTIPLY;
-            case 15:
-                return PorterDuff.Mode.SCREEN;
-            default:
-                return defaultMode;
-        }
-    }
-
-}
diff --git a/design/tests/AndroidManifest.xml b/design/tests/AndroidManifest.xml
deleted file mode 100755
index 756d7c1..0000000
--- a/design/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  Copyright (C) 2015 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.design.test">
-    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
-    <application
-        android:supportsRtl="true"
-        android:theme="@style/Theme.Design">
-
-        <activity
-            android:name="android.support.design.widget.TabLayoutWithViewPagerActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.SnackbarActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.SnackbarActivityWithTranslucentNavBar"
-            android:theme="@style/Theme.TranslucentNavBar"/>
-
-        <activity
-            android:name="android.support.design.widget.SnackbarActivityWithFAB"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.DynamicCoordinatorLayoutActivity"
-            android:theme="@style/Theme.TranslucentStatus"/>
-
-        <activity
-            android:name="android.support.design.widget.TabLayoutPoolingActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.BottomSheetBehaviorActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.BottomSheetBehaviorWithInsetsActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.BottomSheetDialogActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.CoordinatorLayoutActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.FloatingActionButtonActivity"
-            android:theme="@style/Theme.AppCompat.Light.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.NavigationViewActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.BottomNavigationViewActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.TextInputLayoutActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-        <activity
-            android:name="android.support.v7.app.AppCompatActivity"/>
-
-        <activity
-            android:name="android.support.design.widget.AppBarLayoutCollapsePinTestActivity"
-            android:theme="@style/Theme.TranslucentStatus"/>
-
-        <activity
-            android:name="android.support.design.widget.AppBarWithScrollbarsActivity"
-            android:theme="@style/Theme.AppCompat.Light.DarkActionBar"/>
-
-        <activity
-            android:name="android.support.design.widget.AppBarHorizontalScrollingActivity"
-            android:theme="@style/Theme.AppCompat.NoActionBar"/>
-
-    </application>
-
-</manifest>
diff --git a/design/tests/NO_DOCS b/design/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/design/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/design/tests/res/color/color_state_list_lilac.xml b/design/tests/res/color/color_state_list_lilac.xml
deleted file mode 100644
index f0b2791..0000000
--- a/design/tests/res/color/color_state_list_lilac.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="@color/lilac_disabled" />
-    <item android:color="@color/lilac_default"/>
-</selector>
-
diff --git a/design/tests/res/color/color_state_list_red_translucent.xml b/design/tests/res/color/color_state_list_red_translucent.xml
deleted file mode 100644
index fdf8b2b..0000000
--- a/design/tests/res/color/color_state_list_red_translucent.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="@color/red_translucent"/>
-</selector>
-
diff --git a/design/tests/res/color/color_state_list_sand.xml b/design/tests/res/color/color_state_list_sand.xml
deleted file mode 100644
index eb472c2..0000000
--- a/design/tests/res/color/color_state_list_sand.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false" android:color="@color/sand_disabled" />
-    <item android:state_checked="true" android:color="@color/sand_checked" />
-    <item android:color="@color/sand_default" />
-</selector>
-
diff --git a/design/tests/res/color/color_state_list_themed.xml b/design/tests/res/color/color_state_list_themed.xml
deleted file mode 100644
index e17fa66..0000000
--- a/design/tests/res/color/color_state_list_themed.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:color="?attr/colorAccent"/>
-</selector>
-
diff --git a/design/tests/res/color/fab_tint.xml b/design/tests/res/color/fab_tint.xml
deleted file mode 100644
index 2ac659d..0000000
--- a/design/tests/res/color/fab_tint.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_selected="false" android:color="@color/sand_disabled" />
-    <item android:color="@color/sand_default" />
-</selector>
-
diff --git a/design/tests/res/drawable-hdpi/ic_account_circle_white_48dp.png b/design/tests/res/drawable-hdpi/ic_account_circle_white_48dp.png
deleted file mode 100644
index bfd4632..0000000
--- a/design/tests/res/drawable-hdpi/ic_account_circle_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-hdpi/ic_lightbulb_outline_white_24dp.png b/design/tests/res/drawable-hdpi/ic_lightbulb_outline_white_24dp.png
deleted file mode 100644
index c9dd4c1..0000000
--- a/design/tests/res/drawable-hdpi/ic_lightbulb_outline_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-mdpi/ic_account_circle_white_48dp.png b/design/tests/res/drawable-mdpi/ic_account_circle_white_48dp.png
deleted file mode 100644
index 246e0c8..0000000
--- a/design/tests/res/drawable-mdpi/ic_account_circle_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-mdpi/ic_lightbulb_outline_white_24dp.png b/design/tests/res/drawable-mdpi/ic_lightbulb_outline_white_24dp.png
deleted file mode 100644
index 91702b1..0000000
--- a/design/tests/res/drawable-mdpi/ic_lightbulb_outline_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-mdpi/test_drawable_blue.png b/design/tests/res/drawable-mdpi/test_drawable_blue.png
deleted file mode 100644
index 6350c14..0000000
--- a/design/tests/res/drawable-mdpi/test_drawable_blue.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-mdpi/test_drawable_green.png b/design/tests/res/drawable-mdpi/test_drawable_green.png
deleted file mode 100644
index e3afddb..0000000
--- a/design/tests/res/drawable-mdpi/test_drawable_green.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-mdpi/test_drawable_red.png b/design/tests/res/drawable-mdpi/test_drawable_red.png
deleted file mode 100644
index d95db88..0000000
--- a/design/tests/res/drawable-mdpi/test_drawable_red.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-nodpi/photo.jpg b/design/tests/res/drawable-nodpi/photo.jpg
deleted file mode 100644
index d5a2ef0..0000000
--- a/design/tests/res/drawable-nodpi/photo.jpg
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xhdpi/ic_account_circle_white_48dp.png b/design/tests/res/drawable-xhdpi/ic_account_circle_white_48dp.png
deleted file mode 100644
index 07643f9..0000000
--- a/design/tests/res/drawable-xhdpi/ic_account_circle_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xhdpi/ic_lightbulb_outline_white_24dp.png b/design/tests/res/drawable-xhdpi/ic_lightbulb_outline_white_24dp.png
deleted file mode 100644
index afc7e53..0000000
--- a/design/tests/res/drawable-xhdpi/ic_lightbulb_outline_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xxhdpi/ic_account_circle_white_48dp.png b/design/tests/res/drawable-xxhdpi/ic_account_circle_white_48dp.png
deleted file mode 100644
index 1ac34a7..0000000
--- a/design/tests/res/drawable-xxhdpi/ic_account_circle_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xxhdpi/ic_add.png b/design/tests/res/drawable-xxhdpi/ic_add.png
deleted file mode 100644
index a84106b..0000000
--- a/design/tests/res/drawable-xxhdpi/ic_add.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xxhdpi/ic_airplay_black_24dp.png b/design/tests/res/drawable-xxhdpi/ic_airplay_black_24dp.png
deleted file mode 100644
index ddf2620..0000000
--- a/design/tests/res/drawable-xxhdpi/ic_airplay_black_24dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xxhdpi/ic_album_black_24dp.png b/design/tests/res/drawable-xxhdpi/ic_album_black_24dp.png
deleted file mode 100644
index 60f59f5..0000000
--- a/design/tests/res/drawable-xxhdpi/ic_album_black_24dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xxhdpi/ic_lightbulb_outline_white_24dp.png b/design/tests/res/drawable-xxhdpi/ic_lightbulb_outline_white_24dp.png
deleted file mode 100644
index 1c16761..0000000
--- a/design/tests/res/drawable-xxhdpi/ic_lightbulb_outline_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xxxhdpi/ic_account_circle_white_48dp.png b/design/tests/res/drawable-xxxhdpi/ic_account_circle_white_48dp.png
deleted file mode 100644
index baa6045..0000000
--- a/design/tests/res/drawable-xxxhdpi/ic_account_circle_white_48dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable-xxxhdpi/ic_lightbulb_outline_white_24dp.png b/design/tests/res/drawable-xxxhdpi/ic_lightbulb_outline_white_24dp.png
deleted file mode 100644
index 983a253..0000000
--- a/design/tests/res/drawable-xxxhdpi/ic_lightbulb_outline_white_24dp.png
+++ /dev/null
Binary files differ
diff --git a/design/tests/res/drawable/test_background_blue.xml b/design/tests/res/drawable/test_background_blue.xml
deleted file mode 100644
index fe4bca2..0000000
--- a/design/tests/res/drawable/test_background_blue.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <solid
-        android:color="@color/test_blue" />
-</shape>
\ No newline at end of file
diff --git a/design/tests/res/drawable/test_background_green.xml b/design/tests/res/drawable/test_background_green.xml
deleted file mode 100644
index b90d9bc..0000000
--- a/design/tests/res/drawable/test_background_green.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <solid
-        android:color="@color/test_green" />
-</shape>
\ No newline at end of file
diff --git a/design/tests/res/drawable/test_drawable_state_list.xml b/design/tests/res/drawable/test_drawable_state_list.xml
deleted file mode 100644
index f125913..0000000
--- a/design/tests/res/drawable/test_drawable_state_list.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_checked="true" android:drawable="@drawable/test_background_blue" />
-    <item android:drawable="@drawable/test_background_green" />
-</selector>
-
diff --git a/design/tests/res/drawable/vector_icon.xml b/design/tests/res/drawable/vector_icon.xml
deleted file mode 100644
index 19e97ee..0000000
--- a/design/tests/res/drawable/vector_icon.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-    Copyright (C) 2016 The Android Open Source Project
-
-    Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?attr/colorControlNormal">
-    <path
-            android:pathData="M19,6.41L17.59,5,12,10.59,6.41,5,5,6.41,10.59,12,5,17.59,6.41,19,12,13.41,17.59,19,19,17.59,13.41,12z"
-            android:fillColor="@android:color/white"/>
-</vector>
diff --git a/design/tests/res/layout/action_layout.xml b/design/tests/res/layout/action_layout.xml
deleted file mode 100644
index 8c4dc05..0000000
--- a/design/tests/res/layout/action_layout.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<android.support.v7.widget.SwitchCompat
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/toggle"
-    android:orientation="vertical"
-    android:layout_width="wrap_content"
-    android:layout_height="match_parent"
-    android:gravity="center_vertical"/>
diff --git a/design/tests/res/layout/action_layout_custom.xml b/design/tests/res/layout/action_layout_custom.xml
deleted file mode 100644
index 10a3268..0000000
--- a/design/tests/res/layout/action_layout_custom.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<TextView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@color/lilac_default"
-    android:text="@string/navigate_custom"/>
diff --git a/design/tests/res/layout/activity_coordinator_layout.xml b/design/tests/res/layout/activity_coordinator_layout.xml
deleted file mode 100644
index 93bf947..0000000
--- a/design/tests/res/layout/activity_coordinator_layout.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:id="@+id/container"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent">
-
-    <android.support.design.widget.CoordinatorLayout
-        android:id="@+id/coordinator"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-</FrameLayout>
\ No newline at end of file
diff --git a/design/tests/res/layout/custom_snackbar_include.xml b/design/tests/res/layout/custom_snackbar_include.xml
deleted file mode 100644
index 4e610df..0000000
--- a/design/tests/res/layout/custom_snackbar_include.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2016 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
--->
-
-<android.support.design.widget.CustomSnackbarMainContent
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:theme="@style/ThemeOverlay.AppCompat.Dark"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:padding="8dp">
-
-    <ImageView
-        android:id="@+id/custom_snackbar_image_leading"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentLeft="true"
-        android:layout_marginRight="8dp"
-        android:src="@drawable/ic_account_circle_white_48dp" />
-
-    <ImageView
-        android:id="@+id/custom_snackbar_image_trailing"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_alignParentRight="true"
-        android:layout_marginTop="8dp"
-        android:src="@drawable/ic_lightbulb_outline_white_24dp" />
-
-    <TextView
-        android:id="@+id/custom_snackbar_title"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_toRightOf="@id/custom_snackbar_image_leading"
-        android:layout_toLeftOf="@id/custom_snackbar_image_trailing"
-        android:layout_marginTop="4dp"
-        android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
-        android:textStyle="bold"
-        android:singleLine="true" />
-
-    <TextView
-        android:id="@+id/custom_snackbar_subtitle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_toRightOf="@id/custom_snackbar_image_leading"
-        android:layout_toLeftOf="@id/custom_snackbar_image_trailing"
-        android:layout_below="@id/custom_snackbar_title"
-        android:textAppearance="@style/TextAppearance.Design.Snackbar.Message"
-        android:singleLine="true" />
-
-</android.support.design.widget.CustomSnackbarMainContent>
diff --git a/design/tests/res/layout/design_appbar_anchored_fab_margin_bottom.xml b/design/tests/res/layout/design_appbar_anchored_fab_margin_bottom.xml
deleted file mode 100644
index aaed2f9..0000000
--- a/design/tests/res/layout/design_appbar_anchored_fab_margin_bottom.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        app:layout_anchor="@+id/app_bar"
-        app:layout_anchorGravity="bottom|center_horizontal"
-        android:src="@drawable/ic_add"
-        android:layout_marginBottom="@dimen/fab_margin"
-        android:clickable="true" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_anchored_fab_margin_left.xml b/design/tests/res/layout/design_appbar_anchored_fab_margin_left.xml
deleted file mode 100644
index 9fabb7b..0000000
--- a/design/tests/res/layout/design_appbar_anchored_fab_margin_left.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        app:layout_anchor="@+id/app_bar"
-        app:layout_anchorGravity="bottom|left"
-        android:src="@drawable/ic_add"
-        android:layout_marginLeft="@dimen/fab_margin"
-        android:clickable="true" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_anchored_fab_margin_right.xml b/design/tests/res/layout/design_appbar_anchored_fab_margin_right.xml
deleted file mode 100644
index ea2e1c0..0000000
--- a/design/tests/res/layout/design_appbar_anchored_fab_margin_right.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        app:layout_anchor="@+id/app_bar"
-        app:layout_anchorGravity="bottom|right"
-        android:src="@drawable/ic_add"
-        android:layout_marginRight="@dimen/fab_margin"
-        android:clickable="true" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_anchored_fab_margin_top.xml b/design/tests/res/layout/design_appbar_anchored_fab_margin_top.xml
deleted file mode 100644
index 763d013..0000000
--- a/design/tests/res/layout/design_appbar_anchored_fab_margin_top.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        app:layout_anchor="@+id/app_bar"
-        app:layout_anchorGravity="bottom|center_horizontal"
-        android:src="@drawable/ic_add"
-        android:layout_marginTop="@dimen/fab_margin"
-        android:clickable="true" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_dodge_left.xml b/design/tests/res/layout/design_appbar_dodge_left.xml
deleted file mode 100644
index 7f3ecb9..0000000
--- a/design/tests/res/layout/design_appbar_dodge_left.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_gravity="bottom|left"
-        android:src="@drawable/ic_album_black_24dp"
-        app:layout_insetEdge="left"
-        android:clickable="true" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab2"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_gravity="bottom|left"
-        android:src="@drawable/ic_airplay_black_24dp"
-        app:layout_dodgeInsetEdges="left"
-        android:clickable="true" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_dodge_right.xml b/design/tests/res/layout/design_appbar_dodge_right.xml
deleted file mode 100644
index 10815c0..0000000
--- a/design/tests/res/layout/design_appbar_dodge_right.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_gravity="bottom|right"
-        android:src="@drawable/ic_album_black_24dp"
-        app:layout_insetEdge="right"
-        android:clickable="true" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab2"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_gravity="bottom|right"
-        android:src="@drawable/ic_airplay_black_24dp"
-        app:layout_dodgeInsetEdges="right"
-        android:clickable="true" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_horizontal_scrolling.xml b/design/tests/res/layout/design_appbar_horizontal_scrolling.xml
deleted file mode 100644
index 131a07e..0000000
--- a/design/tests/res/layout/design_appbar_horizontal_scrolling.xml
+++ /dev/null
@@ -1,89 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="200dp"
-        android:fitsSystemWindows="true">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/toolbar_layout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:fitsSystemWindows="true"
-            app:contentScrim="?attr/colorPrimary"
-            app:layout_scrollFlags="scroll|exitUntilCollapsed">
-
-            <HorizontalScrollView
-                android:id="@+id/hsv"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content">
-
-                <LinearLayout
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:orientation="horizontal">
-
-                    <View
-                        android:layout_width="200dp"
-                        android:layout_height="200dp"
-                        android:background="#ff0000"/>
-
-                    <View
-                        android:layout_width="900dp"
-                        android:layout_height="200dp"
-                        android:background="#00ff00"/>
-
-                    <View
-                        android:layout_width="900dp"
-                        android:layout_height="200dp"
-                        android:background="#0000ff"/>
-                </LinearLayout>
-            </HorizontalScrollView>
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_width="match_parent"
-                android:layout_height="?attr/actionBarSize"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-    </android.support.design.widget.AppBarLayout>
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        app:layout_behavior="@string/appbar_scrolling_view_behavior">
-
-        <Button
-            android:id="@+id/button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_margin="24dp"
-            android:text="@string/text1"/>
-
-    </FrameLayout>
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_pin.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_pin.xml
deleted file mode 100644
index e6cfb96..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_pin.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_pin_margins.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_pin_margins.xml
deleted file mode 100644
index 4eed2e2..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_pin_margins.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/appbar_height">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/collapsing_app_bar"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            app:layout_scrollFlags="scroll">
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_height="?attr/actionBarSize"
-                android:layout_width="match_parent"
-                android:layout_marginTop="20dp"
-                android:layout_marginBottom="20dp"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_pin_restore_test.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_pin_restore_test.xml
deleted file mode 100644
index fbe031b..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_pin_restore_test.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/coordinator_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/appbar_height"
-        android:fitsSystemWindows="true"
-        app:expanded="true">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/collapsing_app_bar"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            app:layout_scrollFlags="scroll|exitUntilCollapsed">
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_height="?attr/actionBarSize"
-                android:layout_width="match_parent"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_pin_with_fab.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_pin_with_fab.xml
deleted file mode 100644
index f5a2557..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_pin_with_fab.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <include layout="@layout/design_content_appbar_toolbar_collapse_pin" />
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        app:layout_anchor="@+id/app_bar"
-        app:layout_anchorGravity="bottom|right|end"
-        android:layout_marginRight="16dp"
-        android:clickable="true"
-        app:backgroundTint="#FF0000"/>
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_scroll.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_scroll.xml
deleted file mode 100644
index 8c68021..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_scroll.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/appbar_height"
-        android:fitsSystemWindows="true">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/collapsing_app_bar"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed">
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_height="?attr/actionBarSize"
-                android:layout_width="match_parent"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_scroll_enteralways.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_scroll_enteralways.xml
deleted file mode 100644
index 43a8d51..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_scroll_enteralways.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/appbar_height"
-        android:fitsSystemWindows="true">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/collapsing_app_bar"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            app:layout_scrollFlags="scroll|enterAlways">
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_height="?attr/actionBarSize"
-                android:layout_width="match_parent"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview" />
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_sole_toolbar.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_sole_toolbar.xml
deleted file mode 100644
index d2f3588..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_sole_toolbar.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/col"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:fitsSystemWindows="true"
-        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/collapsing_app_bar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:layout_scrollFlags="scroll|exitUntilCollapsed">
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_width="match_parent"
-                android:layout_height="?attr/actionBarSize"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview"/>
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_collapse_with_image.xml b/design/tests/res/layout/design_appbar_toolbar_collapse_with_image.xml
deleted file mode 100644
index a4d667f..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_collapse_with_image.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/appbar_height"
-        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
-        android:fitsSystemWindows="true">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/collapsing_app_bar"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            app:layout_scrollFlags="scroll|exitUntilCollapsed">
-
-            <ImageView
-                android:id="@+id/app_bar_image"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                app:layout_collapseMode="parallax"
-                android:src="@drawable/photo"
-                android:scaleType="centerCrop"
-                android:fitsSystemWindows="true"/>
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_width="match_parent"
-                android:layout_height="?attr/actionBarSize"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview"/>
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_appbar_toolbar_scroll_fitsystemwindows_parent.xml b/design/tests/res/layout/design_appbar_toolbar_scroll_fitsystemwindows_parent.xml
deleted file mode 100644
index b41ab95..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_scroll_fitsystemwindows_parent.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent">
-
-        <android.support.v7.widget.Toolbar
-            android:id="@+id/toolbar"
-            android:layout_height="?attr/actionBarSize"
-            android:layout_width="match_parent"
-            app:layout_scrollFlags="scroll|enterAlways"/>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview"/>
-
-</android.support.design.widget.CoordinatorLayout>
-
diff --git a/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_pinned.xml b/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_pinned.xml
deleted file mode 100644
index cbb5ee0..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_pinned.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent">
-
-        <android.support.v7.widget.Toolbar
-            android:id="@+id/toolbar"
-            android:layout_height="?attr/actionBarSize"
-            android:layout_width="match_parent"
-            app:layout_scrollFlags="scroll|enterAlways"/>
-
-        <android.support.design.widget.TabLayout
-            android:id="@+id/tabs"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:tabMode="scrollable"/>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview"/>
-
-</android.support.design.widget.CoordinatorLayout>
-
diff --git a/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_scroll.xml b/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_scroll.xml
deleted file mode 100644
index 49b5597..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_scroll.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent">
-
-        <android.support.v7.widget.Toolbar
-            android:id="@+id/toolbar"
-            android:layout_height="?attr/actionBarSize"
-            android:layout_width="match_parent"
-            app:layout_scrollFlags="scroll|enterAlways"/>
-
-        <android.support.design.widget.TabLayout
-            android:id="@+id/tabs"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:layout_scrollFlags="scroll|enterAlways"
-            app:tabMode="scrollable"/>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview"/>
-
-</android.support.design.widget.CoordinatorLayout>
-
diff --git a/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_scroll_snap.xml b/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_scroll_snap.xml
deleted file mode 100644
index 0d067b1..0000000
--- a/design/tests/res/layout/design_appbar_toolbar_scroll_tabs_scroll_snap.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent">
-
-        <android.support.v7.widget.Toolbar
-            android:id="@+id/toolbar"
-            android:layout_height="?attr/actionBarSize"
-            android:layout_width="match_parent"
-            app:layout_scrollFlags="scroll|enterAlways|snap"/>
-
-        <android.support.design.widget.TabLayout
-            android:id="@+id/tabs"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:layout_scrollFlags="scroll|enterAlways|snap"
-            app:tabMode="scrollable"/>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview"/>
-
-</android.support.design.widget.CoordinatorLayout>
-
diff --git a/design/tests/res/layout/design_appbar_with_scrollbars.xml b/design/tests/res/layout/design_appbar_with_scrollbars.xml
deleted file mode 100644
index 6c89a2a..0000000
--- a/design/tests/res/layout/design_appbar_with_scrollbars.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<android.support.design.widget.AppBarLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="200dp"
-    android:theme="@style/AppBarWithScrollbars"/>
\ No newline at end of file
diff --git a/design/tests/res/layout/design_bottom_navigation_view.xml b/design/tests/res/layout/design_bottom_navigation_view.xml
deleted file mode 100644
index 0e85aad..0000000
--- a/design/tests/res/layout/design_bottom_navigation_view.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-    <android.support.design.widget.BottomNavigationView
-        android:id="@+id/bottom_navigation"
-        android:layout_height="56dp"
-        android:layout_width="match_parent"
-        app:menu="@menu/bottom_navigation_view_content"
-        app:itemIconTint="@color/emerald_translucent"
-        app:itemTextColor="@color/emerald_text"
-        app:itemBackground="@color/sand_default" />
-</FrameLayout>
\ No newline at end of file
diff --git a/design/tests/res/layout/design_content_appbar_toolbar_collapse_pin.xml b/design/tests/res/layout/design_content_appbar_toolbar_collapse_pin.xml
deleted file mode 100644
index 961ce41..0000000
--- a/design/tests/res/layout/design_content_appbar_toolbar_collapse_pin.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<merge
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-    <android.support.design.widget.AppBarLayout
-        android:id="@+id/app_bar"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/appbar_height"
-        android:fitsSystemWindows="true">
-
-        <android.support.design.widget.CollapsingToolbarLayout
-            android:id="@+id/collapsing_app_bar"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            app:layout_scrollFlags="scroll|exitUntilCollapsed">
-
-            <android.support.v7.widget.Toolbar
-                android:id="@+id/toolbar"
-                android:layout_height="?attr/actionBarSize"
-                android:layout_width="match_parent"
-                app:layout_collapseMode="pin"/>
-
-        </android.support.design.widget.CollapsingToolbarLayout>
-
-    </android.support.design.widget.AppBarLayout>
-
-    <include layout="@layout/include_appbar_scrollview" />
-</merge>
\ No newline at end of file
diff --git a/design/tests/res/layout/design_fab.xml b/design/tests/res/layout/design_fab.xml
deleted file mode 100644
index 44fe826..0000000
--- a/design/tests/res/layout/design_fab.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-              xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:app="http://schemas.android.com/apk/res-auto"
-              android:id="@+id/container"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-
-    <!-- Dummy view to steal the focus -->
-    <ImageButton
-        android:id="@+id/dummy_focus_vew"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab_standard"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_margin="16dp"
-        android:src="@drawable/ic_add"/>
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab_tint"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_margin="16dp"
-        android:src="@drawable/ic_add"
-        app:backgroundTint="#FF00FF"/>
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab_state_tint"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_margin="16dp"
-        android:src="@drawable/ic_add"
-        app:backgroundTint="@color/fab_tint"/>
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/design_navigation_view.xml b/design/tests/res/layout/design_navigation_view.xml
deleted file mode 100644
index 4f7147d..0000000
--- a/design/tests/res/layout/design_navigation_view.xml
+++ /dev/null
@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.v4.widget.DrawerLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/drawer_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:fitsSystemWindows="true">
-    <!-- As the main content view, the view below consumes the entire
-         space available using match_parent in both dimensions. Note that
-         this child does not specify android:layout_gravity attribute. -->
-    <FrameLayout
-        android:id="@+id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <!-- android:layout_gravity="start" tells DrawerLayout to treat
-         this as a sliding drawer on the starting side, which is
-         left for left-to-right locales. The navigation view extends
-         the full height of the container. A
-         solid background is used for contrast with the content view.
-         android:fitsSystemWindows="true" tells the system to have
-         DrawerLayout span the full height of the screen, including the
-         system status bar on Lollipop+ versions of the plaform. -->
-    <android.support.design.widget.NavigationTestView
-        android:id="@+id/start_drawer"
-        android:layout_width="wrap_content"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:background="#333"
-        android:fitsSystemWindows="true"
-        app:menu="@menu/navigation_view_content"
-        app:itemIconTint="@color/emerald_translucent"
-        app:itemTextColor="@color/emerald_text"
-        app:itemBackground="@color/sand_default"
-        app:itemTextAppearance="@style/TextMediumStyle" />
-
-</android.support.v4.widget.DrawerLayout>
-
diff --git a/design/tests/res/layout/design_navigation_view_header1.xml b/design/tests/res/layout/design_navigation_view_header1.xml
deleted file mode 100644
index 2fd6f20..0000000
--- a/design/tests/res/layout/design_navigation_view_header1.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<View
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/header1"
-    android:layout_width="match_parent"
-    android:layout_height="120dip"
-    android:background="@color/test_red" />
-
diff --git a/design/tests/res/layout/design_navigation_view_header2.xml b/design/tests/res/layout/design_navigation_view_header2.xml
deleted file mode 100644
index 77ad32a..0000000
--- a/design/tests/res/layout/design_navigation_view_header2.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<View
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/header2"
-    android:layout_width="match_parent"
-    android:layout_height="100dip"
-    android:background="@color/test_blue" />
-
diff --git a/design/tests/res/layout/design_navigation_view_header3.xml b/design/tests/res/layout/design_navigation_view_header3.xml
deleted file mode 100644
index b1fd676..0000000
--- a/design/tests/res/layout/design_navigation_view_header3.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<View
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/header3"
-    android:layout_width="match_parent"
-    android:layout_height="80dip"
-    android:background="@color/test_green" />
-
diff --git a/design/tests/res/layout/design_navigation_view_header_switch.xml b/design/tests/res/layout/design_navigation_view_header_switch.xml
deleted file mode 100644
index 5bfe8fa..0000000
--- a/design/tests/res/layout/design_navigation_view_header_switch.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/header_frame"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:padding="16dp">
-
-    <android.support.v7.widget.SwitchCompat
-        android:id="@+id/header_toggle"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:fitsSystemWindows="true"/>
-
-</FrameLayout>
diff --git a/design/tests/res/layout/design_snackbar_with_fab.xml b/design/tests/res/layout/design_snackbar_with_fab.xml
deleted file mode 100644
index a06dc1b..0000000
--- a/design/tests/res/layout/design_snackbar_with_fab.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_gravity="bottom|end"
-        android:layout_margin="16dp"
-        android:src="@drawable/ic_add"
-        android:clickable="true" />
-
-</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/design/tests/res/layout/design_tab_item_custom.xml b/design/tests/res/layout/design_tab_item_custom.xml
deleted file mode 100644
index f6ba30b..0000000
--- a/design/tests/res/layout/design_tab_item_custom.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<View xmlns:android="http://schemas.android.com/apk/res/android"
-          android:id="@+id/my_custom_tab"
-          android:layout_width="match_parent"
-          android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/design/tests/res/layout/design_tabs.xml b/design/tests/res/layout/design_tabs.xml
deleted file mode 100644
index fbb24bd..0000000
--- a/design/tests/res/layout/design_tabs.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.TabLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content" />
diff --git a/design/tests/res/layout/design_tabs_fixed_width.xml b/design/tests/res/layout/design_tabs_fixed_width.xml
deleted file mode 100644
index 752034f..0000000
--- a/design/tests/res/layout/design_tabs_fixed_width.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Width is fixed to test scrolling -->
-<android.support.design.widget.TabLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/tabs"
-    android:layout_width="160dp"
-    android:layout_height="wrap_content"
-    app:tabMode="scrollable">
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 0" />
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 1" />
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 2" />
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 3" />
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 4" />
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 5" />
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 6" />
-
-    <android.support.design.widget.TabItem
-        android:text="Tab 7" />
-
-</android.support.design.widget.TabLayout>
diff --git a/design/tests/res/layout/design_tabs_items.xml b/design/tests/res/layout/design_tabs_items.xml
deleted file mode 100644
index e67f3b6..0000000
--- a/design/tests/res/layout/design_tabs_items.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.TabLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-    <android.support.design.widget.TabItem
-            android:text="@string/tab_layout_text"/>
-
-    <android.support.design.widget.TabItem
-            android:icon="@android:drawable/star_on"/>
-
-    <android.support.design.widget.TabItem
-            android:layout="@layout/design_tab_item_custom"/>
-
-</android.support.design.widget.TabLayout>
\ No newline at end of file
diff --git a/design/tests/res/layout/design_tabs_twice.xml b/design/tests/res/layout/design_tabs_twice.xml
deleted file mode 100644
index 1421c10..0000000
--- a/design/tests/res/layout/design_tabs_twice.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/container"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <android.support.design.widget.TabLayout
-        android:id="@+id/tabs_1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-        <android.support.design.widget.TabItem
-            android:text="@string/tab_layout_text"/>
-
-        <android.support.design.widget.TabItem
-            android:icon="@android:drawable/star_on"/>
-
-        <android.support.design.widget.TabItem
-            android:layout="@layout/design_tab_item_custom"/>
-
-    </android.support.design.widget.TabLayout>
-
-    <android.support.design.widget.TabLayout
-        android:id="@+id/tabs_2"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content" />
-
-</LinearLayout>
diff --git a/design/tests/res/layout/design_tabs_viewpager.xml b/design/tests/res/layout/design_tabs_viewpager.xml
deleted file mode 100644
index 9cc7bcb..0000000
--- a/design/tests/res/layout/design_tabs_viewpager.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/container"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical">
-
-    <android.support.v7.widget.Toolbar
-        android:id="@+id/toolbar"
-        android:layout_width="match_parent"
-        android:layout_height="?attr/actionBarSize"
-        android:background="?attr/colorPrimary"
-        app:contentInsetStart="72dp"/>
-
-    <include layout="@layout/tab_layout_unbound" />
-
-    <android.support.v4.view.ViewPager
-        android:id="@+id/tabs_viewpager"
-        android:layout_width="match_parent"
-        android:layout_height="0px"
-        android:layout_weight="1"/>
-
-</LinearLayout>
diff --git a/design/tests/res/layout/design_tabs_with_non_tabitems.xml b/design/tests/res/layout/design_tabs_with_non_tabitems.xml
deleted file mode 100644
index cb96715..0000000
--- a/design/tests/res/layout/design_tabs_with_non_tabitems.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.TabLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-
-    <TextView
-        android:text="@string/tab_layout_text"/>
-
-    <TextView
-        android:src="@android:drawable/star_on"/>
-
-    <include
-        layout="@layout/design_tab_item_custom"/>
-
-</android.support.design.widget.TabLayout>
\ No newline at end of file
diff --git a/design/tests/res/layout/design_text_input.xml b/design/tests/res/layout/design_text_input.xml
deleted file mode 100644
index 4dba825..0000000
--- a/design/tests/res/layout/design_text_input.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:app="http://schemas.android.com/apk/res-auto"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical"
-              android:padding="16dp">
-
-    <android.support.design.widget.TextInputLayout
-            android:id="@+id/textinput"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            app:errorEnabled="true">
-
-        <android.support.design.widget.TextInputEditText
-                android:id="@+id/textinput_edittext"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:imeOptions="flagNoExtractUi"
-                android:hint="@string/textinput_hint"/>
-
-    </android.support.design.widget.TextInputLayout>
-
-    <android.support.design.widget.TextInputLayout
-        android:id="@+id/textinput_password"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        app:passwordToggleEnabled="true">
-
-        <android.support.design.widget.TextInputEditText
-            android:id="@+id/textinput_edittext_pwd"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:imeOptions="flagNoExtractUi"
-            android:hint="@string/textinput_hint"
-            android:inputType="textPassword"/>
-
-    </android.support.design.widget.TextInputLayout>
-
-    <android.support.design.widget.TextInputLayout
-        android:id="@+id/textinput_noedittext"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-
-    <android.support.design.widget.TextInputLayout
-        android:id="@+id/textinput_with_text"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content">
-
-        <android.support.design.widget.TextInputEditText
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:imeOptions="flagNoExtractUi"
-            android:hint="@string/textinput_hint"
-            android:text="@string/snackbar_text"/>
-
-    </android.support.design.widget.TextInputLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/design/tests/res/layout/dynamic_coordinator_layout.xml b/design/tests/res/layout/dynamic_coordinator_layout.xml
deleted file mode 100644
index a2253c7..0000000
--- a/design/tests/res/layout/dynamic_coordinator_layout.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- ViewStub that will be inflated to a CoordinatorLayout at test runtime. -->
-<ViewStub
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/coordinator_stub"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:inflatedId="@+id/coordinator_layout"
-    android:fitsSystemWindows="true" />
diff --git a/design/tests/res/layout/frame_layout.xml b/design/tests/res/layout/frame_layout.xml
deleted file mode 100644
index 45b3474..0000000
--- a/design/tests/res/layout/frame_layout.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-             android:layout_width="match_parent"
-             android:layout_height="match_parent"/>
diff --git a/design/tests/res/layout/include_appbar_scrollview.xml b/design/tests/res/layout/include_appbar_scrollview.xml
deleted file mode 100644
index cd6eca2..0000000
--- a/design/tests/res/layout/include_appbar_scrollview.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<android.support.v4.widget.NestedScrollView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/scrolling_content"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    app:layout_behavior="@string/appbar_scrolling_view_behavior">
-
-    <LinearLayout
-        android:id="@+id/scrolling_content_inner"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical">
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_horizontal"
-            android:text="@string/scroll_top" />
-
-        <TextView
-            android:id="@+id/textview_dialogue"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:padding="16dp"/>
-
-        <TextView
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_horizontal"
-            android:text="@string/scroll_bottom" />
-
-    </LinearLayout>
-
-</android.support.v4.widget.NestedScrollView>
\ No newline at end of file
diff --git a/design/tests/res/layout/tab_layout_bound_max.xml b/design/tests/res/layout/tab_layout_bound_max.xml
deleted file mode 100644
index 9958edf..0000000
--- a/design/tests/res/layout/tab_layout_bound_max.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.TabLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:id="@+id/tabs"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        app:tabMode="scrollable"
-        app:tabContentStart="72dp"
-        app:tabMaxWidth="@dimen/tab_width_limit_medium" />
diff --git a/design/tests/res/layout/tab_layout_bound_min.xml b/design/tests/res/layout/tab_layout_bound_min.xml
deleted file mode 100644
index a05bd64..0000000
--- a/design/tests/res/layout/tab_layout_bound_min.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.TabLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:id="@+id/tabs"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        app:tabMode="scrollable"
-        app:tabContentStart="72dp"
-        app:tabMinWidth="@dimen/tab_width_limit_medium" />
diff --git a/design/tests/res/layout/tab_layout_bound_minmax.xml b/design/tests/res/layout/tab_layout_bound_minmax.xml
deleted file mode 100644
index 0e34286..0000000
--- a/design/tests/res/layout/tab_layout_bound_minmax.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.TabLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:id="@+id/tabs"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        app:tabMode="scrollable"
-        app:tabContentStart="72dp"
-        app:tabMinWidth="@dimen/tab_width_limit_small"
-        app:tabMaxWidth="@dimen/tab_width_limit_large" />
diff --git a/design/tests/res/layout/tab_layout_unbound.xml b/design/tests/res/layout/tab_layout_unbound.xml
deleted file mode 100644
index fb51d4d..0000000
--- a/design/tests/res/layout/tab_layout_unbound.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.TabLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:id="@+id/tabs"
-        android:layout_height="wrap_content"
-        android:layout_width="match_parent"
-        app:tabMode="scrollable"
-        app:tabContentStart="72dp"/>
diff --git a/design/tests/res/layout/test_design_bottom_sheet_behavior.xml b/design/tests/res/layout/test_design_bottom_sheet_behavior.xml
deleted file mode 100644
index 8a2835e..0000000
--- a/design/tests/res/layout/test_design_bottom_sheet_behavior.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<android.support.design.widget.CoordinatorLayout
-        android:id="@+id/coordinator"
-        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">
-
-    <LinearLayout
-            android:id="@+id/bottom_sheet"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical"
-            android:background="#00f"
-            app:layout_behavior="@string/bottom_sheet_behavior"
-            app:behavior_peekHeight="@dimen/bottom_sheet_peek_height"
-            app:behavior_hideable="true">
-
-    </LinearLayout>
-
-    <android.support.design.widget.FloatingActionButton
-            android:id="@+id/fab"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:src="@drawable/ic_add"
-            app:layout_anchor="@id/bottom_sheet"
-            app:layout_anchorGravity="top|end"
-            app:useCompatPadding="true"
-            app:backgroundTint="#f00"/>
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/test_design_bottom_sheet_behavior_with_insets.xml b/design/tests/res/layout/test_design_bottom_sheet_behavior_with_insets.xml
deleted file mode 100644
index 442654c..0000000
--- a/design/tests/res/layout/test_design_bottom_sheet_behavior_with_insets.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<android.support.design.widget.CoordinatorLayout
-        android:id="@+id/coordinator"
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:app="http://schemas.android.com/apk/res-auto"
-        android:fitsSystemWindows="true"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-    <LinearLayout
-            android:id="@+id/bottom_sheet"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical"
-            android:background="#00f"
-            app:layout_behavior="@string/bottom_sheet_behavior"
-            app:behavior_peekHeight="@dimen/bottom_sheet_peek_height"
-            app:behavior_hideable="true">
-
-        <View
-            android:id="@+id/bottom_sheet_content"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="#f00"/>
-
-    </LinearLayout>
-
-</android.support.design.widget.CoordinatorLayout>
diff --git a/design/tests/res/layout/test_design_snackbar.xml b/design/tests/res/layout/test_design_snackbar.xml
deleted file mode 100644
index cb3643a..0000000
--- a/design/tests/res/layout/test_design_snackbar.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:id="@+id/col"
-        android:fitsSystemWindows="true"/>
\ No newline at end of file
diff --git a/design/tests/res/layout/test_design_snackbar_fab.xml b/design/tests/res/layout/test_design_snackbar_fab.xml
deleted file mode 100644
index 68e5353..0000000
--- a/design/tests/res/layout/test_design_snackbar_fab.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<android.support.design.widget.CoordinatorLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:id="@+id/col">
-
-    <android.support.design.widget.FloatingActionButton
-        android:id="@+id/fab"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:layout_gravity="right|bottom"
-        android:src="@drawable/ic_add"/>
-
-</android.support.design.widget.CoordinatorLayout>
\ No newline at end of file
diff --git a/design/tests/res/menu/bottom_navigation_view_content.xml b/design/tests/res/menu/bottom_navigation_view_content.xml
deleted file mode 100644
index d61d6d8..0000000
--- a/design/tests/res/menu/bottom_navigation_view_content.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 Google Inc.
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
-      xmlns:app="http://schemas.android.com/apk/res-auto">
-    <item android:id="@+id/destination_home"
-          android:icon="@drawable/test_drawable_red"
-          android:title="@string/navigate_home"
-          app:contentDescription="@string/navigate_home"
-          app:tooltipText="@string/navigate_home"/>
-    <item android:id="@+id/destination_profile"
-          android:icon="@drawable/test_drawable_green"
-          android:title="@string/navigate_profile"
-          app:contentDescription="@string/navigate_profile"
-          app:tooltipText="@string/navigate_profile"/>
-    <item android:id="@+id/destination_people"
-          android:icon="@drawable/test_drawable_blue"
-          android:title="@string/navigate_people"
-          app:contentDescription="@string/navigate_people"
-          app:tooltipText="@string/navigate_people"/>
-</menu>
diff --git a/design/tests/res/menu/navigation_view_content.xml b/design/tests/res/menu/navigation_view_content.xml
deleted file mode 100644
index 25fb016..0000000
--- a/design/tests/res/menu/navigation_view_content.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 Google Inc.
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<menu
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto">
-    <group android:checkableBehavior="single">
-        <item android:id="@+id/destination_home"
-              android:title="@string/navigate_home"
-              android:icon="@drawable/test_drawable_red" />
-        <item android:id="@+id/destination_profile"
-              android:title="@string/navigate_profile"
-              android:icon="@drawable/test_drawable_green" />
-        <item android:id="@+id/destination_people"
-              android:title="@string/navigate_people"
-              android:icon="@drawable/test_drawable_blue"
-              app:actionLayout="@layout/action_layout" />
-        <item android:id="@+id/destination_settings"
-              android:title="@string/navigate_settings" />
-        <item android:id="@+id/destination_custom"
-              app:actionLayout="@layout/action_layout_custom" />
-    </group>
-</menu>
diff --git a/design/tests/res/values-sw600dp/dimens.xml b/design/tests/res/values-sw600dp/dimens.xml
deleted file mode 100644
index 67765c5..0000000
--- a/design/tests/res/values-sw600dp/dimens.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <dimen name="custom_snackbar_max_width">540dp</dimen>
-</resources>
\ No newline at end of file
diff --git a/design/tests/res/values/colors.xml b/design/tests/res/values/colors.xml
deleted file mode 100644
index ea8da2a..0000000
--- a/design/tests/res/values/colors.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <color name="emerald_translucent">#8020A060</color>
-    <color name="emerald_text">#30B050</color>
-    <color name="red_translucent">#90FF2040</color>
-
-    <color name="lilac_default">#F080F0</color>
-    <color name="lilac_disabled">#F0A0FF</color>
-    <color name="sand_default">#F0B000</color>
-    <color name="sand_disabled">#FFC080</color>
-    <color name="sand_checked">#FFD0A0</color>
-
-    <color name="test_red">#FF6030</color>
-    <color name="test_green">#50E080</color>
-    <color name="test_blue">#3050CF</color>
-</resources>
diff --git a/design/tests/res/values/dimens.xml b/design/tests/res/values/dimens.xml
deleted file mode 100644
index 37c1f48..0000000
--- a/design/tests/res/values/dimens.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <dimen name="tab_width_limit_small">80dip</dimen>
-    <dimen name="tab_width_limit_medium">100dip</dimen>
-    <dimen name="tab_width_limit_large">120dip</dimen>
-    <dimen name="bottom_sheet_peek_height">256dp</dimen>
-
-    <dimen name="text_small_size">16sp</dimen>
-    <dimen name="text_medium_size">20sp</dimen>
-
-    <dimen name="drawable_small_size">12dip</dimen>
-    <dimen name="drawable_medium_size">16dip</dimen>
-    <dimen name="drawable_large_size">20dip</dimen>
-
-    <dimen name="appbar_height">160dip</dimen>
-    <dimen name="fab_margin">32dip</dimen>
-
-    <dimen name="fab_mini_height">40dp</dimen>
-    <dimen name="fab_normal_height">56dip</dimen>
-
-    <dimen name="custom_snackbar_max_width">-1px</dimen>
-</resources>
\ No newline at end of file
diff --git a/design/tests/res/values/ids.xml b/design/tests/res/values/ids.xml
deleted file mode 100644
index 52b8356..0000000
--- a/design/tests/res/values/ids.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <item name="page_0" type="id"/>
-    <item name="page_1" type="id"/>
-    <item name="page_2" type="id"/>
-    <item name="page_3" type="id"/>
-    <item name="page_4" type="id"/>
-    <item name="page_5" type="id"/>
-    <item name="page_6" type="id"/>
-    <item name="page_7" type="id"/>
-    <item name="page_8" type="id"/>
-    <item name="page_9" type="id"/>
-    <item name="textinputlayout" type="id"/>
-    <item name="textinputedittext" type="id"/>
-</resources>
\ No newline at end of file
diff --git a/design/tests/res/values/strings.xml b/design/tests/res/values/strings.xml
deleted file mode 100644
index 02763ec..0000000
--- a/design/tests/res/values/strings.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <string name="tab_layout_text">Tab text!</string>
-
-    <string name="navigate_home">Home</string>
-    <string name="navigate_profile">Profile</string>
-    <string name="navigate_people">People</string>
-    <string name="navigate_custom">Custom</string>
-    <string name="navigate_settings">Settings</string>
-
-    <string name="snackbar_text">This is a test message</string>
-    <string name="snackbar_action">Undo</string>
-
-    <string name="text1">Text</string>
-
-    <string name="scroll_top">Top</string>
-    <string name="scroll_bottom">Bottom</string>
-    <string name="design_appbar_collapsing_toolbar_pin">AppBar/Collapsing Toolbar (pinned)</string>
-    <string name="design_appbar_collapsing_toolbar_scroll">AppBar/Collapsing Toolbar (scroll off)</string>
-    <string name="design_appbar_collapsing_toolbar_pin_fab">AppBar/Collapsing Toolbar (pinned with FAB)</string>
-    <string name="design_appbar_toolbar_scroll_tabs_scroll">AppBar/Toolbar Scroll + Tabs Scroll</string>
-    <string name="design_appbar_toolbar_scroll_tabs_scroll_snap">AppBar/Toolbar Scroll + Tabs Scroll + Snap</string>
-    <string name="design_appbar_toolbar_scroll_tabs_pin">AppBar/Toolbar Scroll + Tabs Pin</string>
-    <string name="design_appbar_collapsing_toolbar_pin_margins">AppBar/Collapsing Toolbar (pinned + margins)</string>
-    <string name="design_appbar_collapsing_toolbar_with_image">AppBar/Collapsing Toolbar + Parallax Image</string>
-    <string name="design_appbar_anchored_fab_margin_bottom">AppBar + anchored FAB with bottom margin</string>
-    <string name="design_appbar_anchored_fab_margin_top">AppBar + anchored FAB with top margin</string>
-    <string name="design_appbar_anchored_fab_margin_left">AppBar + anchored FAB with left margin</string>
-    <string name="design_appbar_anchored_fab_margin_right">AppBar + anchored FAB with right margin</string>
-
-    <string name="design_appbar_dodge_left">AppBar + FABs with dodge on left</string>
-    <string name="design_appbar_dodge_right">AppBar + FABs with dodge on right</string>
-
-    <string name="textinput_hint">Hint to the user</string>
-
-</resources>
\ No newline at end of file
diff --git a/design/tests/res/values/styles.xml b/design/tests/res/values/styles.xml
deleted file mode 100644
index eb6aee6..0000000
--- a/design/tests/res/values/styles.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <style name="TextSmallStyle" parent="@android:style/TextAppearance">
-        <item name="android:textSize">@dimen/text_small_size</item>
-    </style>
-
-    <style name="TextMediumStyle" parent="@android:style/TextAppearance.Medium">
-        <item name="android:textSize">@dimen/text_medium_size</item>
-    </style>
-
-    <style name="Theme.TranslucentStatus" parent="Theme.AppCompat.Light.NoActionBar">
-        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
-        <item name="android:statusBarColor">@android:color/transparent</item>
-    </style>
-
-    <style name="Theme.TranslucentNavBar" parent="Theme.AppCompat.Light.NoActionBar">
-        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
-    </style>
-
-
-    <style name="TextAppearanceWithThemedCslTextColor" parent="@android:style/TextAppearance">
-        <item name="android:textColor">@color/color_state_list_themed</item>
-    </style>
-
-    <style name="AppBarWithScrollbars" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
-        <item name="android:scrollbars">horizontal</item>
-    </style>
-</resources>
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/testutils/AppBarLayoutMatchers.java b/design/tests/src/android/support/design/testutils/AppBarLayoutMatchers.java
deleted file mode 100755
index 4d6fc63..0000000
--- a/design/tests/src/android/support/design/testutils/AppBarLayoutMatchers.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import android.support.design.widget.AppBarLayout;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-
-public class AppBarLayoutMatchers {
-
-    /**
-     * Returns a matcher that matches AppBarLayouts which are collapsed.
-     */
-    public static Matcher isCollapsed() {
-        return new TypeSafeMatcher<AppBarLayout>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("AppBarLayout is collapsed");
-            }
-
-            @Override
-            protected boolean matchesSafely(AppBarLayout item) {
-                return item.getBottom() == (item.getHeight() - item.getTotalScrollRange());
-            }
-        };
-    }
-
-}
diff --git a/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java b/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java
deleted file mode 100644
index 31b527f..0000000
--- a/design/tests/src/android/support/design/testutils/BottomNavigationViewActions.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-
-import android.content.res.ColorStateList;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.IdRes;
-import android.support.annotation.Nullable;
-import android.support.design.widget.BottomNavigationView;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.view.View;
-
-import org.hamcrest.Matcher;
-
-
-public class BottomNavigationViewActions {
-    /**
-     * Sets item icon tint list on the content of the bottom navigation view.
-     */
-    public static ViewAction setItemIconTintList(@Nullable final ColorStateList tint) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set item icon tint list";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                BottomNavigationView navigationView = (BottomNavigationView) view;
-                navigationView.setItemIconTintList(tint);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets icon for the menu item of the navigation view.
-     */
-    public static ViewAction setIconForMenuItem(@IdRes final int menuItemId,
-            final Drawable iconDrawable) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set menu item icon";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                BottomNavigationView navigationView = (BottomNavigationView) view;
-                navigationView.getMenu().findItem(menuItemId).setIcon(iconDrawable);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/Cheeses.java b/design/tests/src/android/support/design/testutils/Cheeses.java
deleted file mode 100644
index 6215569..0000000
--- a/design/tests/src/android/support/design/testutils/Cheeses.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-public class Cheeses {
-
-    public static final String[] sCheeseStrings = {
-            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
-            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
-            "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
-            "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
-            "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
-            "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
-            "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
-            "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
-            "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
-            "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
-            "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
-            "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
-            "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
-            "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
-            "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
-            "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
-            "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
-            "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
-            "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
-            "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
-            "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
-            "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
-            "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
-            "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
-            "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
-            "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
-            "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
-            "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
-            "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
-            "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
-            "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
-            "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
-            "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
-            "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
-            "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
-            "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
-            "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
-            "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
-            "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
-            "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
-            "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
-            "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
-            "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
-            "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
-            "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
-            "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
-            "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
-            "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
-            "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
-            "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
-            "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
-            "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
-            "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
-            "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
-            "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
-            "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
-            "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
-            "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
-            "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
-            "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
-            "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
-            "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
-            "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
-            "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
-            "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
-            "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
-            "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
-            "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
-            "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
-            "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
-            "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
-            "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
-            "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
-            "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
-            "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
-            "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
-            "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
-            "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
-            "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
-            "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
-            "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
-            "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
-            "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
-            "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
-            "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
-            "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
-            "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
-            "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
-            "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
-            "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
-            "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
-            "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
-            "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
-            "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
-            "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
-            "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
-            "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
-            "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
-            "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
-            "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
-            "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
-            "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
-            "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
-            "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
-            "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
-            "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
-            "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
-            "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
-            "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
-            "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
-            "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
-            "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
-            "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
-            "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
-            "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
-            "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
-            "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
-            "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
-            "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
-            "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
-            "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
-            "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
-            "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
-            "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
-            "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
-            "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
-            "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
-            "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
-            "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
-            "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
-    };
-
-}
diff --git a/design/tests/src/android/support/design/testutils/CollapsingToolbarLayoutActions.java b/design/tests/src/android/support/design/testutils/CollapsingToolbarLayoutActions.java
deleted file mode 100644
index 71dd150..0000000
--- a/design/tests/src/android/support/design/testutils/CollapsingToolbarLayoutActions.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-
-import android.support.annotation.ColorInt;
-import android.support.design.widget.CollapsingToolbarLayout;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.view.View;
-
-import org.hamcrest.Matcher;
-
-public class CollapsingToolbarLayoutActions {
-
-    public static ViewAction setContentScrimColor(@ColorInt final int color) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set the content scrim to a color";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-                CollapsingToolbarLayout ctl = (CollapsingToolbarLayout) view;
-                ctl.setContentScrimColor(color);
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/DrawerLayoutActions.java b/design/tests/src/android/support/design/testutils/DrawerLayoutActions.java
deleted file mode 100755
index e4ea867..0000000
--- a/design/tests/src/android/support/design/testutils/DrawerLayoutActions.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.v4.widget.DrawerLayout;
-import android.view.View;
-import org.hamcrest.Matcher;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-
-public class DrawerLayoutActions {
-    /**
-     * Opens the drawer at the specified edge gravity.
-     */
-    public static ViewAction openDrawer(final int drawerEdgeGravity) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(DrawerLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Opens the drawer";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                DrawerLayout drawerLayout = (DrawerLayout) view;
-                drawerLayout.openDrawer(drawerEdgeGravity);
-
-                // Wait for a full second to let the inner ViewDragHelper complete the operation
-                uiController.loopMainThreadForAtLeast(1000);
-            }
-        };
-    }
-
-    /**
-     * Closes the drawer at the specified edge gravity.
-     */
-    public static ViewAction closeDrawer(final int drawerEdgeGravity) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(DrawerLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Closes the drawer";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                DrawerLayout drawerLayout = (DrawerLayout) view;
-                drawerLayout.closeDrawer(drawerEdgeGravity);
-
-                // Wait for a full second to let the inner ViewDragHelper complete the operation
-                uiController.loopMainThreadForAtLeast(1000);
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/FloatingActionButtonActions.java b/design/tests/src/android/support/design/testutils/FloatingActionButtonActions.java
deleted file mode 100644
index a166f6b..0000000
--- a/design/tests/src/android/support/design/testutils/FloatingActionButtonActions.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-
-import android.content.res.ColorStateList;
-import android.support.annotation.ColorInt;
-import android.support.annotation.DrawableRes;
-import android.support.design.widget.CoordinatorLayout;
-import android.support.design.widget.FloatingActionButton;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.view.View;
-
-import org.hamcrest.Matcher;
-
-public class FloatingActionButtonActions {
-
-    public static ViewAction setBackgroundTintColor(@ColorInt final int color) {
-        return setBackgroundTintList(ColorStateList.valueOf(color));
-    }
-
-    public static ViewAction setBackgroundTintList(@ColorInt final ColorStateList tint) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(FloatingActionButton.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets FloatingActionButton background tint";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                fab.setBackgroundTintList(tint);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setImageResource(@DrawableRes final int resId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(FloatingActionButton.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets FloatingActionButton image resource";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                fab.setImageResource(resId);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setSize(@FloatingActionButton.Size final int size) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(FloatingActionButton.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets FloatingActionButton size";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                fab.setSize(size);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setCustomSize(final int size) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(FloatingActionButton.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets FloatingActionButton custom size";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                fab.setCustomSize(size);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setCompatElevation(final float size) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(FloatingActionButton.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets FloatingActionButton elevation";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                fab.setCompatElevation(size);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setLayoutGravity(final int gravity) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(View.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets Views layout_gravity";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                CoordinatorLayout.LayoutParams lp =
-                        (CoordinatorLayout.LayoutParams) view.getLayoutParams();
-                lp.gravity = gravity;
-                view.requestLayout();
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction hideThenShow(final int animDuration) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(FloatingActionButton.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Calls hide() then show()";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                FloatingActionButton fab = (FloatingActionButton) view;
-                fab.hide();
-                fab.show();
-
-                uiController.loopMainThreadForAtLeast(animDuration + 100);
-            }
-        };
-    }
-
-    public static ViewAction showThenHide(final int animDuration) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(FloatingActionButton.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Calls show() then hide()";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                FloatingActionButton fab = (FloatingActionButton) view;
-                fab.show();
-                fab.hide();
-
-                uiController.loopMainThreadForAtLeast(animDuration + 50);
-            }
-        };
-    }
-
-}
diff --git a/design/tests/src/android/support/design/testutils/NavigationViewActions.java b/design/tests/src/android/support/design/testutils/NavigationViewActions.java
deleted file mode 100644
index 6a05fab..0000000
--- a/design/tests/src/android/support/design/testutils/NavigationViewActions.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-
-import android.content.res.ColorStateList;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.IdRes;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.StyleRes;
-import android.support.design.widget.NavigationView;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.view.LayoutInflater;
-import android.view.View;
-
-import org.hamcrest.Matcher;
-
-public class NavigationViewActions {
-    /**
-     * Sets item text appearance on the content of the navigation view.
-     */
-    public static ViewAction setItemTextAppearance(final @StyleRes int resId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set item text appearance";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.setItemTextAppearance(resId);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets item text color on the content of the navigation view.
-     */
-    public static ViewAction setItemTextColor(final ColorStateList textColor) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set item text color";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.setItemTextColor(textColor);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets item background on the content of the navigation view.
-     */
-    public static ViewAction setItemBackground(final @Nullable Drawable itemBackground) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set item background";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.setItemBackground(itemBackground);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets item background on the content of the navigation view.
-     */
-    public static ViewAction setItemBackgroundResource(final @DrawableRes int resId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set item background";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.setItemBackgroundResource(resId);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets item icon tint list on the content of the navigation view.
-     */
-    public static ViewAction setItemIconTintList(final @Nullable ColorStateList tint) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set item icon tint list";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.setItemIconTintList(tint);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Add the specified view as a header to the navigation view.
-     */
-    public static ViewAction addHeaderView(final @NonNull LayoutInflater inflater,
-            final @LayoutRes int res) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Add header view";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.addHeaderView(inflater.inflate(res, null, false));
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Inflates a view from the specified layout ID and adds it as a header to the navigation view.
-     */
-    public static ViewAction inflateHeaderView(final @LayoutRes int res) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Inflate and add header view";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.inflateHeaderView(res);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Removes a previously added header view from the navigation view.
-     */
-    public static ViewAction removeHeaderView(final @Nullable View headerView) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Remove header view";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.removeHeaderView(headerView);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets checked item on the navigation view.
-     */
-    public static ViewAction setCheckedItem(final @IdRes int id) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set checked item";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.setCheckedItem(id);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets icon for the menu item of the navigation view.
-     */
-    public static ViewAction setIconForMenuItem(final @IdRes int menuItemId,
-            final Drawable iconDrawable) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set menu item icon";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.getMenu().findItem(menuItemId).setIcon(iconDrawable);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Removes the specified menu item from the navigation view.
-     *
-     * @param menuItemId The ID of the menu item to be removed.
-     */
-    public static ViewAction removeMenuItem(final @IdRes int menuItemId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(NavigationView.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Remove menu item " + menuItemId;
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-                NavigationView navigationView = (NavigationView) view;
-                navigationView.getMenu().removeItem(menuItemId);
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-}
diff --git a/design/tests/src/android/support/design/testutils/Shakespeare.java b/design/tests/src/android/support/design/testutils/Shakespeare.java
deleted file mode 100644
index 285a185..0000000
--- a/design/tests/src/android/support/design/testutils/Shakespeare.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-public final class Shakespeare {
-    /**
-     * Our data, part 1.
-     */
-    public static final String[] TITLES = {
-            "Henry IV (1)",
-            "Henry V",
-            "Henry VIII",
-            "Richard II",
-            "Richard III",
-            "Merchant of Venice",
-            "Othello",
-            "King Lear"
-    };
-
-    /**
-     * Our data, part 2.
-     */
-    public static final String[] DIALOGUE = {
-            "So shaken as we are, so wan with care," +
-            "Find we a time for frighted peace to pant," +
-            "And breathe short-winded accents of new broils" +
-            "To be commenced in strands afar remote." +
-            "No more the thirsty entrance of this soil" +
-            "Shall daub her lips with her own children's blood;" +
-            "Nor more shall trenching war channel her fields," +
-            "Nor bruise her flowerets with the armed hoofs" +
-            "Of hostile paces: those opposed eyes," +
-            "Which, like the meteors of a troubled heaven," +
-            "All of one nature, of one substance bred," +
-            "Did lately meet in the intestine shock" +
-            "And furious close of civil butchery" +
-            "Shall now, in mutual well-beseeming ranks," +
-            "March all one way and be no more opposed" +
-            "Against acquaintance, kindred and allies:" +
-            "The edge of war, like an ill-sheathed knife," +
-            "No more shall cut his master. Therefore, friends," +
-            "As far as to the sepulchre of Christ," +
-            "Whose soldier now, under whose blessed cross" +
-            "We are impressed and engaged to fight," +
-            "Forthwith a power of English shall we levy;" +
-            "Whose arms were moulded in their mothers' womb" +
-            "To chase these pagans in those holy fields" +
-            "Over whose acres walk'd those blessed feet" +
-            "Which fourteen hundred years ago were nail'd" +
-            "For our advantage on the bitter cross." +
-            "But this our purpose now is twelve month old," +
-            "And bootless 'tis to tell you we will go:" +
-            "Therefore we meet not now. Then let me hear" +
-            "Of you, my gentle cousin Westmoreland," +
-            "What yesternight our council did decree" +
-            "In forwarding this dear expedience.",
-
-            "Hear him but reason in divinity," +
-            "And all-admiring with an inward wish" +
-            "You would desire the king were made a prelate:" +
-            "Hear him debate of commonwealth affairs," +
-            "You would say it hath been all in all his study:" +
-            "List his discourse of war, and you shall hear" +
-            "A fearful battle render'd you in music:" +
-            "Turn him to any cause of policy," +
-            "The Gordian knot of it he will unloose," +
-            "Familiar as his garter: that, when he speaks," +
-            "The air, a charter'd libertine, is still," +
-            "And the mute wonder lurketh in men's ears," +
-            "To steal his sweet and honey'd sentences;" +
-            "So that the art and practic part of life" +
-            "Must be the mistress to this theoric:" +
-            "Which is a wonder how his grace should glean it," +
-            "Since his addiction was to courses vain," +
-            "His companies unletter'd, rude and shallow," +
-            "His hours fill'd up with riots, banquets, sports," +
-            "And never noted in him any study," +
-            "Any retirement, any sequestration" +
-            "From open haunts and popularity.",
-
-            "I come no more to make you laugh: things now," +
-            "That bear a weighty and a serious brow," +
-            "Sad, high, and working, full of state and woe," +
-            "Such noble scenes as draw the eye to flow," +
-            "We now present. Those that can pity, here" +
-            "May, if they think it well, let fall a tear;" +
-            "The subject will deserve it. Such as give" +
-            "Their money out of hope they may believe," +
-            "May here find truth too. Those that come to see" +
-            "Only a show or two, and so agree" +
-            "The play may pass, if they be still and willing," +
-            "I'll undertake may see away their shilling" +
-            "Richly in two short hours. Only they" +
-            "That come to hear a merry bawdy play," +
-            "A noise of targets, or to see a fellow" +
-            "In a long motley coat guarded with yellow," +
-            "Will be deceived; for, gentle hearers, know," +
-            "To rank our chosen truth with such a show" +
-            "As fool and fight is, beside forfeiting" +
-            "Our own brains, and the opinion that we bring," +
-            "To make that only true we now intend," +
-            "Will leave us never an understanding friend." +
-            "Therefore, for goodness' sake, and as you are known" +
-            "The first and happiest hearers of the town," +
-            "Be sad, as we would make ye: think ye see" +
-            "The very persons of our noble story" +
-            "As they were living; think you see them great," +
-            "And follow'd with the general throng and sweat" +
-            "Of thousand friends; then in a moment, see" +
-            "How soon this mightiness meets misery:" +
-            "And, if you can be merry then, I'll say" +
-            "A man may weep upon his wedding-day.",
-
-            "First, heaven be the record to my speech!" +
-            "In the devotion of a subject's love," +
-            "Tendering the precious safety of my prince," +
-            "And free from other misbegotten hate," +
-            "Come I appellant to this princely presence." +
-            "Now, Thomas Mowbray, do I turn to thee," +
-            "And mark my greeting well; for what I speak" +
-            "My body shall make good upon this earth," +
-            "Or my divine soul answer it in heaven." +
-            "Thou art a traitor and a miscreant," +
-            "Too good to be so and too bad to live," +
-            "Since the more fair and crystal is the sky," +
-            "The uglier seem the clouds that in it fly." +
-            "Once more, the more to aggravate the note," +
-            "With a foul traitor's name stuff I thy throat;" +
-            "And wish, so please my sovereign, ere I move," +
-            "What my tongue speaks my right drawn sword may prove.",
-
-            "Now is the winter of our discontent" +
-            "Made glorious summer by this sun of York;" +
-            "And all the clouds that lour'd upon our house" +
-            "In the deep bosom of the ocean buried." +
-            "Now are our brows bound with victorious wreaths;" +
-            "Our bruised arms hung up for monuments;" +
-            "Our stern alarums changed to merry meetings," +
-            "Our dreadful marches to delightful measures." +
-            "Grim-visaged war hath smooth'd his wrinkled front;" +
-            "And now, instead of mounting barded steeds" +
-            "To fright the souls of fearful adversaries," +
-            "He capers nimbly in a lady's chamber" +
-            "To the lascivious pleasing of a lute." +
-            "But I, that am not shaped for sportive tricks," +
-            "Nor made to court an amorous looking-glass;" +
-            "I, that am rudely stamp'd, and want love's majesty" +
-            "To strut before a wanton ambling nymph;" +
-            "I, that am curtail'd of this fair proportion," +
-            "Cheated of feature by dissembling nature," +
-            "Deformed, unfinish'd, sent before my time" +
-            "Into this breathing world, scarce half made up," +
-            "And that so lamely and unfashionable" +
-            "That dogs bark at me as I halt by them;" +
-            "Why, I, in this weak piping time of peace," +
-            "Have no delight to pass away the time," +
-            "Unless to spy my shadow in the sun" +
-            "And descant on mine own deformity:" +
-            "And therefore, since I cannot prove a lover," +
-            "To entertain these fair well-spoken days," +
-            "I am determined to prove a villain" +
-            "And hate the idle pleasures of these days." +
-            "Plots have I laid, inductions dangerous," +
-            "By drunken prophecies, libels and dreams," +
-            "To set my brother Clarence and the king" +
-            "In deadly hate the one against the other:" +
-            "And if King Edward be as true and just" +
-            "As I am subtle, false and treacherous," +
-            "This day should Clarence closely be mew'd up," +
-            "About a prophecy, which says that 'G'" +
-            "Of Edward's heirs the murderer shall be." +
-            "Dive, thoughts, down to my soul: here" +
-            "Clarence comes.",
-
-            "To bait fish withal: if it will feed nothing else," +
-            "it will feed my revenge. He hath disgraced me, and" +
-            "hindered me half a million; laughed at my losses," +
-            "mocked at my gains, scorned my nation, thwarted my" +
-            "bargains, cooled my friends, heated mine" +
-            "enemies; and what's his reason? I am a Jew. Hath" +
-            "not a Jew eyes? hath not a Jew hands, organs," +
-            "dimensions, senses, affections, passions? fed with" +
-            "the same food, hurt with the same weapons, subject" +
-            "to the same diseases, healed by the same means," +
-            "warmed and cooled by the same winter and summer, as" +
-            "a Christian is? If you prick us, do we not bleed?" +
-            "if you tickle us, do we not laugh? if you poison" +
-            "us, do we not die? and if you wrong us, shall we not" +
-            "revenge? If we are like you in the rest, we will" +
-            "resemble you in that. If a Jew wrong a Christian," +
-            "what is his humility? Revenge. If a Christian" +
-            "wrong a Jew, what should his sufferance be by" +
-            "Christian example? Why, revenge. The villany you" +
-            "teach me, I will execute, and it shall go hard but I" +
-            "will better the instruction.",
-
-            "Virtue! a fig! 'tis in ourselves that we are thus" +
-            "or thus. Our bodies are our gardens, to the which" +
-            "our wills are gardeners: so that if we will plant" +
-            "nettles, or sow lettuce, set hyssop and weed up" +
-            "thyme, supply it with one gender of herbs, or" +
-            "distract it with many, either to have it sterile" +
-            "with idleness, or manured with industry, why, the" +
-            "power and corrigible authority of this lies in our" +
-            "wills. If the balance of our lives had not one" +
-            "scale of reason to poise another of sensuality, the" +
-            "blood and baseness of our natures would conduct us" +
-            "to most preposterous conclusions: but we have" +
-            "reason to cool our raging motions, our carnal" +
-            "stings, our unbitted lusts, whereof I take this that" +
-            "you call love to be a sect or scion.",
-
-            "Blow, winds, and crack your cheeks! rage! blow!" +
-            "You cataracts and hurricanoes, spout" +
-            "Till you have drench'd our steeples, drown'd the cocks!" +
-            "You sulphurous and thought-executing fires," +
-            "Vaunt-couriers to oak-cleaving thunderbolts," +
-            "Singe my white head! And thou, all-shaking thunder," +
-            "Smite flat the thick rotundity o' the world!" +
-            "Crack nature's moulds, an germens spill at once," +
-            "That make ingrateful man!"
-    };
-}
diff --git a/design/tests/src/android/support/design/testutils/SnackbarUtils.java b/design/tests/src/android/support/design/testutils/SnackbarUtils.java
deleted file mode 100644
index 04aa878..0000000
--- a/design/tests/src/android/support/design/testutils/SnackbarUtils.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.testutils;
-
-import static android.support.design.testutils.TestUtilsActions.waitUntilIdle;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.widget.BaseTransientBottomBar;
-import android.support.design.widget.Snackbar;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingResource;
-
-public class SnackbarUtils {
-    public interface TransientBottomBarAction {
-        void perform() throws Throwable;
-    }
-
-    private static class TransientBottomBarShownCallback
-            extends BaseTransientBottomBar.BaseCallback<BaseTransientBottomBar>
-            implements IdlingResource {
-        private boolean mIsShown = false;
-
-        @Nullable
-        private IdlingResource.ResourceCallback mCallback;
-
-        private boolean mNeedsIdle = false;
-
-        @Override
-        public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
-            mCallback = resourceCallback;
-        }
-
-        @Override
-        public String getName() {
-            return "Transient bottom bar shown callback";
-        }
-
-        @Override
-        public boolean isIdleNow() {
-            if (!mNeedsIdle) {
-                return true;
-            } else {
-                return mIsShown;
-            }
-        }
-
-        @Override
-        public void onShown(BaseTransientBottomBar transientBottomBar) {
-            mIsShown = true;
-            if (mCallback != null) {
-                mCallback.onTransitionToIdle();
-            }
-        }
-    }
-
-    private static class TransientBottomBarDismissedCallback
-            extends BaseTransientBottomBar.BaseCallback<BaseTransientBottomBar>
-            implements IdlingResource {
-        private boolean mIsDismissed = false;
-
-        @Nullable
-        private IdlingResource.ResourceCallback mCallback;
-
-        private boolean mNeedsIdle = false;
-
-        @Override
-        public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
-            mCallback = resourceCallback;
-        }
-
-        @Override
-        public String getName() {
-            return "Transient bottom bar dismissed callback";
-        }
-
-        @Override
-        public boolean isIdleNow() {
-            if (!mNeedsIdle) {
-                return true;
-            } else {
-                return mIsDismissed;
-            }
-        }
-
-        @Override
-        public void onDismissed(BaseTransientBottomBar transientBottomBar,
-                @DismissEvent int event) {
-            mIsDismissed = true;
-            if (mCallback != null) {
-                mCallback.onTransitionToIdle();
-            }
-        }
-    }
-
-    /**
-     * Helper method that shows that specified {@link Snackbar} and waits until
-     * it has been fully shown.
-     */
-    public static void showTransientBottomBarAndWaitUntilFullyShown(
-            @NonNull BaseTransientBottomBar transientBottomBar) {
-        TransientBottomBarShownCallback callback = new TransientBottomBarShownCallback();
-        transientBottomBar.addCallback(callback);
-        try {
-            // Register our listener as idling resource so that Espresso waits until the
-            // the bar has been fully shown
-            Espresso.registerIdlingResources(callback);
-            // Show the bar
-            transientBottomBar.show();
-            // Mark the callback to require waiting for idle state
-            callback.mNeedsIdle = true;
-            // Perform a dummy Espresso action that loops until the UI thread is idle. This
-            // effectively blocks us until the Snackbar has completed its sliding animation.
-            onView(isRoot()).perform(waitUntilIdle());
-            callback.mNeedsIdle = false;
-        } finally {
-            // Unregister our idling resource
-            Espresso.unregisterIdlingResources(callback);
-            // And remove our tracker listener from Snackbar
-            transientBottomBar.removeCallback(callback);
-        }
-    }
-
-    /**
-     * Helper method that dismissed that specified {@link Snackbar} and waits until
-     * it has been fully dismissed.
-     */
-    public static void dismissTransientBottomBarAndWaitUntilFullyDismissed(
-            @NonNull final BaseTransientBottomBar transientBottomBar) throws Throwable {
-        performActionAndWaitUntilFullyDismissed(transientBottomBar,
-                new TransientBottomBarAction() {
-                    @Override
-                    public void perform() throws Throwable {
-                        transientBottomBar.dismiss();
-                    }
-                });
-    }
-
-    /**
-     * Helper method that dismissed that specified {@link Snackbar} and waits until
-     * it has been fully dismissed.
-     */
-    public static void performActionAndWaitUntilFullyDismissed(
-            @NonNull BaseTransientBottomBar transientBottomBar,
-            @NonNull TransientBottomBarAction action) throws Throwable {
-        TransientBottomBarDismissedCallback callback = new TransientBottomBarDismissedCallback();
-        transientBottomBar.addCallback(callback);
-        try {
-            // Register our listener as idling resource so that Espresso waits until the
-            // the bar has been fully dismissed
-            Espresso.registerIdlingResources(callback);
-            // Run the action
-            action.perform();
-            // Mark the callback to require waiting for idle state
-            callback.mNeedsIdle = true;
-            // Perform a dummy Espresso action that loops until the UI thread is idle. This
-            // effectively blocks us until the Snackbar has completed its sliding animation.
-            onView(isRoot()).perform(waitUntilIdle());
-            callback.mNeedsIdle = false;
-        } finally {
-            // Unregister our idling resource
-            Espresso.unregisterIdlingResources(callback);
-            // And remove our tracker listener from Snackbar
-            transientBottomBar.removeCallback(null);
-        }
-    }
-
-    /**
-     * Helper method that waits until the given bar has been fully dismissed.
-     */
-    public static void waitUntilFullyDismissed(@NonNull BaseTransientBottomBar transientBottomBar) {
-        TransientBottomBarDismissedCallback callback = new TransientBottomBarDismissedCallback();
-        transientBottomBar.addCallback(callback);
-        try {
-            // Register our listener as idling resource so that Espresso waits until the
-            // the bar has been fully dismissed
-            Espresso.registerIdlingResources(callback);
-            // Mark the callback to require waiting for idle state
-            callback.mNeedsIdle = true;
-            // Perform a dummy Espresso action that loops until the UI thread is idle. This
-            // effectively blocks us until the Snackbar has completed its sliding animation.
-            onView(isRoot()).perform(waitUntilIdle());
-            callback.mNeedsIdle = false;
-        } finally {
-            // Unregister our idling resource
-            Espresso.unregisterIdlingResources(callback);
-            // And remove our tracker listener from Snackbar
-            transientBottomBar.removeCallback(null);
-        }
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/SwipeUtils.java b/design/tests/src/android/support/design/testutils/SwipeUtils.java
deleted file mode 100644
index cf92883..0000000
--- a/design/tests/src/android/support/design/testutils/SwipeUtils.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralSwipeAction;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Swipe;
-import android.view.View;
-
-public class SwipeUtils {
-
-    public static GeneralSwipeAction swipeUp(final int swipeX,
-            final int swipeStartY, final int swipeAmountY) {
-        return new GeneralSwipeAction(
-                Swipe.SLOW,
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY };
-                    }
-                },
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY - swipeAmountY };
-                    }
-                },
-                Press.FINGER
-        );
-    }
-
-    public static GeneralSwipeAction swipeDown(final int swipeX,
-            final int swipeStartY, final int swipeAmountY) {
-        return new GeneralSwipeAction(
-                Swipe.SLOW,
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY };
-                    }
-                },
-                new CoordinatesProvider() {
-                    @Override
-                    public float[] calculateCoordinates(View view) {
-                        return new float[] { swipeX, swipeStartY + swipeAmountY };
-                    }
-                },
-                Press.FINGER
-        );
-    }
-
-
-}
diff --git a/design/tests/src/android/support/design/testutils/TabLayoutActions.java b/design/tests/src/android/support/design/testutils/TabLayoutActions.java
deleted file mode 100644
index 7c17850..0000000
--- a/design/tests/src/android/support/design/testutils/TabLayoutActions.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
-
-import android.support.annotation.Nullable;
-import android.support.design.widget.TabLayout;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.matcher.ViewMatchers;
-import android.support.v4.view.ViewPager;
-import android.view.View;
-
-import org.hamcrest.Matcher;
-
-public class TabLayoutActions {
-    /**
-     * Wires <code>TabLayout</code> to <code>ViewPager</code> content.
-     */
-    public static ViewAction setupWithViewPager(final @Nullable ViewPager viewPager) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Setup with ViewPager content";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TabLayout tabLayout = (TabLayout) view;
-                tabLayout.setupWithViewPager(viewPager);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Wires <code>TabLayout</code> to <code>ViewPager</code> content.
-     */
-    public static ViewAction setupWithViewPager(final @Nullable ViewPager viewPager,
-            final boolean autoRefresh) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Setup with ViewPager content";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TabLayout tabLayout = (TabLayout) view;
-                tabLayout.setupWithViewPager(viewPager, autoRefresh);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Selects the specified tab in the <code>TabLayout</code>.
-     */
-    public static ViewAction selectTab(final int tabIndex) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Selects tab";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TabLayout tabLayout = (TabLayout) view;
-                tabLayout.getTabAt(tabIndex).select();
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets the specified tab mode in the <code>TabLayout</code>.
-     */
-    public static ViewAction setTabMode(final int tabMode) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets tab mode";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TabLayout tabLayout = (TabLayout) view;
-                tabLayout.setTabMode(tabMode);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Calls <code>setScrollPosition(position, positionOffset, true)</code> on the
-     * <code>TabLayout</code>
-     */
-    public static ViewAction setScrollPosition(final int position, final float positionOffset) {
-        return new ViewAction() {
-
-            @Override
-            public Matcher<View> getConstraints() {
-                return ViewMatchers.isAssignableFrom(TabLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "setScrollPosition(" + position + ", " + positionOffset + ", true)";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                TabLayout tabs = (TabLayout) view;
-                tabs.setScrollPosition(position, positionOffset, true);
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/TestDrawable.java b/design/tests/src/android/support/design/testutils/TestDrawable.java
deleted file mode 100644
index 26b3bf0..0000000
--- a/design/tests/src/android/support/design/testutils/TestDrawable.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import android.graphics.drawable.GradientDrawable;
-import android.support.annotation.ColorInt;
-
-/**
- * Custom drawable class that provides a reliable way for testing various tinting scenarios
- * across a range of platform versions. ColorDrawable doesn't support tinting on Kitkat and
- * below, and BitmapDrawable (PNG sources) appears to slightly alter green and blue channels
- * by a few units on some of the older platform versions (Gingerbread). Using GradientDrawable
- * allows doing reliable tests at the level of individual channels (alpha / red / green / blue)
- * for tinted and untinted icons in the testIconTinting method.
- */
-public class TestDrawable extends GradientDrawable {
-    private int mWidth;
-    private int mHeight;
-
-    public TestDrawable(@ColorInt int color, int width, int height) {
-        super(Orientation.TOP_BOTTOM, new int[] { color, color });
-        mWidth = width;
-        mHeight = height;
-    }
-
-    @Override
-    public int getIntrinsicWidth() {
-        return mWidth;
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mHeight;
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/TestUtils.java b/design/tests/src/android/support/design/testutils/TestUtils.java
deleted file mode 100644
index 5b1eff7..0000000
--- a/design/tests/src/android/support/design/testutils/TestUtils.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static org.junit.Assert.fail;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
-
-public class TestUtils {
-    /**
-     * Checks whether all the pixels in the specified drawable are of the same specified color.
-     *
-     * In case there is a color mismatch, the behavior of this method depends on the
-     * <code>throwExceptionIfFails</code> parameter. If it is <code>true</code>, this method will
-     * throw an <code>Exception</code> describing the mismatch. Otherwise this method will call
-     * <code>Assert.fail</code> with detailed description of the mismatch.
-     */
-    public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
-            int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
-            int allowedComponentVariance, boolean throwExceptionIfFails) {
-        assertAllPixelsOfColor(failMessagePrefix, drawable, drawableWidth, drawableHeight,
-                callSetBounds, color, null, allowedComponentVariance, throwExceptionIfFails);
-    }
-
-    public static void assertAllPixelsOfColor(String failMessagePrefix, @NonNull Drawable drawable,
-            int drawableWidth, int drawableHeight, boolean callSetBounds, @ColorInt int color,
-            Rect checkArea, int allowedComponentVariance, boolean throwExceptionIfFails) {
-
-        // Create a bitmap
-        Bitmap bitmap = Bitmap.createBitmap(drawableWidth, drawableHeight, Bitmap.Config.ARGB_8888);
-        // Create a canvas that wraps the bitmap
-        Canvas canvas = new Canvas(bitmap);
-        if (callSetBounds) {
-            // Configure the drawable to have bounds that match the passed size
-            drawable.setBounds(0, 0, drawableWidth, drawableHeight);
-        }
-
-        // And ask the drawable to draw itself to the canvas / bitmap
-        drawable.draw(canvas);
-
-        try {
-            int[] rowPixels = new int[drawableWidth];
-
-            final int firstRow = checkArea != null ? checkArea.top : 0;
-            final int lastRow = checkArea != null ? checkArea.bottom : drawableHeight - 1;
-            final int firstCol = checkArea != null ? checkArea.left : 0;
-            final int lastCol = checkArea != null ? checkArea.right : drawableWidth - 1;
-
-            final int expectedAlpha = Color.alpha(color);
-            final int expectedRed = Color.red(color);
-            final int expectedGreen = Color.green(color);
-            final int expectedBlue = Color.blue(color);
-
-            for (int row = firstRow; row <= lastRow; row++) {
-                bitmap.getPixels(rowPixels, 0, drawableWidth, 0, row, drawableWidth, 1);
-
-                for (int column = firstCol; column <= lastCol; column++) {
-                    int sourceAlpha = Color.alpha(rowPixels[column]);
-                    int sourceRed = Color.red(rowPixels[column]);
-                    int sourceGreen = Color.green(rowPixels[column]);
-                    int sourceBlue = Color.blue(rowPixels[column]);
-
-                    int varianceAlpha = Math.abs(sourceAlpha - expectedAlpha);
-                    int varianceRed = Math.abs(sourceRed - expectedRed);
-                    int varianceGreen = Math.abs(sourceGreen - expectedGreen);
-                    int varianceBlue = Math.abs(sourceBlue - expectedBlue);
-
-                    boolean isColorMatch = (varianceAlpha <= allowedComponentVariance)
-                            && (varianceRed <= allowedComponentVariance)
-                            && (varianceGreen <= allowedComponentVariance)
-                            && (varianceBlue <= allowedComponentVariance);
-
-                    if (!isColorMatch) {
-                        String mismatchDescription = failMessagePrefix
-                                + ": expected all drawable colors to be ["
-                                + expectedAlpha + "," + expectedRed + ","
-                                + expectedGreen + "," + expectedBlue
-                                + "] but at position (" + row + "," + column + ") found ["
-                                + sourceAlpha + "," + sourceRed + ","
-                                + sourceGreen + "," + sourceBlue + "]";
-                        if (throwExceptionIfFails) {
-                            throw new RuntimeException(mismatchDescription);
-                        } else {
-                            fail(mismatchDescription);
-                        }
-                    }
-                }
-            }
-        } finally {
-            bitmap.recycle();
-        }
-    }
-
-    public static int getThemeAttrColor(Context context, final int attr) {
-        TypedArray a = null;
-        try {
-            a = context.obtainStyledAttributes(new int[]{attr});
-            return a.getColor(0, 0);
-        } finally {
-            if (a != null) {
-                a.recycle();
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/testutils/TestUtilsActions.java b/design/tests/src/android/support/design/testutils/TestUtilsActions.java
deleted file mode 100644
index a9d1233..0000000
--- a/design/tests/src/android/support/design/testutils/TestUtilsActions.java
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
-import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
-
-import android.graphics.drawable.Drawable;
-import android.os.Parcelable;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.MenuRes;
-import android.support.annotation.Nullable;
-import android.support.design.widget.CollapsingToolbarLayout;
-import android.support.design.widget.NavigationView;
-import android.support.design.widget.TabLayout;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.TextViewCompat;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.hamcrest.Matcher;
-
-public class TestUtilsActions {
-    /**
-     * Replaces an existing {@link TabLayout} with a new one inflated from the specified
-     * layout resource.
-     */
-    public static ViewAction replaceTabLayout(final @LayoutRes int tabLayoutResId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Replace TabLayout";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final ViewGroup viewGroup = (ViewGroup) view;
-                final int childCount = viewGroup.getChildCount();
-                // Iterate over children and find TabLayout
-                for (int i = 0; i < childCount; i++) {
-                    View child = viewGroup.getChildAt(i);
-                    if (child instanceof TabLayout) {
-                        // Remove the existing TabLayout
-                        viewGroup.removeView(child);
-                        // Create a new one
-                        final LayoutInflater layoutInflater =
-                                LayoutInflater.from(view.getContext());
-                        final TabLayout newTabLayout = (TabLayout) layoutInflater.inflate(
-                                tabLayoutResId, viewGroup, false);
-                        // Make sure we're adding the new TabLayout at the same index
-                        viewGroup.addView(newTabLayout, i);
-                        break;
-                    }
-                }
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets layout direction on the view.
-     */
-    public static ViewAction setLayoutDirection(final int layoutDirection) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "set layout direction";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewCompat.setLayoutDirection(view, layoutDirection);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets title on the {@link CollapsingToolbarLayout}.
-     */
-    public static ViewAction setTitle(final CharSequence title) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(CollapsingToolbarLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "set toolbar title";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                CollapsingToolbarLayout collapsingToolbarLayout =
-                        (CollapsingToolbarLayout) view;
-                collapsingToolbarLayout.setTitle(title);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets text content on {@link TextView}
-     */
-    public static ViewAction setText(final @Nullable CharSequence text) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextView.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "TextView set text";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextView textView = (TextView) view;
-                textView.setText(text);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Adds tabs to {@link TabLayout}
-     */
-    public static ViewAction addTabs(final String... tabs) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TabLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "TabLayout add tabs";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TabLayout tabLayout = (TabLayout) view;
-                for (int i = 0; i < tabs.length; i++) {
-                    tabLayout.addTab(tabLayout.newTab().setText(tabs[i]));
-                }
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Dummy Espresso action that waits until the UI thread is idle. This action can be performed
-     * on the root view to wait for an ongoing animation to be completed.
-     */
-    public static ViewAction waitUntilIdle() {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isRoot();
-            }
-
-            @Override
-            public String getDescription() {
-                return "wait for idle";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setEnabled(final boolean enabled) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "set enabled";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                view.setEnabled(enabled);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setClickable(final boolean clickable) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "set clickable";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                view.setClickable(clickable);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setSelected(final boolean selected) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "set selected";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-                view.setSelected(selected);
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets compound drawables on {@link TextView}
-     */
-    public static ViewAction setCompoundDrawablesRelative(final @Nullable Drawable start,
-            final @Nullable Drawable top, final @Nullable Drawable end,
-            final @Nullable Drawable bottom) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextView.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "TextView set compound drawables relative";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextView textView = (TextView) view;
-                TextViewCompat.setCompoundDrawablesRelative(textView, start, top, end, bottom);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Restores the saved hierarchy state.
-     *
-     * @param container The saved hierarchy state.
-     */
-    public static ViewAction restoreHierarchyState(final SparseArray<Parcelable> container) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(View.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "restore the saved state";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-                view.restoreHierarchyState(container);
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Clears and inflates the menu.
-     *
-     * @param menuResId The menu resource XML to be used.
-     */
-    public static ViewAction reinflateMenu(final @MenuRes int menuResId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(NavigationView.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "clear and inflate menu " + menuResId;
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-                final NavigationView nv = (NavigationView) view;
-                nv.getMenu().clear();
-                nv.inflateMenu(menuResId);
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-}
diff --git a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java b/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
deleted file mode 100644
index 46bb982..0000000
--- a/design/tests/src/android/support/design/testutils/TestUtilsMatchers.java
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IdRes;
-import android.support.annotation.NonNull;
-import android.support.design.widget.FloatingActionButton;
-import android.support.test.espresso.matcher.BoundedMatcher;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.TextViewCompat;
-import android.support.v7.view.menu.MenuItemImpl;
-import android.view.Gravity;
-import android.view.Menu;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-
-public class TestUtilsMatchers {
-    /**
-     * Returns a matcher that matches Views that are not narrower than specified width in pixels.
-     */
-    public static Matcher<View> isNotNarrowerThan(final int minWidth) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                final int viewWidth = view.getWidth();
-                if (viewWidth < minWidth) {
-                    failedCheckDescription =
-                            "width " + viewWidth + " is less than minimum " + minWidth;
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches Views that are not wider than specified width in pixels.
-     */
-    public static Matcher<View> isNotWiderThan(final int maxWidth) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                final int viewWidth = view.getWidth();
-                if (viewWidth > maxWidth) {
-                    failedCheckDescription =
-                            "width " + viewWidth + " is more than maximum " + maxWidth;
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches TextViews with the specified text size.
-     */
-    public static Matcher withTextSize(final float textSize) {
-        return new BoundedMatcher<View, TextView>(TextView.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final TextView view) {
-                final float ourTextSize = view.getTextSize();
-                if (Math.abs(textSize - ourTextSize) > 1.0f) {
-                    failedCheckDescription =
-                            "text size " + ourTextSize + " is different than expected " + textSize;
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches TextViews with the specified text color.
-     */
-    public static Matcher withTextColor(final @ColorInt int textColor) {
-        return new BoundedMatcher<View, TextView>(TextView.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final TextView view) {
-                final @ColorInt int ourTextColor = view.getCurrentTextColor();
-                if (ourTextColor != textColor) {
-                    int ourAlpha = Color.alpha(ourTextColor);
-                    int ourRed = Color.red(ourTextColor);
-                    int ourGreen = Color.green(ourTextColor);
-                    int ourBlue = Color.blue(ourTextColor);
-
-                    int expectedAlpha = Color.alpha(textColor);
-                    int expectedRed = Color.red(textColor);
-                    int expectedGreen = Color.green(textColor);
-                    int expectedBlue = Color.blue(textColor);
-
-                    failedCheckDescription =
-                            "expected color to be ["
-                                    + expectedAlpha + "," + expectedRed + ","
-                                    + expectedGreen + "," + expectedBlue
-                                    + "] but found ["
-                                    + ourAlpha + "," + ourRed + ","
-                                    + ourGreen + "," + ourBlue + "]";
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches TextViews whose start drawable is filled with the specified
-     * fill color.
-     */
-    public static Matcher withStartDrawableFilledWith(final @ColorInt int fillColor,
-            final int allowedComponentVariance) {
-        return new BoundedMatcher<View, TextView>(TextView.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final TextView view) {
-                final Drawable[] compoundDrawables = view.getCompoundDrawables();
-                final boolean isRtl =
-                        (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL);
-                final Drawable startDrawable = isRtl ? compoundDrawables[2] : compoundDrawables[0];
-                if (startDrawable == null) {
-                    failedCheckDescription = "no start drawable";
-                    return false;
-                }
-                try {
-                    final Rect bounds = startDrawable.getBounds();
-                    TestUtils.assertAllPixelsOfColor("",
-                            startDrawable, bounds.width(), bounds.height(), true,
-                            fillColor, allowedComponentVariance, true);
-                } catch (Throwable t) {
-                    failedCheckDescription = t.getMessage();
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches <code>ImageView</code>s which have drawable flat-filled
-     * with the specific color.
-     */
-    public static Matcher drawable(@ColorInt final int color, final int allowedComponentVariance) {
-        return new BoundedMatcher<View, ImageView>(ImageView.class) {
-            private String mFailedComparisonDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText("with drawable of color: ");
-
-                description.appendText(mFailedComparisonDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final ImageView view) {
-                Drawable drawable = view.getDrawable();
-                if (drawable == null) {
-                    return false;
-                }
-
-                // One option is to check if we have a ColorDrawable and then call getColor
-                // but that API is v11+. Instead, we call our helper method that checks whether
-                // all pixels in a Drawable are of the same specified color.
-                try {
-                    TestUtils.assertAllPixelsOfColor("", drawable, view.getWidth(),
-                            view.getHeight(), true, color, allowedComponentVariance, true);
-                    // If we are here, the color comparison has passed.
-                    mFailedComparisonDescription = null;
-                    return true;
-                } catch (Throwable t) {
-                    // If we are here, the color comparison has failed.
-                    mFailedComparisonDescription = t.getMessage();
-                    return false;
-                }
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches Views with the specified background fill color.
-     */
-    public static Matcher withBackgroundFill(final @ColorInt int fillColor) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                Drawable background = view.getBackground();
-                try {
-                    TestUtils.assertAllPixelsOfColor("",
-                            background, view.getWidth(), view.getHeight(), true,
-                            fillColor, 0, true);
-                } catch (Throwable t) {
-                    failedCheckDescription = t.getMessage();
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches FloatingActionButtons with the specified custom size.
-     */
-    public static Matcher withFabCustomSize(final int customSize) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String mFailedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(mFailedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                if (!(view instanceof FloatingActionButton)) {
-                    return false;
-                }
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                if (Math.abs(fab.getCustomSize() - customSize) > 1.0f) {
-                    mFailedCheckDescription =
-                            "Custom size " + fab.getCustomSize() + " is different than expected "
-                                    + customSize;
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches FloatingActionButtons with the specified background
-     * fill color.
-     */
-    public static Matcher withFabBackgroundFill(final @ColorInt int fillColor) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                if (!(view instanceof FloatingActionButton)) {
-                    return false;
-                }
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-
-                // Since the FAB background is round, and may contain the shadow, we'll look at
-                // just the center half rect of the content area
-                final Rect area = new Rect();
-                fab.getContentRect(area);
-
-                final int rectHeightQuarter = area.height() / 4;
-                final int rectWidthQuarter = area.width() / 4;
-                area.left += rectWidthQuarter;
-                area.top += rectHeightQuarter;
-                area.right -= rectWidthQuarter;
-                area.bottom -= rectHeightQuarter;
-
-                try {
-                    TestUtils.assertAllPixelsOfColor("",
-                            fab.getBackground(), view.getWidth(), view.getHeight(), false,
-                            fillColor, area, 0, true);
-                } catch (Throwable t) {
-                    failedCheckDescription = t.getMessage();
-                    return false;
-                }
-                return true;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches {@link View}s based on the given parent type.
-     *
-     * @param parentMatcher the type of the parent to match on
-     */
-    public static Matcher<View> isChildOfA(final Matcher<View> parentMatcher) {
-        return new TypeSafeMatcher<View>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("is child of a: ");
-                parentMatcher.describeTo(description);
-            }
-
-            @Override
-            public boolean matchesSafely(View view) {
-                final ViewParent viewParent = view.getParent();
-                if (!(viewParent instanceof View)) {
-                    return false;
-                }
-                if (parentMatcher.matches(viewParent)) {
-                    return true;
-                }
-                return false;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches FloatingActionButtons with the specified content height
-     */
-    public static Matcher withFabContentHeight(final int size) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                if (!(view instanceof FloatingActionButton)) {
-                    return false;
-                }
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                final Rect area = new Rect();
-                fab.getContentRect(area);
-
-                return area.height() == size;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches FloatingActionButtons with the specified gravity.
-     */
-    public static Matcher withFabContentAreaOnMargins(final int gravity) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                if (!(view instanceof FloatingActionButton)) {
-                    return false;
-                }
-
-                final FloatingActionButton fab = (FloatingActionButton) view;
-                final ViewGroup.MarginLayoutParams lp =
-                        (ViewGroup.MarginLayoutParams) fab.getLayoutParams();
-                final ViewGroup parent = (ViewGroup) view.getParent();
-
-                final Rect area = new Rect();
-                fab.getContentRect(area);
-
-                final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
-                        ViewCompat.getLayoutDirection(view));
-
-                try {
-                    switch (absGravity & Gravity.VERTICAL_GRAVITY_MASK) {
-                        case Gravity.TOP:
-                            assertEquals(lp.topMargin, fab.getTop() + area.top);
-                            break;
-                        case Gravity.BOTTOM:
-                            assertEquals(parent.getHeight() - lp.bottomMargin,
-                                    fab.getTop() + area.bottom);
-                            break;
-                    }
-                    switch (absGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-                        case Gravity.LEFT:
-                            assertEquals(lp.leftMargin, fab.getLeft() + area.left);
-                            break;
-                        case Gravity.RIGHT:
-                            assertEquals(parent.getWidth() - lp.rightMargin,
-                                    fab.getLeft() + area.right);
-                            break;
-                    }
-                    return true;
-                } catch (Throwable t) {
-                    failedCheckDescription = t.getMessage();
-                    return false;
-                }
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches FloatingActionButtons with the specified content height
-     */
-    public static Matcher withCompoundDrawable(final int index, final Drawable expected) {
-        return new BoundedMatcher<View, View>(View.class) {
-            private String failedCheckDescription;
-
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText(failedCheckDescription);
-            }
-
-            @Override
-            public boolean matchesSafely(final View view) {
-                if (!(view instanceof TextView)) {
-                    return false;
-                }
-
-                final TextView textView = (TextView) view;
-                return expected == TextViewCompat.getCompoundDrawablesRelative(textView)[index];
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches {@link View}s that are pressed.
-     */
-    public static Matcher<View> isPressed() {
-        return new TypeSafeMatcher<View>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("is pressed");
-            }
-
-            @Override
-            public boolean matchesSafely(View view) {
-                return view.isPressed();
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches views which have a z-value greater than 0. Also matches if
-     * the platform we're running on does not support z-values.
-     */
-    public static Matcher<View> hasZ() {
-        return new TypeSafeMatcher<View>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("has a z value greater than 0");
-            }
-
-            @Override
-            public boolean matchesSafely(View view) {
-                return Build.VERSION.SDK_INT < 21 || ViewCompat.getZ(view) > 0f;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches TextViews with the specified typeface.
-     */
-    public static Matcher withTypeface(@NonNull final Typeface typeface) {
-        return new TypeSafeMatcher<TextView>(TextView.class) {
-            @Override
-            public void describeTo(final Description description) {
-                description.appendText("view with typeface: " + typeface);
-            }
-
-            @Override
-            public boolean matchesSafely(final TextView view) {
-                return typeface.equals(view.getTypeface());
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches the action view of the specified menu item.
-     *
-     * @param menu The menu
-     * @param id   The ID of the menu item
-     */
-    public static Matcher<View> isActionViewOf(@NonNull final Menu menu, @IdRes final int id) {
-        return new TypeSafeMatcher<View>() {
-
-            private Resources mResources;
-
-            @Override
-            protected boolean matchesSafely(View view) {
-                mResources = view.getResources();
-                MenuItemImpl item = (MenuItemImpl) menu.findItem(id);
-                return item != null && item.getActionView() == view;
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                String name;
-                if (mResources != null) {
-                    name = mResources.getResourceName(id);
-                } else {
-                    name = Integer.toString(id);
-                }
-                description.appendText("is action view of menu item " + name);
-            }
-        };
-    }
-
-}
diff --git a/design/tests/src/android/support/design/testutils/TextInputLayoutActions.java b/design/tests/src/android/support/design/testutils/TextInputLayoutActions.java
deleted file mode 100755
index c4d4520..0000000
--- a/design/tests/src/android/support/design/testutils/TextInputLayoutActions.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-
-import android.graphics.Typeface;
-import android.support.design.R;
-import android.support.design.widget.TextInputLayout;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.matcher.ViewMatchers;
-import android.view.View;
-
-import org.hamcrest.Matcher;
-
-public class TextInputLayoutActions {
-
-    public static ViewAction setErrorEnabled(final boolean enabled) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Enables/disables the error";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextInputLayout layout = (TextInputLayout) view;
-                layout.setErrorEnabled(enabled);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setError(final CharSequence error) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets the error";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextInputLayout layout = (TextInputLayout) view;
-                layout.setError(error);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setErrorTextAppearance(final int resId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets the error text appearance";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextInputLayout layout = (TextInputLayout) view;
-                layout.setErrorTextAppearance(resId);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setTypeface(final Typeface typeface) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets the typeface";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextInputLayout layout = (TextInputLayout) view;
-                layout.setTypeface(typeface);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setPasswordVisibilityToggleEnabled(final boolean enabled) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets the error";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextInputLayout layout = (TextInputLayout) view;
-                layout.setPasswordVisibilityToggleEnabled(enabled);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setCounterEnabled(final boolean enabled) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets the counter enabled";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextInputLayout layout = (TextInputLayout) view;
-                layout.setCounterEnabled(enabled);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public static ViewAction setCounterMaxLength(final int maxLength) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets the counter max length";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                TextInputLayout layout = (TextInputLayout) view;
-                layout.setCounterMaxLength(maxLength);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Toggles password.
-     */
-    public static ViewAction clickPasswordToggle() {
-        return new ViewAction() {
-
-            @Override
-            public Matcher<View> getConstraints() {
-                return ViewMatchers.isAssignableFrom(TextInputLayout.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Clicks the password toggle";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                TextInputLayout textInputLayout = (TextInputLayout) view;
-                // Reach in and find the password toggle since we don't have a public API
-                // to get a reference to it
-                View passwordToggle = textInputLayout.findViewById(R.id.text_input_password_toggle);
-                passwordToggle.performClick();
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-}
diff --git a/design/tests/src/android/support/design/testutils/TextInputLayoutMatchers.java b/design/tests/src/android/support/design/testutils/TextInputLayoutMatchers.java
deleted file mode 100755
index d67e555..0000000
--- a/design/tests/src/android/support/design/testutils/TextInputLayoutMatchers.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import android.support.design.R;
-import android.support.design.widget.CheckableImageButton;
-import android.support.design.widget.TextInputLayout;
-import android.text.TextUtils;
-import android.view.View;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-
-public class TextInputLayoutMatchers {
-
-    /**
-     * Returns a matcher that matches TextInputLayouts with non-empty content descriptions for
-     * the password toggle.
-     */
-    public static Matcher passwordToggleHasContentDescription() {
-        return new TypeSafeMatcher<TextInputLayout>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("TextInputLayout has non-empty content description"
-                        + "for password toggle.");
-            }
-
-            @Override
-            protected boolean matchesSafely(TextInputLayout item) {
-                // Reach in and find the password toggle since we don't have a public API
-                // to get a reference to it
-                View passwordToggle = item.findViewById(R.id.text_input_password_toggle);
-                return !TextUtils.isEmpty(item.getPasswordVisibilityToggleContentDescription())
-                    && !TextUtils.isEmpty(passwordToggle.getContentDescription());
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches TextInputLayouts with non-displayed password toggles
-     */
-    public static Matcher doesNotShowPasswordToggle() {
-        return new TypeSafeMatcher<TextInputLayout>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("TextInputLayout shows password toggle.");
-            }
-
-            @Override
-            protected boolean matchesSafely(TextInputLayout item) {
-                // Reach in and find the password toggle since we don't have a public API
-                // to get a reference to it
-                View passwordToggle = item.findViewById(R.id.text_input_password_toggle);
-                return passwordToggle.getVisibility() != View.VISIBLE;
-            }
-        };
-    }
-
-    /**
-     * Returns a matcher that matches TextInputLayouts with non-displayed password toggles
-     */
-    public static Matcher passwordToggleIsNotChecked() {
-        return new TypeSafeMatcher<TextInputLayout>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("TextInputLayout has checked password toggle.");
-            }
-
-            @Override
-            protected boolean matchesSafely(TextInputLayout item) {
-                // Reach in and find the password toggle since we don't have a public API
-                // to get a reference to it
-                CheckableImageButton passwordToggle = (CheckableImageButton) item.findViewById(
-                        R.id.text_input_password_toggle);
-                return !passwordToggle.isChecked();
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/ViewPagerActions.java b/design/tests/src/android/support/design/testutils/ViewPagerActions.java
deleted file mode 100644
index 1a147cf..0000000
--- a/design/tests/src/android/support/design/testutils/ViewPagerActions.java
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.testutils;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayingAtLeast;
-
-import android.support.annotation.Nullable;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.view.View;
-
-import org.hamcrest.Matcher;
-
-public class ViewPagerActions {
-    /**
-     * Moves <code>ViewPager</code> to the right by one page.
-     */
-    public static ViewAction scrollRight() {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "ViewPager scroll one page to the right";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewPager viewPager = (ViewPager) view;
-                int current = viewPager.getCurrentItem();
-                viewPager.setCurrentItem(current + 1, false);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Moves <code>ViewPager</code> to the left by one page.
-     */
-    public static ViewAction scrollLeft() {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "ViewPager scroll one page to the left";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewPager viewPager = (ViewPager) view;
-                int current = viewPager.getCurrentItem();
-                viewPager.setCurrentItem(current - 1, false);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Moves <code>ViewPager</code> to the last page.
-     */
-    public static ViewAction scrollToLast() {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "ViewPager scroll to last page";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewPager viewPager = (ViewPager) view;
-                int size = viewPager.getAdapter().getCount();
-                if (size > 0) {
-                    viewPager.setCurrentItem(size - 1, false);
-                }
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Moves <code>ViewPager</code> to the first page.
-     */
-    public static ViewAction scrollToFirst() {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "ViewPager scroll to first page";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewPager viewPager = (ViewPager) view;
-                int size = viewPager.getAdapter().getCount();
-                if (size > 0) {
-                    viewPager.setCurrentItem(0, false);
-                }
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Moves <code>ViewPager</code> to specific page.
-     */
-    public static ViewAction scrollToPage(final int page) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isDisplayingAtLeast(90);
-            }
-
-            @Override
-            public String getDescription() {
-                return "ViewPager move to a specific page";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewPager viewPager = (ViewPager) view;
-                viewPager.setCurrentItem(page, false);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    /**
-     * Sets the specified adapter on <code>ViewPager</code>.
-     */
-    public static ViewAction setAdapter(final @Nullable PagerAdapter adapter) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(ViewPager.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "ViewPager set adapter";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewPager viewPager = (ViewPager) view;
-                viewPager.setAdapter(adapter);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/testutils/ViewStructureImpl.java b/design/tests/src/android/support/design/testutils/ViewStructureImpl.java
deleted file mode 100644
index c7369e9..0000000
--- a/design/tests/src/android/support/design/testutils/ViewStructureImpl.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.testutils;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.view.ViewStructure;
-import android.view.ViewStructure.HtmlInfo.Builder;
-import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillValue;
-
-/**
- * Simple implementation of {@link ViewStructure} that's easier to use than a Mockito mock.
- *
- * <p>Currently supports only {@code hint}, {@code className}, and child-related methods.
- */
-public class ViewStructureImpl extends ViewStructure {
-
-    private CharSequence mHint;
-    private String mClassName;
-    private ViewStructureImpl[] mChildren;
-
-    @Override
-    public void setHint(CharSequence hint) {
-        mHint = hint;
-    }
-
-    // Supported methods
-    @Override
-    public CharSequence getHint() {
-        return mHint;
-    }
-
-    @Override
-    public void setChildCount(int num) {
-        mChildren = new ViewStructureImpl[num];
-    }
-
-    @Override
-    public void setClassName(String className) {
-        mClassName = className;
-    }
-
-    public String getClassName() {
-        return mClassName;
-    }
-
-    @Override
-    public int addChildCount(int num) {
-        if (mChildren == null) {
-            setChildCount(num);
-            return 0;
-        }
-        final int start = mChildren.length;
-        ViewStructureImpl[] newArray = new ViewStructureImpl[start + num];
-        System.arraycopy(mChildren, 0, newArray, 0, start);
-        mChildren = newArray;
-        return start;
-    }
-
-    @Override
-    public int getChildCount() {
-        if (mChildren == null) {
-            return 0;
-        }
-        return mChildren.length;
-    }
-
-    public ViewStructureImpl getChildAt(int index) {
-        return mChildren[index];
-    }
-
-    @Override
-    public ViewStructure newChild(int index) {
-        final ViewStructureImpl child = new ViewStructureImpl();
-        mChildren[index] = child;
-        return child;
-    }
-
-    @Override
-    public ViewStructure asyncNewChild(int index) {
-        return newChild(index);
-    }
-
-
-    // Unsupported methods
-    @Override
-    public void setId(int id, String packageName, String typeName, String entryName) {
-    }
-
-    @Override
-    public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
-    }
-
-    @Override
-    public void setTransformation(Matrix matrix) {
-    }
-
-    @Override
-    public void setElevation(float elevation) {
-    }
-
-    @Override
-    public void setAlpha(float alpha) {
-    }
-
-    @Override
-    public void setVisibility(int visibility) {
-    }
-
-    public void setAssistBlocked(boolean state) {
-    }
-
-    @Override
-    public void setEnabled(boolean state) {
-    }
-
-    @Override
-    public void setClickable(boolean state) {
-    }
-
-    @Override
-    public void setLongClickable(boolean state) {
-    }
-
-    @Override
-    public void setContextClickable(boolean state) {
-    }
-
-    @Override
-    public void setFocusable(boolean state) {
-    }
-
-    @Override
-    public void setFocused(boolean state) {
-    }
-
-    @Override
-    public void setAccessibilityFocused(boolean state) {
-    }
-
-    @Override
-    public void setCheckable(boolean state) {
-    }
-
-    @Override
-    public void setChecked(boolean state) {
-    }
-
-    @Override
-    public void setSelected(boolean state) {
-    }
-
-    @Override
-    public void setActivated(boolean state) {
-    }
-
-    @Override
-    public void setOpaque(boolean opaque) {
-    }
-
-    @Override
-    public void setContentDescription(CharSequence contentDescription) {
-    }
-
-    @Override
-    public void setText(CharSequence text) {
-    }
-
-    @Override
-    public void setText(CharSequence text, int selectionStart, int selectionEnd) {
-    }
-
-    @Override
-    public void setTextStyle(float size, int fgColor, int bgColor, int style) {
-    }
-
-    @Override
-    public void setTextLines(int[] charOffsets, int[] baselines) {
-    }
-
-    @Override
-    public CharSequence getText() {
-        return null;
-    }
-
-    @Override
-    public int getTextSelectionStart() {
-        return 0;
-    }
-
-    @Override
-    public int getTextSelectionEnd() {
-        return 0;
-    }
-
-    @Override
-    public Bundle getExtras() {
-        return null;
-    }
-
-    @Override
-    public boolean hasExtras() {
-        return false;
-    }
-
-    @Override
-    public AutofillId getAutofillId() {
-        return null;
-    }
-
-    @Override
-    public void setAutofillId(AutofillId id) {
-    }
-
-    public void setAutofillId(ViewStructure parent, int virtualId) {
-    }
-
-    @Override
-    public void setAutofillId(AutofillId parentId, int virtualId) {
-    }
-
-    @Override
-    public void setAutofillType(int type) {
-    }
-
-    @Override
-    public void setAutofillHints(String[] hint) {
-    }
-
-    @Override
-    public void setAutofillValue(AutofillValue value) {
-    }
-
-    @Override
-    public void setAutofillOptions(CharSequence[] options) {
-    }
-
-    @Override
-    public void setInputType(int inputType) {
-    }
-
-    @Override
-    public void setDataIsSensitive(boolean sensitive) {
-    }
-
-    @Override
-    public void asyncCommit() {
-    }
-
-    public Rect getTempRect() {
-        return null;
-    }
-
-    @Override
-    public void setWebDomain(String domain) {
-    }
-
-    @Override
-    public void setLocaleList(LocaleList localeList) {
-    }
-
-    @Override
-    public Builder newHtmlInfoBuilder(String tagName) {
-        return null;
-    }
-
-    @Override
-    public void setHtmlInfo(HtmlInfo htmlInfo) {
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarHorizontalScrollingActivity.java b/design/tests/src/android/support/design/widget/AppBarHorizontalScrollingActivity.java
deleted file mode 100644
index 960dbd9..0000000
--- a/design/tests/src/android/support/design/widget/AppBarHorizontalScrollingActivity.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.os.Bundle;
-import android.support.design.test.R;
-import android.support.v7.widget.Toolbar;
-
-public class AppBarHorizontalScrollingActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_appbar_horizontal_scrolling;
-    }
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarHorizontalScrollingTest.java b/design/tests/src/android/support/design/widget/AppBarHorizontalScrollingTest.java
deleted file mode 100644
index ccda8b0..0000000
--- a/design/tests/src/android/support/design/widget/AppBarHorizontalScrollingTest.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.swipeLeft;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.verify;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.os.SystemClock;
-import android.support.design.test.R;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.Button;
-import android.widget.HorizontalScrollView;
-
-import org.junit.Test;
-
-/**
- * Testing that if we have a {@link AppBarLayout} child that intercepts touch events (such as
- * {@link HorizontalScrollView} that handles horizontal swipes), that does not interfere with
- * event handling after the event sequence is no longer being intercepted by that child.
- */
-@LargeTest
-public class AppBarHorizontalScrollingTest extends
-        BaseInstrumentationTestCase<AppBarHorizontalScrollingActivity> {
-
-    public AppBarHorizontalScrollingTest() {
-        super(AppBarHorizontalScrollingActivity.class);
-    }
-
-    @Test
-    public void testScrollAndClick() throws Throwable {
-        final Activity activity = mActivityTestRule.getActivity();
-        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-
-        final Button button = activity.findViewById(R.id.button);
-        final View.OnClickListener mockClickListener = mock(View.OnClickListener.class);
-        button.setOnClickListener(mockClickListener);
-
-        // Emulate a click on the button to verify that the registered listener is invoked
-        // prior to performing a horizontal swipe across the app bar
-        final int[] buttonXY = new int[2];
-        button.getLocationOnScreen(buttonXY);
-        final int buttonWidth = button.getWidth();
-        final int buttonHeight = button.getHeight();
-        final float emulatedTapX = buttonXY[0] + buttonWidth / 2.0f;
-        final float emulatedTapY = buttonXY[1] + buttonHeight / 2.0f;
-
-        emulateButtonClick(instrumentation, emulatedTapX, emulatedTapY);
-        verify(mockClickListener).onClick(button);
-        reset(mockClickListener);
-
-        final HorizontalScrollView hsv = activity.findViewById(R.id.hsv);
-        final int scrollXBefore = hsv.getScrollX();
-        // Now scroll / swipe horizontally across our scrollable content in the app bar
-        onView(withId(R.id.app_bar)).perform(swipeLeft());
-        assertTrue("Horizontal scroll performed", hsv.getScrollX() > scrollXBefore);
-
-        // And emulate another click on the button to verify that the registered listener is still
-        // invoked immediately after performing the horizontal swipe across the app bar
-        emulateButtonClick(instrumentation, emulatedTapX, emulatedTapY);
-        verify(mockClickListener).onClick(button);
-    }
-
-    private void emulateButtonClick(Instrumentation instrumentation, float emulatedTapX,
-            float emulatedTapY) {
-        // Note that the reason to not use Espresso's click() view action is so that we can
-        // faithfully emulate what was happening in the reported bug. We don't want the events
-        // to be sent directly to the button, but rather be processed by the parent coordinator
-        // layout, so that we reproduce what is happening as the events are processed at the level
-        // of that parent.
-
-        // Inject DOWN event
-        long downTime = SystemClock.uptimeMillis();
-        MotionEvent eventDown = MotionEvent.obtain(
-                downTime, downTime, MotionEvent.ACTION_DOWN, emulatedTapX, emulatedTapY, 1);
-        instrumentation.sendPointerSync(eventDown);
-
-        // Inject MOVE event
-        long moveTime = SystemClock.uptimeMillis();
-        MotionEvent eventMove = MotionEvent.obtain(
-                moveTime, moveTime, MotionEvent.ACTION_MOVE, emulatedTapX, emulatedTapY, 1);
-        instrumentation.sendPointerSync(eventMove);
-
-        // Inject UP event
-        long upTime = SystemClock.uptimeMillis();
-        MotionEvent eventUp = MotionEvent.obtain(
-                upTime, upTime, MotionEvent.ACTION_UP, emulatedTapX, emulatedTapY, 1);
-        instrumentation.sendPointerSync(eventUp);
-
-        // Wait for the system to process all events in the queue
-        instrumentation.waitForIdleSync();
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarLayoutBaseTest.java b/design/tests/src/android/support/design/widget/AppBarLayoutBaseTest.java
deleted file mode 100644
index bd49506..0000000
--- a/design/tests/src/android/support/design/widget/AppBarLayoutBaseTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.CollapsingToolbarLayoutActions.setContentScrimColor;
-import static android.support.design.testutils.SwipeUtils.swipeDown;
-import static android.support.design.testutils.SwipeUtils.swipeUp;
-import static android.support.design.testutils.TestUtilsActions.setText;
-import static android.support.design.testutils.TestUtilsActions.setTitle;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.junit.Assert.assertEquals;
-
-import android.graphics.Color;
-import android.os.Build;
-import android.os.SystemClock;
-import android.support.annotation.CallSuper;
-import android.support.annotation.IdRes;
-import android.support.annotation.IntRange;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.StringRes;
-import android.support.design.test.R;
-import android.support.design.testutils.Shakespeare;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.text.TextUtils;
-import android.widget.TextView;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-
-public abstract class AppBarLayoutBaseTest extends BaseDynamicCoordinatorLayoutTest {
-
-    protected AppBarLayout mAppBar;
-
-    protected CollapsingToolbarLayout mCollapsingToolbar;
-
-    protected Toolbar mToolbar;
-
-    protected TextView mTextView;
-
-    protected float mDefaultElevationValue;
-
-    protected static void performVerticalSwipeUpGesture(@IdRes int containerId, final int swipeX,
-            final int swipeStartY, final int swipeAmountY) {
-        onView(withId(containerId)).perform(swipeUp(swipeX, swipeStartY, swipeAmountY));
-    }
-
-    protected static void performVerticalSwipeDownGesture(@IdRes int containerId, final int swipeX,
-            final int swipeStartY, final int swipeAmountY) {
-        onView(withId(containerId)).perform(swipeDown(swipeX, swipeStartY, swipeAmountY));
-    }
-
-    @CallSuper
-    protected void configureContent(@LayoutRes final int layoutResId,
-            @StringRes final int titleResId) throws Throwable {
-        onView(withId(R.id.coordinator_stub)).perform(inflateViewStub(layoutResId));
-
-        mAppBar = (AppBarLayout) mCoordinatorLayout.findViewById(R.id.app_bar);
-        mCollapsingToolbar =
-                (CollapsingToolbarLayout) mAppBar.findViewById(R.id.collapsing_app_bar);
-        mToolbar = (Toolbar) mAppBar.findViewById(R.id.toolbar);
-
-        final AppCompatActivity activity = mActivityTestRule.getActivity();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                activity.setSupportActionBar(mToolbar);
-            }
-        });
-
-        final CharSequence activityTitle = activity.getString(titleResId);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                activity.setTitle(activityTitle);
-            }
-        });
-
-        if (mCollapsingToolbar != null) {
-            onView(withId(R.id.collapsing_app_bar))
-                    .perform(setTitle(activityTitle))
-                    .perform(setContentScrimColor(Color.MAGENTA));
-        }
-
-        TextView dialog = (TextView) mCoordinatorLayout.findViewById(R.id.textview_dialogue);
-        if (dialog != null) {
-            onView(withId(R.id.textview_dialogue))
-                    .perform(setText(TextUtils.concat(Shakespeare.DIALOGUE)));
-        }
-
-        mDefaultElevationValue = mAppBar.getResources()
-                .getDimension(R.dimen.design_appbar_elevation);
-    }
-
-    protected void assertAppBarElevation(float expectedValue) {
-        if (Build.VERSION.SDK_INT >= 21) {
-            assertEquals(expectedValue, ViewCompat.getElevation(mAppBar), 0.05f);
-        }
-    }
-
-    protected void assertScrimAlpha(@IntRange(from = 0, to = 255) int alpha) {
-        SystemClock.sleep(300);
-        onView(withId(R.id.collapsing_app_bar))
-                .check(matches(withScrimAlpha(alpha)));
-    }
-
-    static Matcher withScrimAlpha(final int alpha) {
-        return new TypeSafeMatcher<CollapsingToolbarLayout>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText(
-                        "CollapsingToolbarLayout has content scrim with alpha: " + alpha);
-            }
-
-            @Override
-            protected boolean matchesSafely(CollapsingToolbarLayout view) {
-                return alpha == view.getScrimAlpha();
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarLayoutCollapsePinTestActivity.java b/design/tests/src/android/support/design/widget/AppBarLayoutCollapsePinTestActivity.java
deleted file mode 100644
index d7ea68f..0000000
--- a/design/tests/src/android/support/design/widget/AppBarLayoutCollapsePinTestActivity.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-import android.support.v7.widget.Toolbar;
-
-public class AppBarLayoutCollapsePinTestActivity extends BaseTestActivity {
-
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_appbar_toolbar_collapse_pin_restore_test;
-    }
-
-    @Override
-    protected void onContentViewSet() {
-        Toolbar toolbar = findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithAnchoredFabMarginsTest.java b/design/tests/src/android/support/design/widget/AppBarWithAnchoredFabMarginsTest.java
deleted file mode 100644
index 416eda1..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithAnchoredFabMarginsTest.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.junit.Assert.assertEquals;
-
-import android.support.design.test.R;
-import android.support.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-
-@SmallTest
-public class AppBarWithAnchoredFabMarginsTest extends AppBarLayoutBaseTest {
-    private int mFabMargin;
-
-    @Before
-    public void setup() {
-        mFabMargin = mActivityTestRule.getActivity().getResources().getDimensionPixelSize(
-                R.dimen.fab_margin);
-    }
-
-    @Test
-    public void testFabBottomMargin() throws Throwable {
-        configureContent(R.layout.design_appbar_anchored_fab_margin_bottom,
-                R.string.design_appbar_anchored_fab_margin_bottom);
-
-        final FloatingActionButton fab =
-                (FloatingActionButton) mCoordinatorLayout.findViewById(R.id.fab);
-        final CoordinatorLayout.LayoutParams fabLp =
-                (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
-        assertEquals(mAppBar.getId(), fabLp.getAnchorId());
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] fabOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        fab.getLocationOnScreen(fabOnScreenXY);
-
-        // FAB is horizontally centered in the coordinate system of its anchor (app bar).
-        assertEquals(appbarOnScreenXY[0] + mAppBar.getWidth() / 2,
-                fabOnScreenXY[0] + fab.getWidth() / 2, 1);
-        // Bottom margin is in the coordinate space of the parent (CoordinatorLayout) and not
-        // the anchor. Since our FAB is far enough from the bottom edge of CoordinatorLayout,
-        // we are expecting the vertical center of the FAB to be aligned with the bottom edge
-        // of its anchor (app bar).
-        assertEquals(appbarOnScreenXY[1] + mAppBar.getHeight(),
-                fabOnScreenXY[1] + fab.getHeight() / 2, 1);
-    }
-
-    @Test
-    public void testFabTopMargin() throws Throwable {
-        configureContent(R.layout.design_appbar_anchored_fab_margin_top,
-                R.string.design_appbar_anchored_fab_margin_top);
-
-        final FloatingActionButton fab =
-                (FloatingActionButton) mCoordinatorLayout.findViewById(R.id.fab);
-        final CoordinatorLayout.LayoutParams fabLp =
-                (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
-        assertEquals(mAppBar.getId(), fabLp.getAnchorId());
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] fabOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        fab.getLocationOnScreen(fabOnScreenXY);
-
-        // FAB is horizontally centered in the coordinate system of its anchor (app bar).
-        assertEquals(appbarOnScreenXY[0] + mAppBar.getWidth() / 2,
-                fabOnScreenXY[0] + fab.getWidth() / 2, 1);
-        // Top margin is in the coordinate space of the parent (CoordinatorLayout) and not
-        // the anchor. Since our FAB is far enough from the bottom edge of CoordinatorLayout,
-        // we are expecting the vertical center of the FAB to be aligned with the bottom edge
-        // of its anchor (app bar).
-        assertEquals(appbarOnScreenXY[1] + mAppBar.getHeight(),
-                fabOnScreenXY[1] + fab.getHeight() / 2, 1);
-    }
-
-    @Test
-    public void testFabLeftMargin() throws Throwable {
-        configureContent(R.layout.design_appbar_anchored_fab_margin_left,
-                R.string.design_appbar_anchored_fab_margin_left);
-
-        final FloatingActionButton fab =
-                (FloatingActionButton) mCoordinatorLayout.findViewById(R.id.fab);
-        final CoordinatorLayout.LayoutParams fabLp =
-                (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
-        assertEquals(mAppBar.getId(), fabLp.getAnchorId());
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] fabOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        fab.getLocationOnScreen(fabOnScreenXY);
-
-        // FAB is left-aligned in the coordinate system of its anchor (app bar). In addition,
-        // its left margin "pushes" it away in the coordinate system of the parent
-        // (CoordinatorLayout)
-        assertEquals(appbarOnScreenXY[0] + mFabMargin, fabOnScreenXY[0], 1);
-        // FAB's vertical center should be aligned with the bottom edge of its anchor (app bar).
-        assertEquals(appbarOnScreenXY[1] + mAppBar.getHeight(),
-                fabOnScreenXY[1] + fab.getHeight() / 2, 1);
-    }
-
-    @Test
-    public void testFabRightMargin() throws Throwable {
-        configureContent(R.layout.design_appbar_anchored_fab_margin_right,
-                R.string.design_appbar_anchored_fab_margin_right);
-
-        final FloatingActionButton fab =
-                (FloatingActionButton) mCoordinatorLayout.findViewById(R.id.fab);
-        final CoordinatorLayout.LayoutParams fabLp =
-                (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
-        assertEquals(mAppBar.getId(), fabLp.getAnchorId());
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] fabOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        fab.getLocationOnScreen(fabOnScreenXY);
-
-        // FAB is right-aligned in the coordinate system of its anchor (app bar). In addition,
-        // its right margin "pushes" it away in the coordinate system of the parent
-        // (CoordinatorLayout)
-        assertEquals(appbarOnScreenXY[0] + mAppBar.getWidth() - mFabMargin,
-                fabOnScreenXY[0] + fab.getWidth(), 1);
-        // FAB's vertical center should be aligned with the bottom edge of its anchor (app bar).
-        assertEquals(appbarOnScreenXY[1] + mAppBar.getHeight(),
-                fabOnScreenXY[1] + fab.getHeight() / 2, 1);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java
deleted file mode 100644
index e8a29af..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarStateRestoreTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.AppBarLayoutMatchers.isCollapsed;
-import static android.support.design.testutils.SwipeUtils.swipeUp;
-import static android.support.design.testutils.TestUtilsMatchers.hasZ;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import android.support.design.test.R;
-import android.support.test.filters.LargeTest;
-import android.support.testutils.AppCompatActivityUtils;
-
-import org.junit.Before;
-import org.junit.Test;
-
-@LargeTest
-public class AppBarWithCollapsingToolbarStateRestoreTest
-        extends BaseInstrumentationTestCase<AppBarLayoutCollapsePinTestActivity> {
-
-    private AppBarLayoutCollapsePinTestActivity mActivity;
-
-    public AppBarWithCollapsingToolbarStateRestoreTest() {
-        super(AppBarLayoutCollapsePinTestActivity.class);
-    }
-
-    @Before
-    public void setup() {
-        mActivity = mActivityTestRule.getActivity();
-    }
-
-    @Test
-    public void testRecreateAndRestore() throws Throwable {
-        final AppBarLayout appBar = (AppBarLayout) mActivity.findViewById(R.id.app_bar);
-
-        // Swipe up and collapse the AppBarLayout
-        onView(withId(R.id.coordinator_layout))
-                .perform(swipeUp(
-                        appBar.getLeft() + (appBar.getWidth() / 2),
-                        appBar.getBottom() + 20,
-                        appBar.getHeight()));
-        onView(withId(R.id.app_bar))
-                .check(matches(hasZ()))
-                .check(matches(isCollapsed()));
-
-        mActivity = AppCompatActivityUtils.recreateActivity(mActivityTestRule, mActivity);
-        AppCompatActivityUtils.waitForExecution(mActivityTestRule);
-
-        // And check that the app bar still is restored correctly
-        onView(withId(R.id.app_bar))
-                .check(matches(hasZ()))
-                .check(matches(isCollapsed()));
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java b/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
deleted file mode 100644
index a9fa46a..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithCollapsingToolbarTest.java
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.Matchers.greaterThan;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import android.support.design.test.R;
-import android.support.test.filters.LargeTest;
-import android.support.testutils.PollingCheck;
-import android.widget.ImageView;
-
-import org.junit.Test;
-
-@LargeTest
-public class AppBarWithCollapsingToolbarTest extends AppBarLayoutBaseTest {
-
-    @Test
-    public void testPinnedToolbar() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_pin,
-                R.string.design_appbar_collapsing_toolbar_pin);
-
-        CollapsingToolbarLayout.LayoutParams toolbarLp =
-                (CollapsingToolbarLayout.LayoutParams) mToolbar.getLayoutParams();
-        assertEquals(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PIN,
-                toolbarLp.getCollapseMode());
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] coordinatorLayoutOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int toolbarHeight = mToolbar.getHeight();
-        final int appbarHeight = mAppBar.getHeight();
-        final int longSwipeAmount = 3 * appbarHeight / 2;
-        final int reallyLongSwipeAmount = 2 * appbarHeight;
-        final int shortSwipeAmount = toolbarHeight;
-
-        assertAppBarElevation(0f);
-        assertScrimAlpha(0);
-
-        // Perform a swipe-up gesture across the horizontal center of the screen.
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + longSwipeAmount / 2,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be visually snapped below the system status bar.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + toolbarHeight + mAppBar.getTopInset(),
-                appbarOnScreenXY[1] + appbarHeight, 1);
-
-        // Perform another swipe-up gesture
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                appbarOnScreenXY[1] + appbarHeight + 5,
-                shortSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be visually snapped below the system status bar
-        // as it is in the pinned mode. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + toolbarHeight + mAppBar.getTopInset(),
-                appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(255);
-
-        // Perform a short swipe-down gesture across the horizontal center of the screen.
-        // Note that the swipe down is a bit longer than the swipe up to check that the app bar
-        // is not starting to expand too early.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom - shortSwipeAmount,
-                3 * shortSwipeAmount / 2);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be visually snapped below the system status bar
-        // as it is in the pinned mode and we haven't fully swiped down the content below the
-        // app bar. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + toolbarHeight + mAppBar.getTopInset(),
-                appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(255);
-
-        // Perform another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                reallyLongSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(0f);
-        assertScrimAlpha(0);
-
-        // Perform yet another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(0f);
-        assertScrimAlpha(0);
-    }
-
-    @Test
-    public void testScrollingToolbar() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_scroll,
-                R.string.design_appbar_collapsing_toolbar_scroll);
-
-        CollapsingToolbarLayout.LayoutParams toolbarLp =
-                (CollapsingToolbarLayout.LayoutParams) mToolbar.getLayoutParams();
-        assertEquals(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PIN,
-                toolbarLp.getCollapseMode());
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] coordinatorLayoutOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
-
-        final int topInset = mAppBar.getTopInset();
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int toolbarHeight = mToolbar.getHeight();
-        final int appbarHeight = mAppBar.getHeight();
-        final int longSwipeAmount = 3 * appbarHeight / 2;
-        final int reallyLongSwipeAmount = 2 * appbarHeight;
-        final int shortSwipeAmount = toolbarHeight;
-
-        assertAppBarElevation(0f);
-        assertScrimAlpha(0);
-
-        // Perform a swipe-up gesture across the horizontal center of the screen, starting from
-        // just below the AppBarLayout
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + 20,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should not be visually "present" on the screen, with its bottom
-        // edge aligned with the bottom of system status bar. If we're running on a device which
-        // supports a translucent status bar, we need to take the status bar height into account.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight - topInset, 1);
-        assertAppBarElevation(0f);
-        assertScrimAlpha(255);
-
-        // Perform another swipe-up gesture
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                shortSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be off the screen. Allow for off-by-a-pixel
-        // margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight - topInset, 1);
-        assertAppBarElevation(0f);
-        assertScrimAlpha(255);
-
-        // Perform a short swipe-down gesture across the horizontal center of the screen.
-        // Note that the swipe down is a bit longer than the swipe up to fully bring down
-        // the scrolled-away toolbar
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                3 * shortSwipeAmount / 2);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be visually snapped below the system status bar as it
-        // in scrolling mode and we've swiped down, but not fully. Allow for off-by-a-pixel
-        // margin of error.
-        assertEquals(originalAppbarTop + toolbarHeight + topInset,
-                appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(255);
-
-        // Perform another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                reallyLongSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1]);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight);
-        assertAppBarElevation(0f);
-        assertScrimAlpha(0);
-
-        // Perform yet another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(0f);
-        assertScrimAlpha(0);
-    }
-
-    @Test
-    public void testScrollingToolbarEnterAlways() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_scroll_enteralways,
-                R.string.design_appbar_collapsing_toolbar_scroll);
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] coordinatorLayoutOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
-
-        final int topInset = mAppBar.getTopInset();
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int toolbarHeight = mToolbar.getHeight();
-        final int appbarHeight = mAppBar.getHeight();
-        final int longSwipeAmount = 3 * appbarHeight / 2;
-        final int reallyLongSwipeAmount = 2 * appbarHeight;
-        final int shortSwipeAmount = toolbarHeight;
-
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(0);
-
-        // Perform a swipe-up gesture across the horizontal center of the screen, starting from
-        // just below the AppBarLayout
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + 20,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should not be visually "present" on the screen, with its bottom
-        // edge aligned with the bottom of system status bar. If we're running on a device which
-        // supports a translucent status bar, we need to take the status bar height into account.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight - topInset, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(255);
-
-        // Perform another swipe-up gesture
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                shortSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be off the screen. Allow for off-by-a-pixel
-        // margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight - topInset, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(255);
-
-        // Perform a short swipe-down gesture across the horizontal center of the screen.
-        // Note that the swipe down is a bit longer than the swipe up to fully bring down
-        // the scrolled-away toolbar
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                3 * shortSwipeAmount / 2);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-
-        // At this point the app bar should be visually below the system status bar as it
-        // in scrolling mode and we've swiped down, not fully but more than collapsed
-        assertThat(appbarOnScreenXY[1] + appbarHeight,
-                is(greaterThan(originalAppbarTop + toolbarHeight + topInset)));
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(255);
-
-        // Perform another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                reallyLongSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1]);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight);
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(0);
-
-        // Perform yet another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-        assertScrimAlpha(0);
-    }
-
-    @Test
-    public void testPinnedToolbarAndAnchoredFab() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_pin_with_fab,
-                R.string.design_appbar_collapsing_toolbar_pin_fab);
-
-        CollapsingToolbarLayout.LayoutParams toolbarLp =
-                (CollapsingToolbarLayout.LayoutParams) mToolbar.getLayoutParams();
-        assertEquals(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PIN,
-                toolbarLp.getCollapseMode());
-
-        final FloatingActionButton fab =
-                (FloatingActionButton) mCoordinatorLayout.findViewById(R.id.fab);
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] coordinatorLayoutOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
-
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int appbarHeight = mAppBar.getHeight();
-        final int longSwipeAmount = 3 * appbarHeight / 2;
-
-        // Perform a swipe-up gesture across the horizontal center of the screen.
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + longSwipeAmount / 2,
-                longSwipeAmount);
-
-        // Since we the visibility change listener path is only exposed via direct calls to
-        // FloatingActionButton.show and not the internal path that FAB's behavior is using,
-        // this test needs to be tied to the internal implementation details of running animation
-        // that scales the FAB to 0/0 scales and interpolates its alpha to 0. Since that animation
-        // starts running partway through our swipe gesture and may complete a bit later then
-        // the swipe gesture, poll to catch the "final" state of the FAB.
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return fab.getScaleX() == 0.0f;
-            }
-        });
-
-        // At this point the FAB should be scaled to 0/0 and set at alpha 0. Since the relevant
-        // getter methods are only available on v11+, wrap the asserts with build version check.
-        assertEquals(0.0f, fab.getScaleX(), 0.0f);
-        assertEquals(0.0f, fab.getScaleY(), 0.0f);
-        assertEquals(0.0f, fab.getAlpha(), 0.0f);
-
-        // Perform a swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        // Same as for swipe-up gesture.
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return fab.getScaleX() == 1.0f;
-            }
-        });
-
-        // At this point the FAB should be scaled back to its original size and be at full opacity.
-        assertEquals(1.0f, fab.getScaleX(), 0.0f);
-        assertEquals(1.0f, fab.getScaleY(), 0.0f);
-        assertEquals(1.0f, fab.getAlpha(), 0.0f);
-    }
-
-    @Test
-    public void testPinnedToolbarAndParallaxImage() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_with_image,
-                R.string.design_appbar_collapsing_toolbar_with_image);
-
-        final ImageView parallaxImageView =
-                (ImageView) mCoordinatorLayout.findViewById(R.id.app_bar_image);
-
-        // We have not set any padding on the ImageView, so ensure that none is set via
-        // window insets handling
-        assertEquals(0, parallaxImageView.getPaddingLeft());
-        assertEquals(0, parallaxImageView.getPaddingTop());
-        assertEquals(0, parallaxImageView.getPaddingRight());
-        assertEquals(0, parallaxImageView.getPaddingBottom());
-
-        CollapsingToolbarLayout.LayoutParams parallaxImageViewLp =
-                (CollapsingToolbarLayout.LayoutParams) parallaxImageView.getLayoutParams();
-        assertEquals(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PARALLAX,
-                parallaxImageViewLp.getCollapseMode());
-
-        final float parallaxMultiplier = parallaxImageViewLp.getParallaxMultiplier();
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] parallaxImageOnScreenXY = new int[2];
-        final int appbarHeight = mAppBar.getHeight();
-        final int toolbarHeight = mToolbar.getHeight();
-        final int parallaxImageHeight = parallaxImageView.getHeight();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        parallaxImageView.getLocationOnScreen(parallaxImageOnScreenXY);
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int originalParallaxImageTop = parallaxImageOnScreenXY[1];
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        // Test that at the beginning our image is top-aligned with the app bar
-        assertEquals(appbarOnScreenXY[1], parallaxImageOnScreenXY[1]);
-
-        // Swipe up by the toolbar's height
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                toolbarHeight);
-
-        // Test that the top edge of the image (in the screen coordinates) has "moved" by half
-        // the amount that the top edge of the app bar (in the screen coordinates) has.
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        parallaxImageView.getLocationOnScreen(parallaxImageOnScreenXY);
-        assertEquals(parallaxMultiplier * (appbarOnScreenXY[1] - originalAppbarTop),
-                parallaxImageOnScreenXY[1] - originalParallaxImageTop, 1);
-
-        // Swipe up by another toolbar's height
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                toolbarHeight);
-
-        // Test that the top edge of the image (in the screen coordinates) has "moved" by half
-        // the amount that the top edge of the app bar (in the screen coordinates) has.
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        parallaxImageView.getLocationOnScreen(parallaxImageOnScreenXY);
-        assertEquals(parallaxMultiplier * (appbarOnScreenXY[1] - originalAppbarTop),
-                parallaxImageOnScreenXY[1] - originalParallaxImageTop, 1);
-
-        // Swipe down by a different value (150% of the toolbar's height) to test parallax going the
-        // other way
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                3 * toolbarHeight / 2);
-
-        // Test that the top edge of the image (in the screen coordinates) has "moved" by half
-        // the amount that the top edge of the app bar (in the screen coordinates) has.
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        parallaxImageView.getLocationOnScreen(parallaxImageOnScreenXY);
-        assertEquals(parallaxMultiplier * (appbarOnScreenXY[1] - originalAppbarTop),
-                parallaxImageOnScreenXY[1] - originalParallaxImageTop, 1);
-    }
-
-    @Test
-    public void testAddViewWithDefaultLayoutParams() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_pin,
-                R.string.design_appbar_collapsing_toolbar_pin);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ImageView view = new ImageView(mCollapsingToolbar.getContext());
-                mCollapsingToolbar.addView(view);
-            }
-        });
-
-    }
-
-    @Test
-    public void testPinnedToolbarWithMargins() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_pin_margins,
-                R.string.design_appbar_collapsing_toolbar_pin_margins);
-
-        CollapsingToolbarLayout.LayoutParams toolbarLp =
-                (CollapsingToolbarLayout.LayoutParams) mToolbar.getLayoutParams();
-        assertEquals(CollapsingToolbarLayout.LayoutParams.COLLAPSE_MODE_PIN,
-                toolbarLp.getCollapseMode());
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] toolbarOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mToolbar.getLocationOnScreen(toolbarOnScreenXY);
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = originalAppbarTop + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int toolbarHeight = mToolbar.getHeight();
-        final int toolbarVerticalMargins = toolbarLp.topMargin + toolbarLp.bottomMargin;
-        final int appbarHeight = mAppBar.getHeight();
-
-        // Perform a swipe-up gesture across the horizontal center of the screen.
-        int swipeAmount = appbarHeight - toolbarHeight - toolbarVerticalMargins;
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + (3 * swipeAmount / 2),
-                swipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mToolbar.getLocationOnScreen(toolbarOnScreenXY);
-        // At this point the toolbar should be visually pinned to the bottom of the appbar layout,
-        // observing it's margins and top inset
-        // The toolbar should still be visually pinned to the bottom of the appbar layout
-        assertEquals(originalAppbarTop + mAppBar.getTopInset(),
-                toolbarOnScreenXY[1] - toolbarLp.topMargin, 1);
-
-        // Swipe up again, this time just 50% of the margin size
-        swipeAmount = toolbarVerticalMargins / 2;
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + (3 * swipeAmount / 2),
-                swipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mToolbar.getLocationOnScreen(toolbarOnScreenXY);
-
-        // The toolbar should still be visually pinned to the bottom of the appbar layout
-        assertEquals(appbarOnScreenXY[1] + appbarHeight,
-                toolbarOnScreenXY[1] + toolbarHeight + toolbarLp.bottomMargin, 1);
-    }
-
-    @Test
-    public void testSingleToolbarWithInset() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_collapse_sole_toolbar,
-                R.string.design_appbar_collapsing_toolbar_pin_margins);
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] toolbarOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mToolbar.getLocationOnScreen(toolbarOnScreenXY);
-
-        assertEquals(appbarOnScreenXY[1] + mAppBar.getTopInset(), toolbarOnScreenXY[1], 1);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithDodgingTest.java b/design/tests/src/android/support/design/widget/AppBarWithDodgingTest.java
deleted file mode 100644
index ad337d5..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithDodgingTest.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Rect;
-import android.support.design.test.R;
-import android.support.test.filters.SmallTest;
-
-import org.junit.Test;
-
-@SmallTest
-public class AppBarWithDodgingTest extends AppBarLayoutBaseTest {
-    @Test
-    public void testLeftDodge() throws Throwable {
-        configureContent(R.layout.design_appbar_dodge_left,
-                R.string.design_appbar_dodge_left);
-
-        final FloatingActionButton fab = mCoordinatorLayout.findViewById(R.id.fab);
-        final FloatingActionButton fab2 = mCoordinatorLayout.findViewById(R.id.fab2);
-
-        final int[] fabOnScreenXY = new int[2];
-        final int[] fab2OnScreenXY = new int[2];
-        fab.getLocationOnScreen(fabOnScreenXY);
-        fab2.getLocationOnScreen(fab2OnScreenXY);
-
-        final Rect fabRect = new Rect();
-        final Rect fab2Rect = new Rect();
-        fab.getContentRect(fabRect);
-        fab2.getContentRect(fab2Rect);
-
-        // Our second FAB is configured to "dodge" the first one - to be displayed to the
-        // right of it
-        int firstRight = fabOnScreenXY[0] + fabRect.right;
-        int secondLeft = fab2OnScreenXY[0] + fab2Rect.left;
-        assertTrue("Second button left edge at " + secondLeft
-                        + " should be dodging the first button right edge at " + firstRight,
-                secondLeft >= firstRight);
-    }
-
-    @Test
-    public void testRightDodge() throws Throwable {
-        configureContent(R.layout.design_appbar_dodge_right,
-                R.string.design_appbar_dodge_right);
-
-        final FloatingActionButton fab = mCoordinatorLayout.findViewById(R.id.fab);
-        final FloatingActionButton fab2 = mCoordinatorLayout.findViewById(R.id.fab2);
-
-        final int[] fabOnScreenXY = new int[2];
-        final int[] fab2OnScreenXY = new int[2];
-        fab.getLocationOnScreen(fabOnScreenXY);
-        fab2.getLocationOnScreen(fab2OnScreenXY);
-
-        final Rect fabRect = new Rect();
-        final Rect fab2Rect = new Rect();
-        fab.getContentRect(fabRect);
-        fab2.getContentRect(fab2Rect);
-
-        // Our second FAB is configured to "dodge" the first one - to be displayed to the
-        // left of it
-        int firstLeft = fabOnScreenXY[0] + fabRect.left;
-        int secondRight = fab2OnScreenXY[0] + fab2Rect.right;
-        assertTrue("Second button right edge at " + secondRight
-                        + " should be dodging the first button left edge at " + firstLeft,
-                secondRight <= firstLeft);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithScrollbarsActivity.java b/design/tests/src/android/support/design/widget/AppBarWithScrollbarsActivity.java
deleted file mode 100644
index bd693d4..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithScrollbarsActivity.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class AppBarWithScrollbarsActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_appbar_with_scrollbars;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithScrollbarsTest.java b/design/tests/src/android/support/design/widget/AppBarWithScrollbarsTest.java
deleted file mode 100644
index f6fe8bf..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithScrollbarsTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.test.filters.SmallTest;
-
-import org.junit.Test;
-
-public class AppBarWithScrollbarsTest extends
-        BaseInstrumentationTestCase<AppBarWithScrollbarsActivity> {
-
-    public AppBarWithScrollbarsTest() {
-        super(AppBarWithScrollbarsActivity.class);
-    }
-
-    @Test
-    @SmallTest
-    public void testInflationNoCrash() {
-        // This is the implicit test for to check that AppBarLayout inflation doesn't crash
-        // when its theme has attributes that would cause onCreateDrawableState to be called
-        // during the super's constructor flow.
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithToolbarAndTabsTest.java b/design/tests/src/android/support/design/widget/AppBarWithToolbarAndTabsTest.java
deleted file mode 100644
index 23ef7c5..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithToolbarAndTabsTest.java
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.TestUtilsActions.addTabs;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.junit.Assert.assertEquals;
-
-import android.os.SystemClock;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.StringRes;
-import android.support.design.test.R;
-import android.support.design.testutils.Cheeses;
-import android.support.test.filters.FlakyTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.Suppress;
-
-import org.junit.Test;
-
-@LargeTest
-public class AppBarWithToolbarAndTabsTest extends AppBarLayoutBaseTest {
-    private TabLayout mTabLayout;
-
-    @Override
-    protected void configureContent(@LayoutRes int layoutResId, @StringRes int titleResId)
-            throws Throwable {
-        super.configureContent(layoutResId, titleResId);
-
-        mTabLayout = (TabLayout) mAppBar.findViewById(R.id.tabs);
-        String[] tabTitles = new String[5];
-        System.arraycopy(Cheeses.sCheeseStrings, 0, tabTitles, 0, 5);
-        onView(withId(R.id.tabs)).perform(addTabs(tabTitles));
-    }
-
-    @Test
-    public void testScrollingToolbarAndScrollingTabs() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_tabs_scroll,
-                R.string.design_appbar_toolbar_scroll_tabs_scroll);
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] coordinatorLayoutOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int toolbarHeight = mToolbar.getHeight();
-        final int tabsHeight = mTabLayout.getHeight();
-        final int appbarHeight = mAppBar.getHeight();
-        final int longSwipeAmount = 3 * appbarHeight / 2;
-        final int shortSwipeAmount = toolbarHeight;
-
-        // Perform a swipe-up gesture across the horizontal center of the screen, starting from
-        // just below the AppBarLayout
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + 20,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should not be visually "present" on the screen, with its bottom
-        // edge aligned with the system status bar. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform another swipe-up gesture
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                shortSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be off the screen. Allow for off-by-a-pixel
-        // margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a long swipe-down gesture across the horizontal center of the screen.
-        // Note that the swipe down is a bit longer than the swipe up to fully bring down
-        // the scrolled-away toolbar and tab layout
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount * 3 / 2);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be visually snapped below the system status bar as it
-        // in scrolling mode and we've swiped down. Allow for off-by-a-pixel
-        // margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform yet another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-    }
-
-    @Test
-    public void testScrollingToolbarAndPinnedTabs() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_tabs_pinned,
-                R.string.design_appbar_toolbar_scroll_tabs_pin);
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] coordinatorLayoutOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int toolbarHeight = mToolbar.getHeight();
-        final int tabsHeight = mTabLayout.getHeight();
-        final int appbarHeight = mAppBar.getHeight();
-        final int longSwipeAmount = 3 * appbarHeight / 2;
-        final int shortSwipeAmount = toolbarHeight;
-
-        // Perform a swipe-up gesture across the horizontal center of the screen, starting from
-        // just below the AppBarLayout
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + 20,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the tab bar should be visually snapped below the system status bar.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform another swipe-up gesture
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                shortSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the tab bar should still be visually snapped below the system status bar
-        // as it is in the pinned mode. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a short swipe-down gesture across the horizontal center of the screen.
-        // Note that the swipe down is a bit longer than the swipe up to fully bring down
-        // the scrolled-away toolbar and tab layout
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom - shortSwipeAmount,
-                3 * shortSwipeAmount / 2);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position as it
-        // in scrolling mode and we've swiped down. Allow for off-by-a-pixel
-        // margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform yet another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-    }
-
-    @Suppress
-    @FlakyTest(bugId = 30701044)
-    @LargeTest
-    @Test
-    public void testSnappingToolbarAndSnappingTabs() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_tabs_scroll_snap,
-                R.string.design_appbar_toolbar_scroll_tabs_scroll_snap);
-
-        final int[] appbarOnScreenXY = new int[2];
-        final int[] coordinatorLayoutOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        mCoordinatorLayout.getLocationOnScreen(coordinatorLayoutOnScreenXY);
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int toolbarHeight = mToolbar.getHeight();
-        final int tabsHeight = mTabLayout.getHeight();
-        final int appbarHeight = mAppBar.getHeight();
-
-        // Since AppBarLayout doesn't expose a way to track snap animations, the three possible
-        // options are
-        // a) track how vertical offsets and invalidation is propagated through the
-        // view hierarchy and wait until there are no more events of that kind
-        // b) run a dummy Espresso action that waits until the main thread is idle
-        // c) sleep for a hardcoded period of time to "wait" until the snap animation is done
-        // In this test method we go with option b)
-
-        // Perform a swipe-up gesture across the horizontal center of the screen. The amount
-        // of swipe is 25% of the toolbar height and we expect the snap behavior to "move"
-        // the app bar back to its original position.
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                toolbarHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position as it
-        // in snapping mode and we haven't swiped "enough". Allow for off-by-a-pixel
-        // margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a slightly longer swipe-up gesture, this time by 75% of the toolbar height.
-        // We expect the snap behavior to move the app bar to snap the tab layout below the
-        // system status bar.
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                3 * toolbarHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should "snap" the toolbar away and align the tab layout below
-        // the system status bar. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a short swipe-up gesture, this time by 25% of the tab layout height. We expect
-        // snap behavior to move the app bar back to snap the tab layout below the system status
-        // bar.
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                tabsHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should "snap" back to align the tab layout below
-        // the system status bar. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a longer swipe-up gesture, this time by 75% of the tab layout height. We expect
-        // snap behavior to move the app bar fully away from the screen.
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                3 * tabsHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should not be visually "present" on the screen, with its bottom
-        // edge aligned with the system status bar. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a short swipe-down gesture by 25% of the tab layout height. We expect
-        // snap behavior to move the app bar back fully away from the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                tabsHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still not be visually "present" on the screen, with
-        // its bottom edge aligned with the system status bar. Allow for off-by-a-pixel margin
-        // of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a longer swipe-up gesture, this time by 75% of the tab layout height. We expect
-        // snap behavior to move the app bar to snap the tab layout below the system status
-        // bar.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                3 * tabsHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should "snap" the toolbar away and align the tab layout below
-        // the system status bar. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a short swipe-down gesture by 25% of the toolbar height. We expect
-        // snap behavior to align the tab layout below the system status bar
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                toolbarHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should still align the tab layout below
-        // the system status bar. Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop + tabsHeight, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-
-        // Perform a longer swipe-up gesture, this time by 75% of the toolbar height. We expect
-        // snap behavior to move the app bar back to its original place (fully visible).
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + toolbarHeight,
-                3 * tabsHeight / 4);
-
-        // Wait for the snap animation to be done
-        waitForSnapAnimationToFinish();
-
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        // At this point the app bar should be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-        assertAppBarElevation(mDefaultElevationValue);
-    }
-
-    private void waitForSnapAnimationToFinish() {
-        final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior)
-                ((CoordinatorLayout.LayoutParams) mAppBar.getLayoutParams()).getBehavior();
-        while (behavior.isOffsetAnimatorRunning()) {
-            SystemClock.sleep(16);
-        }
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/AppBarWithToolbarTest.java b/design/tests/src/android/support/design/widget/AppBarWithToolbarTest.java
deleted file mode 100644
index fd5cd26..0000000
--- a/design/tests/src/android/support/design/widget/AppBarWithToolbarTest.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.junit.Assert.assertEquals;
-
-import android.graphics.Rect;
-import android.support.design.test.R;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.junit.Test;
-
-@MediumTest
-public class AppBarWithToolbarTest extends AppBarLayoutBaseTest {
-
-    /**
-     * Tests a Toolbar with fitSystemWindows = undefined, with a fitSystemWindows = true parent
-     */
-    @LargeTest
-    @Test
-    public void testScrollToolbarWithFitSystemWindowsParent() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_fitsystemwindows_parent,
-                R.string.design_appbar_toolbar_scroll_tabs_pin);
-
-        final int[] appbarOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-
-        final int originalAppbarTop = appbarOnScreenXY[1];
-        final int originalAppbarBottom = appbarOnScreenXY[1] + mAppBar.getHeight();
-        final int centerX = appbarOnScreenXY[0] + mAppBar.getWidth() / 2;
-
-        final int appbarHeight = mAppBar.getHeight();
-        final int longSwipeAmount = 3 * appbarHeight / 2;
-
-        // Perform a swipe-up gesture across the horizontal center of the screen.
-        performVerticalSwipeUpGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom + 3 * longSwipeAmount / 2,
-                longSwipeAmount);
-
-        // At this point the tab bar should be visually snapped below the system status bar.
-        // Allow for off-by-a-pixel margin of error.
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1] + appbarHeight, 1);
-
-        // Perform yet another swipe-down gesture across the horizontal center of the screen.
-        performVerticalSwipeDownGesture(
-                R.id.coordinator_layout,
-                centerX,
-                originalAppbarBottom,
-                longSwipeAmount);
-
-        // At this point the app bar should still be in its original position.
-        // Allow for off-by-a-pixel margin of error.
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-        assertEquals(originalAppbarTop, appbarOnScreenXY[1], 1);
-        assertEquals(originalAppbarBottom, appbarOnScreenXY[1] + appbarHeight, 1);
-    }
-
-    /**
-     * Tests a AppBarLayout + scrolling content with fitSystemWindows = undefined,
-     * with a fitSystemWindows = true parent
-     */
-    @Test
-    public void testScrollingContentPositionWithFitSystemWindowsParent() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_fitsystemwindows_parent,
-                R.string.design_appbar_toolbar_scroll_tabs_pin);
-
-        final int[] appbarOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-
-        final View scrollingContent = mCoordinatorLayout.findViewById(R.id.scrolling_content);
-        final int[] scrollingContentOnScreenXY = new int[2];
-        scrollingContent.getLocationOnScreen(scrollingContentOnScreenXY);
-
-        // Assert that they have the same left
-        assertEquals(appbarOnScreenXY[0], scrollingContentOnScreenXY[0]);
-        // ...and the same width
-        assertEquals(mAppBar.getWidth(), scrollingContent.getWidth());
-        // ...and are vertically stacked
-        assertEquals(mAppBar.getBottom(), scrollingContent.getTop());
-    }
-
-    /**
-     * Tests a AppBarLayout + scrolling content with fitSystemWindows = undefined,
-     * with a fitSystemWindows = true parent, in RTL
-     */
-    @Test
-    public void testScrollingContentPositionWithFitSystemWindowsParentInRtl() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_fitsystemwindows_parent,
-                R.string.design_appbar_toolbar_scroll_tabs_pin);
-
-        // Force RTL
-        onView(withId(R.id.app_bar)).perform(setLayoutDirection(ViewCompat.LAYOUT_DIRECTION_RTL));
-
-        final int[] appbarOnScreenXY = new int[2];
-        mAppBar.getLocationOnScreen(appbarOnScreenXY);
-
-        final View scrollingContent = mCoordinatorLayout.findViewById(R.id.scrolling_content);
-        final int[] scrollingContentOnScreenXY = new int[2];
-        scrollingContent.getLocationOnScreen(scrollingContentOnScreenXY);
-
-        // Assert that they have the same left
-        assertEquals(appbarOnScreenXY[0], scrollingContentOnScreenXY[0]);
-        // ...and the same width
-        assertEquals(mAppBar.getWidth(), scrollingContent.getWidth());
-        // ...and are vertically stacked
-        assertEquals(mAppBar.getBottom(), scrollingContent.getTop());
-    }
-
-    @Test
-    public void testRequestRectangleWithChildThatDoesNotRequireScroll() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_fitsystemwindows_parent,
-                R.string.design_appbar_toolbar_scroll_tabs_pin);
-
-        final View scrollingContent = mCoordinatorLayout.findViewById(R.id.scrolling_content);
-
-        // Get the initial XY
-        final int[] originalScrollingXY = new int[2];
-        scrollingContent.getLocationInWindow(originalScrollingXY);
-
-        // Now request that the first child has its full rectangle displayed
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final ViewGroup scrollingContentInner = (ViewGroup) scrollingContent
-                        .findViewById(R.id.scrolling_content_inner);
-                View child = scrollingContentInner.getChildAt(0);
-                Rect rect = new Rect(0, 0, child.getWidth(), child.getHeight());
-                child.requestRectangleOnScreen(rect, true);
-            }
-        });
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        final int[] newScrollingXY = new int[2];
-        scrollingContent.getLocationInWindow(newScrollingXY);
-
-        // Assert that the scrolling view has not moved
-        assertEquals(originalScrollingXY[0], newScrollingXY[0]);
-        assertEquals(originalScrollingXY[1], newScrollingXY[1]);
-    }
-
-    @Test
-    public void testRequestRectangleWithChildThatDoesRequireScroll() throws Throwable {
-        configureContent(R.layout.design_appbar_toolbar_scroll_fitsystemwindows_parent,
-                R.string.design_appbar_toolbar_scroll_tabs_pin);
-
-        final View scrollingContent = mCoordinatorLayout.findViewById(R.id.scrolling_content);
-
-        // Get the initial XY
-        final int[] originalScrollingXY = new int[2];
-        scrollingContent.getLocationInWindow(originalScrollingXY);
-
-        // Now request that the first child has its full rectangle displayed
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final ViewGroup scrollingContentInner = (ViewGroup) scrollingContent
-                        .findViewById(R.id.scrolling_content_inner);
-                View child = scrollingContentInner
-                        .getChildAt(scrollingContentInner.getChildCount() - 1);
-                Rect rect = new Rect(0, 0, child.getWidth(), child.getHeight());
-                child.requestRectangleOnScreen(rect, true);
-            }
-        });
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        final int[] newScrollingXY = new int[2];
-        scrollingContent.getLocationInWindow(newScrollingXY);
-
-        // Assert that the appbar has collapsed vertically
-        assertEquals(originalScrollingXY[0], newScrollingXY[0]);
-        assertEquals(originalScrollingXY[1] - mAppBar.getHeight(), newScrollingXY[1]);
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java b/design/tests/src/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java
deleted file mode 100755
index 32cef17..0000000
--- a/design/tests/src/android/support/design/widget/BaseDynamicCoordinatorLayoutTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.Matchers.any;
-
-import android.support.annotation.LayoutRes;
-import android.support.design.test.R;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.v4.view.ViewCompat;
-import android.view.View;
-import android.view.ViewStub;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.After;
-
-/**
- * Base class for tests that are exercising various aspects of {@link CoordinatorLayout}.
- */
-public abstract class BaseDynamicCoordinatorLayoutTest
-        extends BaseInstrumentationTestCase<DynamicCoordinatorLayoutActivity> {
-    protected CoordinatorLayout mCoordinatorLayout;
-
-    public BaseDynamicCoordinatorLayoutTest() {
-        super(DynamicCoordinatorLayoutActivity.class);
-    }
-
-    @UiThreadTest
-    @After
-    public void tearDown() {
-        // Now that the test is done, replace the activity content view with ViewStub so
-        // that it's ready to be replaced for the next test.
-        final DynamicCoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        activity.setContentView(R.layout.dynamic_coordinator_layout);
-        mCoordinatorLayout = null;
-    }
-
-    /**
-     * Matches views that have parents.
-     */
-    private Matcher<View> hasParent() {
-        return new TypeSafeMatcher<View>() {
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("has parent");
-            }
-
-            @Override
-            public boolean matchesSafely(View view) {
-                return view.getParent() != null;
-            }
-        };
-    }
-
-    /**
-     * Inflates the <code>ViewStub</code> with the passed layout resource.
-     */
-    protected ViewAction inflateViewStub(final @LayoutRes int layoutResId) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return allOf(isAssignableFrom(ViewStub.class), hasParent());
-            }
-
-            @Override
-            public String getDescription() {
-                return "Inflates view stub";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewStub viewStub = (ViewStub) view;
-                viewStub.setLayoutResource(layoutResId);
-                viewStub.inflate();
-
-                mCoordinatorLayout = (CoordinatorLayout) mActivityTestRule.getActivity()
-                        .findViewById(viewStub.getInflatedId());
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    protected ViewAction setLayoutDirection(final int layoutDir) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return any(View.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Sets layout direction";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                ViewCompat.setLayoutDirection(view, layoutDir);
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java b/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
deleted file mode 100644
index e06fa0a..0000000
--- a/design/tests/src/android/support/design/widget/BaseInstrumentationTestCase.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.app.Activity;
-import android.support.test.rule.BootlegActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Rule;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public abstract class BaseInstrumentationTestCase<A extends Activity> {
-    @Rule
-    public final BootlegActivityTestRule<A> mActivityTestRule;
-
-    protected BaseInstrumentationTestCase(Class<A> activityClass) {
-        mActivityTestRule = new BootlegActivityTestRule<>(activityClass);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/BaseTestActivity.java b/design/tests/src/android/support/design/widget/BaseTestActivity.java
deleted file mode 100755
index e1e44e2..0000000
--- a/design/tests/src/android/support/design/widget/BaseTestActivity.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.os.Bundle;
-import android.support.annotation.LayoutRes;
-import android.support.testutils.RecreatedAppCompatActivity;
-import android.view.WindowManager;
-
-abstract class BaseTestActivity extends RecreatedAppCompatActivity {
-
-    private boolean mDestroyed;
-
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        overridePendingTransition(0, 0);
-
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        final int contentView = getContentViewLayoutResId();
-        if (contentView > 0) {
-            setContentView(contentView);
-        }
-        onContentViewSet();
-        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-    }
-
-    @Override
-    public void finish() {
-        super.finish();
-        overridePendingTransition(0, 0);
-    }
-
-    @LayoutRes
-    protected abstract int getContentViewLayoutResId();
-
-    protected void onContentViewSet() {}
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        mDestroyed = true;
-    }
-
-    @Override
-    public boolean isDestroyed() {
-        return mDestroyed;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java b/design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
deleted file mode 100644
index 2afe695..0000000
--- a/design/tests/src/android/support/design/widget/BottomNavigationViewActivity.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class BottomNavigationViewActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_bottom_navigation_view;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java b/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
deleted file mode 100644
index 3365fac..0000000
--- a/design/tests/src/android/support/design/widget/BottomNavigationViewTest.java
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import static android.support.design.testutils.BottomNavigationViewActions.setIconForMenuItem;
-import static android.support.design.testutils.BottomNavigationViewActions.setItemIconTintList;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.core.AllOf.allOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.app.Activity;
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.Parcelable;
-import android.support.annotation.ColorInt;
-import android.support.design.test.R;
-import android.support.design.testutils.TestDrawable;
-import android.support.design.testutils.TestUtilsMatchers;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.SmallTest;
-import android.support.v4.content.res.ResourcesCompat;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.PointerIcon;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class BottomNavigationViewTest
-        extends BaseInstrumentationTestCase<BottomNavigationViewActivity> {
-    private static final int[] MENU_CONTENT_ITEM_IDS = { R.id.destination_home,
-            R.id.destination_profile, R.id.destination_people };
-    private Map<Integer, String> mMenuStringContent;
-
-    private BottomNavigationView mBottomNavigation;
-
-    public BottomNavigationViewTest() {
-        super(BottomNavigationViewActivity.class);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        final BottomNavigationViewActivity activity = mActivityTestRule.getActivity();
-        mBottomNavigation = (BottomNavigationView) activity.findViewById(R.id.bottom_navigation);
-
-        final Resources res = activity.getResources();
-        mMenuStringContent = new HashMap<>(MENU_CONTENT_ITEM_IDS.length);
-        mMenuStringContent.put(R.id.destination_home, res.getString(R.string.navigate_home));
-        mMenuStringContent.put(R.id.destination_profile, res.getString(R.string.navigate_profile));
-        mMenuStringContent.put(R.id.destination_people, res.getString(R.string.navigate_people));
-    }
-
-    @UiThreadTest
-    @Test
-    @SmallTest
-    public void testAddItemsWithoutMenuInflation() {
-        BottomNavigationView navigation = new BottomNavigationView(mActivityTestRule.getActivity());
-        mActivityTestRule.getActivity().setContentView(navigation);
-        navigation.getMenu().add("Item1");
-        navigation.getMenu().add("Item2");
-        assertEquals(2, navigation.getMenu().size());
-        navigation.getMenu().removeItem(0);
-        navigation.getMenu().removeItem(0);
-        assertEquals(0, navigation.getMenu().size());
-    }
-
-    @Test
-    @SmallTest
-    public void testBasics() {
-        // Check the contents of the Menu object
-        final Menu menu = mBottomNavigation.getMenu();
-        assertNotNull("Menu should not be null", menu);
-        assertEquals("Should have matching number of items", MENU_CONTENT_ITEM_IDS.length,
-                menu.size());
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            final MenuItem currItem = menu.getItem(i);
-            assertEquals("ID for Item #" + i, MENU_CONTENT_ITEM_IDS[i], currItem.getItemId());
-        }
-
-    }
-
-    @Test
-    @LargeTest
-    public void testNavigationSelectionListener() {
-        BottomNavigationView.OnNavigationItemSelectedListener mockedListener =
-                mock(BottomNavigationView.OnNavigationItemSelectedListener.class);
-        mBottomNavigation.setOnNavigationItemSelectedListener(mockedListener);
-
-        // Make the listener return true to allow selecting the item.
-        when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(true);
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify our listener has been notified of the click
-        verify(mockedListener, times(1)).onNavigationItemSelected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_profile));
-        // Verify the item is now selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-
-        // Select the same item again
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify our listener has been notified of the click
-        verify(mockedListener, times(2)).onNavigationItemSelected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_profile));
-        // Verify the item is still selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-
-        // Make the listener return false to disallow selecting the item.
-        when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(false);
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify our listener has been notified of the click
-        verify(mockedListener, times(1)).onNavigationItemSelected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_people));
-        // Verify the previous item is still selected
-        assertFalse(mBottomNavigation.getMenu().findItem(R.id.destination_people).isChecked());
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-
-        // Set null listener to test that the next click is not going to notify the
-        // previously set listener and will allow selecting items.
-        mBottomNavigation.setOnNavigationItemSelectedListener(null);
-
-        // Click one of our items
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify that our previous listener has not been notified of the click
-        verifyNoMoreInteractions(mockedListener);
-        // Verify the correct item is now selected.
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_home).isChecked());
-    }
-
-    @UiThreadTest
-    @Test
-    @SmallTest
-    public void testSetSelectedItemId() {
-        BottomNavigationView.OnNavigationItemSelectedListener mockedListener =
-                mock(BottomNavigationView.OnNavigationItemSelectedListener.class);
-        mBottomNavigation.setOnNavigationItemSelectedListener(mockedListener);
-
-        // Make the listener return true to allow selecting the item.
-        when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(true);
-        // Programmatically select an item
-        mBottomNavigation.setSelectedItemId(R.id.destination_profile);
-        // Verify our listener has been notified of the click
-        verify(mockedListener, times(1)).onNavigationItemSelected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_profile));
-        // Verify the item is now selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-
-        // Select the same item
-        mBottomNavigation.setSelectedItemId(R.id.destination_profile);
-        // Verify our listener has been notified of the click
-        verify(mockedListener, times(2)).onNavigationItemSelected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_profile));
-        // Verify the item is still selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-
-        // Make the listener return false to disallow selecting the item.
-        when(mockedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(false);
-        // Programmatically select an item
-        mBottomNavigation.setSelectedItemId(R.id.destination_people);
-        // Verify our listener has been notified of the click
-        verify(mockedListener, times(1)).onNavigationItemSelected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_people));
-        // Verify the previous item is still selected
-        assertFalse(mBottomNavigation.getMenu().findItem(R.id.destination_people).isChecked());
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-
-        // Set null listener to test that the next click is not going to notify the
-        // previously set listener and will allow selecting items.
-        mBottomNavigation.setOnNavigationItemSelectedListener(null);
-
-        // Select one of our items
-        mBottomNavigation.setSelectedItemId(R.id.destination_home);
-        // Verify that our previous listener has not been notified of the click
-        verifyNoMoreInteractions(mockedListener);
-        // Verify the correct item is now selected.
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_home).isChecked());
-    }
-
-    @Test
-    @SmallTest
-    public void testNavigationReselectionListener() {
-        // Add an OnNavigationItemReselectedListener
-        BottomNavigationView.OnNavigationItemReselectedListener reselectedListener =
-                mock(BottomNavigationView.OnNavigationItemReselectedListener.class);
-        mBottomNavigation.setOnNavigationItemReselectedListener(reselectedListener);
-
-        // Select an item
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify the item is now selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-        // Verify the listener was not called
-        verify(reselectedListener, never()).onNavigationItemReselected(any(MenuItem.class));
-
-        // Select the same item again
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify the item is still selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-        // Verify the listener was called
-        verify(reselectedListener, times(1)).onNavigationItemReselected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_profile));
-
-        // Add an OnNavigationItemSelectedListener
-        BottomNavigationView.OnNavigationItemSelectedListener selectedListener =
-                mock(BottomNavigationView.OnNavigationItemSelectedListener.class);
-        mBottomNavigation.setOnNavigationItemSelectedListener(selectedListener);
-        // Make the listener return true to allow selecting the item.
-        when(selectedListener.onNavigationItemSelected(any(MenuItem.class))).thenReturn(true);
-
-        // Select another item
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify the item is now selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_people).isChecked());
-        // Verify the correct listeners were called
-        verify(selectedListener, times(1)).onNavigationItemSelected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_people));
-        verify(reselectedListener, never()).onNavigationItemReselected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_people));
-
-        // Select the same item again
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify the item is still selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_people).isChecked());
-        // Verify the correct listeners were called
-        verifyNoMoreInteractions(selectedListener);
-        verify(reselectedListener, times(1)).onNavigationItemReselected(
-                mBottomNavigation.getMenu().findItem(R.id.destination_people));
-
-        // Remove the OnNavigationItemReselectedListener
-        mBottomNavigation.setOnNavigationItemReselectedListener(null);
-
-        // Select the same item again
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        // Verify the item is still selected
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_people).isChecked());
-        // Verify the reselectedListener was not called
-        verifyNoMoreInteractions(reselectedListener);
-    }
-
-    @UiThreadTest
-    @Test
-    @SmallTest
-    public void testSelectedItemIdWithEmptyMenu() {
-        // First item initially selected
-        assertEquals(R.id.destination_home, mBottomNavigation.getSelectedItemId());
-
-        // Remove all the items
-        for (int id : mMenuStringContent.keySet()) {
-            mBottomNavigation.getMenu().removeItem(id);
-        }
-        // Verify selected ID is zero
-        assertEquals(0, mBottomNavigation.getSelectedItemId());
-
-        // Add an item
-        mBottomNavigation.getMenu().add(0, R.id.destination_home, 0, R.string.navigate_home);
-        // Verify item is selected
-        assertEquals(R.id.destination_home, mBottomNavigation.getSelectedItemId());
-
-        // Try selecting an invalid ID
-        mBottomNavigation.setSelectedItemId(R.id.destination_people);
-        // Verify the view has not changed
-        assertEquals(R.id.destination_home, mBottomNavigation.getSelectedItemId());
-    }
-
-    @Test
-    @SmallTest
-    public void testIconTinting() {
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        @ColorInt final int redFill = ResourcesCompat.getColor(res, R.color.test_red, null);
-        @ColorInt final int greenFill = ResourcesCompat.getColor(res, R.color.test_green, null);
-        @ColorInt final int blueFill = ResourcesCompat.getColor(res, R.color.test_blue, null);
-        final int iconSize = res.getDimensionPixelSize(R.dimen.drawable_small_size);
-        onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_home,
-                new TestDrawable(redFill, iconSize, iconSize)));
-        onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_profile,
-                new TestDrawable(greenFill, iconSize, iconSize)));
-        onView(withId(R.id.bottom_navigation)).perform(setIconForMenuItem(R.id.destination_people,
-                new TestDrawable(blueFill, iconSize, iconSize)));
-
-        @ColorInt final int defaultTintColor = ResourcesCompat.getColor(res,
-                R.color.emerald_translucent, null);
-
-        // We're allowing a margin of error in checking the color of the items' icons.
-        // This is due to the translucent color being used in the icon tinting
-        // and off-by-one discrepancies of SRC_IN when it's compositing
-        // translucent color. Note that all the checks below are written for the current
-        // logic on BottomNavigationView that uses the default SRC_IN tint mode - effectively
-        // replacing all non-transparent pixels in the destination (original icon) with
-        // our translucent tint color.
-        final int allowedComponentVariance = 1;
-
-        // Note that here we're tying ourselves to the implementation details of the internal
-        // structure of the BottomNavigationView. Specifically, we're checking the drawable the
-        // ImageView with id R.id.icon. If the internal implementation of BottomNavigationView
-        // changes, the second Matcher in the lookups below will need to be tweaked.
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
-                matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
-                matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
-                matches(TestUtilsMatchers.drawable(defaultTintColor, allowedComponentVariance)));
-
-        @ColorInt final int newTintColor = ResourcesCompat.getColor(res,
-                R.color.red_translucent, null);
-        onView(withId(R.id.bottom_navigation)).perform(setItemIconTintList(
-                ResourcesCompat.getColorStateList(res, R.color.color_state_list_red_translucent,
-                        null)));
-        // Check that all menu items with icons now have icons tinted with the newly set color
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
-                matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
-                matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
-                matches(TestUtilsMatchers.drawable(newTintColor, allowedComponentVariance)));
-
-        // And now remove all icon tinting
-        onView(withId(R.id.bottom_navigation)).perform(setItemIconTintList(null));
-        // And verify that all menu items with icons now have the original colors for their icons.
-        // Note that since there is no tinting at this point, we don't allow any color variance
-        // in these checks.
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_home)))).check(
-                matches(TestUtilsMatchers.drawable(redFill, allowedComponentVariance)));
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_profile)))).check(
-                matches(TestUtilsMatchers.drawable(greenFill, allowedComponentVariance)));
-        onView(allOf(withId(R.id.icon), isDescendantOfA(withId(R.id.destination_people)))).check(
-                matches(TestUtilsMatchers.drawable(blueFill, allowedComponentVariance)));
-    }
-
-    @UiThreadTest
-    @Test
-    @SmallTest
-    public void testItemChecking() throws Throwable {
-        final Menu menu = mBottomNavigation.getMenu();
-        assertTrue(menu.getItem(0).isChecked());
-        checkAndVerifyExclusiveItem(menu, R.id.destination_home);
-        checkAndVerifyExclusiveItem(menu, R.id.destination_profile);
-        checkAndVerifyExclusiveItem(menu, R.id.destination_people);
-    }
-
-    @UiThreadTest
-    @Test
-    @SmallTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
-    public void testPointerIcon() throws Throwable {
-        final Activity activity = mActivityTestRule.getActivity();
-        final PointerIcon expectedIcon = PointerIcon.getSystemIcon(activity, PointerIcon.TYPE_HAND);
-        final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
-        final Menu menu = mBottomNavigation.getMenu();
-        for (int i = 0; i < menu.size(); i++) {
-            final MenuItem item = menu.getItem(i);
-            assertTrue(item.isEnabled());
-            final View itemView = activity.findViewById(item.getItemId());
-            assertEquals(expectedIcon, itemView.onResolvePointerIcon(event, 0));
-            item.setEnabled(false);
-            assertEquals(null, itemView.onResolvePointerIcon(event, 0));
-            item.setEnabled(true);
-            assertEquals(expectedIcon, itemView.onResolvePointerIcon(event, 0));
-        }
-    }
-
-    @UiThreadTest
-    @Test
-    @SmallTest
-    public void testClearingMenu() throws Throwable {
-        mBottomNavigation.getMenu().clear();
-        assertEquals(0, mBottomNavigation.getMenu().size());
-        mBottomNavigation.inflateMenu(R.menu.bottom_navigation_view_content);
-        assertEquals(3, mBottomNavigation.getMenu().size());
-    }
-
-    @Test
-    @SmallTest
-    public void testSavedState() throws Throwable {
-        // Select an item other than the first
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.bottom_navigation)), isDisplayed())).perform(click());
-        assertTrue(mBottomNavigation.getMenu().findItem(R.id.destination_profile).isChecked());
-        // Save the state
-        final Parcelable state = mBottomNavigation.onSaveInstanceState();
-
-        // Restore the state into a fresh BottomNavigationView
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                BottomNavigationView testView =
-                        new BottomNavigationView(mActivityTestRule.getActivity());
-                testView.inflateMenu(R.menu.bottom_navigation_view_content);
-                testView.onRestoreInstanceState(state);
-                assertTrue(testView.getMenu().findItem(R.id.destination_profile).isChecked());
-            }
-        });
-    }
-
-    @UiThreadTest
-    @Test
-    @SmallTest
-    public void testContentDescription() {
-        ViewGroup menuView = (ViewGroup) mBottomNavigation.getChildAt(0);
-        final int count = menuView.getChildCount();
-        for (int i = 0; i < count; i++) {
-            View child = menuView.getChildAt(i);
-            // We're using the same strings for content description
-            assertEquals(mMenuStringContent.get(child.getId()),
-                    child.getContentDescription().toString());
-        }
-
-        menuView.getChildAt(0).getContentDescription();
-    }
-
-    private void checkAndVerifyExclusiveItem(final Menu menu, final int id) throws Throwable {
-        menu.findItem(id).setChecked(true);
-        for (int i = 0; i < menu.size(); i++) {
-            final MenuItem item = menu.getItem(i);
-            if (item.getItemId() == id) {
-                assertTrue(item.isChecked());
-            } else {
-                assertFalse(item.isChecked());
-            }
-        }
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorActivity.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorActivity.java
deleted file mode 100644
index 6ab6287..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorActivity.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.content.Intent;
-import android.support.design.test.R;
-import android.widget.LinearLayout;
-
-
-public class BottomSheetBehaviorActivity extends BaseTestActivity {
-
-    public static String EXTRA_INITIAL_STATE = "initial_state";
-
-    CoordinatorLayout mCoordinatorLayout;
-
-    LinearLayout mBottomSheet;
-
-    BottomSheetBehavior mBehavior;
-
-    FloatingActionButton mFab;
-
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.test_design_bottom_sheet_behavior;
-    }
-
-    @Override
-    protected void onContentViewSet() {
-        mCoordinatorLayout = findViewById(R.id.coordinator);
-        mBottomSheet = findViewById(R.id.bottom_sheet);
-        mBehavior = BottomSheetBehavior.from(mBottomSheet);
-        mFab = findViewById(R.id.fab);
-        Intent intent = getIntent();
-        if (intent != null) {
-            int initialState = intent.getIntExtra(EXTRA_INITIAL_STATE, -1);
-            if (initialState != -1) {
-                //noinspection ResourceType
-                mBehavior.setState(initialState);
-            }
-        }
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
deleted file mode 100644
index a59aa87..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorInitialStateTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.Is.is;
-
-import android.content.Context;
-import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class BottomSheetBehaviorInitialStateTest {
-
-    @Rule
-    public final ActivityTestRule<BottomSheetBehaviorActivity> mActivityTestRule
-            = new ActivityTestRule<>(BottomSheetBehaviorActivity.class, true, false);
-
-    @Test
-    public void testSetStateExpanded() {
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        Intent intent = new Intent(context, BottomSheetBehaviorActivity.class);
-        intent.putExtra(BottomSheetBehaviorActivity.EXTRA_INITIAL_STATE,
-                BottomSheetBehavior.STATE_EXPANDED);
-        mActivityTestRule.launchActivity(intent);
-        BottomSheetBehaviorActivity activity = mActivityTestRule.getActivity();
-        assertThat(activity.mBehavior.getState(), is(BottomSheetBehavior.STATE_EXPANDED));
-        assertThat(activity.mBottomSheet.getTop(), is(0));
-    }
-
-
-    @Test
-    public void testSetStateHidden() {
-        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
-        Intent intent = new Intent(context, BottomSheetBehaviorActivity.class);
-        intent.putExtra(BottomSheetBehaviorActivity.EXTRA_INITIAL_STATE,
-                BottomSheetBehavior.STATE_HIDDEN);
-        mActivityTestRule.launchActivity(intent);
-        BottomSheetBehaviorActivity activity = mActivityTestRule.getActivity();
-        assertThat(activity.mBehavior.getState(), is(BottomSheetBehavior.STATE_HIDDEN));
-        assertThat(activity.mBottomSheet.getTop(), is(activity.mCoordinatorLayout.getHeight()));
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
deleted file mode 100644
index 4a27d0c..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTest.java
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.lessThanOrEqualTo;
-import static org.junit.Assert.fail;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.support.annotation.LayoutRes;
-import android.support.annotation.NonNull;
-import android.support.design.test.R;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingResource;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.ViewAssertion;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralLocation;
-import android.support.test.espresso.action.GeneralSwipeAction;
-import android.support.test.espresso.action.MotionEvents;
-import android.support.test.espresso.action.PrecisionDescriber;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Swipe;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.espresso.assertion.ViewAssertions;
-import android.support.test.espresso.matcher.ViewMatchers;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.widget.NestedScrollView;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-
-import org.hamcrest.Matcher;
-import org.hamcrest.Matchers;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class BottomSheetBehaviorTest extends
-        BaseInstrumentationTestCase<BottomSheetBehaviorActivity> {
-
-    public static class Callback extends BottomSheetBehavior.BottomSheetCallback
-            implements IdlingResource {
-
-        private boolean mIsIdle;
-
-        private IdlingResource.ResourceCallback mResourceCallback;
-
-        public Callback(BottomSheetBehavior behavior) {
-            behavior.setBottomSheetCallback(this);
-            int state = behavior.getState();
-            mIsIdle = isIdleState(state);
-        }
-
-        @Override
-        public void onStateChanged(@NonNull View bottomSheet,
-                @BottomSheetBehavior.State int newState) {
-            boolean wasIdle = mIsIdle;
-            mIsIdle = isIdleState(newState);
-            if (!wasIdle && mIsIdle && mResourceCallback != null) {
-                mResourceCallback.onTransitionToIdle();
-            }
-        }
-
-        @Override
-        public void onSlide(@NonNull View bottomSheet, float slideOffset) {
-            assertThat(slideOffset, is(greaterThanOrEqualTo(-1f)));
-            assertThat(slideOffset, is(lessThanOrEqualTo(1f)));
-        }
-
-        @Override
-        public String getName() {
-            return Callback.class.getSimpleName();
-        }
-
-        @Override
-        public boolean isIdleNow() {
-            return mIsIdle;
-        }
-
-        @Override
-        public void registerIdleTransitionCallback(IdlingResource.ResourceCallback callback) {
-            mResourceCallback = callback;
-        }
-
-        private boolean isIdleState(int state) {
-            return state != BottomSheetBehavior.STATE_DRAGGING &&
-                    state != BottomSheetBehavior.STATE_SETTLING;
-        }
-
-    }
-
-    /**
-     * Wait for a FAB to change its visibility (either shown or hidden).
-     */
-    private static class OnVisibilityChangedListener extends
-            FloatingActionButton.OnVisibilityChangedListener implements IdlingResource {
-
-        private final boolean mShown;
-        private boolean mIsIdle;
-        private ResourceCallback mResourceCallback;
-
-        OnVisibilityChangedListener(boolean shown) {
-            mShown = shown;
-        }
-
-        private void transitionToIdle() {
-            if (!mIsIdle) {
-                mIsIdle = true;
-                if (mResourceCallback != null) {
-                    mResourceCallback.onTransitionToIdle();
-                }
-            }
-        }
-
-        @Override
-        public void onShown(FloatingActionButton fab) {
-            if (mShown) {
-                transitionToIdle();
-            }
-        }
-
-        @Override
-        public void onHidden(FloatingActionButton fab) {
-            if (!mShown) {
-                transitionToIdle();
-            }
-        }
-
-        @Override
-        public String getName() {
-            return OnVisibilityChangedListener.class.getSimpleName();
-        }
-
-        @Override
-        public boolean isIdleNow() {
-            return mIsIdle;
-        }
-
-        @Override
-        public void registerIdleTransitionCallback(ResourceCallback resourceCallback) {
-            mResourceCallback = resourceCallback;
-        }
-    }
-
-    /**
-     * This is like {@link GeneralSwipeAction}, but it does not send ACTION_UP at the end.
-     */
-    private static class DragAction implements ViewAction {
-
-        private static final int STEPS = 10;
-        private static final int DURATION = 100;
-
-        private final CoordinatesProvider mStart;
-        private final CoordinatesProvider mEnd;
-        private final PrecisionDescriber mPrecisionDescriber;
-
-        public DragAction(CoordinatesProvider start, CoordinatesProvider end,
-                PrecisionDescriber precisionDescriber) {
-            mStart = start;
-            mEnd = end;
-            mPrecisionDescriber = precisionDescriber;
-        }
-
-        @Override
-        public Matcher<View> getConstraints() {
-            return Matchers.any(View.class);
-        }
-
-        @Override
-        public String getDescription() {
-            return "drag";
-        }
-
-        @Override
-        public void perform(UiController uiController, View view) {
-            float[] precision = mPrecisionDescriber.describePrecision();
-            float[] start = mStart.calculateCoordinates(view);
-            float[] end = mEnd.calculateCoordinates(view);
-            float[][] steps = interpolate(start, end, STEPS);
-            int delayBetweenMovements = DURATION / steps.length;
-            // Down
-            MotionEvent downEvent = MotionEvents.sendDown(uiController, start, precision).down;
-            try {
-                for (int i = 0; i < steps.length; i++) {
-                    // Wait
-                    long desiredTime = downEvent.getDownTime() + (long)(delayBetweenMovements * i);
-                    long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
-                    if (timeUntilDesired > 10L) {
-                        uiController.loopMainThreadForAtLeast(timeUntilDesired);
-                    }
-                    // Move
-                    if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) {
-                        MotionEvents.sendCancel(uiController, downEvent);
-                        throw new RuntimeException("Cannot drag: failed to send a move event.");
-                    }
-                }
-                int duration = ViewConfiguration.getPressedStateDuration();
-                if (duration > 0) {
-                    uiController.loopMainThreadForAtLeast((long) duration);
-                }
-            } finally {
-                downEvent.recycle();
-            }
-        }
-
-        private static float[][] interpolate(float[] start, float[] end, int steps) {
-            Assert.assertTrue(1 < start.length);
-            Assert.assertTrue(1 < end.length);
-            float[][] res = new float[steps][2];
-            for(int i = 1; i < steps + 1; ++i) {
-                res[i - 1][0] = start[0] + (end[0] - start[0]) * (float)i / ((float)steps + 2.0F);
-                res[i - 1][1] = start[1] + (end[1] - start[1]) * (float)i / ((float)steps + 2.0F);
-            }
-            return res;
-        }
-    }
-
-    private static class AddViewAction implements ViewAction {
-
-        private final int mLayout;
-
-        public AddViewAction(@LayoutRes int layout) {
-            mLayout = layout;
-        }
-
-        @Override
-        public Matcher<View> getConstraints() {
-            return ViewMatchers.isAssignableFrom(ViewGroup.class);
-        }
-
-        @Override
-        public String getDescription() {
-            return "add view";
-        }
-
-        @Override
-        public void perform(UiController uiController, View view) {
-            ViewGroup parent = (ViewGroup) view;
-            View child = LayoutInflater.from(view.getContext()).inflate(mLayout, parent, false);
-            parent.addView(child);
-        }
-    }
-
-    private Callback mCallback;
-
-    public BottomSheetBehaviorTest() {
-        super(BottomSheetBehaviorActivity.class);
-    }
-
-    @Test
-    @SmallTest
-    public void testInitialSetup() {
-        BottomSheetBehavior behavior = getBehavior();
-        assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-        CoordinatorLayout coordinatorLayout = getCoordinatorLayout();
-        ViewGroup bottomSheet = getBottomSheet();
-        assertThat(bottomSheet.getTop(),
-                is(coordinatorLayout.getHeight() - behavior.getPeekHeight()));
-    }
-
-    @Test
-    @MediumTest
-    public void testSetStateExpandedToCollapsed() throws Throwable {
-        checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
-        checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
-    }
-
-    @Test
-    @MediumTest
-    public void testSetStateHiddenToCollapsed() throws Throwable {
-        checkSetState(BottomSheetBehavior.STATE_HIDDEN, not(ViewMatchers.isDisplayed()));
-        checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
-    }
-
-    @Test
-    @MediumTest
-    public void testSetStateCollapsedToCollapsed() throws Throwable {
-        checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
-    }
-
-    @Test
-    @LargeTest
-    public void testSwipeDownToCollapse() throws Throwable {
-        checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
-        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                .perform(DesignViewActions.withCustomConstraints(new GeneralSwipeAction(
-                        Swipe.FAST,
-                        // Manually calculate the starting coordinates to make sure that the touch
-                        // actually falls onto the view on Gingerbread
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                int[] location = new int[2];
-                                view.getLocationInWindow(location);
-                                return new float[]{
-                                        view.getWidth() / 2,
-                                        location[1] + 1
-                                };
-                            }
-                        },
-                        // Manually calculate the ending coordinates to make sure that the bottom
-                        // sheet is collapsed, not hidden
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                BottomSheetBehavior behavior = getBehavior();
-                                return new float[]{
-                                        // x: center of the bottom sheet
-                                        view.getWidth() / 2,
-                                        // y: just above the peek height
-                                        view.getHeight() - behavior.getPeekHeight()};
-                            }
-                        }, Press.FINGER), ViewMatchers.isDisplayingAtLeast(5)));
-        registerIdlingResourceCallback();
-        try {
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
-            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testSwipeDownToHide() {
-        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                .perform(DesignViewActions.withCustomConstraints(ViewActions.swipeDown(),
-                        ViewMatchers.isDisplayingAtLeast(5)));
-        registerIdlingResourceCallback();
-        try {
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(not(ViewMatchers.isDisplayed())));
-            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_HIDDEN));
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    @Test
-    @LargeTest
-    public void testSkipCollapsed() throws Throwable {
-        getBehavior().setSkipCollapsed(true);
-        checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
-        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                .perform(DesignViewActions.withCustomConstraints(new GeneralSwipeAction(
-                        Swipe.FAST,
-                        // Manually calculate the starting coordinates to make sure that the touch
-                        // actually falls onto the view on Gingerbread
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                int[] location = new int[2];
-                                view.getLocationInWindow(location);
-                                return new float[]{
-                                        view.getWidth() / 2,
-                                        location[1] + 1
-                                };
-                            }
-                        },
-                        // Manually calculate the ending coordinates to make sure that the bottom
-                        // sheet is collapsed, not hidden
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                BottomSheetBehavior behavior = getBehavior();
-                                return new float[]{
-                                        // x: center of the bottom sheet
-                                        view.getWidth() / 2,
-                                        // y: just above the peek height
-                                        view.getHeight() - behavior.getPeekHeight()};
-                            }
-                        }, Press.FINGER), ViewMatchers.isDisplayingAtLeast(5)));
-        registerIdlingResourceCallback();
-        try {
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(not(ViewMatchers.isDisplayed())));
-            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_HIDDEN));
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testSwipeUpToExpand() {
-        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                .perform(DesignViewActions.withCustomConstraints(
-                        new GeneralSwipeAction(Swipe.FAST,
-                                GeneralLocation.VISIBLE_CENTER, new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                return new float[]{view.getWidth() / 2, 0};
-                            }
-                        }, Press.FINGER),
-                        ViewMatchers.isDisplayingAtLeast(5)));
-        registerIdlingResourceCallback();
-        try {
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
-            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_EXPANDED));
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testInvisible() throws Throwable {
-        // Make the bottomsheet invisible
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getBottomSheet().setVisibility(View.INVISIBLE);
-                assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-            }
-        });
-        // Swipe up as if to expand it
-        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                .perform(DesignViewActions.withCustomConstraints(
-                        new GeneralSwipeAction(Swipe.FAST,
-                                GeneralLocation.VISIBLE_CENTER, new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                return new float[]{view.getWidth() / 2, 0};
-                            }
-                        }, Press.FINGER),
-                        not(ViewMatchers.isDisplayed())));
-        // Check that the bottom sheet stays the same collapsed state
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-            }
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testInvisibleThenVisible() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // The bottom sheet is initially invisible
-                getBottomSheet().setVisibility(View.INVISIBLE);
-                // Then it becomes visible when the CoL is touched
-                getCoordinatorLayout().setOnTouchListener(new View.OnTouchListener() {
-                    @Override
-                    public boolean onTouch(View view, MotionEvent e) {
-                        if (e.getAction() == MotionEvent.ACTION_DOWN) {
-                            getBottomSheet().setVisibility(View.VISIBLE);
-                            return true;
-                        }
-                        return false;
-                    }
-                });
-                assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-            }
-        });
-        // Drag over the CoL
-        Espresso.onView(ViewMatchers.withId(R.id.coordinator))
-                // Drag (and not release)
-                .perform(new DragAction(
-                        GeneralLocation.BOTTOM_CENTER,
-                        GeneralLocation.TOP_CENTER,
-                        Press.FINGER))
-                .check(new ViewAssertion() {
-                    @Override
-                    public void check(View view, NoMatchingViewException e) {
-                        // The bottom sheet should not react to the touch events
-                        assertThat(getBottomSheet(), is(ViewMatchers.isDisplayed()));
-                        assertThat(getBehavior().getState(),
-                                is(BottomSheetBehavior.STATE_COLLAPSED));
-                    }
-                });
-    }
-
-    @Test
-    @LargeTest
-    public void testNestedScroll() throws Throwable {
-        final ViewGroup bottomSheet = getBottomSheet();
-        final BottomSheetBehavior behavior = getBehavior();
-        final NestedScrollView scroll = new NestedScrollView(mActivityTestRule.getActivity());
-        // Set up nested scrolling area
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                bottomSheet.addView(scroll, new ViewGroup.LayoutParams(
-                        ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
-                final View view = new View(mActivityTestRule.getActivity());
-                // Make sure that the NestedScrollView is always scrollable
-                view.setMinimumHeight(bottomSheet.getHeight() + 1000);
-                scroll.addView(view);
-                assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-                // The scroll offset is 0 at first
-                assertThat(scroll.getScrollY(), is(0));
-            }
-        });
-        // Swipe from the very bottom of the bottom sheet to the top edge of the screen so that the
-        // scrolling content is also scrolled
-        Espresso.onView(ViewMatchers.withId(R.id.coordinator))
-                .perform(new GeneralSwipeAction(Swipe.SLOW,
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                return new float[]{view.getWidth() / 2, view.getHeight() - 1};
-                            }
-                        },
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                return new float[]{view.getWidth() / 2, 1};
-                            }
-                        }, Press.FINGER));
-        registerIdlingResourceCallback();
-        try {
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_EXPANDED));
-                    // This confirms that the nested scrolling area was scrolled continuously after
-                    // the bottom sheet is expanded.
-                    assertThat(scroll.getScrollY(), is(not(0)));
-                }
-            });
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testDragOutside() {
-        // Swipe up outside of the bottom sheet
-        Espresso.onView(ViewMatchers.withId(R.id.coordinator))
-                .perform(DesignViewActions.withCustomConstraints(
-                        new GeneralSwipeAction(Swipe.FAST,
-                                // Just above the bottom sheet
-                                new CoordinatesProvider() {
-                                    @Override
-                                    public float[] calculateCoordinates(View view) {
-                                        return new float[]{
-                                                view.getWidth() / 2,
-                                                view.getHeight() - getBehavior().getPeekHeight() - 9
-                                        };
-                                    }
-                                },
-                                // Top of the CoordinatorLayout
-                                new CoordinatesProvider() {
-                                    @Override
-                                    public float[] calculateCoordinates(View view) {
-                                        return new float[]{view.getWidth() / 2, 1};
-                                    }
-                                }, Press.FINGER),
-                        ViewMatchers.isDisplayed()));
-        registerIdlingResourceCallback();
-        try {
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
-            // The bottom sheet should remain collapsed
-            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testLayoutWhileDragging() {
-        Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                // Drag (and not release)
-                .perform(new DragAction(
-                        GeneralLocation.VISIBLE_CENTER,
-                        GeneralLocation.TOP_CENTER,
-                        Press.FINGER))
-                // Check that the bottom sheet is in STATE_DRAGGING
-                .check(new ViewAssertion() {
-                    @Override
-                    public void check(View view, NoMatchingViewException e) {
-                        assertThat(view, is(ViewMatchers.isDisplayed()));
-                        BottomSheetBehavior behavior = BottomSheetBehavior.from(view);
-                        assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_DRAGGING));
-                    }
-                })
-                // Add a new view
-                .perform(new AddViewAction(R.layout.frame_layout))
-                // Check that the newly added view is properly laid out
-                .check(new ViewAssertion() {
-                    @Override
-                    public void check(View view, NoMatchingViewException e) {
-                        ViewGroup parent = (ViewGroup) view;
-                        assertThat(parent.getChildCount(), is(1));
-                        View child = parent.getChildAt(0);
-                        assertThat(ViewCompat.isLaidOut(child), is(true));
-                    }
-                });
-    }
-
-    @Test
-    @MediumTest
-    public void testFabVisibility() {
-        withFabVisibilityChange(false, new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
-                } catch (Throwable throwable) {
-                    fail(throwable.getMessage());
-                }
-            }
-        });
-        withFabVisibilityChange(true, new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
-                } catch (Throwable throwable) {
-                    fail(throwable.getMessage());
-                }
-            }
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testAutoPeekHeight() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getBehavior().setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO);
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                CoordinatorLayout col = getCoordinatorLayout();
-                assertThat(getBottomSheet().getTop(),
-                        is(Math.min(col.getWidth() * 9 / 16,
-                                col.getHeight() - getBehavior().getPeekHeightMin())));
-            }
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testAutoPeekHeightHide() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getBehavior().setHideable(true);
-                getBehavior().setPeekHeight(0);
-                getBehavior().setPeekHeight(BottomSheetBehavior.PEEK_HEIGHT_AUTO);
-            }
-        });
-        checkSetState(BottomSheetBehavior.STATE_HIDDEN, not(ViewMatchers.isDisplayed()));
-    }
-
-    @Test
-    @MediumTest
-    public void testDynamicContent() throws Throwable {
-        registerIdlingResourceCallback();
-        try {
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    ViewGroup.LayoutParams params = getBottomSheet().getLayoutParams();
-                    params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-                    getBottomSheet().setLayoutParams(params);
-                    View view = new View(getBottomSheet().getContext());
-                    int size = getBehavior().getPeekHeight() * 2;
-                    getBottomSheet().addView(view, new ViewGroup.LayoutParams(size, size));
-                    assertThat(getBottomSheet().getChildCount(), is(1));
-                    // Shrink the content height.
-                    ViewGroup.LayoutParams lp = view.getLayoutParams();
-                    lp.height = (int) (size * 0.8);
-                    view.setLayoutParams(lp);
-                    // Immediately expand the bottom sheet.
-                    getBehavior().setState(BottomSheetBehavior.STATE_EXPANDED);
-                }
-            });
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
-            assertThat(getBehavior().getState(), is(BottomSheetBehavior.STATE_EXPANDED));
-            // Make sure that the bottom sheet is not floating above the bottom.
-            assertThat(getBottomSheet().getBottom(), is(getCoordinatorLayout().getBottom()));
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testExpandedPeekHeight() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Make the peek height as tall as the bottom sheet.
-                BottomSheetBehavior behavior = getBehavior();
-                behavior.setPeekHeight(getBottomSheet().getHeight());
-                assertThat(behavior.getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-            }
-        });
-        // Both of these will not animate the sheet , but the state should be changed.
-        checkSetState(BottomSheetBehavior.STATE_EXPANDED, ViewMatchers.isDisplayed());
-        checkSetState(BottomSheetBehavior.STATE_COLLAPSED, ViewMatchers.isDisplayed());
-    }
-
-    @Test
-    @SmallTest
-    public void testFindScrollingChildEnabled() {
-        Context context = mActivityTestRule.getActivity();
-        NestedScrollView disabledParent = new NestedScrollView(context);
-        disabledParent.setNestedScrollingEnabled(false);
-        NestedScrollView enabledChild = new NestedScrollView(context);
-        enabledChild.setNestedScrollingEnabled(true);
-        disabledParent.addView(enabledChild);
-
-        View scrollingChild = getBehavior().findScrollingChild(disabledParent);
-        assertThat(scrollingChild, is((View) enabledChild));
-    }
-
-    private void checkSetState(final int state, Matcher<View> matcher) throws Throwable {
-        registerIdlingResourceCallback();
-        try {
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    getBehavior().setState(state);
-                }
-            });
-            Espresso.onView(ViewMatchers.withId(R.id.bottom_sheet))
-                    .check(ViewAssertions.matches(matcher));
-            assertThat(getBehavior().getState(), is(state));
-        } finally {
-            unregisterIdlingResourceCallback();
-        }
-    }
-
-    private void registerIdlingResourceCallback() {
-        // This cannot be done in setUp(), or swiping action cannot be executed.
-        mCallback = new Callback(getBehavior());
-        Espresso.registerIdlingResources(mCallback);
-    }
-
-    private void unregisterIdlingResourceCallback() {
-        if (mCallback != null) {
-            Espresso.unregisterIdlingResources(mCallback);
-            mCallback = null;
-        }
-    }
-
-    private void withFabVisibilityChange(boolean shown, Runnable action) {
-        OnVisibilityChangedListener listener = new OnVisibilityChangedListener(shown);
-        CoordinatorLayout.LayoutParams lp =
-                (CoordinatorLayout.LayoutParams) mActivityTestRule.getActivity().mFab
-                        .getLayoutParams();
-        FloatingActionButton.Behavior behavior = (FloatingActionButton.Behavior) lp.getBehavior();
-        behavior.setInternalAutoHideListener(listener);
-        Espresso.registerIdlingResources(listener);
-        try {
-            action.run();
-        } finally {
-            Espresso.unregisterIdlingResources(listener);
-        }
-    }
-
-    private ViewGroup getBottomSheet() {
-        return mActivityTestRule.getActivity().mBottomSheet;
-    }
-
-    private BottomSheetBehavior getBehavior() {
-        return mActivityTestRule.getActivity().mBehavior;
-    }
-
-    private CoordinatorLayout getCoordinatorLayout() {
-        return mActivityTestRule.getActivity().mCoordinatorLayout;
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
deleted file mode 100644
index 51ab0fa..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorTouchTest.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.nullValue;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewAssertion;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.filters.MediumTest;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import org.junit.Before;
-import org.junit.Test;
-
-@MediumTest
-public class BottomSheetBehaviorTouchTest extends
-        BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
-
-    private static final int PEEK_HEIGHT = 100;
-
-    private FrameLayout mBottomSheet;
-
-    private BottomSheetBehavior<FrameLayout> mBehavior;
-
-    private boolean mDown;
-
-    private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
-
-        @Override
-        public boolean onTouch(View v, MotionEvent event) {
-            switch (event.getActionMasked()) {
-                case MotionEvent.ACTION_DOWN:
-                    mDown = true;
-                    break;
-            }
-            return true;
-        }
-
-    };
-
-    public BottomSheetBehaviorTouchTest() {
-        super(CoordinatorLayoutActivity.class);
-    }
-
-    @UiThreadTest
-    @Before
-    public void setUpBottomSheet() {
-        CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        activity.mContainer.setOnTouchListener(mOnTouchListener);
-        mBottomSheet = new FrameLayout(activity);
-        CoordinatorLayout.LayoutParams params = new CoordinatorLayout.LayoutParams(
-                CoordinatorLayout.LayoutParams.MATCH_PARENT,
-                CoordinatorLayout.LayoutParams.MATCH_PARENT);
-        mBehavior = new BottomSheetBehavior<>();
-        mBehavior.setPeekHeight(PEEK_HEIGHT);
-        params.setBehavior(mBehavior);
-        activity.mCoordinatorLayout.addView(mBottomSheet, params);
-    }
-
-    @Test
-    public void testSetUp() {
-        assertThat(mBottomSheet, is(notNullValue()));
-        assertThat(mBehavior, is(sameInstance(BottomSheetBehavior.from(mBottomSheet))));
-    }
-
-    @Test
-    public void testTouchCoordinatorLayout() {
-        final CoordinatorLayoutActivity activity = mActivityTestRule.getActivity();
-        mDown = false;
-        Espresso.onView(sameInstance((View) activity.mCoordinatorLayout))
-                .perform(ViewActions.click())  // Click outside the bottom sheet
-                .check(new ViewAssertion() {
-                    @Override
-                    public void check(View view, NoMatchingViewException e) {
-                        assertThat(e, is(nullValue()));
-                        assertThat(view, is(notNullValue()));
-                        // Check that the touch event fell through to the container
-                        assertThat(mDown, is(true));
-                    }
-                });
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorWithInsetsActivity.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorWithInsetsActivity.java
deleted file mode 100644
index c1ab21d..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorWithInsetsActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-import android.view.View;
-
-
-public class BottomSheetBehaviorWithInsetsActivity extends BottomSheetBehaviorActivity {
-
-    View mBottomSheetContent;
-
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.test_design_bottom_sheet_behavior_with_insets;
-    }
-
-    @Override
-    protected void onContentViewSet() {
-        super.onContentViewSet();
-        mBottomSheetContent = findViewById(R.id.bottom_sheet_content);
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetBehaviorWithInsetsTest.java b/design/tests/src/android/support/design/widget/BottomSheetBehaviorWithInsetsTest.java
deleted file mode 100644
index f77542e..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetBehaviorWithInsetsTest.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import android.support.test.filters.SmallTest;
-import android.support.v4.view.ViewCompat;
-import android.view.ViewGroup;
-
-import org.junit.Test;
-
-public class BottomSheetBehaviorWithInsetsTest extends
-        BaseInstrumentationTestCase<BottomSheetBehaviorWithInsetsActivity> {
-
-    public BottomSheetBehaviorWithInsetsTest() {
-        super(BottomSheetBehaviorWithInsetsActivity.class);
-    }
-
-    @Test
-    @SmallTest
-    public void testFitsSystemWindows() {
-        BottomSheetBehaviorWithInsetsActivity activity = mActivityTestRule.getActivity();
-        ViewCompat.setFitsSystemWindows(activity.mCoordinatorLayout, true);
-        assertThat(activity.mBehavior.getState(), is(BottomSheetBehavior.STATE_COLLAPSED));
-        ViewGroup bottomSheet = activity.mBottomSheet;
-        assertThat(bottomSheet.getTop(),
-                is(activity.mCoordinatorLayout.getHeight() - activity.mBehavior.getPeekHeight()));
-        assertThat(activity.mBottomSheetContent.getTop(), is(0));
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/BottomSheetDialogActivity.java b/design/tests/src/android/support/design/widget/BottomSheetDialogActivity.java
deleted file mode 100644
index ab273c2..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetDialogActivity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class BottomSheetDialogActivity extends BaseTestActivity {
-
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.frame_layout;
-    }
-
-}
-
diff --git a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java b/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
deleted file mode 100644
index 8ca9b1d..0000000
--- a/design/tests/src/android/support/design/widget/BottomSheetDialogTest.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.lessThan;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.SystemClock;
-import android.support.design.test.R;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.espresso.assertion.ViewAssertions;
-import android.support.test.espresso.matcher.ViewMatchers;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.v7.widget.AppCompatTextView;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.hamcrest.TypeSafeMatcher;
-import org.junit.Test;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class BottomSheetDialogTest extends
-        BaseInstrumentationTestCase<BottomSheetDialogActivity> {
-
-    private BottomSheetDialog mDialog;
-
-    public BottomSheetDialogTest() {
-        super(BottomSheetDialogActivity.class);
-    }
-
-    @Test
-    @MediumTest
-    public void testBasicDialogSetup() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                showDialog();
-                // Confirms that the dialog is shown
-                assertThat(mDialog.isShowing(), is(true));
-                FrameLayout bottomSheet = (FrameLayout) mDialog
-                        .findViewById(R.id.design_bottom_sheet);
-                assertThat(bottomSheet, is(notNullValue()));
-                BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
-                assertThat(behavior.isHideable(), is(true));
-                assertThat(behavior, is(notNullValue()));
-                // Modal bottom sheets have auto peek height by default.
-                assertThat(behavior.getPeekHeight(), is(BottomSheetBehavior.PEEK_HEIGHT_AUTO));
-            }
-        });
-        // Click outside the bottom sheet
-        Espresso.onView(ViewMatchers.withId(R.id.touch_outside))
-                .perform(ViewActions.click());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Confirm that the dialog is no longer shown
-                assertThat(mDialog.isShowing(), is(false));
-            }
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testTouchInside() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                showDialog();
-                // Confirms that the dialog is shown
-                assertThat(mDialog.isShowing(), is(true));
-                FrameLayout bottomSheet = (FrameLayout) mDialog
-                        .findViewById(R.id.design_bottom_sheet);
-                // The bottom sheet is not clickable
-                assertNotNull(bottomSheet);
-                assertThat(bottomSheet.isClickable(), is(false));
-            }
-        });
-        // Click on the bottom sheet
-        Espresso.onView(ViewMatchers.withId(R.id.design_bottom_sheet))
-                .perform(ViewActions.click());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // Confirm that touch didn't fall through as outside touch
-                assertThat(mDialog.isShowing(), is(true));
-            }
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testClickContent() throws Throwable {
-        final View.OnClickListener mockListener = mock(View.OnClickListener.class);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                showDialog();
-                // Confirms that the dialog is shown
-                assertThat(mDialog.isShowing(), is(true));
-                FrameLayout bottomSheet = (FrameLayout) mDialog
-                        .findViewById(R.id.design_bottom_sheet);
-                // Set up an OnClickListener to the content of the bottom sheet
-                assertNotNull(bottomSheet);
-                View child = bottomSheet.getChildAt(0);
-                child.setOnClickListener(mockListener);
-            }
-        });
-        // Click on the bottom sheet; since the whole sheet is occupied with its only child, this
-        // clicks the child
-        Espresso.onView(ViewMatchers.withParent(ViewMatchers.withId(R.id.design_bottom_sheet)))
-                .perform(ViewActions.click());
-        verify(mockListener, times(1)).onClick(any(View.class));
-    }
-
-    @Test
-    @MediumTest
-    public void testShortDialog() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                showDialog();
-            }
-        });
-        // This ensures that the views are laid out before assertions below
-        Espresso.onView(ViewMatchers.withId(R.id.design_bottom_sheet))
-                .perform(setTallPeekHeight())
-                .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                FrameLayout bottomSheet = (FrameLayout) mDialog
-                        .findViewById(R.id.design_bottom_sheet);
-                CoordinatorLayout coordinator = (CoordinatorLayout) bottomSheet.getParent();
-                BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
-                assertThat(bottomSheet, is(notNullValue()));
-                assertThat(coordinator, is(notNullValue()));
-                assertThat(behavior, is(notNullValue()));
-                // This bottom sheet is shorter than the peek height
-                assertThat(bottomSheet.getHeight(), is(lessThan(behavior.getPeekHeight())));
-                // Confirm that the bottom sheet is bottom-aligned
-                assertThat(bottomSheet.getTop(),
-                        is(coordinator.getHeight() - bottomSheet.getHeight()));
-            }
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testNonCancelableDialog() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                showDialog();
-                mDialog.setCancelable(false);
-            }
-        });
-        // Click outside the bottom sheet
-        Espresso.onView(ViewMatchers.withId(R.id.touch_outside))
-                .perform(ViewActions.click());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                FrameLayout bottomSheet = (FrameLayout) mDialog
-                        .findViewById(R.id.design_bottom_sheet);
-                BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
-                assertThat(behavior.isHideable(), is(false));
-                assertThat(mDialog.isShowing(), is(true));
-                mDialog.cancel();
-                assertThat(mDialog.isShowing(), is(false));
-            }
-        });
-    }
-
-    @Test
-    @MediumTest
-    public void testHideBottomSheet() throws Throwable {
-        final AtomicBoolean canceled = new AtomicBoolean(false);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                showDialog();
-                mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
-                    @Override
-                    public void onCancel(DialogInterface dialogInterface) {
-                        canceled.set(true);
-                    }
-                });
-            }
-        });
-        Espresso.onView(ViewMatchers.withId(R.id.design_bottom_sheet))
-                .perform(setState(BottomSheetBehavior.STATE_HIDDEN));
-        // The dialog should be canceled
-        long start = System.currentTimeMillis();
-        while (!canceled.get()) {
-            SystemClock.sleep(31);
-            if (System.currentTimeMillis() - start > 3000) {
-                fail("Timed out while waiting for the dialog to be canceled.");
-            }
-        }
-    }
-
-    @SuppressWarnings("WrongConstant")
-    @Test
-    @LargeTest
-    public void testHideThenShow() throws Throwable {
-        // Hide the bottom sheet and wait for the dialog to be canceled.
-        final DialogInterface.OnCancelListener onCancelListener = mock(
-                DialogInterface.OnCancelListener.class);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                showDialog();
-                mDialog.setOnCancelListener(onCancelListener);
-            }
-        });
-        Espresso.onView(ViewMatchers.withId(R.id.design_bottom_sheet))
-                .perform(setState(BottomSheetBehavior.STATE_HIDDEN));
-        verify(onCancelListener, timeout(3000)).onCancel(any(DialogInterface.class));
-        // Reshow the same dialog instance and wait for the bottom sheet to be collapsed.
-        final BottomSheetBehavior.BottomSheetCallback callback = mock(
-                BottomSheetBehavior.BottomSheetCallback.class);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                BottomSheetBehavior.from(mDialog.findViewById(R.id.design_bottom_sheet))
-                        .setBottomSheetCallback(callback);
-                mDialog.show(); // Show the same dialog again.
-            }
-        });
-        verify(callback, timeout(3000)).onStateChanged(any(View.class),
-                eq(BottomSheetBehavior.STATE_SETTLING));
-        verify(callback, timeout(3000)).onStateChanged(any(View.class),
-                eq(BottomSheetBehavior.STATE_COLLAPSED));
-    }
-
-    private void showDialog() {
-        Context context = mActivityTestRule.getActivity();
-        mDialog = new BottomSheetDialog(context);
-        AppCompatTextView text = new AppCompatTextView(context);
-        StringBuilder builder = new StringBuilder();
-        builder.append("It is fine today. ");
-        text.setText(builder);
-        mDialog.setContentView(text);
-        mDialog.show();
-    }
-
-    private static ViewAction setTallPeekHeight() {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return ViewMatchers.isDisplayed();
-            }
-
-            @Override
-            public String getDescription() {
-                return "set tall peek height";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                BottomSheetBehavior behavior = BottomSheetBehavior.from(view);
-                behavior.setPeekHeight(view.getHeight() + 100);
-            }
-        };
-    }
-
-    private static ViewAction setState(@BottomSheetBehavior.State final int state) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isBottomSheet();
-            }
-
-            @Override
-            public String getDescription() {
-                return "set state to " + state;
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                BottomSheetBehavior.from(view).setState(state);
-            }
-        };
-    }
-
-    private static Matcher<View> isBottomSheet() {
-        return new TypeSafeMatcher<View>() {
-            @Override
-            protected boolean matchesSafely(View view) {
-                return BottomSheetBehavior.from(view) != null;
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("is a bottom sheet");
-            }
-        };
-    }
-
-}
-
diff --git a/design/tests/src/android/support/design/widget/CoordinatorLayoutActivity.java b/design/tests/src/android/support/design/widget/CoordinatorLayoutActivity.java
deleted file mode 100644
index a42ac8d..0000000
--- a/design/tests/src/android/support/design/widget/CoordinatorLayoutActivity.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-import android.widget.FrameLayout;
-
-public class CoordinatorLayoutActivity extends BaseTestActivity {
-
-    FrameLayout mContainer;
-    CoordinatorLayout mCoordinatorLayout;
-
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.activity_coordinator_layout;
-    }
-
-    @Override
-    protected void onContentViewSet() {
-        mContainer = findViewById(R.id.container);
-        mCoordinatorLayout = findViewById(R.id.coordinator);
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/CustomSnackbar.java b/design/tests/src/android/support/design/widget/CustomSnackbar.java
deleted file mode 100644
index caa1dc4..0000000
--- a/design/tests/src/android/support/design/widget/CustomSnackbar.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import android.support.design.test.R;
-import android.view.View;
-import android.widget.TextView;
-
-/**
- * Sample code for a custom snackbar that shows two separate text views and two images
- * in the main content area.
- */
-public class CustomSnackbar extends BaseTransientBottomBar<CustomSnackbar> {
-    public CustomSnackbar(CoordinatorLayout parent, View content,
-            BaseTransientBottomBar.ContentViewCallback contentViewCallback) {
-        super(parent, content, contentViewCallback);
-    }
-
-    /** Sets the title of this custom snackbar. */
-    public CustomSnackbar setTitle(String title) {
-        TextView titleView = (TextView) getView().findViewById(R.id.custom_snackbar_title);
-        titleView.setText(title);
-        return this;
-    }
-
-    /** Sets the subtitle of this custom snackbar. */
-    public CustomSnackbar setSubtitle(String subtitle) {
-        TextView subtitleView = (TextView) getView().findViewById(R.id.custom_snackbar_subtitle);
-        subtitleView.setText(subtitle);
-        return this;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/CustomSnackbarMainContent.java b/design/tests/src/android/support/design/widget/CustomSnackbarMainContent.java
deleted file mode 100644
index 8435bf7..0000000
--- a/design/tests/src/android/support/design/widget/CustomSnackbarMainContent.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import android.content.Context;
-import android.support.design.test.R;
-import android.util.AttributeSet;
-import android.widget.RelativeLayout;
-
-/**
- * Layout for the custom snackbar that shows two separate text views and two images
- * in the main content area.
- */
-public class CustomSnackbarMainContent extends RelativeLayout {
-    private final int mMaxWidth;
-
-    public CustomSnackbarMainContent(Context context) {
-        this(context, null);
-    }
-
-    public CustomSnackbarMainContent(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public CustomSnackbarMainContent(Context context, AttributeSet attrs,
-            int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        mMaxWidth = context.getResources().getDimensionPixelSize(R.dimen.custom_snackbar_max_width);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        if ((mMaxWidth > 0) && (getMeasuredWidth() > mMaxWidth)) {
-            super.onMeasure(MeasureSpec.makeMeasureSpec(mMaxWidth, MeasureSpec.EXACTLY),
-                    heightMeasureSpec);
-        }
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/CustomSnackbarTest.java b/design/tests/src/android/support/design/widget/CustomSnackbarTest.java
deleted file mode 100644
index cc6ed1a..0000000
--- a/design/tests/src/android/support/design/widget/CustomSnackbarTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.TestUtilsActions.setLayoutDirection;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.swipeLeft;
-import static android.support.test.espresso.action.ViewActions.swipeRight;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.core.AllOf.allOf;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.support.annotation.Nullable;
-import android.support.design.test.R;
-import android.support.design.testutils.SnackbarUtils;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.ViewInteraction;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.v4.view.ViewCompat;
-import android.view.LayoutInflater;
-
-import org.junit.Before;
-import org.junit.Test;
-
-public class CustomSnackbarTest extends BaseInstrumentationTestCase<SnackbarActivity> {
-    private static final String TITLE_TEXT = "Test title";
-    private static final String SUBTITLE_TEXT = "Test subtitle";
-
-    private CoordinatorLayout mCoordinatorLayout;
-
-    private interface DismissAction {
-        void dismiss(CustomSnackbar snackbar);
-    }
-
-    public CustomSnackbarTest() {
-        super(SnackbarActivity.class);
-    }
-
-    @Before
-    public void setup() {
-        mCoordinatorLayout =
-                (CoordinatorLayout) mActivityTestRule.getActivity().findViewById(R.id.col);
-    }
-
-    private void verifySnackbarContent(final CustomSnackbar snackbar, final String expectedTitle,
-            final String expectedSubtitle) throws Throwable {
-        // Show the snackbar
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-
-        // Verify that we're showing the title
-        withText(expectedTitle).matches(allOf(
-                isDescendantOfA(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                isDescendantOfA(isAssignableFrom(CustomSnackbarMainContent.class)),
-                isCompletelyDisplayed()));
-
-        // Verify that we're showing the subtitle
-        withText(expectedSubtitle).matches(allOf(
-                isDescendantOfA(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                isDescendantOfA(isAssignableFrom(CustomSnackbarMainContent.class)),
-                isCompletelyDisplayed()));
-
-        // Dismiss the snackbar
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-    }
-
-    private CustomSnackbar makeCustomSnackbar() {
-        final LayoutInflater inflater = LayoutInflater.from(mCoordinatorLayout.getContext());
-        final CustomSnackbarMainContent content =
-                (CustomSnackbarMainContent) inflater.inflate(
-                        R.layout.custom_snackbar_include, mCoordinatorLayout, false);
-        final BaseTransientBottomBar.ContentViewCallback contentViewCallback =
-                new BaseTransientBottomBar.ContentViewCallback() {
-                    @Override
-                    public void animateContentIn(int delay, int duration) {
-                        content.setAlpha(0f);
-                        content.animate().alpha(1f).setDuration(duration)
-                                .setStartDelay(delay).start();
-                    }
-
-                    @Override
-                    public void animateContentOut(int delay, int duration) {
-                        content.setAlpha(1f);
-                        content.animate().alpha(0f).setDuration(duration)
-                                .setStartDelay(delay).start();
-                    }
-                };
-        return new CustomSnackbar(mCoordinatorLayout, content, contentViewCallback);
-    }
-
-    @Test
-    @LargeTest
-    public void testBasicContent() throws Throwable {
-        // Verify different combinations of snackbar content (title / subtitle and action)
-        // and duration
-
-        // Short duration
-        verifySnackbarContent(
-                makeCustomSnackbar().setTitle(TITLE_TEXT)
-                        .setSubtitle(SUBTITLE_TEXT).setDuration(Snackbar.LENGTH_SHORT),
-                TITLE_TEXT, SUBTITLE_TEXT);
-
-        // Long duration
-        verifySnackbarContent(
-                makeCustomSnackbar().setTitle(TITLE_TEXT)
-                        .setSubtitle(SUBTITLE_TEXT).setDuration(Snackbar.LENGTH_LONG),
-                TITLE_TEXT, SUBTITLE_TEXT);
-
-        // Indefinite duration
-        verifySnackbarContent(
-                makeCustomSnackbar().setTitle(TITLE_TEXT)
-                        .setSubtitle(SUBTITLE_TEXT).setDuration(Snackbar.LENGTH_INDEFINITE),
-                TITLE_TEXT, SUBTITLE_TEXT);
-    }
-
-    private void verifyDismissCallback(final ViewInteraction interaction,
-            @Nullable final ViewAction action, @Nullable final DismissAction dismissAction,
-            final int length, @Snackbar.Callback.DismissEvent final int expectedEvent)
-            throws Throwable {
-        final BaseTransientBottomBar.BaseCallback mockCallback =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        final CustomSnackbar snackbar = makeCustomSnackbar().setTitle(TITLE_TEXT)
-                .setSubtitle(SUBTITLE_TEXT).setDuration(length)
-                .addCallback(mockCallback);
-
-        // Show the snackbar
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        // Verify that our onShown has been called
-        verify(mockCallback, times(1)).onShown(snackbar);
-        // and that the snackbar is either shown or queued to be shown
-        assertTrue(snackbar.isShownOrQueued());
-        // and also check that we have the intended title / subtitle displayed somewhere in
-        // our hierarchy
-        onView(withText(TITLE_TEXT)).check(matches(isCompletelyDisplayed()));
-        onView(withText(SUBTITLE_TEXT)).check(matches(isCompletelyDisplayed()));
-
-        // Now perform the UI interaction
-        SnackbarUtils.performActionAndWaitUntilFullyDismissed(snackbar,
-                new SnackbarUtils.TransientBottomBarAction() {
-                    @Override
-                    public void perform() throws Throwable {
-                        if (action != null) {
-                            interaction.perform(action);
-                        } else if (dismissAction != null) {
-                            mActivityTestRule.runOnUiThread(new Runnable() {
-                                @Override
-                                public void run() {
-                                    dismissAction.dismiss(snackbar);
-                                }
-                            });
-                        }
-                    }
-                });
-
-        // Verify that our onDismissed has been called
-        verify(mockCallback, times(1)).onDismissed(snackbar, expectedEvent);
-        verifyNoMoreInteractions(mockCallback);
-        // and that the snackbar is neither shown nor queued to be shown
-        assertFalse(snackbar.isShownOrQueued());
-    }
-
-    @Test
-    @MediumTest
-    public void testDismissViaSwipe() throws Throwable {
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                swipeRight(),
-                null,
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_SWIPE);
-    }
-
-    @Test
-    @MediumTest
-    public void testDismissViaSwipeRtl() throws Throwable {
-        onView(withId(R.id.col)).perform(setLayoutDirection(ViewCompat.LAYOUT_DIRECTION_RTL));
-        if (ViewCompat.getLayoutDirection(mCoordinatorLayout) == ViewCompat.LAYOUT_DIRECTION_RTL) {
-            // On devices that support RTL layout, the start-to-end dismiss swipe is done
-            // with swipeLeft() action
-            verifyDismissCallback(
-                    onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                    swipeLeft(),
-                    null,
-                    Snackbar.LENGTH_LONG,
-                    Snackbar.Callback.DISMISS_EVENT_SWIPE);
-        }
-    }
-
-    @Test
-    @MediumTest
-    public void testDismissViaApi() throws Throwable {
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                null,
-                new DismissAction() {
-                    @Override
-                    public void dismiss(CustomSnackbar snackbar) {
-                        snackbar.dismiss();
-                    }
-                },
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_MANUAL);
-    }
-
-    @Test
-    @LargeTest
-    public void testDismissViaTimeout() throws Throwable {
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                null,
-                null,
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_TIMEOUT);
-    }
-
-    @Test
-    @MediumTest
-    public void testDismissViaAnotherSnackbar() throws Throwable {
-        final CustomSnackbar anotherSnackbar =
-                makeCustomSnackbar().setTitle("Different title")
-                        .setSubtitle("Different subtitle").setDuration(Snackbar.LENGTH_SHORT);
-
-        // Our dismiss action is to show another snackbar (and verify that the original snackbar
-        // is now dismissed with CONSECUTIVE event)
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                null,
-                new DismissAction() {
-                    @Override
-                    public void dismiss(CustomSnackbar snackbar) {
-                        anotherSnackbar.show();
-                    }
-                },
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE);
-
-        // And dismiss the second snackbar to get back to clean state
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(anotherSnackbar);
-    }
-
-    @Test
-    @MediumTest
-    public void testMultipleCallbacks() throws Throwable {
-        final CustomSnackbar snackbar = makeCustomSnackbar().setTitle(TITLE_TEXT)
-                .setSubtitle(SUBTITLE_TEXT).setDuration(Snackbar.LENGTH_INDEFINITE);
-        final BaseTransientBottomBar.BaseCallback mockCallback1 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        final BaseTransientBottomBar.BaseCallback mockCallback2 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        snackbar.addCallback(mockCallback1);
-        snackbar.addCallback(mockCallback2);
-
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        verify(mockCallback1, times(1)).onShown(snackbar);
-        verify(mockCallback2, times(1)).onShown(snackbar);
-
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-        verify(mockCallback1, times(1)).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-        verify(mockCallback2, times(1)).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/DesignViewActions.java b/design/tests/src/android/support/design/widget/DesignViewActions.java
deleted file mode 100644
index 4ae608a..0000000
--- a/design/tests/src/android/support/design/widget/DesignViewActions.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import org.hamcrest.Matcher;
-
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.matcher.ViewMatchers;
-import android.view.View;
-
-public final class DesignViewActions {
-
-    private DesignViewActions() {
-    }
-
-    /**
-     * Overwrites the constraints of the specified {@link ViewAction}.
-     */
-    public static ViewAction withCustomConstraints(final ViewAction action,
-            final Matcher<View> constraints) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return constraints;
-            }
-
-            @Override
-            public String getDescription() {
-                return action.getDescription();
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                action.perform(uiController, view);
-            }
-        };
-    }
-
-    public static ViewAction setVisibility(final int visibility) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return ViewMatchers.isEnabled();
-            }
-
-            @Override
-            public String getDescription() {
-                return "Set view visibility";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-                view.setVisibility(visibility);
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/DynamicCoordinatorLayoutActivity.java b/design/tests/src/android/support/design/widget/DynamicCoordinatorLayoutActivity.java
deleted file mode 100644
index f26ef12..0000000
--- a/design/tests/src/android/support/design/widget/DynamicCoordinatorLayoutActivity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-/**
- * Test activity for testing various aspects of {@link CoordinatorLayout}.
- */
-public class DynamicCoordinatorLayoutActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.dynamic_coordinator_layout;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/FloatingActionButtonActivity.java b/design/tests/src/android/support/design/widget/FloatingActionButtonActivity.java
deleted file mode 100644
index 3a32827..0000000
--- a/design/tests/src/android/support/design/widget/FloatingActionButtonActivity.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class FloatingActionButtonActivity extends BaseTestActivity {
-
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_fab;
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java b/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
deleted file mode 100644
index f7e9286..0000000
--- a/design/tests/src/android/support/design/widget/FloatingActionButtonTest.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.FloatingActionButtonActions.hideThenShow;
-import static android.support.design.testutils.FloatingActionButtonActions.setBackgroundTintColor;
-import static android.support.design.testutils.FloatingActionButtonActions.setBackgroundTintList;
-import static android.support.design.testutils.FloatingActionButtonActions.setCompatElevation;
-import static android.support.design.testutils.FloatingActionButtonActions.setCustomSize;
-import static android.support.design.testutils.FloatingActionButtonActions.setImageResource;
-import static android.support.design.testutils.FloatingActionButtonActions.setLayoutGravity;
-import static android.support.design.testutils.FloatingActionButtonActions.setSize;
-import static android.support.design.testutils.FloatingActionButtonActions.showThenHide;
-import static android.support.design.testutils.TestUtilsActions.setClickable;
-import static android.support.design.testutils.TestUtilsActions.setEnabled;
-import static android.support.design.testutils.TestUtilsActions.setSelected;
-import static android.support.design.testutils.TestUtilsMatchers.isPressed;
-import static android.support.design.testutils.TestUtilsMatchers.withFabBackgroundFill;
-import static android.support.design.testutils.TestUtilsMatchers.withFabContentAreaOnMargins;
-import static android.support.design.testutils.TestUtilsMatchers.withFabContentHeight;
-import static android.support.design.testutils.TestUtilsMatchers.withFabCustomSize;
-import static android.support.design.widget.DesignViewActions.setVisibility;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.hamcrest.Matchers.not;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.app.Activity;
-import android.content.res.ColorStateList;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.support.design.test.R;
-import android.support.design.testutils.TestUtils;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralSwipeAction;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Swipe;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SmallTest;
-import android.support.v4.content.ContextCompat;
-import android.view.Gravity;
-import android.view.View;
-
-import org.junit.Test;
-
-public class FloatingActionButtonTest
-        extends BaseInstrumentationTestCase<FloatingActionButtonActivity> {
-
-    public FloatingActionButtonTest() {
-        super(FloatingActionButtonActivity.class);
-    }
-
-    @SmallTest
-    @Test
-    public void testDefaultBackgroundTint() {
-        final int colorAccent = TestUtils.getThemeAttrColor(
-                mActivityTestRule.getActivity(), R.attr.colorAccent);
-        onView(withId(R.id.fab_standard))
-                .check(matches(withFabBackgroundFill(colorAccent)));
-    }
-
-    @SmallTest
-    @Test
-    public void testSetTintOnDefaultBackgroundTint() {
-        onView(withId(R.id.fab_standard))
-                .perform(setBackgroundTintColor(Color.GREEN))
-                .check(matches(withFabBackgroundFill(Color.GREEN)));
-    }
-
-    @SmallTest
-    @Test
-    public void testDeclaredBackgroundTint() {
-        onView(withId(R.id.fab_tint))
-                .check(matches(withFabBackgroundFill(Color.MAGENTA)));
-    }
-
-    @SmallTest
-    @Test
-    public void testSetTintOnDeclaredBackgroundTint() {
-        onView(withId(R.id.fab_tint))
-                .perform(setBackgroundTintColor(Color.GREEN))
-                .check(matches(withFabBackgroundFill(Color.GREEN)));
-    }
-
-    @SmallTest
-    @Test
-    public void testSetStatefulTintAcrossStateChanges() {
-        final Activity activity = mActivityTestRule.getActivity();
-
-        final ColorStateList tint = ContextCompat.getColorStateList(activity, R.color.fab_tint);
-        final int normal = ContextCompat.getColor(activity, R.color.sand_default);
-        final int notSelected = ContextCompat.getColor(activity, R.color.sand_disabled);
-
-        // First set the background tint list to the ColorStateList
-        onView(withId(R.id.fab_standard))
-                .perform(setBackgroundTintList(tint));
-
-        // Assert that the background is tinted correctly across state changes
-        onView(withId(R.id.fab_standard))
-                .perform(setSelected(true))
-                .check(matches(withFabBackgroundFill(normal)))
-                .perform(setSelected(false))
-                .check(matches(withFabBackgroundFill(notSelected)))
-                .perform(setSelected(true))
-                .check(matches(withFabBackgroundFill(normal)));
-    }
-
-    @SmallTest
-    @Test
-    public void testDeclaredStatefulTintAcrossStateChanges() {
-        final Activity activity = mActivityTestRule.getActivity();
-        final int normal = ContextCompat.getColor(activity, R.color.sand_default);
-        final int disabled = ContextCompat.getColor(activity, R.color.sand_disabled);
-
-        // Assert that the background is tinted correctly across state changes
-        onView(withId(R.id.fab_state_tint))
-                .perform(setSelected(true))
-                .check(matches(withFabBackgroundFill(normal)))
-                .perform(setSelected(false))
-                .check(matches(withFabBackgroundFill(disabled)));
-    }
-
-    @SmallTest
-    @Test
-    public void setVectorDrawableSrc() {
-        onView(withId(R.id.fab_standard))
-                .perform(setImageResource(R.drawable.vector_icon));
-    }
-
-    @SmallTest
-    @Test
-    public void testSetMiniSize() {
-        final int miniSize = mActivityTestRule.getActivity().getResources()
-                .getDimensionPixelSize(R.dimen.fab_mini_height);
-
-        onView(withId(R.id.fab_standard))
-                .perform(setSize(FloatingActionButton.SIZE_MINI))
-                .check(matches(withFabContentHeight(miniSize)));
-    }
-
-    @SmallTest
-    @Test
-    public void testSetSizeToggle() {
-        final int miniSize = mActivityTestRule.getActivity().getResources()
-                .getDimensionPixelSize(R.dimen.fab_mini_height);
-        final int normalSize = mActivityTestRule.getActivity().getResources()
-                .getDimensionPixelSize(R.dimen.fab_normal_height);
-
-        onView(withId(R.id.fab_standard))
-                .perform(setSize(FloatingActionButton.SIZE_MINI))
-                .check(matches(withFabContentHeight(miniSize)));
-
-        onView(withId(R.id.fab_standard))
-                .perform(setSize(FloatingActionButton.SIZE_NORMAL))
-                .check(matches(withFabContentHeight(normalSize)));
-    }
-
-    @SmallTest
-    @Test
-    public void testOffset() {
-        onView(withId(R.id.fab_standard))
-                .perform(setLayoutGravity(Gravity.LEFT | Gravity.TOP))
-                .check(matches(withFabContentAreaOnMargins(Gravity.LEFT | Gravity.TOP)));
-
-        onView(withId(R.id.fab_standard))
-                .perform(setLayoutGravity(Gravity.RIGHT | Gravity.BOTTOM))
-                .check(matches(withFabContentAreaOnMargins(Gravity.RIGHT | Gravity.BOTTOM)));
-    }
-
-    @SmallTest
-    @Test
-    public void testHideShow() {
-        onView(withId(R.id.fab_standard))
-                .perform(setVisibility(View.VISIBLE))
-                .perform(hideThenShow(FloatingActionButtonImpl.SHOW_HIDE_ANIM_DURATION))
-                .check(matches(isDisplayed()));
-    }
-
-    @MediumTest
-    @Test
-    public void testShowHide() {
-        onView(withId(R.id.fab_standard))
-                .perform(setVisibility(View.GONE))
-                .perform(showThenHide(FloatingActionButtonImpl.SHOW_HIDE_ANIM_DURATION))
-                .check(matches(not(isDisplayed())));
-    }
-
-    @LargeTest
-    @Test
-    public void testClickableTouchAndDragOffView() {
-        onView(withId(R.id.fab_standard))
-                .perform(setClickable(true))
-                .perform(new GeneralSwipeAction(
-                        Swipe.SLOW,
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                // Create coordinators that in the center of the FAB's content area
-                                final FloatingActionButton fab = (FloatingActionButton) view;
-
-                                final int[] xy = new int[2];
-                                fab.getLocationOnScreen(xy);
-                                final Rect rect = new Rect();
-                                fab.getContentRect(rect);
-
-                                return new float[] {
-                                        xy[0] + rect.centerX(),
-                                        xy[1] + rect.centerY()
-                                };
-                            }
-                        },
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                // Create coordinators that in the center horizontally, but well
-                                // below the view vertically (by 50% of the height)
-                                final int[] xy = new int[2];
-                                view.getLocationOnScreen(xy);
-
-                                return new float[]{
-                                        xy[0] + (view.getWidth() / 2f),
-                                        xy[1] + (view.getHeight() * 1.5f)
-                                };
-                            }
-                        },
-                        Press.FINGER))
-                .check(matches(not(isPressed())));
-    }
-
-    @MediumTest
-    @Test
-    public void testOnClickListener() {
-        final View.OnClickListener listener = mock(View.OnClickListener.class);
-        final View view = mActivityTestRule.getActivity().findViewById(R.id.fab_standard);
-        view.setOnClickListener(listener);
-
-        // Click on the fab
-        onView(withId(R.id.fab_standard)).perform(click());
-
-        // And verify that the listener was invoked once
-        verify(listener, times(1)).onClick(view);
-    }
-
-    @SmallTest
-    @Test
-    public void testSetCompatElevation() {
-        onView(withId(R.id.fab_standard))
-                .perform(setEnabled(false))
-                .perform(setCompatElevation(0));
-
-        onView(withId(R.id.fab_standard))
-                .perform(setEnabled(true))
-                .perform(setCompatElevation(8));
-    }
-
-    @SmallTest
-    @Test
-    public void testSetCustomSize() {
-        onView(withId(R.id.fab_standard))
-                .perform(setCustomSize(10))
-                .check(matches(withFabCustomSize(10)));
-
-        onView(withId(R.id.fab_standard))
-                .perform(setCustomSize(20))
-                .check(matches(withFabCustomSize(20)));
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/NavigationTestView.java b/design/tests/src/android/support/design/widget/NavigationTestView.java
deleted file mode 100644
index af3d69e..0000000
--- a/design/tests/src/android/support/design/widget/NavigationTestView.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import android.content.Context;
-import android.support.v4.view.WindowInsetsCompat;
-import android.util.AttributeSet;
-
-/**
- * Expose hasSystemWindowInsets() for testing.
- */
-public class NavigationTestView extends NavigationView {
-
-    boolean mHashSystemWindowInsets;
-
-    public NavigationTestView(Context context) {
-        this(context, null);
-    }
-
-    public NavigationTestView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public NavigationTestView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-    }
-
-    @Override
-    protected void onInsetsChanged(WindowInsetsCompat insets) {
-        super.onInsetsChanged(insets);
-        mHashSystemWindowInsets = insets.hasSystemWindowInsets();
-    }
-
-    public boolean hasSystemWindowInsets() {
-        return mHashSystemWindowInsets;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/NavigationViewActivity.java b/design/tests/src/android/support/design/widget/NavigationViewActivity.java
deleted file mode 100644
index c3e810c..0000000
--- a/design/tests/src/android/support/design/widget/NavigationViewActivity.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class NavigationViewActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_navigation_view;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/NavigationViewTest.java b/design/tests/src/android/support/design/widget/NavigationViewTest.java
deleted file mode 100755
index 5ac3580..0000000
--- a/design/tests/src/android/support/design/widget/NavigationViewTest.java
+++ /dev/null
@@ -1,651 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import static android.support.design.testutils.DrawerLayoutActions.closeDrawer;
-import static android.support.design.testutils.DrawerLayoutActions.openDrawer;
-import static android.support.design.testutils.NavigationViewActions.addHeaderView;
-import static android.support.design.testutils.NavigationViewActions.inflateHeaderView;
-import static android.support.design.testutils.NavigationViewActions.removeHeaderView;
-import static android.support.design.testutils.NavigationViewActions.removeMenuItem;
-import static android.support.design.testutils.NavigationViewActions.setCheckedItem;
-import static android.support.design.testutils.NavigationViewActions.setIconForMenuItem;
-import static android.support.design.testutils.NavigationViewActions.setItemBackground;
-import static android.support.design.testutils.NavigationViewActions.setItemBackgroundResource;
-import static android.support.design.testutils.NavigationViewActions.setItemIconTintList;
-import static android.support.design.testutils.NavigationViewActions.setItemTextAppearance;
-import static android.support.design.testutils.NavigationViewActions.setItemTextColor;
-import static android.support.design.testutils.TestUtilsActions.reinflateMenu;
-import static android.support.design.testutils.TestUtilsActions.restoreHierarchyState;
-import static android.support.design.testutils.TestUtilsMatchers.isActionViewOf;
-import static android.support.design.testutils.TestUtilsMatchers.isChildOfA;
-import static android.support.design.testutils.TestUtilsMatchers.withBackgroundFill;
-import static android.support.design.testutils.TestUtilsMatchers.withStartDrawableFilledWith;
-import static android.support.design.testutils.TestUtilsMatchers.withTextColor;
-import static android.support.design.testutils.TestUtilsMatchers.withTextSize;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.Visibility;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isChecked;
-import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isNotChecked;
-import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.core.AllOf.allOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.content.res.Resources;
-import android.os.Build;
-import android.os.Parcelable;
-import android.support.annotation.ColorInt;
-import android.support.annotation.IdRes;
-import android.support.design.test.R;
-import android.support.design.testutils.TestDrawable;
-import android.support.test.filters.LargeTest;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.SwitchCompat;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.TextView;
-
-import org.hamcrest.Matcher;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-
-@LargeTest
-public class NavigationViewTest
-        extends BaseInstrumentationTestCase<NavigationViewActivity> {
-    private static final int[] MENU_CONTENT_ITEM_IDS = { R.id.destination_home,
-            R.id.destination_profile, R.id.destination_people, R.id.destination_settings };
-    private Map<Integer, String> mMenuStringContent;
-
-    private DrawerLayout mDrawerLayout;
-
-    private NavigationTestView mNavigationView;
-
-    public NavigationViewTest() {
-        super(NavigationViewActivity.class);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        final NavigationViewActivity activity = mActivityTestRule.getActivity();
-        mDrawerLayout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
-        mNavigationView = (NavigationTestView) mDrawerLayout.findViewById(R.id.start_drawer);
-
-        // Close the drawer to reset the state for the next test
-        onView(withId(R.id.drawer_layout)).perform(closeDrawer(GravityCompat.START));
-
-        final Resources res = activity.getResources();
-        mMenuStringContent = new HashMap<>(MENU_CONTENT_ITEM_IDS.length);
-        mMenuStringContent.put(R.id.destination_home, res.getString(R.string.navigate_home));
-        mMenuStringContent.put(R.id.destination_profile, res.getString(R.string.navigate_profile));
-        mMenuStringContent.put(R.id.destination_people, res.getString(R.string.navigate_people));
-        mMenuStringContent.put(R.id.destination_settings,
-                res.getString(R.string.navigate_settings));
-    }
-
-    @Test
-    public void testBasics() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        // Check the contents of the Menu object
-        final Menu menu = mNavigationView.getMenu();
-        assertNotNull("Menu should not be null", menu);
-        assertEquals("Should have matching number of items", MENU_CONTENT_ITEM_IDS.length + 1,
-                menu.size());
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            final MenuItem currItem = menu.getItem(i);
-            assertEquals("ID for Item #" + i, MENU_CONTENT_ITEM_IDS[i], currItem.getItemId());
-        }
-
-        // Check that we have the expected menu items in our NavigationView
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
-                    isDescendantOfA(withId(R.id.start_drawer)))).check(matches(isDisplayed()));
-        }
-    }
-
-    @Test
-    public void testWillNotDraw() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        if (Build.VERSION.SDK_INT >= 21) {
-            if (mNavigationView.hasSystemWindowInsets()) {
-                assertFalse(mNavigationView.willNotDraw());
-            } else {
-                assertTrue(mNavigationView.willNotDraw());
-            }
-        } else {
-            assertTrue(mNavigationView.willNotDraw());
-        }
-    }
-
-    @Test
-    public void testTextAppearance() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        final int defaultTextSize = res.getDimensionPixelSize(R.dimen.text_medium_size);
-
-        // Check the default style of the menu items in our NavigationView
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
-                    isDescendantOfA(withId(R.id.start_drawer)))).check(
-                    matches(withTextSize(defaultTextSize)));
-        }
-
-        // Set a new text appearance on our NavigationView
-        onView(withId(R.id.start_drawer)).perform(setItemTextAppearance(R.style.TextSmallStyle));
-
-        // And check that all the menu items have the new style
-        final int newTextSize = res.getDimensionPixelSize(R.dimen.text_small_size);
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
-                    isDescendantOfA(withId(R.id.start_drawer)))).check(
-                    matches(withTextSize(newTextSize)));
-        }
-    }
-
-    @Test
-    public void testTextColor() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        final @ColorInt int defaultTextColor = ResourcesCompat.getColor(res,
-                R.color.emerald_text, null);
-
-        // Check the default text color of the menu items in our NavigationView
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
-                    isDescendantOfA(withId(R.id.start_drawer)))).check(
-                    matches(withTextColor(defaultTextColor)));
-        }
-
-        // Set a new text color on our NavigationView
-        onView(withId(R.id.start_drawer)).perform(setItemTextColor(
-                ResourcesCompat.getColorStateList(res, R.color.color_state_list_lilac, null)));
-
-        // And check that all the menu items have the new color
-        final @ColorInt int newTextColor = ResourcesCompat.getColor(res,
-                R.color.lilac_default, null);
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            onView(allOf(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
-                    isDescendantOfA(withId(R.id.start_drawer)))).check(
-                    matches(withTextColor(newTextColor)));
-        }
-    }
-
-    @Test
-    public void testBackground() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        final @ColorInt int defaultFillColor = ResourcesCompat.getColor(res,
-                R.color.sand_default, null);
-
-        // Check the default fill color of the menu items in our NavigationView
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            // Note that here we're tying ourselves to the implementation details of the
-            // internal structure of the NavigationView. Specifically, we're looking at the
-            // direct child of RecyclerView which is expected to have the background set
-            // on it. If the internal implementation of NavigationView changes, the second
-            // Matcher below will need to be tweaked.
-            Matcher menuItemMatcher = allOf(
-                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
-                    isChildOfA(isAssignableFrom(RecyclerView.class)),
-                    isDescendantOfA(withId(R.id.start_drawer)));
-
-            onView(menuItemMatcher).check(matches(withBackgroundFill(defaultFillColor)));
-        }
-
-        // Set a new background (flat fill color) on our NavigationView
-        onView(withId(R.id.start_drawer)).perform(setItemBackgroundResource(
-                R.drawable.test_background_blue));
-
-        // And check that all the menu items have the new fill
-        final @ColorInt int newFillColorBlue = ResourcesCompat.getColor(res,
-                R.color.test_blue, null);
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            Matcher menuItemMatcher = allOf(
-                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
-                    isChildOfA(isAssignableFrom(RecyclerView.class)),
-                    isDescendantOfA(withId(R.id.start_drawer)));
-
-            onView(menuItemMatcher).check(matches(withBackgroundFill(newFillColorBlue)));
-        }
-
-        // Set another new background on our NavigationView
-        onView(withId(R.id.start_drawer)).perform(setItemBackground(
-                ResourcesCompat.getDrawable(res, R.drawable.test_background_green, null)));
-
-        // And check that all the menu items have the new fill
-        final @ColorInt int newFillColorGreen = ResourcesCompat.getColor(res,
-                R.color.test_green, null);
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            Matcher menuItemMatcher = allOf(
-                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
-                    isChildOfA(isAssignableFrom(RecyclerView.class)),
-                    isDescendantOfA(withId(R.id.start_drawer)));
-
-            onView(menuItemMatcher).check(matches(withBackgroundFill(newFillColorGreen)));
-        }
-    }
-
-    @Test
-    public void testIconTinting() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        final @ColorInt int redFill = ResourcesCompat.getColor(res, R.color.test_red, null);
-        final @ColorInt int greenFill = ResourcesCompat.getColor(res, R.color.test_green, null);
-        final @ColorInt int blueFill = ResourcesCompat.getColor(res, R.color.test_blue, null);
-        final int iconSize = res.getDimensionPixelSize(R.dimen.drawable_small_size);
-        onView(withId(R.id.start_drawer)).perform(setIconForMenuItem(R.id.destination_home,
-                new TestDrawable(redFill, iconSize, iconSize)));
-        onView(withId(R.id.start_drawer)).perform(setIconForMenuItem(R.id.destination_profile,
-                new TestDrawable(greenFill, iconSize, iconSize)));
-        onView(withId(R.id.start_drawer)).perform(setIconForMenuItem(R.id.destination_people,
-                new TestDrawable(blueFill, iconSize, iconSize)));
-
-        final @ColorInt int defaultTintColor = ResourcesCompat.getColor(res,
-                R.color.emerald_translucent, null);
-
-        // We're allowing a margin of error in checking the color of the items' icons.
-        // This is due to the translucent color being used in the icon tinting
-        // and off-by-one discrepancies of SRC_IN when it's compositing
-        // translucent color. Note that all the checks below are written for the current
-        // logic on NavigationView that uses the default SRC_IN tint mode - effectively
-        // replacing all non-transparent pixels in the destination (original icon) with
-        // our translucent tint color.
-        final int allowedComponentVariance = 1;
-
-        // Note that here we're tying ourselves to the implementation details of the
-        // internal structure of the NavigationView. Specifically, we're checking the
-        // start drawable of the text view with the specific text. If the internal
-        // implementation of NavigationView changes, the second Matcher in the lookups
-        // below will need to be tweaked.
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(defaultTintColor, allowedComponentVariance)));
-
-        final @ColorInt int newTintColor = ResourcesCompat.getColor(res,
-                R.color.red_translucent, null);
-
-        onView(withId(R.id.start_drawer)).perform(setItemIconTintList(
-                ResourcesCompat.getColorStateList(res, R.color.color_state_list_red_translucent,
-                        null)));
-        // Check that all menu items with icons now have icons tinted with the newly set color
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(newTintColor, allowedComponentVariance)));
-
-        // And now remove all icon tinting
-        onView(withId(R.id.start_drawer)).perform(setItemIconTintList(null));
-        // And verify that all menu items with icons now have the original colors for their icons.
-        // Note that since there is no tinting at this point, we don't allow any color variance
-        // in these checks.
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_home)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(redFill, 0)));
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(greenFill, 0)));
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.start_drawer)))).check(matches(
-                    withStartDrawableFilledWith(blueFill, 0)));
-    }
-
-    /**
-     * Gets the list of header IDs (which can be empty) and verifies that the actual header content
-     * of our navigation view matches the expected header content.
-     */
-    private void verifyHeaders(@IdRes int ... expectedHeaderIds) {
-        final int expectedHeaderCount = (expectedHeaderIds != null) ? expectedHeaderIds.length : 0;
-        final int actualHeaderCount = mNavigationView.getHeaderCount();
-        assertEquals("Header count", expectedHeaderCount, actualHeaderCount);
-
-        if (expectedHeaderCount > 0) {
-            for (int i = 0; i < expectedHeaderCount; i++) {
-                final View currentHeader = mNavigationView.getHeaderView(i);
-                assertEquals("Header at #" + i, expectedHeaderIds[i], currentHeader.getId());
-            }
-        }
-    }
-
-    @Test
-    public void testHeaders() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        // We should have no headers at the start
-        verifyHeaders();
-
-        // Inflate one header and check that it's there in the navigation view
-        onView(withId(R.id.start_drawer)).perform(
-                inflateHeaderView(R.layout.design_navigation_view_header1));
-        verifyHeaders(R.id.header1);
-
-        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-
-        // Add one more header and check that it's there in the navigation view
-        onView(withId(R.id.start_drawer)).perform(
-                addHeaderView(inflater, R.layout.design_navigation_view_header2));
-        verifyHeaders(R.id.header1, R.id.header2);
-
-        final View header1 = mNavigationView.findViewById(R.id.header1);
-        // Remove the first header and check that we still have the second header
-        onView(withId(R.id.start_drawer)).perform(removeHeaderView(header1));
-        verifyHeaders(R.id.header2);
-
-        // Add one more header and check that we now have two headers
-        onView(withId(R.id.start_drawer)).perform(
-                inflateHeaderView(R.layout.design_navigation_view_header3));
-        verifyHeaders(R.id.header2, R.id.header3);
-
-        // Add another "copy" of the header from the just-added layout and check that we now
-        // have three headers
-        onView(withId(R.id.start_drawer)).perform(
-                addHeaderView(inflater, R.layout.design_navigation_view_header3));
-        verifyHeaders(R.id.header2, R.id.header3, R.id.header3);
-    }
-
-    @Test
-    public void testHeaderState() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        // Inflate a header with a toggle switch and check that it's there in the navigation view
-        onView(withId(R.id.start_drawer)).perform(
-                inflateHeaderView(R.layout.design_navigation_view_header_switch));
-        verifyHeaders(R.id.header_frame);
-
-        onView(withId(R.id.header_toggle))
-                .check(matches(isNotChecked()))
-                .perform(click())
-                .check(matches(isChecked()));
-
-        // Save the current state
-        SparseArray<Parcelable> container = new SparseArray<>();
-        mNavigationView.saveHierarchyState(container);
-
-        // Remove the header
-        final View header = mNavigationView.findViewById(R.id.header_frame);
-        onView(withId(R.id.start_drawer)).perform(removeHeaderView(header));
-        verifyHeaders();
-
-        // Inflate the header again
-        onView(withId(R.id.start_drawer)).perform(
-                inflateHeaderView(R.layout.design_navigation_view_header_switch));
-        verifyHeaders(R.id.header_frame);
-
-        // Restore the saved state
-        onView(withId(R.id.start_drawer)).perform(
-                restoreHierarchyState(container));
-
-        // Confirm that the state was restored
-        onView(withId(R.id.header_toggle))
-                .check(matches(isChecked()));
-    }
-
-    @Test
-    public void testActionViewState() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        final Menu menu = mNavigationView.getMenu();
-        onView(isActionViewOf(menu, R.id.destination_people))
-                .check(matches(isNotChecked())) // Not checked by default
-                .perform(click())               // Check it
-                .check(matches(isChecked()));
-
-        // Remove the other action view to simulate the case where it is not yet inflated
-        onView(isActionViewOf(menu, R.id.destination_custom))
-                .check(matches(isDisplayed()));
-        onView(withId(R.id.start_drawer))
-                .perform(removeMenuItem(R.id.destination_custom));
-
-        // Save the current state
-        SparseArray<Parcelable> container = new SparseArray<>();
-        mNavigationView.saveHierarchyState(container);
-
-        // Restore the saved state
-        onView(withId(R.id.start_drawer))
-                .perform(reinflateMenu(R.menu.navigation_view_content))
-                .perform(restoreHierarchyState(container));
-
-        // Checked state should be restored
-        onView(isActionViewOf(menu, R.id.destination_people))
-                .check(matches(isChecked()));
-    }
-
-    @Test
-    public void testNavigationSelectionListener() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        // Click one of our items
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
-        // Check that the drawer is still open
-        assertTrue("Drawer is still open after click",
-                mDrawerLayout.isDrawerOpen(GravityCompat.START));
-
-        // Register a listener
-        NavigationView.OnNavigationItemSelectedListener mockedListener =
-                mock(NavigationView.OnNavigationItemSelectedListener.class);
-        mNavigationView.setNavigationItemSelectedListener(mockedListener);
-
-        // Click one of our items
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_profile)),
-                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
-        // Check that the drawer is still open
-        assertTrue("Drawer is still open after click",
-                mDrawerLayout.isDrawerOpen(GravityCompat.START));
-        // And that our listener has been notified of the click
-        verify(mockedListener, times(1)).onNavigationItemSelected(
-                mNavigationView.getMenu().findItem(R.id.destination_profile));
-
-        // Set null listener to test that the next click is not going to notify the
-        // previously set listener
-        mNavigationView.setNavigationItemSelectedListener(null);
-
-        // Click one of our items
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_settings)),
-                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
-        // Check that the drawer is still open
-        assertTrue("Drawer is still open after click",
-                mDrawerLayout.isDrawerOpen(GravityCompat.START));
-        // And that our previous listener has not been notified of the click
-        verifyNoMoreInteractions(mockedListener);
-    }
-
-    private void verifyCheckedAppearance(@IdRes int checkedItemId,
-            @ColorInt int uncheckedItemForeground, @ColorInt int checkedItemForeground,
-            @ColorInt int uncheckedItemBackground, @ColorInt int checkedItemBackground) {
-        for (int i = 0; i < MENU_CONTENT_ITEM_IDS.length; i++) {
-            final boolean expectedToBeChecked = (MENU_CONTENT_ITEM_IDS[i] == checkedItemId);
-            final @ColorInt int expectedItemForeground =
-                    expectedToBeChecked ? checkedItemForeground : uncheckedItemForeground;
-            final @ColorInt int expectedItemBackground =
-                    expectedToBeChecked ? checkedItemBackground : uncheckedItemBackground;
-
-            // For the background fill check we need to select a view that has its background
-            // set by the current implementation (see disclaimer in testBackground)
-            Matcher menuItemMatcher = allOf(
-                    hasDescendant(withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i]))),
-                    isChildOfA(isAssignableFrom(RecyclerView.class)),
-                    isDescendantOfA(withId(R.id.start_drawer)));
-            onView(menuItemMatcher).check(matches(withBackgroundFill(expectedItemBackground)));
-
-            // And for the foreground color check we need to select a view with the text content
-            Matcher menuItemTextMatcher = allOf(
-                    withText(mMenuStringContent.get(MENU_CONTENT_ITEM_IDS[i])),
-                    isDescendantOfA(withId(R.id.start_drawer)));
-            onView(menuItemTextMatcher).check(matches(withTextColor(expectedItemForeground)));
-        }
-    }
-
-    @Test
-    public void testCheckedAppearance() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        // Reconfigure our navigation view to use foreground (text) and background visuals
-        // with explicitly different colors for the checked state
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        onView(withId(R.id.start_drawer)).perform(setItemTextColor(
-                ResourcesCompat.getColorStateList(res, R.color.color_state_list_sand, null)));
-        onView(withId(R.id.start_drawer)).perform(setItemBackgroundResource(
-                R.drawable.test_drawable_state_list));
-
-        final @ColorInt int uncheckedItemForeground = ResourcesCompat.getColor(res,
-                R.color.sand_default, null);
-        final @ColorInt int checkedItemForeground = ResourcesCompat.getColor(res,
-                R.color.sand_checked, null);
-        final @ColorInt int uncheckedItemBackground = ResourcesCompat.getColor(res,
-                R.color.test_green, null);
-        final @ColorInt int checkedItemBackground = ResourcesCompat.getColor(res,
-                R.color.test_blue, null);
-
-        // Verify that all items are rendered with unchecked visuals
-        verifyCheckedAppearance(0, uncheckedItemForeground, checkedItemForeground,
-                uncheckedItemBackground, checkedItemBackground);
-
-        // Mark one of the items as checked
-        onView(withId(R.id.start_drawer)).perform(setCheckedItem(R.id.destination_profile));
-        // And verify that it's now rendered with checked visuals
-        verifyCheckedAppearance(R.id.destination_profile,
-                uncheckedItemForeground, checkedItemForeground,
-                uncheckedItemBackground, checkedItemBackground);
-
-        // Register a navigation listener that "marks" the selected item
-        mNavigationView.setNavigationItemSelectedListener(
-                new NavigationView.OnNavigationItemSelectedListener() {
-                    @Override
-                    public boolean onNavigationItemSelected(MenuItem item) {
-                        return true;
-                    }
-                });
-
-        // Click one of our items
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_people)),
-                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
-        // and verify that it's now checked
-        verifyCheckedAppearance(R.id.destination_people,
-                uncheckedItemForeground, checkedItemForeground,
-                uncheckedItemBackground, checkedItemBackground);
-
-        // Register a navigation listener that doesn't "mark" the selected item
-        mNavigationView.setNavigationItemSelectedListener(
-                new NavigationView.OnNavigationItemSelectedListener() {
-                    @Override
-                    public boolean onNavigationItemSelected(MenuItem item) {
-                        return false;
-                    }
-                });
-
-        // Click another items
-        onView(allOf(withText(mMenuStringContent.get(R.id.destination_settings)),
-                isDescendantOfA(withId(R.id.start_drawer)))).perform(click());
-        // and verify that the checked state remains on the previously clicked item
-        // since the current navigation listener returns false from its callback
-        // implementation
-        verifyCheckedAppearance(R.id.destination_people,
-                uncheckedItemForeground, checkedItemForeground,
-                uncheckedItemBackground, checkedItemBackground);
-    }
-
-    @Test
-    public void testActionLayout() {
-        // Open our drawer
-        onView(withId(R.id.drawer_layout)).perform(openDrawer(GravityCompat.START));
-
-        // There are four conditions to "find" the menu item with action layout (switch):
-        // 1. Is in the NavigationView
-        // 2. Is direct child of a class that extends RecyclerView
-        // 3. Has a child with "people" text
-        // 4. Has fully displayed child that extends SwitchCompat
-        // Note that condition 2 makes a certain assumption about the internal implementation
-        // details of the NavigationMenu, while conditions 3 and 4 aim to be as generic as
-        // possible and to not rely on the internal details of the current layout implementation
-        // of an individual menu item in NavigationMenu.
-        Matcher menuItemMatcher = allOf(
-                isDescendantOfA(withId(R.id.start_drawer)),
-                isChildOfA(isAssignableFrom(RecyclerView.class)),
-                hasDescendant(withText(mMenuStringContent.get(R.id.destination_people))),
-                hasDescendant(allOf(
-                        isAssignableFrom(SwitchCompat.class),
-                        isCompletelyDisplayed())));
-
-        // While we don't need to perform any action on our row, the invocation of perform()
-        // makes our matcher actually run. If for some reason NavigationView fails to inflate and
-        // display our SwitchCompat action layout, the next line will fail in the matcher pass.
-        onView(menuItemMatcher).perform(click());
-
-        // Check that the full custom view is displayed without title and icon.
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        Matcher customItemMatcher = allOf(
-                isDescendantOfA(withId(R.id.start_drawer)),
-                isChildOfA(isAssignableFrom(RecyclerView.class)),
-                hasDescendant(withText(res.getString(R.string.navigate_custom))),
-                hasDescendant(allOf(
-                        isAssignableFrom(TextView.class),
-                        withEffectiveVisibility(Visibility.GONE))));
-        onView(customItemMatcher).perform(click());
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/SnackbarActivity.java b/design/tests/src/android/support/design/widget/SnackbarActivity.java
deleted file mode 100644
index 5d8e118..0000000
--- a/design/tests/src/android/support/design/widget/SnackbarActivity.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class SnackbarActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.test_design_snackbar;
-    }
-}
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/widget/SnackbarActivityWithFAB.java b/design/tests/src/android/support/design/widget/SnackbarActivityWithFAB.java
deleted file mode 100644
index 817af4b..0000000
--- a/design/tests/src/android/support/design/widget/SnackbarActivityWithFAB.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class SnackbarActivityWithFAB extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.test_design_snackbar_fab;
-    }
-}
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/widget/SnackbarActivityWithTranslucentNavBar.java b/design/tests/src/android/support/design/widget/SnackbarActivityWithTranslucentNavBar.java
deleted file mode 100644
index 7ccf69c..0000000
--- a/design/tests/src/android/support/design/widget/SnackbarActivityWithTranslucentNavBar.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class SnackbarActivityWithTranslucentNavBar extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.test_design_snackbar;
-    }
-}
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/widget/SnackbarTest.java b/design/tests/src/android/support/design/widget/SnackbarTest.java
deleted file mode 100644
index 0d0a891..0000000
--- a/design/tests/src/android/support/design/widget/SnackbarTest.java
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.TestUtilsActions.setLayoutDirection;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.action.ViewActions.swipeLeft;
-import static android.support.test.espresso.action.ViewActions.swipeRight;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.core.AllOf.allOf;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.content.res.Resources;
-import android.support.annotation.Nullable;
-import android.support.annotation.StringRes;
-import android.support.design.test.R;
-import android.support.design.testutils.SnackbarUtils;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.ViewInteraction;
-import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralSwipeAction;
-import android.support.test.espresso.action.Press;
-import android.support.test.espresso.action.Swipe;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.v4.view.ViewCompat;
-import android.text.TextUtils;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Test;
-
-@MediumTest
-public class SnackbarTest extends BaseInstrumentationTestCase<SnackbarActivity> {
-    private static final String MESSAGE_TEXT = "Test Message";
-    private static final @StringRes int MESSAGE_ID = R.string.snackbar_text;
-    private static final String ACTION_TEXT = "Action";
-    private static final @StringRes int ACTION_ID = R.string.snackbar_action;
-
-    private CoordinatorLayout mCoordinatorLayout;
-
-    private interface DismissAction {
-        void dismiss(Snackbar snackbar);
-    }
-
-    public SnackbarTest() {
-        super(SnackbarActivity.class);
-    }
-
-    @Before
-    public void setup() {
-        mCoordinatorLayout =
-                (CoordinatorLayout) mActivityTestRule.getActivity().findViewById(R.id.col);
-    }
-
-    private void verifySnackbarContent(final Snackbar snackbar, final String expectedMessage,
-            final String expectedAction) throws Throwable {
-        // Show the snackbar
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-
-        // Verify that we're showing the message
-        withText(expectedMessage).matches(allOf(
-                isDescendantOfA(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                isCompletelyDisplayed()));
-
-        // If the action is not empty, verify that we're showing it
-        if (!TextUtils.isEmpty(expectedAction)) {
-            withText(expectedAction).matches(allOf(
-                    isDescendantOfA(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                    isCompletelyDisplayed()));
-        }
-
-        // Dismiss the snackbar
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-    }
-
-    @LargeTest
-    @Test
-    public void testBasicContent() throws Throwable {
-        // Verify different combinations of snackbar content (message and action) and duration
-
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        final String resolvedMessage = res.getString(MESSAGE_ID);
-        final String resolvedAction = res.getString(ACTION_ID);
-
-        // String message and no action
-        verifySnackbarContent(
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_SHORT),
-                MESSAGE_TEXT, null);
-
-        // Resource message and no action
-        verifySnackbarContent(
-                Snackbar.make(mCoordinatorLayout, MESSAGE_ID, Snackbar.LENGTH_LONG),
-                resolvedMessage, null);
-
-        // String message and string action
-        verifySnackbarContent(
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE)
-                        .setAction(ACTION_TEXT, mock(View.OnClickListener.class)),
-                MESSAGE_TEXT, ACTION_TEXT);
-
-        // String message and resource action
-        verifySnackbarContent(
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_SHORT)
-                        .setAction(ACTION_ID, mock(View.OnClickListener.class)),
-                MESSAGE_TEXT, resolvedAction);
-
-        // Resource message and resource action
-        verifySnackbarContent(
-                Snackbar.make(mCoordinatorLayout, MESSAGE_ID, Snackbar.LENGTH_LONG)
-                        .setAction(ACTION_ID, mock(View.OnClickListener.class)),
-                resolvedMessage, resolvedAction);
-    }
-
-    private void verifyDismissCallback(final ViewInteraction interaction,
-            final @Nullable ViewAction action, final @Nullable DismissAction dismissAction,
-            final int length, @Snackbar.Callback.DismissEvent final int expectedEvent)
-            throws Throwable {
-        final BaseTransientBottomBar.BaseCallback mockCallback =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        final Snackbar snackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, length)
-                .setAction(ACTION_TEXT, mock(View.OnClickListener.class))
-                .addCallback(mockCallback);
-
-        // Show the snackbar
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        // Verify that our onShown has been called
-        verify(mockCallback, times(1)).onShown(snackbar);
-        // and that the snackbar is either shown or queued to be shown
-        assertTrue(snackbar.isShownOrQueued());
-        // and also check that we have the intended message / action displayed somewhere in
-        // our hierarchy
-        onView(withText(MESSAGE_TEXT)).check(matches(isCompletelyDisplayed()));
-        onView(withText(ACTION_TEXT)).check(matches(isCompletelyDisplayed()));
-
-        // Now perform the UI interaction
-        SnackbarUtils.performActionAndWaitUntilFullyDismissed(snackbar,
-                new SnackbarUtils.TransientBottomBarAction() {
-                    @Override
-                    public void perform() throws Throwable {
-                        if (action != null) {
-                            interaction.perform(action);
-                        } else if (dismissAction != null) {
-                            mActivityTestRule.runOnUiThread(new Runnable() {
-                                @Override
-                                public void run() {
-                                    dismissAction.dismiss(snackbar);
-                                }
-                            });
-                        }
-                    }
-                });
-
-        // Verify that our onDismissed has been called
-        verify(mockCallback, times(1)).onDismissed(snackbar, expectedEvent);
-        verifyNoMoreInteractions(mockCallback);
-        // and that the snackbar is neither shown nor queued to be shown
-        assertFalse(snackbar.isShownOrQueued());
-    }
-
-    @Test
-    public void testDismissViaActionClick() throws Throwable {
-        verifyDismissCallback(
-                onView(withId(R.id.snackbar_action)),
-                click(),
-                null,
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_ACTION);
-    }
-
-    @Test
-    public void testDismissViaSwipe() throws Throwable {
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                swipeRight(),
-                null,
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_SWIPE);
-    }
-
-    @Test
-    public void testDismissViaSwipeRtl() throws Throwable {
-        onView(withId(R.id.col)).perform(setLayoutDirection(ViewCompat.LAYOUT_DIRECTION_RTL));
-        if (ViewCompat.getLayoutDirection(mCoordinatorLayout) == ViewCompat.LAYOUT_DIRECTION_RTL) {
-            // On devices that support RTL layout, the start-to-end dismiss swipe is done
-            // with swipeLeft() action
-            verifyDismissCallback(
-                    onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                    swipeLeft(),
-                    null,
-                    Snackbar.LENGTH_LONG,
-                    Snackbar.Callback.DISMISS_EVENT_SWIPE);
-        }
-    }
-
-    @Test
-    public void testDismissViaApi() throws Throwable {
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                null,
-                new DismissAction() {
-                    @Override
-                    public void dismiss(Snackbar snackbar) {
-                        snackbar.dismiss();
-                    }
-                },
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_MANUAL);
-    }
-
-    @LargeTest
-    @Test
-    public void testDismissViaTimeout() throws Throwable {
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                null,
-                null,
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_TIMEOUT);
-    }
-
-    @LargeTest
-    @Test
-    public void testSwipeUpDismissesViaTimeout() throws Throwable {
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                // This is a swipe up, from the middle center of the view, to above the view
-                // (outside the bounds)
-                new GeneralSwipeAction(
-                        Swipe.SLOW,
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                final int[] loc = new int[2];
-                                view.getLocationOnScreen(loc);
-                                return new float[]{
-                                        loc[0] + view.getWidth() / 2,
-                                        loc[1] + view.getHeight() / 2};
-                            }
-                        },
-                        new CoordinatesProvider() {
-                            @Override
-                            public float[] calculateCoordinates(View view) {
-                                final int[] loc = new int[2];
-                                view.getLocationOnScreen(loc);
-                                return new float[]{
-                                        loc[0] + view.getWidth() / 2,
-                                        loc[1] - view.getHeight()};
-                            }
-                        },
-                        Press.FINGER
-                ),
-                null,
-                Snackbar.LENGTH_SHORT,
-                Snackbar.Callback.DISMISS_EVENT_TIMEOUT);
-    }
-
-    @Test
-    public void testDismissViaAnotherSnackbar() throws Throwable {
-        final Snackbar anotherSnackbar =
-                Snackbar.make(mCoordinatorLayout, "A different message", Snackbar.LENGTH_SHORT);
-
-        // Our dismiss action is to show another snackbar (and verify that the original snackbar
-        // is now dismissed with CONSECUTIVE event)
-        verifyDismissCallback(
-                onView(isAssignableFrom(Snackbar.SnackbarLayout.class)),
-                null,
-                new DismissAction() {
-                    @Override
-                    public void dismiss(Snackbar snackbar) {
-                        anotherSnackbar.show();
-                    }
-                },
-                Snackbar.LENGTH_LONG,
-                Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE);
-
-        // And dismiss the second snackbar to get back to clean state
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(anotherSnackbar);
-    }
-
-    @Test
-    public void testActionClickListener() {
-        final View.OnClickListener mockClickListener = mock(View.OnClickListener.class);
-        final Snackbar snackbar =
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_SHORT)
-                    .setAction(ACTION_TEXT, mockClickListener);
-
-        // Show the snackbar
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        // perform the action click
-        onView(withId(R.id.snackbar_action)).perform(click());
-        // and verify that our click listener has been called
-        verify(mockClickListener, times(1)).onClick(any(View.class));
-    }
-
-    @Test
-    public void testSetCallback() throws Throwable {
-        final Snackbar snackbar =
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE)
-                        .setAction(ACTION_TEXT, mock(View.OnClickListener.class));
-        final Snackbar.Callback mockCallback = spy(new Snackbar.Callback());
-        snackbar.setCallback(mockCallback);
-
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        verify(mockCallback, times(1)).onShown(snackbar);
-
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-        verify(mockCallback, times(1)).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-    }
-
-    @Test
-    public void testSingleCallback() throws Throwable {
-        final Snackbar snackbar =
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE)
-                        .setAction(ACTION_TEXT, mock(View.OnClickListener.class));
-        final BaseTransientBottomBar.BaseCallback mockCallback1 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        final BaseTransientBottomBar.BaseCallback mockCallback2 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        snackbar.addCallback(mockCallback1);
-
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        verify(mockCallback1, times(1)).onShown(snackbar);
-        verify(mockCallback2, never()).onShown(snackbar);
-
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-        verify(mockCallback1, times(1)).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-        verify(mockCallback2, never()).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-    }
-
-    @Test
-    public void testMultipleCallbacks() throws Throwable {
-        final Snackbar snackbar =
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE)
-                        .setAction(ACTION_TEXT, mock(View.OnClickListener.class));
-        final BaseTransientBottomBar.BaseCallback mockCallback1 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        final BaseTransientBottomBar.BaseCallback mockCallback2 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        snackbar.addCallback(mockCallback1);
-        snackbar.addCallback(mockCallback2);
-
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        verify(mockCallback1, times(1)).onShown(snackbar);
-        verify(mockCallback2, times(1)).onShown(snackbar);
-
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-        verify(mockCallback1, times(1)).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-        verify(mockCallback2, times(1)).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-    }
-
-    @Test
-    public void testMultipleCallbacksWithRemoval() throws Throwable {
-        final Snackbar snackbar =
-                Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT, Snackbar.LENGTH_INDEFINITE)
-                        .setAction(ACTION_TEXT, mock(View.OnClickListener.class));
-        final BaseTransientBottomBar.BaseCallback mockCallback1 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        final BaseTransientBottomBar.BaseCallback mockCallback2 =
-                mock(BaseTransientBottomBar.BaseCallback.class);
-        snackbar.addCallback(mockCallback1);
-        snackbar.addCallback(mockCallback2);
-
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-        verify(mockCallback1, times(1)).onShown(snackbar);
-        verify(mockCallback2, times(1)).onShown(snackbar);
-
-        snackbar.removeCallback(mockCallback2);
-
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-        verify(mockCallback1, times(1)).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-        verify(mockCallback2, never()).onDismissed(snackbar,
-                BaseTransientBottomBar.BaseCallback.DISMISS_EVENT_MANUAL);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/SnackbarTestWithFAB.java b/design/tests/src/android/support/design/widget/SnackbarTestWithFAB.java
deleted file mode 100644
index 5ffe3ca..0000000
--- a/design/tests/src/android/support/design/widget/SnackbarTestWithFAB.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.junit.Assert.assertEquals;
-
-import android.support.design.test.R;
-import android.support.design.testutils.SnackbarUtils;
-import android.support.test.filters.LargeTest;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Test;
-
-@LargeTest
-public class SnackbarTestWithFAB extends BaseInstrumentationTestCase<SnackbarActivityWithFAB> {
-
-    private static final String MESSAGE_TEXT = "Test Message";
-
-    private CoordinatorLayout mCoordinatorLayout;
-
-    public SnackbarTestWithFAB() {
-        super(SnackbarActivityWithFAB.class);
-    }
-
-    @Before
-    public void setup() {
-        mCoordinatorLayout =
-                (CoordinatorLayout) mActivityTestRule.getActivity().findViewById(R.id.col);
-    }
-
-    @Test
-    public void testShortSnackbarDodgesFab() {
-        final int[] originalFabPosition = new int[2];
-        final View fab = mCoordinatorLayout.findViewById(R.id.fab);
-        fab.getLocationOnScreen(originalFabPosition);
-
-        // Show a simple Snackbar and wait for it to be shown
-        final Snackbar snackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT,
-                Snackbar.LENGTH_SHORT);
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-
-        // Now check that the FAB has shifted up to make space for the Snackbar
-        final int[] fabPosition = new int[2];
-        fab.getLocationOnScreen(fabPosition);
-        assertEquals(originalFabPosition[0], fabPosition[0]);
-        assertEquals(originalFabPosition[1] - snackbar.getView().getHeight(), fabPosition[1]);
-
-        // Now wait until the Snackbar has been dismissed
-        SnackbarUtils.waitUntilFullyDismissed(snackbar);
-
-        // And check that the FAB is back in its original position
-        fab.getLocationOnScreen(fabPosition);
-        assertEquals(originalFabPosition[0], fabPosition[0]);
-        assertEquals(originalFabPosition[1], fabPosition[1]);
-    }
-
-    @Test
-    public void testIndefiniteSnackbarDodgesFab() throws Throwable {
-        final int[] originalFabPosition = new int[2];
-        final View fab = mCoordinatorLayout.findViewById(R.id.fab);
-        fab.getLocationOnScreen(originalFabPosition);
-
-        // Show a simple Snackbar and wait for it to be shown
-        final Snackbar snackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT,
-                Snackbar.LENGTH_INDEFINITE);
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-
-        // Now check that the FAB has shifted up to make space for the Snackbar
-        final int[] fabPosition = new int[2];
-        fab.getLocationOnScreen(fabPosition);
-        assertEquals(originalFabPosition[0], fabPosition[0]);
-        assertEquals(originalFabPosition[1] - snackbar.getView().getHeight(), fabPosition[1]);
-
-        // Now dismiss the Snackbar and wait for it to be dismissed
-        SnackbarUtils.dismissTransientBottomBarAndWaitUntilFullyDismissed(snackbar);
-
-        // And check that the FAB is back in its original position
-        fab.getLocationOnScreen(fabPosition);
-        assertEquals(originalFabPosition[0], fabPosition[0]);
-        assertEquals(originalFabPosition[1], fabPosition[1]);
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/SnackbarTestWithTranslucentNavBar.java b/design/tests/src/android/support/design/widget/SnackbarTestWithTranslucentNavBar.java
deleted file mode 100644
index 07a8d0f..0000000
--- a/design/tests/src/android/support/design/widget/SnackbarTestWithTranslucentNavBar.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-import android.support.design.test.R;
-import android.support.design.testutils.SnackbarUtils;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.v4.view.WindowInsetsCompat;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Test;
-
-@SdkSuppress(minSdkVersion = 21)
-public class SnackbarTestWithTranslucentNavBar
-        extends BaseInstrumentationTestCase<SnackbarActivityWithTranslucentNavBar> {
-
-    private static final String MESSAGE_TEXT = "Test Message";
-
-    private CoordinatorLayout mCoordinatorLayout;
-
-    public SnackbarTestWithTranslucentNavBar() {
-        super(SnackbarActivityWithTranslucentNavBar.class);
-    }
-
-    @Before
-    public void setup() {
-        mCoordinatorLayout =
-                (CoordinatorLayout) mActivityTestRule.getActivity().findViewById(R.id.col);
-    }
-
-    @Test
-    @MediumTest
-    public void testDrawsAboveNavigationBar() {
-        // Show a simple Snackbar and wait for it to be shown
-        final Snackbar snackbar = Snackbar.make(mCoordinatorLayout, MESSAGE_TEXT,
-                Snackbar.LENGTH_SHORT);
-        SnackbarUtils.showTransientBottomBarAndWaitUntilFullyShown(snackbar);
-
-        final WindowInsetsCompat colLastInsets = mCoordinatorLayout.getLastWindowInsets();
-        assertNotNull(colLastInsets);
-
-        // Check that the Snackbar view has padding set to display above the nav bar
-        final View view = snackbar.getView();
-        assertNotNull(view);
-        assertEquals(colLastInsets.getSystemWindowInsetBottom(), view.getPaddingBottom());
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/TabLayoutPoolingActivity.java b/design/tests/src/android/support/design/widget/TabLayoutPoolingActivity.java
deleted file mode 100644
index 2108235..0000000
--- a/design/tests/src/android/support/design/widget/TabLayoutPoolingActivity.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class TabLayoutPoolingActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_tabs_twice;
-    }
-}
\ No newline at end of file
diff --git a/design/tests/src/android/support/design/widget/TabLayoutPoolingTest.java b/design/tests/src/android/support/design/widget/TabLayoutPoolingTest.java
deleted file mode 100755
index a805a2e..0000000
--- a/design/tests/src/android/support/design/widget/TabLayoutPoolingTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.support.design.test.R;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-
-import org.junit.Test;
-
-public class TabLayoutPoolingTest extends BaseInstrumentationTestCase<TabLayoutPoolingActivity> {
-
-    public TabLayoutPoolingTest() {
-        super(TabLayoutPoolingActivity.class);
-    }
-
-    @UiThreadTest
-    @SmallTest
-    @Test
-    public void testUsingTabsFromOtherInstance() {
-        final Activity activity = mActivityTestRule.getActivity();
-
-        // TabLayout1 has items added via the layout, so we'll just check they're
-        // there first
-        final TabLayout tabLayout1 = (TabLayout) activity.findViewById(R.id.tabs_1);
-        assertTrue(tabLayout1.getTabCount() > 0);
-
-        // Now remove all tabs. TabLayout will pool the Tab instances...
-        tabLayout1.removeAllTabs();
-
-        // Now add some tabs to the second TabLayout and make sure that we don't crash
-        final TabLayout tabLayout2 = (TabLayout) activity.findViewById(R.id.tabs_2);
-        tabLayout2.addTab(tabLayout2.newTab());
-        tabLayout2.addTab(tabLayout2.newTab());
-        tabLayout2.addTab(tabLayout2.newTab());
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/TabLayoutTest.java b/design/tests/src/android/support/design/widget/TabLayoutTest.java
deleted file mode 100755
index 730ff56..0000000
--- a/design/tests/src/android/support/design/widget/TabLayoutTest.java
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.TabLayoutActions.selectTab;
-import static android.support.design.testutils.TabLayoutActions.setScrollPosition;
-import static android.support.design.testutils.TestUtilsActions.setLayoutDirection;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.os.Build;
-import android.support.design.test.R;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingResource;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewAssertion;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.SmallTest;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.view.InflateException;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.PointerIcon;
-import android.view.View;
-
-import org.junit.Test;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-@SmallTest
-public class TabLayoutTest extends BaseInstrumentationTestCase<AppCompatActivity> {
-    public TabLayoutTest() {
-        super(AppCompatActivity.class);
-    }
-
-    @Test
-    @UiThreadTest
-    public void testInflateTabLayoutWithTabItems() {
-        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-        final TabLayout tabLayout = (TabLayout) inflater.inflate(R.layout.design_tabs_items, null);
-
-        assertEquals(3, tabLayout.getTabCount());
-
-        // Tab 0 has text, but no icon or custom view
-        TabLayout.Tab tab = tabLayout.getTabAt(0);
-        assertEquals(mActivityTestRule.getActivity().getString(R.string.tab_layout_text),
-                tab.getText());
-        assertNull(tab.getIcon());
-        assertNull(tab.getCustomView());
-
-        // Tab 1 has an icon, but no text or custom view
-        tab = tabLayout.getTabAt(1);
-        assertNull(tab.getText());
-        assertNotNull(tab.getIcon());
-        assertNull(tab.getCustomView());
-
-        // Tab 2 has a custom view, but no text or icon
-        tab = tabLayout.getTabAt(2);
-        assertNull(tab.getText());
-        assertNull(tab.getIcon());
-        assertNotNull(tab.getCustomView());
-        assertEquals(R.id.my_custom_tab, tab.getCustomView().getId());
-    }
-
-    @Test
-    @UiThreadTest
-    public void testInflateTabLayoutWithNonTabItem() throws Throwable {
-        try {
-            final LayoutInflater inflater =
-                    LayoutInflater.from(mActivityTestRule.getActivity());
-            inflater.inflate(R.layout.design_tabs_with_non_tabitems, null);
-        } catch (Throwable throwable) {
-            assertTrue(throwable instanceof InflateException
-                    || throwable instanceof IllegalArgumentException);
-        }
-    }
-
-    @Test
-    @UiThreadTest
-    public void testTabWithCustomLayoutSelection1() {
-        final TabLayout.OnTabSelectedListener mockListener =
-                mock(TabLayout.OnTabSelectedListener.class);
-        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-
-        final TabLayout tabLayout = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
-        tabLayout.addOnTabSelectedListener(mockListener);
-        final TabLayout.Tab tab = tabLayout.newTab();
-        tab.setCustomView(R.layout.design_tab_item_custom);
-        tabLayout.addTab(tab);
-        verify(mockListener, times(1)).onTabSelected(eq(tab));
-        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
-
-        assertNotNull("Tab has custom view", tab.getCustomView());
-        assertEquals("First tab is selected", 0, tabLayout.getSelectedTabPosition());
-        assertTabCustomViewSelected(tabLayout);
-    }
-
-    @Test
-    @UiThreadTest
-    public void testTabWithCustomLayoutSelection2() {
-        final TabLayout.OnTabSelectedListener mockListener =
-                mock(TabLayout.OnTabSelectedListener.class);
-        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-
-        final TabLayout tabLayout = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
-        tabLayout.addOnTabSelectedListener(mockListener);
-        final TabLayout.Tab tab = tabLayout.newTab();
-        tabLayout.addTab(tab);
-        verify(mockListener, times(1)).onTabSelected(eq(tab));
-        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
-        tab.setCustomView(R.layout.design_tab_item_custom);
-
-        assertNotNull("Tab has custom view", tab.getCustomView());
-        assertEquals("First tab is selected", 0, tabLayout.getSelectedTabPosition());
-        assertTabCustomViewSelected(tabLayout);
-    }
-
-    @Test
-    @UiThreadTest
-    public void testMultipleTabsWithCustomLayoutSelection1() {
-        final TabLayout.OnTabSelectedListener mockListener =
-                mock(TabLayout.OnTabSelectedListener.class);
-        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-        final TabLayout tabs = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
-        tabs.addOnTabSelectedListener(mockListener);
-
-        final TabLayout.Tab tab1 = tabs.newTab().setCustomView(R.layout.design_tab_item_custom);
-        tabs.addTab(tab1);
-        verify(mockListener, times(1)).onTabSelected(eq(tab1));
-        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
-        final TabLayout.Tab tab2 = tabs.newTab().setCustomView(R.layout.design_tab_item_custom);
-        tabs.addTab(tab2, true);
-        verify(mockListener, times(1)).onTabSelected(eq(tab2));
-        verify(mockListener, times(1)).onTabUnselected(eq(tab1));
-        final TabLayout.Tab tab3 = tabs.newTab().setCustomView(R.layout.design_tab_item_custom);
-        tabs.addTab(tab3);
-        verifyNoMoreInteractions(mockListener);
-
-        assertEquals("Second tab is selected", 1, tabs.getSelectedTabPosition());
-        assertTabCustomViewSelected(tabs);
-    }
-
-    @Test
-    @UiThreadTest
-    public void testMultipleTabsWithCustomLayoutSelection2() {
-        final TabLayout.OnTabSelectedListener mockListener =
-                mock(TabLayout.OnTabSelectedListener.class);
-        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-        final TabLayout tabs = (TabLayout) inflater.inflate(R.layout.design_tabs, null);
-        tabs.addOnTabSelectedListener(mockListener);
-
-        final TabLayout.Tab tab1 = tabs.newTab();
-        tabs.addTab(tab1);
-        verify(mockListener, times(1)).onTabSelected(eq(tab1));
-        verify(mockListener, times(0)).onTabUnselected(any(TabLayout.Tab.class));
-        final TabLayout.Tab tab2 = tabs.newTab();
-        tabs.addTab(tab2, true);
-        verify(mockListener, times(1)).onTabSelected(eq(tab2));
-        verify(mockListener, times(1)).onTabUnselected(eq(tab1));
-        final TabLayout.Tab tab3 = tabs.newTab();
-        tabs.addTab(tab3);
-        verifyNoMoreInteractions(mockListener);
-
-        tabs.getTabAt(0).setCustomView(R.layout.design_tab_item_custom);
-        tabs.getTabAt(1).setCustomView(R.layout.design_tab_item_custom);
-        tabs.getTabAt(2).setCustomView(R.layout.design_tab_item_custom);
-
-        assertEquals("Second tab is selected", 1, tabs.getSelectedTabPosition());
-        assertTabCustomViewSelected(tabs);
-    }
-
-    @Test
-    @UiThreadTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
-    public void testPointerIcon() {
-        final LayoutInflater inflater = LayoutInflater.from(mActivityTestRule.getActivity());
-        final TabLayout tabLayout = (TabLayout) inflater.inflate(R.layout.design_tabs_items, null);
-        final PointerIcon expectedIcon =
-                PointerIcon.getSystemIcon(mActivityTestRule.getActivity(), PointerIcon.TYPE_HAND);
-
-        final int tabCount = tabLayout.getTabCount();
-        assertEquals(3, tabCount);
-
-        final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, 0, 0, 0);
-        for (int i = 0; i < tabCount; i++) {
-            assertEquals(expectedIcon, tabLayout.getTabAt(i).mView.onResolvePointerIcon(event, 0));
-        }
-    }
-
-    private static void assertTabCustomViewSelected(final TabLayout tabLayout) {
-        for (int i = 0, count = tabLayout.getTabCount(); i < count; i++) {
-            final TabLayout.Tab tab = tabLayout.getTabAt(i);
-            final View tabCustomView = tab.getCustomView();
-            if (tabCustomView != null) {
-                assertEquals(tab.isSelected(), tabCustomView.isSelected());
-            }
-        }
-    }
-
-    @Test
-    public void setScrollPositionLtr() throws Throwable {
-        testSetScrollPosition(true);
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
-    @Test
-    public void setScrollPositionRtl() throws Throwable {
-        testSetScrollPosition(false);
-    }
-
-    private void testSetScrollPosition(final boolean isLtr) throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivityTestRule.getActivity().setContentView(R.layout.design_tabs_fixed_width);
-            }
-        });
-        final TabLayout tabs = (TabLayout) mActivityTestRule.getActivity().findViewById(R.id.tabs);
-        assertEquals(TabLayout.MODE_SCROLLABLE, tabs.getTabMode());
-
-        final TabLayoutScrollIdlingResource idler = new TabLayoutScrollIdlingResource(tabs);
-        Espresso.registerIdlingResources(idler);
-
-        // We're going to call setScrollPosition() incrementally, as if scrolling between one tab
-        // and the next. Use the middle tab for best results. The positionOffsets should be in the
-        // range [0, 1), so the final call will wrap to 0 but use the next tab's position.
-        final int middleTab = tabs.getTabCount() / 2;
-        final int[] positions = {middleTab, middleTab, middleTab, middleTab, middleTab + 1};
-        final float[] positionOffsets = {0f, .25f, .5f, .75f, 0f};
-
-        // Set layout direction
-        onView(withId(R.id.tabs)).perform(setLayoutDirection(
-                isLtr ? ViewCompat.LAYOUT_DIRECTION_LTR : ViewCompat.LAYOUT_DIRECTION_RTL));
-        // Make sure it's scrolled all the way to the start
-        onView(withId(R.id.tabs)).perform(selectTab(0));
-
-        // Perform a series of setScrollPosition() calls
-        final AtomicInteger lastScrollX = new AtomicInteger(tabs.getScrollX());
-        for (int i = 0; i < positions.length; i++) {
-            onView(withId(R.id.tabs))
-                    .perform(setScrollPosition(positions[i], positionOffsets[i]))
-                    .check(new ViewAssertion() {
-                        @Override
-                        public void check(View view, NoMatchingViewException notFoundException) {
-                            if (view == null) {
-                                throw notFoundException;
-                            }
-                            // Verify increasing or decreasing scroll X values
-                            int sx = view.getScrollX();
-                            assertTrue(isLtr ? sx > lastScrollX.get() : sx < lastScrollX.get());
-                            lastScrollX.set(sx);
-                        }
-                    });
-        }
-
-        Espresso.unregisterIdlingResources(idler);
-    }
-
-    static class TabLayoutScrollIdlingResource implements IdlingResource {
-
-        private boolean mIsIdle = true;
-        private ResourceCallback mCallback;
-
-        TabLayoutScrollIdlingResource(final TabLayout tabLayout) {
-            tabLayout.setScrollAnimatorListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animator) {
-                    setIdle(false);
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animator) {
-                    setIdle(true);
-                }
-            });
-        }
-
-        @Override
-        public String getName() {
-            return "TabLayoutScrollIdlingResource";
-        }
-
-        @Override
-        public boolean isIdleNow() {
-            return mIsIdle;
-        }
-
-        @Override
-        public void registerIdleTransitionCallback(ResourceCallback callback) {
-            mCallback = callback;
-        }
-
-        private void setIdle(boolean idle) {
-            boolean wasIdle = mIsIdle;
-            mIsIdle = idle;
-            if (mIsIdle && !wasIdle && mCallback != null) {
-                mCallback.onTransitionToIdle();
-            }
-        }
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerActivity.java b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerActivity.java
deleted file mode 100644
index 39db827..0000000
--- a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerActivity.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import android.support.design.test.R;
-import android.support.v7.widget.Toolbar;
-
-public class TabLayoutWithViewPagerActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_tabs_viewpager;
-    }
-
-    @Override
-    protected void onContentViewSet() {
-        Toolbar toolbar = findViewById(R.id.toolbar);
-        setSupportActionBar(toolbar);
-        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java b/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
deleted file mode 100755
index b169dad..0000000
--- a/design/tests/src/android/support/design/widget/TabLayoutWithViewPagerTest.java
+++ /dev/null
@@ -1,628 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import static android.support.design.testutils.TabLayoutActions.setupWithViewPager;
-import static android.support.design.testutils.ViewPagerActions.setAdapter;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withParent;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.support.annotation.DimenRes;
-import android.support.annotation.LayoutRes;
-import android.support.design.test.R;
-import android.support.design.testutils.TabLayoutActions;
-import android.support.design.testutils.TestUtilsActions;
-import android.support.design.testutils.TestUtilsMatchers;
-import android.support.design.testutils.ViewPagerActions;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SmallTest;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.Pair;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.HorizontalScrollView;
-import android.widget.TextView;
-
-import org.hamcrest.Matcher;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-
-public class TabLayoutWithViewPagerTest
-        extends BaseInstrumentationTestCase<TabLayoutWithViewPagerActivity> {
-    private TabLayout mTabLayout;
-
-    private ViewPager mViewPager;
-
-    private ColorPagerAdapter mDefaultPagerAdapter;
-
-    protected static class BasePagerAdapter<Q> extends PagerAdapter {
-        protected ArrayList<Pair<String, Q>> mEntries = new ArrayList<>();
-
-        public void add(String title, Q content) {
-            mEntries.add(new Pair<>(title, content));
-        }
-
-        @Override
-        public int getCount() {
-            return mEntries.size();
-        }
-
-        protected void configureInstantiatedItem(View view, int position) {
-            switch (position) {
-                case 0:
-                    view.setId(R.id.page_0);
-                    break;
-                case 1:
-                    view.setId(R.id.page_1);
-                    break;
-                case 2:
-                    view.setId(R.id.page_2);
-                    break;
-                case 3:
-                    view.setId(R.id.page_3);
-                    break;
-                case 4:
-                    view.setId(R.id.page_4);
-                    break;
-                case 5:
-                    view.setId(R.id.page_5);
-                    break;
-                case 6:
-                    view.setId(R.id.page_6);
-                    break;
-                case 7:
-                    view.setId(R.id.page_7);
-                    break;
-                case 8:
-                    view.setId(R.id.page_8);
-                    break;
-                case 9:
-                    view.setId(R.id.page_9);
-                    break;
-            }
-        }
-
-        @Override
-        public void destroyItem(ViewGroup container, int position, Object object) {
-            // The adapter is also responsible for removing the view.
-            container.removeView(((ViewHolder) object).view);
-        }
-
-        @Override
-        public int getItemPosition(Object object) {
-            return ((ViewHolder) object).position;
-        }
-
-        @Override
-        public boolean isViewFromObject(View view, Object object) {
-            return ((ViewHolder) object).view == view;
-        }
-
-        @Override
-        public CharSequence getPageTitle(int position) {
-            return mEntries.get(position).first;
-        }
-
-        protected static class ViewHolder {
-            final View view;
-            final int position;
-
-            public ViewHolder(View view, int position) {
-                this.view = view;
-                this.position = position;
-            }
-        }
-    }
-
-    protected static class ColorPagerAdapter extends BasePagerAdapter<Integer> {
-        @Override
-        public Object instantiateItem(ViewGroup container, int position) {
-            final View view = new View(container.getContext());
-            view.setBackgroundColor(mEntries.get(position).second);
-            configureInstantiatedItem(view, position);
-
-            // Unlike ListView adapters, the ViewPager adapter is responsible
-            // for adding the view to the container.
-            container.addView(view);
-
-            return new ViewHolder(view, position);
-        }
-    }
-
-    protected static class TextPagerAdapter extends BasePagerAdapter<String> {
-        @Override
-        public Object instantiateItem(ViewGroup container, int position) {
-            final TextView view = new TextView(container.getContext());
-            view.setText(mEntries.get(position).second);
-            configureInstantiatedItem(view, position);
-
-            // Unlike ListView adapters, the ViewPager adapter is responsible
-            // for adding the view to the container.
-            container.addView(view);
-
-            return new ViewHolder(view, position);
-        }
-    }
-
-    private static <Q> ViewAction addItemToPager(final String title, final Q content) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(ViewPager.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Add item and notify on content change";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final ViewPager viewPager = (ViewPager) view;
-                final BasePagerAdapter<Q> viewPagerAdapter =
-                        (BasePagerAdapter<Q>) viewPager.getAdapter();
-                viewPagerAdapter.add(title, content);
-                viewPagerAdapter.notifyDataSetChanged();
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    private static <Q> ViewAction addItemsToPager(final String[] title, final Q[] content) {
-        return new ViewAction() {
-            @Override
-            public Matcher<View> getConstraints() {
-                return isAssignableFrom(ViewPager.class);
-            }
-
-            @Override
-            public String getDescription() {
-                return "Add items and notify on content change";
-            }
-
-            @Override
-            public void perform(UiController uiController, View view) {
-                uiController.loopMainThreadUntilIdle();
-
-                final ViewPager viewPager = (ViewPager) view;
-                final BasePagerAdapter<Q> viewPagerAdapter =
-                        (BasePagerAdapter<Q>) viewPager.getAdapter();
-                int itemCount = title.length;
-                for (int i = 0; i < itemCount; i++) {
-                    viewPagerAdapter.add(title[i], content[i]);
-                }
-                viewPagerAdapter.notifyDataSetChanged();
-
-                uiController.loopMainThreadUntilIdle();
-            }
-        };
-    }
-
-    public TabLayoutWithViewPagerTest() {
-        super(TabLayoutWithViewPagerActivity.class);
-    }
-
-    @Before
-    public void setUp() throws Exception {
-        final TabLayoutWithViewPagerActivity activity = mActivityTestRule.getActivity();
-        mTabLayout = (TabLayout) activity.findViewById(R.id.tabs);
-        mViewPager = (ViewPager) activity.findViewById(R.id.tabs_viewpager);
-
-        mDefaultPagerAdapter = new ColorPagerAdapter();
-        mDefaultPagerAdapter.add("Red", Color.RED);
-        mDefaultPagerAdapter.add("Green", Color.GREEN);
-        mDefaultPagerAdapter.add("Blue", Color.BLUE);
-
-        // Configure view pager
-        onView(withId(R.id.tabs_viewpager)).perform(
-                setAdapter(mDefaultPagerAdapter),
-                ViewPagerActions.scrollToPage(0));
-    }
-
-    private void setupTabLayoutWithViewPager() {
-        // And wire the tab layout to it
-        onView(withId(R.id.tabs)).perform(setupWithViewPager(mViewPager));
-    }
-
-    /**
-     * Verifies that selecting pages in <code>ViewPager</code> also updates the tab selection
-     * in the wired <code>TabLayout</code>
-     */
-    private void verifyViewPagerSelection() {
-        int itemCount = mViewPager.getAdapter().getCount();
-
-        onView(withId(R.id.tabs_viewpager)).perform(ViewPagerActions.scrollToPage(0));
-        assertEquals("Selected page", 0, mViewPager.getCurrentItem());
-        assertEquals("Selected tab", 0, mTabLayout.getSelectedTabPosition());
-
-        // Scroll tabs to the right
-        for (int i = 0; i < (itemCount - 1); i++) {
-            // Scroll one tab to the right
-            onView(withId(R.id.tabs_viewpager)).perform(ViewPagerActions.scrollRight());
-            final int expectedCurrentTabIndex = i + 1;
-            assertEquals("Scroll right #" + i, expectedCurrentTabIndex,
-                    mViewPager.getCurrentItem());
-            assertEquals("Selected tab after scrolling right #" + i, expectedCurrentTabIndex,
-                    mTabLayout.getSelectedTabPosition());
-        }
-
-        // Scroll tabs to the left
-        for (int i = 0; i < (itemCount - 1); i++) {
-            // Scroll one tab to the left
-            onView(withId(R.id.tabs_viewpager)).perform(ViewPagerActions.scrollLeft());
-            final int expectedCurrentTabIndex = itemCount - i - 2;
-            assertEquals("Scroll left #" + i, expectedCurrentTabIndex, mViewPager.getCurrentItem());
-            assertEquals("Selected tab after scrolling left #" + i, expectedCurrentTabIndex,
-                    mTabLayout.getSelectedTabPosition());
-        }
-    }
-
-    /**
-     * Verifies that selecting pages in <code>ViewPager</code> also updates the tab selection
-     * in the wired <code>TabLayout</code>
-     */
-    private void verifyTabLayoutSelection() {
-        int itemCount = mTabLayout.getTabCount();
-
-        onView(withId(R.id.tabs_viewpager)).perform(ViewPagerActions.scrollToPage(0));
-        assertEquals("Selected tab", 0, mTabLayout.getSelectedTabPosition());
-        assertEquals("Selected page", 0, mViewPager.getCurrentItem());
-
-        // Select tabs "going" to the right. Note that the first loop iteration tests the
-        // scenario of "selecting" the first tab when it's already selected.
-        for (int i = 0; i < itemCount; i++) {
-            onView(withId(R.id.tabs)).perform(TabLayoutActions.selectTab(i));
-            assertEquals("Selected tab after selecting #" + i, i,
-                    mTabLayout.getSelectedTabPosition());
-            assertEquals("Select tab #" + i, i, mViewPager.getCurrentItem());
-        }
-
-        // Select tabs "going" to the left. Note that the first loop iteration tests the
-        // scenario of "selecting" the last tab when it's already selected.
-        for (int i = itemCount - 1; i >= 0; i--) {
-            onView(withId(R.id.tabs)).perform(TabLayoutActions.selectTab(i));
-            assertEquals("Scroll left #" + i, i, mViewPager.getCurrentItem());
-            assertEquals("Selected tab after scrolling left #" + i, i,
-                    mTabLayout.getSelectedTabPosition());
-        }
-    }
-
-    @Test
-    @SmallTest
-    public void testBasics() {
-        setupTabLayoutWithViewPager();
-
-        final int itemCount = mViewPager.getAdapter().getCount();
-
-        assertEquals("Matching item count", itemCount, mTabLayout.getTabCount());
-
-        for (int i = 0; i < itemCount; i++) {
-            assertEquals("Tab #" +i, mViewPager.getAdapter().getPageTitle(i),
-                    mTabLayout.getTabAt(i).getText());
-        }
-
-        assertEquals("Selected tab", mViewPager.getCurrentItem(),
-                mTabLayout.getSelectedTabPosition());
-
-        verifyViewPagerSelection();
-    }
-
-    @Test
-    @SmallTest
-    public void testInteraction() {
-        setupTabLayoutWithViewPager();
-
-        assertEquals("Default selected page", 0, mViewPager.getCurrentItem());
-        assertEquals("Default selected tab", 0, mTabLayout.getSelectedTabPosition());
-
-        verifyTabLayoutSelection();
-    }
-
-    @Test
-    @SmallTest
-    public void testAdapterContentChange() {
-        setupTabLayoutWithViewPager();
-
-        // Verify that we have the expected initial adapter
-        PagerAdapter initialAdapter = mViewPager.getAdapter();
-        assertEquals("Initial adapter class", ColorPagerAdapter.class, initialAdapter.getClass());
-        assertEquals("Initial adapter page count", 3, initialAdapter.getCount());
-
-        // Add two more entries to our adapter
-        onView(withId(R.id.tabs_viewpager)).perform(
-                addItemsToPager(new String[] { "Yellow", "Magenta"},
-                        new Integer[] { Color.YELLOW, Color.MAGENTA }));
-
-        // We have more comprehensive test coverage for changing the ViewPager adapter in v4/tests.
-        // Here we are focused on testing the continuous integration of TabLayout with the new
-        // content of ViewPager
-
-        final int newItemCount = mDefaultPagerAdapter.getCount();
-        assertEquals("Matching item count", newItemCount, mTabLayout.getTabCount());
-
-        for (int i = 0; i < newItemCount; i++) {
-            assertEquals("Tab #" +i, mViewPager.getAdapter().getPageTitle(i),
-                    mTabLayout.getTabAt(i).getText());
-        }
-
-        verifyViewPagerSelection();
-        verifyTabLayoutSelection();
-    }
-
-    @Test
-    @SmallTest
-    public void testAdapterContentChangeWithAutoRefreshDisabled() {
-        onView(withId(R.id.tabs)).perform(setupWithViewPager(mViewPager, false));
-
-        // Verify that we have the expected initial adapter
-        PagerAdapter initialAdapter = mViewPager.getAdapter();
-        assertEquals("Initial adapter class", ColorPagerAdapter.class, initialAdapter.getClass());
-        assertEquals("Initial adapter page count", 3, initialAdapter.getCount());
-
-        // Add two entries to our adapter
-        onView(withId(R.id.tabs_viewpager)).perform(
-                addItemsToPager(new String[] { "Yellow", "Magenta"},
-                        new Integer[] { Color.YELLOW, Color.MAGENTA }));
-
-        // Assert that the TabLayout did not update and add the new items
-        final int newItemCount = mDefaultPagerAdapter.getCount();
-        assertNotEquals("Matching item count", newItemCount, mTabLayout.getTabCount());
-    }
-
-    @Test
-    @SmallTest
-    public void testBasicAutoRefreshDisabled() {
-        onView(withId(R.id.tabs)).perform(setupWithViewPager(mViewPager, false));
-
-        // Check that the TabLayout has the same number of items are the adapter
-        PagerAdapter initialAdapter = mViewPager.getAdapter();
-        assertEquals("Initial adapter page count", initialAdapter.getCount(),
-                mTabLayout.getTabCount());
-
-        // Add two more entries to our adapter
-        mDefaultPagerAdapter.add("Yellow", Color.YELLOW);
-        mDefaultPagerAdapter.add("Magenta", Color.MAGENTA);
-        final int newItemCount = mDefaultPagerAdapter.getCount();
-
-        // Assert that the TabLayout did not update and add the new items
-        assertNotEquals("Matching item count", newItemCount, mTabLayout.getTabCount());
-
-        // Now setup again to update the tabs
-        onView(withId(R.id.tabs)).perform(setupWithViewPager(mViewPager, false));
-
-        // Assert that the TabLayout updated and added the new items
-        assertEquals("Matching item count", newItemCount, mTabLayout.getTabCount());
-    }
-
-    @Test
-    @SmallTest
-    public void testAdapterChange() {
-        setupTabLayoutWithViewPager();
-
-        // Verify that we have the expected initial adapter
-        PagerAdapter initialAdapter = mViewPager.getAdapter();
-        assertEquals("Initial adapter class", ColorPagerAdapter.class, initialAdapter.getClass());
-        assertEquals("Initial adapter page count", 3, initialAdapter.getCount());
-
-        // Create a new adapter
-        TextPagerAdapter newAdapter = new TextPagerAdapter();
-        final int newItemCount = 6;
-        for (int i = 0; i < newItemCount; i++) {
-            newAdapter.add("Title " + i, "Body " + i);
-        }
-        // And set it on the ViewPager
-        onView(withId(R.id.tabs_viewpager)).perform(setAdapter(newAdapter),
-                ViewPagerActions.scrollToPage(0));
-
-        // As TabLayout doesn't track adapter changes, we need to re-wire the new adapter
-        onView(withId(R.id.tabs)).perform(setupWithViewPager(mViewPager));
-
-        // We have more comprehensive test coverage for changing the ViewPager adapter in v4/tests.
-        // Here we are focused on testing the integration of TabLayout with the new
-        // content of ViewPager
-
-        assertEquals("Matching item count", newItemCount, mTabLayout.getTabCount());
-
-        for (int i = 0; i < newItemCount; i++) {
-            assertEquals("Tab #" +i, mViewPager.getAdapter().getPageTitle(i),
-                    mTabLayout.getTabAt(i).getText());
-        }
-
-        verifyViewPagerSelection();
-        verifyTabLayoutSelection();
-    }
-
-    @Test
-    @LargeTest
-    public void testFixedTabMode() {
-        // Create a new adapter (with no content)
-        final TextPagerAdapter newAdapter = new TextPagerAdapter();
-        // And set it on the ViewPager
-        onView(withId(R.id.tabs_viewpager)).perform(setAdapter(newAdapter));
-        // As TabLayout doesn't track adapter changes, we need to re-wire the new adapter
-        onView(withId(R.id.tabs)).perform(setupWithViewPager(mViewPager));
-
-        // Set fixed mode on the TabLayout
-        onView(withId(R.id.tabs)).perform(TabLayoutActions.setTabMode(TabLayout.MODE_FIXED));
-        assertEquals("Fixed tab mode", TabLayout.MODE_FIXED, mTabLayout.getTabMode());
-
-        // Add a bunch of tabs and verify that all of them are visible on the screen
-        for (int i = 0; i < 8; i++) {
-            onView(withId(R.id.tabs_viewpager)).perform(addItemToPager("Title " + i, "Body " + i));
-
-            int expectedTabCount = i + 1;
-            assertEquals("Tab count after adding #" + i, expectedTabCount,
-                    mTabLayout.getTabCount());
-            assertEquals("Page count after adding #" + i, expectedTabCount,
-                    mViewPager.getAdapter().getCount());
-
-            verifyViewPagerSelection();
-            verifyTabLayoutSelection();
-
-            // Check that all tabs are fully visible (the content may or may not be elided)
-            for (int j = 0; j < expectedTabCount; j++) {
-                onView(allOf(isDescendantOfA(withId(R.id.tabs)), withText("Title " + j))).
-                        check(matches(isCompletelyDisplayed()));
-            }
-        }
-    }
-
-    /**
-     * Helper method to verify support for min and max tab width on TabLayout in scrollable mode.
-     * It replaces the TabLayout based on the passed layout resource ID and then adds a bunch of
-     * tab titles to the wired ViewPager with progressively longer texts. After each tab is added
-     * this method then checks that all tab views respect the minimum and maximum tab width set
-     * on TabLayout.
-     *
-     * @param tabLayoutResId Layout resource for the TabLayout to be wired to the ViewPager.
-     * @param tabMinWidthResId If non zero, points to the dimension resource to use for tab min
-     * width check.
-     * @param tabMaxWidthResId If non zero, points to the dimension resource to use for tab max
-     * width check.
-     */
-    private void verifyMinMaxTabWidth(@LayoutRes int tabLayoutResId, @DimenRes int tabMinWidthResId,
-            @DimenRes int tabMaxWidthResId) {
-        setupTabLayoutWithViewPager();
-
-        assertEquals("Scrollable tab mode", TabLayout.MODE_SCROLLABLE, mTabLayout.getTabMode());
-
-        final Resources res = mActivityTestRule.getActivity().getResources();
-        final int minTabWidth = (tabMinWidthResId == 0) ? -1 :
-                res.getDimensionPixelSize(tabMinWidthResId);
-        final int maxTabWidth = (tabMaxWidthResId == 0) ? -1 :
-                res.getDimensionPixelSize(tabMaxWidthResId);
-
-        // Create a new adapter (with no content)
-        final TextPagerAdapter newAdapter = new TextPagerAdapter();
-        // And set it on the ViewPager
-        onView(withId(R.id.tabs_viewpager)).perform(setAdapter(newAdapter));
-
-        // Replace the default TabLayout with the passed one
-        onView(withId(R.id.container)).perform(TestUtilsActions.replaceTabLayout(tabLayoutResId));
-
-        // Now that we have a new TabLayout, wire it to the new content of our ViewPager
-        onView(withId(R.id.tabs)).perform(setupWithViewPager(mViewPager));
-
-        // Since TabLayout doesn't expose a getter for fetching the configured max tab width,
-        // start adding a variety of tabs with progressively longer tab titles and test that
-        // no tab is wider than the configured max width. Before we start that test,
-        // verify that we're in the scrollable mode so that each tab title gets as much width
-        // as needed to display its text.
-        assertEquals("Scrollable tab mode", TabLayout.MODE_SCROLLABLE, mTabLayout.getTabMode());
-
-        final StringBuilder tabTitleBuilder = new StringBuilder();
-        for (int i = 0; i < 40; i++) {
-            final char titleComponent = (char) ('A' + i);
-            for (int j = 0; j <= (i + 1); j++) {
-                tabTitleBuilder.append(titleComponent);
-            }
-            final String tabTitle = tabTitleBuilder.toString();
-            onView(withId(R.id.tabs_viewpager)).perform(addItemToPager(tabTitle, "Body " + i));
-
-            int expectedTabCount = i + 1;
-            // Check that all tabs are at least as wide as min width *and* at most as wide as max
-            // width specified in the XML for the newly loaded TabLayout
-            for (int j = 0; j < expectedTabCount; j++) {
-                // Find the view that is our tab title. It should be:
-                // 1. Descendant of our TabLayout
-                // 2. But not a direct child of the horizontal scroller
-                // 3. With just-added title text
-                // These conditions make sure that we're selecting the "top-level" tab view
-                // instead of the inner (and narrower) TextView
-                Matcher<View> tabMatcher = allOf(
-                        isDescendantOfA(withId(R.id.tabs)),
-                        not(withParent(isAssignableFrom(HorizontalScrollView.class))),
-                        hasDescendant(withText(tabTitle)));
-                if (minTabWidth >= 0) {
-                    onView(tabMatcher).check(matches(
-                            TestUtilsMatchers.isNotNarrowerThan(minTabWidth)));
-                }
-                if (maxTabWidth >= 0) {
-                    onView(tabMatcher).check(matches(
-                            TestUtilsMatchers.isNotWiderThan(maxTabWidth)));
-                }
-            }
-
-            // Reset the title builder for the next tab
-            tabTitleBuilder.setLength(0);
-            tabTitleBuilder.trimToSize();
-        }
-
-    }
-
-    @Test
-    @LargeTest
-    public void testMinTabWidth() {
-        verifyMinMaxTabWidth(R.layout.tab_layout_bound_min, R.dimen.tab_width_limit_medium, 0);
-    }
-
-    @Test
-    @LargeTest
-    public void testMaxTabWidth() {
-        verifyMinMaxTabWidth(R.layout.tab_layout_bound_max, 0, R.dimen.tab_width_limit_medium);
-    }
-
-    @Test
-    @LargeTest
-    public void testMinMaxTabWidth() {
-        verifyMinMaxTabWidth(R.layout.tab_layout_bound_minmax, R.dimen.tab_width_limit_small,
-                R.dimen.tab_width_limit_large);
-    }
-
-    @Test
-    @SmallTest
-    public void testSetupAfterViewPagerScrolled() {
-        // Scroll to the last item
-        final int selected = mViewPager.getAdapter().getCount() - 1;
-        onView(withId(R.id.tabs_viewpager)).perform(ViewPagerActions.scrollToPage(selected));
-
-        // Now setup the TabLayout with the ViewPager
-        setupTabLayoutWithViewPager();
-
-        assertEquals("Selected page", selected, mViewPager.getCurrentItem());
-        assertEquals("Selected tab", selected, mTabLayout.getSelectedTabPosition());
-    }
-
-    @Test
-    @SmallTest
-    public void testEmptyAdapter() {
-        ColorPagerAdapter adapter = new ColorPagerAdapter();
-        onView(withId(R.id.tabs_viewpager)).perform(setAdapter(adapter));
-    }
-
-}
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java b/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
deleted file mode 100644
index 613ae6e..0000000
--- a/design/tests/src/android/support/design/widget/TextInputLayoutActivity.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.design.widget;
-
-import android.support.design.test.R;
-
-public class TextInputLayoutActivity extends BaseTestActivity {
-    @Override
-    protected int getContentViewLayoutResId() {
-        return R.layout.design_text_input;
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutPseudoLocaleTest.java b/design/tests/src/android/support/design/widget/TextInputLayoutPseudoLocaleTest.java
deleted file mode 100755
index 9d705db..0000000
--- a/design/tests/src/android/support/design/widget/TextInputLayoutPseudoLocaleTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.test.InstrumentationRegistry.getContext;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.typeText;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.support.design.test.R;
-import android.support.test.filters.MediumTest;
-
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.util.Locale;
-
-@MediumTest
-public class TextInputLayoutPseudoLocaleTest extends
-        BaseInstrumentationTestCase<TextInputLayoutActivity> {
-
-    private static final String ORIGINAL_LANGUAGE = Locale.getDefault().getLanguage();
-    private static final String ORIGINAL_COUNTRY = Locale.getDefault().getLanguage();
-
-    @BeforeClass
-    public static void setup() {
-        // Change language to pseudo locale.
-        setLocale("ar", "XB", getContext());
-    }
-
-    public TextInputLayoutPseudoLocaleTest() {
-        super(TextInputLayoutActivity.class);
-    }
-
-    private static void setLocale(String language,  String country,  Context context) {
-        context = context.getApplicationContext();
-        Resources resources = context.getResources();
-        Configuration configuration = resources.getConfiguration();
-        configuration.setLocale(new Locale(language, country));
-        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
-    }
-
-    @Test
-    public void testSimpleEdit() {
-        // Type some text
-        onView(withId(R.id.textinput_edittext)).perform(typeText("123"));
-    }
-
-    @AfterClass
-    public static void  cleanup() {
-        setLocale(ORIGINAL_LANGUAGE, ORIGINAL_COUNTRY, getContext());
-    }
-}
diff --git a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java b/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
deleted file mode 100755
index 5969235..0000000
--- a/design/tests/src/android/support/design/widget/TextInputLayoutTest.java
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.design.widget;
-
-import static android.support.design.testutils.TestUtilsActions.setCompoundDrawablesRelative;
-import static android.support.design.testutils.TestUtilsActions.setEnabled;
-import static android.support.design.testutils.TestUtilsMatchers.withCompoundDrawable;
-import static android.support.design.testutils.TestUtilsMatchers.withTextColor;
-import static android.support.design.testutils.TestUtilsMatchers.withTypeface;
-import static android.support.design.testutils.TextInputLayoutActions.clickPasswordToggle;
-import static android.support.design.testutils.TextInputLayoutActions.setCounterEnabled;
-import static android.support.design.testutils.TextInputLayoutActions.setCounterMaxLength;
-import static android.support.design.testutils.TextInputLayoutActions.setError;
-import static android.support.design.testutils.TextInputLayoutActions.setErrorEnabled;
-import static android.support.design.testutils.TextInputLayoutActions.setErrorTextAppearance;
-import static android.support.design.testutils.TextInputLayoutActions
-        .setPasswordVisibilityToggleEnabled;
-import static android.support.design.testutils.TextInputLayoutActions.setTypeface;
-import static android.support.design.testutils.TextInputLayoutMatchers.doesNotShowPasswordToggle;
-import static android.support.design.testutils.TextInputLayoutMatchers
-        .passwordToggleHasContentDescription;
-import static android.support.design.testutils.TextInputLayoutMatchers.passwordToggleIsNotChecked;
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.action.ViewActions.typeText;
-import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.contrib.AccessibilityChecks.accessibilityAssertion;
-import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
-import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.core.AllOf.allOf;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.Typeface;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Parcelable;
-import android.support.design.test.R;
-import android.support.design.testutils.TestUtils;
-import android.support.design.testutils.ViewStructureImpl;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.espresso.NoMatchingViewException;
-import android.support.test.espresso.ViewAssertion;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.testutils.AppCompatActivityUtils;
-import android.support.testutils.RecreatedAppCompatActivity;
-import android.support.v4.widget.TextViewCompat;
-import android.text.method.PasswordTransformationMethod;
-import android.text.method.TransformationMethod;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.widget.EditText;
-
-import org.junit.Test;
-
-@MediumTest
-public class TextInputLayoutTest extends BaseInstrumentationTestCase<TextInputLayoutActivity> {
-
-    private static final String ERROR_MESSAGE_1 = "An error has occured";
-    private static final String ERROR_MESSAGE_2 = "Some other error has occured";
-
-    private static final String INPUT_TEXT = "Random input text";
-
-    private static final Typeface CUSTOM_TYPEFACE = Typeface.SANS_SERIF;
-
-    public class TestTextInputLayout extends TextInputLayout {
-        public int animateToExpansionFractionCount = 0;
-        public float animateToExpansionFractionRecentValue = -1;
-
-        public TestTextInputLayout(Context context) {
-            super(context);
-        }
-
-        public TestTextInputLayout(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public TestTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
-            super(context, attrs, defStyleAttr);
-        }
-
-        @Override
-        protected void animateToExpansionFraction(float target) {
-            super.animateToExpansionFraction(target);
-            animateToExpansionFractionRecentValue = target;
-            animateToExpansionFractionCount++;
-        }
-    }
-
-    public TextInputLayoutTest() {
-        super(TextInputLayoutActivity.class);
-    }
-
-    @Test
-    public void testTypingTextCollapsesHint() {
-        // Type some text
-        onView(withId(R.id.textinput_edittext)).perform(typeText(INPUT_TEXT));
-        // ...and check that the hint has collapsed
-        onView(withId(R.id.textinput)).check(isHintExpanded(false));
-    }
-
-    @Test
-    public void testSetErrorEnablesErrorIsDisplayed() {
-        onView(withId(R.id.textinput)).perform(setError(ERROR_MESSAGE_1));
-        onView(withText(ERROR_MESSAGE_1)).check(matches(isDisplayed()));
-    }
-
-    @Test
-    public void testDisabledErrorIsNotDisplayed() {
-        // First show an error, and then disable error functionality
-        onView(withId(R.id.textinput))
-                .perform(setError(ERROR_MESSAGE_1))
-                .perform(setErrorEnabled(false));
-
-        // Check that the error is no longer there
-        onView(withText(ERROR_MESSAGE_1)).check(doesNotExist());
-    }
-
-    @Test
-    public void testSetErrorOnDisabledSetErrorIsDisplayed() {
-        // First show an error, and then disable error functionality
-        onView(withId(R.id.textinput))
-                .perform(setError(ERROR_MESSAGE_1))
-                .perform(setErrorEnabled(false));
-
-        // Now show a different error message
-        onView(withId(R.id.textinput)).perform(setError(ERROR_MESSAGE_2));
-        // And check that it is displayed
-        onView(withText(ERROR_MESSAGE_2)).check(matches(isDisplayed()));
-    }
-
-    @Test
-    public void testPasswordToggleClick() {
-        // Type some text on the EditText
-        onView(withId(R.id.textinput_edittext_pwd)).perform(typeText(INPUT_TEXT));
-
-        final Activity activity = mActivityTestRule.getActivity();
-        final EditText textInput = (EditText) activity.findViewById(R.id.textinput_edittext_pwd);
-
-        // Assert that the password is disguised
-        assertNotEquals(INPUT_TEXT, textInput.getLayout().getText().toString());
-
-        // Now click the toggle button
-        onView(withId(R.id.textinput_password)).perform(clickPasswordToggle());
-
-        // And assert that the password is not disguised
-        assertEquals(INPUT_TEXT, textInput.getLayout().getText().toString());
-    }
-
-    @Test
-    public void testPasswordToggleDisable() {
-        final Activity activity = mActivityTestRule.getActivity();
-        final EditText textInput = (EditText) activity.findViewById(R.id.textinput_edittext_pwd);
-
-        // Set some text on the EditText
-        onView(withId(R.id.textinput_edittext_pwd))
-                .perform(typeText(INPUT_TEXT));
-        // Assert that the password is disguised
-        assertNotEquals(INPUT_TEXT, textInput.getLayout().getText().toString());
-
-        // Disable the password toggle
-        onView(withId(R.id.textinput_password))
-                .perform(setPasswordVisibilityToggleEnabled(false));
-
-        // Check that the password toggle view is not visible
-        onView(withId(R.id.textinput_password)).check(matches(doesNotShowPasswordToggle()));
-        // ...and that the password is disguised still
-        assertNotEquals(INPUT_TEXT, textInput.getLayout().getText().toString());
-    }
-
-    @Test
-    public void testPasswordToggleDisableWhenVisible() {
-        final Activity activity = mActivityTestRule.getActivity();
-        final EditText textInput = (EditText) activity.findViewById(R.id.textinput_edittext_pwd);
-
-        // Type some text on the EditText
-        onView(withId(R.id.textinput_edittext_pwd)).perform(typeText(INPUT_TEXT));
-        // Assert that the password is disguised
-        assertNotEquals(INPUT_TEXT, textInput.getLayout().getText().toString());
-
-        // Now click the toggle button
-        onView(withId(R.id.textinput_password)).perform(clickPasswordToggle());
-        // Disable the password toggle
-        onView(withId(R.id.textinput_password))
-                .perform(setPasswordVisibilityToggleEnabled(false));
-
-        // Check that the password is disguised again
-        assertNotEquals(INPUT_TEXT, textInput.getLayout().getText().toString());
-    }
-
-    @Test
-    public void testPasswordToggleMaintainsCompoundDrawables() {
-        // Set a known set of test compound drawables on the EditText
-        final Drawable start = new ColorDrawable(Color.RED);
-        final Drawable top = new ColorDrawable(Color.GREEN);
-        final Drawable end = new ColorDrawable(Color.BLUE);
-        final Drawable bottom = new ColorDrawable(Color.BLACK);
-        onView(withId(R.id.textinput_edittext_pwd))
-                .perform(setCompoundDrawablesRelative(start, top, end, bottom));
-
-        // Enable the password toggle and check that the start, top and bottom drawables are
-        // maintained
-        onView(withId(R.id.textinput_password))
-                .perform(setPasswordVisibilityToggleEnabled(true));
-        onView(withId(R.id.textinput_edittext_pwd))
-                .check(matches(withCompoundDrawable(0, start)))
-                .check(matches(withCompoundDrawable(1, top)))
-                .check(matches(not(withCompoundDrawable(2, end))))
-                .check(matches(withCompoundDrawable(3, bottom)));
-
-        // Now disable the password toggle and check that all of the original compound drawables
-        // are set
-        onView(withId(R.id.textinput_password))
-                .perform(setPasswordVisibilityToggleEnabled(false));
-        onView(withId(R.id.textinput_edittext_pwd))
-                .check(matches(withCompoundDrawable(0, start)))
-                .check(matches(withCompoundDrawable(1, top)))
-                .check(matches(withCompoundDrawable(2, end)))
-                .check(matches(withCompoundDrawable(3, bottom)));
-    }
-
-    @Test
-    public void testPasswordToggleIsHiddenAfterReenable() {
-        final Activity activity = mActivityTestRule.getActivity();
-        final EditText textInput = (EditText) activity.findViewById(R.id.textinput_edittext_pwd);
-
-        // Type some text on the EditText and then click the toggle button
-        onView(withId(R.id.textinput_edittext_pwd)).perform(typeText(INPUT_TEXT));
-        onView(withId(R.id.textinput_password)).perform(clickPasswordToggle());
-
-        // Disable the password toggle, and then re-enable it
-        onView(withId(R.id.textinput_password))
-                .perform(setPasswordVisibilityToggleEnabled(false))
-                .perform(setPasswordVisibilityToggleEnabled(true));
-
-        // Check that the password is disguised and the toggle button reflects the same state
-        assertNotEquals(INPUT_TEXT, textInput.getLayout().getText().toString());
-        onView(withId(R.id.textinput_password)).check(matches(passwordToggleIsNotChecked()));
-    }
-
-    @Test
-    public void testSetEnabledFalse() {
-        // First click on the EditText, so that it is focused and the hint collapses...
-        onView(withId(R.id.textinput_edittext)).perform(click());
-
-        // Now disable the TextInputLayout and check that the hint expands
-        onView(withId(R.id.textinput))
-                .perform(setEnabled(false))
-                .check(isHintExpanded(true));
-
-        // Finally check that the EditText is no longer enabled
-        onView(withId(R.id.textinput_edittext)).check(matches(not(isEnabled())));
-    }
-
-    @Test
-    public void testSetEnabledFalseWithText() {
-        // First set some text, then disable the TextInputLayout
-        onView(withId(R.id.textinput_edittext))
-                .perform(typeText(INPUT_TEXT));
-        onView(withId(R.id.textinput)).perform(setEnabled(false));
-
-        // Now check that the EditText is no longer enabled
-        onView(withId(R.id.textinput_edittext)).check(matches(not(isEnabled())));
-    }
-
-    @UiThreadTest
-    @Test
-    public void testExtractUiHintSet() {
-        final Activity activity = mActivityTestRule.getActivity();
-
-        // Set a hint on the TextInputLayout
-        final TextInputLayout layout = (TextInputLayout) activity.findViewById(R.id.textinput);
-        layout.setHint(INPUT_TEXT);
-
-        final EditText editText = (EditText) activity.findViewById(R.id.textinput_edittext);
-
-        // Now manually pass in a EditorInfo to the EditText and make sure it updates the
-        // hintText to our known value
-        final EditorInfo info = new EditorInfo();
-        editText.onCreateInputConnection(info);
-
-        assertEquals(INPUT_TEXT, info.hintText);
-    }
-
-    @UiThreadTest
-    @Test
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
-    public void testDispatchProvideAutofillStructure() {
-        final Activity activity = mActivityTestRule.getActivity();
-
-        final TextInputLayout layout = activity.findViewById(R.id.textinput);
-
-        final ViewStructureImpl structure = new ViewStructureImpl();
-        layout.dispatchProvideAutofillStructure(structure, 0);
-
-        assertEquals(2, structure.getChildCount()); // EditText and TextView
-
-        // Asserts the structure.
-        final ViewStructureImpl childStructure = structure.getChildAt(0);
-        assertEquals(EditText.class.getName(), childStructure.getClassName());
-        assertEquals("Hint to the user", childStructure.getHint());
-
-        // Make sure the widget's hint was restored.
-        assertEquals("Hint to the user", layout.getHint());
-        final EditText editText = activity.findViewById(R.id.textinput_edittext);
-        assertNull(editText.getHint());
-    }
-
-    /**
-     * Regression test for b/31663756.
-     */
-    @UiThreadTest
-    @Test
-    public void testDrawableStateChanged() {
-        final Activity activity = mActivityTestRule.getActivity();
-        final TextInputLayout layout = (TextInputLayout) activity.findViewById(R.id.textinput);
-
-        // Force a drawable state change.
-        layout.drawableStateChanged();
-    }
-
-    @UiThreadTest
-    @Test
-    public void testSaveRestoreStateAnimation() {
-        final Activity activity = mActivityTestRule.getActivity();
-        final TestTextInputLayout layout = new TestTextInputLayout(activity);
-        layout.setId(R.id.textinputlayout);
-        final TextInputEditText editText = new TextInputEditText(activity);
-        editText.setText(INPUT_TEXT);
-        editText.setId(R.id.textinputedittext);
-        layout.addView(editText);
-
-        SparseArray<Parcelable> container = new SparseArray<>();
-        layout.saveHierarchyState(container);
-        layout.restoreHierarchyState(container);
-        assertEquals("Expected no animations since we simply saved/restored state",
-                0, layout.animateToExpansionFractionCount);
-
-        editText.setText("");
-        assertEquals("Expected one call to animate because we cleared text in editText",
-                1, layout.animateToExpansionFractionCount);
-        assertEquals(0f, layout.animateToExpansionFractionRecentValue, 0f);
-
-        container = new SparseArray<>();
-        layout.saveHierarchyState(container);
-        layout.restoreHierarchyState(container);
-        assertEquals("Expected no additional animations since we simply saved/restored state",
-                1, layout.animateToExpansionFractionCount);
-    }
-
-    @UiThreadTest
-    @Test
-    public void testMaintainsLeftRightCompoundDrawables() throws Throwable {
-        final Activity activity = mActivityTestRule.getActivity();
-
-        // Set a known set of test compound drawables on the EditText
-        final Drawable left = new ColorDrawable(Color.RED);
-        final Drawable top = new ColorDrawable(Color.GREEN);
-        final Drawable right = new ColorDrawable(Color.BLUE);
-        final Drawable bottom = new ColorDrawable(Color.BLACK);
-
-        final TextInputEditText editText = new TextInputEditText(activity);
-        editText.setCompoundDrawables(left, top, right, bottom);
-
-        // Now add the EditText to a TextInputLayout
-        TextInputLayout til = (TextInputLayout)
-                activity.findViewById(R.id.textinput_noedittext);
-        til.addView(editText);
-
-        // Finally assert that all of the drawables are untouched
-        final Drawable[] compoundDrawables = editText.getCompoundDrawables();
-        assertSame(left, compoundDrawables[0]);
-        assertSame(top, compoundDrawables[1]);
-        assertSame(right, compoundDrawables[2]);
-        assertSame(bottom, compoundDrawables[3]);
-    }
-
-    @UiThreadTest
-    @Test
-    public void testMaintainsStartEndCompoundDrawables() throws Throwable {
-        final Activity activity = mActivityTestRule.getActivity();
-
-        // Set a known set of test compound drawables on the EditText
-        final Drawable start = new ColorDrawable(Color.RED);
-        final Drawable top = new ColorDrawable(Color.GREEN);
-        final Drawable end = new ColorDrawable(Color.BLUE);
-        final Drawable bottom = new ColorDrawable(Color.BLACK);
-
-        final TextInputEditText editText = new TextInputEditText(activity);
-        TextViewCompat.setCompoundDrawablesRelative(editText, start, top, end, bottom);
-
-        // Now add the EditText to a TextInputLayout
-        TextInputLayout til = (TextInputLayout)
-                activity.findViewById(R.id.textinput_noedittext);
-        til.addView(editText);
-
-        // Finally assert that all of the drawables are untouched
-        final Drawable[] compoundDrawables = TextViewCompat.getCompoundDrawablesRelative(editText);
-        assertSame(start, compoundDrawables[0]);
-        assertSame(top, compoundDrawables[1]);
-        assertSame(end, compoundDrawables[2]);
-        assertSame(bottom, compoundDrawables[3]);
-    }
-
-    @Test
-    public void testPasswordToggleHasDefaultContentDescription() {
-        // Check that the TextInputLayout says that it has a content description and that the
-        // underlying toggle has content description as well
-        onView(withId(R.id.textinput_password))
-                .check(matches(passwordToggleHasContentDescription()));
-    }
-
-    /**
-     * Simple test that uses AccessibilityChecks to check that the password toggle icon is
-     * 'accessible'.
-     */
-    @Test
-    public void testPasswordToggleIsAccessible() {
-        onView(allOf(withId(R.id.text_input_password_toggle),
-                isDescendantOfA(withId(R.id.textinput_password)))).check(accessibilityAssertion());
-    }
-
-    @Test
-    public void testSetTypefaceUpdatesErrorView() {
-        onView(withId(R.id.textinput))
-                .perform(setErrorEnabled(true))
-                .perform(setError(ERROR_MESSAGE_1))
-                .perform(setTypeface(CUSTOM_TYPEFACE));
-
-        // Check that the error message is updated
-        onView(withText(ERROR_MESSAGE_1))
-                .check(matches(withTypeface(CUSTOM_TYPEFACE)));
-    }
-
-    @Test
-    public void testSetTypefaceUpdatesCharacterCountView() {
-        // Turn on character counting
-        onView(withId(R.id.textinput))
-                .perform(setCounterEnabled(true), setCounterMaxLength(10))
-                .perform(setTypeface(CUSTOM_TYPEFACE));
-
-        // Check that the counter message is updated
-        onView(withId(R.id.textinput_counter))
-                .check(matches(withTypeface(CUSTOM_TYPEFACE)));
-    }
-
-    @Test
-    public void testThemedColorStateListForErrorTextColor() {
-        final Activity activity = mActivityTestRule.getActivity();
-        final int textColor = TestUtils.getThemeAttrColor(activity, R.attr.colorAccent);
-
-        onView(withId(R.id.textinput))
-                .perform(setErrorEnabled(true))
-                .perform(setError(ERROR_MESSAGE_1))
-                .perform(setErrorTextAppearance(R.style.TextAppearanceWithThemedCslTextColor));
-
-        onView(withText(ERROR_MESSAGE_1))
-                .check(matches(withTextColor(textColor)));
-    }
-
-    @Test
-    public void testTextSetViaAttributeCollapsedHint() {
-        onView(withId(R.id.textinput_with_text)).check(isHintExpanded(false));
-    }
-
-    @Test
-    public void testFocusMovesToEditTextWithPasswordEnabled() {
-        // Focus the preceding EditText
-        onView(withId(R.id.textinput_edittext))
-                .perform(click())
-                .check(matches(hasFocus()));
-
-        // Then send a TAB to focus the next view
-        getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_TAB);
-
-        // And check that the EditText is focused
-        onView(withId(R.id.textinput_edittext_pwd))
-                .check(matches(hasFocus()));
-    }
-
-    @Test
-    @LargeTest
-    public void testSaveAndRestorePasswordVisibility() throws Throwable {
-        // Type some text on the EditText
-        onView(withId(R.id.textinput_edittext_pwd)).perform(typeText(INPUT_TEXT));
-        onView(withId(R.id.textinput_password)).check(isPasswordToggledVisible(false));
-
-        // Toggle password to be shown as plain text
-        onView(withId(R.id.textinput_password)).perform(clickPasswordToggle());
-        onView(withId(R.id.textinput_password)).check(isPasswordToggledVisible(true));
-
-        RecreatedAppCompatActivity activity = mActivityTestRule.getActivity();
-        AppCompatActivityUtils.recreateActivity(mActivityTestRule, activity);
-        AppCompatActivityUtils.waitForExecution(mActivityTestRule);
-
-        // Check that the password is still toggled to be shown as plain text
-        onView(withId(R.id.textinput_password)).check(isPasswordToggledVisible(true));
-    }
-
-    static ViewAssertion isHintExpanded(final boolean expanded) {
-        return new ViewAssertion() {
-            @Override
-            public void check(View view, NoMatchingViewException noViewFoundException) {
-                assertTrue(view instanceof TextInputLayout);
-                assertEquals(expanded, ((TextInputLayout) view).isHintExpanded());
-            }
-        };
-    }
-
-    static ViewAssertion isPasswordToggledVisible(final boolean isToggledVisible) {
-        return new ViewAssertion() {
-            @Override
-            public void check(View view, NoMatchingViewException noViewFoundException) {
-                assertTrue(view instanceof TextInputLayout);
-                EditText editText = ((TextInputLayout) view).getEditText();
-                TransformationMethod transformationMethod = editText.getTransformationMethod();
-                if (isToggledVisible) {
-                    assertNull(transformationMethod);
-                } else {
-                    assertEquals(PasswordTransformationMethod.getInstance(), transformationMethod);
-                }
-            }
-        };
-    }
-}
diff --git a/design/tests/src/android/support/test/rule/BootlegActivityTestRule.java b/design/tests/src/android/support/test/rule/BootlegActivityTestRule.java
deleted file mode 100644
index b12edfa..0000000
--- a/design/tests/src/android/support/test/rule/BootlegActivityTestRule.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.test.rule;
-
-import android.app.Activity;
-import android.support.annotation.NonNull;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.intercepting.SingleActivityFactory;
-
-/**
- * An extension of existing {@link ActivityTestRule} that contains a fix for finishActivity()
- * method (cr/138555678).
- *
- * Remove this once we move to Android Test Runner 0.7.
- */
-public class BootlegActivityTestRule<T extends Activity> extends ActivityTestRule {
-    public BootlegActivityTestRule(Class activityClass) {
-        super(activityClass);
-    }
-
-    public BootlegActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
-        super(activityClass, initialTouchMode);
-    }
-
-    public BootlegActivityTestRule(Class<T> activityClass, boolean initialTouchMode,
-            boolean launchActivity) {
-        super(activityClass, initialTouchMode, launchActivity);
-    }
-
-    public BootlegActivityTestRule(
-            SingleActivityFactory activityFactory,
-            boolean initialTouchMode, boolean launchActivity) {
-        super(activityFactory, initialTouchMode, launchActivity);
-    }
-
-    public BootlegActivityTestRule(Class<T> activityClass,
-            @NonNull String targetPackage, int launchFlags,
-            boolean initialTouchMode, boolean launchActivity) {
-        super(activityClass, targetPackage, launchFlags, initialTouchMode, launchActivity);
-    }
-
-    @Override
-    public void finishActivity() {
-        super.finishActivity();
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-    }
-
-    @Override
-    public T getActivity() {
-        return (T) super.getActivity();
-    }
-}
diff --git a/samples/SupportTransitionDemos/proguard.flags b/development/unbundled-build
similarity index 100%
rename from samples/SupportTransitionDemos/proguard.flags
rename to development/unbundled-build
diff --git a/documentfile/api/current.txt b/documentfile/api/current.txt
new file mode 100644
index 0000000..6d7790b
--- /dev/null
+++ b/documentfile/api/current.txt
@@ -0,0 +1,29 @@
+package android.support.v4.provider {
+
+  public abstract class DocumentFile {
+    method public abstract boolean canRead();
+    method public abstract boolean canWrite();
+    method public abstract android.support.v4.provider.DocumentFile createDirectory(java.lang.String);
+    method public abstract android.support.v4.provider.DocumentFile createFile(java.lang.String, java.lang.String);
+    method public abstract boolean delete();
+    method public abstract boolean exists();
+    method public android.support.v4.provider.DocumentFile findFile(java.lang.String);
+    method public static android.support.v4.provider.DocumentFile fromFile(java.io.File);
+    method public static android.support.v4.provider.DocumentFile fromSingleUri(android.content.Context, android.net.Uri);
+    method public static android.support.v4.provider.DocumentFile fromTreeUri(android.content.Context, android.net.Uri);
+    method public abstract java.lang.String getName();
+    method public android.support.v4.provider.DocumentFile getParentFile();
+    method public abstract java.lang.String getType();
+    method public abstract android.net.Uri getUri();
+    method public abstract boolean isDirectory();
+    method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public abstract boolean isFile();
+    method public abstract boolean isVirtual();
+    method public abstract long lastModified();
+    method public abstract long length();
+    method public abstract android.support.v4.provider.DocumentFile[] listFiles();
+    method public abstract boolean renameTo(java.lang.String);
+  }
+
+}
+
diff --git a/documentfile/build.gradle b/documentfile/build.gradle
new file mode 100644
index 0000000..2f59518
--- /dev/null
+++ b/documentfile/build.gradle
@@ -0,0 +1,19 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+}
+
+supportLibrary {
+    name = "Android Support Library Document File"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/documentfile/src/main/AndroidManifest.xml b/documentfile/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7602dd7
--- /dev/null
+++ b/documentfile/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.documentfile"/>
diff --git a/core-utils/java/android/support/v4/provider/DocumentFile.java b/documentfile/src/main/java/android/support/v4/provider/DocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/DocumentFile.java
rename to documentfile/src/main/java/android/support/v4/provider/DocumentFile.java
diff --git a/core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java b/documentfile/src/main/java/android/support/v4/provider/DocumentsContractApi19.java
similarity index 100%
rename from core-utils/kitkat/android/support/v4/provider/DocumentsContractApi19.java
rename to documentfile/src/main/java/android/support/v4/provider/DocumentsContractApi19.java
diff --git a/core-utils/java/android/support/v4/provider/RawDocumentFile.java b/documentfile/src/main/java/android/support/v4/provider/RawDocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/RawDocumentFile.java
rename to documentfile/src/main/java/android/support/v4/provider/RawDocumentFile.java
diff --git a/core-utils/java/android/support/v4/provider/SingleDocumentFile.java b/documentfile/src/main/java/android/support/v4/provider/SingleDocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/SingleDocumentFile.java
rename to documentfile/src/main/java/android/support/v4/provider/SingleDocumentFile.java
diff --git a/core-utils/java/android/support/v4/provider/TreeDocumentFile.java b/documentfile/src/main/java/android/support/v4/provider/TreeDocumentFile.java
similarity index 100%
rename from core-utils/java/android/support/v4/provider/TreeDocumentFile.java
rename to documentfile/src/main/java/android/support/v4/provider/TreeDocumentFile.java
diff --git a/drawerlayout/api/current.txt b/drawerlayout/api/current.txt
new file mode 100644
index 0000000..c1a0b4c
--- /dev/null
+++ b/drawerlayout/api/current.txt
@@ -0,0 +1,81 @@
+package android.support.v4.widget {
+
+  public class DrawerLayout extends android.view.ViewGroup {
+    ctor public DrawerLayout(android.content.Context);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void addDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void closeDrawer(android.view.View);
+    method public void closeDrawer(android.view.View, boolean);
+    method public void closeDrawer(int);
+    method public void closeDrawer(int, boolean);
+    method public void closeDrawers();
+    method public float getDrawerElevation();
+    method public int getDrawerLockMode(int);
+    method public int getDrawerLockMode(android.view.View);
+    method public java.lang.CharSequence getDrawerTitle(int);
+    method public android.graphics.drawable.Drawable getStatusBarBackgroundDrawable();
+    method public boolean isDrawerOpen(android.view.View);
+    method public boolean isDrawerOpen(int);
+    method public boolean isDrawerVisible(android.view.View);
+    method public boolean isDrawerVisible(int);
+    method public void onDraw(android.graphics.Canvas);
+    method public void openDrawer(android.view.View);
+    method public void openDrawer(android.view.View, boolean);
+    method public void openDrawer(int);
+    method public void openDrawer(int, boolean);
+    method public void removeDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void setDrawerElevation(float);
+    method public deprecated void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void setDrawerLockMode(int);
+    method public void setDrawerLockMode(int, int);
+    method public void setDrawerLockMode(int, android.view.View);
+    method public void setDrawerShadow(android.graphics.drawable.Drawable, int);
+    method public void setDrawerShadow(int, int);
+    method public void setDrawerTitle(int, java.lang.CharSequence);
+    method public void setScrimColor(int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackground(int);
+    method public void setStatusBarBackgroundColor(int);
+    field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
+    field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+    field public static final int LOCK_MODE_UNDEFINED = 3; // 0x3
+    field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract interface DrawerLayout.DrawerListener {
+    method public abstract void onDrawerClosed(android.view.View);
+    method public abstract void onDrawerOpened(android.view.View);
+    method public abstract void onDrawerSlide(android.view.View, float);
+    method public abstract void onDrawerStateChanged(int);
+  }
+
+  public static class DrawerLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public DrawerLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout.LayoutParams(int, int);
+    ctor public DrawerLayout.LayoutParams(int, int, int);
+    ctor public DrawerLayout.LayoutParams(android.support.v4.widget.DrawerLayout.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    field public int gravity;
+  }
+
+  protected static class DrawerLayout.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public DrawerLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public DrawerLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.widget.DrawerLayout.SavedState> CREATOR;
+  }
+
+  public static abstract class DrawerLayout.SimpleDrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public DrawerLayout.SimpleDrawerListener();
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+  }
+
+}
+
diff --git a/drawerlayout/build.gradle b/drawerlayout/build.gradle
new file mode 100644
index 0000000..1d1476b
--- /dev/null
+++ b/drawerlayout/build.gradle
@@ -0,0 +1,21 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+    api(project(":customview"))
+}
+
+supportLibrary {
+    name = "Android Support Library Drawer Layout"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/drawerlayout/src/main/AndroidManifest.xml b/drawerlayout/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..154538c
--- /dev/null
+++ b/drawerlayout/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.drawerlayout"/>
diff --git a/drawerlayout/src/main/java/android/support/v4/widget/DrawerLayout.java b/drawerlayout/src/main/java/android/support/v4/widget/DrawerLayout.java
new file mode 100644
index 0000000..66104ea
--- /dev/null
+++ b/drawerlayout/src/main/java/android/support/v4/widget/DrawerLayout.java
@@ -0,0 +1,2386 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.support.v4.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.support.annotation.ColorInt;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.view.AbsSavedState;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.WindowInsets;
+import android.view.accessibility.AccessibilityEvent;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * DrawerLayout acts as a top-level container for window content that allows for
+ * interactive "drawer" views to be pulled out from one or both vertical edges of the window.
+ *
+ * <p>Drawer positioning and layout is controlled using the <code>android:layout_gravity</code>
+ * attribute on child views corresponding to which side of the view you want the drawer
+ * to emerge from: left or right (or start/end on platform versions that support layout direction.)
+ * Note that you can only have one drawer view for each vertical edge of the window. If your
+ * layout configures more than one drawer view per vertical edge of the window, an exception will
+ * be thrown at runtime.
+ * </p>
+ *
+ * <p>To use a DrawerLayout, position your primary content view as the first child with
+ * width and height of <code>match_parent</code> and no <code>layout_gravity></code>.
+ * Add drawers as child views after the main content view and set the <code>layout_gravity</code>
+ * appropriately. Drawers commonly use <code>match_parent</code> for height with a fixed width.</p>
+ *
+ * <p>{@link DrawerListener} can be used to monitor the state and motion of drawer views.
+ * Avoid performing expensive operations such as layout during animation as it can cause
+ * stuttering; try to perform expensive operations during the {@link #STATE_IDLE} state.
+ * {@link SimpleDrawerListener} offers default/no-op implementations of each callback method.</p>
+ *
+ * <p>As per the <a href="{@docRoot}design/patterns/navigation-drawer.html">Android Design
+ * guide</a>, any drawers positioned to the left/start should
+ * always contain content for navigating around the application, whereas any drawers
+ * positioned to the right/end should always contain actions to take on the current content.
+ * This preserves the same navigation left, actions right structure present in the Action Bar
+ * and elsewhere.</p>
+ *
+ * <p>For more information about how to use DrawerLayout, read <a
+ * href="{@docRoot}training/implementing-navigation/nav-drawer.html">Creating a Navigation
+ * Drawer</a>.</p>
+ */
+public class DrawerLayout extends ViewGroup {
+    private static final String TAG = "DrawerLayout";
+
+    private static final int[] THEME_ATTRS = {
+            android.R.attr.colorPrimaryDark
+    };
+
+    @IntDef({STATE_IDLE, STATE_DRAGGING, STATE_SETTLING})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface State {}
+
+    /**
+     * Indicates that any drawers are in an idle, settled state. No animation is in progress.
+     */
+    public static final int STATE_IDLE = ViewDragHelper.STATE_IDLE;
+
+    /**
+     * Indicates that a drawer is currently being dragged by the user.
+     */
+    public static final int STATE_DRAGGING = ViewDragHelper.STATE_DRAGGING;
+
+    /**
+     * Indicates that a drawer is in the process of settling to a final position.
+     */
+    public static final int STATE_SETTLING = ViewDragHelper.STATE_SETTLING;
+
+    @IntDef({LOCK_MODE_UNLOCKED, LOCK_MODE_LOCKED_CLOSED, LOCK_MODE_LOCKED_OPEN,
+            LOCK_MODE_UNDEFINED})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface LockMode {}
+
+    /**
+     * The drawer is unlocked.
+     */
+    public static final int LOCK_MODE_UNLOCKED = 0;
+
+    /**
+     * The drawer is locked closed. The user may not open it, though
+     * the app may open it programmatically.
+     */
+    public static final int LOCK_MODE_LOCKED_CLOSED = 1;
+
+    /**
+     * The drawer is locked open. The user may not close it, though the app
+     * may close it programmatically.
+     */
+    public static final int LOCK_MODE_LOCKED_OPEN = 2;
+
+    /**
+     * The drawer's lock state is reset to default.
+     */
+    public static final int LOCK_MODE_UNDEFINED = 3;
+
+    @IntDef(value = {Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END},
+            flag = true)
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface EdgeGravity {}
+
+
+    private static final int MIN_DRAWER_MARGIN = 64; // dp
+    private static final int DRAWER_ELEVATION = 10; //dp
+
+    private static final int DEFAULT_SCRIM_COLOR = 0x99000000;
+
+    /**
+     * Length of time to delay before peeking the drawer.
+     */
+    private static final int PEEK_DELAY = 160; // ms
+
+    /**
+     * Minimum velocity that will be detected as a fling
+     */
+    private static final int MIN_FLING_VELOCITY = 400; // dips per second
+
+    /**
+     * Experimental feature.
+     */
+    private static final boolean ALLOW_EDGE_LOCK = false;
+
+    private static final boolean CHILDREN_DISALLOW_INTERCEPT = true;
+
+    private static final float TOUCH_SLOP_SENSITIVITY = 1.f;
+
+    static final int[] LAYOUT_ATTRS = new int[] {
+            android.R.attr.layout_gravity
+    };
+
+    /** Whether we can use NO_HIDE_DESCENDANTS accessibility importance. */
+    static final boolean CAN_HIDE_DESCENDANTS = Build.VERSION.SDK_INT >= 19;
+
+    /** Whether the drawer shadow comes from setting elevation on the drawer. */
+    private static final boolean SET_DRAWER_SHADOW_FROM_ELEVATION =
+            Build.VERSION.SDK_INT >= 21;
+
+    private final ChildAccessibilityDelegate mChildAccessibilityDelegate =
+            new ChildAccessibilityDelegate();
+    private float mDrawerElevation;
+
+    private int mMinDrawerMargin;
+
+    private int mScrimColor = DEFAULT_SCRIM_COLOR;
+    private float mScrimOpacity;
+    private Paint mScrimPaint = new Paint();
+
+    private final ViewDragHelper mLeftDragger;
+    private final ViewDragHelper mRightDragger;
+    private final ViewDragCallback mLeftCallback;
+    private final ViewDragCallback mRightCallback;
+    private int mDrawerState;
+    private boolean mInLayout;
+    private boolean mFirstLayout = true;
+
+    private @LockMode int mLockModeLeft = LOCK_MODE_UNDEFINED;
+    private @LockMode int mLockModeRight = LOCK_MODE_UNDEFINED;
+    private @LockMode int mLockModeStart = LOCK_MODE_UNDEFINED;
+    private @LockMode int mLockModeEnd = LOCK_MODE_UNDEFINED;
+
+    private boolean mDisallowInterceptRequested;
+    private boolean mChildrenCanceledTouch;
+
+    private @Nullable DrawerListener mListener;
+    private List<DrawerListener> mListeners;
+
+    private float mInitialMotionX;
+    private float mInitialMotionY;
+
+    private Drawable mStatusBarBackground;
+    private Drawable mShadowLeftResolved;
+    private Drawable mShadowRightResolved;
+
+    private CharSequence mTitleLeft;
+    private CharSequence mTitleRight;
+
+    private Object mLastInsets;
+    private boolean mDrawStatusBarBackground;
+
+    /** Shadow drawables for different gravity */
+    private Drawable mShadowStart = null;
+    private Drawable mShadowEnd = null;
+    private Drawable mShadowLeft = null;
+    private Drawable mShadowRight = null;
+
+    private final ArrayList<View> mNonDrawerViews;
+
+    /**
+     * Listener for monitoring events about drawers.
+     */
+    public interface DrawerListener {
+        /**
+         * Called when a drawer's position changes.
+         * @param drawerView The child view that was moved
+         * @param slideOffset The new offset of this drawer within its range, from 0-1
+         */
+        void onDrawerSlide(@NonNull View drawerView, float slideOffset);
+
+        /**
+         * Called when a drawer has settled in a completely open state.
+         * The drawer is interactive at this point.
+         *
+         * @param drawerView Drawer view that is now open
+         */
+        void onDrawerOpened(@NonNull View drawerView);
+
+        /**
+         * Called when a drawer has settled in a completely closed state.
+         *
+         * @param drawerView Drawer view that is now closed
+         */
+        void onDrawerClosed(@NonNull View drawerView);
+
+        /**
+         * Called when the drawer motion state changes. The new state will
+         * be one of {@link #STATE_IDLE}, {@link #STATE_DRAGGING} or {@link #STATE_SETTLING}.
+         *
+         * @param newState The new drawer motion state
+         */
+        void onDrawerStateChanged(@State int newState);
+    }
+
+    /**
+     * Stub/no-op implementations of all methods of {@link DrawerListener}.
+     * Override this if you only care about a few of the available callback methods.
+     */
+    public abstract static class SimpleDrawerListener implements DrawerListener {
+        @Override
+        public void onDrawerSlide(View drawerView, float slideOffset) {
+        }
+
+        @Override
+        public void onDrawerOpened(View drawerView) {
+        }
+
+        @Override
+        public void onDrawerClosed(View drawerView) {
+        }
+
+        @Override
+        public void onDrawerStateChanged(int newState) {
+        }
+    }
+
+    public DrawerLayout(@NonNull Context context) {
+        this(context, null);
+    }
+
+    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DrawerLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+        final float density = getResources().getDisplayMetrics().density;
+        mMinDrawerMargin = (int) (MIN_DRAWER_MARGIN * density + 0.5f);
+        final float minVel = MIN_FLING_VELOCITY * density;
+
+        mLeftCallback = new ViewDragCallback(Gravity.LEFT);
+        mRightCallback = new ViewDragCallback(Gravity.RIGHT);
+
+        mLeftDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mLeftCallback);
+        mLeftDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
+        mLeftDragger.setMinVelocity(minVel);
+        mLeftCallback.setDragger(mLeftDragger);
+
+        mRightDragger = ViewDragHelper.create(this, TOUCH_SLOP_SENSITIVITY, mRightCallback);
+        mRightDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_RIGHT);
+        mRightDragger.setMinVelocity(minVel);
+        mRightCallback.setDragger(mRightDragger);
+
+        // So that we can catch the back button
+        setFocusableInTouchMode(true);
+
+        ViewCompat.setImportantForAccessibility(this,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
+        setMotionEventSplittingEnabled(false);
+        if (ViewCompat.getFitsSystemWindows(this)) {
+            if (Build.VERSION.SDK_INT >= 21) {
+                setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+                    @TargetApi(21)
+                    @Override
+                    public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
+                        final DrawerLayout drawerLayout = (DrawerLayout) view;
+                        drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
+                        return insets.consumeSystemWindowInsets();
+                    }
+                });
+                setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+                final TypedArray a = context.obtainStyledAttributes(THEME_ATTRS);
+                try {
+                    mStatusBarBackground = a.getDrawable(0);
+                } finally {
+                    a.recycle();
+                }
+            } else {
+                mStatusBarBackground = null;
+            }
+        }
+
+        mDrawerElevation = DRAWER_ELEVATION * density;
+
+        mNonDrawerViews = new ArrayList<View>();
+    }
+
+    /**
+     * Sets the base elevation of the drawer(s) relative to the parent, in pixels. Note that the
+     * elevation change is only supported in API 21 and above.
+     *
+     * @param elevation The base depth position of the view, in pixels.
+     */
+    public void setDrawerElevation(float elevation) {
+        mDrawerElevation = elevation;
+        for (int i = 0; i < getChildCount(); i++) {
+            View child = getChildAt(i);
+            if (isDrawerView(child)) {
+                ViewCompat.setElevation(child, mDrawerElevation);
+            }
+        }
+    }
+
+    /**
+     * The base elevation of the drawer(s) relative to the parent, in pixels. Note that the
+     * elevation change is only supported in API 21 and above. For unsupported API levels, 0 will
+     * be returned as the elevation.
+     *
+     * @return The base depth position of the view, in pixels.
+     */
+    public float getDrawerElevation() {
+        if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+            return mDrawerElevation;
+        }
+        return 0f;
+    }
+
+    /**
+     * @hide Internal use only; called to apply window insets when configured
+     * with fitsSystemWindows="true"
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void setChildInsets(Object insets, boolean draw) {
+        mLastInsets = insets;
+        mDrawStatusBarBackground = draw;
+        setWillNotDraw(!draw && getBackground() == null);
+        requestLayout();
+    }
+
+    /**
+     * Set a simple drawable used for the left or right shadow. The drawable provided must have a
+     * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
+     * instead of using the provided shadow drawable.
+     *
+     * <p>Note that for better support for both left-to-right and right-to-left layout
+     * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
+     * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
+     * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
+     * auto-mirrored such that the drawable will be mirrored in RTL layout.</p>
+     *
+     * @param shadowDrawable Shadow drawable to use at the edge of a drawer
+     * @param gravity Which drawer the shadow should apply to
+     */
+    public void setDrawerShadow(Drawable shadowDrawable, @EdgeGravity int gravity) {
+        /*
+         * TODO Someone someday might want to set more complex drawables here.
+         * They're probably nuts, but we might want to consider registering callbacks,
+         * setting states, etc. properly.
+         */
+        if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+            // No op. Drawer shadow will come from setting an elevation on the drawer.
+            return;
+        }
+        if ((gravity & GravityCompat.START) == GravityCompat.START) {
+            mShadowStart = shadowDrawable;
+        } else if ((gravity & GravityCompat.END) == GravityCompat.END) {
+            mShadowEnd = shadowDrawable;
+        } else if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
+            mShadowLeft = shadowDrawable;
+        } else if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
+            mShadowRight = shadowDrawable;
+        } else {
+            return;
+        }
+        resolveShadowDrawables();
+        invalidate();
+    }
+
+    /**
+     * Set a simple drawable used for the left or right shadow. The drawable provided must have a
+     * nonzero intrinsic width. For API 21 and above, an elevation will be set on the drawer
+     * instead of using the provided shadow drawable.
+     *
+     * <p>Note that for better support for both left-to-right and right-to-left layout
+     * directions, a drawable for RTL layout (in additional to the one in LTR layout) can be
+     * defined with a resource qualifier "ldrtl" for API 17 and above with the gravity
+     * {@link GravityCompat#START}. Alternatively, for API 23 and above, the drawable can
+     * auto-mirrored such that the drawable will be mirrored in RTL layout.</p>
+     *
+     * @param resId Resource id of a shadow drawable to use at the edge of a drawer
+     * @param gravity Which drawer the shadow should apply to
+     */
+    public void setDrawerShadow(@DrawableRes int resId, @EdgeGravity int gravity) {
+        setDrawerShadow(ContextCompat.getDrawable(getContext(), resId), gravity);
+    }
+
+    /**
+     * Set a color to use for the scrim that obscures primary content while a drawer is open.
+     *
+     * @param color Color to use in 0xAARRGGBB format.
+     */
+    public void setScrimColor(@ColorInt int color) {
+        mScrimColor = color;
+        invalidate();
+    }
+
+    /**
+     * Set a listener to be notified of drawer events. Note that this method is deprecated
+     * and you should use {@link #addDrawerListener(DrawerListener)} to add a listener and
+     * {@link #removeDrawerListener(DrawerListener)} to remove a registered listener.
+     *
+     * @param listener Listener to notify when drawer events occur
+     * @deprecated Use {@link #addDrawerListener(DrawerListener)}
+     * @see DrawerListener
+     * @see #addDrawerListener(DrawerListener)
+     * @see #removeDrawerListener(DrawerListener)
+     */
+    @Deprecated
+    public void setDrawerListener(DrawerListener listener) {
+        // The logic in this method emulates what we had before support for multiple
+        // registered listeners.
+        if (mListener != null) {
+            removeDrawerListener(mListener);
+        }
+        if (listener != null) {
+            addDrawerListener(listener);
+        }
+        // Update the deprecated field so that we can remove the passed listener the next
+        // time we're called
+        mListener = listener;
+    }
+
+    /**
+     * Adds the specified listener to the list of listeners that will be notified of drawer events.
+     *
+     * @param listener Listener to notify when drawer events occur.
+     * @see #removeDrawerListener(DrawerListener)
+     */
+    public void addDrawerListener(@NonNull DrawerListener listener) {
+        if (listener == null) {
+            return;
+        }
+        if (mListeners == null) {
+            mListeners = new ArrayList<DrawerListener>();
+        }
+        mListeners.add(listener);
+    }
+
+    /**
+     * Removes the specified listener from the list of listeners that will be notified of drawer
+     * events.
+     *
+     * @param listener Listener to remove from being notified of drawer events
+     * @see #addDrawerListener(DrawerListener)
+     */
+    public void removeDrawerListener(@NonNull DrawerListener listener) {
+        if (listener == null) {
+            return;
+        }
+        if (mListeners == null) {
+            // This can happen if this method is called before the first call to addDrawerListener
+            return;
+        }
+        mListeners.remove(listener);
+    }
+
+    /**
+     * Enable or disable interaction with all drawers.
+     *
+     * <p>This allows the application to restrict the user's ability to open or close
+     * any drawer within this layout. DrawerLayout will still respond to calls to
+     * {@link #openDrawer(int)}, {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
+     *
+     * <p>Locking drawers open or closed will implicitly open or close
+     * any drawers as appropriate.</p>
+     *
+     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
+     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
+     */
+    public void setDrawerLockMode(@LockMode int lockMode) {
+        setDrawerLockMode(lockMode, Gravity.LEFT);
+        setDrawerLockMode(lockMode, Gravity.RIGHT);
+    }
+
+    /**
+     * Enable or disable interaction with the given drawer.
+     *
+     * <p>This allows the application to restrict the user's ability to open or close
+     * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
+     * {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
+     *
+     * <p>Locking a drawer open or closed will implicitly open or close
+     * that drawer as appropriate.</p>
+     *
+     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
+     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
+     * @param edgeGravity Gravity.LEFT, RIGHT, START or END.
+     *                    Expresses which drawer to change the mode for.
+     *
+     * @see #LOCK_MODE_UNLOCKED
+     * @see #LOCK_MODE_LOCKED_CLOSED
+     * @see #LOCK_MODE_LOCKED_OPEN
+     */
+    public void setDrawerLockMode(@LockMode int lockMode, @EdgeGravity int edgeGravity) {
+        final int absGravity = GravityCompat.getAbsoluteGravity(edgeGravity,
+                ViewCompat.getLayoutDirection(this));
+
+        switch (edgeGravity) {
+            case Gravity.LEFT:
+                mLockModeLeft = lockMode;
+                break;
+            case Gravity.RIGHT:
+                mLockModeRight = lockMode;
+                break;
+            case GravityCompat.START:
+                mLockModeStart = lockMode;
+                break;
+            case GravityCompat.END:
+                mLockModeEnd = lockMode;
+                break;
+        }
+
+        if (lockMode != LOCK_MODE_UNLOCKED) {
+            // Cancel interaction in progress
+            final ViewDragHelper helper = absGravity == Gravity.LEFT ? mLeftDragger : mRightDragger;
+            helper.cancel();
+        }
+        switch (lockMode) {
+            case LOCK_MODE_LOCKED_OPEN:
+                final View toOpen = findDrawerWithGravity(absGravity);
+                if (toOpen != null) {
+                    openDrawer(toOpen);
+                }
+                break;
+            case LOCK_MODE_LOCKED_CLOSED:
+                final View toClose = findDrawerWithGravity(absGravity);
+                if (toClose != null) {
+                    closeDrawer(toClose);
+                }
+                break;
+            // default: do nothing
+        }
+    }
+
+    /**
+     * Enable or disable interaction with the given drawer.
+     *
+     * <p>This allows the application to restrict the user's ability to open or close
+     * the given drawer. DrawerLayout will still respond to calls to {@link #openDrawer(int)},
+     * {@link #closeDrawer(int)} and friends if a drawer is locked.</p>
+     *
+     * <p>Locking a drawer open or closed will implicitly open or close
+     * that drawer as appropriate.</p>
+     *
+     * @param lockMode The new lock mode for the given drawer. One of {@link #LOCK_MODE_UNLOCKED},
+     *                 {@link #LOCK_MODE_LOCKED_CLOSED} or {@link #LOCK_MODE_LOCKED_OPEN}.
+     * @param drawerView The drawer view to change the lock mode for
+     *
+     * @see #LOCK_MODE_UNLOCKED
+     * @see #LOCK_MODE_LOCKED_CLOSED
+     * @see #LOCK_MODE_LOCKED_OPEN
+     */
+    public void setDrawerLockMode(@LockMode int lockMode, @NonNull View drawerView) {
+        if (!isDrawerView(drawerView)) {
+            throw new IllegalArgumentException("View " + drawerView + " is not a "
+                    + "drawer with appropriate layout_gravity");
+        }
+        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
+        setDrawerLockMode(lockMode, gravity);
+    }
+
+    /**
+     * Check the lock mode of the drawer with the given gravity.
+     *
+     * @param edgeGravity Gravity of the drawer to check
+     * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
+     *         {@link #LOCK_MODE_LOCKED_OPEN}.
+     */
+    @LockMode
+    public int getDrawerLockMode(@EdgeGravity int edgeGravity) {
+        int layoutDirection = ViewCompat.getLayoutDirection(this);
+
+        switch (edgeGravity) {
+            case Gravity.LEFT:
+                if (mLockModeLeft != LOCK_MODE_UNDEFINED) {
+                    return mLockModeLeft;
+                }
+                int leftLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
+                        ? mLockModeStart : mLockModeEnd;
+                if (leftLockMode != LOCK_MODE_UNDEFINED) {
+                    return leftLockMode;
+                }
+                break;
+            case Gravity.RIGHT:
+                if (mLockModeRight != LOCK_MODE_UNDEFINED) {
+                    return mLockModeRight;
+                }
+                int rightLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
+                        ? mLockModeEnd : mLockModeStart;
+                if (rightLockMode != LOCK_MODE_UNDEFINED) {
+                    return rightLockMode;
+                }
+                break;
+            case GravityCompat.START:
+                if (mLockModeStart != LOCK_MODE_UNDEFINED) {
+                    return mLockModeStart;
+                }
+                int startLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
+                        ? mLockModeLeft : mLockModeRight;
+                if (startLockMode != LOCK_MODE_UNDEFINED) {
+                    return startLockMode;
+                }
+                break;
+            case GravityCompat.END:
+                if (mLockModeEnd != LOCK_MODE_UNDEFINED) {
+                    return mLockModeEnd;
+                }
+                int endLockMode = (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR)
+                        ? mLockModeRight : mLockModeLeft;
+                if (endLockMode != LOCK_MODE_UNDEFINED) {
+                    return endLockMode;
+                }
+                break;
+        }
+
+        return LOCK_MODE_UNLOCKED;
+    }
+
+    /**
+     * Check the lock mode of the given drawer view.
+     *
+     * @param drawerView Drawer view to check lock mode
+     * @return one of {@link #LOCK_MODE_UNLOCKED}, {@link #LOCK_MODE_LOCKED_CLOSED} or
+     *         {@link #LOCK_MODE_LOCKED_OPEN}.
+     */
+    @LockMode
+    public int getDrawerLockMode(@NonNull View drawerView) {
+        if (!isDrawerView(drawerView)) {
+            throw new IllegalArgumentException("View " + drawerView + " is not a drawer");
+        }
+        final int drawerGravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
+        return getDrawerLockMode(drawerGravity);
+    }
+
+    /**
+     * Sets the title of the drawer with the given gravity.
+     * <p>
+     * When accessibility is turned on, this is the title that will be used to
+     * identify the drawer to the active accessibility service.
+     *
+     * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which
+     *            drawer to set the title for.
+     * @param title The title for the drawer.
+     */
+    public void setDrawerTitle(@EdgeGravity int edgeGravity, @Nullable CharSequence title) {
+        final int absGravity = GravityCompat.getAbsoluteGravity(
+                edgeGravity, ViewCompat.getLayoutDirection(this));
+        if (absGravity == Gravity.LEFT) {
+            mTitleLeft = title;
+        } else if (absGravity == Gravity.RIGHT) {
+            mTitleRight = title;
+        }
+    }
+
+    /**
+     * Returns the title of the drawer with the given gravity.
+     *
+     * @param edgeGravity Gravity.LEFT, RIGHT, START or END. Expresses which
+     *            drawer to return the title for.
+     * @return The title of the drawer, or null if none set.
+     * @see #setDrawerTitle(int, CharSequence)
+     */
+    @Nullable
+    public CharSequence getDrawerTitle(@EdgeGravity int edgeGravity) {
+        final int absGravity = GravityCompat.getAbsoluteGravity(
+                edgeGravity, ViewCompat.getLayoutDirection(this));
+        if (absGravity == Gravity.LEFT) {
+            return mTitleLeft;
+        } else if (absGravity == Gravity.RIGHT) {
+            return mTitleRight;
+        }
+        return null;
+    }
+
+    /**
+     * Resolve the shared state of all drawers from the component ViewDragHelpers.
+     * Should be called whenever a ViewDragHelper's state changes.
+     */
+    void updateDrawerState(int forGravity, @State int activeState, View activeDrawer) {
+        final int leftState = mLeftDragger.getViewDragState();
+        final int rightState = mRightDragger.getViewDragState();
+
+        final int state;
+        if (leftState == STATE_DRAGGING || rightState == STATE_DRAGGING) {
+            state = STATE_DRAGGING;
+        } else if (leftState == STATE_SETTLING || rightState == STATE_SETTLING) {
+            state = STATE_SETTLING;
+        } else {
+            state = STATE_IDLE;
+        }
+
+        if (activeDrawer != null && activeState == STATE_IDLE) {
+            final LayoutParams lp = (LayoutParams) activeDrawer.getLayoutParams();
+            if (lp.onScreen == 0) {
+                dispatchOnDrawerClosed(activeDrawer);
+            } else if (lp.onScreen == 1) {
+                dispatchOnDrawerOpened(activeDrawer);
+            }
+        }
+
+        if (state != mDrawerState) {
+            mDrawerState = state;
+
+            if (mListeners != null) {
+                // Notify the listeners. Do that from the end of the list so that if a listener
+                // removes itself as the result of being called, it won't mess up with our iteration
+                int listenerCount = mListeners.size();
+                for (int i = listenerCount - 1; i >= 0; i--) {
+                    mListeners.get(i).onDrawerStateChanged(state);
+                }
+            }
+        }
+    }
+
+    void dispatchOnDrawerClosed(View drawerView) {
+        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
+        if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
+            lp.openState = 0;
+
+            if (mListeners != null) {
+                // Notify the listeners. Do that from the end of the list so that if a listener
+                // removes itself as the result of being called, it won't mess up with our iteration
+                int listenerCount = mListeners.size();
+                for (int i = listenerCount - 1; i >= 0; i--) {
+                    mListeners.get(i).onDrawerClosed(drawerView);
+                }
+            }
+
+            updateChildrenImportantForAccessibility(drawerView, false);
+
+            // Only send WINDOW_STATE_CHANGE if the host has window focus. This
+            // may change if support for multiple foreground windows (e.g. IME)
+            // improves.
+            if (hasWindowFocus()) {
+                final View rootView = getRootView();
+                if (rootView != null) {
+                    rootView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                }
+            }
+        }
+    }
+
+    void dispatchOnDrawerOpened(View drawerView) {
+        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
+        if ((lp.openState & LayoutParams.FLAG_IS_OPENED) == 0) {
+            lp.openState = LayoutParams.FLAG_IS_OPENED;
+            if (mListeners != null) {
+                // Notify the listeners. Do that from the end of the list so that if a listener
+                // removes itself as the result of being called, it won't mess up with our iteration
+                int listenerCount = mListeners.size();
+                for (int i = listenerCount - 1; i >= 0; i--) {
+                    mListeners.get(i).onDrawerOpened(drawerView);
+                }
+            }
+
+            updateChildrenImportantForAccessibility(drawerView, true);
+
+            // Only send WINDOW_STATE_CHANGE if the host has window focus.
+            if (hasWindowFocus()) {
+                sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            }
+        }
+    }
+
+    private void updateChildrenImportantForAccessibility(View drawerView, boolean isDrawerOpen) {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if ((!isDrawerOpen && !isDrawerView(child)) || (isDrawerOpen && child == drawerView)) {
+                // Drawer is closed and this is a content view or this is an
+                // open drawer view, so it should be visible.
+                ViewCompat.setImportantForAccessibility(child,
+                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+            } else {
+                ViewCompat.setImportantForAccessibility(child,
+                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            }
+        }
+    }
+
+    void dispatchOnDrawerSlide(View drawerView, float slideOffset) {
+        if (mListeners != null) {
+            // Notify the listeners. Do that from the end of the list so that if a listener
+            // removes itself as the result of being called, it won't mess up with our iteration
+            int listenerCount = mListeners.size();
+            for (int i = listenerCount - 1; i >= 0; i--) {
+                mListeners.get(i).onDrawerSlide(drawerView, slideOffset);
+            }
+        }
+    }
+
+    void setDrawerViewOffset(View drawerView, float slideOffset) {
+        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
+        if (slideOffset == lp.onScreen) {
+            return;
+        }
+
+        lp.onScreen = slideOffset;
+        dispatchOnDrawerSlide(drawerView, slideOffset);
+    }
+
+    float getDrawerViewOffset(View drawerView) {
+        return ((LayoutParams) drawerView.getLayoutParams()).onScreen;
+    }
+
+    /**
+     * @return the absolute gravity of the child drawerView, resolved according
+     *         to the current layout direction
+     */
+    int getDrawerViewAbsoluteGravity(View drawerView) {
+        final int gravity = ((LayoutParams) drawerView.getLayoutParams()).gravity;
+        return GravityCompat.getAbsoluteGravity(gravity, ViewCompat.getLayoutDirection(this));
+    }
+
+    boolean checkDrawerViewAbsoluteGravity(View drawerView, int checkFor) {
+        final int absGravity = getDrawerViewAbsoluteGravity(drawerView);
+        return (absGravity & checkFor) == checkFor;
+    }
+
+    View findOpenDrawer() {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams childLp = (LayoutParams) child.getLayoutParams();
+            if ((childLp.openState & LayoutParams.FLAG_IS_OPENED) == 1) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    void moveDrawerToOffset(View drawerView, float slideOffset) {
+        final float oldOffset = getDrawerViewOffset(drawerView);
+        final int width = drawerView.getWidth();
+        final int oldPos = (int) (width * oldOffset);
+        final int newPos = (int) (width * slideOffset);
+        final int dx = newPos - oldPos;
+
+        drawerView.offsetLeftAndRight(
+                checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT) ? dx : -dx);
+        setDrawerViewOffset(drawerView, slideOffset);
+    }
+
+    /**
+     * @param gravity the gravity of the child to return. If specified as a
+     *            relative value, it will be resolved according to the current
+     *            layout direction.
+     * @return the drawer with the specified gravity
+     */
+    View findDrawerWithGravity(int gravity) {
+        final int absHorizGravity = GravityCompat.getAbsoluteGravity(
+                gravity, ViewCompat.getLayoutDirection(this)) & Gravity.HORIZONTAL_GRAVITY_MASK;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final int childAbsGravity = getDrawerViewAbsoluteGravity(child);
+            if ((childAbsGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == absHorizGravity) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Simple gravity to string - only supports LEFT and RIGHT for debugging output.
+     *
+     * @param gravity Absolute gravity value
+     * @return LEFT or RIGHT as appropriate, or a hex string
+     */
+    static String gravityToString(@EdgeGravity int gravity) {
+        if ((gravity & Gravity.LEFT) == Gravity.LEFT) {
+            return "LEFT";
+        }
+        if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) {
+            return "RIGHT";
+        }
+        return Integer.toHexString(gravity);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mFirstLayout = true;
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mFirstLayout = true;
+    }
+
+    @SuppressLint("WrongConstant")
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) {
+            if (isInEditMode()) {
+                // Don't crash the layout editor. Consume all of the space if specified
+                // or pick a magic number from thin air otherwise.
+                // TODO Better communication with tools of this bogus state.
+                // It will crash on a real device.
+                if (widthMode == MeasureSpec.AT_MOST) {
+                    widthMode = MeasureSpec.EXACTLY;
+                } else if (widthMode == MeasureSpec.UNSPECIFIED) {
+                    widthMode = MeasureSpec.EXACTLY;
+                    widthSize = 300;
+                }
+                if (heightMode == MeasureSpec.AT_MOST) {
+                    heightMode = MeasureSpec.EXACTLY;
+                } else if (heightMode == MeasureSpec.UNSPECIFIED) {
+                    heightMode = MeasureSpec.EXACTLY;
+                    heightSize = 300;
+                }
+            } else {
+                throw new IllegalArgumentException(
+                        "DrawerLayout must be measured with MeasureSpec.EXACTLY.");
+            }
+        }
+
+        setMeasuredDimension(widthSize, heightSize);
+
+        final boolean applyInsets = mLastInsets != null && ViewCompat.getFitsSystemWindows(this);
+        final int layoutDirection = ViewCompat.getLayoutDirection(this);
+
+        // Only one drawer is permitted along each vertical edge (left / right). These two booleans
+        // are tracking the presence of the edge drawers.
+        boolean hasDrawerOnLeftEdge = false;
+        boolean hasDrawerOnRightEdge = false;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (applyInsets) {
+                final int cgrav = GravityCompat.getAbsoluteGravity(lp.gravity, layoutDirection);
+                if (ViewCompat.getFitsSystemWindows(child)) {
+                    if (Build.VERSION.SDK_INT >= 21) {
+                        WindowInsets wi = (WindowInsets) mLastInsets;
+                        if (cgrav == Gravity.LEFT) {
+                            wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(),
+                                    wi.getSystemWindowInsetTop(), 0,
+                                    wi.getSystemWindowInsetBottom());
+                        } else if (cgrav == Gravity.RIGHT) {
+                            wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(),
+                                    wi.getSystemWindowInsetRight(),
+                                    wi.getSystemWindowInsetBottom());
+                        }
+                        child.dispatchApplyWindowInsets(wi);
+                    }
+                } else {
+                    if (Build.VERSION.SDK_INT >= 21) {
+                        WindowInsets wi = (WindowInsets) mLastInsets;
+                        if (cgrav == Gravity.LEFT) {
+                            wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(),
+                                    wi.getSystemWindowInsetTop(), 0,
+                                    wi.getSystemWindowInsetBottom());
+                        } else if (cgrav == Gravity.RIGHT) {
+                            wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(),
+                                    wi.getSystemWindowInsetRight(),
+                                    wi.getSystemWindowInsetBottom());
+                        }
+                        lp.leftMargin = wi.getSystemWindowInsetLeft();
+                        lp.topMargin = wi.getSystemWindowInsetTop();
+                        lp.rightMargin = wi.getSystemWindowInsetRight();
+                        lp.bottomMargin = wi.getSystemWindowInsetBottom();
+                    }
+                }
+            }
+
+            if (isContentView(child)) {
+                // Content views get measured at exactly the layout's size.
+                final int contentWidthSpec = MeasureSpec.makeMeasureSpec(
+                        widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
+                final int contentHeightSpec = MeasureSpec.makeMeasureSpec(
+                        heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
+                child.measure(contentWidthSpec, contentHeightSpec);
+            } else if (isDrawerView(child)) {
+                if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+                    if (ViewCompat.getElevation(child) != mDrawerElevation) {
+                        ViewCompat.setElevation(child, mDrawerElevation);
+                    }
+                }
+                final @EdgeGravity int childGravity =
+                        getDrawerViewAbsoluteGravity(child) & Gravity.HORIZONTAL_GRAVITY_MASK;
+                // Note that the isDrawerView check guarantees that childGravity here is either
+                // LEFT or RIGHT
+                boolean isLeftEdgeDrawer = (childGravity == Gravity.LEFT);
+                if ((isLeftEdgeDrawer && hasDrawerOnLeftEdge)
+                        || (!isLeftEdgeDrawer && hasDrawerOnRightEdge)) {
+                    throw new IllegalStateException("Child drawer has absolute gravity "
+                            + gravityToString(childGravity) + " but this " + TAG + " already has a "
+                            + "drawer view along that edge");
+                }
+                if (isLeftEdgeDrawer) {
+                    hasDrawerOnLeftEdge = true;
+                } else {
+                    hasDrawerOnRightEdge = true;
+                }
+                final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec,
+                        mMinDrawerMargin + lp.leftMargin + lp.rightMargin,
+                        lp.width);
+                final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec,
+                        lp.topMargin + lp.bottomMargin,
+                        lp.height);
+                child.measure(drawerWidthSpec, drawerHeightSpec);
+            } else {
+                throw new IllegalStateException("Child " + child + " at index " + i
+                        + " does not have a valid layout_gravity - must be Gravity.LEFT, "
+                        + "Gravity.RIGHT or Gravity.NO_GRAVITY");
+            }
+        }
+    }
+
+    private void resolveShadowDrawables() {
+        if (SET_DRAWER_SHADOW_FROM_ELEVATION) {
+            return;
+        }
+        mShadowLeftResolved = resolveLeftShadow();
+        mShadowRightResolved = resolveRightShadow();
+    }
+
+    private Drawable resolveLeftShadow() {
+        int layoutDirection = ViewCompat.getLayoutDirection(this);
+        // Prefer shadows defined with start/end gravity over left and right.
+        if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
+            if (mShadowStart != null) {
+                // Correct drawable layout direction, if needed.
+                mirror(mShadowStart, layoutDirection);
+                return mShadowStart;
+            }
+        } else {
+            if (mShadowEnd != null) {
+                // Correct drawable layout direction, if needed.
+                mirror(mShadowEnd, layoutDirection);
+                return mShadowEnd;
+            }
+        }
+        return mShadowLeft;
+    }
+
+    private Drawable resolveRightShadow() {
+        int layoutDirection = ViewCompat.getLayoutDirection(this);
+        if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) {
+            if (mShadowEnd != null) {
+                // Correct drawable layout direction, if needed.
+                mirror(mShadowEnd, layoutDirection);
+                return mShadowEnd;
+            }
+        } else {
+            if (mShadowStart != null) {
+                // Correct drawable layout direction, if needed.
+                mirror(mShadowStart, layoutDirection);
+                return mShadowStart;
+            }
+        }
+        return mShadowRight;
+    }
+
+    /**
+     * Change the layout direction of the given drawable.
+     * Return true if auto-mirror is supported and drawable's layout direction can be changed.
+     * Otherwise, return false.
+     */
+    private boolean mirror(Drawable drawable, int layoutDirection) {
+        if (drawable == null || !DrawableCompat.isAutoMirrored(drawable)) {
+            return false;
+        }
+
+        DrawableCompat.setLayoutDirection(drawable, layoutDirection);
+        return true;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mInLayout = true;
+        final int width = r - l;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+
+            if (child.getVisibility() == GONE) {
+                continue;
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (isContentView(child)) {
+                child.layout(lp.leftMargin, lp.topMargin,
+                        lp.leftMargin + child.getMeasuredWidth(),
+                        lp.topMargin + child.getMeasuredHeight());
+            } else { // Drawer, if it wasn't onMeasure would have thrown an exception.
+                final int childWidth = child.getMeasuredWidth();
+                final int childHeight = child.getMeasuredHeight();
+                int childLeft;
+
+                final float newOffset;
+                if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
+                    childLeft = -childWidth + (int) (childWidth * lp.onScreen);
+                    newOffset = (float) (childWidth + childLeft) / childWidth;
+                } else { // Right; onMeasure checked for us.
+                    childLeft = width - (int) (childWidth * lp.onScreen);
+                    newOffset = (float) (width - childLeft) / childWidth;
+                }
+
+                final boolean changeOffset = newOffset != lp.onScreen;
+
+                final int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+
+                switch (vgrav) {
+                    default:
+                    case Gravity.TOP: {
+                        child.layout(childLeft, lp.topMargin, childLeft + childWidth,
+                                lp.topMargin + childHeight);
+                        break;
+                    }
+
+                    case Gravity.BOTTOM: {
+                        final int height = b - t;
+                        child.layout(childLeft,
+                                height - lp.bottomMargin - child.getMeasuredHeight(),
+                                childLeft + childWidth,
+                                height - lp.bottomMargin);
+                        break;
+                    }
+
+                    case Gravity.CENTER_VERTICAL: {
+                        final int height = b - t;
+                        int childTop = (height - childHeight) / 2;
+
+                        // Offset for margins. If things don't fit right because of
+                        // bad measurement before, oh well.
+                        if (childTop < lp.topMargin) {
+                            childTop = lp.topMargin;
+                        } else if (childTop + childHeight > height - lp.bottomMargin) {
+                            childTop = height - lp.bottomMargin - childHeight;
+                        }
+                        child.layout(childLeft, childTop, childLeft + childWidth,
+                                childTop + childHeight);
+                        break;
+                    }
+                }
+
+                if (changeOffset) {
+                    setDrawerViewOffset(child, newOffset);
+                }
+
+                final int newVisibility = lp.onScreen > 0 ? VISIBLE : INVISIBLE;
+                if (child.getVisibility() != newVisibility) {
+                    child.setVisibility(newVisibility);
+                }
+            }
+        }
+        mInLayout = false;
+        mFirstLayout = false;
+    }
+
+    @Override
+    public void requestLayout() {
+        if (!mInLayout) {
+            super.requestLayout();
+        }
+    }
+
+    @Override
+    public void computeScroll() {
+        final int childCount = getChildCount();
+        float scrimOpacity = 0;
+        for (int i = 0; i < childCount; i++) {
+            final float onscreen = ((LayoutParams) getChildAt(i).getLayoutParams()).onScreen;
+            scrimOpacity = Math.max(scrimOpacity, onscreen);
+        }
+        mScrimOpacity = scrimOpacity;
+
+        boolean leftDraggerSettling = mLeftDragger.continueSettling(true);
+        boolean rightDraggerSettling = mRightDragger.continueSettling(true);
+        if (leftDraggerSettling || rightDraggerSettling) {
+            ViewCompat.postInvalidateOnAnimation(this);
+        }
+    }
+
+    private static boolean hasOpaqueBackground(View v) {
+        final Drawable bg = v.getBackground();
+        if (bg != null) {
+            return bg.getOpacity() == PixelFormat.OPAQUE;
+        }
+        return false;
+    }
+
+    /**
+     * Set a drawable to draw in the insets area for the status bar.
+     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
+     *
+     * @param bg Background drawable to draw behind the status bar
+     */
+    public void setStatusBarBackground(@Nullable Drawable bg) {
+        mStatusBarBackground = bg;
+        invalidate();
+    }
+
+    /**
+     * Gets the drawable used to draw in the insets area for the status bar.
+     *
+     * @return The status bar background drawable, or null if none set
+     */
+    @Nullable
+    public Drawable getStatusBarBackgroundDrawable() {
+        return mStatusBarBackground;
+    }
+
+    /**
+     * Set a drawable to draw in the insets area for the status bar.
+     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
+     *
+     * @param resId Resource id of a background drawable to draw behind the status bar
+     */
+    public void setStatusBarBackground(int resId) {
+        mStatusBarBackground = resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null;
+        invalidate();
+    }
+
+    /**
+     * Set a drawable to draw in the insets area for the status bar.
+     * Note that this will only be activated if this DrawerLayout fitsSystemWindows.
+     *
+     * @param color Color to use as a background drawable to draw behind the status bar
+     *              in 0xAARRGGBB format.
+     */
+    public void setStatusBarBackgroundColor(@ColorInt int color) {
+        mStatusBarBackground = new ColorDrawable(color);
+        invalidate();
+    }
+
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        resolveShadowDrawables();
+    }
+
+    @Override
+    public void onDraw(Canvas c) {
+        super.onDraw(c);
+        if (mDrawStatusBarBackground && mStatusBarBackground != null) {
+            final int inset;
+            if (Build.VERSION.SDK_INT >= 21) {
+                inset = mLastInsets != null
+                        ? ((WindowInsets) mLastInsets).getSystemWindowInsetTop() : 0;
+            } else {
+                inset = 0;
+            }
+            if (inset > 0) {
+                mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
+                mStatusBarBackground.draw(c);
+            }
+        }
+    }
+
+    @Override
+    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+        final int height = getHeight();
+        final boolean drawingContent = isContentView(child);
+        int clipLeft = 0, clipRight = getWidth();
+
+        final int restoreCount = canvas.save();
+        if (drawingContent) {
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View v = getChildAt(i);
+                if (v == child || v.getVisibility() != VISIBLE
+                        || !hasOpaqueBackground(v) || !isDrawerView(v)
+                        || v.getHeight() < height) {
+                    continue;
+                }
+
+                if (checkDrawerViewAbsoluteGravity(v, Gravity.LEFT)) {
+                    final int vright = v.getRight();
+                    if (vright > clipLeft) clipLeft = vright;
+                } else {
+                    final int vleft = v.getLeft();
+                    if (vleft < clipRight) clipRight = vleft;
+                }
+            }
+            canvas.clipRect(clipLeft, 0, clipRight, getHeight());
+        }
+        final boolean result = super.drawChild(canvas, child, drawingTime);
+        canvas.restoreToCount(restoreCount);
+
+        if (mScrimOpacity > 0 && drawingContent) {
+            final int baseAlpha = (mScrimColor & 0xff000000) >>> 24;
+            final int imag = (int) (baseAlpha * mScrimOpacity);
+            final int color = imag << 24 | (mScrimColor & 0xffffff);
+            mScrimPaint.setColor(color);
+
+            canvas.drawRect(clipLeft, 0, clipRight, getHeight(), mScrimPaint);
+        } else if (mShadowLeftResolved != null
+                &&  checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
+            final int shadowWidth = mShadowLeftResolved.getIntrinsicWidth();
+            final int childRight = child.getRight();
+            final int drawerPeekDistance = mLeftDragger.getEdgeSize();
+            final float alpha =
+                    Math.max(0, Math.min((float) childRight / drawerPeekDistance, 1.f));
+            mShadowLeftResolved.setBounds(childRight, child.getTop(),
+                    childRight + shadowWidth, child.getBottom());
+            mShadowLeftResolved.setAlpha((int) (0xff * alpha));
+            mShadowLeftResolved.draw(canvas);
+        } else if (mShadowRightResolved != null
+                &&  checkDrawerViewAbsoluteGravity(child, Gravity.RIGHT)) {
+            final int shadowWidth = mShadowRightResolved.getIntrinsicWidth();
+            final int childLeft = child.getLeft();
+            final int showing = getWidth() - childLeft;
+            final int drawerPeekDistance = mRightDragger.getEdgeSize();
+            final float alpha =
+                    Math.max(0, Math.min((float) showing / drawerPeekDistance, 1.f));
+            mShadowRightResolved.setBounds(childLeft - shadowWidth, child.getTop(),
+                    childLeft, child.getBottom());
+            mShadowRightResolved.setAlpha((int) (0xff * alpha));
+            mShadowRightResolved.draw(canvas);
+        }
+        return result;
+    }
+
+    boolean isContentView(View child) {
+        return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY;
+    }
+
+    boolean isDrawerView(View child) {
+        final int gravity = ((LayoutParams) child.getLayoutParams()).gravity;
+        final int absGravity = GravityCompat.getAbsoluteGravity(gravity,
+                ViewCompat.getLayoutDirection(child));
+        if ((absGravity & Gravity.LEFT) != 0) {
+            // This child is a left-edge drawer
+            return true;
+        }
+        if ((absGravity & Gravity.RIGHT) != 0) {
+            // This child is a right-edge drawer
+            return true;
+        }
+        return false;
+    }
+
+    @SuppressWarnings("ShortCircuitBoolean")
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        final int action = ev.getActionMasked();
+
+        // "|" used deliberately here; both methods should be invoked.
+        final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev)
+                | mRightDragger.shouldInterceptTouchEvent(ev);
+
+        boolean interceptForTap = false;
+
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                mInitialMotionX = x;
+                mInitialMotionY = y;
+                if (mScrimOpacity > 0) {
+                    final View child = mLeftDragger.findTopChildUnder((int) x, (int) y);
+                    if (child != null && isContentView(child)) {
+                        interceptForTap = true;
+                    }
+                }
+                mDisallowInterceptRequested = false;
+                mChildrenCanceledTouch = false;
+                break;
+            }
+
+            case MotionEvent.ACTION_MOVE: {
+                // If we cross the touch slop, don't perform the delayed peek for an edge touch.
+                if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
+                    mLeftCallback.removeCallbacks();
+                    mRightCallback.removeCallbacks();
+                }
+                break;
+            }
+
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP: {
+                closeDrawers(true);
+                mDisallowInterceptRequested = false;
+                mChildrenCanceledTouch = false;
+            }
+        }
+
+        return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        mLeftDragger.processTouchEvent(ev);
+        mRightDragger.processTouchEvent(ev);
+
+        final int action = ev.getAction();
+        boolean wantTouchEvents = true;
+
+        switch (action & MotionEvent.ACTION_MASK) {
+            case MotionEvent.ACTION_DOWN: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                mInitialMotionX = x;
+                mInitialMotionY = y;
+                mDisallowInterceptRequested = false;
+                mChildrenCanceledTouch = false;
+                break;
+            }
+
+            case MotionEvent.ACTION_UP: {
+                final float x = ev.getX();
+                final float y = ev.getY();
+                boolean peekingOnly = true;
+                final View touchedView = mLeftDragger.findTopChildUnder((int) x, (int) y);
+                if (touchedView != null && isContentView(touchedView)) {
+                    final float dx = x - mInitialMotionX;
+                    final float dy = y - mInitialMotionY;
+                    final int slop = mLeftDragger.getTouchSlop();
+                    if (dx * dx + dy * dy < slop * slop) {
+                        // Taps close a dimmed open drawer but only if it isn't locked open.
+                        final View openDrawer = findOpenDrawer();
+                        if (openDrawer != null) {
+                            peekingOnly = getDrawerLockMode(openDrawer) == LOCK_MODE_LOCKED_OPEN;
+                        }
+                    }
+                }
+                closeDrawers(peekingOnly);
+                mDisallowInterceptRequested = false;
+                break;
+            }
+
+            case MotionEvent.ACTION_CANCEL: {
+                closeDrawers(true);
+                mDisallowInterceptRequested = false;
+                mChildrenCanceledTouch = false;
+                break;
+            }
+        }
+
+        return wantTouchEvents;
+    }
+
+    @Override
+    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+        if (CHILDREN_DISALLOW_INTERCEPT
+                || (!mLeftDragger.isEdgeTouched(ViewDragHelper.EDGE_LEFT)
+                        && !mRightDragger.isEdgeTouched(ViewDragHelper.EDGE_RIGHT))) {
+            // If we have an edge touch we want to skip this and track it for later instead.
+            super.requestDisallowInterceptTouchEvent(disallowIntercept);
+        }
+        mDisallowInterceptRequested = disallowIntercept;
+        if (disallowIntercept) {
+            closeDrawers(true);
+        }
+    }
+
+    /**
+     * Close all currently open drawer views by animating them out of view.
+     */
+    public void closeDrawers() {
+        closeDrawers(false);
+    }
+
+    void closeDrawers(boolean peekingOnly) {
+        boolean needsInvalidate = false;
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+            if (!isDrawerView(child) || (peekingOnly && !lp.isPeeking)) {
+                continue;
+            }
+
+            final int childWidth = child.getWidth();
+
+            if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
+                needsInvalidate |= mLeftDragger.smoothSlideViewTo(child,
+                        -childWidth, child.getTop());
+            } else {
+                needsInvalidate |= mRightDragger.smoothSlideViewTo(child,
+                        getWidth(), child.getTop());
+            }
+
+            lp.isPeeking = false;
+        }
+
+        mLeftCallback.removeCallbacks();
+        mRightCallback.removeCallbacks();
+
+        if (needsInvalidate) {
+            invalidate();
+        }
+    }
+
+    /**
+     * Open the specified drawer view by animating it into view.
+     *
+     * @param drawerView Drawer view to open
+     */
+    public void openDrawer(@NonNull View drawerView) {
+        openDrawer(drawerView, true);
+    }
+
+    /**
+     * Open the specified drawer view.
+     *
+     * @param drawerView Drawer view to open
+     * @param animate Whether opening of the drawer should be animated.
+     */
+    public void openDrawer(@NonNull View drawerView, boolean animate) {
+        if (!isDrawerView(drawerView)) {
+            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
+        }
+
+        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
+        if (mFirstLayout) {
+            lp.onScreen = 1.f;
+            lp.openState = LayoutParams.FLAG_IS_OPENED;
+
+            updateChildrenImportantForAccessibility(drawerView, true);
+        } else if (animate) {
+            lp.openState |= LayoutParams.FLAG_IS_OPENING;
+
+            if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
+                mLeftDragger.smoothSlideViewTo(drawerView, 0, drawerView.getTop());
+            } else {
+                mRightDragger.smoothSlideViewTo(drawerView, getWidth() - drawerView.getWidth(),
+                        drawerView.getTop());
+            }
+        } else {
+            moveDrawerToOffset(drawerView, 1.f);
+            updateDrawerState(lp.gravity, STATE_IDLE, drawerView);
+            drawerView.setVisibility(VISIBLE);
+        }
+        invalidate();
+    }
+
+    /**
+     * Open the specified drawer by animating it out of view.
+     *
+     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
+     *                GravityCompat.START or GravityCompat.END may also be used.
+     */
+    public void openDrawer(@EdgeGravity int gravity) {
+        openDrawer(gravity, true);
+    }
+
+    /**
+     * Open the specified drawer.
+     *
+     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
+     *                GravityCompat.START or GravityCompat.END may also be used.
+     * @param animate Whether opening of the drawer should be animated.
+     */
+    public void openDrawer(@EdgeGravity int gravity, boolean animate) {
+        final View drawerView = findDrawerWithGravity(gravity);
+        if (drawerView == null) {
+            throw new IllegalArgumentException("No drawer view found with gravity "
+                    + gravityToString(gravity));
+        }
+        openDrawer(drawerView, animate);
+    }
+
+    /**
+     * Close the specified drawer view by animating it into view.
+     *
+     * @param drawerView Drawer view to close
+     */
+    public void closeDrawer(@NonNull View drawerView) {
+        closeDrawer(drawerView, true);
+    }
+
+    /**
+     * Close the specified drawer view.
+     *
+     * @param drawerView Drawer view to close
+     * @param animate Whether closing of the drawer should be animated.
+     */
+    public void closeDrawer(@NonNull View drawerView, boolean animate) {
+        if (!isDrawerView(drawerView)) {
+            throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
+        }
+
+        final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
+        if (mFirstLayout) {
+            lp.onScreen = 0.f;
+            lp.openState = 0;
+        } else if (animate) {
+            lp.openState |= LayoutParams.FLAG_IS_CLOSING;
+
+            if (checkDrawerViewAbsoluteGravity(drawerView, Gravity.LEFT)) {
+                mLeftDragger.smoothSlideViewTo(drawerView, -drawerView.getWidth(),
+                        drawerView.getTop());
+            } else {
+                mRightDragger.smoothSlideViewTo(drawerView, getWidth(), drawerView.getTop());
+            }
+        } else {
+            moveDrawerToOffset(drawerView, 0.f);
+            updateDrawerState(lp.gravity, STATE_IDLE, drawerView);
+            drawerView.setVisibility(INVISIBLE);
+        }
+        invalidate();
+    }
+
+    /**
+     * Close the specified drawer by animating it out of view.
+     *
+     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
+     *                GravityCompat.START or GravityCompat.END may also be used.
+     */
+    public void closeDrawer(@EdgeGravity int gravity) {
+        closeDrawer(gravity, true);
+    }
+
+    /**
+     * Close the specified drawer.
+     *
+     * @param gravity Gravity.LEFT to move the left drawer or Gravity.RIGHT for the right.
+     *                GravityCompat.START or GravityCompat.END may also be used.
+     * @param animate Whether closing of the drawer should be animated.
+     */
+    public void closeDrawer(@EdgeGravity int gravity, boolean animate) {
+        final View drawerView = findDrawerWithGravity(gravity);
+        if (drawerView == null) {
+            throw new IllegalArgumentException("No drawer view found with gravity "
+                    + gravityToString(gravity));
+        }
+        closeDrawer(drawerView, animate);
+    }
+
+    /**
+     * Check if the given drawer view is currently in an open state.
+     * To be considered "open" the drawer must have settled into its fully
+     * visible state. To check for partial visibility use
+     * {@link #isDrawerVisible(android.view.View)}.
+     *
+     * @param drawer Drawer view to check
+     * @return true if the given drawer view is in an open state
+     * @see #isDrawerVisible(android.view.View)
+     */
+    public boolean isDrawerOpen(@NonNull View drawer) {
+        if (!isDrawerView(drawer)) {
+            throw new IllegalArgumentException("View " + drawer + " is not a drawer");
+        }
+        LayoutParams drawerLp = (LayoutParams) drawer.getLayoutParams();
+        return (drawerLp.openState & LayoutParams.FLAG_IS_OPENED) == 1;
+    }
+
+    /**
+     * Check if the given drawer view is currently in an open state.
+     * To be considered "open" the drawer must have settled into its fully
+     * visible state. If there is no drawer with the given gravity this method
+     * will return false.
+     *
+     * @param drawerGravity Gravity of the drawer to check
+     * @return true if the given drawer view is in an open state
+     */
+    public boolean isDrawerOpen(@EdgeGravity int drawerGravity) {
+        final View drawerView = findDrawerWithGravity(drawerGravity);
+        if (drawerView != null) {
+            return isDrawerOpen(drawerView);
+        }
+        return false;
+    }
+
+    /**
+     * Check if a given drawer view is currently visible on-screen. The drawer
+     * may be only peeking onto the screen, fully extended, or anywhere inbetween.
+     *
+     * @param drawer Drawer view to check
+     * @return true if the given drawer is visible on-screen
+     * @see #isDrawerOpen(android.view.View)
+     */
+    public boolean isDrawerVisible(@NonNull View drawer) {
+        if (!isDrawerView(drawer)) {
+            throw new IllegalArgumentException("View " + drawer + " is not a drawer");
+        }
+        return ((LayoutParams) drawer.getLayoutParams()).onScreen > 0;
+    }
+
+    /**
+     * Check if a given drawer view is currently visible on-screen. The drawer
+     * may be only peeking onto the screen, fully extended, or anywhere in between.
+     * If there is no drawer with the given gravity this method will return false.
+     *
+     * @param drawerGravity Gravity of the drawer to check
+     * @return true if the given drawer is visible on-screen
+     */
+    public boolean isDrawerVisible(@EdgeGravity int drawerGravity) {
+        final View drawerView = findDrawerWithGravity(drawerGravity);
+        if (drawerView != null) {
+            return isDrawerVisible(drawerView);
+        }
+        return false;
+    }
+
+    private boolean hasPeekingDrawer() {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+            if (lp.isPeeking) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams
+                ? new LayoutParams((LayoutParams) p)
+                : p instanceof ViewGroup.MarginLayoutParams
+                ? new LayoutParams((MarginLayoutParams) p)
+                : new LayoutParams(p);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof LayoutParams && super.checkLayoutParams(p);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
+            return;
+        }
+
+        // Only the views in the open drawers are focusables. Add normal child views when
+        // no drawers are opened.
+        final int childCount = getChildCount();
+        boolean isDrawerOpen = false;
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (isDrawerView(child)) {
+                if (isDrawerOpen(child)) {
+                    isDrawerOpen = true;
+                    child.addFocusables(views, direction, focusableMode);
+                }
+            } else {
+                mNonDrawerViews.add(child);
+            }
+        }
+
+        if (!isDrawerOpen) {
+            final int nonDrawerViewsCount = mNonDrawerViews.size();
+            for (int i = 0; i < nonDrawerViewsCount; ++i) {
+                final View child = mNonDrawerViews.get(i);
+                if (child.getVisibility() == View.VISIBLE) {
+                    child.addFocusables(views, direction, focusableMode);
+                }
+            }
+        }
+
+        mNonDrawerViews.clear();
+    }
+
+    private boolean hasVisibleDrawer() {
+        return findVisibleDrawer() != null;
+    }
+
+    View findVisibleDrawer() {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (isDrawerView(child) && isDrawerVisible(child)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    void cancelChildViewTouch() {
+        // Cancel child touches
+        if (!mChildrenCanceledTouch) {
+            final long now = SystemClock.uptimeMillis();
+            final MotionEvent cancelEvent = MotionEvent.obtain(now, now,
+                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                getChildAt(i).dispatchTouchEvent(cancelEvent);
+            }
+            cancelEvent.recycle();
+            mChildrenCanceledTouch = true;
+        }
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK && hasVisibleDrawer()) {
+            event.startTracking();
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            final View visibleDrawer = findVisibleDrawer();
+            if (visibleDrawer != null && getDrawerLockMode(visibleDrawer) == LOCK_MODE_UNLOCKED) {
+                closeDrawers();
+            }
+            return visibleDrawer != null;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            super.onRestoreInstanceState(state);
+            return;
+        }
+
+        final SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (ss.openDrawerGravity != Gravity.NO_GRAVITY) {
+            final View toOpen = findDrawerWithGravity(ss.openDrawerGravity);
+            if (toOpen != null) {
+                openDrawer(toOpen);
+            }
+        }
+
+        if (ss.lockModeLeft != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeLeft, Gravity.LEFT);
+        }
+        if (ss.lockModeRight != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeRight, Gravity.RIGHT);
+        }
+        if (ss.lockModeStart != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeStart, GravityCompat.START);
+        }
+        if (ss.lockModeEnd != LOCK_MODE_UNDEFINED) {
+            setDrawerLockMode(ss.lockModeEnd, GravityCompat.END);
+        }
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        final Parcelable superState = super.onSaveInstanceState();
+        final SavedState ss = new SavedState(superState);
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            // Is the current child fully opened (that is, not closing)?
+            boolean isOpenedAndNotClosing = (lp.openState == LayoutParams.FLAG_IS_OPENED);
+            // Is the current child opening?
+            boolean isClosedAndOpening = (lp.openState == LayoutParams.FLAG_IS_OPENING);
+            if (isOpenedAndNotClosing || isClosedAndOpening) {
+                // If one of the conditions above holds, save the child's gravity
+                // so that we open that child during state restore.
+                ss.openDrawerGravity = lp.gravity;
+                break;
+            }
+        }
+
+        ss.lockModeLeft = mLockModeLeft;
+        ss.lockModeRight = mLockModeRight;
+        ss.lockModeStart = mLockModeStart;
+        ss.lockModeEnd = mLockModeEnd;
+
+        return ss;
+    }
+
+    @Override
+    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+        super.addView(child, index, params);
+
+        final View openDrawer = findOpenDrawer();
+        if (openDrawer != null || isDrawerView(child)) {
+            // A drawer is already open or the new view is a drawer, so the
+            // new view should start out hidden.
+            ViewCompat.setImportantForAccessibility(child,
+                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+        } else {
+            // Otherwise this is a content view and no drawer is open, so the
+            // new view should start out visible.
+            ViewCompat.setImportantForAccessibility(child,
+                    ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+
+        // We only need a delegate here if the framework doesn't understand
+        // NO_HIDE_DESCENDANTS importance.
+        if (!CAN_HIDE_DESCENDANTS) {
+            ViewCompat.setAccessibilityDelegate(child, mChildAccessibilityDelegate);
+        }
+    }
+
+    static boolean includeChildForAccessibility(View child) {
+        // If the child is not important for accessibility we make
+        // sure this hides the entire subtree rooted at it as the
+        // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDATS is not
+        // supported on older platforms but we want to hide the entire
+        // content and not opened drawers if a drawer is opened.
+        return ViewCompat.getImportantForAccessibility(child)
+                != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
+                    && ViewCompat.getImportantForAccessibility(child)
+                != ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO;
+    }
+
+    /**
+     * State persisted across instances
+     */
+    protected static class SavedState extends AbsSavedState {
+        int openDrawerGravity = Gravity.NO_GRAVITY;
+        @LockMode int lockModeLeft;
+        @LockMode int lockModeRight;
+        @LockMode int lockModeStart;
+        @LockMode int lockModeEnd;
+
+        public SavedState(@NonNull Parcel in, @Nullable ClassLoader loader) {
+            super(in, loader);
+            openDrawerGravity = in.readInt();
+            lockModeLeft = in.readInt();
+            lockModeRight = in.readInt();
+            lockModeStart = in.readInt();
+            lockModeEnd = in.readInt();
+        }
+
+        public SavedState(@NonNull Parcelable superState) {
+            super(superState);
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(openDrawerGravity);
+            dest.writeInt(lockModeLeft);
+            dest.writeInt(lockModeRight);
+            dest.writeInt(lockModeStart);
+            dest.writeInt(lockModeEnd);
+        }
+
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
+
+            @Override
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in, null);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    private class ViewDragCallback extends ViewDragHelper.Callback {
+        private final int mAbsGravity;
+        private ViewDragHelper mDragger;
+
+        private final Runnable mPeekRunnable = new Runnable() {
+            @Override public void run() {
+                peekDrawer();
+            }
+        };
+
+        ViewDragCallback(int gravity) {
+            mAbsGravity = gravity;
+        }
+
+        public void setDragger(ViewDragHelper dragger) {
+            mDragger = dragger;
+        }
+
+        public void removeCallbacks() {
+            DrawerLayout.this.removeCallbacks(mPeekRunnable);
+        }
+
+        @Override
+        public boolean tryCaptureView(View child, int pointerId) {
+            // Only capture views where the gravity matches what we're looking for.
+            // This lets us use two ViewDragHelpers, one for each side drawer.
+            return isDrawerView(child) && checkDrawerViewAbsoluteGravity(child, mAbsGravity)
+                    && getDrawerLockMode(child) == LOCK_MODE_UNLOCKED;
+        }
+
+        @Override
+        public void onViewDragStateChanged(int state) {
+            updateDrawerState(mAbsGravity, state, mDragger.getCapturedView());
+        }
+
+        @Override
+        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
+            float offset;
+            final int childWidth = changedView.getWidth();
+
+            // This reverses the positioning shown in onLayout.
+            if (checkDrawerViewAbsoluteGravity(changedView, Gravity.LEFT)) {
+                offset = (float) (childWidth + left) / childWidth;
+            } else {
+                final int width = getWidth();
+                offset = (float) (width - left) / childWidth;
+            }
+            setDrawerViewOffset(changedView, offset);
+            changedView.setVisibility(offset == 0 ? INVISIBLE : VISIBLE);
+            invalidate();
+        }
+
+        @Override
+        public void onViewCaptured(View capturedChild, int activePointerId) {
+            final LayoutParams lp = (LayoutParams) capturedChild.getLayoutParams();
+            lp.isPeeking = false;
+
+            closeOtherDrawer();
+        }
+
+        private void closeOtherDrawer() {
+            final int otherGrav = mAbsGravity == Gravity.LEFT ? Gravity.RIGHT : Gravity.LEFT;
+            final View toClose = findDrawerWithGravity(otherGrav);
+            if (toClose != null) {
+                closeDrawer(toClose);
+            }
+        }
+
+        @Override
+        public void onViewReleased(View releasedChild, float xvel, float yvel) {
+            // Offset is how open the drawer is, therefore left/right values
+            // are reversed from one another.
+            final float offset = getDrawerViewOffset(releasedChild);
+            final int childWidth = releasedChild.getWidth();
+
+            int left;
+            if (checkDrawerViewAbsoluteGravity(releasedChild, Gravity.LEFT)) {
+                left = xvel > 0 || (xvel == 0 && offset > 0.5f) ? 0 : -childWidth;
+            } else {
+                final int width = getWidth();
+                left = xvel < 0 || (xvel == 0 && offset > 0.5f) ? width - childWidth : width;
+            }
+
+            mDragger.settleCapturedViewAt(left, releasedChild.getTop());
+            invalidate();
+        }
+
+        @Override
+        public void onEdgeTouched(int edgeFlags, int pointerId) {
+            postDelayed(mPeekRunnable, PEEK_DELAY);
+        }
+
+        void peekDrawer() {
+            final View toCapture;
+            final int childLeft;
+            final int peekDistance = mDragger.getEdgeSize();
+            final boolean leftEdge = mAbsGravity == Gravity.LEFT;
+            if (leftEdge) {
+                toCapture = findDrawerWithGravity(Gravity.LEFT);
+                childLeft = (toCapture != null ? -toCapture.getWidth() : 0) + peekDistance;
+            } else {
+                toCapture = findDrawerWithGravity(Gravity.RIGHT);
+                childLeft = getWidth() - peekDistance;
+            }
+            // Only peek if it would mean making the drawer more visible and the drawer isn't locked
+            if (toCapture != null && ((leftEdge && toCapture.getLeft() < childLeft)
+                    || (!leftEdge && toCapture.getLeft() > childLeft))
+                    && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
+                final LayoutParams lp = (LayoutParams) toCapture.getLayoutParams();
+                mDragger.smoothSlideViewTo(toCapture, childLeft, toCapture.getTop());
+                lp.isPeeking = true;
+                invalidate();
+
+                closeOtherDrawer();
+
+                cancelChildViewTouch();
+            }
+        }
+
+        @Override
+        public boolean onEdgeLock(int edgeFlags) {
+            if (ALLOW_EDGE_LOCK) {
+                final View drawer = findDrawerWithGravity(mAbsGravity);
+                if (drawer != null && !isDrawerOpen(drawer)) {
+                    closeDrawer(drawer);
+                }
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
+            final View toCapture;
+            if ((edgeFlags & ViewDragHelper.EDGE_LEFT) == ViewDragHelper.EDGE_LEFT) {
+                toCapture = findDrawerWithGravity(Gravity.LEFT);
+            } else {
+                toCapture = findDrawerWithGravity(Gravity.RIGHT);
+            }
+
+            if (toCapture != null && getDrawerLockMode(toCapture) == LOCK_MODE_UNLOCKED) {
+                mDragger.captureChildView(toCapture, pointerId);
+            }
+        }
+
+        @Override
+        public int getViewHorizontalDragRange(View child) {
+            return isDrawerView(child) ? child.getWidth() : 0;
+        }
+
+        @Override
+        public int clampViewPositionHorizontal(View child, int left, int dx) {
+            if (checkDrawerViewAbsoluteGravity(child, Gravity.LEFT)) {
+                return Math.max(-child.getWidth(), Math.min(left, 0));
+            } else {
+                final int width = getWidth();
+                return Math.max(width - child.getWidth(), Math.min(left, width));
+            }
+        }
+
+        @Override
+        public int clampViewPositionVertical(View child, int top, int dy) {
+            return child.getTop();
+        }
+    }
+
+    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
+        private static final int FLAG_IS_OPENED = 0x1;
+        private static final int FLAG_IS_OPENING = 0x2;
+        private static final int FLAG_IS_CLOSING = 0x4;
+
+        public int gravity = Gravity.NO_GRAVITY;
+        float onScreen;
+        boolean isPeeking;
+        int openState;
+
+        public LayoutParams(@NonNull Context c, @Nullable AttributeSet attrs) {
+            super(c, attrs);
+
+            final TypedArray a = c.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
+            this.gravity = a.getInt(0, Gravity.NO_GRAVITY);
+            a.recycle();
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(int width, int height, int gravity) {
+            this(width, height);
+            this.gravity = gravity;
+        }
+
+        public LayoutParams(@NonNull LayoutParams source) {
+            super(source);
+            this.gravity = source.gravity;
+        }
+
+        public LayoutParams(@NonNull ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(@NonNull ViewGroup.MarginLayoutParams source) {
+            super(source);
+        }
+    }
+
+    class AccessibilityDelegate extends AccessibilityDelegateCompat {
+        private final Rect mTmpRect = new Rect();
+
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
+            if (CAN_HIDE_DESCENDANTS) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+            } else {
+                // Obtain a node for the host, then manually generate the list
+                // of children to only include non-obscured views.
+                final AccessibilityNodeInfoCompat superNode =
+                        AccessibilityNodeInfoCompat.obtain(info);
+                super.onInitializeAccessibilityNodeInfo(host, superNode);
+
+                info.setSource(host);
+                final ViewParent parent = ViewCompat.getParentForAccessibility(host);
+                if (parent instanceof View) {
+                    info.setParent((View) parent);
+                }
+                copyNodeInfoNoChildren(info, superNode);
+                superNode.recycle();
+
+                addChildrenForAccessibility(info, (ViewGroup) host);
+            }
+
+            info.setClassName(DrawerLayout.class.getName());
+
+            // This view reports itself as focusable so that it can intercept
+            // the back button, but we should prevent this view from reporting
+            // itself as focusable to accessibility services.
+            info.setFocusable(false);
+            info.setFocused(false);
+            info.removeAction(AccessibilityActionCompat.ACTION_FOCUS);
+            info.removeAction(AccessibilityActionCompat.ACTION_CLEAR_FOCUS);
+        }
+
+        @Override
+        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+            super.onInitializeAccessibilityEvent(host, event);
+
+            event.setClassName(DrawerLayout.class.getName());
+        }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
+            // Special case to handle window state change events. As far as
+            // accessibility services are concerned, state changes from
+            // DrawerLayout invalidate the entire contents of the screen (like
+            // an Activity or Dialog) and they should announce the title of the
+            // new content.
+            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+                final List<CharSequence> eventText = event.getText();
+                final View visibleDrawer = findVisibleDrawer();
+                if (visibleDrawer != null) {
+                    final int edgeGravity = getDrawerViewAbsoluteGravity(visibleDrawer);
+                    final CharSequence title = getDrawerTitle(edgeGravity);
+                    if (title != null) {
+                        eventText.add(title);
+                    }
+                }
+
+                return true;
+            }
+
+            return super.dispatchPopulateAccessibilityEvent(host, event);
+        }
+
+        @Override
+        public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+                AccessibilityEvent event) {
+            if (CAN_HIDE_DESCENDANTS || includeChildForAccessibility(child)) {
+                return super.onRequestSendAccessibilityEvent(host, child, event);
+            }
+            return false;
+        }
+
+        private void addChildrenForAccessibility(AccessibilityNodeInfoCompat info, ViewGroup v) {
+            final int childCount = v.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                final View child = v.getChildAt(i);
+                if (includeChildForAccessibility(child)) {
+                    info.addChild(child);
+                }
+            }
+        }
+
+        /**
+         * This should really be in AccessibilityNodeInfoCompat, but there unfortunately
+         * seem to be a few elements that are not easily cloneable using the underlying API.
+         * Leave it private here as it's not general-purpose useful.
+         */
+        private void copyNodeInfoNoChildren(AccessibilityNodeInfoCompat dest,
+                AccessibilityNodeInfoCompat src) {
+            final Rect rect = mTmpRect;
+
+            src.getBoundsInParent(rect);
+            dest.setBoundsInParent(rect);
+
+            src.getBoundsInScreen(rect);
+            dest.setBoundsInScreen(rect);
+
+            dest.setVisibleToUser(src.isVisibleToUser());
+            dest.setPackageName(src.getPackageName());
+            dest.setClassName(src.getClassName());
+            dest.setContentDescription(src.getContentDescription());
+
+            dest.setEnabled(src.isEnabled());
+            dest.setClickable(src.isClickable());
+            dest.setFocusable(src.isFocusable());
+            dest.setFocused(src.isFocused());
+            dest.setAccessibilityFocused(src.isAccessibilityFocused());
+            dest.setSelected(src.isSelected());
+            dest.setLongClickable(src.isLongClickable());
+
+            dest.addAction(src.getActions());
+        }
+    }
+
+    static final class ChildAccessibilityDelegate extends AccessibilityDelegateCompat {
+        @Override
+        public void onInitializeAccessibilityNodeInfo(View child,
+                AccessibilityNodeInfoCompat info) {
+            super.onInitializeAccessibilityNodeInfo(child, info);
+
+            if (!includeChildForAccessibility(child)) {
+                // If we are ignoring the sub-tree rooted at the child,
+                // break the connection to the rest of the node tree.
+                // For details refer to includeChildForAccessibility.
+                info.setParent(null);
+            }
+        }
+    }
+}
diff --git a/dynamic-animation/Android.mk b/dynamic-animation/Android.mk
deleted file mode 100644
index 98e8f45..0000000
--- a/dynamic-animation/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-dynamic-animation
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/dynamic-animation/AndroidManifest.xml b/dynamic-animation/AndroidManifest.xml
deleted file mode 100644
index bfe97cc..0000000
--- a/dynamic-animation/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.dynamicanimation">
-    <uses-sdk android:minSdkVersion="16"/>
-</manifest>
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 10e49e0..451e874 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -22,5 +22,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "Physics-based animation in support library, where the animations are driven by physics force. You can use this Animation library to create smooth and realistic animations."
-    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/dynamic-animation/tests/AndroidManifest.xml b/dynamic-animation/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from dynamic-animation/tests/AndroidManifest.xml
rename to dynamic-animation/src/androidTest/AndroidManifest.xml
diff --git a/dynamic-animation/tests/src/android/support/dynamicanimation/tests/AnimationActivity.java b/dynamic-animation/src/androidTest/java/android/support/dynamicanimation/tests/AnimationActivity.java
similarity index 100%
rename from dynamic-animation/tests/src/android/support/dynamicanimation/tests/AnimationActivity.java
rename to dynamic-animation/src/androidTest/java/android/support/dynamicanimation/tests/AnimationActivity.java
diff --git a/dynamic-animation/tests/src/android/support/dynamicanimation/tests/FlingTests.java b/dynamic-animation/src/androidTest/java/android/support/dynamicanimation/tests/FlingTests.java
similarity index 100%
rename from dynamic-animation/tests/src/android/support/dynamicanimation/tests/FlingTests.java
rename to dynamic-animation/src/androidTest/java/android/support/dynamicanimation/tests/FlingTests.java
diff --git a/dynamic-animation/tests/src/android/support/dynamicanimation/tests/SpringTests.java b/dynamic-animation/src/androidTest/java/android/support/dynamicanimation/tests/SpringTests.java
similarity index 100%
rename from dynamic-animation/tests/src/android/support/dynamicanimation/tests/SpringTests.java
rename to dynamic-animation/src/androidTest/java/android/support/dynamicanimation/tests/SpringTests.java
diff --git a/dynamic-animation/tests/res/layout/anim_layout.xml b/dynamic-animation/src/androidTest/res/layout/anim_layout.xml
similarity index 100%
rename from dynamic-animation/tests/res/layout/anim_layout.xml
rename to dynamic-animation/src/androidTest/res/layout/anim_layout.xml
diff --git a/dynamic-animation/src/main/AndroidManifest.xml b/dynamic-animation/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..0103fd5
--- /dev/null
+++ b/dynamic-animation/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.dynamicanimation"/>
diff --git a/dynamic-animation/tests/NO_DOCS b/dynamic-animation/tests/NO_DOCS
deleted file mode 100644
index 4dad694..0000000
--- a/dynamic-animation/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/emoji/Android.mk b/emoji/Android.mk
deleted file mode 100644
index 337f5b9..0000000
--- a/emoji/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/emoji/appcompat/Android.mk b/emoji/appcompat/Android.mk
deleted file mode 100644
index 0ef8cb7..0000000
--- a/emoji/appcompat/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-emoji-appcompat \
-#       android-support-v7-appcompat \
-#       android-support-emoji \
-#       android-support-compat
-#
-# in their makefiles to include the resources and their dependencies in their package.
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-emoji-appcompat
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v7-appcompat \
-    android-support-emoji \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/emoji/appcompat/AndroidManifest.xml b/emoji/appcompat/AndroidManifest.xml
deleted file mode 100644
index bf83391..0000000
--- a/emoji/appcompat/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.text.emoji.appcompat">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
index a4aaff2..8a75f66 100644
--- a/emoji/appcompat/build.gradle
+++ b/emoji/appcompat/build.gradle
@@ -33,5 +33,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "EmojiCompat Widgets for AppCompat integration"
-    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/emoji/appcompat/src/main/AndroidManifest.xml b/emoji/appcompat/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..cdc4524
--- /dev/null
+++ b/emoji/appcompat/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest package="android.support.text.emoji.appcompat"/>
diff --git a/emoji/bundled/Android.mk b/emoji/bundled/Android.mk
deleted file mode 100644
index c5c1ac9..0000000
--- a/emoji/bundled/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-emoji-bundled \
-#       android-support-emoji \
-#       android-support-compat
-#
-# in their makefiles to include the resources and their dependencies in their package.
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-emoji-bundled
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-emoji \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/emoji/bundled/AndroidManifest.xml b/emoji/bundled/AndroidManifest.xml
deleted file mode 100644
index 01c1713..0000000
--- a/emoji/bundled/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.text.emoji.bundled">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
\ No newline at end of file
diff --git a/emoji/bundled/build.gradle b/emoji/bundled/build.gradle
index a2760d3..7c3a76a 100644
--- a/emoji/bundled/build.gradle
+++ b/emoji/bundled/build.gradle
@@ -36,5 +36,4 @@
         name = "Unicode, Inc. License"
         url = "http://www.unicode.org/copyright.html#License"
     }
-    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/emoji/bundled/src/main/AndroidManifest.xml b/emoji/bundled/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..848c6d5
--- /dev/null
+++ b/emoji/bundled/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.text.emoji.bundled"/>
\ No newline at end of file
diff --git a/emoji/core/Android.mk b/emoji/core/Android.mk
deleted file mode 100644
index 89426f0..0000000
--- a/emoji/core/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-emoji \
-#       android-support-compat
-#
-# in their makefiles to include the resources and their dependencies in their package.
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-emoji
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    noto-emoji-compat-java
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/emoji/core/AndroidManifest.xml b/emoji/core/AndroidManifest.xml
index d153151..8b52e92 100644
--- a/emoji/core/AndroidManifest.xml
+++ b/emoji/core/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.text.emoji">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.text.emoji"/>
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index 8d470f0..449ebb1 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -44,11 +44,6 @@
         }
 
         androidTest {
-            // We use a non-standard test directory structure.
-            root 'tests'
-            java.srcDir 'tests/src'
-            res.srcDir 'tests/res'
-            manifest.srcFile 'tests/AndroidManifest.xml'
             assets {
                 srcDirs = [new File(fontDir, "font").getAbsolutePath(),
                            new File(fontDir, "supported-emojis").getAbsolutePath()]
diff --git a/emoji/core/tests/AndroidManifest.xml b/emoji/core/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from emoji/core/tests/AndroidManifest.xml
rename to emoji/core/src/androidTest/AndroidManifest.xml
diff --git a/emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/AllEmojisTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/AllEmojisTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/AllEmojisTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/ConfigTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/ConfigTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/ConfigTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/ConfigTest.java
diff --git a/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiCompatTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiCompatTest.java
new file mode 100644
index 0000000..5d14876
--- /dev/null
+++ b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiCompatTest.java
@@ -0,0 +1,850 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.text.emoji;
+
+import static android.support.text.emoji.TestConfigBuilder.TestConfig;
+import static android.support.text.emoji.TestConfigBuilder.WaitingDataLoader;
+import static android.support.text.emoji.TestConfigBuilder.config;
+import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_EMOJI_STYLE;
+import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_TEXT_STYLE;
+import static android.support.text.emoji.util.Emoji.CHAR_DIGIT;
+import static android.support.text.emoji.util.Emoji.CHAR_FITZPATRICK;
+import static android.support.text.emoji.util.Emoji.CHAR_VS_EMOJI;
+import static android.support.text.emoji.util.Emoji.CHAR_VS_TEXT;
+import static android.support.text.emoji.util.Emoji.DEFAULT_TEXT_STYLE;
+import static android.support.text.emoji.util.Emoji.EMOJI_ASTERISK_KEYCAP;
+import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES;
+import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES_KEYCAP;
+import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_KEYCAP;
+import static android.support.text.emoji.util.Emoji.EMOJI_FLAG;
+import static android.support.text.emoji.util.Emoji.EMOJI_GENDER;
+import static android.support.text.emoji.util.Emoji.EMOJI_GENDER_WITHOUT_VS;
+import static android.support.text.emoji.util.Emoji.EMOJI_REGIONAL_SYMBOL;
+import static android.support.text.emoji.util.Emoji.EMOJI_SINGLE_CODEPOINT;
+import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER;
+import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_TYPE_ONE;
+import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_WITH_VS;
+import static android.support.text.emoji.util.Emoji.EMOJI_UNKNOWN_FLAG;
+import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiAt;
+import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
+import static android.support.text.emoji.util.KeyboardUtil.del;
+
+import static org.hamcrest.Matchers.instanceOf;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat.Config;
+import android.support.text.emoji.util.Emoji.EmojiMapping;
+import android.support.text.emoji.util.TestString;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
+import android.text.SpannedString;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiCompatTest {
+
+    @Before
+    public void setup() {
+        EmojiCompat.reset(config());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testGet_throwsException() {
+        EmojiCompat.reset((EmojiCompat) null);
+        EmojiCompat.get();
+    }
+
+    @Test
+    public void testProcess_doesNothing_withNullCharSequence() {
+        assertNull(EmojiCompat.get().process(null));
+    }
+
+    @Test
+    public void testProcess_returnsEmptySpanned_withEmptyString() {
+        final CharSequence charSequence = EmojiCompat.get().process("");
+        assertNotNull(charSequence);
+        assertEquals(0, charSequence.length());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+
+    @SuppressLint("Range")
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withNegativeStartValue() {
+        EmojiCompat.get().process("a", -1, 1);
+    }
+
+    @SuppressLint("Range")
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withNegativeEndValue() {
+        EmojiCompat.get().process("a", 1, -1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withStartSmallerThanEndValue() {
+        EmojiCompat.get().process("aa", 1, 0);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withStartGreaterThanLength() {
+        EmojiCompat.get().process("a", 2, 2);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_withEndGreaterThanLength() {
+        EmojiCompat.get().process("a", 0, 2);
+    }
+
+    @Test
+    public void testProcessWithStartEnd_withNoOpValues() {
+        final Spannable spannable = new SpannableString(new TestString('a')
+                .withPrefix().withSuffix().toString());
+        // early return check
+        assertSame(spannable, EmojiCompat.get().process(spannable, 0, 0));
+        assertSame(spannable, EmojiCompat.get().process(spannable, 1, 1));
+        assertSame(spannable, EmojiCompat.get().process(spannable, spannable.length(),
+                spannable.length()));
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmojiSpan() {
+        final String string = "abc";
+        final CharSequence charSequence = EmojiCompat.get().process(string);
+        assertNotNull(charSequence);
+        assertEquals(string, charSequence.toString());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testProcess_returnsSameCharSequence_pre19() {
+        assertNull(EmojiCompat.get().process(null));
+
+        CharSequence testString = "abc";
+        assertSame(testString, EmojiCompat.get().process(testString));
+
+        testString = new SpannableString("abc");
+        assertSame(testString, EmojiCompat.get().process(testString));
+
+        testString = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
+        assertSame(testString, EmojiCompat.get().process(testString));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsSingleCodePointEmoji() {
+        assertCodePointMatch(EMOJI_SINGLE_CODEPOINT);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsFlagEmoji() {
+        assertCodePointMatch(EMOJI_FLAG);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsUnknownFlagEmoji() {
+        assertCodePointMatch(EMOJI_UNKNOWN_FLAG);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsRegionalIndicatorSymbol() {
+        assertCodePointMatch(EMOJI_REGIONAL_SYMBOL);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsKeyCapEmoji() {
+        assertCodePointMatch(EMOJI_DIGIT_KEYCAP);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_doesNotAddEmojiForNumbers() {
+        assertCodePointDoesNotMatch(new int[] {CHAR_DIGIT});
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_doesNotAddEmojiForNumbers_1() {
+        final TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).append('1', 'f');
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiCount(1));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsVariantSelectorEmoji() {
+        assertCodePointMatch(EMOJI_DIGIT_ES);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_doesNotAddVariantSelectorTextStyle() {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT, CHAR_VS_TEXT});
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsVariantSelectorAndKeyCapEmoji() {
+        assertCodePointMatch(EMOJI_DIGIT_ES_KEYCAP);
+    }
+
+    @Test
+    public void testProcess_doesNotAddEmoji_forVariantBaseWithoutSelector() {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT});
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsAsteriskKeyCapEmoji() {
+        assertCodePointMatch(EMOJI_ASTERISK_KEYCAP);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsSkinModifierEmoji() {
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER);
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER_TYPE_ONE);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsSkinModifierEmoji_withVariantSelector() {
+        assertCodePointMatch(EMOJI_SKIN_MODIFIER_WITH_VS);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsSkinModifierEmoji_270c_withVariantSelector() {
+        // 0x270c is a Standardized Variant Base, Emoji Modifier Base and also Emoji
+        // therefore it is different than i.e. 0x1f3c3. The code actually failed for this test
+        // at first.
+        assertCodePointMatch(0xF0734, new int[]{0x270C, CHAR_VS_EMOJI, CHAR_FITZPATRICK});
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_defaultStyleDoesNotAddSpan() {
+        assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_TEXT_STYLE});
+        assertCodePointMatch(DEFAULT_TEXT_STYLE);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_defaultEmojiStyle_withTextStyleVs() {
+        assertCodePointMatch(EMOJI_SINGLE_CODEPOINT.id(),
+                new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI});
+        assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT});
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_genderEmoji() {
+        assertCodePointMatch(EMOJI_GENDER);
+        assertCodePointMatch(EMOJI_GENDER_WITHOUT_VS);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_standardizedVariantEmojiExceptions() {
+        final int[][] exceptions = new int[][]{
+                {0x2600, 0xF034D},
+                {0x2601, 0xF0167},
+                {0x260E, 0xF034E},
+                {0x261D, 0xF0227},
+                {0x263A, 0xF02A6},
+                {0x2660, 0xF0350},
+                {0x2663, 0xF033F},
+                {0x2665, 0xF033B},
+                {0x2666, 0xF033E},
+                {0x270C, 0xF0079},
+                {0x2744, 0xF0342},
+                {0x2764, 0xF0362}
+        };
+
+        for (int i = 0; i < exceptions.length; i++) {
+            final int[] codepoints = new int[]{exceptions[i][0]};
+            assertCodePointMatch(exceptions[i][1], codepoints);
+        }
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsZwjEmoji() {
+        assertCodePointMatch(EMOJI_WITH_ZWJ);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_doesNotAddEmojiForNumbersAfterZwjEmo() {
+        TestString string = new TestString(EMOJI_WITH_ZWJ).append(0x20, 0x2B, 0x31)
+                .withSuffix().withPrefix();
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(),
+                string.emojiEndIndex() - 3));
+        assertThat(charSequence, hasEmojiCount(1));
+
+        string = new TestString(EMOJI_WITH_ZWJ).withSuffix().withPrefix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiCount(1));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_addsEmojiThatFollowsDigit() {
+        TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).prepend('N', '5');
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(EMOJI_SINGLE_CODEPOINT, string.emojiStartIndex() + 2,
+                string.emojiEndIndex()));
+        assertThat(charSequence, hasEmojiCount(1));
+
+        string = new TestString(EMOJI_WITH_ZWJ).prepend('N', '5');
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex() + 2,
+                string.emojiEndIndex()));
+        assertThat(charSequence, hasEmojiCount(1));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_withAppend() {
+        final Editable editable = new SpannableStringBuilder(new TestString('a').withPrefix()
+                .withSuffix().toString());
+        final int start = 1;
+        final int end = start + EMOJI_SINGLE_CODEPOINT.charCount();
+        editable.insert(start, new TestString(EMOJI_SINGLE_CODEPOINT).toString());
+        EmojiCompat.get().process(editable, start, end);
+        assertThat(editable, hasEmojiCount(1));
+        assertThat(editable, hasEmojiAt(EMOJI_SINGLE_CODEPOINT, start, end));
+    }
+
+    @Test
+    public void testProcess_doesNotCreateSpannable_ifNoEmoji() {
+        CharSequence processed = EmojiCompat.get().process("abc");
+        assertNotNull(processed);
+        assertThat(processed, instanceOf(String.class));
+
+        processed = EmojiCompat.get().process(new SpannedString("abc"));
+        assertNotNull(processed);
+        assertThat(processed, instanceOf(SpannedString.class));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_reprocess() {
+        final String string = new TestString(EMOJI_SINGLE_CODEPOINT)
+                .append(EMOJI_SINGLE_CODEPOINT)
+                .append(EMOJI_SINGLE_CODEPOINT)
+                .withPrefix().withSuffix().toString();
+
+        Spannable processed = (Spannable) EmojiCompat.get().process(string);
+        assertThat(processed, hasEmojiCount(3));
+
+        final EmojiSpan[] spans = processed.getSpans(0, processed.length(), EmojiSpan.class);
+        final Set<EmojiSpan> spanSet = new HashSet<>();
+        Collections.addAll(spanSet, spans);
+
+        processed = (Spannable) EmojiCompat.get().process(processed);
+        assertThat(processed, hasEmojiCount(3));
+        // new spans should be new instances
+        final EmojiSpan[] newSpans = processed.getSpans(0, processed.length(), EmojiSpan.class);
+        for (int i = 0; i < newSpans.length; i++) {
+            assertFalse(spanSet.contains(newSpans[i]));
+        }
+    }
+
+    @SuppressLint("Range")
+    @Test(expected = IllegalArgumentException.class)
+    public void testProcess_throwsException_withMaxEmojiSetToNegative() {
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+
+        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
+                -1 /*maxEmojiCount*/);
+
+        assertThat(processed, not(hasEmoji()));
+    }
+
+    @Test
+    public void testProcess_withMaxEmojiSetToZero() {
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+
+        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
+                0 /*maxEmojiCount*/);
+
+        assertThat(processed, not(hasEmoji()));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_withMaxEmojiSetToOne() {
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+
+        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
+                1 /*maxEmojiCount*/);
+
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_withMaxEmojiSetToLessThenExistingSpanCount() {
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT)
+                .append(EMOJI_SINGLE_CODEPOINT)
+                .append(EMOJI_SINGLE_CODEPOINT)
+                .toString();
+
+        // add 2 spans
+        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(), 2);
+
+        assertThat(processed, hasEmojiCount(2));
+
+        // use the Spannable with 2 spans, but use maxEmojiCount=1, start from the beginning of
+        // last (3rd) emoji
+        EmojiCompat.get().process(processed, original.length() - EMOJI_SINGLE_CODEPOINT.charCount(),
+                original.length(), 1 /*maxEmojiCount*/);
+
+        // expectation: there are still 2 emojis
+        assertThat(processed, hasEmojiCount(2));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_withMaxEmojiSet_withExistingEmojis() {
+        // test string with two emoji characters
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT)
+                .append(EMOJI_FLAG).toString();
+
+        // process and add 1 EmojiSpan, maxEmojiCount=1
+        CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
+                1 /*maxEmojiCount*/);
+
+        // assert that there is a single emoji
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed,
+                hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount()));
+
+        // call process again with the charSequence that already has 1 span
+        processed = EmojiCompat.get().process(processed, EMOJI_SINGLE_CODEPOINT.charCount(),
+                processed.length(), 1 /*maxEmojiCount*/);
+
+        // assert that there is still a single emoji
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed,
+                hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount()));
+
+        // make the same call, this time with maxEmojiCount=2
+        processed = EmojiCompat.get().process(processed, EMOJI_SINGLE_CODEPOINT.charCount(),
+                processed.length(), 2 /*maxEmojiCount*/);
+
+        // assert that it contains 2 emojis
+        assertThat(processed, hasEmojiCount(2));
+        assertThat(processed,
+                hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount()));
+        assertThat(processed,
+                hasEmojiAt(EMOJI_FLAG, EMOJI_SINGLE_CODEPOINT.charCount(),
+                        original.length()));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_withReplaceNonExistent_callsGlyphChecker() {
+        final Config config = TestConfigBuilder.config().setReplaceAll(true);
+        EmojiCompat.reset(config);
+
+        final EmojiProcessor.GlyphChecker glyphChecker = mock(EmojiProcessor.GlyphChecker.class);
+        when(glyphChecker.hasGlyph(any(CharSequence.class), anyInt(), anyInt())).thenReturn(true);
+        EmojiCompat.get().setGlyphChecker(glyphChecker);
+
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+
+        CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
+                Integer.MAX_VALUE /*maxEmojiCount*/, EmojiCompat.REPLACE_STRATEGY_NON_EXISTENT);
+
+        // when function overrides config level replaceAll, a call to GlyphChecker is expected.
+        verify(glyphChecker, times(1)).hasGlyph(any(CharSequence.class), anyInt(), anyInt());
+
+        // since replaceAll is false, there should be no EmojiSpans
+        assertThat(processed, not(hasEmoji()));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_withReplaceDefault_doesNotCallGlyphChecker() {
+        final Config config = TestConfigBuilder.config().setReplaceAll(true);
+        EmojiCompat.reset(config);
+
+        final EmojiProcessor.GlyphChecker glyphChecker = mock(EmojiProcessor.GlyphChecker.class);
+        when(glyphChecker.hasGlyph(any(CharSequence.class), anyInt(), anyInt())).thenReturn(true);
+        EmojiCompat.get().setGlyphChecker(glyphChecker);
+
+        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        // call without replaceAll, config value (true) should be used
+        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
+                Integer.MAX_VALUE /*maxEmojiCount*/, EmojiCompat.REPLACE_STRATEGY_DEFAULT);
+
+        // replaceAll=true should not call hasGlyph
+        verify(glyphChecker, times(0)).hasGlyph(any(CharSequence.class), anyInt(), anyInt());
+
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testProcess_withSpanned_replaceNonExistent() {
+        final Config config = TestConfigBuilder.config().setReplaceAll(false);
+        EmojiCompat.reset(config);
+
+        final String string = new TestString(EMOJI_SINGLE_CODEPOINT).append(
+                EMOJI_SINGLE_CODEPOINT).toString();
+        CharSequence processed = EmojiCompat.get().process(string, 0, string.length(),
+                Integer.MAX_VALUE, EmojiCompat.REPLACE_STRATEGY_ALL);
+
+        final SpannedString spanned = new SpannedString(processed);
+        assertThat(spanned, hasEmojiCount(2));
+
+        // mock GlyphChecker so that we can return true for hasGlyph
+        final EmojiProcessor.GlyphChecker glyphChecker = mock(EmojiProcessor.GlyphChecker.class);
+        when(glyphChecker.hasGlyph(any(CharSequence.class), anyInt(), anyInt())).thenReturn(true);
+        EmojiCompat.get().setGlyphChecker(glyphChecker);
+
+        processed = EmojiCompat.get().process(spanned, 0, spanned.length(),
+                Integer.MAX_VALUE, EmojiCompat.REPLACE_STRATEGY_NON_EXISTENT);
+
+        assertThat(processed, not(hasEmoji()));
+
+        // start: 1 char after the first emoji (in the second emoji)
+        processed = EmojiCompat.get().process(spanned, EMOJI_SINGLE_CODEPOINT.charCount() + 1,
+                spanned.length(), Integer.MAX_VALUE, EmojiCompat.REPLACE_STRATEGY_NON_EXISTENT);
+
+        assertThat(processed, hasEmojiCount(1));
+        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testHasEmojiGlyph_withNullCharSequence() {
+        EmojiCompat.get().hasEmojiGlyph(null);
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testHasEmojiGlyph_withMetadataVersion_withNullCharSequence() {
+        EmojiCompat.get().hasEmojiGlyph(null, Integer.MAX_VALUE);
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testHasEmojiGlyph_pre19() {
+        String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testHasEmojiGlyph_withMetaVersion_pre19() {
+        String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testHasEmojiGlyph_returnsTrueForExistingEmoji() {
+        final String sequence = new TestString(EMOJI_FLAG).toString();
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    public void testHasGlyph_returnsFalseForNonExistentEmoji() {
+        final String sequence = new TestString(EMOJI_FLAG).append(0x1111).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testHashEmojiGlyph_withDefaultEmojiStyles() {
+        String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
+
+        sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI}).toString();
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
+
+        sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT}).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testHashEmojiGlyph_withMetadataVersion() {
+        final String sequence = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
+        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, 0));
+        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE));
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testGetLoadState_returnsSuccess_pre19() {
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCEEDED);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testGetLoadState_returnsSuccessIfLoadSuccess() throws InterruptedException {
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(true /*success*/);
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING);
+
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCEEDED);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testGetLoadState_returnsFailIfLoadFail() throws InterruptedException {
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader(false/*fail*/);
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING);
+
+        metadataLoader.getLoaderLatch().countDown();
+        metadataLoader.getTestLatch().await();
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_FAILED);
+    }
+
+    @Test
+    public void testUpdateEditorInfoAttrs_doesNotSetKeyIfNotInitialized() {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.extras = new Bundle();
+
+        final WaitingDataLoader metadataLoader = new WaitingDataLoader();
+        final Config config = new TestConfig(metadataLoader);
+        EmojiCompat.reset(config);
+
+        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
+
+        final Bundle extras = editorInfo.extras;
+        assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY));
+        assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+
+        metadataLoader.getLoaderLatch().countDown();
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testGetAssetSignature() {
+        final String signature = EmojiCompat.get().getAssetSignature();
+        assertTrue(signature.isEmpty());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testGetAssetSignature_api19() {
+        final String signature = EmojiCompat.get().getAssetSignature();
+        assertNotNull(signature);
+        assertFalse(signature.isEmpty());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testUpdateEditorInfoAttrs_setsKeysIfInitialized() {
+        final EditorInfo editorInfo = new EditorInfo();
+        editorInfo.extras = new Bundle();
+        Config config = new TestConfig().setReplaceAll(false);
+        EmojiCompat.reset(config);
+        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
+
+        final Bundle extras = editorInfo.extras;
+        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY));
+        assertTrue(extras.getInt(EmojiCompat.EDITOR_INFO_METAVERSION_KEY) > 0);
+        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+        assertFalse(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+
+        config = new TestConfig().setReplaceAll(true);
+        EmojiCompat.reset(config);
+        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
+
+        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+        assertTrue(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testHandleDeleteSurroundingText_pre19() {
+        final TestString testString = new TestString(EMOJI_SINGLE_CODEPOINT);
+        final InputConnection inputConnection = mock(InputConnection.class);
+        final Editable editable = spy(new SpannableStringBuilder(testString.toString()));
+
+        Selection.setSelection(editable, testString.emojiEndIndex());
+
+        reset(editable);
+        reset(inputConnection);
+        verifyNoMoreInteractions(editable);
+        verifyNoMoreInteractions(inputConnection);
+
+        // try backwards delete 1 character
+        assertFalse(EmojiCompat.handleDeleteSurroundingText(inputConnection, editable,
+                1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testOnKeyDown_pre19() {
+        final TestString testString = new TestString(EMOJI_SINGLE_CODEPOINT);
+        final Editable editable = spy(new SpannableStringBuilder(testString.toString()));
+        Selection.setSelection(editable, testString.emojiEndIndex());
+        final KeyEvent event = del();
+
+        reset(editable);
+        verifyNoMoreInteractions(editable);
+
+        assertFalse(EmojiCompat.handleOnKeyDown(editable, event.getKeyCode(), event));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testUseEmojiAsDefaultStyle_whenEmojiInTheMiddle() {
+        final Config config = new TestConfig().setReplaceAll(true);
+        EmojiCompat.reset(config);
+        String s = new TestString(0x0061, CHAR_DEFAULT_TEXT_STYLE, 0x0062).toString();
+        // no span should be added as the emoji is text style presented by default
+        assertThat(EmojiCompat.get().process(s), not(hasEmoji()));
+        // a span should be added when we use the emoji style presentation as default
+        EmojiCompat.reset(config.setUseEmojiAsDefaultStyle(true));
+        assertThat(EmojiCompat.get().process(s), hasEmojiAt(DEFAULT_TEXT_STYLE, 1, 2));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testUseEmojiAsDefaultStyle_whenEmojiAtTheEnd() {
+        final Config config = new TestConfig().setReplaceAll(true);
+        EmojiCompat.reset(config);
+        String s = new TestString(0x0061, CHAR_DEFAULT_TEXT_STYLE).toString();
+        // no span should be added as the emoji is text style presented by default
+        assertThat(EmojiCompat.get().process(s), not(hasEmoji()));
+        // a span should be added when we use the emoji style presentation as default
+        EmojiCompat.reset(config.setUseEmojiAsDefaultStyle(true));
+        assertThat(EmojiCompat.get().process(s), hasEmojiAt(DEFAULT_TEXT_STYLE, 1, 2));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testUseEmojiAsDefaultStyle_noEmojisAdded_whenMarkedAsException() {
+        final String s = new TestString(CHAR_DEFAULT_TEXT_STYLE).toString();
+        final List<Integer> exceptions =
+                Arrays.asList(CHAR_DEFAULT_TEXT_STYLE + 1, CHAR_DEFAULT_TEXT_STYLE);
+        final Config config = new TestConfig().setReplaceAll(true)
+                .setUseEmojiAsDefaultStyle(true, exceptions);
+        EmojiCompat.reset(config);
+        // no span should be added as the text style codepoint is marked as exception
+        assertThat(EmojiCompat.get().process(s), not(hasEmoji()));
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testUseEmojiAsDefaultStyle_emojisAdded_whenNotMarkedAsException() {
+        final String s = new TestString(CHAR_DEFAULT_TEXT_STYLE).toString();
+        final List<Integer> exceptions =
+                Arrays.asList(CHAR_DEFAULT_TEXT_STYLE - 1, CHAR_DEFAULT_TEXT_STYLE + 1);
+        final Config config = new TestConfig().setReplaceAll(true)
+                .setUseEmojiAsDefaultStyle(true, exceptions);
+        EmojiCompat.reset(config);
+        // a span should be added as the codepoint is not included in the set of exceptions
+        assertThat(EmojiCompat.get().process(s), hasEmojiAt(DEFAULT_TEXT_STYLE, 0, 1));
+    }
+
+    private void assertCodePointMatch(EmojiMapping emoji) {
+        assertCodePointMatch(emoji.id(), emoji.codepoints());
+    }
+
+    private void assertCodePointMatch(int id, int[] codepoints) {
+        TestString string = new TestString(codepoints);
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is in the middle of string
+        string = new TestString(codepoints).withPrefix().withSuffix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
+
+        // case where Emoji is at the end of string
+        string = new TestString(codepoints).withSuffix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
+    }
+
+    private void assertCodePointDoesNotMatch(int[] codepoints) {
+        TestString string = new TestString(codepoints);
+        CharSequence charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, not(hasEmoji()));
+
+        string = new TestString(codepoints).withSuffix().withPrefix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, not(hasEmoji()));
+
+        string = new TestString(codepoints).withPrefix();
+        charSequence = EmojiCompat.get().process(string.toString());
+        assertThat(charSequence, not(hasEmoji()));
+    }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiKeyboardTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/EmojiKeyboardTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiSpanInstrumentationTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiSpanInstrumentationTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/EmojiSpanInstrumentationTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/EmojiSpanInstrumentationTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiSpanTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/EmojiSpanTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/EmojiSpanTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/FontRequestEmojiCompatConfigTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/FontRequestEmojiCompatConfigTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/FontRequestEmojiCompatConfigTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/FontRequestEmojiCompatConfigTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/HardDeleteTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/HardDeleteTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/HardDeleteTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/InitCallbackTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/InitCallbackTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/InitCallbackTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/MetadataRepoTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/MetadataRepoTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/MetadataRepoTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/SoftDeleteTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/SoftDeleteTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/SoftDeleteTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestActivity.java b/emoji/core/src/androidTest/java/android/support/text/emoji/TestActivity.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/TestActivity.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/TestActivity.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java b/emoji/core/src/androidTest/java/android/support/text/emoji/TestConfigBuilder.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/TestConfigBuilder.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/TestConfigBuilder.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java b/emoji/core/src/androidTest/java/android/support/text/emoji/TestEmojiMetadata.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/TestEmojiMetadata.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/TestEmojiMetadata.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/UninitializedStateTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/UninitializedStateTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/UninitializedStateTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/Emoji.java b/emoji/core/src/androidTest/java/android/support/text/emoji/util/Emoji.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/util/Emoji.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/util/Emoji.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java b/emoji/core/src/androidTest/java/android/support/text/emoji/util/EmojiMatcher.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/util/EmojiMatcher.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/util/EmojiMatcher.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java b/emoji/core/src/androidTest/java/android/support/text/emoji/util/KeyboardUtil.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/util/KeyboardUtil.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/util/KeyboardUtil.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/util/TestString.java b/emoji/core/src/androidTest/java/android/support/text/emoji/util/TestString.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/util/TestString.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/util/TestString.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperPre19Test.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditTextHelperPre19Test.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperPre19Test.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditTextHelperPre19Test.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditTextHelperTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditTextHelperTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditTextTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditTextTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiEditableFactoryTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiExtractTextLayoutTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiInputConnectionTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiInputFilterTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiInputFilterTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiInputFilterTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiKeyListenerTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperPre19Test.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiTextViewHelperPre19Test.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperPre19Test.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiTextViewHelperPre19Test.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiTextViewHelperTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiTextViewHelperTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextWatcherTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiTextWatcherTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextWatcherTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/EmojiTextWatcherTest.java
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/widget/SpannableBuilderTest.java
similarity index 100%
rename from emoji/core/tests/java/android/support/text/emoji/widget/SpannableBuilderTest.java
rename to emoji/core/src/androidTest/java/android/support/text/emoji/widget/SpannableBuilderTest.java
diff --git a/emoji/core/tests/res/layout/activity_default.xml b/emoji/core/src/androidTest/res/layout/activity_default.xml
similarity index 100%
rename from emoji/core/tests/res/layout/activity_default.xml
rename to emoji/core/src/androidTest/res/layout/activity_default.xml
diff --git a/emoji/core/tests/res/layout/extract_view.xml b/emoji/core/src/androidTest/res/layout/extract_view.xml
similarity index 100%
rename from emoji/core/tests/res/layout/extract_view.xml
rename to emoji/core/src/androidTest/res/layout/extract_view.xml
diff --git a/emoji/core/tests/res/layout/extract_view_with_attrs.xml b/emoji/core/src/androidTest/res/layout/extract_view_with_attrs.xml
similarity index 100%
rename from emoji/core/tests/res/layout/extract_view_with_attrs.xml
rename to emoji/core/src/androidTest/res/layout/extract_view_with_attrs.xml
diff --git a/emoji/core/src/main/java/android/support/text/emoji/EmojiProcessor.java b/emoji/core/src/main/java/android/support/text/emoji/EmojiProcessor.java
index f711704..77898af 100644
--- a/emoji/core/src/main/java/android/support/text/emoji/EmojiProcessor.java
+++ b/emoji/core/src/main/java/android/support/text/emoji/EmojiProcessor.java
@@ -171,6 +171,15 @@
             // into a Spannable.
             if (isSpannableBuilder || charSequence instanceof Spannable) {
                 spannable = (Spannable) charSequence;
+            } else if (charSequence instanceof Spanned) {
+                // check if there are any EmojiSpans as cheap as possible
+                // start-1, end+1 will return emoji span that starts/ends at start/end indices
+                final int nextSpanTransition = ((Spanned) charSequence).nextSpanTransition(
+                        start - 1, end + 1, EmojiSpan.class);
+
+                if (nextSpanTransition <= end) {
+                    spannable = new SpannableString(charSequence);
+                }
             }
 
             if (spannable != null) {
diff --git a/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java b/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java
deleted file mode 100644
index 7d5cfb9..0000000
--- a/emoji/core/tests/java/android/support/text/emoji/EmojiCompatTest.java
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.text.emoji;
-
-import static android.support.text.emoji.TestConfigBuilder.TestConfig;
-import static android.support.text.emoji.TestConfigBuilder.WaitingDataLoader;
-import static android.support.text.emoji.TestConfigBuilder.config;
-import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_EMOJI_STYLE;
-import static android.support.text.emoji.util.Emoji.CHAR_DEFAULT_TEXT_STYLE;
-import static android.support.text.emoji.util.Emoji.CHAR_DIGIT;
-import static android.support.text.emoji.util.Emoji.CHAR_FITZPATRICK;
-import static android.support.text.emoji.util.Emoji.CHAR_VS_EMOJI;
-import static android.support.text.emoji.util.Emoji.CHAR_VS_TEXT;
-import static android.support.text.emoji.util.Emoji.DEFAULT_TEXT_STYLE;
-import static android.support.text.emoji.util.Emoji.EMOJI_ASTERISK_KEYCAP;
-import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES;
-import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_ES_KEYCAP;
-import static android.support.text.emoji.util.Emoji.EMOJI_DIGIT_KEYCAP;
-import static android.support.text.emoji.util.Emoji.EMOJI_FLAG;
-import static android.support.text.emoji.util.Emoji.EMOJI_GENDER;
-import static android.support.text.emoji.util.Emoji.EMOJI_GENDER_WITHOUT_VS;
-import static android.support.text.emoji.util.Emoji.EMOJI_REGIONAL_SYMBOL;
-import static android.support.text.emoji.util.Emoji.EMOJI_SINGLE_CODEPOINT;
-import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER;
-import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_TYPE_ONE;
-import static android.support.text.emoji.util.Emoji.EMOJI_SKIN_MODIFIER_WITH_VS;
-import static android.support.text.emoji.util.Emoji.EMOJI_UNKNOWN_FLAG;
-import static android.support.text.emoji.util.Emoji.EMOJI_WITH_ZWJ;
-import static android.support.text.emoji.util.EmojiMatcher.hasEmoji;
-import static android.support.text.emoji.util.EmojiMatcher.hasEmojiAt;
-import static android.support.text.emoji.util.EmojiMatcher.hasEmojiCount;
-import static android.support.text.emoji.util.KeyboardUtil.del;
-
-import static org.hamcrest.Matchers.instanceOf;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.annotation.SuppressLint;
-import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.text.emoji.EmojiCompat.Config;
-import android.support.text.emoji.util.Emoji.EmojiMapping;
-import android.support.text.emoji.util.TestString;
-import android.text.Editable;
-import android.text.Selection;
-import android.text.Spannable;
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.SpannedString;
-import android.view.KeyEvent;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputConnection;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class EmojiCompatTest {
-
-    @Before
-    public void setup() {
-        EmojiCompat.reset(config());
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void testGet_throwsException() {
-        EmojiCompat.reset((EmojiCompat) null);
-        EmojiCompat.get();
-    }
-
-    @Test
-    public void testProcess_doesNothing_withNullCharSequence() {
-        assertNull(EmojiCompat.get().process(null));
-    }
-
-    @Test
-    public void testProcess_returnsEmptySpanned_withEmptyString() {
-        final CharSequence charSequence = EmojiCompat.get().process("");
-        assertNotNull(charSequence);
-        assertEquals(0, charSequence.length());
-        assertThat(charSequence, not(hasEmoji()));
-    }
-
-    @SuppressLint("Range")
-    @Test(expected = IllegalArgumentException.class)
-    public void testProcess_withNegativeStartValue() {
-        EmojiCompat.get().process("a", -1, 1);
-    }
-
-    @SuppressLint("Range")
-    @Test(expected = IllegalArgumentException.class)
-    public void testProcess_withNegativeEndValue() {
-        EmojiCompat.get().process("a", 1, -1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testProcess_withStartSmallerThanEndValue() {
-        EmojiCompat.get().process("aa", 1, 0);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testProcess_withStartGreaterThanLength() {
-        EmojiCompat.get().process("a", 2, 2);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testProcess_withEndGreaterThanLength() {
-        EmojiCompat.get().process("a", 0, 2);
-    }
-
-    @Test
-    public void testProcessWithStartEnd_withNoOpValues() {
-        final Spannable spannable = new SpannableString(new TestString('a')
-                .withPrefix().withSuffix().toString());
-        // early return check
-        assertSame(spannable, EmojiCompat.get().process(spannable, 0, 0));
-        assertSame(spannable, EmojiCompat.get().process(spannable, 1, 1));
-        assertSame(spannable, EmojiCompat.get().process(spannable, spannable.length(),
-                spannable.length()));
-    }
-
-    @Test
-    public void testProcess_doesNotAddEmojiSpan() {
-        final String string = "abc";
-        final CharSequence charSequence = EmojiCompat.get().process(string);
-        assertNotNull(charSequence);
-        assertEquals(string, charSequence.toString());
-        assertThat(charSequence, not(hasEmoji()));
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 18)
-    public void testProcess_returnsSameCharSequence_pre19() {
-        assertNull(EmojiCompat.get().process(null));
-
-        CharSequence testString = "abc";
-        assertSame(testString, EmojiCompat.get().process(testString));
-
-        testString = new SpannableString("abc");
-        assertSame(testString, EmojiCompat.get().process(testString));
-
-        testString = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
-        assertSame(testString, EmojiCompat.get().process(testString));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsSingleCodePointEmoji() {
-        assertCodePointMatch(EMOJI_SINGLE_CODEPOINT);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsFlagEmoji() {
-        assertCodePointMatch(EMOJI_FLAG);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsUnknownFlagEmoji() {
-        assertCodePointMatch(EMOJI_UNKNOWN_FLAG);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsRegionalIndicatorSymbol() {
-        assertCodePointMatch(EMOJI_REGIONAL_SYMBOL);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsKeyCapEmoji() {
-        assertCodePointMatch(EMOJI_DIGIT_KEYCAP);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_doesNotAddEmojiForNumbers() {
-        assertCodePointDoesNotMatch(new int[] {CHAR_DIGIT});
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_doesNotAddEmojiForNumbers_1() {
-        final TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).append('1', 'f');
-        CharSequence charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiCount(1));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsVariantSelectorEmoji() {
-        assertCodePointMatch(EMOJI_DIGIT_ES);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_doesNotAddVariantSelectorTextStyle() {
-        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT, CHAR_VS_TEXT});
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsVariantSelectorAndKeyCapEmoji() {
-        assertCodePointMatch(EMOJI_DIGIT_ES_KEYCAP);
-    }
-
-    @Test
-    public void testProcess_doesNotAddEmoji_forVariantBaseWithoutSelector() {
-        assertCodePointDoesNotMatch(new int[]{CHAR_DIGIT});
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsAsteriskKeyCapEmoji() {
-        assertCodePointMatch(EMOJI_ASTERISK_KEYCAP);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsSkinModifierEmoji() {
-        assertCodePointMatch(EMOJI_SKIN_MODIFIER);
-        assertCodePointMatch(EMOJI_SKIN_MODIFIER_TYPE_ONE);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsSkinModifierEmoji_withVariantSelector() {
-        assertCodePointMatch(EMOJI_SKIN_MODIFIER_WITH_VS);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsSkinModifierEmoji_270c_withVariantSelector() {
-        // 0x270c is a Standardized Variant Base, Emoji Modifier Base and also Emoji
-        // therefore it is different than i.e. 0x1f3c3. The code actually failed for this test
-        // at first.
-        assertCodePointMatch(0xF0734, new int[]{0x270C, CHAR_VS_EMOJI, CHAR_FITZPATRICK});
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_defaultStyleDoesNotAddSpan() {
-        assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_TEXT_STYLE});
-        assertCodePointMatch(DEFAULT_TEXT_STYLE);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_defaultEmojiStyle_withTextStyleVs() {
-        assertCodePointMatch(EMOJI_SINGLE_CODEPOINT.id(),
-                new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI});
-        assertCodePointDoesNotMatch(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT});
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_genderEmoji() {
-        assertCodePointMatch(EMOJI_GENDER);
-        assertCodePointMatch(EMOJI_GENDER_WITHOUT_VS);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_standardizedVariantEmojiExceptions() {
-        final int[][] exceptions = new int[][]{
-                {0x2600, 0xF034D},
-                {0x2601, 0xF0167},
-                {0x260E, 0xF034E},
-                {0x261D, 0xF0227},
-                {0x263A, 0xF02A6},
-                {0x2660, 0xF0350},
-                {0x2663, 0xF033F},
-                {0x2665, 0xF033B},
-                {0x2666, 0xF033E},
-                {0x270C, 0xF0079},
-                {0x2744, 0xF0342},
-                {0x2764, 0xF0362}
-        };
-
-        for (int i = 0; i < exceptions.length; i++) {
-            final int[] codepoints = new int[]{exceptions[i][0]};
-            assertCodePointMatch(exceptions[i][1], codepoints);
-        }
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsZwjEmoji() {
-        assertCodePointMatch(EMOJI_WITH_ZWJ);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_doesNotAddEmojiForNumbersAfterZwjEmo() {
-        TestString string = new TestString(EMOJI_WITH_ZWJ).append(0x20, 0x2B, 0x31)
-                .withSuffix().withPrefix();
-        CharSequence charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(),
-                string.emojiEndIndex() - 3));
-        assertThat(charSequence, hasEmojiCount(1));
-
-        string = new TestString(EMOJI_WITH_ZWJ).withSuffix().withPrefix();
-        charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiCount(1));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_addsEmojiThatFollowsDigit() {
-        TestString string = new TestString(EMOJI_SINGLE_CODEPOINT).prepend('N', '5');
-        CharSequence charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiAt(EMOJI_SINGLE_CODEPOINT, string.emojiStartIndex() + 2,
-                string.emojiEndIndex()));
-        assertThat(charSequence, hasEmojiCount(1));
-
-        string = new TestString(EMOJI_WITH_ZWJ).prepend('N', '5');
-        charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex() + 2,
-                string.emojiEndIndex()));
-        assertThat(charSequence, hasEmojiCount(1));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_withAppend() {
-        final Editable editable = new SpannableStringBuilder(new TestString('a').withPrefix()
-                .withSuffix().toString());
-        final int start = 1;
-        final int end = start + EMOJI_SINGLE_CODEPOINT.charCount();
-        editable.insert(start, new TestString(EMOJI_SINGLE_CODEPOINT).toString());
-        EmojiCompat.get().process(editable, start, end);
-        assertThat(editable, hasEmojiCount(1));
-        assertThat(editable, hasEmojiAt(EMOJI_SINGLE_CODEPOINT, start, end));
-    }
-
-    @Test
-    public void testProcess_doesNotCreateSpannable_ifNoEmoji() {
-        CharSequence processed = EmojiCompat.get().process("abc");
-        assertNotNull(processed);
-        assertThat(processed, instanceOf(String.class));
-
-        processed = EmojiCompat.get().process(new SpannedString("abc"));
-        assertNotNull(processed);
-        assertThat(processed, instanceOf(SpannedString.class));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_reprocess() {
-        final String string = new TestString(EMOJI_SINGLE_CODEPOINT)
-                .append(EMOJI_SINGLE_CODEPOINT)
-                .append(EMOJI_SINGLE_CODEPOINT)
-                .withPrefix().withSuffix().toString();
-
-        Spannable processed = (Spannable) EmojiCompat.get().process(string);
-        assertThat(processed, hasEmojiCount(3));
-
-        final EmojiSpan[] spans = processed.getSpans(0, processed.length(), EmojiSpan.class);
-        final Set<EmojiSpan> spanSet = new HashSet<>();
-        Collections.addAll(spanSet, spans);
-
-        processed = (Spannable) EmojiCompat.get().process(processed);
-        assertThat(processed, hasEmojiCount(3));
-        // new spans should be new instances
-        final EmojiSpan[] newSpans = processed.getSpans(0, processed.length(), EmojiSpan.class);
-        for (int i = 0; i < newSpans.length; i++) {
-            assertFalse(spanSet.contains(newSpans[i]));
-        }
-    }
-
-    @SuppressLint("Range")
-    @Test(expected = IllegalArgumentException.class)
-    public void testProcess_throwsException_withMaxEmojiSetToNegative() {
-        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
-
-        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
-                -1 /*maxEmojiCount*/);
-
-        assertThat(processed, not(hasEmoji()));
-    }
-
-    @Test
-    public void testProcess_withMaxEmojiSetToZero() {
-        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
-
-        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
-                0 /*maxEmojiCount*/);
-
-        assertThat(processed, not(hasEmoji()));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_withMaxEmojiSetToOne() {
-        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
-
-        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
-                1 /*maxEmojiCount*/);
-
-        assertThat(processed, hasEmojiCount(1));
-        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_withMaxEmojiSetToLessThenExistingSpanCount() {
-        final String original = new TestString(EMOJI_SINGLE_CODEPOINT)
-                .append(EMOJI_SINGLE_CODEPOINT)
-                .append(EMOJI_SINGLE_CODEPOINT)
-                .toString();
-
-        // add 2 spans
-        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(), 2);
-
-        assertThat(processed, hasEmojiCount(2));
-
-        // use the Spannable with 2 spans, but use maxEmojiCount=1, start from the beginning of
-        // last (3rd) emoji
-        EmojiCompat.get().process(processed, original.length() - EMOJI_SINGLE_CODEPOINT.charCount(),
-                original.length(), 1 /*maxEmojiCount*/);
-
-        // expectation: there are still 2 emojis
-        assertThat(processed, hasEmojiCount(2));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_withMaxEmojiSet_withExistingEmojis() {
-        // test string with two emoji characters
-        final String original = new TestString(EMOJI_SINGLE_CODEPOINT)
-                .append(EMOJI_FLAG).toString();
-
-        // process and add 1 EmojiSpan, maxEmojiCount=1
-        CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
-                1 /*maxEmojiCount*/);
-
-        // assert that there is a single emoji
-        assertThat(processed, hasEmojiCount(1));
-        assertThat(processed,
-                hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount()));
-
-        // call process again with the charSequence that already has 1 span
-        processed = EmojiCompat.get().process(processed, EMOJI_SINGLE_CODEPOINT.charCount(),
-                processed.length(), 1 /*maxEmojiCount*/);
-
-        // assert that there is still a single emoji
-        assertThat(processed, hasEmojiCount(1));
-        assertThat(processed,
-                hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount()));
-
-        // make the same call, this time with maxEmojiCount=2
-        processed = EmojiCompat.get().process(processed, EMOJI_SINGLE_CODEPOINT.charCount(),
-                processed.length(), 2 /*maxEmojiCount*/);
-
-        // assert that it contains 2 emojis
-        assertThat(processed, hasEmojiCount(2));
-        assertThat(processed,
-                hasEmojiAt(EMOJI_SINGLE_CODEPOINT, 0, EMOJI_SINGLE_CODEPOINT.charCount()));
-        assertThat(processed,
-                hasEmojiAt(EMOJI_FLAG, EMOJI_SINGLE_CODEPOINT.charCount(),
-                        original.length()));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_withReplaceNonExistent_callsGlyphChecker() {
-        final Config config = TestConfigBuilder.config().setReplaceAll(true);
-        EmojiCompat.reset(config);
-
-        final EmojiProcessor.GlyphChecker glyphChecker = mock(EmojiProcessor.GlyphChecker.class);
-        when(glyphChecker.hasGlyph(any(CharSequence.class), anyInt(), anyInt())).thenReturn(true);
-        EmojiCompat.get().setGlyphChecker(glyphChecker);
-
-        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
-
-        CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
-                Integer.MAX_VALUE /*maxEmojiCount*/, EmojiCompat.REPLACE_STRATEGY_NON_EXISTENT);
-
-        // when function overrides config level replaceAll, a call to GlyphChecker is expected.
-        verify(glyphChecker, times(1)).hasGlyph(any(CharSequence.class), anyInt(), anyInt());
-
-        // since replaceAll is false, there should be no EmojiSpans
-        assertThat(processed, not(hasEmoji()));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testProcess_withReplaceDefault_doesNotCallGlyphChecker() {
-        final Config config = TestConfigBuilder.config().setReplaceAll(true);
-        EmojiCompat.reset(config);
-
-        final EmojiProcessor.GlyphChecker glyphChecker = mock(EmojiProcessor.GlyphChecker.class);
-        when(glyphChecker.hasGlyph(any(CharSequence.class), anyInt(), anyInt())).thenReturn(true);
-        EmojiCompat.get().setGlyphChecker(glyphChecker);
-
-        final String original = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
-        // call without replaceAll, config value (true) should be used
-        final CharSequence processed = EmojiCompat.get().process(original, 0, original.length(),
-                Integer.MAX_VALUE /*maxEmojiCount*/, EmojiCompat.REPLACE_STRATEGY_DEFAULT);
-
-        // replaceAll=true should not call hasGlyph
-        verify(glyphChecker, times(0)).hasGlyph(any(CharSequence.class), anyInt(), anyInt());
-
-        assertThat(processed, hasEmojiCount(1));
-        assertThat(processed, hasEmoji(EMOJI_SINGLE_CODEPOINT));
-    }
-
-    @Test(expected = NullPointerException.class)
-    public void testHasEmojiGlyph_withNullCharSequence() {
-        EmojiCompat.get().hasEmojiGlyph(null);
-    }
-
-    @Test(expected = NullPointerException.class)
-    public void testHasEmojiGlyph_withMetadataVersion_withNullCharSequence() {
-        EmojiCompat.get().hasEmojiGlyph(null, Integer.MAX_VALUE);
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 18)
-    public void testHasEmojiGlyph_pre19() {
-        String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
-        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 18)
-    public void testHasEmojiGlyph_withMetaVersion_pre19() {
-        String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
-        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testHasEmojiGlyph_returnsTrueForExistingEmoji() {
-        final String sequence = new TestString(EMOJI_FLAG).toString();
-        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
-    }
-
-    @Test
-    public void testHasGlyph_returnsFalseForNonExistentEmoji() {
-        final String sequence = new TestString(EMOJI_FLAG).append(0x1111).toString();
-        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testHashEmojiGlyph_withDefaultEmojiStyles() {
-        String sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE}).toString();
-        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
-
-        sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_EMOJI}).toString();
-        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence));
-
-        sequence = new TestString(new int[]{CHAR_DEFAULT_EMOJI_STYLE, CHAR_VS_TEXT}).toString();
-        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testHashEmojiGlyph_withMetadataVersion() {
-        final String sequence = new TestString(EMOJI_SINGLE_CODEPOINT).toString();
-        assertFalse(EmojiCompat.get().hasEmojiGlyph(sequence, 0));
-        assertTrue(EmojiCompat.get().hasEmojiGlyph(sequence, Integer.MAX_VALUE));
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 18)
-    public void testGetLoadState_returnsSuccess_pre19() {
-        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCEEDED);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testGetLoadState_returnsSuccessIfLoadSuccess() throws InterruptedException {
-        final WaitingDataLoader metadataLoader = new WaitingDataLoader(true /*success*/);
-        final Config config = new TestConfig(metadataLoader);
-        EmojiCompat.reset(config);
-
-        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING);
-
-        metadataLoader.getLoaderLatch().countDown();
-        metadataLoader.getTestLatch().await();
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCEEDED);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testGetLoadState_returnsFailIfLoadFail() throws InterruptedException {
-        final WaitingDataLoader metadataLoader = new WaitingDataLoader(false/*fail*/);
-        final Config config = new TestConfig(metadataLoader);
-        EmojiCompat.reset(config);
-
-        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING);
-
-        metadataLoader.getLoaderLatch().countDown();
-        metadataLoader.getTestLatch().await();
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-
-        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_FAILED);
-    }
-
-    @Test
-    public void testUpdateEditorInfoAttrs_doesNotSetKeyIfNotInitialized() {
-        final EditorInfo editorInfo = new EditorInfo();
-        editorInfo.extras = new Bundle();
-
-        final WaitingDataLoader metadataLoader = new WaitingDataLoader();
-        final Config config = new TestConfig(metadataLoader);
-        EmojiCompat.reset(config);
-
-        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
-
-        final Bundle extras = editorInfo.extras;
-        assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY));
-        assertFalse(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
-
-        metadataLoader.getLoaderLatch().countDown();
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 18)
-    public void testGetAssetSignature() {
-        final String signature = EmojiCompat.get().getAssetSignature();
-        assertTrue(signature.isEmpty());
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testGetAssetSignature_api19() {
-        final String signature = EmojiCompat.get().getAssetSignature();
-        assertNotNull(signature);
-        assertFalse(signature.isEmpty());
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testUpdateEditorInfoAttrs_setsKeysIfInitialized() {
-        final EditorInfo editorInfo = new EditorInfo();
-        editorInfo.extras = new Bundle();
-        Config config = new TestConfig().setReplaceAll(false);
-        EmojiCompat.reset(config);
-        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
-
-        final Bundle extras = editorInfo.extras;
-        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_METAVERSION_KEY));
-        assertTrue(extras.getInt(EmojiCompat.EDITOR_INFO_METAVERSION_KEY) > 0);
-        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
-        assertFalse(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
-
-        config = new TestConfig().setReplaceAll(true);
-        EmojiCompat.reset(config);
-        EmojiCompat.get().updateEditorInfoAttrs(editorInfo);
-
-        assertTrue(extras.containsKey(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
-        assertTrue(extras.getBoolean(EmojiCompat.EDITOR_INFO_REPLACE_ALL_KEY));
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 18)
-    public void testHandleDeleteSurroundingText_pre19() {
-        final TestString testString = new TestString(EMOJI_SINGLE_CODEPOINT);
-        final InputConnection inputConnection = mock(InputConnection.class);
-        final Editable editable = spy(new SpannableStringBuilder(testString.toString()));
-
-        Selection.setSelection(editable, testString.emojiEndIndex());
-
-        reset(editable);
-        reset(inputConnection);
-        verifyNoMoreInteractions(editable);
-        verifyNoMoreInteractions(inputConnection);
-
-        // try backwards delete 1 character
-        assertFalse(EmojiCompat.handleDeleteSurroundingText(inputConnection, editable,
-                1 /*beforeLength*/, 0 /*afterLength*/, false /*inCodePoints*/));
-    }
-
-    @Test
-    @SdkSuppress(maxSdkVersion = 18)
-    public void testOnKeyDown_pre19() {
-        final TestString testString = new TestString(EMOJI_SINGLE_CODEPOINT);
-        final Editable editable = spy(new SpannableStringBuilder(testString.toString()));
-        Selection.setSelection(editable, testString.emojiEndIndex());
-        final KeyEvent event = del();
-
-        reset(editable);
-        verifyNoMoreInteractions(editable);
-
-        assertFalse(EmojiCompat.handleOnKeyDown(editable, event.getKeyCode(), event));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testUseEmojiAsDefaultStyle_whenEmojiInTheMiddle() {
-        final Config config = new TestConfig().setReplaceAll(true);
-        EmojiCompat.reset(config);
-        String s = new TestString(0x0061, CHAR_DEFAULT_TEXT_STYLE, 0x0062).toString();
-        // no span should be added as the emoji is text style presented by default
-        assertThat(EmojiCompat.get().process(s), not(hasEmoji()));
-        // a span should be added when we use the emoji style presentation as default
-        EmojiCompat.reset(config.setUseEmojiAsDefaultStyle(true));
-        assertThat(EmojiCompat.get().process(s), hasEmojiAt(DEFAULT_TEXT_STYLE, 1, 2));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testUseEmojiAsDefaultStyle_whenEmojiAtTheEnd() {
-        final Config config = new TestConfig().setReplaceAll(true);
-        EmojiCompat.reset(config);
-        String s = new TestString(0x0061, CHAR_DEFAULT_TEXT_STYLE).toString();
-        // no span should be added as the emoji is text style presented by default
-        assertThat(EmojiCompat.get().process(s), not(hasEmoji()));
-        // a span should be added when we use the emoji style presentation as default
-        EmojiCompat.reset(config.setUseEmojiAsDefaultStyle(true));
-        assertThat(EmojiCompat.get().process(s), hasEmojiAt(DEFAULT_TEXT_STYLE, 1, 2));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testUseEmojiAsDefaultStyle_noEmojisAdded_whenMarkedAsException() {
-        final String s = new TestString(CHAR_DEFAULT_TEXT_STYLE).toString();
-        final List<Integer> exceptions =
-                Arrays.asList(CHAR_DEFAULT_TEXT_STYLE + 1, CHAR_DEFAULT_TEXT_STYLE);
-        final Config config = new TestConfig().setReplaceAll(true)
-                .setUseEmojiAsDefaultStyle(true, exceptions);
-        EmojiCompat.reset(config);
-        // no span should be added as the text style codepoint is marked as exception
-        assertThat(EmojiCompat.get().process(s), not(hasEmoji()));
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = 19)
-    public void testUseEmojiAsDefaultStyle_emojisAdded_whenNotMarkedAsException() {
-        final String s = new TestString(CHAR_DEFAULT_TEXT_STYLE).toString();
-        final List<Integer> exceptions =
-                Arrays.asList(CHAR_DEFAULT_TEXT_STYLE - 1, CHAR_DEFAULT_TEXT_STYLE + 1);
-        final Config config = new TestConfig().setReplaceAll(true)
-                .setUseEmojiAsDefaultStyle(true, exceptions);
-        EmojiCompat.reset(config);
-        // a span should be added as the codepoint is not included in the set of exceptions
-        assertThat(EmojiCompat.get().process(s), hasEmojiAt(DEFAULT_TEXT_STYLE, 0, 1));
-    }
-
-    private void assertCodePointMatch(EmojiMapping emoji) {
-        assertCodePointMatch(emoji.id(), emoji.codepoints());
-    }
-
-    private void assertCodePointMatch(int id, int[] codepoints) {
-        TestString string = new TestString(codepoints);
-        CharSequence charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
-
-        // case where Emoji is in the middle of string
-        string = new TestString(codepoints).withPrefix().withSuffix();
-        charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
-
-        // case where Emoji is at the end of string
-        string = new TestString(codepoints).withSuffix();
-        charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, hasEmojiAt(id, string.emojiStartIndex(), string.emojiEndIndex()));
-    }
-
-    private void assertCodePointDoesNotMatch(int[] codepoints) {
-        TestString string = new TestString(codepoints);
-        CharSequence charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, not(hasEmoji()));
-
-        string = new TestString(codepoints).withSuffix().withPrefix();
-        charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, not(hasEmoji()));
-
-        string = new TestString(codepoints).withPrefix();
-        charSequence = EmojiCompat.get().process(string.toString());
-        assertThat(charSequence, not(hasEmoji()));
-    }
-}
diff --git a/exifinterface/Android.mk b/exifinterface/Android.mk
deleted file mode 100644
index 18ffcf3..0000000
--- a/exifinterface/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must include it with
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := android-support-exifinterface
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-exifinterface
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/exifinterface/src/androidTest/NO_DOCS b/exifinterface/src/androidTest/NO_DOCS
deleted file mode 100644
index bd77b1a..0000000
--- a/exifinterface/src/androidTest/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
\ No newline at end of file
diff --git a/exifinterface/src/main/AndroidManifest.xml b/exifinterface/src/main/AndroidManifest.xml
index db7cabb..fd33d20 100644
--- a/exifinterface/src/main/AndroidManifest.xml
+++ b/exifinterface/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.exifinterface">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.exifinterface"/>
diff --git a/fragment/Android.mk b/fragment/Android.mk
deleted file mode 100644
index adb6764..0000000
--- a/fragment/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-fragment \
-#       android-support-compat \
-#       android-support-media-compat \
-#       android-support-core-ui \
-#       android-support-core-utils
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-fragment
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat \
-    android-support-core-ui \
-    android-support-core-utils
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-arch-lifecycle-livedata-core \
-    android-arch-lifecycle-viewmodel
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/fragment/api/27.1.0.ignore b/fragment/api/27.1.0.ignore
new file mode 100644
index 0000000..91e8cba
--- /dev/null
+++ b/fragment/api/27.1.0.ignore
@@ -0,0 +1,2 @@
+4a027b3
+1aab1d6
diff --git a/fragment/api/current.txt b/fragment/api/current.txt
index 5df18f8..1a4955c 100644
--- a/fragment/api/current.txt
+++ b/fragment/api/current.txt
@@ -383,22 +383,5 @@
     method public void setSelection(int);
   }
 
-  public abstract class LoaderManager {
-    ctor public LoaderManager();
-    method public abstract void destroyLoader(int);
-    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
-    method public static void enableDebugLogging(boolean);
-    method public abstract <D> android.support.v4.content.Loader<D> getLoader(int);
-    method public boolean hasRunningLoaders();
-    method public abstract <D> android.support.v4.content.Loader<D> initLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
-    method public abstract <D> android.support.v4.content.Loader<D> restartLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
-  }
-
-  public static abstract interface LoaderManager.LoaderCallbacks<D> {
-    method public abstract android.support.v4.content.Loader<D> onCreateLoader(int, android.os.Bundle);
-    method public abstract void onLoadFinished(android.support.v4.content.Loader<D>, D);
-    method public abstract void onLoaderReset(android.support.v4.content.Loader<D>);
-  }
-
 }
 
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 593e8de..4a3c1d1 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -11,7 +11,7 @@
     api(project(":support-core-ui"))
     api(project(":support-core-utils"))
     api(project(":support-annotations"))
-    api(ARCH_LIFECYCLE_LIVEDATA_CORE, libs.exclude_annotations_transitive)
+    api(project(":loader"))
     api(ARCH_LIFECYCLE_VIEWMODEL, libs.exclude_annotations_transitive)
 
     androidTestImplementation(TEST_RUNNER)
diff --git a/fragment/src/androidTest/java/android/support/v4/app/FragmentLifecycleTest.java b/fragment/src/androidTest/java/android/support/v4/app/FragmentLifecycleTest.java
index 89433df..f816dd8 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/FragmentLifecycleTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/FragmentLifecycleTest.java
@@ -1098,8 +1098,8 @@
     }
 
     /**
-     * When there are no retained instance fragments, the FragmentManagerNonConfig should be
-     * null
+     * When there are no retained instance fragments, the FragmentManagerNonConfig's fragments
+     * should be null
      */
     @Test
     @UiThreadTest
@@ -1116,7 +1116,7 @@
         fm.executePendingTransactions();
         Pair<Parcelable, FragmentManagerNonConfig> savedState =
                 FragmentTestUtil.destroy(mActivityRule, fc);
-        assertNull(savedState.second);
+        assertNull(savedState.second.getFragments());
     }
 
     /**
diff --git a/fragment/src/androidTest/java/android/support/v4/app/LoaderInfoTest.java b/fragment/src/androidTest/java/android/support/v4/app/LoaderInfoTest.java
deleted file mode 100644
index 799b6ab..0000000
--- a/fragment/src/androidTest/java/android/support/v4/app/LoaderInfoTest.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.os.SystemClock;
-import android.support.annotation.Nullable;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.app.test.LoaderActivity;
-import android.support.v4.content.AsyncTaskLoader;
-import android.support.v4.content.Loader;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LoaderInfoTest {
-
-    @Rule
-    public ActivityTestRule<LoaderActivity> mActivityRule =
-            new ActivityTestRule<>(LoaderActivity.class);
-
-    @Test
-    public void testIsCallbackWaitingForData() throws Throwable {
-        final LoaderTest.DummyLoaderCallbacks loaderCallback =
-                new LoaderTest.DummyLoaderCallbacks(mActivityRule.getActivity());
-        final CountDownLatch deliverResultLatch = new CountDownLatch(1);
-        Loader<Boolean> delayLoader = new AsyncTaskLoader<Boolean>(mActivityRule.getActivity()) {
-            @Override
-            public Boolean loadInBackground() {
-                SystemClock.sleep(50);
-                return true;
-            }
-
-            @Override
-            protected void onStartLoading() {
-                forceLoad();
-            }
-
-            @Override
-            public void deliverResult(@Nullable Boolean data) {
-                super.deliverResult(data);
-                deliverResultLatch.countDown();
-            }
-        };
-        final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
-                0, null, delayLoader);
-        assertFalse("isCallbackWaitingForData should be false before setCallback",
-                loaderInfo.isCallbackWaitingForData());
-
-        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
-        assertTrue("isCallbackWaitingForData should be true immediately after setCallback",
-                loaderInfo.isCallbackWaitingForData());
-
-        assertTrue("Loader timed out delivering results",
-                deliverResultLatch.await(1, TimeUnit.SECONDS));
-        // Results are posted to the UI thread, so we wait for them there
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertTrue("onLoadFinished should be called after setCallback",
-                        loaderCallback.mOnLoadFinished);
-                assertFalse("isCallbackWaitingForData should be false after onLoadFinished",
-                        loaderInfo.isCallbackWaitingForData());
-            }
-        });
-    }
-
-    @UiThreadTest
-    @Test
-    public void testSetCallback() throws Throwable {
-        final LoaderTest.DummyLoaderCallbacks loaderCallback =
-                new LoaderTest.DummyLoaderCallbacks(mActivityRule.getActivity());
-        Loader<Boolean> loader = loaderCallback.onCreateLoader(0, null);
-        final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
-                0, null, loader);
-        assertFalse("onLoadFinished shouldn't be called before setCallback",
-                loaderCallback.mOnLoadFinished);
-
-        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
-        assertTrue("onLoadFinished should be called after setCallback",
-                loaderCallback.mOnLoadFinished);
-    }
-
-    @UiThreadTest
-    @Test
-    public void testSetCallback_replace() throws Throwable {
-        LoaderTest.DummyLoaderCallbacks initialCallback =
-                new LoaderTest.DummyLoaderCallbacks(mActivityRule.getActivity());
-        Loader<Boolean> loader = initialCallback.onCreateLoader(0, null);
-        LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
-                0, null, loader);
-        assertFalse("onLoadFinished for initial shouldn't be called before setCallback initial",
-                initialCallback.mOnLoadFinished);
-
-        loaderInfo.setCallback(mActivityRule.getActivity(), initialCallback);
-        assertTrue("onLoadFinished for initial should be called after setCallback initial",
-                initialCallback.mOnLoadFinished);
-
-        final LoaderTest.DummyLoaderCallbacks replacementCallback =
-                new LoaderTest.DummyLoaderCallbacks(mActivityRule.getActivity());
-        initialCallback.mOnLoadFinished = false;
-
-        loaderInfo.setCallback(mActivityRule.getActivity(), replacementCallback);
-        assertFalse("onLoadFinished for initial should not be called "
-                        + "after setCallback replacement",
-                initialCallback.mOnLoadFinished);
-        assertTrue("onLoadFinished for replacement should be called "
-                        + " after setCallback replacement",
-                replacementCallback.mOnLoadFinished);
-    }
-
-    @UiThreadTest
-    @Test
-    public void testDestroy() throws Throwable {
-        final LoaderTest.DummyLoaderCallbacks loaderCallback =
-                new LoaderTest.DummyLoaderCallbacks(mActivityRule.getActivity());
-        final Loader<Boolean> loader = loaderCallback.onCreateLoader(0, null);
-        final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
-                0, null, loader);
-
-        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
-        assertTrue("Loader should be started after setCallback", loader.isStarted());
-        loaderInfo.destroy();
-        assertFalse("Loader should not be started after destroy", loader.isStarted());
-    }
-}
diff --git a/fragment/src/androidTest/java/android/support/v4/app/LoaderObserverTest.java b/fragment/src/androidTest/java/android/support/v4/app/LoaderObserverTest.java
deleted file mode 100644
index 14c2321..0000000
--- a/fragment/src/androidTest/java/android/support/v4/app/LoaderObserverTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-
-import android.content.Context;
-import android.support.test.filters.SmallTest;
-import android.support.v4.content.Loader;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class LoaderObserverTest {
-
-    @Test
-    public void testOnChanged() {
-        LoaderTest.DummyLoaderCallbacks callback =
-                new LoaderTest.DummyLoaderCallbacks(mock(Context.class));
-        @SuppressWarnings("unchecked")
-        LoaderManagerImpl.LoaderObserver<Boolean> observer = new LoaderManagerImpl.LoaderObserver<>(
-                mock(Loader.class), callback);
-        assertFalse("LoaderObserver should not have delivered data before onChanged",
-                observer.hasDeliveredData());
-        assertFalse("onLoadFinished should not be called before onChanged",
-                callback.mOnLoadFinished);
-
-
-        observer.onChanged(true);
-        assertTrue("LoaderObserver should have delivered data after onChanged",
-                observer.hasDeliveredData());
-        assertTrue("onLoadFinished should be called after onChanged",
-                callback.mOnLoadFinished);
-    }
-
-    @Test
-    public void testReset() {
-        LoaderTest.DummyLoaderCallbacks callback =
-                new LoaderTest.DummyLoaderCallbacks(mock(Context.class));
-        @SuppressWarnings("unchecked")
-        LoaderManagerImpl.LoaderObserver<Boolean> observer = new LoaderManagerImpl.LoaderObserver<>(
-                mock(Loader.class), callback);
-        assertFalse("onLoaderReset shouldn't be called before onChanged+reset",
-                callback.mOnLoaderReset);
-
-        observer.reset();
-        assertFalse("onLoaderReset should not be called after only reset",
-                callback.mOnLoaderReset);
-    }
-
-    @Test
-    public void testResetWithOnChanged() {
-        LoaderTest.DummyLoaderCallbacks callback =
-                new LoaderTest.DummyLoaderCallbacks(mock(Context.class));
-        @SuppressWarnings("unchecked")
-        LoaderManagerImpl.LoaderObserver<Boolean> observer = new LoaderManagerImpl.LoaderObserver<>(
-                mock(Loader.class), callback);
-        assertFalse("onLoaderReset shouldn't be called before onChanged+reset",
-                callback.mOnLoaderReset);
-
-        observer.onChanged(true);
-        observer.reset();
-        assertTrue("onLoaderReset should be called after onChanged+reset",
-                callback.mOnLoaderReset);
-    }
-}
diff --git a/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java b/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
index 5a29135..1d89e27 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
@@ -142,52 +142,6 @@
     }
 
     /**
-     * Test to ensure that loader operations, such as destroyLoader, can safely be called
-     * in onLoadFinished
-     */
-    @Test
-    public void testDestroyFromOnLoadFinished() throws Throwable {
-        final LoaderActivity activity = mActivityRule.getActivity();
-        final CountDownLatch onLoadFinishedLatch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final LoaderManager loaderManager = activity.getSupportLoaderManager();
-                activity.getSupportLoaderManager().initLoader(43, null,
-                        new DummyLoaderCallbacks(activity) {
-                            @Override
-                            public void onLoadFinished(@NonNull Loader<Boolean> loader,
-                                    Boolean data) {
-                                super.onLoadFinished(loader, data);
-                                loaderManager.destroyLoader(43);
-                            }
-                        });
-            }
-        });
-        onLoadFinishedLatch.await(1, TimeUnit.SECONDS);
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void enforceOnMainThread_initLoader() {
-        LoaderActivity activity = mActivityRule.getActivity();
-        activity.getSupportLoaderManager().initLoader(-1, null,
-                new DummyLoaderCallbacks(activity));
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void enforceOnMainThread_restartLoader() {
-        LoaderActivity activity = mActivityRule.getActivity();
-        activity.getSupportLoaderManager().restartLoader(-1, null,
-                new DummyLoaderCallbacks(activity));
-    }
-
-    @Test(expected = IllegalStateException.class)
-    public void enforceOnMainThread_destroyLoader() {
-        LoaderActivity activity = mActivityRule.getActivity();
-        activity.getSupportLoaderManager().destroyLoader(-1);
-    }
-
-    /**
      * When a change is interrupted with stop, the data in the LoaderManager remains stale.
      */
     //@Test
@@ -201,7 +155,7 @@
             @Override
             public void run() {
                 final Loader<String> loader =
-                        activity.getSupportLoaderManager().initLoader(DELAY_LOADER, null,
+                        LoaderManager.getInstance(activity).initLoader(DELAY_LOADER, null,
                                 new LoaderManager.LoaderCallbacks<String>() {
                                     @NonNull
                                     @Override
@@ -272,54 +226,41 @@
         assertEquals("Second Value", activity.textViewB.getText().toString());
     }
 
-
-    public static class LoaderFragment extends Fragment {
+    public static class LoaderFragment extends Fragment implements
+            LoaderManager.LoaderCallbacks<Boolean> {
         private static final int LOADER_ID = 1;
 
         @Override
         public void onActivityCreated(@Nullable Bundle savedInstanceState) {
             super.onActivityCreated(savedInstanceState);
 
-            getLoaderManager().initLoader(LOADER_ID, null,
-                    new DummyLoaderCallbacks(getContext()));
-        }
-    }
-
-    static class DummyLoaderCallbacks implements LoaderManager.LoaderCallbacks<Boolean> {
-        private final Context mContext;
-
-        boolean mOnLoadFinished;
-        boolean mOnLoaderReset;
-
-        DummyLoaderCallbacks(Context context) {
-            mContext = context;
+            LoaderManager.getInstance(this).initLoader(LOADER_ID, null, this);
         }
 
         @NonNull
         @Override
-        public Loader<Boolean> onCreateLoader(int id, Bundle args) {
-            return new DummyLoader(mContext);
+        public Loader<Boolean> onCreateLoader(int id, @Nullable Bundle args) {
+            return new SimpleLoader(requireContext());
         }
 
         @Override
         public void onLoadFinished(@NonNull Loader<Boolean> loader, Boolean data) {
-            mOnLoadFinished = true;
         }
 
         @Override
         public void onLoaderReset(@NonNull Loader<Boolean> loader) {
-            mOnLoaderReset = true;
-        }
-    }
-
-    static class DummyLoader extends Loader<Boolean> {
-        DummyLoader(Context context) {
-            super(context);
         }
 
-        @Override
-        protected void onStartLoading() {
-            deliverResult(true);
+        static class SimpleLoader extends Loader<Boolean> {
+
+            SimpleLoader(@NonNull Context context) {
+                super(context);
+            }
+
+            @Override
+            protected void onStartLoading() {
+                deliverResult(true);
+            }
         }
     }
 }
diff --git a/fragment/src/androidTest/java/android/support/v4/app/LoaderViewModelTest.java b/fragment/src/androidTest/java/android/support/v4/app/LoaderViewModelTest.java
deleted file mode 100644
index 911e169..0000000
--- a/fragment/src/androidTest/java/android/support/v4/app/LoaderViewModelTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.app.test.LoaderActivity;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-@SmallTest
-public class LoaderViewModelTest {
-
-    @Rule
-    public ActivityTestRule<LoaderActivity> mActivityRule =
-            new ActivityTestRule<>(LoaderActivity.class);
-
-    @Test
-    public void testHasRunningLoaders() {
-        LoaderManagerImpl.LoaderViewModel loaderViewModel = new LoaderManagerImpl.LoaderViewModel();
-        assertFalse("LoaderViewModel should not be running with before putLoader",
-                loaderViewModel.hasRunningLoaders());
-
-        AlwaysRunningLoaderInfo info = new AlwaysRunningLoaderInfo(mActivityRule.getActivity());
-        loaderViewModel.putLoader(0, info);
-        assertTrue("LoaderViewModel should be running after a running LoaderInfo is added",
-                loaderViewModel.hasRunningLoaders());
-
-        loaderViewModel.removeLoader(0);
-        assertFalse("LoaderViewModel should not be running after all LoaderInfos are removed",
-                loaderViewModel.hasRunningLoaders());
-    }
-
-    @Test
-    public void testOnCleared() {
-        LoaderManagerImpl.LoaderViewModel loaderViewModel = new LoaderManagerImpl.LoaderViewModel();
-        AlwaysRunningLoaderInfo info = new AlwaysRunningLoaderInfo(
-                mActivityRule.getActivity());
-        loaderViewModel.putLoader(0, info);
-
-        assertFalse("LoaderInfo shouldn't be destroyed before onCleared", info.mDestroyed);
-        loaderViewModel.onCleared();
-        assertTrue("LoaderInfo should be destroyed after onCleared", info.mDestroyed);
-        assertNull("LoaderInfo should be removed from LoaderViewModel after onCleared",
-                loaderViewModel.getLoader(0));
-    }
-
-    private class AlwaysRunningLoaderInfo extends LoaderManagerImpl.LoaderInfo<Boolean> {
-        boolean mDestroyed = false;
-
-        AlwaysRunningLoaderInfo(Context context) {
-            super(0, null, new LoaderTest.DummyLoader(context));
-        }
-
-        @Override
-        boolean isCallbackWaitingForData() {
-            return true;
-        }
-
-        @Override
-        void destroy() {
-            mDestroyed = true;
-        }
-    }
-}
diff --git a/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java b/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
index 3ae5bab..f6ddf9c 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
@@ -57,7 +57,7 @@
     @Override
     protected void onResume() {
         super.onResume();
-        getSupportLoaderManager().initLoader(TEXT_LOADER_ID, null, this);
+        LoaderManager.getInstance(this).initLoader(TEXT_LOADER_ID, null, this);
     }
 
     @NonNull
@@ -98,7 +98,7 @@
         @Override
         public void onCreate(@Nullable Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-            getLoaderManager().initLoader(TEXT_LOADER_ID, null, this);
+            LoaderManager.getInstance(this).initLoader(TEXT_LOADER_ID, null, this);
         }
 
         @Nullable
diff --git a/fragment/src/main/AndroidManifest.xml b/fragment/src/main/AndroidManifest.xml
index ec15d66..85892d2 100644
--- a/fragment/src/main/AndroidManifest.xml
+++ b/fragment/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.fragment">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.fragment"/>
diff --git a/fragment/src/main/java/android/support/v4/app/Fragment.java b/fragment/src/main/java/android/support/v4/app/Fragment.java
index b15c49f..9eade40 100644
--- a/fragment/src/main/java/android/support/v4/app/Fragment.java
+++ b/fragment/src/main/java/android/support/v4/app/Fragment.java
@@ -209,8 +209,6 @@
     // Hint provided by the app that this fragment is currently visible to the user.
     boolean mUserVisibleHint = true;
 
-    LoaderManagerImpl mLoaderManager;
-
     // The animation and transition information for the fragment. This will be null
     // unless the elements are explicitly accessed and should remain null for Fragments
     // without Views.
@@ -971,14 +969,10 @@
     }
 
     /**
-     * Return the LoaderManager for this fragment, creating it if needed.
+     * Return the LoaderManager for this fragment.
      */
     public LoaderManager getLoaderManager() {
-        if (mLoaderManager != null) {
-            return mLoaderManager;
-        }
-        mLoaderManager = new LoaderManagerImpl(this, getViewModelStore());
-        return mLoaderManager;
+        return LoaderManager.getInstance(this);
     }
 
     /**
@@ -2272,10 +2266,7 @@
             writer.print("mStateAfterAnimating=");
             writer.println(getStateAfterAnimating());
         }
-        if (mLoaderManager != null) {
-            writer.print(prefix); writer.println("Loader Manager:");
-            mLoaderManager.dump(prefix + "  ", fd, writer, args);
-        }
+        LoaderManager.getInstance(this).dump(prefix, fd, writer, args);
         if (mChildFragmentManager != null) {
             writer.print(prefix); writer.println("Child " + mChildFragmentManager + ":");
             mChildFragmentManager.dump(prefix + "  ", fd, writer, args);
@@ -2564,13 +2555,11 @@
             throw new SuperNotCalledException("Fragment " + this
                     + " did not call through to super.onDestroyView()");
         }
-        if (mLoaderManager != null) {
-            // Handles the detach/reattach case where the view hierarchy
-            // is destroyed and recreated and an additional call to
-            // onLoadFinished may be needed to ensure the new view
-            // hierarchy is populated from data from the Loaders
-            mLoaderManager.markForRedelivery();
-        }
+        // Handles the detach/reattach case where the view hierarchy
+        // is destroyed and recreated and an additional call to
+        // onLoadFinished may be needed to ensure the new view
+        // hierarchy is populated from data from the Loaders
+        LoaderManager.getInstance(this).markForRedelivery();
         mPerformedCreateView = false;
     }
 
diff --git a/fragment/src/main/java/android/support/v4/app/FragmentActivity.java b/fragment/src/main/java/android/support/v4/app/FragmentActivity.java
index 68bc51e..e47c505 100644
--- a/fragment/src/main/java/android/support/v4/app/FragmentActivity.java
+++ b/fragment/src/main/java/android/support/v4/app/FragmentActivity.java
@@ -100,7 +100,6 @@
 
     };
     final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
-    LoaderManager mLoaderManager;
 
     private ViewModelStore mViewModelStore;
 
@@ -674,13 +673,11 @@
                 writer.println(" State:");
         String innerPrefix = prefix + "  ";
         writer.print(innerPrefix); writer.print("mCreated=");
-                writer.print(mCreated); writer.print("mResumed=");
+                writer.print(mCreated); writer.print(" mResumed=");
                 writer.print(mResumed); writer.print(" mStopped=");
                 writer.print(mStopped); writer.print(" mReallyStopped=");
                 writer.println(mReallyStopped);
-        if (mLoaderManager != null) {
-            mLoaderManager.dump(innerPrefix, fd, writer, args);
-        }
+        LoaderManager.getInstance(this).dump(innerPrefix, fd, writer, args);
         mFragments.getSupportFragmentManager().dump(prefix, fd, writer, args);
     }
 
@@ -728,11 +725,7 @@
     }
 
     public LoaderManager getSupportLoaderManager() {
-        if (mLoaderManager != null) {
-            return mLoaderManager;
-        }
-        mLoaderManager = new LoaderManagerImpl(this, getViewModelStore());
-        return mLoaderManager;
+        return LoaderManager.getInstance(this);
     }
 
     /**
diff --git a/fragment/src/main/java/android/support/v4/app/FragmentManager.java b/fragment/src/main/java/android/support/v4/app/FragmentManager.java
index f53bc32..dc99333 100644
--- a/fragment/src/main/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/src/main/java/android/support/v4/app/FragmentManager.java
@@ -1819,8 +1819,8 @@
             for (int i = 0; i < numAdded; i++) {
                 Fragment f = mAdded.get(i);
                 moveFragmentToExpectedState(f);
-                if (f.mLoaderManager != null) {
-                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
+                if (f.mHost != null) {
+                    loadersRunning |= LoaderManager.getInstance(f).hasRunningLoaders();
                 }
             }
 
@@ -1831,8 +1831,8 @@
                 Fragment f = mActive.valueAt(i);
                 if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
                     moveFragmentToExpectedState(f);
-                    if (f.mLoaderManager != null) {
-                        loadersRunning |= f.mLoaderManager.hasRunningLoaders();
+                    if (f.mHost != null) {
+                        loadersRunning |= LoaderManager.getInstance(f).hasRunningLoaders();
                     }
                 }
             }
@@ -2695,8 +2695,8 @@
             boolean loadersRunning = false;
             for (int i = 0; i < mActive.size(); i++) {
                 Fragment f = mActive.valueAt(i);
-                if (f != null && f.mLoaderManager != null) {
-                    loadersRunning |= f.mLoaderManager.hasRunningLoaders();
+                if (f != null && f.mHost != null) {
+                    loadersRunning |= LoaderManager.getInstance(f).hasRunningLoaders();
                 }
             }
             if (!loadersRunning) {
diff --git a/fragment/src/main/java/android/support/v4/app/LoaderManager.java b/fragment/src/main/java/android/support/v4/app/LoaderManager.java
deleted file mode 100644
index 4b08aec..0000000
--- a/fragment/src/main/java/android/support/v4/app/LoaderManager.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import android.os.Bundle;
-import android.support.annotation.MainThread;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.Loader;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Static library support version of the framework's {@link android.app.LoaderManager}.
- * Used to write apps that run on platforms prior to Android 3.0.  When running
- * on Android 3.0 or above, this implementation is still used; it does not try
- * to switch to the framework's implementation.  See the framework SDK
- * documentation for a class overview.
- *
- * <p>Your activity must derive from {@link FragmentActivity} to use this.
- */
-public abstract class LoaderManager {
-    /**
-     * Callback interface for a client to interact with the manager.
-     */
-    public interface LoaderCallbacks<D> {
-        /**
-         * Instantiate and return a new Loader for the given ID.
-         *
-         * <p>This will always be called from the process's main thread.
-         *
-         * @param id The ID whose loader is to be created.
-         * @param args Any arguments supplied by the caller.
-         * @return Return a new Loader instance that is ready to start loading.
-         */
-        @MainThread
-        @NonNull
-        Loader<D> onCreateLoader(int id, @Nullable Bundle args);
-
-        /**
-         * Called when a previously created loader has finished its load.  Note
-         * that normally an application is <em>not</em> allowed to commit fragment
-         * transactions while in this call, since it can happen after an
-         * activity's state is saved.  See {@link FragmentManager#beginTransaction()
-         * FragmentManager.openTransaction()} for further discussion on this.
-         *
-         * <p>This function is guaranteed to be called prior to the release of
-         * the last data that was supplied for this Loader.  At this point
-         * you should remove all use of the old data (since it will be released
-         * soon), but should not do your own release of the data since its Loader
-         * owns it and will take care of that.  The Loader will take care of
-         * management of its data so you don't have to.  In particular:
-         *
-         * <ul>
-         * <li> <p>The Loader will monitor for changes to the data, and report
-         * them to you through new calls here.  You should not monitor the
-         * data yourself.  For example, if the data is a {@link android.database.Cursor}
-         * and you place it in a {@link android.widget.CursorAdapter}, use
-         * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context,
-         * android.database.Cursor, int)} constructor <em>without</em> passing
-         * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY}
-         * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER}
-         * (that is, use 0 for the flags argument).  This prevents the CursorAdapter
-         * from doing its own observing of the Cursor, which is not needed since
-         * when a change happens you will get a new Cursor throw another call
-         * here.
-         * <li> The Loader will release the data once it knows the application
-         * is no longer using it.  For example, if the data is
-         * a {@link android.database.Cursor} from a {@link android.content.CursorLoader},
-         * you should not call close() on it yourself.  If the Cursor is being placed in a
-         * {@link android.widget.CursorAdapter}, you should use the
-         * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)}
-         * method so that the old Cursor is not closed.
-         * </ul>
-         *
-         * <p>This will always be called from the process's main thread.
-         *
-         * @param loader The Loader that has finished.
-         * @param data The data generated by the Loader.
-         */
-        @MainThread
-        void onLoadFinished(@NonNull Loader<D> loader, D data);
-
-        /**
-         * Called when a previously created loader is being reset, and thus
-         * making its data unavailable.  The application should at this point
-         * remove any references it has to the Loader's data.
-         *
-         * <p>This will always be called from the process's main thread.
-         *
-         * @param loader The Loader that is being reset.
-         */
-        @MainThread
-        void onLoaderReset(@NonNull Loader<D> loader);
-    }
-
-    /**
-     * Ensures a loader is initialized and active.  If the loader doesn't
-     * already exist, one is created and (if the activity/fragment is currently
-     * started) starts the loader.  Otherwise the last created
-     * loader is re-used.
-     *
-     * <p>In either case, the given callback is associated with the loader, and
-     * will be called as the loader state changes.  If at the point of call
-     * the caller is in its started state, and the requested loader
-     * already exists and has generated its data, then
-     * callback {@link LoaderCallbacks#onLoadFinished} will
-     * be called immediately (inside of this function), so you must be prepared
-     * for this to happen.
-     *
-     * <p>Must be called from the process's main thread.
-     *
-     * @param id A unique identifier for this loader.  Can be whatever you want.
-     * Identifiers are scoped to a particular LoaderManager instance.
-     * @param args Optional arguments to supply to the loader at construction.
-     * If a loader already exists (a new one does not need to be created), this
-     * parameter will be ignored and the last arguments continue to be used.
-     * @param callback Interface the LoaderManager will call to report about
-     * changes in the state of the loader.  Required.
-     */
-    @MainThread
-    @NonNull
-    public abstract <D> Loader<D> initLoader(int id, @Nullable Bundle args,
-            @NonNull LoaderManager.LoaderCallbacks<D> callback);
-
-    /**
-     * Starts a new or restarts an existing {@link android.content.Loader} in
-     * this manager, registers the callbacks to it,
-     * and (if the activity/fragment is currently started) starts loading it.
-     * If a loader with the same id has previously been
-     * started it will automatically be destroyed when the new loader completes
-     * its work. The callback will be delivered before the old loader
-     * is destroyed.
-     *
-     * <p>Must be called from the process's main thread.
-     *
-     * @param id A unique identifier for this loader.  Can be whatever you want.
-     * Identifiers are scoped to a particular LoaderManager instance.
-     * @param args Optional arguments to supply to the loader at construction.
-     * @param callback Interface the LoaderManager will call to report about
-     * changes in the state of the loader.  Required.
-     */
-    @MainThread
-    @NonNull
-    public abstract <D> Loader<D> restartLoader(int id, @Nullable Bundle args,
-            @NonNull LoaderManager.LoaderCallbacks<D> callback);
-
-    /**
-     * Stops and removes the loader with the given ID.  If this loader
-     * had previously reported data to the client through
-     * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call
-     * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}.
-     *
-     * <p>Must be called from the process's main thread.
-     */
-    @MainThread
-    public abstract void destroyLoader(int id);
-
-    /**
-     * Return the Loader with the given id or null if no matching Loader
-     * is found.
-     */
-    @Nullable
-    public abstract <D> Loader<D> getLoader(int id);
-
-    /**
-     * Print the LoaderManager's state into the given stream.
-     *
-     * @param prefix Text to print at the front of each line.
-     * @param fd The raw file descriptor that the dump is being sent to.
-     * @param writer A PrintWriter to which the dump is to be set.
-     * @param args Additional arguments to the dump request.
-     */
-    public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
-
-    /**
-     * Control whether the framework's internal loader manager debugging
-     * logs are turned on.  If enabled, you will see output in logcat as
-     * the framework performs loader operations.
-     */
-    public static void enableDebugLogging(boolean enabled) {
-        LoaderManagerImpl.DEBUG = enabled;
-    }
-
-    /**
-     * Returns true if any loaders managed are currently running and have not
-     * returned data to the application yet.
-     */
-    public boolean hasRunningLoaders() { return false; }
-}
diff --git a/fragment/src/main/java/android/support/v4/app/LoaderManagerImpl.java b/fragment/src/main/java/android/support/v4/app/LoaderManagerImpl.java
deleted file mode 100644
index 17687ff..0000000
--- a/fragment/src/main/java/android/support/v4/app/LoaderManagerImpl.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v4.app;
-
-import android.arch.lifecycle.LifecycleOwner;
-import android.arch.lifecycle.MutableLiveData;
-import android.arch.lifecycle.Observer;
-import android.arch.lifecycle.ViewModel;
-import android.arch.lifecycle.ViewModelProvider;
-import android.arch.lifecycle.ViewModelStore;
-import android.os.Bundle;
-import android.os.Looper;
-import android.support.annotation.MainThread;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.content.Loader;
-import android.support.v4.util.DebugUtils;
-import android.support.v4.util.SparseArrayCompat;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.reflect.Modifier;
-
-class LoaderManagerImpl extends LoaderManager {
-    static final String TAG = "LoaderManager";
-    static boolean DEBUG = false;
-
-    /**
-     * Class which manages the state of a {@link Loader} and its associated
-     * {@link LoaderCallbacks}
-     *
-     * @param <D> Type of data the Loader handles
-     */
-    public static class LoaderInfo<D> extends MutableLiveData<D>
-            implements Loader.OnLoadCompleteListener<D> {
-
-        private final int mId;
-        private final @Nullable Bundle mArgs;
-        private final @NonNull Loader<D> mLoader;
-        private LifecycleOwner mLifecycleOwner;
-        private LoaderObserver<D> mObserver;
-
-        LoaderInfo(int id, @Nullable Bundle args, @NonNull Loader<D> loader) {
-            mId = id;
-            mArgs = args;
-            mLoader = loader;
-            mLoader.registerListener(id, this);
-        }
-
-        @NonNull
-        Loader<D> getLoader() {
-            return mLoader;
-        }
-
-        @Override
-        protected void onActive() {
-            if (DEBUG) Log.v(TAG, "  Starting: " + LoaderInfo.this);
-            mLoader.startLoading();
-        }
-
-        @Override
-        protected void onInactive() {
-            if (DEBUG) Log.v(TAG, "  Stopping: " + LoaderInfo.this);
-            mLoader.stopLoading();
-        }
-
-        /**
-         * Set the {@link LoaderCallbacks} to associate with this {@link Loader}. This
-         * removes any existing {@link LoaderCallbacks}.
-         *
-         * @param owner The lifecycle that should be used to start and stop the {@link Loader}
-         * @param callback The new {@link LoaderCallbacks} to use
-         * @return The {@link Loader} associated with this LoaderInfo
-         */
-        @MainThread
-        @NonNull
-        Loader<D> setCallback(@NonNull LifecycleOwner owner,
-                @NonNull LoaderCallbacks<D> callback) {
-            LoaderObserver<D> observer = new LoaderObserver<>(mLoader, callback);
-            // Add the new observer
-            observe(owner, observer);
-            // Loaders only support one observer at a time, so remove the current observer, if any
-            if (mObserver != null) {
-                removeObserver(mObserver);
-            }
-            mLifecycleOwner = owner;
-            mObserver = observer;
-            return mLoader;
-        }
-
-        void markForRedelivery() {
-            LifecycleOwner lifecycleOwner = mLifecycleOwner;
-            LoaderObserver<D> observer = mObserver;
-            if (lifecycleOwner != null && observer != null) {
-                // Removing and re-adding the observer ensures that the
-                // observer is called again, even if they had already
-                // received the current data
-                removeObserver(observer);
-                observe(lifecycleOwner, observer);
-            }
-        }
-
-        boolean isCallbackWaitingForData() {
-            //noinspection SimplifiableIfStatement
-            if (!hasActiveObservers()) {
-                // No active observers means no one is waiting for data
-                return false;
-            }
-            return mObserver != null && !mObserver.hasDeliveredData();
-        }
-
-        @Override
-        public void removeObserver(@NonNull Observer<D> observer) {
-            super.removeObserver(observer);
-            // Clear out our references when the observer is removed to avoid leaking
-            mLifecycleOwner = null;
-            mObserver = null;
-        }
-
-        @MainThread
-        void destroy() {
-            if (DEBUG) Log.v(TAG, "  Destroying: " + this);
-            // First tell the Loader that we don't need it anymore
-            mLoader.cancelLoad();
-            mLoader.abandon();
-            // Then clean up the LoaderObserver
-            LoaderObserver<D> observer = mObserver;
-            if (observer != null) {
-                removeObserver(observer);
-                observer.reset();
-            }
-            // Finally, send the reset to the Loader
-            mLoader.unregisterListener(this);
-            mLoader.reset();
-        }
-
-        @Override
-        public void onLoadComplete(@NonNull Loader<D> loader, @Nullable D data) {
-            if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
-            if (Looper.myLooper() == Looper.getMainLooper()) {
-                setValue(data);
-            } else {
-                // The Loader#deliverResult method that calls this should
-                // only be called on the main thread, so this should never
-                // happen, but we don't want to lose the data
-                if (DEBUG) {
-                    Log.w(TAG, "onLoadComplete was incorrectly called on a "
-                            + "background thread");
-                }
-                postValue(data);
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(64);
-            sb.append("LoaderInfo{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" #");
-            sb.append(mId);
-            sb.append(" : ");
-            DebugUtils.buildShortClassTag(mLoader, sb);
-            sb.append("}}");
-            return sb.toString();
-        }
-
-        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
-            writer.print(prefix); writer.print("mId="); writer.print(mId);
-            writer.print(" mArgs="); writer.println(mArgs);
-            writer.print(prefix); writer.print("mLoader="); writer.println(mLoader);
-            mLoader.dump(prefix + "  ", fd, writer, args);
-            if (mObserver != null) {
-                writer.print(prefix); writer.print("mCallbacks="); writer.println(mObserver);
-                mObserver.dump(prefix + "  ", writer);
-            }
-            writer.print(prefix); writer.print("mData="); writer.println(
-                    getLoader().dataToString(getValue()));
-            writer.print(prefix); writer.print("mStarted="); writer.println(
-                    hasActiveObservers());
-        }
-    }
-
-    /**
-     * Encapsulates the {@link LoaderCallbacks} as a {@link Observer}.
-     *
-     * @param <D> Type of data the LoaderCallbacks handles
-     */
-    static class LoaderObserver<D> implements Observer<D> {
-
-        private final @NonNull Loader<D> mLoader;
-        private final @NonNull LoaderCallbacks<D> mCallback;
-
-        private boolean mDeliveredData = false;
-
-        LoaderObserver(@NonNull Loader<D> loader, @NonNull LoaderCallbacks<D> callback) {
-            mLoader = loader;
-            mCallback = callback;
-        }
-
-        @Override
-        public void onChanged(@Nullable D data) {
-            if (DEBUG) {
-                Log.v(TAG, "  onLoadFinished in " + mLoader + ": "
-                        + mLoader.dataToString(data));
-            }
-            mCallback.onLoadFinished(mLoader, data);
-            mDeliveredData = true;
-        }
-
-        boolean hasDeliveredData() {
-            return mDeliveredData;
-        }
-
-        @MainThread
-        void reset() {
-            if (mDeliveredData) {
-                if (DEBUG) Log.v(TAG, "  Resetting: " + mLoader);
-                mCallback.onLoaderReset(mLoader);
-            }
-        }
-
-        @Override
-        public String toString() {
-            return mCallback.toString();
-        }
-
-        public void dump(String prefix, PrintWriter writer) {
-            writer.print(prefix); writer.print("mDeliveredData="); writer.println(
-                    mDeliveredData);
-        }
-    }
-
-    /**
-     * ViewModel responsible for retaining {@link LoaderInfo} instances across configuration changes
-     */
-    static class LoaderViewModel extends ViewModel {
-        private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
-            @NonNull
-            @Override
-            @SuppressWarnings("unchecked")
-            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
-                return (T) new LoaderViewModel();
-            }
-        };
-
-        @NonNull
-        static LoaderViewModel getInstance(ViewModelStore viewModelStore) {
-            return new ViewModelProvider(viewModelStore, FACTORY).get(LoaderViewModel.class);
-        }
-
-        private SparseArrayCompat<LoaderInfo> mLoaders = new SparseArrayCompat<>();
-
-        void putLoader(int id, @NonNull LoaderInfo info) {
-            mLoaders.put(id, info);
-        }
-
-        @SuppressWarnings("unchecked")
-        <D> LoaderInfo<D> getLoader(int id) {
-            return mLoaders.get(id);
-        }
-
-        void removeLoader(int id) {
-            mLoaders.remove(id);
-        }
-
-        boolean hasRunningLoaders() {
-            int size = mLoaders.size();
-            for (int index = 0; index < size; index++) {
-                LoaderInfo info = mLoaders.valueAt(index);
-                if (info.isCallbackWaitingForData()) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        void markForRedelivery() {
-            int size = mLoaders.size();
-            for (int index = 0; index < size; index++) {
-                LoaderInfo info = mLoaders.valueAt(index);
-                info.markForRedelivery();
-            }
-        }
-
-        @Override
-        protected void onCleared() {
-            super.onCleared();
-            int size = mLoaders.size();
-            for (int index = 0; index < size; index++) {
-                LoaderInfo info = mLoaders.valueAt(index);
-                info.destroy();
-            }
-            mLoaders.clear();
-        }
-
-        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
-            if (mLoaders.size() > 0) {
-                writer.print(prefix); writer.println("Loaders:");
-                String innerPrefix = prefix + "    ";
-                for (int i = 0; i < mLoaders.size(); i++) {
-                    LoaderInfo info = mLoaders.valueAt(i);
-                    writer.print(prefix); writer.print("  #"); writer.print(mLoaders.keyAt(i));
-                    writer.print(": "); writer.println(info.toString());
-                    info.dump(innerPrefix, fd, writer, args);
-                }
-            }
-        }
-    }
-
-    private final @NonNull LifecycleOwner mLifecycleOwner;
-    private final @NonNull LoaderViewModel mLoaderViewModel;
-
-    private boolean mCreatingLoader;
-
-    LoaderManagerImpl(@NonNull LifecycleOwner lifecycleOwner,
-            @NonNull ViewModelStore viewModelStore) {
-        mLifecycleOwner = lifecycleOwner;
-        mLoaderViewModel = LoaderViewModel.getInstance(viewModelStore);
-    }
-
-    @MainThread
-    @NonNull
-    private <D> Loader<D> createAndInstallLoader(int id, @Nullable Bundle args,
-            @NonNull LoaderCallbacks<D> callback) {
-        LoaderInfo<D> info;
-        try {
-            mCreatingLoader = true;
-            Loader<D> loader = callback.onCreateLoader(id, args);
-            if (loader.getClass().isMemberClass()
-                    && !Modifier.isStatic(loader.getClass().getModifiers())) {
-                throw new IllegalArgumentException("Object returned from onCreateLoader "
-                        + "must not be a non-static inner member class: "
-                        + loader);
-            }
-            info = new LoaderInfo<>(id, args, loader);
-            if (DEBUG) Log.v(TAG, "  Created new loader " + info);
-            mLoaderViewModel.putLoader(id, info);
-        } finally {
-            mCreatingLoader = false;
-        }
-        return info.setCallback(mLifecycleOwner, callback);
-    }
-
-    @MainThread
-    @NonNull
-    @Override
-    public <D> Loader<D> initLoader(int id, @Nullable Bundle args,
-            @NonNull LoaderCallbacks<D> callback) {
-        if (mCreatingLoader) {
-            throw new IllegalStateException("Called while creating a loader");
-        }
-        if (Looper.getMainLooper() != Looper.myLooper()) {
-            throw new IllegalStateException("initLoader must be called on the main thread");
-        }
-
-        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
-
-        if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
-
-        if (info == null) {
-            // Loader doesn't already exist; create.
-            return createAndInstallLoader(id, args, callback);
-        } else {
-            if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
-            return info.setCallback(mLifecycleOwner, callback);
-        }
-    }
-
-    @MainThread
-    @NonNull
-    @Override
-    public <D> Loader<D> restartLoader(int id, @Nullable Bundle args,
-            @NonNull LoaderCallbacks<D> callback) {
-        if (mCreatingLoader) {
-            throw new IllegalStateException("Called while creating a loader");
-        }
-        if (Looper.getMainLooper() != Looper.myLooper()) {
-            throw new IllegalStateException("restartLoader must be called on the main thread");
-        }
-
-        if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
-        // Destroy any existing Loader
-        destroyLoader(id);
-        // And create a new Loader
-        return createAndInstallLoader(id, args, callback);
-    }
-
-    @MainThread
-    @Override
-    public void destroyLoader(int id) {
-        if (mCreatingLoader) {
-            throw new IllegalStateException("Called while creating a loader");
-        }
-        if (Looper.getMainLooper() != Looper.myLooper()) {
-            throw new IllegalStateException("destroyLoader must be called on the main thread");
-        }
-
-        if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
-        LoaderInfo info = mLoaderViewModel.getLoader(id);
-        if (info != null) {
-            info.destroy();
-            mLoaderViewModel.removeLoader(id);
-        }
-    }
-
-    @Nullable
-    @Override
-    public <D> Loader<D> getLoader(int id) {
-        if (mCreatingLoader) {
-            throw new IllegalStateException("Called while creating a loader");
-        }
-
-        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
-        return info != null ? info.getLoader() : null;
-    }
-
-    /**
-     * Mark all Loaders associated with this LoaderManager for redelivery of their current
-     * data (if any) the next time the LifecycleOwner is started. In cases where no data has
-     * yet been delivered, this is effectively a no-op. In cases where data has already been
-     * delivered via {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, this will ensure
-     * that {@link LoaderCallbacks#onLoadFinished(Loader, Object)} is called again with the
-     * same data.
-     */
-    void markForRedelivery() {
-        mLoaderViewModel.markForRedelivery();
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder(128);
-        sb.append("LoaderManager{");
-        sb.append(Integer.toHexString(System.identityHashCode(this)));
-        sb.append(" in ");
-        DebugUtils.buildShortClassTag(mLifecycleOwner, sb);
-        sb.append("}}");
-        return sb.toString();
-    }
-
-    @Override
-    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
-        mLoaderViewModel.dump(prefix, fd, writer, args);
-    }
-
-    @Override
-    public boolean hasRunningLoaders() {
-        return mLoaderViewModel.hasRunningLoaders();
-    }
-}
diff --git a/graphics/Android.mk b/graphics/Android.mk
deleted file mode 100644
index 365b3b1..0000000
--- a/graphics/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/graphics/OWNERS b/graphics/OWNERS
deleted file mode 100644
index 4e6deac..0000000
--- a/graphics/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-ztenghui@google.com
\ No newline at end of file
diff --git a/graphics/drawable/Android.mk b/graphics/drawable/Android.mk
deleted file mode 100644
index 6667dd9..0000000
--- a/graphics/drawable/Android.mk
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# ---------------------------------------------
-#
-# Static vector drawable library
-#
-# ---------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-vectordrawable
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, static/src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/static/res
-LOCAL_MANIFEST_FILE := static/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# ---------------------------------------------
-#
-# Animated vector drawable library
-#
-# ---------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-animatedvectordrawable
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, animated/src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/animated/res
-LOCAL_MANIFEST_FILE := animated/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat \
-    android-support-vectordrawable \
-    android-support-core-ui
-LOCAL_AAPT_FLAGS := --no-version-vectors --add-javadoc-annotation doconly
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/graphics/drawable/animated/AndroidManifest.xml b/graphics/drawable/animated/AndroidManifest.xml
deleted file mode 100644
index 166b786..0000000
--- a/graphics/drawable/animated/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-   Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-        http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.graphics.drawable.animated">
-</manifest>
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index 30827a9..2f18053 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -36,5 +36,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support AnimatedVectorDrawable"
-    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/graphics/drawable/animated/tests/AndroidManifest.xml b/graphics/drawable/animated/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from graphics/drawable/animated/tests/AndroidManifest.xml
rename to graphics/drawable/animated/src/androidTest/AndroidManifest.xml
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java b/graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java
similarity index 100%
rename from graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java
rename to graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/AnimatedVectorDrawableParameterizedTest.java
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java b/graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
similarity index 100%
rename from graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
rename to graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/AnimatedVectorDrawableTest.java
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/DrawableStubActivity.java b/graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/DrawableStubActivity.java
similarity index 100%
rename from graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/DrawableStubActivity.java
rename to graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/DrawableStubActivity.java
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/DrawableUtils.java b/graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/DrawableUtils.java
similarity index 100%
rename from graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/DrawableUtils.java
rename to graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/DrawableUtils.java
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/PathInterpolatorExceptionParameterizedTest.java b/graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/PathInterpolatorExceptionParameterizedTest.java
similarity index 100%
rename from graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/PathInterpolatorExceptionParameterizedTest.java
rename to graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/PathInterpolatorExceptionParameterizedTest.java
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/PathInterpolatorParameterizedTest.java b/graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/PathInterpolatorParameterizedTest.java
similarity index 100%
rename from graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/PathInterpolatorParameterizedTest.java
rename to graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/PathInterpolatorParameterizedTest.java
diff --git a/graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/PathInterpolatorValueParameterizedTest.java b/graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/PathInterpolatorValueParameterizedTest.java
similarity index 100%
rename from graphics/drawable/animated/tests/src/android/support/graphics/drawable/tests/PathInterpolatorValueParameterizedTest.java
rename to graphics/drawable/animated/src/androidTest/java/android/support/graphics/drawable/tests/PathInterpolatorValueParameterizedTest.java
diff --git a/graphics/drawable/animated/tests/res/anim/animation_grouping_1_01.xml b/graphics/drawable/animated/src/androidTest/res/anim/animation_grouping_1_01.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/animation_grouping_1_01.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/animation_grouping_1_01.xml
diff --git a/graphics/drawable/animated/tests/res/anim/animation_rect.xml b/graphics/drawable/animated/src/androidTest/res/anim/animation_rect.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/animation_rect.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/animation_rect.xml
diff --git a/graphics/drawable/animated/tests/res/anim/animation_rect_exception.xml b/graphics/drawable/animated/src/androidTest/res/anim/animation_rect_exception.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/animation_rect_exception.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/animation_rect_exception.xml
diff --git a/graphics/drawable/animated/tests/res/anim/color_anim.xml b/graphics/drawable/animated/src/androidTest/res/anim/color_anim.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/color_anim.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/color_anim.xml
diff --git a/graphics/drawable/animated/tests/res/anim/path_motion_object.xml b/graphics/drawable/animated/src/androidTest/res/anim/path_motion_object.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/path_motion_object.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/path_motion_object.xml
diff --git a/graphics/drawable/animated/tests/res/anim/shift_to_center_1.xml b/graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_1.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/shift_to_center_1.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_1.xml
diff --git a/graphics/drawable/animated/tests/res/anim/shift_to_center_2.xml b/graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_2.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/shift_to_center_2.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_2.xml
diff --git a/graphics/drawable/animated/tests/res/anim/shift_to_center_exception_1.xml b/graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_1.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/shift_to_center_exception_1.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_1.xml
diff --git a/graphics/drawable/animated/tests/res/anim/shift_to_center_exception_2.xml b/graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_2.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/shift_to_center_exception_2.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_2.xml
diff --git a/graphics/drawable/animated/tests/res/anim/shift_to_center_exception_3.xml b/graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_3.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/shift_to_center_exception_3.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_3.xml
diff --git a/graphics/drawable/animated/tests/res/anim/shift_to_center_exception_4.xml b/graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_4.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/shift_to_center_exception_4.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_4.xml
diff --git a/graphics/drawable/animated/tests/res/anim/shift_to_center_exception_5.xml b/graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_5.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/anim/shift_to_center_exception_5.xml
rename to graphics/drawable/animated/src/androidTest/res/anim/shift_to_center_exception_5.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animated_color_fill.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animated_color_fill.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animated_color_fill.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animated_color_fill.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animated_color_fill_copy.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animated_color_fill_copy.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animated_color_fill_copy.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animated_color_fill_copy.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_1.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_1.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_1.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_1.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_2.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_2.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_2.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_2.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_1.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_1.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_1.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_1.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_2.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_2.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_2.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_2.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_3.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_3.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_3.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_3.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_4.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_4.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_4.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_4.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_5.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_5.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_interpolator_exception_5.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_interpolator_exception_5.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_morphing_rect.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_morphing_rect.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_morphing_rect.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_morphing_rect.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_morphing_rect2.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_morphing_rect2.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_morphing_rect2.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_morphing_rect2.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_morphing_rect_exception.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_morphing_rect_exception.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_morphing_rect_exception.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_morphing_rect_exception.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_path_motion_rect.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_path_motion_rect.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_path_motion_rect.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_path_motion_rect.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_vector_drawable_circle.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_vector_drawable_circle.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_vector_drawable_circle.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_vector_drawable_circle.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/animation_vector_drawable_grouping_1.xml b/graphics/drawable/animated/src/androidTest/res/drawable/animation_vector_drawable_grouping_1.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/animation_vector_drawable_grouping_1.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/animation_vector_drawable_grouping_1.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/rect.xml b/graphics/drawable/animated/src/androidTest/res/drawable/rect.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/rect.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/rect.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/small_rect.xml b/graphics/drawable/animated/src/androidTest/res/drawable/small_rect.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/small_rect.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/small_rect.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/vector_drawable_circle.xml b/graphics/drawable/animated/src/androidTest/res/drawable/vector_drawable_circle.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/vector_drawable_circle.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/vector_drawable_circle.xml
diff --git a/graphics/drawable/animated/tests/res/drawable/vector_drawable_grouping_1.xml b/graphics/drawable/animated/src/androidTest/res/drawable/vector_drawable_grouping_1.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/drawable/vector_drawable_grouping_1.xml
rename to graphics/drawable/animated/src/androidTest/res/drawable/vector_drawable_grouping_1.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/control_points_interpolator.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/control_points_interpolator.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/control_points_interpolator.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/control_points_interpolator.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/path_interpolator.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/path_interpolator.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/path_interpolator.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/path_interpolator.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/single_control_point_interpolator.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/single_control_point_interpolator.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/single_control_point_interpolator.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/single_control_point_interpolator.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/wrong_control_point_interpolator.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/wrong_control_point_interpolator.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/wrong_control_point_interpolator.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/wrong_control_point_interpolator.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/wrong_control_points_interpolator.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/wrong_control_points_interpolator.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/wrong_control_points_interpolator.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/wrong_control_points_interpolator.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/wrong_path_interpolator_1.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/wrong_path_interpolator_1.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/wrong_path_interpolator_1.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/wrong_path_interpolator_1.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/wrong_path_interpolator_2.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/wrong_path_interpolator_2.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/wrong_path_interpolator_2.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/wrong_path_interpolator_2.xml
diff --git a/graphics/drawable/animated/tests/res/interpolator/wrong_path_interpolator_3.xml b/graphics/drawable/animated/src/androidTest/res/interpolator/wrong_path_interpolator_3.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/interpolator/wrong_path_interpolator_3.xml
rename to graphics/drawable/animated/src/androidTest/res/interpolator/wrong_path_interpolator_3.xml
diff --git a/graphics/drawable/animated/tests/res/layout/avd_layout.xml b/graphics/drawable/animated/src/androidTest/res/layout/avd_layout.xml
similarity index 100%
rename from graphics/drawable/animated/tests/res/layout/avd_layout.xml
rename to graphics/drawable/animated/src/androidTest/res/layout/avd_layout.xml
diff --git a/graphics/drawable/animated/src/main/AndroidManifest.xml b/graphics/drawable/animated/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..0f341f7
--- /dev/null
+++ b/graphics/drawable/animated/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+  -->
+<manifest package="android.support.graphics.drawable.animated"/>
diff --git a/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
index cff61bc..bc521cc 100644
--- a/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
+++ b/graphics/drawable/animated/src/main/java/android/support/graphics/drawable/AnimatedVectorDrawableCompat.java
@@ -118,6 +118,9 @@
  *         <td>trimPathStart</td>
  *     </tr>
  *     <tr>
+ *         <td>trimPathEnd</td>
+ *     </tr>
+ *     <tr>
  *         <td>trimPathOffset</td>
  *     </tr>
  * </table>
diff --git a/graphics/drawable/animated/tests/NO_DOCS b/graphics/drawable/animated/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/graphics/drawable/animated/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index f0ac9f0..9388480 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -31,5 +31,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support VectorDrawable"
-    legacySourceLocation = true
 }
\ No newline at end of file
diff --git a/graphics/drawable/static/tests/AndroidManifest.xml b/graphics/drawable/static/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from graphics/drawable/static/tests/AndroidManifest.xml
rename to graphics/drawable/static/src/androidTest/AndroidManifest.xml
diff --git a/graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java b/graphics/drawable/static/src/androidTest/java/android/support/graphics/drawable/tests/VectorDrawableTest.java
similarity index 100%
rename from graphics/drawable/static/tests/src/android/support/graphics/drawable/tests/VectorDrawableTest.java
rename to graphics/drawable/static/src/androidTest/java/android/support/graphics/drawable/tests/VectorDrawableTest.java
diff --git a/graphics/drawable/static/tests/res/color/vector_icon_fill_state_list.xml b/graphics/drawable/static/src/androidTest/res/color/vector_icon_fill_state_list.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/color/vector_icon_fill_state_list.xml
rename to graphics/drawable/static/src/androidTest/res/color/vector_icon_fill_state_list.xml
diff --git a/graphics/drawable/static/tests/res/color/vector_icon_stroke_state_list.xml b/graphics/drawable/static/src/androidTest/res/color/vector_icon_stroke_state_list.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/color/vector_icon_stroke_state_list.xml
rename to graphics/drawable/static/src/androidTest/res/color/vector_icon_stroke_state_list.xml
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_clip_path_1_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_clip_path_1_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_create_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_create_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_create_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_create_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_delete_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_delete_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_delete_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_delete_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_filltype_evenodd_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_filltype_nonzero_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_five_bars_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_five_bars_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_five_bars_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_five_bars_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_group_clip_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_group_clip_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_group_clip_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_group_clip_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_heart_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_heart_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_heart_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_heart_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_random_path_1_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_random_path_1_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_random_path_1_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_random_path_1_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_random_path_2_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_random_path_2_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_random_path_2_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_random_path_2_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_render_order_1_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_render_order_1_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_render_order_1_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_render_order_1_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_render_order_2_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_render_order_2_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_render_order_2_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_render_order_2_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_a_1_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_a_2_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_cq_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_cq_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_st_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_st_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_repeated_st_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_repeated_st_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_scale_1_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_scale_1_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_scale_1_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_scale_1_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_scale_2_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_scale_2_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_scale_2_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_scale_2_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_schedule_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_schedule_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_schedule_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_schedule_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_settings_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_settings_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_settings_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_settings_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_share_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_share_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_share_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_stroke_1_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_stroke_1_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_stroke_1_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_stroke_1_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_stroke_2_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_stroke_2_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_stroke_2_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_stroke_2_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_stroke_3_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_stroke_3_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_stroke_3_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_stroke_3_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_1_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_1_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_1_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_1_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_2_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_2_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_2_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_2_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_3_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_3_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_3_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_3_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_4_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_4_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_4_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_4_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_5_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_5_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_5_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_5_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_6_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_6_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_transformation_6_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_transformation_6_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png b/graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_wishlist_golden.png
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable-nodpi/vector_icon_wishlist_golden.png
rename to graphics/drawable/static/src/androidTest/res/drawable-nodpi/vector_icon_wishlist_golden.png
Binary files differ
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_clip_path_1.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_clip_path_1.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_clip_path_1.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_clip_path_1.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_create.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_create.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_create.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_create.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_delete.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_delete.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_delete.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_delete.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_filltype_evenodd.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_filltype_evenodd.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_filltype_evenodd.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_filltype_evenodd.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_filltype_nonzero.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_filltype_nonzero.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_filltype_nonzero.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_filltype_nonzero.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_five_bars.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_five_bars.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_five_bars.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_five_bars.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_group_clip.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_group_clip.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_group_clip.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_group_clip.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_heart.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_heart.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_heart.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_heart.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_random_path_1.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_random_path_1.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_random_path_1.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_random_path_1.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_random_path_2.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_random_path_2.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_random_path_2.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_random_path_2.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_render_order_1.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_render_order_1.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_render_order_1.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_render_order_1.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_render_order_2.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_render_order_2.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_render_order_2.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_render_order_2.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_repeated_a_1.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_a_1.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_repeated_a_1.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_a_1.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_repeated_a_2.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_a_2.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_repeated_a_2.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_a_2.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_repeated_cq.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_cq.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_repeated_cq.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_cq.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_repeated_st.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_st.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_repeated_st.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_repeated_st.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_scale_1.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_scale_1.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_scale_1.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_scale_1.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_scale_2.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_scale_2.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_scale_2.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_scale_2.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_schedule.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_schedule.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_schedule.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_schedule.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_settings.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_settings.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_settings.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_settings.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_share.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_share.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_share.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_share.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_state_list.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_state_list.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_state_list.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_state_list.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_stroke_1.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_stroke_1.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_stroke_1.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_stroke_1.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_stroke_2.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_stroke_2.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_stroke_2.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_stroke_2.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_stroke_3.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_stroke_3.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_stroke_3.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_stroke_3.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_transformation_1.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_1.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_transformation_1.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_1.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_transformation_2.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_2.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_transformation_2.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_2.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_transformation_3.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_3.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_transformation_3.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_3.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_transformation_4.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_4.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_transformation_4.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_4.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_transformation_5.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_5.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_transformation_5.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_5.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_transformation_6.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_6.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_transformation_6.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_transformation_6.xml
diff --git a/graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml b/graphics/drawable/static/src/androidTest/res/drawable/vector_icon_wishlist.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/drawable/vector_icon_wishlist.xml
rename to graphics/drawable/static/src/androidTest/res/drawable/vector_icon_wishlist.xml
diff --git a/graphics/drawable/static/tests/res/values/colors.xml b/graphics/drawable/static/src/androidTest/res/values/colors.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/values/colors.xml
rename to graphics/drawable/static/src/androidTest/res/values/colors.xml
diff --git a/graphics/drawable/static/tests/res/values/strings.xml b/graphics/drawable/static/src/androidTest/res/values/strings.xml
similarity index 100%
rename from graphics/drawable/static/tests/res/values/strings.xml
rename to graphics/drawable/static/src/androidTest/res/values/strings.xml
diff --git a/graphics/drawable/static/AndroidManifest.xml b/graphics/drawable/static/src/main/AndroidManifest.xml
similarity index 100%
rename from graphics/drawable/static/AndroidManifest.xml
rename to graphics/drawable/static/src/main/AndroidManifest.xml
diff --git a/graphics/drawable/static/src/main/java/android/support/graphics/drawable/AndroidResources.java b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/AndroidResources.java
index 31370a2..804c623 100644
--- a/graphics/drawable/static/src/main/java/android/support/graphics/drawable/AndroidResources.java
+++ b/graphics/drawable/static/src/main/java/android/support/graphics/drawable/AndroidResources.java
@@ -89,8 +89,7 @@
 
     public static final int[] STYLEABLE_ANIMATOR = {
             0x01010141, 0x01010198, 0x010101be, 0x010101bf,
-            0x010101c0, 0x010102de, 0x010102df, 0x010102e0,
-            0x0111009c
+            0x010101c0, 0x010102de, 0x010102df, 0x010102e0
     };
 
     public static final int STYLEABLE_ANIMATOR_INTERPOLATOR = 0;
@@ -101,7 +100,6 @@
     public static final int STYLEABLE_ANIMATOR_VALUE_FROM = 5;
     public static final int STYLEABLE_ANIMATOR_VALUE_TO = 6;
     public static final int STYLEABLE_ANIMATOR_VALUE_TYPE = 7;
-    public static final int STYLEABLE_ANIMATOR_REMOVE_BEFORE_M_RELEASE = 8;
     public static final int[] STYLEABLE_ANIMATOR_SET = {
             0x010102e2
     };
diff --git a/graphics/drawable/static/tests/NO_DOCS b/graphics/drawable/static/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/graphics/drawable/static/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/heifwriter/api/current.txt b/heifwriter/api/current.txt
new file mode 100644
index 0000000..3fbb5b8
--- /dev/null
+++ b/heifwriter/api/current.txt
@@ -0,0 +1,19 @@
+package androidx.media.heifwriter {
+
+  public final class HeifWriter implements java.lang.AutoCloseable {
+    ctor public HeifWriter(java.lang.String, int, int, boolean, int, int, int, int, android.os.Handler) throws java.io.IOException;
+    ctor public HeifWriter(java.io.FileDescriptor, int, int, boolean, int, int, int, int, android.os.Handler) throws java.io.IOException;
+    method public void addBitmap(android.graphics.Bitmap);
+    method public void addYuvBuffer(int, byte[]);
+    method public void close();
+    method public android.view.Surface getInputSurface();
+    method public void setInputEndOfStreamTimestamp(long);
+    method public void start();
+    method public void stop(long) throws java.lang.Exception;
+    field public static final int INPUT_MODE_BITMAP = 2; // 0x2
+    field public static final int INPUT_MODE_BUFFER = 0; // 0x0
+    field public static final int INPUT_MODE_SURFACE = 1; // 0x1
+  }
+
+}
+
diff --git a/heifwriter/build.gradle b/heifwriter/build.gradle
new file mode 100644
index 0000000..b66d8a8
--- /dev/null
+++ b/heifwriter/build.gradle
@@ -0,0 +1,29 @@
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+android {
+    defaultConfig {
+        targetSdkVersion = 'P'
+    }
+}
+
+dependencies {
+    api(project(":support-annotations"))
+
+    androidTestImplementation(TEST_RUNNER)
+}
+
+supportLibrary {
+    name = "Android Support HeifWriter"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    minSdkVersion = 'P'
+    description = "Android Support HeifWriter for writing HEIF still images"
+}
diff --git a/heifwriter/src/androidTest/AndroidManifest.xml b/heifwriter/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..755ac70
--- /dev/null
+++ b/heifwriter/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Copyright (C) 2018 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.media.heifwriter.test">
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+</manifest>
diff --git a/heifwriter/src/androidTest/NO_DOCS b/heifwriter/src/androidTest/NO_DOCS
new file mode 100644
index 0000000..ece084d
--- /dev/null
+++ b/heifwriter/src/androidTest/NO_DOCS
@@ -0,0 +1,17 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Having this file, named NO_DOCS, in a directory will prevent
+Android javadocs from being generated for java files under
+the directory. This is especially useful for test projects.
diff --git a/heifwriter/src/androidTest/java/androidx/media/heifwriter/HeifWriterTest.java b/heifwriter/src/androidTest/java/androidx/media/heifwriter/HeifWriterTest.java
new file mode 100644
index 0000000..8673c5c
--- /dev/null
+++ b/heifwriter/src/androidTest/java/androidx/media/heifwriter/HeifWriterTest.java
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.heifwriter;
+
+import static android.support.test.InstrumentationRegistry.getContext;
+
+import static androidx.media.heifwriter.HeifWriter.INPUT_MODE_BITMAP;
+import static androidx.media.heifwriter.HeifWriter.INPUT_MODE_BUFFER;
+import static androidx.media.heifwriter.HeifWriter.INPUT_MODE_SURFACE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import android.graphics.Bitmap;
+import android.graphics.ImageFormat;
+import android.media.MediaExtractor;
+import android.media.MediaFormat;
+import android.media.MediaMetadataRetriever;
+import android.opengl.GLES20;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import androidx.media.heifwriter.test.R;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+
+/**
+ * Test {@link HeifWriter}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class HeifWriterTest {
+    private static final String TAG = HeifWriterTest.class.getSimpleName();
+    private static final boolean DEBUG = false;
+    private static final boolean DUMP_YUV_INPUT = false;
+
+    private static byte[][] TEST_COLORS = {
+            {(byte) 255, (byte) 0, (byte) 0},
+            {(byte) 255, (byte) 0, (byte) 255},
+            {(byte) 255, (byte) 255, (byte) 255},
+            {(byte) 255, (byte) 255, (byte) 0},
+    };
+
+    private static final String TEST_HEIC = "test.heic";
+    private static final int[] IMAGE_RESOURCES = new int[] {
+            R.raw.test
+    };
+    private static final String[] IMAGE_FILENAMES = new String[] {
+            TEST_HEIC
+    };
+    private static final String OUTPUT_FILENAME = "output.heic";
+
+    private EglWindowSurface mInputEglSurface;
+    private Handler mHandler;
+    private int mInputIndex;
+
+    @Before
+    public void setUp() throws Exception {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String outputPath = new File(Environment.getExternalStorageDirectory(),
+                    IMAGE_FILENAMES[i]).getAbsolutePath();
+
+            InputStream inputStream = null;
+            FileOutputStream outputStream = null;
+            try {
+                inputStream = getContext().getResources().openRawResource(IMAGE_RESOURCES[i]);
+                outputStream = new FileOutputStream(outputPath);
+                copy(inputStream, outputStream);
+            } finally {
+                closeQuietly(inputStream);
+                closeQuietly(outputStream);
+            }
+        }
+
+        HandlerThread handlerThread = new HandlerThread(
+                "HeifEncoderThread", Process.THREAD_PRIORITY_FOREGROUND);
+        handlerThread.start();
+        mHandler = new Handler(handlerThread.getLooper());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String imageFilePath =
+                    new File(Environment.getExternalStorageDirectory(), IMAGE_FILENAMES[i])
+                            .getAbsolutePath();
+            File imageFile = new File(imageFilePath);
+            if (imageFile.exists()) {
+                imageFile.delete();
+            }
+        }
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBuffer_NoGrid_NoHandler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_BUFFER, false, false));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBuffer_Grid_NoHandler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_BUFFER, true, false));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBuffer_NoGrid_Handler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_BUFFER, false, true));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBuffer_Grid_Handler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_BUFFER, true, true));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputSurface_NoGrid_NoHandler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_SURFACE, false, false));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputSurface_Grid_NoHandler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_SURFACE, true, false));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputSurface_NoGrid_Handler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_SURFACE, false, true));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputSurface_Grid_Handler() throws Throwable {
+        doTest(new TestConfig(INPUT_MODE_SURFACE, true, true));
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBitmap_NoGrid_NoHandler() throws Throwable {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String inputPath = new File(Environment.getExternalStorageDirectory(),
+                    IMAGE_FILENAMES[i]).getAbsolutePath();
+            doTest(new TestConfig(
+                    INPUT_MODE_BITMAP, false, false, inputPath));
+        }
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBitmap_Grid_NoHandler() throws Throwable {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String inputPath = new File(Environment.getExternalStorageDirectory(),
+                    IMAGE_FILENAMES[i]).getAbsolutePath();
+            doTest(new TestConfig(
+                    INPUT_MODE_BITMAP, true, false, inputPath));
+        }
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBitmap_NoGrid_Handler() throws Throwable {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String inputPath = new File(Environment.getExternalStorageDirectory(),
+                    IMAGE_FILENAMES[i]).getAbsolutePath();
+            doTest(new TestConfig(
+                    INPUT_MODE_BITMAP, false, true, inputPath));
+        }
+    }
+
+    @Test
+    @LargeTest
+    public void testInputBitmap_Grid_Handler() throws Throwable {
+        for (int i = 0; i < IMAGE_RESOURCES.length; ++i) {
+            String inputPath = new File(Environment.getExternalStorageDirectory(),
+                    IMAGE_FILENAMES[i]).getAbsolutePath();
+            doTest(new TestConfig(
+                    INPUT_MODE_BITMAP, true, true, inputPath));
+        }
+    }
+
+    private void closeQuietly(Closeable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) {
+            }
+        }
+    }
+
+    private int copy(InputStream in, OutputStream out) throws IOException {
+        int total = 0;
+        byte[] buffer = new byte[8192];
+        int c;
+        while ((c = in.read(buffer)) != -1) {
+            total += c;
+            out.write(buffer, 0, c);
+        }
+        return total;
+    }
+
+    private static class TestConfig {
+        int inputMode;
+        boolean useGrid;
+        boolean useHandler;
+        int numImages;
+        int width;
+        int height;
+        int quality;
+        String inputPath;
+        String outputPath;
+        Bitmap[] bitmaps;
+
+        TestConfig(int _inputMode, boolean _useGrids, boolean _useHandler) {
+            this(_inputMode, _useGrids, _useHandler, null);
+        }
+
+        TestConfig(int _inputMode, boolean _useGrids, boolean _useHandler, String _inputPath) {
+            inputMode = _inputMode;
+            useGrid = _useGrids;
+            useHandler = _useHandler;
+            numImages = 4;
+            width = 1920;
+            height = 1080;
+            quality = 100;
+            inputPath = (inputMode == INPUT_MODE_BITMAP) ? _inputPath : null;
+            outputPath = new File(Environment.getExternalStorageDirectory(),
+                    OUTPUT_FILENAME).getAbsolutePath();;
+
+            cleanupStaleOutputs();
+            loadBitmapInputs();
+        }
+
+        private void loadBitmapInputs() {
+            if (inputMode != INPUT_MODE_BITMAP) {
+                return;
+            }
+            MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+            retriever.setDataSource(inputPath);
+            String hasImage = retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
+            if (!"yes".equals(hasImage)) {
+                throw new IllegalArgumentException("no bitmap found!");
+            }
+            width = Integer.parseInt(retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH));
+            height = Integer.parseInt(retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT));
+            numImages = Math.min(numImages, Integer.parseInt(retriever.extractMetadata(
+                    MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT)));
+            bitmaps = new Bitmap[numImages];
+            for (int i = 0; i < bitmaps.length; i++) {
+                bitmaps[i] = retriever.getImageAtIndex(i);
+            }
+            retriever.release();
+        }
+
+        private void cleanupStaleOutputs() {
+            File outputFile = new File(outputPath);
+            if (outputFile.exists()) {
+                outputFile.delete();
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "TestConfig" +
+                    ": inputMode " + inputMode +
+                    ", useGrid " + useGrid +
+                    ", useHandler " + useHandler +
+                    ", numImages " + numImages +
+                    ", width " + width +
+                    ", height " + height +
+                    ", quality " + quality +
+                    ", inputPath " + inputPath +
+                    ", outputPath " + outputPath;
+        }
+    }
+
+    private void doTest(TestConfig testConfig) {
+        int width = testConfig.width;
+        int height = testConfig.height;
+        int numImages = testConfig.numImages;
+
+        mInputIndex = 0;
+        HeifWriter heifWriter = null;
+        FileInputStream inputStream = null;
+        FileOutputStream outputStream = null;
+        try {
+            if (DEBUG) Log.d(TAG, "started: " + testConfig);
+
+            heifWriter = new HeifWriter(testConfig.outputPath,
+                    width, height, testConfig.useGrid, testConfig.quality,
+                    numImages, numImages - 1
+                    , testConfig.inputMode,
+                    testConfig.useHandler ? mHandler : null);
+
+            if (testConfig.inputMode == INPUT_MODE_SURFACE) {
+                mInputEglSurface = new EglWindowSurface(heifWriter.getInputSurface());
+            }
+
+            heifWriter.start();
+
+            if (testConfig.inputMode == INPUT_MODE_BUFFER) {
+                byte[] data = new byte[width * height * 3 / 2];
+
+                if (testConfig.inputPath != null) {
+                    inputStream = new FileInputStream(testConfig.inputPath);
+                }
+
+                if (DUMP_YUV_INPUT) {
+                    File outputFile = new File("/sdcard/input.yuv");
+                    outputFile.createNewFile();
+                    outputStream = new FileOutputStream(outputFile);
+                }
+
+                for (int i = 0; i < numImages; i++) {
+                    if (DEBUG) Log.d(TAG, "fillYuvBuffer: " + i);
+                    fillYuvBuffer(i, data, width, height, inputStream);
+                    if (DUMP_YUV_INPUT) {
+                        Log.d(TAG, "@@@ dumping input YUV");
+                        outputStream.write(data);
+                    }
+                    heifWriter.addYuvBuffer(ImageFormat.YUV_420_888, data);
+                }
+            } else if (testConfig.inputMode == INPUT_MODE_SURFACE) {
+                // The input surface is a surface texture using single buffer mode, draws will be
+                // blocked until onFrameAvailable is done with the buffer, which is dependant on
+                // how fast MediaCodec processes them, which is further dependent on how fast the
+                // MediaCodec callbacks are handled. We can't put draws on the same looper that
+                // handles MediaCodec callback, it will cause deadlock.
+                for (int i = 0; i < numImages; i++) {
+                    if (DEBUG) Log.d(TAG, "drawFrame: " + i);
+                    drawFrame(width, height);
+                }
+                heifWriter.setInputEndOfStreamTimestamp(
+                        1000 * computePresentationTime(numImages - 1));
+            } else if (testConfig.inputMode == INPUT_MODE_BITMAP) {
+                Bitmap[] bitmaps = testConfig.bitmaps;
+                for (int i = 0; i < Math.min(bitmaps.length, numImages); i++) {
+                    if (DEBUG) Log.d(TAG, "addBitmap: " + i);
+                    heifWriter.addBitmap(bitmaps[i]);
+                    bitmaps[i].recycle();
+                }
+            }
+
+            heifWriter.stop(3000);
+            verifyResult(testConfig.outputPath, width, height, testConfig.useGrid, numImages);
+            if (DEBUG) Log.d(TAG, "finished: PASS");
+        } catch (Exception e) {
+            fail("finished: FAIL " + e.toString());
+        } finally {
+            try {
+                if (outputStream != null) {
+                    outputStream.close();
+                }
+                if (inputStream != null) {
+                    inputStream.close();
+                }
+            } catch (IOException e) {}
+
+            if (heifWriter != null) {
+                heifWriter.close();
+                heifWriter = null;
+            }
+            if (mInputEglSurface != null) {
+                // This also releases the surface from encoder.
+                mInputEglSurface.release();
+                mInputEglSurface = null;
+            }
+        }
+    }
+
+    private long computePresentationTime(int frameIndex) {
+        return 132 + (long)frameIndex * 1000000;
+    }
+
+    private void fillYuvBuffer(int frameIndex, @NonNull byte[] data, int width, int height,
+                               @Nullable FileInputStream inputStream) throws IOException {
+        if (inputStream != null) {
+            inputStream.read(data);
+        } else {
+            byte[] color = TEST_COLORS[frameIndex % TEST_COLORS.length];
+            int sizeY = width * height;
+            Arrays.fill(data, 0, sizeY, color[0]);
+            Arrays.fill(data, sizeY, sizeY * 5 / 4, color[1]);
+            Arrays.fill(data, sizeY * 5 / 4, sizeY * 3 / 2, color[2]);
+        }
+    }
+
+    private void drawFrame(int width, int height) {
+        mInputEglSurface.makeCurrent();
+        generateSurfaceFrame(mInputIndex, width, height);
+        mInputEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex));
+        mInputEglSurface.swapBuffers();
+        mInputIndex++;
+    }
+
+    private void generateSurfaceFrame(int frameIndex, int width, int height) {
+        frameIndex %= 4;
+
+        GLES20.glViewport(0, 0, width, height);
+        GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+        GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+
+        int startX, startY;
+        int borderWidth = 16;
+        for (int i = 0; i < 7; i++) {
+            startX = (width - borderWidth * 2) * i / 7 + borderWidth;
+            GLES20.glScissor(startX, borderWidth,
+                    (width - borderWidth * 2) / 7, height - borderWidth * 2);
+            GLES20.glClearColor(((7 - i) & 0x4) * 0.16f,
+                    ((7 - i) & 0x2) * 0.32f,
+                    ((7 - i) & 0x1) * 0.64f,
+                    1.0f);
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        }
+
+        startX = (width / 6) + (width / 6) * frameIndex;
+        startY = height / 4;
+        GLES20.glScissor(startX, startY, width / 6, height / 3);
+        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        GLES20.glScissor(startX + borderWidth, startY + borderWidth,
+                width / 6 - borderWidth * 2, height / 3 - borderWidth * 2);
+        GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+    }
+
+    private void verifyResult(
+            String filename, int width, int height, boolean useGrid, int numImages)
+            throws Exception {
+        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+        retriever.setDataSource(filename);
+        String hasImage = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
+        if (!"yes".equals(hasImage)) {
+            throw new Exception("No images found in file " + filename);
+        }
+        assertEquals("Wrong image count", numImages,
+                Integer.parseInt(retriever.extractMetadata(
+                MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT)));
+        assertEquals("Wrong width", width,
+                Integer.parseInt(retriever.extractMetadata(
+                MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH)));
+        assertEquals("Wrong height", height,
+                Integer.parseInt(retriever.extractMetadata(
+                MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT)));
+        retriever.release();
+
+        if (useGrid) {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(filename);
+            MediaFormat format = extractor.getTrackFormat(0);
+            int gridWidth = format.getInteger(MediaFormat.KEY_GRID_WIDTH);
+            int gridHeight = format.getInteger(MediaFormat.KEY_GRID_HEIGHT);
+            assertEquals("Wrong grid width", 512, gridWidth);
+            assertEquals("Wrong grid height", 512, gridHeight);
+            extractor.release();
+        }
+    }
+}
diff --git a/heifwriter/src/androidTest/res/raw/test.heic b/heifwriter/src/androidTest/res/raw/test.heic
new file mode 100644
index 0000000..ceaff92
--- /dev/null
+++ b/heifwriter/src/androidTest/res/raw/test.heic
Binary files differ
diff --git a/heifwriter/src/main/AndroidManifest.xml b/heifwriter/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b4d86af
--- /dev/null
+++ b/heifwriter/src/main/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.media.heifwriter">
+</manifest>
diff --git a/heifwriter/src/main/java/androidx/media/heifwriter/EglRectBlt.java b/heifwriter/src/main/java/androidx/media/heifwriter/EglRectBlt.java
new file mode 100644
index 0000000..f70d01c
--- /dev/null
+++ b/heifwriter/src/main/java/androidx/media/heifwriter/EglRectBlt.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.heifwriter;
+
+import android.graphics.Rect;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+/**
+ * This class represents a viewport-sized sprite that will be rendered with
+ * a subrect from a texture.
+ *
+ * @hide
+ */
+public class EglRectBlt {
+    private static final int SIZEOF_FLOAT = 4;
+
+    /**
+     * A "full" square, extending from -1 to +1 in both dimensions. When the
+     * model/view/projection matrix is identity, this will exactly cover the viewport.
+     */
+    private static final float FULL_RECTANGLE_COORDS[] = {
+            -1.0f, -1.0f,   // 0 bottom left
+             1.0f, -1.0f,   // 1 bottom right
+            -1.0f,  1.0f,   // 2 top left
+             1.0f,  1.0f,   // 3 top right
+    };
+
+    private static final FloatBuffer FULL_RECTANGLE_BUF =
+            createFloatBuffer(FULL_RECTANGLE_COORDS);
+
+    private final float mTexCoords[] = new float[8];
+    private final FloatBuffer mTexCoordArray = createFloatBuffer(mTexCoords);
+    private final int mTexWidth;
+    private final int mTexHeight;
+
+    private Texture2dProgram mProgram;
+
+    /**
+     * Allocates a direct float buffer, and populates it with the float array data.
+     */
+    public static FloatBuffer createFloatBuffer(float[] coords) {
+        // Allocate a direct ByteBuffer, using 4 bytes per float, and copy coords into it.
+        ByteBuffer bb = ByteBuffer.allocateDirect(coords.length * SIZEOF_FLOAT);
+        bb.order(ByteOrder.nativeOrder());
+        FloatBuffer fb = bb.asFloatBuffer();
+        fb.put(coords);
+        fb.position(0);
+        return fb;
+    }
+
+    /**
+     * Prepares the object.
+     *
+     * @param program The program to use. EglRectBlitter takes ownership, and will release
+     *     the program when no longer needed.
+     */
+    public EglRectBlt(Texture2dProgram program, int texWidth, int texHeight) {
+        mProgram = program;
+
+        mTexWidth = texWidth;
+        mTexHeight = texHeight;
+    }
+
+    /**
+     * Releases resources.
+     * <p>
+     * This must be called with the appropriate EGL context current (i.e. the one that was
+     * current when the constructor was called). If we're about to destroy the EGL context,
+     * there's no value in having the caller make it current just to do this cleanup, so you
+     * can pass a flag that will tell this function to skip any EGL-context-specific cleanup.
+     */
+    public void release(boolean doEglCleanup) {
+        if (mProgram != null) {
+            if (doEglCleanup) {
+                mProgram.release();
+            }
+            mProgram = null;
+        }
+    }
+
+    /**
+     * Creates a texture object suitable for use with drawFrame().
+     */
+    public int createTextureObject() {
+        return mProgram.createTextureObject();
+    }
+
+    /**
+     * Draws a viewport-filling rect, texturing it with the specified texture object and rect.
+     */
+    public void copyRect(int textureId, float[] texMatrix, Rect texRect) {
+        setTexRect(texRect);
+
+        // Use the identity matrix for MVP so our 2x2 FULL_RECTANGLE covers the viewport.
+        mProgram.draw(Texture2dProgram.IDENTITY_MATRIX, FULL_RECTANGLE_BUF, 0,
+                4, 2, 2 * SIZEOF_FLOAT,
+                texMatrix, mTexCoordArray, textureId, 2 * SIZEOF_FLOAT);
+    }
+
+    void setTexRect(Rect rect) {
+        mTexCoords[0] = rect.left / (float)mTexWidth;
+        mTexCoords[1] = 1.0f - rect.bottom / (float)mTexHeight;
+        mTexCoords[2] = rect.right / (float)mTexWidth;
+        mTexCoords[3] = 1.0f - rect.bottom / (float)mTexHeight;
+        mTexCoords[4] = rect.left / (float)mTexWidth;
+        mTexCoords[5] = 1.0f - rect.top / (float)mTexHeight;
+        mTexCoords[6] = rect.right / (float)mTexWidth;
+        mTexCoords[7] = 1.0f - rect.top / (float)mTexHeight;
+
+        mTexCoordArray.put(mTexCoords);
+        mTexCoordArray.position(0);
+    }
+}
diff --git a/heifwriter/src/main/java/androidx/media/heifwriter/EglWindowSurface.java b/heifwriter/src/main/java/androidx/media/heifwriter/EglWindowSurface.java
new file mode 100644
index 0000000..a73aac4
--- /dev/null
+++ b/heifwriter/src/main/java/androidx/media/heifwriter/EglWindowSurface.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.heifwriter;
+
+import android.opengl.EGL14;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLExt;
+import android.opengl.EGLSurface;
+import android.util.Log;
+import android.view.Surface;
+
+/**
+ * Holds state associated with a Surface used for MediaCodec encoder input.
+ * <p>
+ * The constructor takes a Surface obtained from MediaCodec.createInputSurface(), and uses that
+ * to create an EGL window surface. Calls to eglSwapBuffers() cause a frame of data to be sent
+ * to the video encoder.
+ *
+ * @hide
+ */
+public class EglWindowSurface {
+    private static final String TAG = "EglWindowSurface";
+
+    private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
+    private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
+    private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;
+    private EGLConfig[] mConfigs = new EGLConfig[1];
+
+    private Surface mSurface;
+    private int mWidth;
+    private int mHeight;
+
+    /**
+     * Creates an EglWindowSurface from a Surface.
+     */
+    public EglWindowSurface(Surface surface) {
+        if (surface == null) {
+            throw new NullPointerException();
+        }
+        mSurface = surface;
+
+        eglSetup();
+    }
+
+    /**
+     * Prepares EGL. We want a GLES 2.0 context and a surface that supports recording.
+     */
+    private void eglSetup() {
+        mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {
+            throw new RuntimeException("unable to get EGL14 display");
+        }
+        int[] version = new int[2];
+        if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {
+            mEGLDisplay = null;
+            throw new RuntimeException("unable to initialize EGL14");
+        }
+
+        // Configure EGL for recordable and OpenGL ES 2.0.  We want enough RGB bits
+        // to minimize artifacts from possible YUV conversion.
+        int[] attribList = {
+                EGL14.EGL_RED_SIZE, 8,
+                EGL14.EGL_GREEN_SIZE, 8,
+                EGL14.EGL_BLUE_SIZE, 8,
+                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+                EGLExt.EGL_RECORDABLE_ANDROID, 1,
+                EGL14.EGL_NONE
+        };
+        int[] numConfigs = new int[1];
+        if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, mConfigs, 0, mConfigs.length,
+                numConfigs, 0)) {
+            throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
+        }
+
+        // Configure context for OpenGL ES 2.0.
+        int[] attrib_list = {
+                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
+                EGL14.EGL_NONE
+        };
+        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mConfigs[0], EGL14.EGL_NO_CONTEXT,
+                attrib_list, 0);
+        checkEglError("eglCreateContext");
+        if (mEGLContext == null) {
+            throw new RuntimeException("null context");
+        }
+
+        // Create a window surface, and attach it to the Surface we received.
+        createEGLSurface();
+
+        mWidth = getWidth();
+        mHeight = getHeight();
+    }
+
+    public void updateSize(int width, int height) {
+        if (width != mWidth || height != mHeight) {
+            Log.d(TAG, "re-create EGLSurface");
+            releaseEGLSurface();
+            createEGLSurface();
+            mWidth = getWidth();
+            mHeight = getHeight();
+        }
+    }
+
+    private void createEGLSurface() {
+        int[] surfaceAttribs = {
+                EGL14.EGL_NONE
+        };
+        mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs[0], mSurface,
+                surfaceAttribs, 0);
+        checkEglError("eglCreateWindowSurface");
+        if (mEGLSurface == null) {
+            throw new RuntimeException("surface was null");
+        }
+    }
+
+    private void releaseEGLSurface() {
+        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+            EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
+            mEGLSurface = EGL14.EGL_NO_SURFACE;
+        }
+    }
+
+    /**
+     * Discard all resources held by this class, notably the EGL context. Also releases the
+     * Surface that was passed to our constructor.
+     */
+    public void release() {
+        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+            EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
+            EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);
+            EGL14.eglReleaseThread();
+            EGL14.eglTerminate(mEGLDisplay);
+        }
+
+        mSurface.release();
+
+        mEGLDisplay = EGL14.EGL_NO_DISPLAY;
+        mEGLContext = EGL14.EGL_NO_CONTEXT;
+        mEGLSurface = EGL14.EGL_NO_SURFACE;
+
+        mSurface = null;
+    }
+
+    /**
+     * Makes our EGL context and surface current.
+     */
+    public void makeCurrent() {
+        if (!EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) {
+            throw new RuntimeException("eglMakeCurrent failed");
+        }
+    }
+
+    /**
+     * Makes our EGL context and surface not current.
+     */
+    public void makeUnCurrent() {
+        if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
+                EGL14.EGL_NO_CONTEXT)) {
+            throw new RuntimeException("eglMakeCurrent failed");
+        }
+    }
+
+    /**
+     * Calls eglSwapBuffers. Use this to "publish" the current frame.
+     */
+    public boolean swapBuffers() {
+        return EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface);
+    }
+
+    /**
+     * Returns the Surface that the MediaCodec receives buffers from.
+     */
+    public Surface getSurface() {
+        return mSurface;
+    }
+
+    /**
+     * Queries the surface's width.
+     */
+    public int getWidth() {
+        int[] value = new int[1];
+        EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_WIDTH, value, 0);
+        return value[0];
+    }
+
+    /**
+     * Queries the surface's height.
+     */
+    public int getHeight() {
+        int[] value = new int[1];
+        EGL14.eglQuerySurface(mEGLDisplay, mEGLSurface, EGL14.EGL_HEIGHT, value, 0);
+        return value[0];
+    }
+
+    /**
+     * Sends the presentation time stamp to EGL. Time is expressed in nanoseconds.
+     */
+    public void setPresentationTime(long nsecs) {
+        EGLExt.eglPresentationTimeANDROID(mEGLDisplay, mEGLSurface, nsecs);
+    }
+
+    /**
+     * Checks for EGL errors.
+     */
+    private void checkEglError(String msg) {
+        int error;
+        if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException(msg + ": EGL error: 0x" + Integer.toHexString(error));
+        }
+    }
+}
diff --git a/heifwriter/src/main/java/androidx/media/heifwriter/HeifEncoder.java b/heifwriter/src/main/java/androidx/media/heifwriter/HeifEncoder.java
new file mode 100644
index 0000000..92fcbf4
--- /dev/null
+++ b/heifwriter/src/main/java/androidx/media/heifwriter/HeifEncoder.java
@@ -0,0 +1,832 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.heifwriter;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLES20;
+import android.opengl.GLUtils;
+import android.os.Looper;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.media.Image;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaFormat;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.util.Log;
+import android.util.Range;
+import android.view.Surface;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * This class encodes images into HEIF-compatible samples using HEVC encoder.
+ *
+ * It currently supports three input modes: {@link #INPUT_MODE_BUFFER},
+ * {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+ *
+ * The output format and samples are sent back in {@link
+ * Callback#onOutputFormatChanged(HeifEncoder, MediaFormat)} and {@link
+ * Callback#onDrainOutputBuffer(HeifEncoder, ByteBuffer)}. If the client
+ * requests to use grid, each tile will be sent back individually.
+ *
+ * HeifEncoder is made a separate class from {@link HeifWriter}, as some more
+ * advanced use cases might want to build solutions on top of the HeifEncoder directly.
+ * (eg. mux still images and video tracks into a single container).
+ *
+ * @hide
+ */
+public final class HeifEncoder implements AutoCloseable,
+        SurfaceTexture.OnFrameAvailableListener {
+    private static final String TAG = "HeifEncoder";
+    private static final boolean DEBUG = false;
+
+    private static final int GRID_WIDTH = 512;
+    private static final int GRID_HEIGHT = 512;
+    private static final double MAX_COMPRESS_RATIO = 0.25f;
+    private static final int INPUT_BUFFER_POOL_SIZE = 2;
+
+    private MediaCodec mEncoder;
+
+    private final Callback mCallback;
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+    private final @InputMode int mInputMode;
+
+    private final int mWidth;
+    private final int mHeight;
+    private final int mGridWidth;
+    private final int mGridHeight;
+    private final int mGridRows;
+    private final int mGridCols;
+    private final int mNumTiles;
+
+    private int mInputIndex;
+    private boolean mInputEOS;
+    private final Rect mSrcRect;
+    private final Rect mDstRect;
+    private ByteBuffer mCurrentBuffer;
+    private final ArrayList<ByteBuffer> mEmptyBuffers = new ArrayList<>();
+    private final ArrayList<ByteBuffer> mFilledBuffers = new ArrayList<>();
+    private final ArrayList<Integer> mCodecInputBuffers = new ArrayList<>();
+
+    // Helper for tracking EOS when surface is used
+    private SurfaceEOSTracker mEOSTracker;
+
+    // Below variables are to handle GL copy from client's surface
+    // to encoder surface when tiles are used.
+    private SurfaceTexture mInputTexture;
+    private Surface mInputSurface;
+    private Surface mEncoderSurface;
+    private EglWindowSurface mEncoderEglSurface;
+    private EglRectBlt mRectBlt;
+    private int mTextureId;
+    private final float[] mTmpMatrix = new float[16];
+
+    public static final int INPUT_MODE_BUFFER = HeifWriter.INPUT_MODE_BUFFER;
+    public static final int INPUT_MODE_SURFACE = HeifWriter.INPUT_MODE_SURFACE;
+    public static final int INPUT_MODE_BITMAP = HeifWriter.INPUT_MODE_BITMAP;
+    @IntDef({
+        INPUT_MODE_BUFFER,
+        INPUT_MODE_SURFACE,
+        INPUT_MODE_BITMAP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InputMode {}
+
+    public static abstract class Callback {
+        /**
+         * Called when the output format has changed.
+         *
+         * @param encoder The HeifEncoder object.
+         * @param format The new output format.
+         */
+        public abstract void onOutputFormatChanged(
+                @NonNull HeifEncoder encoder, @NonNull MediaFormat format);
+
+        /**
+         * Called when an output buffer becomes available.
+         *
+         * @param encoder The HeifEncoder object.
+         * @param byteBuffer the available output buffer.
+         */
+        public abstract void onDrainOutputBuffer(
+                @NonNull HeifEncoder encoder, @NonNull ByteBuffer byteBuffer);
+
+        /**
+         * Called when encoding reached the end of stream without error.
+         *
+         * @param encoder The HeifEncoder object.
+         */
+        public abstract void onComplete(@NonNull HeifEncoder encoder);
+
+        /**
+         * Called when encoding hits an error.
+         *
+         * @param encoder The HeifEncoder object.
+         * @param e The exception that the codec reported.
+         */
+        public abstract void onError(@NonNull HeifEncoder encoder, @NonNull CodecException e);
+    }
+
+    /**
+     * Configure the heif encoding session. Should only be called once.
+     *
+     * @param width Width of the image.
+     * @param height Height of the image.
+     * @param useGrid Whether to encode image into tiles. If enabled, tile size will be
+     *                automatically chosen.
+     * @param quality A number between 0 and 100 (inclusive), with 100 indicating the best quality
+     *                supported by this implementation (which often results in larger file size).
+     * @param inputMode The input type of this encoding session.
+     * @param handler If not null, client will receive all callbacks on the handler's looper.
+     *                Otherwise, client will receive callbacks on a looper created by us.
+     * @param cb The callback to receive various messages from the heif encoder.
+     */
+    public HeifEncoder(int width, int height, boolean useGrid,
+                       int quality, @InputMode int inputMode,
+                       @Nullable Handler handler, @NonNull Callback cb) throws IOException {
+        if (DEBUG) Log.d(TAG, "width: " + width + ", height: " + height +
+                ", useGrid: " + useGrid + ", quality: " + quality + ", inputMode: " + inputMode);
+
+        if (width < 0 || height < 0 || quality < 0 || quality > 100) {
+            throw new IllegalArgumentException("invalid encoder inputs");
+        }
+
+        mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC);
+
+        mWidth = width;
+        mHeight = height;
+
+        if (useGrid) {
+            mGridWidth = GRID_WIDTH;
+            mGridHeight = GRID_HEIGHT;
+            mGridRows = (height + GRID_HEIGHT - 1) / GRID_HEIGHT;
+            mGridCols = (width + GRID_WIDTH - 1) / GRID_WIDTH;
+        } else {
+            mGridWidth = mWidth;
+            mGridHeight = mHeight;
+            mGridRows = 1;
+            mGridCols = 1;
+        }
+
+        mNumTiles = mGridRows * mGridCols;
+
+        mInputMode = inputMode;
+
+        mCallback = cb;
+
+        Looper looper = (handler != null) ? handler.getLooper() : null;
+        if (looper == null) {
+            mHandlerThread = new HandlerThread("HeifEncoderThread",
+                    Process.THREAD_PRIORITY_FOREGROUND);
+            mHandlerThread.start();
+            looper = mHandlerThread.getLooper();
+        } else {
+            mHandlerThread = null;
+        }
+        mHandler = new Handler(looper);
+        boolean useSurfaceInternally =
+                (inputMode == INPUT_MODE_SURFACE) || (inputMode == INPUT_MODE_BITMAP);
+        int colorFormat = useSurfaceInternally ? CodecCapabilities.COLOR_FormatSurface :
+                CodecCapabilities.COLOR_FormatYUV420Flexible;
+
+        // TODO: determine how to set bitrate and framerate, or use constant quality
+        MediaFormat codecFormat = MediaFormat.createVideoFormat(
+                MediaFormat.MIMETYPE_VIDEO_HEVC, mGridWidth, mGridHeight);
+        codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
+        codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
+
+        MediaCodecInfo.CodecCapabilities caps =
+                mEncoder.getCodecInfo().getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_HEVC);
+        MediaCodecInfo.EncoderCapabilities encoderCaps = caps.getEncoderCapabilities();
+
+        codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mNumTiles);
+        codecFormat.setInteger(MediaFormat.KEY_CAPTURE_RATE, mNumTiles * 30);
+        if (encoderCaps.isBitrateModeSupported(
+                MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ)) {
+            Log.d(TAG, "Setting bitrate mode to constant quality");
+            Range<Integer> qualityRange = encoderCaps.getQualityRange();
+            Log.d(TAG, "Quality range: " + qualityRange);
+            codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+                    MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ);
+            codecFormat.setInteger(MediaFormat.KEY_QUALITY, (int) (qualityRange.getLower() +
+                            (qualityRange.getUpper() - qualityRange.getLower()) * quality / 100.0));
+        } else {
+            if (encoderCaps.isBitrateModeSupported(
+                    MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR)) {
+                Log.d(TAG, "Setting bitrate mode to variable bitrate");
+                codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+                        MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
+            } else { // assume CBR
+                Log.d(TAG, "Setting bitrate mode to constant bitrate");
+                codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+                        MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
+            }
+            // Calculate the bitrate based on image dimension, max compression ratio and quality.
+            // Note that we set the frame rate to the number of tiles, so the bitrate would be the
+            // intended bits for one image.
+            int bitrate = (int) (width * height * 1.5 * 8 * MAX_COMPRESS_RATIO * quality / 100.0f);
+            codecFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
+        }
+
+        mEncoder.setCallback(new EncoderCallback(), mHandler);
+        mEncoder.configure(codecFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+        if (useSurfaceInternally) {
+            mEncoderSurface = mEncoder.createInputSurface();
+
+            boolean useGLCopy = (mNumTiles > 1) || (inputMode == INPUT_MODE_BITMAP);
+            mEOSTracker = new SurfaceEOSTracker(useGLCopy);
+
+            if (useGLCopy) {
+                mEncoderEglSurface = new EglWindowSurface(mEncoderSurface);
+                mEncoderEglSurface.makeCurrent();
+
+                mRectBlt = new EglRectBlt(
+                        new Texture2dProgram((inputMode == INPUT_MODE_BITMAP) ?
+                                Texture2dProgram.TEXTURE_2D :
+                                Texture2dProgram.TEXTURE_EXT),
+                        mWidth, mHeight);
+
+                mTextureId = mRectBlt.createTextureObject();
+
+                if (inputMode == INPUT_MODE_SURFACE) {
+                    // use single buffer mode to block on input
+                    mInputTexture = new SurfaceTexture(mTextureId, true);
+                    mInputTexture.setOnFrameAvailableListener(this);
+                    mInputTexture.setDefaultBufferSize(mWidth, mHeight);
+                    mInputSurface = new Surface(mInputTexture);
+                }
+
+                // make uncurrent since the onFrameAvailable could be called on arbituray thread.
+                // making the context current on a different thread will cause error.
+                mEncoderEglSurface.makeUnCurrent();
+            } else {
+                mInputSurface = mEncoderSurface;
+            }
+        } else {
+            for (int i = 0; i < INPUT_BUFFER_POOL_SIZE; i++) {
+                mEmptyBuffers.add(ByteBuffer.allocateDirect(mWidth * mHeight * 3 / 2));
+            }
+        }
+
+        mDstRect = new Rect(0, 0, mGridWidth, mGridHeight);
+        mSrcRect = new Rect();
+    }
+
+    @Override
+    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
+        mEncoderEglSurface.makeCurrent();
+
+        surfaceTexture.updateTexImage();
+        surfaceTexture.getTransformMatrix(mTmpMatrix);
+
+        long timestampNs = surfaceTexture.getTimestamp();
+
+        if (DEBUG) Log.d(TAG, "onFrameAvailable: timestampUs " + (timestampNs / 1000));
+
+        boolean takeFrame = mEOSTracker.updateLastInputAndEncoderTime(timestampNs,
+                computePresentationTime(mInputIndex + mNumTiles - 1));
+
+        if (takeFrame) {
+            copyTilesGL(mTmpMatrix);
+        }
+
+        surfaceTexture.releaseTexImage();
+
+        // make uncurrent since the onFrameAvailable could be called on arbituray thread.
+        // making the context current on a different thread will cause error.
+        mEncoderEglSurface.makeUnCurrent();
+    }
+
+    /**
+     * Start the encoding process.
+     */
+    public void start() {
+        mEncoder.start();
+    }
+
+    /**
+     * Add one YUV buffer to be encoded. This might block if the encoder can't process the input
+     * buffers fast enough.
+     *
+     * After the call returns, the client can reuse the data array.
+     *
+     * @param format The YUV format as defined in {@link android.graphics.ImageFormat}, currently
+     *               only support YUV_420_888.
+     *
+     * @param data byte array containing the YUV data. If the format has more than one planes,
+     *             they must be concatenated.
+     */
+    public void addYuvBuffer(int format, @NonNull byte[] data) {
+        if (mInputMode != INPUT_MODE_BUFFER) {
+            throw new IllegalStateException(
+                    "addYuvBuffer is only allowed in buffer input mode");
+        }
+        if (data == null || data.length != mWidth * mHeight * 3 / 2) {
+            throw new IllegalArgumentException("invalid data");
+        }
+        addYuvBufferInternal(data);
+    }
+
+    /**
+     * Retrieves the input surface for encoding.
+     *
+     * Will only return valid value if configured to use surface input.
+     */
+    public @NonNull Surface getInputSurface() {
+        if (mInputMode != INPUT_MODE_SURFACE) {
+            throw new IllegalStateException(
+                    "getInputSurface is only allowed in surface input mode");
+        }
+        return mInputSurface;
+    }
+
+    /**
+     * Sets the timestamp (in nano seconds) of the last input frame to encode. Frames with
+     * timestamps larger than the specified value will not be encoded. However, if a frame
+     * already started encoding when this is set, all tiles within that frame will be encoded.
+     *
+     * This method only applies when surface is used.
+     */
+    public void setEndOfInputStreamTimestamp(long timestampNs) {
+        if (mInputMode != INPUT_MODE_SURFACE) {
+            throw new IllegalStateException(
+                    "setEndOfInputStreamTimestamp is only allowed in surface input mode");
+        }
+        if (mEOSTracker != null) {
+            mEOSTracker.updateInputEOSTime(timestampNs);
+        }
+    }
+
+    /**
+     * Adds one bitmap to be encoded.
+     */
+    public void addBitmap(@NonNull Bitmap bitmap) {
+        if (mInputMode != INPUT_MODE_BITMAP) {
+            throw new IllegalStateException("addBitmap is only allowed in bitmap input mode");
+        }
+
+        boolean takeFrame = mEOSTracker.updateLastInputAndEncoderTime(
+                computePresentationTime(mInputIndex),
+                computePresentationTime(mInputIndex + mNumTiles - 1));
+
+        if (takeFrame) {
+            mEncoderEglSurface.makeCurrent();
+
+            // load the bitmap to texture
+            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
+            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
+
+            copyTilesGL(Texture2dProgram.V_FLIP_MATRIX);
+
+            // make uncurrent since the onFrameAvailable could be called on arbituray thread.
+            // making the context current on a different thread will cause error.
+            mEncoderEglSurface.makeUnCurrent();
+        }
+    }
+
+    /**
+     * Sends input EOS to the encoder. Result will be notified asynchronously via
+     * {@link Callback#onComplete(HeifEncoder)} if encoder reaches EOS without error, or
+     * {@link Callback#onError(HeifEncoder, CodecException)} otherwise.
+     */
+    public void stopAsync() {
+        if (mInputMode == INPUT_MODE_BITMAP) {
+            // here we simply set the EOS timestamp to 0, so that the cut off will be the last
+            // bitmap ever added.
+            mEOSTracker.updateInputEOSTime(0);
+        } else if (mInputMode == INPUT_MODE_BUFFER) {
+            addYuvBufferInternal(null);
+        }
+    }
+
+    /**
+     * Generates the presentation time for input frame N, in microseconds.
+     * The timestamp advances 1 sec for every whole frame.
+     */
+    private long computePresentationTime(int frameIndex) {
+        return 132 + (long)frameIndex * 1000000 / mNumTiles;
+    }
+
+    /**
+     * Obtains one empty input buffer and copies the data into it. Before input
+     * EOS is sent, this would block until the data is copied. After input EOS
+     * is sent, this would return immediately.
+     */
+    private void addYuvBufferInternal(@Nullable byte[] data) {
+        ByteBuffer buffer = acquireEmptyBuffer();
+        if (buffer == null) {
+            return;
+        }
+        buffer.clear();
+        if (data != null) {
+            buffer.put(data);
+        }
+        buffer.flip();
+        synchronized (mFilledBuffers) {
+            mFilledBuffers.add(buffer);
+        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                maybeCopyOneTileYUV();
+            }
+        });
+    }
+
+    /**
+     * Routine to copy one tile if we have both input and codec buffer available.
+     *
+     * Must be called on the handler looper that also handles the MediaCodec callback.
+     */
+    private void maybeCopyOneTileYUV() {
+        ByteBuffer currentBuffer;
+        while ((currentBuffer = getCurrentBuffer()) != null && !mCodecInputBuffers.isEmpty()) {
+            int index = mCodecInputBuffers.remove(0);
+
+            // 0-length input means EOS.
+            boolean inputEOS = (mInputIndex % mNumTiles == 0) && (currentBuffer.remaining() == 0);
+
+            if (!inputEOS) {
+                Image image = mEncoder.getInputImage(index);
+                int left = mGridWidth * (mInputIndex % mGridCols);
+                int top = mGridHeight * (mInputIndex / mGridCols % mGridRows);
+                mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+                copyOneTileYUV(currentBuffer, image, mWidth, mHeight, mSrcRect, mDstRect);
+            }
+
+            mEncoder.queueInputBuffer(index, 0,
+                    inputEOS ? 0 : mEncoder.getInputBuffer(index).capacity(),
+                    computePresentationTime(mInputIndex++),
+                    inputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+
+            if (inputEOS || mInputIndex % mNumTiles == 0) {
+                returnEmptyBufferAndNotify(inputEOS);
+            }
+        }
+    }
+
+    /**
+     * Copies from a rect from src buffer to dst image.
+     * TOOD: This will be replaced by JNI.
+     */
+    private static void copyOneTileYUV(
+            ByteBuffer srcBuffer, Image dstImage,
+            int srcWidth, int srcHeight,
+            Rect srcRect, Rect dstRect) {
+        if (srcRect.width() != dstRect.width() || srcRect.height() != dstRect.height()) {
+            throw new IllegalArgumentException("src and dst rect size are different!");
+        }
+        if (srcWidth % 2 != 0      || srcHeight % 2 != 0      ||
+                srcRect.left % 2 != 0  || srcRect.top % 2 != 0    ||
+                srcRect.right % 2 != 0 || srcRect.bottom % 2 != 0 ||
+                dstRect.left % 2 != 0  || dstRect.top % 2 != 0    ||
+                dstRect.right % 2 != 0 || dstRect.bottom % 2 != 0) {
+            throw new IllegalArgumentException("src or dst are not aligned!");
+        }
+
+        Image.Plane[] planes = dstImage.getPlanes();
+        for (int n = 0; n < planes.length; n++) {
+            ByteBuffer dstBuffer = planes[n].getBuffer();
+            int colStride = planes[n].getPixelStride();
+            int copyWidth = Math.min(srcRect.width(), srcWidth - srcRect.left);
+            int copyHeight = Math.min(srcRect.height(), srcHeight - srcRect.top);
+            int srcPlanePos = 0, div = 1;
+            if (n > 0) {
+                div = 2;
+                srcPlanePos = srcWidth * srcHeight * (n + 3) / 4;
+            }
+            for (int i = 0; i < copyHeight / div; i++) {
+                srcBuffer.position(srcPlanePos +
+                        (i + srcRect.top / div) * srcWidth / div + srcRect.left / div);
+                dstBuffer.position((i + dstRect.top / div) * planes[n].getRowStride()
+                        + dstRect.left * colStride / div);
+
+                for (int j = 0; j < copyWidth / div; j++) {
+                    dstBuffer.put(srcBuffer.get());
+                    if (colStride > 1 && j != copyWidth / div - 1) {
+                        dstBuffer.position(dstBuffer.position() + colStride - 1);
+                    }
+                }
+            }
+        }
+    }
+
+    private ByteBuffer acquireEmptyBuffer() {
+        synchronized (mEmptyBuffers) {
+            // wait for an empty input buffer first
+            while (!mInputEOS && mEmptyBuffers.isEmpty()) {
+                try {
+                    mEmptyBuffers.wait();
+                } catch (InterruptedException e) {}
+            }
+
+            // if already EOS, return null to stop further encoding.
+            return mInputEOS ? null : mEmptyBuffers.remove(0);
+        }
+    }
+
+    /**
+     * Routine to get the current input buffer to copy from.
+     * Only called on callback handler thread.
+     */
+    private ByteBuffer getCurrentBuffer() {
+        if (!mInputEOS && mCurrentBuffer == null) {
+            synchronized (mFilledBuffers) {
+                mCurrentBuffer = mFilledBuffers.isEmpty() ?
+                        null : mFilledBuffers.remove(0);
+            }
+        }
+        return mInputEOS ? null : mCurrentBuffer;
+    }
+
+    /**
+     * Routine to put the consumed input buffer back into the empty buffer pool.
+     * Only called on callback handler thread.
+     */
+    private void returnEmptyBufferAndNotify(boolean inputEOS) {
+        synchronized (mEmptyBuffers) {
+            mInputEOS |= inputEOS;
+            mEmptyBuffers.add(mCurrentBuffer);
+            mEmptyBuffers.notifyAll();
+        }
+        mCurrentBuffer = null;
+    }
+
+    /**
+     * Copies from source frame to encoder inputs using GL. The source could be either
+     * client's input surface, or the input bitmap loaded to texture.
+     *
+     * @param texMatrix The texture matrix to use. See the shader program in
+     * {@link Texture2dProgram} as well as {@link SurfaceTexture} for more details.
+     */
+    private void copyTilesGL(float[] texMatrix) {
+        GLES20.glViewport(0, 0, mGridWidth, mGridHeight);
+
+        for (int row = 0; row < mGridRows; row++) {
+            for (int col = 0; col < mGridCols; col++) {
+                int left = col * mGridWidth;
+                int top = row * mGridHeight;
+                mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+                mRectBlt.copyRect(mTextureId, texMatrix, mSrcRect);
+                mEncoderEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex++));
+                mEncoderEglSurface.swapBuffers();
+            }
+        }
+    }
+
+    /**
+     * Routine to release all resources. Must be run on the same looper that
+     * handles the MediaCodec callbacks.
+     */
+    private void stopInternal() {
+        if (DEBUG) Log.d(TAG, "stopInternal");
+
+        if (mEncoder != null) {
+            mEncoder.stop();
+            mEncoder.release();
+            mEncoder = null;
+        }
+
+        // unblock the addBuffer() if we're tearing down before EOS is sent.
+        synchronized (mEmptyBuffers) {
+            mInputEOS = true;
+            mEmptyBuffers.notifyAll();
+        }
+
+        if (mRectBlt != null) {
+            mRectBlt.release(false);
+            mRectBlt = null;
+        }
+        if (mEncoderEglSurface != null)  {
+            // Note that this frees mEncoderSurface too. If mEncoderEglSurface is not
+            // there, client is responsible to release the input surface it got from us,
+            // we don't release mEncoderSurface here.
+            mEncoderEglSurface.release();
+            mEncoderEglSurface = null;
+        }
+        if (mInputTexture != null) {
+            mInputTexture.release();
+            mInputTexture = null;
+        }
+    }
+
+    /**
+     * This class handles EOS for surface or bitmap inputs.
+     *
+     * When encoding from surface or bitmap, we can't call {@link MediaCodec#signalEndOfInputStream()}
+     * immediately after input is drawn, since this could drop all pending frames in the
+     * buffer queue. When there are tiles, this could leave us a partially encoded image.
+     *
+     * So here we track the EOS status by timestamps, and only signal EOS to the encoder
+     * when we collected all images we need.
+     *
+     * Since this is updated from multiple threads ({@link #setEndOfInputStreamTimestamp(long)},
+     * {@link EncoderCallback#onOutputBufferAvailable(MediaCodec, int, BufferInfo)},
+     * {@link #addBitmap(Bitmap)} and {@link #onFrameAvailable(SurfaceTexture)}), it must be fully
+     * synchronized.
+     *
+     * Note that when buffer input is used, the EOS flag is set in
+     * {@link EncoderCallback#onInputBufferAvailable(MediaCodec, int)} and this class is not used.
+     */
+    private class SurfaceEOSTracker {
+        private static final boolean DEBUG_EOS = false;
+
+        final boolean mUseGLCopy;
+        long mInputEOSTimeNs = -1;
+        long mLastInputTimeNs = -1;
+        long mEncoderEOSTimeUs = -1;
+        long mLastEncoderTimeUs = -1;
+        long mLastOutputTimeUs = -1;
+        boolean mSignaled;
+
+        SurfaceEOSTracker(boolean useGLCopy) {
+            mUseGLCopy = useGLCopy;
+        }
+
+        synchronized void updateInputEOSTime(long timestampNs) {
+            if (DEBUG_EOS) Log.d(TAG, "updateInputEOSTime: " + timestampNs);
+
+            if (mUseGLCopy) {
+                if (mInputEOSTimeNs < 0) {
+                    mInputEOSTimeNs = timestampNs;
+                }
+            } else {
+                if (mEncoderEOSTimeUs < 0) {
+                    mEncoderEOSTimeUs = timestampNs / 1000;
+                }
+            }
+            updateEOSLocked();
+        }
+
+        synchronized boolean updateLastInputAndEncoderTime(long inputTimeNs, long encoderTimeUs) {
+            if (DEBUG_EOS) Log.d(TAG,
+                    "updateLastInputAndEncoderTime: " + inputTimeNs + ", " + encoderTimeUs);
+
+            boolean shouldTakeFrame = mInputEOSTimeNs < 0 || inputTimeNs <= mInputEOSTimeNs;
+            if (shouldTakeFrame) {
+                mLastEncoderTimeUs = encoderTimeUs;
+            }
+            mLastInputTimeNs = inputTimeNs;
+            updateEOSLocked();
+            return shouldTakeFrame;
+        }
+
+        synchronized void updateLastOutputTime(long outputTimeUs) {
+            if (DEBUG_EOS) Log.d(TAG, "updateLastOutputTime: " + outputTimeUs);
+
+            mLastOutputTimeUs = outputTimeUs;
+            updateEOSLocked();
+        }
+
+        private void updateEOSLocked() {
+            if (mSignaled) {
+                return;
+            }
+            if (mEncoderEOSTimeUs < 0) {
+                if (mInputEOSTimeNs >= 0 && mLastInputTimeNs >= mInputEOSTimeNs) {
+                    if (mLastEncoderTimeUs < 0) {
+                        doSignalEOSLocked();
+                        return;
+                    }
+                    // mEncoderEOSTimeUs tracks the timestamp of the last output buffer we
+                    // will wait for. When that buffer arrives, encoder will be signalled EOS.
+                    mEncoderEOSTimeUs = mLastEncoderTimeUs;
+                    if (DEBUG_EOS) Log.d(TAG,
+                            "updateEOSLocked: mEncoderEOSTimeUs " + mEncoderEOSTimeUs);
+                }
+            }
+            if (mEncoderEOSTimeUs >= 0 && mEncoderEOSTimeUs <= mLastOutputTimeUs) {
+                doSignalEOSLocked();
+            }
+        }
+
+        private void doSignalEOSLocked() {
+            if (DEBUG_EOS) Log.d(TAG, "doSignalEOSLocked");
+
+            mEncoder.signalEndOfInputStream();
+            mSignaled = true;
+        }
+    }
+
+    /**
+     * MediaCodec callback for HEVC encoding.
+     */
+    private class EncoderCallback extends MediaCodec.Callback {
+        private boolean mOutputEOS;
+
+        @Override
+        public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+            if (codec != mEncoder) return;
+
+            if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
+
+            format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
+            format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
+            format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
+
+            if (mNumTiles > 1) {
+                format.setInteger(MediaFormat.KEY_GRID_WIDTH, mGridWidth);
+                format.setInteger(MediaFormat.KEY_GRID_HEIGHT, mGridHeight);
+                format.setInteger(MediaFormat.KEY_GRID_ROWS, mGridRows);
+                format.setInteger(MediaFormat.KEY_GRID_COLS, mGridCols);
+            }
+
+            mCallback.onOutputFormatChanged(HeifEncoder.this, format);
+        }
+
+        @Override
+        public void onInputBufferAvailable(MediaCodec codec, int index) {
+            if (codec != mEncoder || mInputEOS) return;
+
+            if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index);
+            mCodecInputBuffers.add(index);
+            maybeCopyOneTileYUV();
+        }
+
+        @Override
+        public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
+            if (codec != mEncoder || mOutputEOS) return;
+
+            if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index + ", time "
+                    + info.presentationTimeUs + ", size " + info.size + ", flags " + info.flags);
+
+            if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
+                ByteBuffer outputBuffer = codec.getOutputBuffer(index);
+
+                // reset position as addBuffer() modifies it
+                outputBuffer.position(info.offset);
+                outputBuffer.limit(info.offset + info.size);
+
+                if (mEOSTracker != null) {
+                    mEOSTracker.updateLastOutputTime(info.presentationTimeUs);
+                }
+
+                mCallback.onDrainOutputBuffer(HeifEncoder.this, outputBuffer);
+            }
+
+            mOutputEOS |= ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0);
+
+            codec.releaseOutputBuffer(index, false);
+
+            if (mOutputEOS) {
+                stopAndNotify(null);
+            }
+        }
+
+        @Override
+        public void onError(MediaCodec codec, CodecException e) {
+            if (codec != mEncoder) return;
+
+            Log.e(TAG, "onError: " + e);
+            stopAndNotify(e);
+        }
+
+        private void stopAndNotify(@Nullable CodecException e) {
+            stopInternal();
+            if (e == null) {
+                mCallback.onComplete(HeifEncoder.this);
+            } else {
+                mCallback.onError(HeifEncoder.this, e);
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+        mHandler.postAtFrontOfQueue(new Runnable() {
+            @Override
+            public void run() {
+                stopInternal();
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/heifwriter/src/main/java/androidx/media/heifwriter/HeifWriter.java b/heifwriter/src/main/java/androidx/media/heifwriter/HeifWriter.java
new file mode 100644
index 0000000..b9c1959
--- /dev/null
+++ b/heifwriter/src/main/java/androidx/media/heifwriter/HeifWriter.java
@@ -0,0 +1,521 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.heifwriter;
+
+import android.annotation.SuppressLint;
+import android.graphics.Bitmap;
+import android.media.MediaCodec;
+import android.media.MediaFormat;
+import android.media.MediaMuxer;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.view.Surface;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.concurrent.TimeoutException;
+
+import static android.media.MediaMuxer.OutputFormat.MUXER_OUTPUT_HEIF;
+
+/**
+ * This class writes one or more still images (of the same dimensions) into
+ * a heif file.
+ *
+ * It currently supports three input modes: {@link #INPUT_MODE_BUFFER},
+ * {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+ *
+ * The general sequence (in pseudo-code) to write a heif file using this class is as follows:
+ *
+ * 1) Construct the writer:
+ * HeifWriter heifwriter = new HeifWriter(...);
+ *
+ * 2) If using surface input mode, obtain the input surface:
+ * Surface surface = heifwriter.getInputSurface();
+ *
+ * 3) Call start:
+ * heifwriter.start();
+ *
+ * 4) Depending on the chosen input mode, add one or more images using one of these methods:
+ * heifwriter.addYuvBuffer(...);   Or
+ * heifwriter.addBitmap(...);   Or
+ * render to the previously obtained surface
+ *
+ * 5) Call stop:
+ * heifwriter.stop(...);
+ *
+ * 6) Close the writer:
+ * heifwriter.close();
+ *
+ * Please refer to the documentations on individual methods for the exact usage.
+ */
+public final class HeifWriter implements AutoCloseable {
+    private static final String TAG = "HeifWriter";
+    private static final boolean DEBUG = false;
+
+    private final @InputMode int mInputMode;
+    private final HandlerThread mHandlerThread;
+    private final Handler mHandler;
+    private int mNumTiles;
+    private final int mNumImages;
+    private final int mPrimaryIndex;
+    private final ResultWaiter mResultWaiter = new ResultWaiter();
+
+    private MediaMuxer mMuxer;
+    private HeifEncoder mHeifEncoder;
+    private int[] mTrackIndexArray;
+    private int mOutputIndex;
+    private boolean mStarted;
+
+    /**
+     * The input mode where the client adds input buffers with YUV data.
+     *
+     * @see #addYuvBuffer(int, byte[])
+     */
+    public static final int INPUT_MODE_BUFFER = 0;
+
+    /**
+     * The input mode where the client renders the images to an input Surface
+     * created by the writer.
+     *
+     * @see #getInputSurface()
+     */
+    public static final int INPUT_MODE_SURFACE = 1;
+
+    /**
+     * The input mode where the client adds bitmaps.
+     *
+     * @see #addBitmap(Bitmap)
+     */
+    public static final int INPUT_MODE_BITMAP = 2;
+
+    /** @hide */
+    @IntDef({
+            INPUT_MODE_BUFFER, INPUT_MODE_SURFACE, INPUT_MODE_BITMAP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InputMode {}
+
+    /**
+     * Construct a heif writer that writes to a file specified by its path.
+     *
+     * @param path Path of the file to be written.
+     * @param width Width of the image.
+     * @param height Height of the image.
+     * @param useGrid Whether to encode image into tiles. If enabled, the tile size will be
+     *                automatically chosen.
+     * @param quality A number between 0 and 100 (inclusive), with 100 indicating the best quality
+     *                supported by this implementation (which often results in larger file size).
+     * @param numImages Max number of images to write. Frames exceeding this number will not be
+     *                  written to file. The writing can be stopped earlier before this number of
+     *                  images are written by {@link #stop(long)}, except for the input mode of
+     *                  {@link #INPUT_MODE_SURFACE}, where the EOS timestamp must be specified (via
+     *                 {@link #setInputEndOfStreamTimestamp(long)} and reached.
+     * @param primaryIndex Index of the image that should be marked as primary, must be within range
+     *                     [0, numImages - 1] inclusive.
+     * @param inputMode Input mode for this writer, must be one of {@link #INPUT_MODE_BUFFER},
+     *                  {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+     * @param handler If not null, client will receive all callbacks on the handler's looper.
+     *                Otherwise, client will receive callbacks on a looper created by the writer.
+     *
+     * @throws IOException if failed to construct MediaMuxer or HeifEncoder.
+     */
+    @SuppressLint("WrongConstant")
+    public HeifWriter(@NonNull String path,
+                      int width, int height, boolean useGrid,
+                      int quality, int numImages, int primaryIndex,
+                      @InputMode int inputMode,
+                      @Nullable Handler handler) throws IOException {
+        this(width, height, useGrid, quality, numImages, primaryIndex, inputMode, handler,
+                new MediaMuxer(path, MUXER_OUTPUT_HEIF));
+    }
+
+    /**
+     * Construct a heif writer that writes to a file specified by file descriptor.
+     *
+     * @param fd File descriptor of the file to be written.
+     * @param width Width of the image.
+     * @param height Height of the image.
+     * @param useGrid Whether to encode image into tiles. If enabled, the tile size will be
+     *                automatically chosen.
+     * @param quality A number between 0 and 100 (inclusive), with 100 indicating the best quality
+     *                supported by this implementation (which often results in larger file size).
+     * @param numImages Max number of images to write. Frames exceeding this number will not be
+     *                  written to file. The writing can be stopped earlier before this number of
+     *                  images are written by {@link #stop(long)}, except for the input mode of
+     *                  {@link #INPUT_MODE_SURFACE}, where the EOS timestamp must be specified (via
+     *                 {@link #setInputEndOfStreamTimestamp(long)} and reached.
+     * @param primaryIndex Index of the image that should be marked as primary, must be within range
+     *                     [0, numImages - 1] inclusive.
+     * @param inputMode Input mode for this writer, must be one of {@link #INPUT_MODE_BUFFER},
+     *                  {@link #INPUT_MODE_SURFACE}, or {@link #INPUT_MODE_BITMAP}.
+     * @param handler If not null, client will receive all callbacks on the handler's looper.
+     *                Otherwise, client will receive callbacks on a looper created by the writer.
+     *
+     * @throws IOException if failed to construct MediaMuxer or HeifEncoder.
+     */
+    @SuppressLint("WrongConstant")
+    public HeifWriter(@NonNull FileDescriptor fd,
+                      int width, int height, boolean useGrid,
+                      int quality, int numImages, int primaryIndex,
+                      @InputMode int inputMode,
+                      @Nullable Handler handler) throws IOException {
+        this(width, height, useGrid, quality, numImages, primaryIndex, inputMode, handler,
+                new MediaMuxer(fd, MUXER_OUTPUT_HEIF));
+    }
+
+    private HeifWriter(int width, int height, boolean useGrid,
+                       int quality, int numImages, int primaryIndex,
+                       @InputMode int inputMode,
+                       @Nullable Handler handler,
+                       @NonNull MediaMuxer muxer) throws IOException {
+        if (numImages <= 0 || primaryIndex < 0 || primaryIndex >= numImages) {
+            throw new IllegalArgumentException(
+                    "Invalid numImages (" + numImages + ") or primaryIndex (" + primaryIndex + ")");
+        }
+
+        MediaFormat format = MediaFormat.createVideoFormat(
+                MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC, width, height);
+
+        if (DEBUG) {
+            Log.d(TAG, "format: " + format + ", inputMode: " + inputMode +
+                    ", numImage: " + numImages + ", primaryIndex: " + primaryIndex);
+        }
+
+        // set to 1 initially, and wait for output format to know for sure
+        mNumTiles = 1;
+
+        mInputMode = inputMode;
+        mNumImages = numImages;
+        mPrimaryIndex = primaryIndex;
+
+        Looper looper = (handler != null) ? handler.getLooper() : null;
+        if (looper == null) {
+            mHandlerThread = new HandlerThread("HeifEncoderThread",
+                    Process.THREAD_PRIORITY_FOREGROUND);
+            mHandlerThread.start();
+            looper = mHandlerThread.getLooper();
+        } else {
+            mHandlerThread = null;
+        }
+        mHandler = new Handler(looper);
+
+        mMuxer = muxer;
+
+        mHeifEncoder = new HeifEncoder(width, height, useGrid, quality,
+                mInputMode, mHandler, new HeifCallback());
+    }
+
+    /**
+     * Start the heif writer. Can only be called once.
+     *
+     * @throws IllegalStateException if called more than once.
+     */
+    public void start() {
+        checkStarted(false);
+        mStarted = true;
+        mHeifEncoder.start();
+    }
+
+    /**
+     * Add one YUV buffer to the heif file.
+     *
+     * @param format The YUV format as defined in {@link android.graphics.ImageFormat}, currently
+     *               only support YUV_420_888.
+     *
+     * @param data byte array containing the YUV data. If the format has more than one planes,
+     *             they must be concatenated.
+     *
+     * @throws IllegalStateException if not started or not configured to use buffer input.
+     */
+    public void addYuvBuffer(int format, @NonNull byte[] data) {
+        checkStartedAndMode(INPUT_MODE_BUFFER);
+        mHeifEncoder.addYuvBuffer(format, data);
+    }
+
+    /**
+     * Retrieves the input surface for encoding.
+     *
+     * @return the input surface if configured to use surface input.
+     *
+     * @throws IllegalStateException if called after start or not configured to use surface input.
+     */
+    public @NonNull Surface getInputSurface() {
+        checkStarted(false);
+        checkMode(INPUT_MODE_SURFACE);
+        return mHeifEncoder.getInputSurface();
+    }
+
+    /**
+     * Set the timestamp (in nano seconds) of the last input frame to encode.
+     *
+     * This call is only valid for surface input. Client can use this to stop the heif writer
+     * earlier before the maximum number of images are written. If not called, the writer will
+     * only stop when the maximum number of images are written.
+     *
+     * @param timestampNs timestamp (in nano seconds) of the last frame that will be written to the
+     *                    heif file. Frames with timestamps larger than the specified value will not
+     *                    be written. However, if a frame already started encoding when this is set,
+     *                    all tiles within that frame will be encoded.
+     *
+     * @throws IllegalStateException if not started or not configured to use surface input.
+     */
+    public void setInputEndOfStreamTimestamp(long timestampNs) {
+        checkStartedAndMode(INPUT_MODE_SURFACE);
+        mHeifEncoder.setEndOfInputStreamTimestamp(timestampNs);
+    }
+
+    /**
+     * Add one bitmap to the heif file.
+     *
+     * @param bitmap the bitmap to be added to the file.
+     * @throws IllegalStateException if not started or not configured to use bitmap input.
+     */
+    public void addBitmap(@NonNull Bitmap bitmap) {
+        checkStartedAndMode(INPUT_MODE_BITMAP);
+        mHeifEncoder.addBitmap(bitmap);
+    }
+
+    /**
+     * Stop the heif writer synchronously. Throws exception if the writer didn't finish writing
+     * successfully. Upon a success return:
+     *
+     * - For buffer and bitmap inputs, all images sent before stop will be written.
+     *
+     * - For surface input, images with timestamp on or before that specified in
+     *   {@link #setInputEndOfStreamTimestamp(long)} will be written. In case where
+     *   {@link #setInputEndOfStreamTimestamp(long)} was never called, stop will block
+     *   until maximum number of images are received.
+     *
+     * @param timeoutMs Maximum time (in microsec) to wait for the writer to complete, with zero
+     *                  indicating waiting indefinitely.
+     * @see #setInputEndOfStreamTimestamp(long)
+     * @throws Exception if encountered error, in which case the output file may not be valid. In
+     *                   particular, {@link TimeoutException} is thrown when timed out, and {@link
+     *                   MediaCodec.CodecException} is thrown when encountered codec error.
+     */
+    public void stop(long timeoutMs) throws Exception {
+        checkStarted(true);
+        mHeifEncoder.stopAsync();
+        mResultWaiter.waitForResult(timeoutMs);
+    }
+
+    private void checkStarted(boolean requiredStarted) {
+        if (mStarted != requiredStarted) {
+            throw new IllegalStateException("Already started");
+        }
+    }
+
+    private void checkMode(@InputMode int requiredMode) {
+        if (mInputMode != requiredMode) {
+            throw new IllegalStateException("Not valid in input mode " + mInputMode);
+        }
+    }
+
+    private void checkStartedAndMode(@InputMode int requiredMode) {
+        checkStarted(true);
+        checkMode(requiredMode);
+    }
+
+    /**
+     * Routine to stop and release writer, must be called on the same looper
+     * that receives heif encoder callbacks.
+     */
+    private void closeInternal() {
+        if (DEBUG) Log.d(TAG, "closeInternal");
+
+        if (mMuxer != null) {
+            mMuxer.stop();
+            mMuxer.release();
+            mMuxer = null;
+        }
+
+        if (mHeifEncoder != null) {
+            mHeifEncoder.close();
+            mHeifEncoder = null;
+        }
+    }
+
+    /**
+     * Callback from the heif encoder.
+     */
+    private class HeifCallback extends HeifEncoder.Callback {
+        /**
+         * Upon receiving output format from the encoder, add the requested number of
+         * image tracks to the muxer and start the muxer.
+         */
+        @Override
+        public void onOutputFormatChanged(
+                @NonNull HeifEncoder encoder, @NonNull MediaFormat format) {
+            if (encoder != mHeifEncoder) return;
+
+            if (DEBUG) {
+                Log.d(TAG, "onOutputFormatChanged: " + format);
+            }
+            if (mTrackIndexArray != null) {
+                stopAndNotify(new IllegalStateException(
+                        "Output format changed after muxer started"));
+                return;
+            }
+
+            try {
+                int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
+                int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLS);
+                mNumTiles = gridRows * gridCols;
+            } catch (NullPointerException | ClassCastException  e) {
+                mNumTiles = 1;
+            }
+
+            // add mNumImages image tracks of the same format
+            mTrackIndexArray = new int[mNumImages];
+            for (int i = 0; i < mTrackIndexArray.length; i++) {
+                // mark primary
+                if (i == mPrimaryIndex) {
+                    format.setInteger(MediaFormat.KEY_IS_DEFAULT, 1);
+                }
+                mTrackIndexArray[i] = mMuxer.addTrack(format);
+            }
+            mMuxer.start();
+        }
+
+        /**
+         * Upon receiving an output buffer from the encoder (which is one image when
+         * grid is not used, or one tile if grid is used), add that sample to the muxer.
+         */
+        @Override
+        public void onDrainOutputBuffer(
+                @NonNull HeifEncoder encoder, @NonNull ByteBuffer byteBuffer) {
+            if (encoder != mHeifEncoder) return;
+
+            if (DEBUG) {
+                Log.d(TAG, "onDrainOutputBuffer: " + mOutputIndex);
+            }
+            if (mTrackIndexArray == null) {
+                stopAndNotify(new IllegalStateException(
+                        "Output buffer received before format info"));
+                return;
+            }
+
+            if (mOutputIndex < mNumImages * mNumTiles) {
+                MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+                info.set(byteBuffer.position(), byteBuffer.remaining(), 0, 0);
+                mMuxer.writeSampleData(
+                        mTrackIndexArray[mOutputIndex / mNumTiles], byteBuffer, info);
+            }
+
+            mOutputIndex++;
+
+            // post EOS if reached max number of images allowed.
+            if (mOutputIndex == mNumImages * mNumTiles) {
+                stopAndNotify(null);
+            }
+        }
+
+        @Override
+        public void onComplete(@NonNull HeifEncoder encoder) {
+            if (encoder != mHeifEncoder) return;
+
+            stopAndNotify(null);
+        }
+
+        @Override
+        public void onError(@NonNull HeifEncoder encoder, @NonNull MediaCodec.CodecException e) {
+            if (encoder != mHeifEncoder) return;
+
+            stopAndNotify(e);
+        }
+
+        private void stopAndNotify(@Nullable Exception error) {
+            try {
+                closeInternal();
+            } catch (Exception e) {
+                // if there is an error during muxer stop, that must be propagated,
+                // unless error exists already.
+                if (error == null) {
+                    error = e;
+                }
+            }
+            mResultWaiter.signalResult(error);
+        }
+    }
+
+    private static class ResultWaiter {
+        private boolean mDone;
+        private Exception mException;
+
+        synchronized void waitForResult(long timeoutMs) throws Exception {
+            if (timeoutMs < 0) {
+                throw new IllegalArgumentException("timeoutMs is negative");
+            }
+            if (timeoutMs == 0) {
+                while (!mDone) {
+                    try {
+                        wait();
+                    } catch (InterruptedException ex) {}
+                }
+            } else {
+                final long startTimeMs = System.currentTimeMillis();
+                long remainingWaitTimeMs = timeoutMs;
+                // avoid early termination by "spurious" wakeup.
+                while (!mDone && remainingWaitTimeMs > 0) {
+                    try {
+                        wait(remainingWaitTimeMs);
+                    } catch (InterruptedException ex) {}
+                    remainingWaitTimeMs -= (System.currentTimeMillis() - startTimeMs);
+                }
+            }
+            if (!mDone) {
+                mDone = true;
+                mException = new TimeoutException("timed out waiting for result");
+            }
+            if (mException != null) {
+                throw mException;
+            }
+        }
+
+        synchronized void signalResult(@Nullable Exception e) {
+            if (!mDone) {
+                mDone = true;
+                mException = e;
+                notifyAll();
+            }
+        }
+    }
+
+    @Override
+    public void close() {
+        mHandler.postAtFrontOfQueue(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    closeInternal();
+                } catch (Exception e) {
+                    // If the client called stop() properly, any errors would have been
+                    // reported there. We don't want to crash when closing.
+                }
+            }
+        });
+    }
+}
diff --git a/heifwriter/src/main/java/androidx/media/heifwriter/Texture2dProgram.java b/heifwriter/src/main/java/androidx/media/heifwriter/Texture2dProgram.java
new file mode 100644
index 0000000..b6e720d
--- /dev/null
+++ b/heifwriter/src/main/java/androidx/media/heifwriter/Texture2dProgram.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2018 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.media.heifwriter;
+
+import android.support.annotation.IntDef;
+import android.opengl.GLES11Ext;
+import android.opengl.GLES20;
+import android.opengl.Matrix;
+import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.FloatBuffer;
+
+/**
+ * GL program and supporting functions for textured 2D shapes.
+ *
+ * (Contains mostly code borrowed from Grafika)
+ *
+ * @hide
+ */
+public class Texture2dProgram {
+    private static final String TAG = "Texture2dProgram";
+
+    /** Identity matrix for general use. Don't modify or life will get weird. */
+    public static final float[] IDENTITY_MATRIX;
+
+    /**
+     * Following matrix is for texturing from bitmap. We set up the frame rects
+     * to work with SurfaceTexture's texcoords and texmatrix, but then the bitmap
+     * texturing must flip it vertically. (Don't modify or life gets weird too.)
+     */
+    public static final float[] V_FLIP_MATRIX;
+
+    static {
+        IDENTITY_MATRIX = new float[16];
+        Matrix.setIdentityM(IDENTITY_MATRIX, 0);
+
+        V_FLIP_MATRIX = new float[16];
+        Matrix.setIdentityM(V_FLIP_MATRIX, 0);
+        Matrix.translateM(V_FLIP_MATRIX, 0, 0.0f, 1.0f, 0.0f);
+        Matrix.scaleM(V_FLIP_MATRIX, 0, 1.0f, -1.0f, 1.0f);
+    }
+
+    public static final int TEXTURE_2D = 0;
+    public static final int TEXTURE_EXT = 1;
+
+    /** @hide */
+    @IntDef({
+        TEXTURE_2D,
+        TEXTURE_EXT,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ProgramType {}
+
+    // Simple vertex shader, used for all programs.
+    private static final String VERTEX_SHADER =
+            "uniform mat4 uMVPMatrix;\n" +
+            "uniform mat4 uTexMatrix;\n" +
+            "attribute vec4 aPosition;\n" +
+            "attribute vec4 aTextureCoord;\n" +
+            "varying vec2 vTextureCoord;\n" +
+            "void main() {\n" +
+            "    gl_Position = uMVPMatrix * aPosition;\n" +
+            "    vTextureCoord = (uTexMatrix * aTextureCoord).xy;\n" +
+            "}\n";
+
+    // Simple fragment shader for use with "normal" 2D textures.
+    private static final String FRAGMENT_SHADER_2D =
+            "precision mediump float;\n" +
+            "varying vec2 vTextureCoord;\n" +
+            "uniform sampler2D sTexture;\n" +
+            "void main() {\n" +
+            "    gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+            "}\n";
+
+    // Simple fragment shader for use with external 2D textures (e.g. what we get from
+    // SurfaceTexture).
+    private static final String FRAGMENT_SHADER_EXT =
+            "#extension GL_OES_EGL_image_external : require\n" +
+            "precision mediump float;\n" +
+            "varying vec2 vTextureCoord;\n" +
+            "uniform samplerExternalOES sTexture;\n" +
+            "void main() {\n" +
+            "    gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+            "}\n";
+
+    private @ProgramType int mProgramType;
+
+    // Handles to the GL program and various components of it.
+    private int mProgramHandle;
+    private int muMVPMatrixLoc;
+    private int muTexMatrixLoc;
+    private int maPositionLoc;
+    private int maTextureCoordLoc;
+    private int mTextureTarget;
+
+    /**
+     * Prepares the program in the current EGL context.
+     */
+    public Texture2dProgram(@ProgramType int programType) {
+        mProgramType = programType;
+
+        switch (programType) {
+            case TEXTURE_2D:
+                mTextureTarget = GLES20.GL_TEXTURE_2D;
+                mProgramHandle = createProgram(VERTEX_SHADER, FRAGMENT_SHADER_2D);
+                break;
+            case TEXTURE_EXT:
+                mTextureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES;
+                mProgramHandle = createProgram(VERTEX_SHADER, FRAGMENT_SHADER_EXT);
+                break;
+            default:
+                throw new RuntimeException("Unhandled type " + programType);
+        }
+        if (mProgramHandle == 0) {
+            throw new RuntimeException("Unable to create program");
+        }
+        Log.d(TAG, "Created program " + mProgramHandle + " (" + programType + ")");
+
+        // get locations of attributes and uniforms
+
+        maPositionLoc = GLES20.glGetAttribLocation(mProgramHandle, "aPosition");
+        checkLocation(maPositionLoc, "aPosition");
+        maTextureCoordLoc = GLES20.glGetAttribLocation(mProgramHandle, "aTextureCoord");
+        checkLocation(maTextureCoordLoc, "aTextureCoord");
+        muMVPMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uMVPMatrix");
+        checkLocation(muMVPMatrixLoc, "uMVPMatrix");
+        muTexMatrixLoc = GLES20.glGetUniformLocation(mProgramHandle, "uTexMatrix");
+        checkLocation(muTexMatrixLoc, "uTexMatrix");
+    }
+
+    /**
+     * Releases the program.
+     * <p>
+     * The appropriate EGL context must be current (i.e. the one that was used to create
+     * the program).
+     */
+    public void release() {
+        Log.d(TAG, "deleting program " + mProgramHandle);
+        GLES20.glDeleteProgram(mProgramHandle);
+        mProgramHandle = -1;
+    }
+
+    /**
+     * Returns the program type.
+     */
+    public @ProgramType int getProgramType() {
+        return mProgramType;
+    }
+
+    /**
+     * Creates a texture object suitable for use with this program.
+     * <p>
+     * On exit, the texture will be bound.
+     */
+    public int createTextureObject() {
+        int[] textures = new int[1];
+        GLES20.glGenTextures(1, textures, 0);
+        checkGlError("glGenTextures");
+
+        int texId = textures[0];
+        GLES20.glBindTexture(mTextureTarget, texId);
+        checkGlError("glBindTexture " + texId);
+
+        GLES20.glTexParameterf(mTextureTarget, GLES20.GL_TEXTURE_MIN_FILTER,
+                GLES20.GL_NEAREST);
+        GLES20.glTexParameterf(mTextureTarget, GLES20.GL_TEXTURE_MAG_FILTER,
+                (mTextureTarget == GLES20.GL_TEXTURE_2D) ? GLES20.GL_NEAREST : GLES20.GL_LINEAR);
+        GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_WRAP_S,
+                GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glTexParameteri(mTextureTarget, GLES20.GL_TEXTURE_WRAP_T,
+                GLES20.GL_CLAMP_TO_EDGE);
+        checkGlError("glTexParameter");
+
+        return texId;
+    }
+
+    /**
+     * Issues the draw call.  Does the full setup on every call.
+     *
+     * @param mvpMatrix The 4x4 projection matrix.
+     * @param vertexBuffer Buffer with vertex position data.
+     * @param firstVertex Index of first vertex to use in vertexBuffer.
+     * @param vertexCount Number of vertices in vertexBuffer.
+     * @param coordsPerVertex The number of coordinates per vertex (e.g. x,y is 2).
+     * @param vertexStride Width, in bytes, of the position data for each vertex (often
+     *        vertexCount * sizeof(float)).
+     * @param texMatrix A 4x4 transformation matrix for texture coords.  (Primarily intended
+     *        for use with SurfaceTexture.)
+     * @param texBuffer Buffer with vertex texture data.
+     * @param texStride Width, in bytes, of the texture data for each vertex.
+     */
+    public void draw(float[] mvpMatrix, FloatBuffer vertexBuffer, int firstVertex,
+            int vertexCount, int coordsPerVertex, int vertexStride,
+            float[] texMatrix, FloatBuffer texBuffer, int textureId, int texStride) {
+        checkGlError("draw start");
+
+        // Select the program.
+        GLES20.glUseProgram(mProgramHandle);
+        checkGlError("glUseProgram");
+
+        // Set the texture.
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+        GLES20.glBindTexture(mTextureTarget, textureId);
+
+        // Copy the model / view / projection matrix over.
+        GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mvpMatrix, 0);
+        checkGlError("glUniformMatrix4fv");
+
+        // Copy the texture transformation matrix over.
+        GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, texMatrix, 0);
+        checkGlError("glUniformMatrix4fv");
+
+        // Enable the "aPosition" vertex attribute.
+        GLES20.glEnableVertexAttribArray(maPositionLoc);
+        checkGlError("glEnableVertexAttribArray");
+
+        // Connect vertexBuffer to "aPosition".
+        GLES20.glVertexAttribPointer(maPositionLoc, coordsPerVertex,
+            GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);
+        checkGlError("glVertexAttribPointer");
+
+        // Enable the "aTextureCoord" vertex attribute.
+        GLES20.glEnableVertexAttribArray(maTextureCoordLoc);
+        checkGlError("glEnableVertexAttribArray");
+
+        // Connect texBuffer to "aTextureCoord".
+        GLES20.glVertexAttribPointer(maTextureCoordLoc, 2,
+                GLES20.GL_FLOAT, false, texStride, texBuffer);
+            checkGlError("glVertexAttribPointer");
+
+        // Draw the rect.
+        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, firstVertex, vertexCount);
+        checkGlError("glDrawArrays");
+
+        // Done -- disable vertex array, texture, and program.
+        GLES20.glDisableVertexAttribArray(maPositionLoc);
+        GLES20.glDisableVertexAttribArray(maTextureCoordLoc);
+        GLES20.glBindTexture(mTextureTarget, 0);
+        GLES20.glUseProgram(0);
+    }
+
+    /**
+     * Creates a new program from the supplied vertex and fragment shaders.
+     *
+     * @return A handle to the program, or 0 on failure.
+     */
+    public static int createProgram(String vertexSource, String fragmentSource) {
+        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+        if (vertexShader == 0) {
+            return 0;
+        }
+        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+        if (pixelShader == 0) {
+            return 0;
+        }
+
+        int program = GLES20.glCreateProgram();
+        checkGlError("glCreateProgram");
+        if (program == 0) {
+            Log.e(TAG, "Could not create program");
+        }
+        GLES20.glAttachShader(program, vertexShader);
+        checkGlError("glAttachShader");
+        GLES20.glAttachShader(program, pixelShader);
+        checkGlError("glAttachShader");
+        GLES20.glLinkProgram(program);
+        int[] linkStatus = new int[1];
+        GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+        if (linkStatus[0] != GLES20.GL_TRUE) {
+            Log.e(TAG, "Could not link program: ");
+            Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+            GLES20.glDeleteProgram(program);
+            program = 0;
+        }
+        return program;
+    }
+
+    /**
+     * Compiles the provided shader source.
+     *
+     * @return A handle to the shader, or 0 on failure.
+     */
+    public static int loadShader(int shaderType, String source) {
+        int shader = GLES20.glCreateShader(shaderType);
+        checkGlError("glCreateShader type=" + shaderType);
+        GLES20.glShaderSource(shader, source);
+        GLES20.glCompileShader(shader);
+        int[] compiled = new int[1];
+        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+        if (compiled[0] == 0) {
+            Log.e(TAG, "Could not compile shader " + shaderType + ":");
+            Log.e(TAG, " " + GLES20.glGetShaderInfoLog(shader));
+            GLES20.glDeleteShader(shader);
+            shader = 0;
+        }
+        return shader;
+    }
+
+    /**
+     * Checks to see if the location we obtained is valid.  GLES returns -1 if a label
+     * could not be found, but does not set the GL error.
+     * <p>
+     * Throws a RuntimeException if the location is invalid.
+     */
+    public static void checkLocation(int location, String label) {
+        if (location < 0) {
+            throw new RuntimeException("Unable to locate '" + label + "' in program");
+        }
+    }
+
+    /**
+     * Checks to see if a GLES error has been raised.
+     */
+    public static void checkGlError(String op) {
+        int error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            String msg = op + ": glError 0x" + Integer.toHexString(error);
+            Log.e(TAG, msg);
+            throw new RuntimeException(msg);
+        }
+    }
+}
diff --git a/include-composite-deps.gradle b/include-composite-deps.gradle
new file mode 100644
index 0000000..c8a795f
--- /dev/null
+++ b/include-composite-deps.gradle
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+// This file is part of a a workaround for https://github.com/gradle/gradle/issues/1909 to enable
+// including this Support Library build as an included build. See include-support-library.gradle
+// for usage instructions.
+
+boolean currentBuildIsRootBuild = (gradle.parent == null)
+
+// Add included builds. This only works if this is currently the root build, so this script should
+// be applied to several builds and will only enable itself when part of the root build.
+if (currentBuildIsRootBuild) {
+  String buildScriptDir = buildscript.sourceFile.parent
+  File externalRoot = new File(buildScriptDir, '../../external')
+
+  includeBuild(new File(externalRoot, 'doclava'))
+  includeBuild(new File(externalRoot, 'jdiff'))
+}
+
+
diff --git a/include-support-library.gradle b/include-support-library.gradle
new file mode 100644
index 0000000..fec8041
--- /dev/null
+++ b/include-support-library.gradle
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This file enables using Support Library in a Composite Build. More information about Composite
+// Builds can be found at https://docs.gradle.org/current/userguide/composite_builds.html .
+// This file is a workaround for https://github.com/gradle/gradle/issues/1909 .
+
+// Projects that want to include the build of Support Library should apply this file to their
+// settings.gradle . For example, if Support Library is at the file path ~/support-library, then
+// to include Support Library in your build, add this line to the bottom of your settings.gradle:
+//
+//   apply(from:'~/support-library/frameworks/support/include-support-library.gradle')
+
+String buildScriptDir = buildscript.sourceFile.parent
+
+// include any builds required by Support Library
+apply(from:new File(buildScriptDir, 'include-composite-deps.gradle'))
+
+// include Support Library itself
+includeBuild(buildScriptDir)
+
diff --git a/interpolator/api/current.txt b/interpolator/api/current.txt
new file mode 100644
index 0000000..7de1883
--- /dev/null
+++ b/interpolator/api/current.txt
@@ -0,0 +1,16 @@
+package android.support.v4.view.animation {
+
+  public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
+    ctor public FastOutLinearInInterpolator();
+  }
+
+  public class FastOutSlowInInterpolator implements android.view.animation.Interpolator {
+    ctor public FastOutSlowInInterpolator();
+  }
+
+  public class LinearOutSlowInInterpolator implements android.view.animation.Interpolator {
+    ctor public LinearOutSlowInInterpolator();
+  }
+
+}
+
diff --git a/interpolator/build.gradle b/interpolator/build.gradle
new file mode 100644
index 0000000..6bc6e04
--- /dev/null
+++ b/interpolator/build.gradle
@@ -0,0 +1,19 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+}
+
+supportLibrary {
+    name = "Android Support Library Interpolators"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/interpolator/src/main/AndroidManifest.xml b/interpolator/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..7d63897
--- /dev/null
+++ b/interpolator/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.interpolator"/>
diff --git a/core-ui/src/main/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java b/interpolator/src/main/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java
rename to interpolator/src/main/java/android/support/v4/view/animation/FastOutLinearInInterpolator.java
diff --git a/core-ui/src/main/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java b/interpolator/src/main/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java
rename to interpolator/src/main/java/android/support/v4/view/animation/FastOutSlowInInterpolator.java
diff --git a/core-ui/src/main/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java b/interpolator/src/main/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java
rename to interpolator/src/main/java/android/support/v4/view/animation/LinearOutSlowInInterpolator.java
diff --git a/core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java b/interpolator/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
rename to interpolator/src/main/java/android/support/v4/view/animation/LookupTableInterpolator.java
diff --git a/jetifier/OWNERS b/jetifier/OWNERS
new file mode 100644
index 0000000..8ae348f
--- /dev/null
+++ b/jetifier/OWNERS
@@ -0,0 +1 @@
+pavlis@google.com
diff --git a/jetifier/jetifier/build.gradle b/jetifier/jetifier/build.gradle
index 0f13962..e69de29 100644
--- a/jetifier/jetifier/build.gradle
+++ b/jetifier/jetifier/build.gradle
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-buildscript {
-    ext.supportRootFolder = "${project.projectDir}/../.."
-    def prebuiltsDir = "${ext.supportRootFolder}/../../prebuilts"
-    repositories {
-        maven {
-            url "${prebuiltsDir}/tools/common/m2/repository"
-        }
-    }
-
-    ext.kotlin_version = '1.2.0'
-
-    dependencies {
-        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-    }
-}
-
-// upload anchor for subprojects to upload their artifacts to the local repo.
-task(mainUpload)
-
-subprojects {
-    group 'androidx.tools.jetifier'
-
-    ext.supportRootFolder = "${project.projectDir}/../../.."
-    def prebuiltsDir = "${ext.supportRootFolder}/../../prebuilts"
-    repositories {
-        maven {
-            url "${prebuiltsDir}/tools/common/m2/repository"
-        }
-    }
-
-    apply plugin: 'kotlin'
-
-    compileKotlin {
-        kotlinOptions.jvmTarget = "1.8"
-    }
-    compileTestKotlin {
-        kotlinOptions.jvmTarget = "1.8"
-    }
-
-    dependencies {
-        compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
-    }
-}
-
-ext.runningInBuildServer = System.env.DIST_DIR != null && System.env.OUT_DIR != null
-def setupOutDirs() {
-    /*
-     * With the build server you are given two env variables.
-     * The OUT_DIR is a temporary directory you can use to put things during the build.
-     * The DIST_DIR is where you want to save things from the build.
-     *
-     * The build server will copy the contents of DIST_DIR to somewhere and make it available.
-     */
-    if (ext.runningInBuildServer) {
-        buildDir = new File(System.env.OUT_DIR + '/gradle/frameworks/support/build')
-                .getCanonicalFile()
-        project.ext.distDir = new File(System.env.DIST_DIR).getCanonicalFile()
-        // the build server does not pass the build number so we infer it from the last folder of
-        // the dist path.
-        ext.buildNumber = project.ext.distDir.getName()
-
-        // the build server should always print out full stack traces for any failures.
-        gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS
-    } else {
-        buildDir = file("${ext.supportRootFolder}/../../out/host/gradle/frameworks/support/jetifier/build")
-        project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist")
-        ext.buildNumber = 0
-    }
-
-    ext.repoDir = "file://$project.buildDir/repo"
-
-    subprojects {
-        // Change buildDir so that all plugins pick up the new value.
-        project.buildDir = new File("$project.parent.buildDir/../$project.name/build")
-        project.ext.distDir = new File("${ext.supportRootFolder}/../../out/dist")
-    }
-}
-
-def configureBuildOnServer() {
-    def buildOnServerTask = rootProject.tasks.create("buildOnServer")
-    rootProject.tasks.whenTaskAdded { task ->
-        if ("build".equals(task.name)) {
-            buildOnServerTask.dependsOn task
-        }
-    }
-    subprojects {
-        project.tasks.whenTaskAdded { task ->
-            if ("fatJar".equals(task.name)) {
-                buildOnServerTask.dependsOn task
-            }
-        }
-    }
-    buildOnServerTask.dependsOn "createArchive"
-}
-
-setupOutDirs()
-configureBuildOnServer()
-
-// anchor for prepare repo. This is post unzip.
-task prepareRepo() {
-    description "This task clears the repo folder to ensure that we run a fresh build every" +
-            " time we create arhives. Otherwise, snapshots will accumulate in the builds folder."
-    doFirst {
-        file(rootProject.ext.repoDir).deleteDir()
-        file(rootProject.ext.repoDir).mkdirs()
-    }
-}
-
-task createArchive(type : Zip) {
-    description "Creates a maven repository that includes just the libraries compiled in this" +
-            " project, without any history from prebuilts."
-    from rootProject.ext.repoDir
-    destinationDir rootProject.ext.distDir
-    into 'm2repository'
-    baseName = String.format("top-of-tree-m2repository-%s", project.ext.buildNumber)
-    dependsOn mainUpload
-}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/build.gradle b/jetifier/jetifier/core/build.gradle
index 72edcfa..683a020 100644
--- a/jetifier/jetifier/core/build.gradle
+++ b/jetifier/jetifier/core/build.gradle
@@ -14,26 +14,31 @@
  * limitations under the License
  */
 
-apply plugin: 'maven'
+import static android.support.dependencies.DependenciesKt.KOTLIN_STDLIB
 
-version '0.2'
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportKotlinLibraryPlugin")
+}
 
 dependencies {
     compile("org.ow2.asm:asm:5.2")
     compile("org.ow2.asm:asm-commons:5.2")
     compile("com.google.code.gson:gson:2.8.0")
     compile("org.jdom:jdom2:2.0.6")
+    compile(KOTLIN_STDLIB)
     testCompile("junit:junit:4.12")
-    testCompile("com.google.truth:truth:0.31")
+    testCompile("com.google.truth:truth:0.34")
 }
 
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: rootProject.ext.repoDir)
-        }
-    }
+supportLibrary {
+    name = "Android Jetifier Core"
+    publish = true
+    mavenVersion = LibraryVersions.JETIFIER
+    mavenGroup = LibraryGroups.JETIFIER
+    generateDocs = false
+    inceptionYear = "2017"
+    description = "Android Jetifier Core"
 }
-
-rootProject.mainUpload.dependsOn tasks["uploadArchives"]
-tasks["uploadArchives"].dependsOn rootProject.prepareRepo
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/Processor.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/Processor.kt
index 5af8fb2..1f0b901 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/Processor.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/Processor.kt
@@ -23,6 +23,7 @@
 import android.support.tools.jetifier.core.transform.TransformationContext
 import android.support.tools.jetifier.core.transform.Transformer
 import android.support.tools.jetifier.core.transform.bytecode.ByteCodeTransformer
+import android.support.tools.jetifier.core.transform.metainf.MetaInfTransformer
 import android.support.tools.jetifier.core.transform.pom.PomDocument
 import android.support.tools.jetifier.core.transform.pom.PomScanner
 import android.support.tools.jetifier.core.transform.proguard.ProGuardTransformer
@@ -30,7 +31,6 @@
 import android.support.tools.jetifier.core.utils.Log
 import java.io.File
 import java.io.FileNotFoundException
-import java.nio.file.Files
 import java.nio.file.Path
 
 /**
@@ -38,31 +38,106 @@
  * the registered [Transformer]s over the set and creates new archives that will contain the
  * transformed files.
  */
-class Processor(private val config : Config) : ArchiveItemVisitor {
+class Processor private constructor (
+    private val context: TransformationContext,
+    private val transformers: List<Transformer>
+) : ArchiveItemVisitor {
 
     companion object {
         private const val TAG = "Processor"
-    }
 
-    private val context = TransformationContext(config)
+        /**
+         * Value of "restrictToPackagePrefixes" config for reversed jetification.
+         */
+        private const val REVERSE_RESTRICT_TO_PACKAGE = "androidx"
 
-    private val transformers = listOf(
+        /**
+         * Transformers to be used when refactoring general libraries.
+         */
+        private fun createTransformers(context: TransformationContext) = listOf(
             // Register your transformers here
             ByteCodeTransformer(context),
             XmlResourcesTransformer(context),
             ProGuardTransformer(context)
-    )
+        )
+
+        /**
+         * Transformers to be used when refactoring the support library itself.
+         */
+        private fun createSLTransformers(context: TransformationContext) = listOf(
+            // Register your transformers here
+            ByteCodeTransformer(context),
+            XmlResourcesTransformer(context),
+            ProGuardTransformer(context),
+            MetaInfTransformer(context)
+        )
+
+        /**
+         * Creates a new instance of the [Processor].
+         *
+         * @param config Transformation configuration
+         * @param reversedMode Whether the processor should run in reversed mode
+         * @param rewritingSupportLib Whether we are rewriting the support library itself
+         */
+        fun createProcessor(
+            config: Config,
+            reversedMode: Boolean = false,
+            rewritingSupportLib: Boolean = false
+        ): Processor {
+            var newConfig = config
+
+            if (reversedMode) {
+                newConfig = Config(
+                    restrictToPackagePrefixes = listOf(REVERSE_RESTRICT_TO_PACKAGE),
+                    rewriteRules = config.rewriteRules,
+                    slRules = config.slRules,
+                    pomRewriteRules = emptyList(), // TODO: This will need a new set of rules
+                    typesMap = config.typesMap.reverseMapOrDie(),
+                    proGuardMap = config.proGuardMap.reverseMapOrDie(),
+                    packageMap = config.packageMap.reverse()
+                )
+            }
+
+            val context = TransformationContext(newConfig, rewritingSupportLib, reversedMode)
+            val transformers = if (rewritingSupportLib) {
+                createSLTransformers(context)
+            } else {
+                createTransformers(context)
+            }
+
+            return Processor(context, transformers)
+        }
+    }
 
     /**
      * Transforms the input libraries given in [inputLibraries] using all the registered
-     * [Transformer]s and returns new libraries stored in [outputPath].
+     * [Transformer]s and returns a list of replacement libraries (the newly created libraries are
+     * get stored into [outputPath]).
      *
      * Currently we have the following transformers:
      * - [ByteCodeTransformer] for java native code
      * - [XmlResourcesTransformer] for java native code
      * - [ProGuardTransformer] for PorGuard files
+     *
+     * @param outputPath Path where to save the generated library / libraries.
+     * @param outputIsDir Whether the [outputPath] represents a single file or a directory. In case
+     * of a single file, only one library can be given as input.
+     * @param copyUnmodifiedLibsAlso Whether archives that were not modified should be also copied
+     * to the given [outputPath]
+     * @return List of files (existing and generated) that should replace the given [inputLibraries]
      */
-    fun transform(inputLibraries: Set<File>, outputPath: Path) : TransformationResult {
+    fun transform(inputLibraries: Set<File>,
+            outputPath: Path,
+            outputIsDir: Boolean,
+            copyUnmodifiedLibsAlso: Boolean = true
+    ): Set<File> {
+        // 0) Validate arguments
+        if (!outputIsDir && inputLibraries.size > 1) {
+            throw IllegalArgumentException("Cannot process more than 1 library (" + inputLibraries +
+                    ") when it is requested tha the destination (" + outputPath +
+                    ") be made a file")
+        }
+
         // 1) Extract and load all libraries
         val libraries = loadLibraries(inputLibraries)
 
@@ -70,10 +145,10 @@
         val pomFiles = scanPomFiles(libraries)
 
         // 3) Transform all the libraries
-        libraries.forEach{ transformLibrary(it) }
+        libraries.forEach { transformLibrary(it) }
 
-        if (context.wasErrorFound()) {
-            throw IllegalArgumentException("There were ${context.mappingNotFoundFailuresCount}" +
+        if (context.errorsTotal() > 0) {
+            throw IllegalArgumentException("There were ${context.errorsTotal()}" +
                 " errors found during the remapping. Check the logs for more details.")
         }
 
@@ -83,16 +158,32 @@
         // 4) Transform the previously discovered POM files
         transformPomFiles(pomFiles)
 
-        // 5) Repackage the libraries back to archives
-        val outputLibraries = libraries.map{ it.writeSelfToDir(outputPath) }.toSet()
+        // 5) Repackage the libraries back to archive files
+        val generatedLibraries = libraries
+            .filter { copyUnmodifiedLibsAlso || it.wasChanged }
+            .map {
+                if (outputIsDir) {
+                    it.writeSelfToDir(outputPath)
+                } else {
+                    it.writeSelfToFile(outputPath)
+                }
+            }
+            .toSet()
 
-        // TODO: Filter out only the libraries that have been really changed
-        return TransformationResult(
-            filesToRemove = inputLibraries,
-            filesToAdd = outputLibraries)
+        if (copyUnmodifiedLibsAlso) {
+            return generatedLibraries
+        }
+
+        // 6) Create a set of files that should be removed (because they've been changed).
+        val filesToRemove = libraries
+            .filter { it.wasChanged }
+            .map { it.relativePath.toFile() }
+            .toSet()
+
+        return inputLibraries.minus(filesToRemove).plus(generatedLibraries)
     }
 
-    private fun loadLibraries(inputLibraries : Iterable<File>) : List<Archive> {
+    private fun loadLibraries(inputLibraries: Iterable<File>): List<Archive> {
         val libraries = mutableListOf<Archive>()
         for (library in inputLibraries) {
             if (!library.canRead()) {
@@ -104,8 +195,8 @@
         return libraries.toList()
     }
 
-    private fun scanPomFiles(libraries: List<Archive>) : List<PomDocument> {
-        val scanner = PomScanner(config)
+    private fun scanPomFiles(libraries: List<Archive>): List<PomDocument> {
+        val scanner = PomScanner(context.config)
 
         libraries.forEach { scanner.scanArchiveForPomFile(it) }
         if (scanner.wasErrorFound()) {
@@ -118,7 +209,7 @@
 
     private fun transformPomFiles(files: List<PomDocument>) {
         files.forEach {
-            it.applyRules(config.pomRewriteRules)
+            it.applyRules(context.config.pomRewriteRules)
             it.saveBackToFileIfNeeded()
         }
     }
@@ -127,11 +218,12 @@
         Log.i(TAG, "Started new transformation")
         Log.i(TAG, "- Input file: %s", archive.relativePath)
 
+        context.libraryName = archive.fileName
         archive.accept(this)
     }
 
     override fun visit(archive: Archive) {
-        archive.files.forEach{ it.accept(this) }
+        archive.files.forEach { it.accept(this) }
     }
 
     override fun visit(archiveFile: ArchiveFile) {
@@ -145,5 +237,4 @@
         Log.i(TAG, "[Applied: %s] %s", transformer.javaClass.simpleName, archiveFile.relativePath)
         transformer.runTransform(archiveFile)
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/Archive.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/Archive.kt
index 70ea68c..38d810b 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/Archive.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/Archive.kt
@@ -48,21 +48,29 @@
 
     override val fileName: String = relativePath.fileName.toString()
 
+    override val wasChanged: Boolean
+        get() = files.any { it.wasChanged }
+
     override fun accept(visitor: ArchiveItemVisitor) {
         visitor.visit(this)
     }
 
     @Throws(IOException::class)
-    fun writeSelfToDir(outputDirPath: Path) : File {
+    fun writeSelfToDir(outputDirPath: Path): File {
         val outputPath = Paths.get(outputDirPath.toString(), fileName)
 
+        return writeSelfToFile(outputPath)
+    }
+
+    @Throws(IOException::class)
+    fun writeSelfToFile(outputPath: Path): File {
         if (Files.exists(outputPath)) {
             Log.i(TAG, "Deleting old output file")
             Files.delete(outputPath)
         }
 
         // Create directories if they don't exist yet
-        Files.createDirectories(outputDirPath)
+        Files.createDirectories(outputPath.parent)
 
         Log.i(TAG, "Writing archive: %s", outputPath.toUri())
         val file = outputPath.toFile()
@@ -88,7 +96,6 @@
         out.finish()
     }
 
-
     object Builder {
 
         @Throws(IOException::class)
@@ -102,8 +109,7 @@
         }
 
         @Throws(IOException::class)
-        private fun extractArchive(inputStream: InputStream, relativePath: Path)
-                : Archive {
+        private fun extractArchive(inputStream: InputStream, relativePath: Path): Archive {
             val zipIn = ZipInputStream(inputStream)
             val files = mutableListOf<ArchiveItem>()
 
@@ -136,9 +142,8 @@
             return ArchiveFile(relativePath, data)
         }
 
-        private fun isArchive(zipEntry: ZipEntry) : Boolean {
+        private fun isArchive(zipEntry: ZipEntry): Boolean {
             return ARCHIVE_EXTENSIONS.any { zipEntry.name.endsWith(it, ignoreCase = true) }
         }
-
     }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveFile.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveFile.kt
index 3054b71..81c166e 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveFile.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveFile.kt
@@ -23,9 +23,19 @@
 /**
  * Represents a file in the archive that is not an archive.
  */
-class ArchiveFile(override val relativePath: Path, var data: ByteArray) : ArchiveItem {
+class ArchiveFile(relativePath: Path, data: ByteArray) : ArchiveItem {
 
-    override val fileName: String = relativePath.fileName.toString()
+    override var relativePath = relativePath
+        private set
+
+    override var fileName: String = relativePath.fileName.toString()
+        private set
+
+    override var wasChanged: Boolean = false
+        private set
+
+    var data: ByteArray = data
+        private set
 
     override fun accept(visitor: ArchiveItemVisitor) {
         visitor.visit(this)
@@ -36,4 +46,17 @@
         outputStream.write(data)
     }
 
+    fun updateRelativePath(newRelativePath: Path) {
+        if (relativePath != newRelativePath) {
+            wasChanged = true
+        }
+
+        relativePath = newRelativePath
+        fileName = relativePath.fileName.toString()
+    }
+
+    fun setNewData(newData: ByteArray) {
+        data = newData
+        wasChanged = true
+    }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItem.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItem.kt
index 2d35e13..63c795a 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItem.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/archive/ArchiveItem.kt
@@ -20,7 +20,8 @@
 import java.nio.file.Path
 
 /**
- * Abstraction to represent archive and its files as a one thing.
+ * Abstraction to represent archive and its files as a one thing before and after transformation
+ * together with information if any changes happened during the transformation.
  */
 interface ArchiveItem {
 
@@ -30,12 +31,17 @@
      * Files in a nested archive have a path relative to that archive not to the parent of
      * the archive. The root archive has the file system path set as its relative path.
      */
-    val relativePath : Path
+    val relativePath: Path
 
     /**
      * Name of the file.
      */
-    val fileName : String
+    val fileName: String
+
+    /**
+     * Whether the item's content or its children were changed by Jetifier.
+     */
+    val wasChanged: Boolean
 
     /**
      * Accepts visitor.
@@ -47,7 +53,6 @@
      */
     fun writeSelfTo(outputStream: OutputStream)
 
-
     fun isPomFile() = fileName.equals("pom.xml", ignoreCase = true)
 
     fun isClassFile() = fileName.endsWith(".class", ignoreCase = true)
@@ -55,5 +60,4 @@
     fun isXmlFile() = fileName.endsWith(".xml", ignoreCase = true)
 
     fun isProGuardFile () = fileName.equals("proguard.txt", ignoreCase = true)
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/Config.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/Config.kt
index 8d70d87..007130d 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/Config.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/config/Config.kt
@@ -19,6 +19,7 @@
 import android.support.tools.jetifier.core.rules.RewriteRule
 import android.support.tools.jetifier.core.transform.pom.PomRewriteRule
 import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.transform.PackageMap
 import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
 import com.google.gson.annotations.SerializedName
 
@@ -27,38 +28,44 @@
  *
  * [restrictToPackagePrefixes] Package prefixes that limit the scope of the rewriting
  * [rewriteRules] Rules to scan support libraries to generate [TypesMap]
+ * [slRules] List of rules used when rewriting the support library itself in the reversed mode to
+ * ignore packages that don't need rewriting anymore.
  * [pomRewriteRules] Rules to rewrite POM files
  * [typesMap] Map of all java types and fields to be used to rewrite libraries.
+ * [packageMap] Package map to be used to rewrite packages, used only during the support library
+ * rewrite.
  */
 data class Config(
         val restrictToPackagePrefixes: List<String>,
         val rewriteRules: List<RewriteRule>,
+        val slRules: List<RewriteRule>,
         val pomRewriteRules: List<PomRewriteRule>,
         val typesMap: TypesMap,
-        val proGuardMap: ProGuardTypesMap) {
+        val proGuardMap: ProGuardTypesMap,
+        val packageMap: PackageMap = PackageMap(PackageMap.DEFAULT_RULES)) {
 
     companion object {
         /** Path to the default config file located within the jar file. */
         const val DEFAULT_CONFIG_RES_PATH = "/default.generated.config"
     }
 
-    fun setNewMap(mappings: TypesMap) : Config {
-        return Config(
-            restrictToPackagePrefixes, rewriteRules, pomRewriteRules, mappings, proGuardMap)
+    fun setNewMap(mappings: TypesMap): Config {
+        return Config(restrictToPackagePrefixes, rewriteRules, slRules, pomRewriteRules,
+            mappings, proGuardMap)
     }
 
     /** Returns JSON data model of this class */
-    fun toJson() : JsonData {
+    fun toJson(): JsonData {
         return JsonData(
             restrictToPackagePrefixes,
             rewriteRules.map { it.toJson() }.toList(),
+            slRules.map { it.toJson() }.toList(),
             pomRewriteRules.map { it.toJson() }.toList(),
             typesMap.toJson(),
             proGuardMap.toJson()
         )
     }
 
-
     /**
      * JSON data model for [Config].
      */
@@ -69,6 +76,9 @@
             @SerializedName("rules")
             val rules: List<RewriteRule.JsonData?>,
 
+            @SerializedName("slRules")
+            val slRules: List<RewriteRule.JsonData?>?,
+
             @SerializedName("pomRules")
             val pomRules: List<PomRewriteRule.JsonData?>,
 
@@ -79,15 +89,15 @@
             val proGuardMap: ProGuardTypesMap.JsonData? = null) {
 
         /** Creates instance of [Config] */
-        fun toConfig() : Config {
+        fun toConfig(): Config {
             return Config(
-                restrictToPackages.filterNotNull(),
-                rules.filterNotNull().map { it.toRule() },
-                pomRules.filterNotNull().map { it.toRule() },
-                mappings?.toMappings() ?: TypesMap.EMPTY,
-                proGuardMap?.toMappings() ?: ProGuardTypesMap.EMPTY
+                restrictToPackagePrefixes = restrictToPackages.filterNotNull(),
+                rewriteRules = rules.filterNotNull().map { it.toRule() },
+                slRules = slRules?.filterNotNull()?.map { it.toRule() } ?: listOf(),
+                pomRewriteRules = pomRules.filterNotNull().map { it.toRule() },
+                typesMap = mappings?.toMappings() ?: TypesMap.EMPTY,
+                proGuardMap = proGuardMap?.toMappings() ?: ProGuardTypesMap.EMPTY
             )
         }
     }
-
 }
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/LibraryMapGenerator.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/LibraryMapGenerator.kt
index e52009f..c9d8f9f 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/LibraryMapGenerator.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/LibraryMapGenerator.kt
@@ -42,9 +42,7 @@
      * Creates the [TypesMap] based on the meta-data aggregated via previous [scanFile] calls
      */
     fun generateMap(): TypesMap {
-        val map = remapper.createTypesMap()
-        map.validateThatMapIsReversibleOrDie()
-        return map
+        return remapper.createTypesMap()
     }
 
     override fun visit(archive: Archive) {
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/MapGeneratorRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/MapGeneratorRemapper.kt
index 10abe1e..369cf91 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/MapGeneratorRemapper.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/MapGeneratorRemapper.kt
@@ -17,18 +17,16 @@
 package android.support.tools.jetifier.core.map
 
 import android.support.tools.jetifier.core.config.Config
-import android.support.tools.jetifier.core.rules.JavaField
 import android.support.tools.jetifier.core.rules.JavaType
 import android.support.tools.jetifier.core.transform.bytecode.CoreRemapper
-import android.support.tools.jetifier.core.transform.bytecode.asm.CustomClassRemapper
 import android.support.tools.jetifier.core.transform.bytecode.asm.CustomRemapper
 import android.support.tools.jetifier.core.utils.Log
 import org.objectweb.asm.ClassVisitor
-import java.util.regex.Pattern
+import org.objectweb.asm.commons.ClassRemapper
 
 /**
  * Hooks to asm remapping to collect data for [TypesMap] by applying all the [RewriteRule]s from the
- * given [config] on all discovered and eligible types and fields.
+ * given [config] on all discovered and eligible types.
  */
 class MapGeneratorRemapper(private val config: Config) : CoreRemapper {
 
@@ -36,26 +34,13 @@
         private const val TAG: String = "MapGeneratorRemapper"
     }
 
-    private val typesRewritesMap = hashMapOf<JavaType, JavaType>()
-    private val fieldsRewritesMap = hashMapOf<JavaField, JavaField>()
+    private val typesRewritesMap = mutableMapOf<JavaType, JavaType>()
 
     var isMapNotComplete = false
         private set
 
-    /**
-     * Ignore mPrefix types and anything that contains $ as these are internal fields that won't be
-     * ever referenced.
-     */
-    private val ignoredFields = Pattern.compile("(^m[A-Z]+.*$)|(.*\\$.*)")
-
-    /**
-     * Ignores types ending with '$digit' as these are private inner classes and won't be ever
-     * referenced.
-     */
-    private val ignoredTypes = Pattern.compile("^(.*)\\$[0-9]+$")
-
-    fun createClassRemapper(visitor: ClassVisitor): CustomClassRemapper {
-        return CustomClassRemapper(visitor, CustomRemapper(this))
+    fun createClassRemapper(visitor: ClassVisitor): ClassRemapper {
+        return ClassRemapper(visitor, CustomRemapper(this))
     }
 
     override fun rewriteType(type: JavaType): JavaType {
@@ -67,10 +52,6 @@
             return type
         }
 
-        if (isTypeIgnored(type)) {
-            return type
-        }
-
         // Try to find a rule
         for (rule in config.rewriteRules) {
             val typeRewriteResult = rule.apply(type)
@@ -92,58 +73,16 @@
         return type
     }
 
-    override fun rewriteField(field: JavaField): JavaField {
-        if (!isTypeSupported(field.owner)) {
-            return field
-        }
-
-        if (isTypeIgnored(field.owner) || isFieldIgnored(field)) {
-            return field
-        }
-
-        if (fieldsRewritesMap.contains(field)) {
-            return field
-        }
-
-        // Try to find a rule
-        for (rule in config.rewriteRules) {
-            val fieldRewriteResult = rule.apply(field)
-            if (fieldRewriteResult.isIgnored) {
-                Log.i(TAG, "Ignoring: " + field)
-                return field
-            }
-            if (fieldRewriteResult.result == null) {
-                continue
-            }
-            fieldsRewritesMap.put(field, fieldRewriteResult.result)
-            Log.i(TAG, "  map: %s -> %s", field, fieldRewriteResult.result)
-            return fieldRewriteResult.result
-        }
-
-        isMapNotComplete = true
-        Log.e(TAG, "No rule for: " + field)
-        fieldsRewritesMap.put(field, field) // Identity
-        return field
-    }
-
     override fun rewriteString(value: String): String {
         // We don't build map from strings
         return value
     }
 
     fun createTypesMap(): TypesMap {
-        return TypesMap(typesRewritesMap, fieldsRewritesMap)
+        return TypesMap(typesRewritesMap)
     }
 
     private fun isTypeSupported(type: JavaType): Boolean {
         return config.restrictToPackagePrefixes.any { type.fullName.startsWith(it) }
     }
-
-    private fun isTypeIgnored(type: JavaType): Boolean {
-        return ignoredTypes.matcher(type.fullName).matches()
-    }
-
-    private fun isFieldIgnored(field: JavaField): Boolean {
-        return ignoredFields.matcher(field.name).matches()
-    }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/TypesMap.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/TypesMap.kt
index b33d4bc..c5f221e 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/TypesMap.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/map/TypesMap.kt
@@ -16,54 +16,35 @@
 
 package android.support.tools.jetifier.core.map
 
-import android.support.tools.jetifier.core.rules.JavaField
 import android.support.tools.jetifier.core.rules.JavaType
 import android.support.tools.jetifier.core.rules.RewriteRule
 import android.support.tools.jetifier.core.utils.Log
 
 /**
- * Contains all the mappings needed to rewrite java types and fields.
+ * Contains all the mappings needed to rewrite java types.
  *
  * These mappings are generated by the preprocessor from existing support libraries and by applying
  * the given [RewriteRule]s.
  */
 data class TypesMap(
-        val types: Map<JavaType, JavaType>,
-        val fields: Map<JavaField, JavaField>) {
+        val types: Map<JavaType, JavaType>) {
 
     companion object {
         private const val TAG = "TypesMap"
 
-        val EMPTY = TypesMap(emptyMap(), emptyMap())
+        val EMPTY = TypesMap(emptyMap())
     }
 
     /** Returns JSON data model of this class */
     fun toJson(): JsonData {
-        return JsonData(
-                types = types.map { it.key.fullName to it.value.fullName }
-                        .toMap(),
-                fields = mapFields())
-    }
-
-    private fun mapFields(): Map<String, Map<String, List<String>>> {
-        val rawMap = mutableMapOf<String, MutableMap<String, MutableList<String>>>()
-
-        fields.forEach {
-            rawMap
-                .getOrPut(it.key.owner.fullName, { mutableMapOf() })
-                .getOrPut(it.value.owner.fullName, { mutableListOf() })
-                .add(it.key.name)
-        }
-        return rawMap
+        return JsonData(types.map { it.key.fullName to it.value.fullName }.toMap())
     }
 
     /**
-     * Validates that the current map can be used in reversed mode (values become keys). Throws
-     * exception if the map does not satisfy that.
+     * Creates reversed version of this map (values become keys). Throws exception if the map does
+     * not satisfy that.
      */
-    fun validateThatMapIsReversibleOrDie() {
-        Log.i(TAG, "Validating that the map is reversible")
-
+    fun reverseMapOrDie(): TypesMap {
         val typesReversed = mutableMapOf<JavaType, JavaType>()
         for ((from, to) in types) {
             val conflictFrom = typesReversed[to]
@@ -74,29 +55,32 @@
             typesReversed[to] = from
         }
 
-        val fieldsReversed = mutableMapOf<JavaField, JavaField>()
-        for ((from, to) in fields) {
-            val conflictFrom = fieldsReversed[to]
-            if (conflictFrom != null) {
-                Log.e(TAG, "Conflict: %s -> (%s, %s)", to, from, conflictFrom)
-                continue
-            }
-            fieldsReversed[to] = from
+        if (types.size != typesReversed.size) {
+            throw IllegalArgumentException("Types map is not reversible as conflicts were found! " +
+                "See the log for more details.")
         }
 
-        if (types.size != typesReversed.size || fields.size != fieldsReversed.size) {
-            throw IllegalArgumentException(
-                "Map is not reversible as conflicts were found! See the log for more details.")
+        return TypesMap(types= typesReversed)
+    }
+
+    fun mergetWith(typesMap: TypesMap): TypesMap {
+        val mergedMap = mutableMapOf<JavaType, JavaType>()
+        mergedMap.putAll(types)
+        typesMap.types.forEach {
+            if (mergedMap.containsKey(it.key)) {
+                throw RuntimeException("Failed to merge the given types maps as there is" +
+                    " a duplicity with key '${it.key.fullName}' for values '${it.value}' and " +
+                    "'${mergedMap[it.key]}'.")
+            }
+            mergedMap.put(it.key, it.value)
         }
-        Log.i(TAG, "Map is reversible. Success!")
+        return TypesMap(mergedMap)
     }
 
     /**
      * JSON data model for [TypesMap].
      */
-    data class JsonData(
-            val types: Map<String, String>,
-            val fields: Map<String, Map<String, List<String>>>) {
+    data class JsonData(val types: Map<String, String>) {
 
         /** Creates instance of [TypesMap] */
         fun toMappings(): TypesMap {
@@ -104,18 +88,6 @@
                 types = types
                     .orEmpty()
                     .map { JavaType(it.key) to JavaType(it.value) }
-                    .toMap(),
-                fields = fields
-                    .orEmpty().entries
-                    .flatMap {
-                        top ->
-                        top.value.flatMap {
-                            mid ->
-                            mid.value.map {
-                                JavaField(top.key, it) to JavaField(mid.key, it)
-                            }
-                        }
-                    }
                     .toMap())
         }
     }
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaField.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaField.kt
deleted file mode 100644
index c423f0a..0000000
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaField.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.support.tools.jetifier.core.rules
-
-/**
- * Wrapper for Java field declaration.
- */
-data class JavaField(val owner : JavaType, val name : String) {
-
-    constructor(owner : String, name : String) : this(JavaType(owner), name)
-
-
-    fun renameOwner(newOwner: JavaType) = JavaField(newOwner, name)
-
-    override fun toString() = owner.toString() + "." + name
-
-}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaType.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaType.kt
index d7a077b..744ec29 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaType.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaType.kt
@@ -18,6 +18,8 @@
 
 /**
  * Wrapper for Java type declaration.
+ *
+ * For packages use [PackageName].
  */
 data class JavaType(val fullName: String) {
 
@@ -29,17 +31,15 @@
 
     companion object {
         /** Creates the type from notation where packages are separated using '.' */
-        fun fromDotVersion(fullName: String) : JavaType {
+        fun fromDotVersion(fullName: String): JavaType {
             return JavaType(fullName.replace('.', '/'))
         }
     }
 
     /** Returns the type as a string where packages are separated using '.' */
-    fun toDotNotation() : String {
+    fun toDotNotation(): String {
         return fullName.replace('/', '.')
     }
 
-
     override fun toString() = fullName
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaTypeXmlRef.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaTypeXmlRef.kt
deleted file mode 100644
index 9d58046..0000000
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/JavaTypeXmlRef.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.support.tools.jetifier.core.rules
-
-/**
- * Wrapper for Java type reference used in XML.
- *
- * In XML we use '.' as a package separator.
- */
-data class JavaTypeXmlRef(val fullName : String) {
-
-    constructor(type: JavaType)
-        : this(type.fullName.replace('/', '.'))
-
-    fun toJavaType() : JavaType {
-        return JavaType(fullName.replace('.', '/'))
-    }
-
-    override fun toString() = fullName
-}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/PackageName.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/PackageName.kt
new file mode 100644
index 0000000..c42f995
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/PackageName.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.tools.jetifier.core.rules
+
+/**
+ * Wrapper for Java package name declaration.
+ */
+data class PackageName(val fullName: String) {
+
+    init {
+        if (fullName.contains('.')) {
+            throw IllegalArgumentException("The type does not support '.' as a package separator!")
+        }
+    }
+
+    companion object {
+        /** Creates the package from notation where packages are separated using '.' */
+        fun fromDotVersion(fullName: String): PackageName {
+            return PackageName(fullName.replace('.', '/'))
+        }
+    }
+
+    /** Returns the package as a string where packages are separated using '.' */
+    fun toDotNotation(): String {
+        return fullName.replace('/', '.')
+    }
+
+    override fun toString() = fullName
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/RewriteRule.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/RewriteRule.kt
index 40497d8..0a7fbde 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/RewriteRule.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/rules/RewriteRule.kt
@@ -16,11 +16,12 @@
 
 package android.support.tools.jetifier.core.rules
 
+import android.support.tools.jetifier.core.transform.proguard.ProGuardType
 import com.google.gson.annotations.SerializedName
 import java.util.regex.Pattern
 
 /**
- * Rule that rewrites a Java type or field based on the given arguments.
+ * Rule that rewrites a Java type based on the given arguments.
  *
  * Used in the preprocessor when generating [TypesMap].
  *
@@ -28,62 +29,52 @@
  * is "$". Used to match the input type.
  * @param to A string to be used as a replacement if the 'from' pattern is matched. It can also
  * apply groups matched from the original pattern using {x} annotation, e.g. {0}.
- * @param fieldSelectors Collection of regular expressions that are used to match fields. If the
- * type is matched (using 'from') and the field is matched (or the list of fields selectors is
- * empty) the field's type gets rewritten according to the 'to' parameter.
  */
 class RewriteRule(
         private val from: String,
-        private val to: String,
-        private val fieldSelectors: List<String> = emptyList()) {
+        private val to: String) {
+
+    companion object {
+        const val IGNORE_RUNTIME = "ignore"
+        const val IGNORE_PREPROCESSOR_ONLY = "ignoreInPreprocessorOnly"
+    }
 
     // We escape '$' so we don't conflict with regular expression symbols.
     private val inputPattern = Pattern.compile("^${from.replace("$", "\\$")}$")
     private val outputPattern = to.replace("$", "\$")
 
-    private val fields = fieldSelectors.map { Pattern.compile("^$it$") }
+    /*
+     * Whether this is any type of an ignore rule.
+     */
+    fun isIgnoreRule() = isRuntimeIgnoreRule() || isPreprocessorOnlyIgnoreRule()
+
+    /*
+     * Whether this rules is an ignore rule.
+     *
+     * Any type matched to [from] will be in such case ignored by the preprocessor (thus missing
+     * from the map) but it will be also ignored during rewriting.
+     */
+    fun isRuntimeIgnoreRule() = to == IGNORE_RUNTIME
+
+    /*
+     * Whether this rule is an ignore rule that should be used only in the preprocessor.
+     *
+     * That means that error is still thrown if [from] is found in a library that is being
+     * rewritten. Use this for types that are internal to support library. This is weaker version of
+     * [isRuntimeIgnoreRule].
+     */
+    fun isPreprocessorOnlyIgnoreRule() = to == IGNORE_PREPROCESSOR_ONLY
 
     /**
      * Rewrites the given java type. Returns null if this rule is not applicable for the given type.
      */
     fun apply(input: JavaType): TypeRewriteResult {
-        if (fields.isNotEmpty()) {
-            return TypeRewriteResult.NOT_APPLIED
-        }
-
-        return applyInternal(input)
-    }
-
-    /**
-     * Rewrites the given field type. Returns null if this rule is not applicable for the given
-     * type.
-     */
-    fun apply(inputField: JavaField): FieldRewriteResult {
-        val typeRewriteResult = applyInternal(inputField.owner)
-
-        if (typeRewriteResult.isIgnored) {
-            return FieldRewriteResult.IGNORED
-        }
-        if (typeRewriteResult.result == null) {
-            return FieldRewriteResult.NOT_APPLIED
-        }
-
-        val isFieldInTheFilter = fields.isEmpty()
-                || fields.any { it.matcher(inputField.name).matches() }
-        if (!isFieldInTheFilter) {
-            return FieldRewriteResult.NOT_APPLIED
-        }
-
-        return FieldRewriteResult(inputField.renameOwner(typeRewriteResult.result))
-    }
-
-    private fun applyInternal(input: JavaType): TypeRewriteResult {
         val matcher = inputPattern.matcher(input.fullName)
         if (!matcher.matches()) {
             return TypeRewriteResult.NOT_APPLIED
         }
 
-        if (to == "ignore") {
+        if (isIgnoreRule()) {
             return TypeRewriteResult.IGNORED
         }
 
@@ -95,13 +86,25 @@
         return TypeRewriteResult(JavaType(result))
     }
 
+    /*
+     * Returns whether this rule is an ignore rule and applies to the given proGuard type.
+     */
+    fun doesThisIgnoreProGuard(type: ProGuardType): Boolean {
+        if (!isIgnoreRule()) {
+            return false
+        }
+
+        val matcher = inputPattern.matcher(type.value)
+        return matcher.matches()
+    }
+
     override fun toString(): String {
-        return "$inputPattern -> $outputPattern " + fields.joinToString { it.toString() }
+        return "$inputPattern -> $outputPattern "
     }
 
     /** Returns JSON data model of this class */
     fun toJson(): JsonData {
-        return JsonData(from, to, fieldSelectors)
+        return JsonData(from, to)
     }
 
     /**
@@ -112,14 +115,11 @@
             val from: String,
 
             @SerializedName("to")
-            val to: String,
-
-            @SerializedName("fieldSelectors")
-            val fieldSelectors: List<String>? = null) {
+            val to: String) {
 
         /** Creates instance of [RewriteRule] */
         fun toRule(): RewriteRule {
-            return RewriteRule(from, to, fieldSelectors.orEmpty())
+            return RewriteRule(from, to)
         }
     }
 
@@ -134,16 +134,4 @@
             val IGNORED = TypeRewriteResult(result = null, isIgnored = true)
         }
     }
-
-    /**
-     * Result of java field rewrite using [RewriteRule]
-     */
-    data class FieldRewriteResult(val result: JavaField?, val isIgnored: Boolean = false) {
-
-        companion object {
-            val NOT_APPLIED = FieldRewriteResult(result = null, isIgnored = false)
-
-            val IGNORED = FieldRewriteResult(result = null, isIgnored = true)
-        }
-    }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/PackageMap.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/PackageMap.kt
new file mode 100644
index 0000000..639dfb8
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/PackageMap.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.tools.jetifier.core.transform
+
+import android.support.tools.jetifier.core.rules.PackageName
+
+/**
+ * Package map to be used to rewrite packages. The rewrite rules allow duplicities where the
+ * artifact name prefix defined in a rule determines if such rule should be used or skipped.
+ * The priority is determined only by the order (top to bottom). Having a rule with no file prefix
+ * as first means that it is always applied.
+ *
+ * We use this only for the support library rewriting to rewrite packages in manifest files.
+ */
+class PackageMap(private val rules: List<PackageRule>) {
+
+    companion object {
+        val DEFAULT_RULES = listOf(
+            PackageRule(
+                from = "android/support/exifinterface",
+                to = "android/support/exifinterface"
+            ),
+            PackageRule(
+                from = "android/support/graphics/drawable",
+                to = "androidx/graphics/drawable"
+            ),
+            PackageRule(
+                from = "android/support/graphics/drawable/animated",
+                to = "androidx/graphics/drawable/animated"
+            ),
+            PackageRule(
+                from = "androidx/media/tv",
+                to = "androidx/media/tv"
+            ),
+            PackageRule(
+                from = "androidx/view/textclassifier",
+                to = "androidx/view/textclassifier"
+            ),
+            PackageRule(
+                from = "androidx/widget/recyclerview/selection",
+                to = "androidx/widget/recyclerview/selection"),
+            PackageRule(
+                from = "android/support/v4",
+                to = "android/support/v4"
+            ),
+            PackageRule(
+                from = "android/support/v7/palette",
+                to = "android/support/v7/palette"
+            ),
+            PackageRule(
+                from = "android/support/v7/cardview",
+                to = "android/support/v7/cardview"
+            ),
+            PackageRule(
+                from = "android/support/v7/mediarouter",
+                to = "android/support/v7/mediarouter"
+            ),
+            PackageRule(
+                from = "android/support/v7/appcompat",
+                to = "android/support/v7/appcompat"
+            ),
+            PackageRule(
+                from = "android/support/v7/recyclerview",
+                to = "android/support/v7/recyclerview"
+            ),
+            PackageRule(
+                from = "android/support/v7/gridlayout",
+                to = "android/support/v7/gridlayout"
+            ),
+            PackageRule(
+                from = "android/support/v13",
+                to = "android/support/v13"
+            ),
+            PackageRule(
+                from = "android/support/v7/preference",
+                to = "androidx/preference",
+                filePrefix = "preference-v7"
+            ),
+            PackageRule(
+                from = "android/support/v14/preference",
+                to = "androidx/preference",
+                filePrefix = "preference-v14"
+            ),
+            PackageRule(
+                from = "android/support/v17/lexanback",
+                to = "androidx/leanback"
+            ),
+            PackageRule(
+                from = "android/support/v17/preference",
+                to = "androidx/leanback/preference"
+            ),
+            PackageRule(
+                from = "android/support/compat",
+                to = "android/support/compat"
+            ),
+            PackageRule(
+                from = "android/support/mediacompat",
+                to = "android/support/mediacompat"
+            ),
+            PackageRule(
+                from = "android/support/fragment",
+                to = "android/support/fragment"
+            ),
+            PackageRule(
+                from = "android/support/coreutils",
+                to = "android/support/coreutils"
+            ),
+            PackageRule(
+                from = "android/support/dynamicanimation",
+                to = "android/support/dynamicanimation"
+            ),
+            PackageRule(
+                from = "android/support/customtabs",
+                to = "androidx/browser/customtabs"
+            ),
+            PackageRule(
+                from = "android/support/coreui",
+                to = "android/support/coreui"
+            ),
+            PackageRule(
+                from = "android/support/content",
+                to = "android/support/content"
+            ),
+            PackageRule(
+                from = "android/support/transition",
+                to = "androidx/transition"
+            ),
+            PackageRule(
+                from = "android/support/v17/leanback",
+                to = "androidx/leanback"
+            ),
+            PackageRule(
+                from = "android/support/recommendation",
+                to = "android/support/recommendation"
+            ),
+            PackageRule(
+                from = "android/support/wear",
+                to = "androidx/wear"
+            ),
+            PackageRule(
+                from = "android/support/design",
+                to = "androidx/design"
+            ),
+            PackageRule(
+                from = "androidx/text/emoji",
+                to = "androidx/text/emoji"
+            ),
+            PackageRule(
+                from = "androidx/text/emoji/appcompat",
+                to = "androidx/text/emoji/appcompat"
+            ),
+            PackageRule(
+                from = "androidx/text/emoji/bundled",
+                to = "androidx/text/emoji/bundled"
+            )
+        )
+
+        val EMPTY = PackageMap(emptyList())
+    }
+
+    /**
+     * Creates reversed version of this map (from becomes to and vice versa).
+     */
+    fun reverse(): PackageMap {
+        return PackageMap(rules
+            .map { PackageRule(from = it.to, to = it.from, filePrefix = it.filePrefix) }
+            .toList())
+    }
+
+    /**
+     * Returns a new package name for the given [fromPackage] defined in artifact being called
+     * [libraryName].
+     */
+    fun getPackageFor(fromPackage: PackageName, libraryName: String): PackageName? {
+        val rule = rules.find {
+            it.from == fromPackage.fullName
+                && (it.filePrefix == null
+                || libraryName.startsWith(it.filePrefix, ignoreCase = true))
+        }
+        if (rule != null) {
+            return PackageName(rule.to)
+        }
+        return null
+    }
+
+    data class PackageRule(val from: String, val to: String, val filePrefix: String? = null)
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/TransformationContext.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/TransformationContext.kt
index 3f8af95..08a22a4 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/TransformationContext.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/TransformationContext.kt
@@ -18,13 +18,18 @@
 
 import android.support.tools.jetifier.core.config.Config
 import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.RewriteRule.TypeRewriteResult
 import android.support.tools.jetifier.core.transform.proguard.ProGuardType
 import java.util.regex.Pattern
 
 /**
  * Context to share the transformation state between individual [Transformer]s.
  */
-class TransformationContext(val config: Config) {
+class TransformationContext(
+    val config: Config,
+    val rewritingSupportLib: Boolean = false,
+    val isInReversedMode: Boolean = false
+) {
 
     // Merges all packages prefixes into one regEx pattern
     private val packagePrefixPattern = Pattern.compile(
@@ -38,19 +43,38 @@
     var proGuardMappingNotFoundFailuresCount = 0
         private set
 
-    /** Returns whether any errors were found during the transformation process */
-    fun wasErrorFound() = mappingNotFoundFailuresCount > 0
+    /** Counter for [reportNoPackageMappingFoundFailure] calls. */
+    var packageMappingNotFoundFailuresCounts = 0
+
+    var libraryName: String = ""
+
+    private var runtimeIgnoreRules =
+        (
+            if (rewritingSupportLib) {
+                config.slRules
+            } else {
+                config.rewriteRules
+            }
+        )
+        .filter { it.isRuntimeIgnoreRule() }
+        .toTypedArray()
+
+    /** Total amount of errors found during the transformation process */
+    fun errorsTotal() = mappingNotFoundFailuresCount + proGuardMappingNotFoundFailuresCount +
+        packageMappingNotFoundFailuresCounts
 
     /**
      * Returns whether the given type is eligible for rewrite.
      *
      * If not, the transformers should ignore it.
      */
-    fun isEligibleForRewrite(type: JavaType) : Boolean {
-        if (config.restrictToPackagePrefixes.isEmpty()) {
+    fun isEligibleForRewrite(type: JavaType): Boolean {
+        if (!isEligibleForRewriteInternal(type.fullName)) {
             return false
         }
-        return packagePrefixPattern.matcher(type.fullName).matches()
+
+        val isIgnored = runtimeIgnoreRules.any { it.apply(type) == TypeRewriteResult.IGNORED }
+        return !isIgnored
     }
 
     /**
@@ -60,15 +84,24 @@
      * like *.v7 are not matched by prefix support.v7. So don't rely on it and use
      * the [ProGuardTypesMap] as first.
      */
-    fun isEligibleForRewrite(type: ProGuardType) : Boolean {
+    fun isEligibleForRewrite(type: ProGuardType): Boolean {
+        if (!isEligibleForRewriteInternal(type.value)) {
+            return false
+        }
+
+        val isIgnored = runtimeIgnoreRules.any { it.doesThisIgnoreProGuard(type) }
+        return !isIgnored
+    }
+
+    private fun isEligibleForRewriteInternal(type: String): Boolean {
         if (config.restrictToPackagePrefixes.isEmpty()) {
             return false
         }
-        return packagePrefixPattern.matcher(type.value).matches()
+        return packagePrefixPattern.matcher(type).matches()
     }
 
     /**
-     * Used to report that there was a reference found that satisfies [isEligibleForRewrite] but no
+     * Reports that there was a reference found that satisfies [isEligibleForRewrite] but no
      * mapping was found to rewrite it.
      */
     fun reportNoMappingFoundFailure() {
@@ -76,10 +109,18 @@
     }
 
     /**
-     * Used to report that there was a reference found in the ProGuard file that satisfies
+     * Reports that there was a reference found in a ProGuard file that satisfies
      * [isEligibleForRewrite] but no mapping was found to rewrite it.
      */
     fun reportNoProGuardMappingFoundFailure() {
         proGuardMappingNotFoundFailuresCount++
     }
+
+    /**
+     * Reports that there was a package reference found in a manifest file during a support library
+     * artifact rewrite but no mapping was found for it.
+     */
+    fun reportNoPackageMappingFoundFailure() {
+        packageMappingNotFoundFailuresCounts++
+    }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/Transformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/Transformer.kt
index 0c6c8aa..51335e2 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/Transformer.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/Transformer.kt
@@ -32,5 +32,4 @@
      * Runs transformation of the given file.
      */
     fun runTransform(file: ArchiveFile)
-
-}
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/ByteCodeTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/ByteCodeTransformer.kt
index 33235e0..9024ff1 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/ByteCodeTransformer.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/ByteCodeTransformer.kt
@@ -17,7 +17,6 @@
 package android.support.tools.jetifier.core.transform.bytecode
 
 import android.support.tools.jetifier.core.archive.ArchiveFile
-import android.support.tools.jetifier.core.config.Config
 import android.support.tools.jetifier.core.transform.TransformationContext
 import android.support.tools.jetifier.core.transform.Transformer
 import org.objectweb.asm.ClassReader
@@ -26,10 +25,9 @@
 /**
  * The [Transformer] responsible for java byte code refactoring.
  */
-class ByteCodeTransformer internal constructor(context: TransformationContext) : Transformer {
-
-    private val remapper: CoreRemapperImpl = CoreRemapperImpl(context)
-
+class ByteCodeTransformer internal constructor(
+    private val context: TransformationContext
+) : Transformer {
 
     override fun canTransform(file: ArchiveFile) = file.isClassFile()
 
@@ -37,10 +35,14 @@
         val reader = ClassReader(file.data)
         val writer = ClassWriter(0 /* flags */)
 
-        val visitor = remapper.createClassRemapper(writer)
+        val remapper = CoreRemapperImpl(context, writer)
+        reader.accept(remapper.classRemapper, 0 /* flags */)
 
-        reader.accept(visitor, 0 /* flags */)
+        if (!remapper.changesDone) {
+            return
+        }
 
-        file.data = writer.toByteArray()
+        file.setNewData(writer.toByteArray())
+        file.updateRelativePath(remapper.rewritePath(file.relativePath))
     }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapper.kt
index 38ce393..1b91088 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapper.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapper.kt
@@ -16,7 +16,6 @@
 
 package android.support.tools.jetifier.core.transform.bytecode
 
-import android.support.tools.jetifier.core.rules.JavaField
 import android.support.tools.jetifier.core.rules.JavaType
 
 /**
@@ -25,7 +24,5 @@
 interface CoreRemapper {
     fun rewriteType(type: JavaType): JavaType
 
-    fun rewriteField(field: JavaField): JavaField
-
     fun rewriteString(value: String): String
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt
index 71c4e9e..4603ae0 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/CoreRemapperImpl.kt
@@ -17,18 +17,21 @@
 package android.support.tools.jetifier.core.transform.bytecode
 
 import android.support.tools.jetifier.core.map.TypesMap
-import android.support.tools.jetifier.core.rules.JavaField
 import android.support.tools.jetifier.core.rules.JavaType
 import android.support.tools.jetifier.core.transform.TransformationContext
-import android.support.tools.jetifier.core.transform.bytecode.asm.CustomClassRemapper
 import android.support.tools.jetifier.core.transform.bytecode.asm.CustomRemapper
 import android.support.tools.jetifier.core.utils.Log
 import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.commons.ClassRemapper
+import java.nio.file.Path
 
 /**
  * Applies mappings defined in [TypesMap] during the remapping process.
  */
-class CoreRemapperImpl(private val context: TransformationContext) : CoreRemapper {
+class CoreRemapperImpl(
+    private val context: TransformationContext,
+    visitor: ClassVisitor
+) : CoreRemapper {
 
     companion object {
         const val TAG = "CoreRemapperImpl"
@@ -36,9 +39,10 @@
 
     private val typesMap = context.config.typesMap
 
-    fun createClassRemapper(visitor: ClassVisitor): CustomClassRemapper {
-        return CustomClassRemapper(visitor, CustomRemapper(this))
-    }
+    var changesDone = false
+        private set
+
+    val classRemapper = ClassRemapper(visitor, CustomRemapper(this))
 
     override fun rewriteType(type: JavaType): JavaType {
         if (!context.isEligibleForRewrite(type)) {
@@ -47,6 +51,7 @@
 
         val result = typesMap.types[type]
         if (result != null) {
+            changesDone = changesDone || result != type
             Log.i(TAG, "  map: %s -> %s", type, result)
             return result
         }
@@ -56,22 +61,6 @@
         return type
     }
 
-    override fun rewriteField(field: JavaField): JavaField {
-        if (!context.isEligibleForRewrite(field.owner)) {
-            return field
-        }
-
-        val result = typesMap.fields[field]
-        if (result != null) {
-            Log.i(TAG, "  map: %s -> %s", field, result)
-            return result
-        }
-
-        context.reportNoMappingFoundFailure()
-        Log.e(TAG, "No mapping for: " + field)
-        return field
-    }
-
     override fun rewriteString(value: String): String {
         val type = JavaType.fromDotVersion(value)
         if (!context.isEligibleForRewrite(type)) {
@@ -80,6 +69,7 @@
 
         val result = typesMap.types[type]
         if (result != null) {
+            changesDone = changesDone || result != type
             Log.i(TAG, "  map string: %s -> %s", type, result)
             return result.toDotNotation()
         }
@@ -87,5 +77,26 @@
         // We do not treat string content mismatches as errors
         return value
     }
-}
 
+    fun rewritePath(path: Path): Path {
+        if (!context.rewritingSupportLib) {
+            return path
+        }
+
+        val owner = path.toFile().path.replace('\\', '/').removeSuffix(".class")
+        val type = JavaType(owner)
+        if (!context.isEligibleForRewrite(type)) {
+            return path
+        }
+
+        val result = rewriteType(type)
+        if (result != type) {
+            changesDone = true
+            return path.fileSystem.getPath(result.fullName + ".class")
+        }
+
+        context.reportNoMappingFoundFailure()
+        Log.e(TAG, "No mapping for: " + type)
+        return path
+    }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomClassRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomClassRemapper.kt
deleted file mode 100644
index 692e65d..0000000
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomClassRemapper.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.support.tools.jetifier.core.transform.bytecode.asm
-
-import org.objectweb.asm.ClassVisitor
-import org.objectweb.asm.FieldVisitor
-import org.objectweb.asm.MethodVisitor
-import org.objectweb.asm.Opcodes
-import org.objectweb.asm.commons.ClassRemapper
-
-/**
- * Currently only adds field context awareness into [ClassRemapper] and substitutes the default
- * method remapper with [CustomMethodRemapper]
- */
-class CustomClassRemapper(cv: ClassVisitor, private val customRemapper: CustomRemapper)
-    : ClassRemapper(Opcodes.ASM5, cv, customRemapper) {
-
-    override fun visitField(access: Int,
-                            name: String,
-                            desc: String?,
-                            signature: String?,
-                            value: Any?) : FieldVisitor? {
-        cv ?: return null
-
-        val field = customRemapper.mapField(className, name)
-        val fieldVisitor = cv.visitField(
-                access,
-                field.name,
-                remapper.mapDesc(desc),
-                remapper.mapSignature(signature, true),
-                remapper.mapValue(value))
-
-        fieldVisitor ?: return null
-
-        return createFieldRemapper(fieldVisitor)
-    }
-
-    override fun createMethodRemapper(mv: MethodVisitor) : MethodVisitor {
-        return CustomMethodRemapper(mv, customRemapper)
-    }
-}
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomMethodRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomMethodRemapper.kt
deleted file mode 100644
index cc60cbf..0000000
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomMethodRemapper.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.support.tools.jetifier.core.transform.bytecode.asm
-
-import org.objectweb.asm.MethodVisitor
-import org.objectweb.asm.Opcodes
-import org.objectweb.asm.commons.MethodRemapper
-
-/**
- * Currently only adds field context awareness into [MethodRemapper]
- */
-internal class CustomMethodRemapper(mv:MethodVisitor,
-                                    private val customRemapper: CustomRemapper)
-    : MethodRemapper(Opcodes.ASM5, mv, customRemapper) {
-
-    override fun visitFieldInsn(opcode: Int, owner: String, name: String, desc: String?) {
-        mv ?: return
-
-        val field = customRemapper.mapField(owner, name)
-        mv.visitFieldInsn(opcode, field.owner.fullName, field.name, remapper.mapDesc(desc))
-    }
-}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomRemapper.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomRemapper.kt
index aba4725..a54e8bd 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomRemapper.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/bytecode/asm/CustomRemapper.kt
@@ -16,13 +16,12 @@
 
 package android.support.tools.jetifier.core.transform.bytecode.asm
 
-import android.support.tools.jetifier.core.rules.JavaField
 import android.support.tools.jetifier.core.rules.JavaType
 import android.support.tools.jetifier.core.transform.bytecode.CoreRemapper
 import org.objectweb.asm.commons.Remapper
 
 /**
- * Extends [Remapper] with a capability to rewrite field names together with their owner.
+ * Extends [Remapper] to allow further customizations.
  */
 class CustomRemapper(private val remapper: CoreRemapper) : Remapper() {
 
@@ -38,12 +37,4 @@
 
         return remapper.rewriteString(stringMaybe)
     }
-
-    fun mapField(ownerName: String, fieldName: String): JavaField {
-        return remapper.rewriteField(JavaField(ownerName, fieldName))
-    }
-
-    override fun mapFieldName(owner: String?, name: String, desc: String?): String {
-        throw RuntimeException("This should not be called")
-    }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/metainf/MetaInfTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/metainf/MetaInfTransformer.kt
new file mode 100644
index 0000000..333d776
--- /dev/null
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/metainf/MetaInfTransformer.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.tools.jetifier.core.transform.metainf
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.Transformer
+import java.nio.charset.StandardCharsets
+
+/**
+ * Transformer for META-INF/(.*).version files.
+ *
+ * Replaces version files from the META-INF directory. This should be used only for processing
+ * of the support library itself.
+ */
+class MetaInfTransformer internal constructor(
+    private val context: TransformationContext
+) : Transformer {
+
+    companion object {
+        const val FROM_VERSION = "28.0.0-SNAPSHOT"
+
+        const val TO_VERSION = "1.0.0-SNAPSHOT"
+
+        const val META_INF_DIR = "meta-inf"
+
+        const val VERSION_FILE_SUFFIX = ".version"
+    }
+
+    override fun canTransform(file: ArchiveFile): Boolean {
+        return context.rewritingSupportLib
+            && file.relativePath.toString().contains(META_INF_DIR, ignoreCase = true)
+            && file.fileName.endsWith(VERSION_FILE_SUFFIX, ignoreCase = true)
+    }
+
+    override fun runTransform(file: ArchiveFile) {
+        val sb = StringBuilder(file.data.toString(StandardCharsets.UTF_8))
+
+        var from = FROM_VERSION
+        var to = TO_VERSION
+        if (context.isInReversedMode) {
+            from = TO_VERSION
+            to = FROM_VERSION
+        }
+
+        if (sb.toString() != from) {
+            return
+        }
+
+        file.setNewData(to.toByteArray())
+    }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocument.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocument.kt
index d5bdc3a..7dcd826 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocument.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/pom/PomDocument.kt
@@ -29,7 +29,7 @@
     companion object {
         private const val TAG = "Pom"
 
-        fun loadFrom(file: ArchiveFile) : PomDocument {
+        fun loadFrom(file: ArchiveFile): PomDocument {
             val document = XmlUtils.createDocumentFromByteArray(file.data)
             val pomDoc = PomDocument(file, document)
             pomDoc.initialize()
@@ -37,10 +37,10 @@
         }
     }
 
-    val dependencies : MutableSet<PomDependency> = mutableSetOf()
-    private val properties : MutableMap<String, String> = mutableMapOf()
-    private var dependenciesGroup : Element? = null
-    private var hasChanged : Boolean = false
+    val dependencies: MutableSet<PomDependency> = mutableSetOf()
+    private val properties: MutableMap<String, String> = mutableMapOf()
+    private var dependenciesGroup: Element? = null
+    private var hasChanged: Boolean = false
 
     private fun initialize() {
         val propertiesGroup = document.rootElement
@@ -64,7 +64,7 @@
      * Currently it checks that all the dependencies that are going to be rewritten by the given
      * rules satisfy the minimal version requirements defined by the rules.
      */
-    fun validate(rules: List<PomRewriteRule>) : Boolean {
+    fun validate(rules: List<PomRewriteRule>): Boolean {
         if (dependenciesGroup == null) {
             // Nothing to validate as this file has no dependencies section
             return true
@@ -96,7 +96,7 @@
                 newDependencies.add(dependency)
             } else {
                 // Replace with new dependencies
-                newDependencies.addAll(rule.to.mapTo(newDependencies){ it.rewrite(dependency) })
+                newDependencies.addAll(rule.to.mapTo(newDependencies) { it.rewrite(dependency) })
             }
         }
 
@@ -118,7 +118,7 @@
             return
         }
 
-        file.data =  XmlUtils.convertDocumentToByteArray(document)
+        file.setNewData(XmlUtils.convertDocumentToByteArray(document))
     }
 
     /**
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTransformer.kt
index 423bf05..b7536c7 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTransformer.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTransformer.kt
@@ -39,9 +39,14 @@
     }
 
     override fun runTransform(file: ArchiveFile) {
-        val sb = StringBuilder(file.data.toString(StandardCharsets.UTF_8))
-        val result = replacer.applyReplacers(sb.toString())
-        file.data = result.toByteArray()
+        val content = StringBuilder(file.data.toString(StandardCharsets.UTF_8)).toString()
+        val result = replacer.applyReplacers(content)
+
+        if (result == content) {
+            return
+        }
+
+        file.setNewData(result.toByteArray())
     }
 }
 
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMap.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMap.kt
index 03d6282..f232a35 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMap.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMap.kt
@@ -16,28 +16,56 @@
 
 package android.support.tools.jetifier.core.transform.proguard
 
+import android.support.tools.jetifier.core.utils.Log
+
 /**
  * Contains custom mappings to map support library types referenced in ProGuard to new ones.
  */
 data class ProGuardTypesMap(val rules: Map<ProGuardType, ProGuardType>) {
 
     companion object {
+        const val TAG = "ProGuardTypesMap"
+
         val EMPTY = ProGuardTypesMap(emptyMap())
     }
 
     /** Returns JSON data model of this class */
-    fun toJson() : JsonData {
+    fun toJson(): JsonData {
         return JsonData(rules.map { it.key.value to it.value.value }.toMap())
     }
 
     /**
      * JSON data model for [ProGuardTypesMap].
      */
-    data class JsonData(val rules: Map<String, String>)  {
+    data class JsonData(val rules: Map<String, String>) {
 
         /** Creates instance of [ProGuardTypesMap] */
-        fun toMappings() : ProGuardTypesMap {
-            return ProGuardTypesMap(rules.map { ProGuardType(it.key) to ProGuardType(it.value) }.toMap())
+        fun toMappings(): ProGuardTypesMap {
+            return ProGuardTypesMap(
+                rules.map { ProGuardType(it.key) to ProGuardType(it.value) }.toMap())
         }
     }
+
+    /**
+     * Creates reversed version of this map (values become keys). Throws exception if the map does
+     * not satisfy that.
+     */
+    fun reverseMapOrDie(): ProGuardTypesMap {
+        val reversed = mutableMapOf<ProGuardType, ProGuardType>()
+        for ((from, to) in rules) {
+            val conflictFrom = reversed[to]
+            if (conflictFrom != null) {
+                Log.e(TAG, "Conflict: %s -> (%s, %s)", to, from, conflictFrom)
+                continue
+            }
+            reversed[to] = from
+        }
+
+        if (rules.size != reversed.size || rules.size != reversed.size) {
+            throw IllegalArgumentException("Types map is not reversible as conflicts were found! " +
+                "See the log for more details.")
+        }
+
+        return ProGuardTypesMap(reversed)
+    }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/ReplacersRunner.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/ReplacersRunner.kt
index 54501f9..bd2fc12 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/ReplacersRunner.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/proguard/patterns/ReplacersRunner.kt
@@ -27,7 +27,7 @@
      * The replacers have to be distinct as this method can't guarantee that output of one replacer
      * won't be matched by another replacer.
      */
-    fun applyReplacers(input : String) : String {
+    fun applyReplacers(input: String): String {
         val sb = StringBuilder()
         var lastSeenChar = 0
         var processedInput = input
@@ -37,7 +37,7 @@
 
             while (matcher.find()) {
                 if (lastSeenChar < matcher.start()) {
-                    sb.append(input, lastSeenChar, matcher.start())
+                    sb.append(processedInput, lastSeenChar, matcher.start())
                 }
 
                 val result = replacer.runReplacements(matcher)
@@ -57,8 +57,6 @@
             processedInput = sb.toString()
             sb.setLength(0)
         }
-
         return processedInput
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt
index 0a29828..18c8994 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformer.kt
@@ -18,7 +18,8 @@
 
 import android.support.tools.jetifier.core.archive.ArchiveFile
 import android.support.tools.jetifier.core.map.TypesMap
-import android.support.tools.jetifier.core.rules.JavaTypeXmlRef
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.PackageName
 import android.support.tools.jetifier.core.transform.TransformationContext
 import android.support.tools.jetifier.core.transform.Transformer
 import android.support.tools.jetifier.core.utils.Log
@@ -40,10 +41,13 @@
         const val TAG = "XmlResourcesTransformer"
 
         const val PATTERN_TYPE_GROUP = 1
+
+        const val MANIFEST_FILE_NAME = "AndroidManifest.xml"
     }
 
     /**
-     * List of regular expression patterns used to find support library references in XML files.
+     * List of regular expression patterns used to find support library types references in XML
+     * files.
      *
      * Matches xml tags in form of:
      * 1. '<(/)prefix(SOMETHING)'.
@@ -57,42 +61,39 @@
         Pattern.compile("<view[^>]*class=\"([a-zA-Z0-9.\$_]+)\"[^>]*>")
     )
 
+    /**
+     * List of regular expression patterns used to find support library package references in
+     * manifest files.
+     *
+     * Matches xml tag in form of:
+     * 1. <manifest package="package.name" ...>
+     */
+    private val packagePatterns = listOf(
+        Pattern.compile("<manifest[^>]*package=\"([a-zA-Z0-9._]+)\"[^>]*>")
+    )
+
     private val typesMap = context.config.typesMap
 
     override fun canTransform(file: ArchiveFile) = file.isXmlFile() && !file.isPomFile()
 
     override fun runTransform(file: ArchiveFile) {
-        file.data = transform(file.data)
-    }
+        val isManifestFile = file.fileName.equals(MANIFEST_FILE_NAME, ignoreCase = true)
+        val charset = getCharset(file.data)
+        val sb = StringBuilder(file.data.toString(charset))
 
-    fun transform(data: ByteArray) : ByteArray {
-        var changesDone = false
+        var changesDone = replaceWithPatterns(sb, patterns, { rewriteType(it) })
 
-        val charset = getCharset(data)
-        val sb = StringBuilder(data.toString(charset))
-        for (pattern in patterns) {
-            var matcher = pattern.matcher(sb)
-            while (matcher.find()) {
-                val typeToReplace = JavaTypeXmlRef(matcher.group(PATTERN_TYPE_GROUP))
-                val result = rewriteType(typeToReplace)
-                if (result == typeToReplace) {
-                    continue
-                }
-                sb.replace(matcher.start(PATTERN_TYPE_GROUP), matcher.end(PATTERN_TYPE_GROUP),
-                    result.fullName)
-                changesDone = true
-                matcher = pattern.matcher(sb)
-            }
+        if (isManifestFile && context.rewritingSupportLib) {
+            changesDone = replaceWithPatterns(sb, packagePatterns,
+                { rewritePackage(it, context.libraryName) }) || changesDone
         }
 
         if (changesDone) {
-            return sb.toString().toByteArray(charset)
+            file.setNewData(sb.toString().toByteArray(charset))
         }
-
-        return data
     }
 
-    fun getCharset(data: ByteArray) : Charset {
+    fun getCharset(data: ByteArray): Charset {
         data.inputStream().use {
             val xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(it)
 
@@ -107,20 +108,78 @@
         }
     }
 
-    fun rewriteType(type: JavaTypeXmlRef): JavaTypeXmlRef {
-        val javaType = type.toJavaType()
-        if (!context.isEligibleForRewrite(javaType)) {
-            return type
+    /**
+     * For each pattern in [patterns] matching a portion of the string represented by [sb], applies
+     * [mappingFunction] to the match and puts the result back into [sb].
+     */
+    private fun replaceWithPatterns(
+        sb: StringBuilder,
+        patterns: List<Pattern>,
+        mappingFunction: (String) -> String
+    ): Boolean {
+        var changesDone = false
+
+        for (pattern in patterns) {
+            var lastSeenChar = 0
+            val processedInput = sb.toString()
+            sb.setLength(0)
+            val matcher = pattern.matcher(processedInput)
+
+            while (matcher.find()) {
+                if (lastSeenChar < matcher.start()) {
+                    sb.append(processedInput, lastSeenChar, matcher.start())
+                }
+
+                val toReplace = matcher.group(PATTERN_TYPE_GROUP)
+                val matched = matcher.group(0)
+                val replacement = mappingFunction(toReplace)
+                changesDone = changesDone || replacement != toReplace
+
+                val localStart = matcher.start(PATTERN_TYPE_GROUP) - matcher.start()
+                val localEnd = matcher.end(PATTERN_TYPE_GROUP) - matcher.start()
+
+                val result = matched.replaceRange(
+                    startIndex = localStart,
+                    endIndex = localEnd,
+                    replacement = replacement)
+
+                sb.append(result)
+                lastSeenChar = matcher.end()
+            }
+
+            if (lastSeenChar <= processedInput.length - 1) {
+                sb.append(processedInput, lastSeenChar, processedInput.length)
+            }
         }
 
-        val result = typesMap.types[javaType]
+        return changesDone
+    }
+
+    private fun rewriteType(typeName: String): String {
+        val type = JavaType.fromDotVersion(typeName)
+        if (!context.isEligibleForRewrite(type)) {
+            return typeName
+        }
+
+        val result = typesMap.types[type]
         if (result != null) {
             Log.i(TAG, "  map: %s -> %s", type, result)
-            return JavaTypeXmlRef(result)
+            return result.toDotNotation()
         }
 
         context.reportNoMappingFoundFailure()
         Log.e(TAG, "No mapping for: " + type)
-        return type
+        return typeName
+    }
+
+    private fun rewritePackage(packageName: String, archiveName: String): String {
+        val pckg = PackageName.fromDotVersion(packageName)
+        val result = context.config.packageMap.getPackageFor(pckg, archiveName)
+        if (result != null) {
+            return result.toDotNotation()
+        }
+        context.reportNoPackageMappingFoundFailure()
+        Log.e(TAG, "No mapping for package: '$pckg' in artifact: '$archiveName'")
+        return packageName
     }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/Log.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/Log.kt
index 902dea4..b1bb0af 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/Log.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/utils/Log.kt
@@ -18,17 +18,17 @@
 
 object Log {
 
-    var currentLevel : LogLevel = LogLevel.INFO
+    var currentLevel: LogLevel = LogLevel.INFO
 
-    var logConsumer : LogConsumer = StdOutLogConsumer()
+    var logConsumer: LogConsumer = StdOutLogConsumer()
 
     fun setLevel(level: String?) {
         currentLevel = when (level) {
+            "error" -> LogLevel.ERROR
             "debug" -> LogLevel.DEBUG
             "verbose" -> LogLevel.VERBOSE
             else -> LogLevel.INFO
         }
-
     }
 
     fun e(tag: String, message: String, vararg args: Any?) {
@@ -54,5 +54,4 @@
             logConsumer.verbose("[$tag] $message".format(*args))
         }
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/main/resources/default.config b/jetifier/jetifier/core/src/main/resources/default.config
index a64d7eb..54d561c 100644
--- a/jetifier/jetifier/core/src/main/resources/default.config
+++ b/jetifier/jetifier/core/src/main/resources/default.config
@@ -15,93 +15,206 @@
 {
     # Skip packages that don't match the following regex
     restrictToPackagePrefixes: [
-        "android/support/"
+        "android/support/",
+        "android/arch"
     ],
     rules: [
         # Ignore
         {
             from: "(.*)BuildConfig",
-            to: "ignore"
-        },
-        {
-            from: "android/support/v7/preference/R(.*)",
-            to: "ignore"
+            to: "ignoreInPreprocessorOnly"
         },
         {
             from: "(.*)/package-info",
+            to: "ignoreInPreprocessorOnly"
+        },
+        {
+            from: "android/support/test/(.*)",
             to: "ignore"
         },
 
         # Legacy
         {
-            from: "android/support/v13/app/FragmentTabHost(.*)",
-            to: "androidx/app/legacy/FragmentTabHost{0}"
+            from: "android/support/v4/app/ActionBarDrawerToggle(.*)",
+            to: "androidx/legacy/app/ActionBarDrawerToggle{0}"
+        },
+        {
+            from: "android/support/v13/view/ViewCompat(.*)",
+            to: "androidx/legacy/view/ViewCompat{0}"
+        },
+        {
+            from: "android/support/v13/app/ActivityCompat(.*)",
+            to: "androidx/legacy/app/ActivityCompat{0}"
+        },
+        {
+            from: "android/support/v13/app/FragmentCompat(.*)",
+            to: "androidx/legacy/app/FragmentCompat{0}"
         },
         {
             from: "android/support/v13/app/FragmentPagerAdapter(.*)",
-            to: "androidx/app/legacy/FragmentPagerAdapter{0}"
+            to: "androidx/legacy/app/FragmentPagerAdapter{0}"
         },
         {
             from: "android/support/v13/app/FragmentStatePagerAdapter(.*)",
-            to: "androidx/app/legacy/FragmentStatePagerAdapter{0}"
+            to: "androidx/legacy/app/FragmentStatePagerAdapter{0}"
         },
         {
-            from: "android/support/v4/app/ActionBarDrawerToggle(.*)",
-            to: "androidx/app/legacy/ActionBarDrawerToggle{0}"
-        },
-        {
-            from: "android/support/v4/app/ActivityCompat(.*)",
-            to: "androidx/app/legacy/ActivityCompat{0}"
-        },
-        {
-            from: "android/support/v4/view/ViewCompat(.*)",
-            to: "androidx/view/legacy/ViewCompat{0}"
+            from: "android/support/v13/app/FragmentTabHost(.*)",
+            to: "androidx/legacy/app/FragmentTabHost{0}"
         },
 
-        # Internal
+        # Re-map Recycler view
         {
-            from: "android/support/v4/graphics/drawable/DrawableWrapper",
-            to: "androidx/graphics/drawable/internal/DrawableWrapper"
+            from: "android/support/v7/widget/AdapterHelper(.*)",
+            to: "androidx/widget/recyclerview/AdapterHelper{0}"
         },
         {
-            from: "android/support/v7/widget/ListViewCompat(.*)",
-            to: "androidx/widget/internal/ListViewCompat{0}"
+            from: "android/support/v7/widget/ChildHelper(.*)",
+            to: "androidx/widget/recyclerview/ChildHelper{0}"
+        },
+        {
+            from: "android/support/v7/widget/DefaultItemAnimator(.*)",
+            to: "androidx/widget/recyclerview/DefaultItemAnimator{0}"
+        },
+        {
+            from: "android/support/v7/widget/DividerItemDecoration(.*)",
+            to: "androidx/widget/recyclerview/DividerItemDecoration{0}"
+        },
+        {
+            from: "android/support/v7/widget/FastScroller(.*)",
+            to: "androidx/widget/recyclerview/FastScroller{0}"
+        },
+        {
+            from: "android/support/v7/widget/GapWorker(.*)",
+            to: "androidx/widget/recyclerview/GapWorker{0}"
+        },
+        {
+            from: "android/support/v7/widget/GridLayoutManager(.*)",
+            to: "androidx/widget/recyclerview/GridLayoutManager{0}"
+        },
+        {
+            from: "android/support/v7/widget/LayoutState(.*)",
+            to: "androidx/widget/recyclerview/LayoutState{0}"
+        },
+        {
+            from: "android/support/v7/widget/LinearLayoutManager(.*)",
+            to: "androidx/widget/recyclerview/LinearLayoutManager{0}"
+        },
+        {
+            from: "android/support/v7/widget/LinearSmoothScroller(.*)",
+            to: "androidx/widget/recyclerview/LinearSmoothScroller{0}"
+        },
+        {
+            from: "android/support/v7/widget/LinearSnapHelper(.*)",
+            to: "androidx/widget/recyclerview/LinearSnapHelper{0}"
+        },
+        {
+            from: "android/support/v7/widget/OpReorderer(.*)",
+            to: "androidx/widget/recyclerview/OpReorderer{0}"
+        },
+        {
+            from: "android/support/v7/widget/OrientationHelper(.*)",
+            to: "androidx/widget/recyclerview/OrientationHelper{0}"
+        },
+        {
+            from: "android/support/v7/widget/PagerSnapHelper(.*)",
+            to: "androidx/widget/recyclerview/PagerSnapHelper{0}"
+        },
+        {
+            from: "android/support/v7/widget/PositionMap(.*)",
+            to: "androidx/widget/recyclerview/PositionMap{0}"
+        },
+        {
+            from: "android/support/v7/widget/RecyclerViewAccessibilityDelegate(.*)",
+            to: "androidx/widget/recyclerview/RecyclerViewAccessibilityDelegate{0}"
+        },
+        {
+            from: "android/support/v7/widget/RecyclerView(.*)",
+            to: "androidx/widget/recyclerview/RecyclerView{0}"
+        },
+        {
+            from: "android/support/v7/widget/ScrollbarHelper(.*)",
+            to: "androidx/widget/recyclerview/ScrollbarHelper{0}"
+        },
+        {
+            from: "android/support/v7/widget/SimpleItemAnimator(.*)",
+            to: "androidx/widget/recyclerview/SimpleItemAnimator{0}"
+        },
+        {
+            from: "android/support/v7/widget/SnapHelper(.*)",
+            to: "androidx/widget/recyclerview/SnapHelper{0}"
+        },
+        {
+            from: "android/support/v7/widget/StaggeredGridLayoutManager(.*)",
+            to: "androidx/widget/recyclerview/StaggeredGridLayoutManager{0}"
+        },
+        {
+            from: "android/support/v7/widget/ViewBoundsCheck(.*)",
+            to: "androidx/widget/recyclerview/ViewBoundsCheck{0}"
+        },
+        {
+            from: "android/support/v7/widget/ViewInfoStore(.*)",
+            to: "androidx/widget/recyclerview/ViewInfoStore{0}"
+        },
+        {
+            from: "android/support/v7/widget/helper/(.*)",
+            to: "androidx/widget/recyclerview/{0}"
+        },
+        {
+            from: "android/support/v7/widget/util/SortedListAdapterCallback",
+            to: "androidx/widget/recyclerview/SortedListAdapterCallback"
+        },
+        {
+            from: "android/support/v7/recyclerview/extensions/(.*)",
+            to: "androidx/widget/recyclerview/{0}"
+        },
+        {
+            from: "android/support/v7/util/(.*)",
+            to: "androidx/widget/recyclerview/{0}"
         },
 
         # Re-map
         {
-            from: "android/support/design/widget/CoordinatorLayout",
-            to: "androidx/widget/CoordinatorLayout"
+            from: "android/support/design/widget/CoordinatorLayout(.*)",
+            to: "androidx/widget/CoordinatorLayout{0}"
         },
         {
-            from: "android/support/design/widget/DirectedAcyclicGraph",
-            to: "androidx/widget/DirectedAcyclicGraph"
+            from: "android/support/design/widget/DirectedAcyclicGraph(.*)",
+            to: "androidx/widget/DirectedAcyclicGraph{0}"
         },
         {
-            from: "android/support/design/widget/ViewGroupUtils",
-            to: "androidx/widget/ViewGroupUtils"
+            from: "android/support/design/widget/ViewGroupUtils(.*)",
+            to: "androidx/widget/ViewGroupUtils{0}"
         },
         {
-            from: "android/support/v4/view/ViewPager",
-            to: "androidx/widget/ViewPager"
+            from: "android/support/constraint/(.*)",
+            to: "androidx/widget/constraint/{0}"
         },
         {
-            from: "android/support/v4/view/PagerAdapter",
-            to: "androidx/widget/PagerAdapter"
+            from: "android/support/v4/view/ViewPager(.*)",
+            to: "androidx/widget/ViewPager{0}"
         },
         {
-            from: "android/support/v4/view/PagerTabStrip",
-            to: "androidx/widget/PagerTabStrip"
+            from: "android/support/v4/view/PagerAdapter(.*)",
+            to: "androidx/widget/PagerAdapter{0}"
         },
         {
-            from: "android/support/v4/view/PagerTitleStrip",
-            to: "androidx/widget/PagerTitleStrip"
+            from: "android/support/v4/view/PagerTabStrip(.*)",
+            to: "androidx/widget/PagerTabStrip{0}"
+        },
+        {
+            from: "android/support/v4/view/PagerTitleStrip(.*)",
+            to: "androidx/widget/PagerTitleStrip{0}"
         },
         {
             from: "android/support/v17/preference/(.*)",
             to: "androidx/leanback/preference/{0}"
         },
         {
+            from: "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout(.*)",
+            to: "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout{0}"
+        },
+        {
             from: "android/support/customtabs/(.*)",
             to: "androidx/browser/customtabs/{0}"
         },
@@ -110,22 +223,30 @@
             to: "androidx/{0}"
         },
         {
-            from: "android/support/v7/graphics/ColorCutQuantizer",
-            to: "androidx/graphics/palette/ColorCutQuantizer"
+            from: "android/support/v7/graphics/ColorCutQuantizer(.*)",
+            to: "androidx/graphics/palette/ColorCutQuantizer{0}"
         },
         {
-            from: "android/support/v7/graphics/Palette",
-            to: "androidx/graphics/palette/Palette"
+            from: "android/support/v7/graphics/Palette(.*)",
+            to: "androidx/graphics/palette/Palette{0}"
         },
         {
-            from: "android/support/v7/graphics/Target",
-            to: "androidx/graphics/palette/Target"
+            from: "android/support/v7/graphics/Target(.*)",
+            to: "androidx/graphics/palette/Target{0}"
+        },
+        {
+            from: "android/support/v7/internal/widget/PreferenceImageView(.*)",
+            to: "androidx/preference/internal/PreferenceImageView{0}"
         },
         {
             from: "android/support/v7/(.*)",
             to: "androidx/{0}"
         },
         {
+            from: "android/support/v8/(.*)",
+            to: "androidx/{0}"
+        },
+        {
             from: "android/support/v13/(.*)",
             to: "androidx/{0}"
         },
@@ -138,8 +259,12 @@
             to: "androidx/{0}"
         },
         {
+            from: "android/support/content/(.*)",
+            to: "androidx/util/contentpaging/{0}"
+        },
+        {
             from: "android/support/percent/(.*)",
-            to: "androidx/{0}"
+            to: "androidx/widget/{0}"
         },
         {
             from: "android/support/(.*)",
@@ -148,6 +273,33 @@
         {
             from: "android/arch/(.*)",
             to: "androidx/{0}"
+        },
+        {
+            from: "android/databinding/(.*)",
+            to: "androidx/databinding/{0}"
+        }
+    ],
+    slRules: [
+        # Ignore
+        {
+            from: "(.*)/package-info",
+            to: "ignore"
+        },
+        {
+            from: "androidx/text/emoji/flatbuffer/(.*)",
+            to: "ignore"
+        },
+        {
+            from: "androidx/textclassifier/(.*)",
+            to: "ignore"
+        },
+        {
+            from: "androidx/widget/recyclerview/selection/(.*)",
+            to: "ignore"
+        },
+        {
+            from: "androidx/browser/browseractions/(.*)",
+            to: "ignore"
         }
     ],
     pomRules: [
@@ -286,6 +438,10 @@
             from: { groupId: "com.android.support", artifactId: "support-vector-drawable", version: "27.0.1" },
             to: [{ groupId: "com.androidx", artifactId: "vector-drawable", version: "28.0.0" }]
         },
+	{
+	    from: { groupId: "com.android.support", artifactId: "textclassifier", version: "28.0.0" },
+	    to: [{ groupId: "com.androidx.view.textclassifier", artifactId: "textclassifier", version: "28.0.0" }]
+	},
         {
             from: { groupId: "com.android.support", artifactId: "transition", version: "27.0.1" },
             to: [{ groupId: "com.androidx", artifactId: "transition", version: "28.0.0" }]
@@ -298,5 +454,20 @@
             from: { groupId: "com.android.support", artifactId: "wearable", version: "26.0.0-alpha1" },
             to: [{ groupId: "com.androidx", artifactId: "wearable", version: "28.0.0" }]
         }
-    ]
-}
\ No newline at end of file
+    ],
+    map: {
+        # Types added in 28.0.0 (missing in 27.1.0)
+        types: {
+            "android/support/v4/app/NotificationCompat$Action$SemanticAction": "androidx/app/NotificationCompat$Action$SemanticAction",
+            "android/support/v4/graphics/TypefaceCompatApi28Impl": "androidx/graphics/TypefaceCompatApi28Impl",
+            "android/support/v7/util/AdapterListUpdateCallback": "androidx/widget/recyclerview/AdapterListUpdateCallback",
+            "android/support/v7/recyclerview/extensions/ListAdapterConfig$Builder$MainThreadExecutor": "androidx/widget/recyclerview/ListAdapterConfig$Builder$MainThreadExecutor"
+        }
+    },
+    proGuardMap: {
+        rules: {
+            "android/support/transition/ChangeBounds$*": "androidx/transition/ChangeBounds$*",
+            "android/support/graphics/drawable/VectorDrawableCompat$*": "androidx/graphics/drawable/VectorDrawableCompat$*"
+        }
+    }
+}
diff --git a/jetifier/jetifier/core/src/main/resources/default.generated.config b/jetifier/jetifier/core/src/main/resources/default.generated.config
index d74d4c7..6e447a5 100644
--- a/jetifier/jetifier/core/src/main/resources/default.generated.config
+++ b/jetifier/jetifier/core/src/main/resources/default.generated.config
@@ -1,4 +1,4 @@
-# Copyright (C) 2017 The Android Open Source Project
+# Copyright (C) 2018 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -18,163 +18,283 @@
 
 {
   "restrictToPackagePrefixes": [
-    "android/support/"
+    "android/support/",
+    "android/arch"
   ],
   "rules": [
     {
       "from": "(.*)BuildConfig",
-      "to": "ignore",
-      "fieldSelectors": []
-    },
-    {
-      "from": "android/support/v7/preference/R(.*)",
-      "to": "ignore",
-      "fieldSelectors": []
+      "to": "ignoreInPreprocessorOnly"
     },
     {
       "from": "(.*)/package-info",
-      "to": "ignore",
-      "fieldSelectors": []
+      "to": "ignoreInPreprocessorOnly"
     },
     {
-      "from": "android/support/v13/app/FragmentTabHost(.*)",
-      "to": "androidx/app/legacy/FragmentTabHost{0}",
-      "fieldSelectors": []
-    },
-    {
-      "from": "android/support/v13/app/FragmentPagerAdapter(.*)",
-      "to": "androidx/app/legacy/FragmentPagerAdapter{0}",
-      "fieldSelectors": []
-    },
-    {
-      "from": "android/support/v13/app/FragmentStatePagerAdapter(.*)",
-      "to": "androidx/app/legacy/FragmentStatePagerAdapter{0}",
-      "fieldSelectors": []
+      "from": "android/support/test/(.*)",
+      "to": "ignore"
     },
     {
       "from": "android/support/v4/app/ActionBarDrawerToggle(.*)",
-      "to": "androidx/app/legacy/ActionBarDrawerToggle{0}",
-      "fieldSelectors": []
+      "to": "androidx/legacy/app/ActionBarDrawerToggle{0}"
     },
     {
-      "from": "android/support/v4/app/ActivityCompat(.*)",
-      "to": "androidx/app/legacy/ActivityCompat{0}",
-      "fieldSelectors": []
+      "from": "android/support/v13/view/ViewCompat(.*)",
+      "to": "androidx/legacy/view/ViewCompat{0}"
     },
     {
-      "from": "android/support/v4/view/ViewCompat(.*)",
-      "to": "androidx/view/legacy/ViewCompat{0}",
-      "fieldSelectors": []
+      "from": "android/support/v13/app/ActivityCompat(.*)",
+      "to": "androidx/legacy/app/ActivityCompat{0}"
     },
     {
-      "from": "android/support/v4/graphics/drawable/DrawableWrapper",
-      "to": "androidx/graphics/drawable/internal/DrawableWrapper",
-      "fieldSelectors": []
+      "from": "android/support/v13/app/FragmentCompat(.*)",
+      "to": "androidx/legacy/app/FragmentCompat{0}"
     },
     {
-      "from": "android/support/v7/widget/ListViewCompat(.*)",
-      "to": "androidx/widget/internal/ListViewCompat{0}",
-      "fieldSelectors": []
+      "from": "android/support/v13/app/FragmentPagerAdapter(.*)",
+      "to": "androidx/legacy/app/FragmentPagerAdapter{0}"
     },
     {
-      "from": "android/support/design/widget/CoordinatorLayout",
-      "to": "androidx/widget/CoordinatorLayout",
-      "fieldSelectors": []
+      "from": "android/support/v13/app/FragmentStatePagerAdapter(.*)",
+      "to": "androidx/legacy/app/FragmentStatePagerAdapter{0}"
     },
     {
-      "from": "android/support/design/widget/DirectedAcyclicGraph",
-      "to": "androidx/widget/DirectedAcyclicGraph",
-      "fieldSelectors": []
+      "from": "android/support/v13/app/FragmentTabHost(.*)",
+      "to": "androidx/legacy/app/FragmentTabHost{0}"
     },
     {
-      "from": "android/support/design/widget/ViewGroupUtils",
-      "to": "androidx/widget/ViewGroupUtils",
-      "fieldSelectors": []
+      "from": "android/support/v7/widget/AdapterHelper(.*)",
+      "to": "androidx/widget/recyclerview/AdapterHelper{0}"
     },
     {
-      "from": "android/support/v4/view/ViewPager",
-      "to": "androidx/widget/ViewPager",
-      "fieldSelectors": []
+      "from": "android/support/v7/widget/ChildHelper(.*)",
+      "to": "androidx/widget/recyclerview/ChildHelper{0}"
     },
     {
-      "from": "android/support/v4/view/PagerAdapter",
-      "to": "androidx/widget/PagerAdapter",
-      "fieldSelectors": []
+      "from": "android/support/v7/widget/DefaultItemAnimator(.*)",
+      "to": "androidx/widget/recyclerview/DefaultItemAnimator{0}"
     },
     {
-      "from": "android/support/v4/view/PagerTabStrip",
-      "to": "androidx/widget/PagerTabStrip",
-      "fieldSelectors": []
+      "from": "android/support/v7/widget/DividerItemDecoration(.*)",
+      "to": "androidx/widget/recyclerview/DividerItemDecoration{0}"
     },
     {
-      "from": "android/support/v4/view/PagerTitleStrip",
-      "to": "androidx/widget/PagerTitleStrip",
-      "fieldSelectors": []
+      "from": "android/support/v7/widget/FastScroller(.*)",
+      "to": "androidx/widget/recyclerview/FastScroller{0}"
+    },
+    {
+      "from": "android/support/v7/widget/GapWorker(.*)",
+      "to": "androidx/widget/recyclerview/GapWorker{0}"
+    },
+    {
+      "from": "android/support/v7/widget/GridLayoutManager(.*)",
+      "to": "androidx/widget/recyclerview/GridLayoutManager{0}"
+    },
+    {
+      "from": "android/support/v7/widget/LayoutState(.*)",
+      "to": "androidx/widget/recyclerview/LayoutState{0}"
+    },
+    {
+      "from": "android/support/v7/widget/LinearLayoutManager(.*)",
+      "to": "androidx/widget/recyclerview/LinearLayoutManager{0}"
+    },
+    {
+      "from": "android/support/v7/widget/LinearSmoothScroller(.*)",
+      "to": "androidx/widget/recyclerview/LinearSmoothScroller{0}"
+    },
+    {
+      "from": "android/support/v7/widget/LinearSnapHelper(.*)",
+      "to": "androidx/widget/recyclerview/LinearSnapHelper{0}"
+    },
+    {
+      "from": "android/support/v7/widget/OpReorderer(.*)",
+      "to": "androidx/widget/recyclerview/OpReorderer{0}"
+    },
+    {
+      "from": "android/support/v7/widget/OrientationHelper(.*)",
+      "to": "androidx/widget/recyclerview/OrientationHelper{0}"
+    },
+    {
+      "from": "android/support/v7/widget/PagerSnapHelper(.*)",
+      "to": "androidx/widget/recyclerview/PagerSnapHelper{0}"
+    },
+    {
+      "from": "android/support/v7/widget/PositionMap(.*)",
+      "to": "androidx/widget/recyclerview/PositionMap{0}"
+    },
+    {
+      "from": "android/support/v7/widget/RecyclerViewAccessibilityDelegate(.*)",
+      "to": "androidx/widget/recyclerview/RecyclerViewAccessibilityDelegate{0}"
+    },
+    {
+      "from": "android/support/v7/widget/RecyclerView(.*)",
+      "to": "androidx/widget/recyclerview/RecyclerView{0}"
+    },
+    {
+      "from": "android/support/v7/widget/ScrollbarHelper(.*)",
+      "to": "androidx/widget/recyclerview/ScrollbarHelper{0}"
+    },
+    {
+      "from": "android/support/v7/widget/SimpleItemAnimator(.*)",
+      "to": "androidx/widget/recyclerview/SimpleItemAnimator{0}"
+    },
+    {
+      "from": "android/support/v7/widget/SnapHelper(.*)",
+      "to": "androidx/widget/recyclerview/SnapHelper{0}"
+    },
+    {
+      "from": "android/support/v7/widget/StaggeredGridLayoutManager(.*)",
+      "to": "androidx/widget/recyclerview/StaggeredGridLayoutManager{0}"
+    },
+    {
+      "from": "android/support/v7/widget/ViewBoundsCheck(.*)",
+      "to": "androidx/widget/recyclerview/ViewBoundsCheck{0}"
+    },
+    {
+      "from": "android/support/v7/widget/ViewInfoStore(.*)",
+      "to": "androidx/widget/recyclerview/ViewInfoStore{0}"
+    },
+    {
+      "from": "android/support/v7/widget/helper/(.*)",
+      "to": "androidx/widget/recyclerview/{0}"
+    },
+    {
+      "from": "android/support/v7/widget/util/SortedListAdapterCallback",
+      "to": "androidx/widget/recyclerview/SortedListAdapterCallback"
+    },
+    {
+      "from": "android/support/v7/recyclerview/extensions/(.*)",
+      "to": "androidx/widget/recyclerview/{0}"
+    },
+    {
+      "from": "android/support/v7/util/(.*)",
+      "to": "androidx/widget/recyclerview/{0}"
+    },
+    {
+      "from": "android/support/design/widget/CoordinatorLayout(.*)",
+      "to": "androidx/widget/CoordinatorLayout{0}"
+    },
+    {
+      "from": "android/support/design/widget/DirectedAcyclicGraph(.*)",
+      "to": "androidx/widget/DirectedAcyclicGraph{0}"
+    },
+    {
+      "from": "android/support/design/widget/ViewGroupUtils(.*)",
+      "to": "androidx/widget/ViewGroupUtils{0}"
+    },
+    {
+      "from": "android/support/constraint/(.*)",
+      "to": "androidx/widget/constraint/{0}"
+    },
+    {
+      "from": "android/support/v4/view/ViewPager(.*)",
+      "to": "androidx/widget/ViewPager{0}"
+    },
+    {
+      "from": "android/support/v4/view/PagerAdapter(.*)",
+      "to": "androidx/widget/PagerAdapter{0}"
+    },
+    {
+      "from": "android/support/v4/view/PagerTabStrip(.*)",
+      "to": "androidx/widget/PagerTabStrip{0}"
+    },
+    {
+      "from": "android/support/v4/view/PagerTitleStrip(.*)",
+      "to": "androidx/widget/PagerTitleStrip{0}"
     },
     {
       "from": "android/support/v17/preference/(.*)",
-      "to": "androidx/leanback/preference/{0}",
-      "fieldSelectors": []
+      "to": "androidx/leanback/preference/{0}"
+    },
+    {
+      "from": "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout(.*)",
+      "to": "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout{0}"
     },
     {
       "from": "android/support/customtabs/(.*)",
-      "to": "androidx/browser/customtabs/{0}",
-      "fieldSelectors": []
+      "to": "androidx/browser/customtabs/{0}"
     },
     {
       "from": "android/support/v4/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/{0}"
     },
     {
-      "from": "android/support/v7/graphics/ColorCutQuantizer",
-      "to": "androidx/graphics/palette/ColorCutQuantizer",
-      "fieldSelectors": []
+      "from": "android/support/v7/graphics/ColorCutQuantizer(.*)",
+      "to": "androidx/graphics/palette/ColorCutQuantizer{0}"
     },
     {
-      "from": "android/support/v7/graphics/Palette",
-      "to": "androidx/graphics/palette/Palette",
-      "fieldSelectors": []
+      "from": "android/support/v7/graphics/Palette(.*)",
+      "to": "androidx/graphics/palette/Palette{0}"
     },
     {
-      "from": "android/support/v7/graphics/Target",
-      "to": "androidx/graphics/palette/Target",
-      "fieldSelectors": []
+      "from": "android/support/v7/graphics/Target(.*)",
+      "to": "androidx/graphics/palette/Target{0}"
+    },
+    {
+      "from": "android/support/v7/internal/widget/PreferenceImageView(.*)",
+      "to": "androidx/preference/internal/PreferenceImageView{0}"
     },
     {
       "from": "android/support/v7/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/{0}"
+    },
+    {
+      "from": "android/support/v8/(.*)",
+      "to": "androidx/{0}"
     },
     {
       "from": "android/support/v13/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/{0}"
     },
     {
       "from": "android/support/v14/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/{0}"
     },
     {
       "from": "android/support/v17/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/{0}"
+    },
+    {
+      "from": "android/support/content/(.*)",
+      "to": "androidx/util/contentpaging/{0}"
     },
     {
       "from": "android/support/percent/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/widget/{0}"
     },
     {
       "from": "android/support/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/{0}"
     },
     {
       "from": "android/arch/(.*)",
-      "to": "androidx/{0}",
-      "fieldSelectors": []
+      "to": "androidx/{0}"
+    },
+    {
+      "from": "android/databinding/(.*)",
+      "to": "androidx/databinding/{0}"
+    }
+  ],
+  "slRules": [
+    {
+      "from": "(.*)/package-info",
+      "to": "ignore"
+    },
+    {
+      "from": "androidx/text/emoji/flatbuffer/(.*)",
+      "to": "ignore"
+    },
+    {
+      "from": "androidx/textclassifier/(.*)",
+      "to": "ignore"
+    },
+    {
+      "from": "androidx/widget/recyclerview/selection/(.*)",
+      "to": "ignore"
+    },
+    {
+      "from": "androidx/browser/browseractions/(.*)",
+      "to": "ignore"
     }
   ],
   "pomRules": [
@@ -690,13356 +810,4147 @@
   ],
   "map": {
     "types": {
-      "android/support/v4/provider/FontsContractCompat$Columns": "androidx/provider/FontsContractCompat$Columns",
-      "android/support/design/widget/AppBarLayout$Behavior$SavedState": "androidx/design/widget/AppBarLayout$Behavior$SavedState",
-      "android/support/v4/internal/view/SupportMenu": "androidx/internal/view/SupportMenu",
-      "android/support/v4/media/MediaDescriptionCompat": "androidx/media/MediaDescriptionCompat",
-      "android/support/transition/ChangeTransform$GhostListener": "androidx/transition/ChangeTransform$GhostListener",
-      "android/support/design/widget/BaseTransientBottomBar$BaseCallback": "androidx/design/widget/BaseTransientBottomBar$BaseCallback",
-      "android/support/v4/print/PrintHelper$ColorMode": "androidx/print/PrintHelper$ColorMode",
-      "android/support/annotation/RequiresPermission$Write": "androidx/annotation/RequiresPermission$Write",
-      "android/support/v7/widget/FastScroller$AnimatorUpdater": "androidx/widget/FastScroller$AnimatorUpdater",
-      "android/support/multidex/MultiDex$V14": "androidx/multidex/MultiDex$V14",
-      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry",
-      "android/support/v7/preference/PreferenceDataStore": "androidx/preference/PreferenceDataStore",
-      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper$PlaybackControlStateCallback": "androidx/leanback/app/DetailsBackgroundVideoHelper$PlaybackControlStateCallback",
-      "android/support/v4/content/LocalBroadcastManager": "androidx/content/LocalBroadcastManager",
-      "android/support/v7/view/ActionBarPolicy": "androidx/view/ActionBarPolicy",
-      "android/support/v4/content/Loader$OnLoadCanceledListener": "androidx/content/Loader$OnLoadCanceledListener",
-      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase",
-      "android/support/v4/app/SharedElementCallback$OnSharedElementsReadyListener": "androidx/app/SharedElementCallback$OnSharedElementsReadyListener",
-      "android/support/v7/app/MediaRouteVolumeSlider": "androidx/app/MediaRouteVolumeSlider",
-      "android/support/multidex/MultiDex$V19": "androidx/multidex/MultiDex$V19",
-      "android/support/v17/leanback/widget/StaggeredGridDefault": "androidx/leanback/widget/StaggeredGridDefault",
-      "android/support/v17/leanback/widget/GuidedActionAdapter$ActionOnKeyListener": "androidx/leanback/widget/GuidedActionAdapter$ActionOnKeyListener",
-      "android/support/design/widget/BottomNavigationView$OnNavigationItemReselectedListener": "androidx/design/widget/BottomNavigationView$OnNavigationItemReselectedListener",
-      "android/support/app/recommendation/ContentRecommendation$ContentPricing": "androidx/app/recommendation/ContentRecommendation$ContentPricing",
-      "android/support/v17/leanback/widget/BaseCardView$LayoutParams": "androidx/leanback/widget/BaseCardView$LayoutParams",
-      "android/support/text/emoji/MetadataListReader": "androidx/text/emoji/MetadataListReader",
-      "android/support/v7/appcompat/R$drawable": "androidx/appcompat/R$drawable",
-      "android/support/design/widget/BaseTransientBottomBar$OnAttachStateChangeListener": "androidx/design/widget/BaseTransientBottomBar$OnAttachStateChangeListener",
-      "android/support/v4/view/GravityCompat": "androidx/view/GravityCompat",
-      "android/support/v7/view/menu/SubMenuWrapperICS": "androidx/view/menu/SubMenuWrapperICS",
-      "android/support/graphics/drawable/VectorDrawableCompat": "androidx/graphics/drawable/VectorDrawableCompat",
-      "android/support/v4/view/AsyncLayoutInflater$InflateRequest": "androidx/view/AsyncLayoutInflater$InflateRequest",
-      "android/support/v17/leanback/app/HeadersFragment$NoOverlappingFrameLayout": "androidx/leanback/app/HeadersFragment$NoOverlappingFrameLayout",
-      "android/support/v17/leanback/widget/ShadowHelperJbmr2": "androidx/leanback/widget/ShadowHelperJbmr2",
-      "android/support/design/internal/ScrimInsetsFrameLayout": "androidx/design/internal/ScrimInsetsFrameLayout",
-      "android/support/v17/leanback/widget/HorizontalHoverCardSwitcher": "androidx/leanback/widget/HorizontalHoverCardSwitcher",
-      "android/support/v7/widget/RecyclerView$Recycler": "androidx/widget/RecyclerView$Recycler",
-      "android/support/v7/widget/FastScroller$State": "androidx/widget/FastScroller$State",
-      "android/support/v7/media/SystemMediaRouteProvider$JellybeanMr2Impl": "androidx/media/SystemMediaRouteProvider$JellybeanMr2Impl",
-      "android/support/wear/R$id": "androidx/wear/R$id",
-      "android/support/v17/leanback/widget/FocusHighlight": "androidx/leanback/widget/FocusHighlight",
-      "android/support/v7/view/menu/ExpandedMenuView": "androidx/view/menu/ExpandedMenuView",
-      "android/support/graphics/drawable/PathInterpolatorCompat": "androidx/graphics/drawable/PathInterpolatorCompat",
-      "android/support/v17/leanback/widget/MediaItemActionPresenter": "androidx/leanback/widget/MediaItemActionPresenter",
-      "android/support/v4/content/Loader$OnLoadCompleteListener": "androidx/content/Loader$OnLoadCompleteListener",
-      "android/support/v17/leanback/widget/NonOverlappingLinearLayout": "androidx/leanback/widget/NonOverlappingLinearLayout",
-      "android/support/v7/view/menu/MenuItemWrapperICS$CollapsibleActionViewWrapper": "androidx/view/menu/MenuItemWrapperICS$CollapsibleActionViewWrapper",
-      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplJB": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplJB",
-      "android/support/v17/leanback/app/ErrorFragment": "androidx/leanback/app/ErrorFragment",
-      "android/support/v7/view/menu/MenuItemWrapperICS$OnActionExpandListenerWrapper": "androidx/view/menu/MenuItemWrapperICS$OnActionExpandListenerWrapper",
-      "android/support/v7/app/AppCompatActivity": "androidx/app/AppCompatActivity",
-      "android/support/v17/preference/LeanbackSettingsFragment$DummyFragment": "androidx/leanback/preference/LeanbackSettingsFragment$DummyFragment",
-      "android/support/app/recommendation/ContentRecommendation$IntentType": "androidx/app/recommendation/ContentRecommendation$IntentType",
-      "android/support/v17/leanback/widget/PlaybackControlsRowView": "androidx/leanback/widget/PlaybackControlsRowView",
-      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale",
-      "android/support/v4/util/SparseArrayCompat": "androidx/util/SparseArrayCompat",
-      "android/support/v4/net/TrafficStatsCompat": "androidx/net/TrafficStatsCompat",
-      "android/support/design/widget/TabLayout$Tab": "androidx/design/widget/TabLayout$Tab",
-      "android/support/v7/view/CollapsibleActionView": "androidx/view/CollapsibleActionView",
-      "android/support/v17/leanback/R$id": "androidx/leanback/R$id",
-      "android/support/v4/content/MimeTypeFilter": "androidx/content/MimeTypeFilter",
-      "android/support/media/tv/TvContractCompat$WatchNextPrograms$WatchNextType": "androidx/media/tv/TvContractCompat$WatchNextPrograms$WatchNextType",
-      "android/support/transition/ViewUtilsImpl": "androidx/transition/ViewUtilsImpl",
-      "android/support/v17/leanback/app/DetailsFragment$SetSelectionRunnable": "androidx/leanback/app/DetailsFragment$SetSelectionRunnable",
-      "android/support/v7/app/MediaRouteControllerDialog$ClickListener": "androidx/app/MediaRouteControllerDialog$ClickListener",
-      "android/support/design/widget/VisibilityAwareImageButton": "androidx/design/widget/VisibilityAwareImageButton",
-      "android/support/transition/ViewGroupUtilsImpl": "androidx/transition/ViewGroupUtilsImpl",
-      "android/support/v7/widget/SearchView$SearchAutoComplete": "androidx/widget/SearchView$SearchAutoComplete",
-      "android/support/v17/leanback/widget/GuidedActionAdapterGroup": "androidx/leanback/widget/GuidedActionAdapterGroup",
-      "android/support/v7/widget/AppCompatBackgroundHelper": "androidx/widget/AppCompatBackgroundHelper",
-      "android/support/v4/widget/EdgeEffectCompat$EdgeEffectApi21Impl": "androidx/widget/EdgeEffectCompat$EdgeEffectApi21Impl",
-      "android/support/v17/leanback/R$fraction": "androidx/leanback/R$fraction",
-      "android/support/wear/widget/drawer/WearableActionDrawerMenu": "androidx/wear/widget/drawer/WearableActionDrawerMenu",
-      "android/support/v4/content/IntentCompat": "androidx/content/IntentCompat",
-      "android/support/compat/R": "androidx/compat/R",
-      "android/support/v7/widget/RecyclerView$ViewCacheExtension": "androidx/widget/RecyclerView$ViewCacheExtension",
-      "android/support/v7/widget/DecorContentParent": "androidx/widget/DecorContentParent",
-      "android/support/design/widget/BaseTransientBottomBar$Behavior": "androidx/design/widget/BaseTransientBottomBar$Behavior",
-      "android/support/design/widget/TabLayout$ViewPagerOnTabSelectedListener": "androidx/design/widget/TabLayout$ViewPagerOnTabSelectedListener",
-      "android/support/v7/preference/EditTextPreference$SavedState": "androidx/preference/EditTextPreference$SavedState",
-      "android/support/design/widget/ShadowViewDelegate": "androidx/design/widget/ShadowViewDelegate",
-      "android/support/v7/app/AlertController$ButtonHandler": "androidx/app/AlertController$ButtonHandler",
-      "android/support/v4/widget/AutoScrollHelper$ScrollAnimationRunnable": "androidx/widget/AutoScrollHelper$ScrollAnimationRunnable",
-      "android/support/v7/view/menu/ShowableListMenu": "androidx/view/menu/ShowableListMenu",
-      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper": "androidx/leanback/widget/DetailsOverviewSharedElementHelper",
-      "android/support/v7/widget/MenuPopupWindow$MenuDropDownListView": "androidx/widget/MenuPopupWindow$MenuDropDownListView",
-      "android/support/v17/leanback/transition/LeanbackTransitionHelper": "androidx/leanback/transition/LeanbackTransitionHelper",
-      "android/support/design/widget/BottomSheetDialogFragment": "androidx/design/widget/BottomSheetDialogFragment",
-      "android/support/v4/app/NotificationCompat$Extender": "androidx/app/NotificationCompat$Extender",
-      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicInternal": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicInternal",
-      "android/support/wear/widget/SwipeDismissLayout$OnPreSwipeListener": "androidx/wear/widget/SwipeDismissLayout$OnPreSwipeListener",
-      "android/support/v4/graphics/BitmapCompat$BitmapCompatApi18Impl": "androidx/graphics/BitmapCompat$BitmapCompatApi18Impl",
-      "android/support/v4/view/ViewCompat$AutofillImportance": "androidx/view/legacy/ViewCompat$AutofillImportance",
-      "android/support/v4/app/AppOpsManagerCompat": "androidx/app/AppOpsManagerCompat",
-      "android/support/annotation/FractionRes": "androidx/annotation/FractionRes",
-      "android/support/media/instantvideo/widget/InstantVideoView": "androidx/media/instantvideo/widget/InstantVideoView",
-      "android/support/design/internal/NavigationMenuPresenter$NormalViewHolder": "androidx/design/internal/NavigationMenuPresenter$NormalViewHolder",
-      "android/support/v4/view/accessibility/AccessibilityRecordCompat": "androidx/view/accessibility/AccessibilityRecordCompat",
-      "android/support/v7/view/menu/MenuWrapperFactory": "androidx/view/menu/MenuWrapperFactory",
-      "android/support/v17/leanback/app/HeadersSupportFragment$NoOverlappingFrameLayout": "androidx/leanback/app/HeadersSupportFragment$NoOverlappingFrameLayout",
-      "android/support/v7/widget/ScrollingTabContainerView$VisibilityAnimListener": "androidx/widget/ScrollingTabContainerView$VisibilityAnimListener",
-      "android/support/v4/media/MediaBrowserServiceCompatApi26$ResultWrapper": "androidx/media/MediaBrowserServiceCompatApi26$ResultWrapper",
-      "android/support/v4/media/MediaBrowserServiceCompat$ResultFlags": "androidx/media/MediaBrowserServiceCompat$ResultFlags",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraBinderRequestResultReceiver": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraBinderRequestResultReceiver",
-      "android/support/v17/leanback/widget/OnChildSelectedListener": "androidx/leanback/widget/OnChildSelectedListener",
-      "android/support/v4/os/LocaleListHelper": "androidx/os/LocaleListHelper",
-      "android/support/v7/widget/ChildHelper": "androidx/widget/ChildHelper",
-      "android/support/v17/leanback/widget/BaseOnItemViewClickedListener": "androidx/leanback/widget/BaseOnItemViewClickedListener",
-      "android/support/v17/leanback/widget/VerticalGridPresenter": "androidx/leanback/widget/VerticalGridPresenter",
-      "android/support/v7/widget/Toolbar$LayoutParams": "androidx/widget/Toolbar$LayoutParams",
-      "android/support/v4/provider/SelfDestructiveThread": "androidx/provider/SelfDestructiveThread",
-      "android/support/v17/leanback/widget/DetailsParallax": "androidx/leanback/widget/DetailsParallax",
-      "android/support/v4/content/pm/ActivityInfoCompat": "androidx/content/pm/ActivityInfoCompat",
-      "android/support/percent/PercentFrameLayout$LayoutParams": "androidx/PercentFrameLayout$LayoutParams",
-      "android/support/v7/widget/RecyclerView$ItemAnimator$ItemAnimatorFinishedListener": "androidx/widget/RecyclerView$ItemAnimator$ItemAnimatorFinishedListener",
-      "android/support/v4/media/MediaBrowserCompat$ConnectionCallback": "androidx/media/MediaBrowserCompat$ConnectionCallback",
-      "android/support/design/widget/ThemeUtils": "androidx/design/widget/ThemeUtils",
-      "android/support/wear/widget/drawer/RecyclerViewFlingWatcher": "androidx/wear/widget/drawer/RecyclerViewFlingWatcher",
-      "android/support/v4/app/SupportActivity": "androidx/app/SupportActivity",
-      "android/support/transition/TransitionUtils": "androidx/transition/TransitionUtils",
-      "android/support/v4/graphics/TypefaceCompatApi21Impl": "androidx/graphics/TypefaceCompatApi21Impl",
-      "android/support/v7/media/MediaRouter$CallbackRecord": "androidx/media/MediaRouter$CallbackRecord",
-      "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher": "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher",
-      "android/support/v4/graphics/drawable/TintAwareDrawable": "androidx/graphics/drawable/TintAwareDrawable",
-      "android/support/text/emoji/widget/EmojiTextViewHelper$HelperInternal": "androidx/text/emoji/widget/EmojiTextViewHelper$HelperInternal",
-      "android/support/transition/Styleable": "androidx/transition/Styleable",
-      "android/support/v17/leanback/widget/BaseCardView": "androidx/leanback/widget/BaseCardView",
-      "android/support/v17/leanback/app/DetailsSupportFragment": "androidx/leanback/app/DetailsSupportFragment",
-      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuSeparatorItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuSeparatorItem",
-      "android/support/app/recommendation/ContentRecommendation$IntentData": "androidx/app/recommendation/ContentRecommendation$IntentData",
-      "android/support/wear/widget/drawer/WearableDrawerLayout$DrawerStateCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$DrawerStateCallback",
-      "android/support/wear/widget/CircularProgressLayoutController$CircularProgressTimer": "androidx/wear/widget/CircularProgressLayoutController$CircularProgressTimer",
-      "android/support/v4/widget/CircleImageView": "androidx/widget/CircleImageView",
-      "android/support/v17/leanback/app/BaseRowFragment": "androidx/leanback/app/BaseRowFragment",
-      "android/support/text/emoji/EmojiCompat$ReplaceStrategy": "androidx/text/emoji/EmojiCompat$ReplaceStrategy",
-      "android/support/v7/widget/ViewInfoStore$InfoRecord": "androidx/widget/ViewInfoStore$InfoRecord",
-      "android/support/transition/TransitionInflater": "androidx/transition/TransitionInflater",
-      "android/support/v17/leanback/media/PlaybackControlGlue$UpdatePlaybackStateHandler": "androidx/leanback/media/PlaybackControlGlue$UpdatePlaybackStateHandler",
-      "android/support/v7/widget/RecyclerView$State$LayoutState": "androidx/widget/RecyclerView$State$LayoutState",
-      "android/support/v17/leanback/widget/RoundedRectHelper": "androidx/leanback/widget/RoundedRectHelper",
-      "android/support/v4/app/ServiceCompat": "androidx/app/ServiceCompat",
-      "android/support/percent/PercentRelativeLayout$LayoutParams": "androidx/PercentRelativeLayout$LayoutParams",
-      "android/support/v17/leanback/widget/RowHeaderPresenter": "androidx/leanback/widget/RowHeaderPresenter",
-      "android/support/v7/widget/SearchView$UpdatableTouchDelegate": "androidx/widget/SearchView$UpdatableTouchDelegate",
-      "android/support/media/tv/TvContractCompat$PreviewProgramColumns$AspectRatio": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$AspectRatio",
-      "android/support/text/emoji/EmojiMetadata$HasGlyph": "androidx/text/emoji/EmojiMetadata$HasGlyph",
-      "android/support/media/tv/BasePreviewProgram$Builder": "androidx/media/tv/BasePreviewProgram$Builder",
-      "android/support/multidex/ZipUtil$CentralDirectory": "androidx/multidex/ZipUtil$CentralDirectory",
-      "android/support/v7/widget/helper/ItemTouchUIUtil": "androidx/widget/helper/ItemTouchUIUtil",
-      "android/support/v4/widget/DrawerLayout$ChildAccessibilityDelegate": "androidx/widget/DrawerLayout$ChildAccessibilityDelegate",
-      "android/support/v7/media/SystemMediaRouteProvider": "androidx/media/SystemMediaRouteProvider",
-      "android/support/v4/app/LoaderManagerImpl": "androidx/app/LoaderManagerImpl",
-      "android/support/media/ExifInterface$IfdType": "androidx/media/ExifInterface$IfdType",
-      "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl",
-      "android/support/v4/graphics/drawable/DrawableWrapperApi14": "androidx/graphics/drawable/DrawableWrapperApi14",
-      "android/support/wear/widget/drawer/WearableDrawerLayout$BottomDrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$BottomDrawerDraggerCallback",
-      "android/support/v4/view/TintableBackgroundView": "androidx/view/TintableBackgroundView",
-      "android/support/v17/leanback/graphics/BoundsRule": "androidx/leanback/graphics/BoundsRule",
-      "android/support/v17/leanback/widget/RecyclerViewParallax$ChildPositionProperty": "androidx/leanback/widget/RecyclerViewParallax$ChildPositionProperty",
-      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicImpl": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicImpl",
-      "android/support/v17/leanback/widget/PlaybackControlsPresenter": "androidx/leanback/widget/PlaybackControlsPresenter",
-      "android/support/v7/app/ActionBarDrawerToggle": "androidx/app/ActionBarDrawerToggle",
-      "android/support/design/internal/BaselineLayout": "androidx/design/internal/BaselineLayout",
-      "android/support/v7/preference/PreferenceScreen": "androidx/preference/PreferenceScreen",
-      "android/support/v4/graphics/drawable/DrawableWrapperApi19": "androidx/graphics/drawable/DrawableWrapperApi19",
-      "android/support/v17/leanback/app/DetailsFragment": "androidx/leanback/app/DetailsFragment",
-      "android/support/annotation/ColorLong": "androidx/annotation/ColorLong",
-      "android/support/annotation/IntRange": "androidx/annotation/IntRange",
-      "android/support/v7/widget/LinearLayoutCompat$DividerMode": "androidx/widget/LinearLayoutCompat$DividerMode",
+      "android/support/v17/leanback/animation/LogAccelerateInterpolator": "androidx/leanback/animation/LogAccelerateInterpolator",
       "android/support/annotation/RestrictTo": "androidx/annotation/RestrictTo",
-      "android/support/v4/media/session/PlaybackStateCompat": "androidx/media/session/PlaybackStateCompat",
-      "android/support/v17/leanback/widget/RecyclerViewParallax": "androidx/leanback/widget/RecyclerViewParallax",
-      "android/support/v7/widget/ChildHelper$Callback": "androidx/widget/ChildHelper$Callback",
-      "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter": "androidx/leanback/widget/DetailsOverviewLogoPresenter",
-      "android/support/constraint/Guideline": "androidx/constraint/Guideline",
-      "android/support/design/widget/CircularBorderDrawable": "androidx/design/widget/CircularBorderDrawable",
-      "android/support/text/emoji/widget/EmojiInputConnection": "androidx/text/emoji/widget/EmojiInputConnection",
-      "android/support/v4/widget/ImageViewCompat$ImageViewCompatImpl": "androidx/widget/ImageViewCompat$ImageViewCompatImpl",
-      "android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper": "androidx/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper",
-      "android/support/v7/view/menu/MenuBuilder": "androidx/view/menu/MenuBuilder",
-      "android/support/v7/media/MediaRouteDiscoveryRequest": "androidx/media/MediaRouteDiscoveryRequest",
-      "android/support/design/widget/AppBarLayout$ScrollingViewBehavior": "androidx/design/widget/AppBarLayout$ScrollingViewBehavior",
-      "android/support/v17/leanback/widget/PersistentFocusWrapper$SavedState": "androidx/leanback/widget/PersistentFocusWrapper$SavedState",
-      "android/support/v7/widget/RecyclerView$ItemAnimator$ItemAnimatorListener": "androidx/widget/RecyclerView$ItemAnimator$ItemAnimatorListener",
-      "android/support/v17/leanback/media/PlaybackBannerControlGlue": "androidx/leanback/media/PlaybackBannerControlGlue",
-      "android/support/design/internal/NavigationMenuPresenter$ViewHolder": "androidx/design/internal/NavigationMenuPresenter$ViewHolder",
-      "android/support/v7/widget/AppCompatDrawableManager$VdcInflateDelegate": "androidx/widget/AppCompatDrawableManager$VdcInflateDelegate",
-      "android/support/graphics/drawable/AndroidResources": "androidx/graphics/drawable/AndroidResources",
-      "android/support/v7/widget/RecyclerView$RecyclerViewDataObserver": "androidx/widget/RecyclerView$RecyclerViewDataObserver",
-      "android/support/design/R$integer": "androidx/design/R$integer",
-      "android/support/v4/app/AppLaunchChecker": "androidx/app/AppLaunchChecker",
-      "android/support/v17/leanback/transition/ParallaxTransition": "androidx/leanback/transition/ParallaxTransition",
-      "android/support/text/emoji/widget/SpannableBuilder": "androidx/text/emoji/widget/SpannableBuilder",
-      "android/support/text/emoji/widget/ExtractButtonCompat": "androidx/text/emoji/widget/ExtractButtonCompat",
-      "android/support/v17/leanback/app/ListRowDataAdapter$QueueBasedDataObserver": "androidx/leanback/app/ListRowDataAdapter$QueueBasedDataObserver",
-      "android/support/content/ContentPager$QueryRunner": "androidx/content/ContentPager$QueryRunner",
-      "android/support/v4/app/FragmentTabHost$SavedState": "androidx/app/FragmentTabHost$SavedState",
-      "android/support/v7/widget/OpReorderer$Callback": "androidx/widget/OpReorderer$Callback",
-      "android/support/multidex/MultiDexExtractor$ExtractedDex": "androidx/multidex/MultiDexExtractor$ExtractedDex",
-      "android/support/design/widget/SwipeDismissBehavior": "androidx/design/widget/SwipeDismissBehavior",
-      "android/support/v4/content/FileProvider": "androidx/content/FileProvider",
-      "android/support/v17/leanback/app/BrowseFragment$BrowseTransitionListener": "androidx/leanback/app/BrowseFragment$BrowseTransitionListener",
-      "android/support/design/widget/ViewOffsetBehavior": "androidx/design/widget/ViewOffsetBehavior",
-      "android/support/v17/leanback/app/ListRowDataAdapter$SimpleDataObserver": "androidx/leanback/app/ListRowDataAdapter$SimpleDataObserver",
-      "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": "androidx/accessibilityservice/AccessibilityServiceInfoCompat",
-      "android/support/v7/widget/ScrollbarHelper": "androidx/widget/ScrollbarHelper",
-      "android/support/v17/leanback/widget/BaseCardView$InfoAlphaAnimation": "androidx/leanback/widget/BaseCardView$InfoAlphaAnimation",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$RepeatAction": "androidx/leanback/widget/PlaybackControlsRow$RepeatAction",
-      "android/support/v7/widget/LinearSnapHelper": "androidx/widget/LinearSnapHelper",
-      "android/support/v7/view/menu/BaseWrapper": "androidx/view/menu/BaseWrapper",
-      "android/support/wear/utils/MetadataConstants": "androidx/wear/utils/MetadataConstants",
-      "android/support/v7/widget/RecyclerView$ItemAnimator": "androidx/widget/RecyclerView$ItemAnimator",
-      "android/support/v17/leanback/media/PlaybackGlueHost$HostCallback": "androidx/leanback/media/PlaybackGlueHost$HostCallback",
-      "android/support/v7/widget/ActionMenuPresenter$ActionMenuPopupCallback": "androidx/widget/ActionMenuPresenter$ActionMenuPopupCallback",
-      "android/support/v7/widget/GridLayout$Interval": "androidx/widget/GridLayout$Interval",
-      "android/support/v17/leanback/widget/GuidedActionsStylist$ViewHolder": "androidx/leanback/widget/GuidedActionsStylist$ViewHolder",
-      "android/support/v4/app/Fragment$InstantiationException": "androidx/app/Fragment$InstantiationException",
-      "android/support/v14/preference/EditTextPreferenceDialogFragment": "androidx/preference/EditTextPreferenceDialogFragment",
-      "android/support/text/emoji/EmojiCompat$CompatInternal": "androidx/text/emoji/EmojiCompat$CompatInternal",
-      "android/support/v4/app/FragmentManagerNonConfig": "androidx/app/FragmentManagerNonConfig",
-      "android/support/v7/media/MediaRouter$GlobalMediaRouter": "androidx/media/MediaRouter$GlobalMediaRouter",
-      "android/support/transition/Styleable$TransitionManager": "androidx/transition/Styleable$TransitionManager",
-      "android/support/v4/content/res/ConfigurationHelper": "androidx/content/res/ConfigurationHelper",
-      "android/support/v7/app/MediaRouteDiscoveryFragment": "androidx/app/MediaRouteDiscoveryFragment",
-      "android/support/v7/media/MediaRouteSelector": "androidx/media/MediaRouteSelector",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21",
-      "android/support/v17/leanback/widget/ControlBar": "androidx/leanback/widget/ControlBar",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi24": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi24",
-      "android/support/app/recommendation/ContentRecommendation$ContentStatus": "androidx/app/recommendation/ContentRecommendation$ContentStatus",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi23": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi23",
-      "android/support/v4/media/MediaMetadataCompat": "androidx/media/MediaMetadataCompat",
-      "android/support/v4/util/CircularIntArray": "androidx/util/CircularIntArray",
-      "android/support/transition/Slide$CalculateSlide": "androidx/transition/Slide$CalculateSlide",
-      "android/support/transition/GhostViewUtils": "androidx/transition/GhostViewUtils",
-      "android/support/design/widget/NavigationView$OnNavigationItemSelectedListener": "androidx/design/widget/NavigationView$OnNavigationItemSelectedListener",
-      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$CryptoObject": "androidx/hardware/fingerprint/FingerprintManagerCompat$CryptoObject",
-      "android/support/media/tv/TvContractCompat$Programs": "androidx/media/tv/TvContractCompat$Programs",
-      "android/support/v4/provider/FontsContractCompat": "androidx/provider/FontsContractCompat",
-      "android/support/v4/content/res/FontResourcesParserCompat$ProviderResourceEntry": "androidx/content/res/FontResourcesParserCompat$ProviderResourceEntry",
-      "android/support/v17/leanback/widget/BaseGridView": "androidx/leanback/widget/BaseGridView",
-      "android/support/design/R": "androidx/design/R",
-      "android/support/annotation/GuardedBy": "androidx/annotation/GuardedBy",
-      "android/support/v17/leanback/widget/ListRowPresenter$ViewHolder": "androidx/leanback/widget/ListRowPresenter$ViewHolder",
-      "android/support/constraint/solver/widgets/ConstraintWidgetContainer": "androidx/constraint/solver/widgets/ConstraintWidgetContainer",
-      "android/support/wear/widget/drawer/WearableDrawerView$DrawerState": "androidx/wear/widget/drawer/WearableDrawerView$DrawerState",
-      "android/support/v7/widget/LinearLayoutManager$SavedState": "androidx/widget/LinearLayoutManager$SavedState",
-      "android/support/v4/util/LongSparseArray": "androidx/util/LongSparseArray",
-      "android/support/media/tv/TvContractCompat$ProgramColumns$ReviewRatingStyle": "androidx/media/tv/TvContractCompat$ProgramColumns$ReviewRatingStyle",
-      "android/support/v7/media/MediaRouter$GlobalMediaRouter$RemoteControlClientRecord": "androidx/media/MediaRouter$GlobalMediaRouter$RemoteControlClientRecord",
-      "android/support/v7/widget/TintResources": "androidx/widget/TintResources",
-      "android/support/v7/util/ThreadUtil$MainThreadCallback": "androidx/util/ThreadUtil$MainThreadCallback",
-      "android/support/animation/DynamicAnimation$MassState": "androidx/animation/DynamicAnimation$MassState",
-      "android/support/v4/widget/PopupWindowCompat": "androidx/widget/PopupWindowCompat",
-      "android/support/design/widget/FloatingActionButton$Behavior": "androidx/design/widget/FloatingActionButton$Behavior",
-      "android/support/v7/preference/PreferenceFragmentCompat$DividerDecoration": "androidx/preference/PreferenceFragmentCompat$DividerDecoration",
-      "android/support/transition/Styleable$PatternPathMotion": "androidx/transition/Styleable$PatternPathMotion",
-      "android/support/v4/media/session/MediaSessionCompat$Callback$CallbackHandler": "androidx/media/session/MediaSessionCompat$Callback$CallbackHandler",
-      "android/support/v4/app/INotificationSideChannel": "androidx/app/INotificationSideChannel",
-      "android/support/media/tv/TvContractCompat$Channels$VideoFormat": "androidx/media/tv/TvContractCompat$Channels$VideoFormat",
-      "android/support/v17/preference/LeanbackSettingsFragment$RootViewOnKeyListener": "androidx/leanback/preference/LeanbackSettingsFragment$RootViewOnKeyListener",
-      "android/support/v7/widget/ActionMenuView$MenuBuilderCallback": "androidx/widget/ActionMenuView$MenuBuilderCallback",
-      "android/support/design/widget/TabLayout$Mode": "androidx/design/widget/TabLayout$Mode",
-      "android/support/transition/ChangeTransform$Transforms": "androidx/transition/ChangeTransform$Transforms",
-      "android/support/v4/media/MediaBrowserServiceCompatApi21$ResultWrapper": "androidx/media/MediaBrowserServiceCompatApi21$ResultWrapper",
-      "android/support/v17/leanback/transition/TranslationAnimationCreator$TransitionPositionListener": "androidx/leanback/transition/TranslationAnimationCreator$TransitionPositionListener",
-      "android/support/text/emoji/widget/EmojiEditText": "androidx/text/emoji/widget/EmojiEditText",
-      "android/support/wear/R$styleable": "androidx/wear/R$styleable",
-      "android/support/v17/leanback/app/BrowseSupportFragment$FragmentHost": "androidx/leanback/app/BrowseSupportFragment$FragmentHost",
-      "android/support/transition/Scene": "androidx/transition/Scene",
-      "android/support/text/emoji/widget/EmojiTransformationMethod": "androidx/text/emoji/widget/EmojiTransformationMethod",
-      "android/support/v4/view/ViewCompat$ResolvedLayoutDirectionMode": "androidx/view/legacy/ViewCompat$ResolvedLayoutDirectionMode",
-      "android/support/v7/appcompat/R": "androidx/appcompat/R",
-      "android/support/v4/media/session/MediaSessionCompatApi24$Callback": "androidx/media/session/MediaSessionCompatApi24$Callback",
-      "android/support/v7/widget/RecyclerView": "androidx/widget/RecyclerView",
-      "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerCompat": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerCompat",
-      "android/support/v17/leanback/widget/FragmentAnimationProvider": "androidx/leanback/widget/FragmentAnimationProvider",
-      "android/support/v7/widget/ActivityChooserModel": "androidx/widget/ActivityChooserModel",
-      "android/support/media/tv/TvContractCompat$PreviewProgramColumns$InteractionType": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$InteractionType",
-      "android/support/transition/Transition$TransitionListener": "androidx/transition/Transition$TransitionListener",
-      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackControlsRowPresenter$ViewHolder",
-      "android/support/design/widget/CoordinatorLayout": "androidx/widget/CoordinatorLayout",
-      "android/support/content/Query": "androidx/content/Query",
-      "android/support/v17/leanback/app/BackgroundManager$EmptyDrawable": "androidx/leanback/app/BackgroundManager$EmptyDrawable",
-      "android/support/v17/leanback/app/PlaybackSupportFragment$OnFadeCompleteListener": "androidx/leanback/app/PlaybackSupportFragment$OnFadeCompleteListener",
-      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapter": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapter",
-      "android/support/v4/media/MediaBrowserCompat$ItemReceiver": "androidx/media/MediaBrowserCompat$ItemReceiver",
-      "android/support/transition/Styleable$VisibilityTransition": "androidx/transition/Styleable$VisibilityTransition",
-      "android/support/transition/TransitionValues": "androidx/transition/TransitionValues",
-      "android/support/v4/content/res/FontResourcesParserCompat$FamilyResourceEntry": "androidx/content/res/FontResourcesParserCompat$FamilyResourceEntry",
-      "android/support/v17/leanback/app/RowsSupportFragment$MainFragmentAdapter": "androidx/leanback/app/RowsSupportFragment$MainFragmentAdapter",
-      "android/support/v17/leanback/widget/Visibility": "androidx/leanback/widget/Visibility",
-      "android/support/design/widget/AppBarLayout$LayoutParams": "androidx/design/widget/AppBarLayout$LayoutParams",
-      "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback$StubApi26": "androidx/media/MediaBrowserCompat$SubscriptionCallback$StubApi26",
-      "android/support/v4/widget/AutoScrollHelper$ClampedScroller": "androidx/widget/AutoScrollHelper$ClampedScroller",
-      "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceStartScreenCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceStartScreenCallback",
-      "android/support/v7/graphics/Palette$Builder": "androidx/graphics/Palette$Builder",
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionItemInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionItemInfoCompat",
-      "android/support/design/widget/StateListAnimator$Tuple": "androidx/design/widget/StateListAnimator$Tuple",
-      "android/support/v4/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListener": "androidx/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListener",
-      "android/support/text/emoji/EmojiCompat$SpanFactory": "androidx/text/emoji/EmojiCompat$SpanFactory",
-      "android/support/media/tv/TvContractCompat$Channels$Type": "androidx/media/tv/TvContractCompat$Channels$Type",
-      "android/support/v7/widget/GridLayout$LayoutParams": "androidx/widget/GridLayout$LayoutParams",
-      "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback$StubApi21": "androidx/media/MediaBrowserCompat$SubscriptionCallback$StubApi21",
-      "android/support/v17/leanback/widget/WindowAlignment$Axis": "androidx/leanback/widget/WindowAlignment$Axis",
-      "android/support/v17/leanback/widget/ControlBarPresenter": "androidx/leanback/widget/ControlBarPresenter",
-      "android/support/constraint/ConstraintSet": "androidx/constraint/ConstraintSet",
-      "android/support/v17/leanback/transition/TransitionHelperKitkat": "androidx/leanback/transition/TransitionHelperKitkat",
-      "android/support/wear/widget/ScrollManager": "androidx/wear/widget/ScrollManager",
-      "android/support/content/ContentPager$QueryRunner$Callback": "androidx/content/ContentPager$QueryRunner$Callback",
-      "android/support/v4/graphics/TypefaceCompat$TypefaceCompatImpl": "androidx/graphics/TypefaceCompat$TypefaceCompatImpl",
-      "android/support/v7/widget/ContentFrameLayout": "androidx/widget/ContentFrameLayout",
-      "android/support/v4/app/ActionBarDrawerToggle$SetIndicatorInfo": "androidx/app/legacy/ActionBarDrawerToggle$SetIndicatorInfo",
-      "android/support/v4/util/TimeUtils": "androidx/util/TimeUtils",
-      "android/support/v7/widget/ActionBarBackgroundDrawableV21": "androidx/widget/ActionBarBackgroundDrawableV21",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$SkipNextAction": "androidx/leanback/widget/PlaybackControlsRow$SkipNextAction",
-      "android/support/design/internal/ParcelableSparseArray": "androidx/design/internal/ParcelableSparseArray",
-      "android/support/media/tv/Channel$Builder": "androidx/media/tv/Channel$Builder",
-      "android/support/v7/widget/AppCompatCompoundButtonHelper": "androidx/widget/AppCompatCompoundButtonHelper",
-      "android/support/v4/media/MediaBrowserCompatApi23$ItemCallback": "androidx/media/MediaBrowserCompatApi23$ItemCallback",
-      "android/support/v4/app/ActionBarDrawerToggle$Delegate": "androidx/app/legacy/ActionBarDrawerToggle$Delegate",
-      "android/support/graphics/drawable/AnimationUtilsCompat": "androidx/graphics/drawable/AnimationUtilsCompat",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ShuffleAction": "androidx/leanback/widget/PlaybackControlsRow$ShuffleAction",
-      "android/support/v4/app/JobIntentService$JobServiceEngineImpl$WrapperWorkItem": "androidx/app/JobIntentService$JobServiceEngineImpl$WrapperWorkItem",
-      "android/support/v7/media/SystemMediaRouteProvider$SyncCallback": "androidx/media/SystemMediaRouteProvider$SyncCallback",
-      "android/support/v7/util/AsyncListUtil$ViewCallback": "androidx/util/AsyncListUtil$ViewCallback",
-      "android/support/v4/view/ViewPager$OnAdapterChangeListener": "androidx/view/ViewPager$OnAdapterChangeListener",
-      "android/support/v7/media/RegisteredMediaRouteProviderWatcher": "androidx/media/RegisteredMediaRouteProviderWatcher",
-      "android/support/transition/Fade$FadeAnimatorListener": "androidx/transition/Fade$FadeAnimatorListener",
-      "android/support/v4/content/res/FontResourcesParserCompat$FetchStrategy": "androidx/content/res/FontResourcesParserCompat$FetchStrategy",
-      "android/support/v17/leanback/graphics/FitWidthBitmapDrawable": "androidx/leanback/graphics/FitWidthBitmapDrawable",
-      "android/support/v7/widget/CardViewDelegate": "androidx/widget/CardViewDelegate",
-      "android/support/v4/media/MediaBrowserCompat$ItemCallback": "androidx/media/MediaBrowserCompat$ItemCallback",
-      "android/support/design/widget/BottomSheetDialog": "androidx/design/widget/BottomSheetDialog",
-      "android/support/v17/leanback/system/Settings$Customizations": "androidx/leanback/system/Settings$Customizations",
-      "android/support/design/widget/FloatingActionButtonImpl$InternalVisibilityChangedListener": "androidx/design/widget/FloatingActionButtonImpl$InternalVisibilityChangedListener",
-      "android/support/v7/media/RemotePlaybackClient$SessionActionCallback": "androidx/media/RemotePlaybackClient$SessionActionCallback",
-      "android/support/wear/ambient/AmbientDelegate$AmbientCallback": "androidx/wear/ambient/AmbientDelegate$AmbientCallback",
-      "android/support/v4/widget/FocusStrategy$BoundsAdapter": "androidx/widget/FocusStrategy$BoundsAdapter",
-      "android/support/v17/leanback/widget/DividerPresenter": "androidx/leanback/widget/DividerPresenter",
-      "android/support/text/emoji/EmojiProcessor$GlyphChecker": "androidx/text/emoji/EmojiProcessor$GlyphChecker",
-      "android/support/v7/preference/PreferenceFragmentCompat": "androidx/preference/PreferenceFragmentCompat",
-      "android/support/v7/widget/TooltipPopup": "androidx/widget/TooltipPopup",
-      "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat": "androidx/view/accessibility/AccessibilityNodeProviderCompat",
-      "android/support/v4/media/MediaBrowserCompat$SearchCallback": "androidx/media/MediaBrowserCompat$SearchCallback",
-      "android/support/v4/media/session/IMediaControllerCallback": "androidx/media/session/IMediaControllerCallback",
-      "android/support/compat/R$styleable": "androidx/compat/R$styleable",
-      "android/support/v7/view/menu/MenuBuilder$ItemInvoker": "androidx/view/menu/MenuBuilder$ItemInvoker",
-      "android/support/v17/leanback/widget/MultiActionsProvider$MultiAction": "androidx/leanback/widget/MultiActionsProvider$MultiAction",
-      "android/support/v7/gridlayout/R$dimen": "androidx/gridlayout/R$dimen",
-      "android/support/v4/app/FragmentManagerImpl$FragmentTag": "androidx/app/FragmentManagerImpl$FragmentTag",
-      "android/support/v4/media/MediaDescriptionCompat$Builder": "androidx/media/MediaDescriptionCompat$Builder",
-      "android/support/v17/leanback/widget/PlaybackControlsPresenter$BoundData": "androidx/leanback/widget/PlaybackControlsPresenter$BoundData",
-      "android/support/v7/app/MediaRouteChooserDialog$RouteComparator": "androidx/app/MediaRouteChooserDialog$RouteComparator",
-      "android/support/v7/app/ActionBar": "androidx/app/ActionBar",
-      "android/support/design/widget/HeaderBehavior$FlingRunnable": "androidx/design/widget/HeaderBehavior$FlingRunnable",
-      "android/support/v7/widget/GapWorker$Task": "androidx/widget/GapWorker$Task",
-      "android/support/v4/view/AsyncLayoutInflater$InflateThread": "androidx/view/AsyncLayoutInflater$InflateThread",
-      "android/support/v17/leanback/R$string": "androidx/leanback/R$string",
-      "android/support/v4/content/LocalBroadcastManager$BroadcastRecord": "androidx/content/LocalBroadcastManager$BroadcastRecord",
-      "android/support/wear/widget/drawer/AbsListViewFlingWatcher": "androidx/wear/widget/drawer/AbsListViewFlingWatcher",
-      "android/support/v17/leanback/widget/ActionPresenterSelector$ActionViewHolder": "androidx/leanback/widget/ActionPresenterSelector$ActionViewHolder",
-      "android/support/v17/leanback/widget/ImageCardView": "androidx/leanback/widget/ImageCardView",
-      "android/support/v4/app/AlarmManagerCompat": "androidx/app/AlarmManagerCompat",
-      "android/support/v7/app/MediaRouterThemeHelper$ControllerColorType": "androidx/app/MediaRouterThemeHelper$ControllerColorType",
-      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplBase": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplBase",
-      "android/support/v4/view/WindowCompat": "androidx/view/WindowCompat",
-      "android/support/v7/widget/ThemedSpinnerAdapter$Helper": "androidx/widget/ThemedSpinnerAdapter$Helper",
-      "android/support/v4/media/session/MediaControllerCompat$Callback$StubCompat": "androidx/media/session/MediaControllerCompat$Callback$StubCompat",
-      "android/support/v4/widget/NestedScrollView$AccessibilityDelegate": "androidx/widget/NestedScrollView$AccessibilityDelegate",
-      "android/support/annotation/MainThread": "androidx/annotation/MainThread",
-      "android/support/v17/leanback/app/RowsFragment$RowViewHolderExtra": "androidx/leanback/app/RowsFragment$RowViewHolderExtra",
-      "android/support/v17/leanback/widget/MultiActionsProvider": "androidx/leanback/widget/MultiActionsProvider",
-      "android/support/v7/mediarouter/R$id": "androidx/mediarouter/R$id",
-      "android/support/v4/view/ViewCompat$NestedScrollType": "androidx/view/legacy/ViewCompat$NestedScrollType",
-      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionAlgorithm": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionAlgorithm",
-      "android/support/v4/media/session/MediaControllerCompatApi21$CallbackProxy": "androidx/media/session/MediaControllerCompatApi21$CallbackProxy",
-      "android/support/customtabs/TrustedWebUtils": "androidx/browser/customtabs/TrustedWebUtils",
-      "android/support/v4/text/BidiFormatter$Builder": "androidx/text/BidiFormatter$Builder",
-      "android/support/design/widget/TabLayout$TabView": "androidx/design/widget/TabLayout$TabView",
-      "android/support/wear/internal/widget/drawer/SinglePageUi$OnSelectedClickHandler": "androidx/wear/internal/widget/drawer/SinglePageUi$OnSelectedClickHandler",
-      "android/support/v17/leanback/widget/BrowseFrameLayout": "androidx/leanback/widget/BrowseFrameLayout",
-      "android/support/v4/widget/ImageViewCompat$BaseViewCompatImpl": "androidx/widget/ImageViewCompat$BaseViewCompatImpl",
-      "android/support/customtabs/PostMessageService": "androidx/browser/customtabs/PostMessageService",
-      "android/support/annotation/FontRes": "androidx/annotation/FontRes",
-      "android/support/transition/ViewGroupUtilsApi14": "androidx/transition/ViewGroupUtilsApi14",
-      "android/support/v4/view/ViewParentCompat": "androidx/view/ViewParentCompat",
-      "android/support/v17/leanback/widget/SectionRow": "androidx/leanback/widget/SectionRow",
-      "android/support/v7/preference/DropDownPreference": "androidx/preference/DropDownPreference",
-      "android/support/v4/widget/DrawerLayout$SavedState": "androidx/widget/DrawerLayout$SavedState",
-      "android/support/transition/AnimatorUtilsApi14": "androidx/transition/AnimatorUtilsApi14",
-      "android/support/transition/AnimatorUtilsApi19": "androidx/transition/AnimatorUtilsApi19",
-      "android/support/constraint/solver/widgets/ConstraintAnchor$Strength": "androidx/constraint/solver/widgets/ConstraintAnchor$Strength",
-      "android/support/v7/widget/RecyclerView$SmoothScroller": "androidx/widget/RecyclerView$SmoothScroller",
-      "android/support/design/R$drawable": "androidx/design/R$drawable",
-      "android/support/v7/util/BatchingListUpdateCallback": "androidx/util/BatchingListUpdateCallback",
-      "android/support/v17/leanback/app/BrandedSupportFragment": "androidx/leanback/app/BrandedSupportFragment",
-      "android/support/transition/ViewGroupUtilsApi18": "androidx/transition/ViewGroupUtilsApi18",
-      "android/support/v17/leanback/app/BrowseFragment$FragmentHost": "androidx/leanback/app/BrowseFragment$FragmentHost",
-      "android/support/v17/leanback/widget/MediaNowPlayingView": "androidx/leanback/widget/MediaNowPlayingView",
-      "android/support/v4/app/ActivityCompat$PermissionCompatDelegate": "androidx/app/legacy/ActivityCompat$PermissionCompatDelegate",
-      "android/support/v7/app/ActionBar$TabListener": "androidx/app/ActionBar$TabListener",
-      "android/support/design/widget/CoordinatorLayout$HierarchyChangeListener": "androidx/design/widget/CoordinatorLayout$HierarchyChangeListener",
-      "android/support/v7/app/AppCompatDelegateImplV9": "androidx/app/AppCompatDelegateImplV9",
-      "android/support/v4/app/LoaderManager$LoaderCallbacks": "androidx/app/LoaderManager$LoaderCallbacks",
-      "android/support/v4/view/MenuItemCompat$MenuItemCompatBaseImpl": "androidx/view/MenuItemCompat$MenuItemCompatBaseImpl",
-      "android/support/design/widget/BaseTransientBottomBar$SnackbarBaseLayout": "androidx/design/widget/BaseTransientBottomBar$SnackbarBaseLayout",
-      "android/support/text/emoji/EmojiCompat$CompatInternal19": "androidx/text/emoji/EmojiCompat$CompatInternal19",
-      "android/support/wear/R$fraction": "androidx/wear/R$fraction",
-      "android/support/v7/widget/DividerItemDecoration": "androidx/widget/DividerItemDecoration",
-      "android/support/v4/view/MenuItemCompat$OnActionExpandListener": "androidx/view/MenuItemCompat$OnActionExpandListener",
-      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImpl": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImpl",
-      "android/support/v4/graphics/PathParser$ExtractFloatResult": "androidx/graphics/PathParser$ExtractFloatResult",
-      "android/support/graphics/drawable/ArgbEvaluator": "androidx/graphics/drawable/ArgbEvaluator",
-      "android/support/v17/leanback/widget/ShadowHelper": "androidx/leanback/widget/ShadowHelper",
-      "android/support/design/widget/FloatingActionButtonImpl$ElevateToTranslationZAnimation": "androidx/design/widget/FloatingActionButtonImpl$ElevateToTranslationZAnimation",
-      "android/support/v4/app/NotificationManagerCompat$SideChannelManager": "androidx/app/NotificationManagerCompat$SideChannelManager",
-      "android/support/v17/leanback/widget/PlaybackRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackRowPresenter$ViewHolder",
-      "android/support/v17/leanback/media/PlaybackBaseControlGlue": "androidx/leanback/media/PlaybackBaseControlGlue",
-      "android/support/v7/app/MediaRouteButton": "androidx/app/MediaRouteButton",
-      "android/support/v4/view/PagerTabStrip": "androidx/widget/PagerTabStrip",
-      "android/support/v7/widget/ActivityChooserView$InnerLayout": "androidx/widget/ActivityChooserView$InnerLayout",
-      "android/support/v17/leanback/widget/TitleHelper": "androidx/leanback/widget/TitleHelper",
-      "android/support/v7/media/RegisteredMediaRouteProvider": "androidx/media/RegisteredMediaRouteProvider",
-      "android/support/v4/print/PrintHelper$PrintHelperStub": "androidx/print/PrintHelper$PrintHelperStub",
-      "android/support/v7/media/MediaRouter": "androidx/media/MediaRouter",
-      "android/support/v4/widget/ViewDragHelper": "androidx/widget/ViewDragHelper",
-      "android/support/v4/media/MediaBrowserCompat$MediaItem": "androidx/media/MediaBrowserCompat$MediaItem",
-      "android/support/app/recommendation/ContentRecommendation$ContentMaturity": "androidx/app/recommendation/ContentRecommendation$ContentMaturity",
-      "android/support/v7/widget/SwitchCompat": "androidx/widget/SwitchCompat",
-      "android/support/v7/media/MediaSessionStatus": "androidx/media/MediaSessionStatus",
-      "android/support/v17/leanback/widget/picker/Picker$PickerScrollArrayAdapter": "androidx/leanback/widget/picker/Picker$PickerScrollArrayAdapter",
-      "android/support/v4/util/Pools": "androidx/util/Pools",
-      "android/support/v4/widget/SlidingPaneLayout$SavedState": "androidx/widget/SlidingPaneLayout$SavedState",
-      "android/support/v7/widget/ViewStubCompat$OnInflateListener": "androidx/widget/ViewStubCompat$OnInflateListener",
-      "android/support/design/widget/ViewOffsetHelper": "androidx/design/widget/ViewOffsetHelper",
-      "android/support/design/widget/FloatingActionButton$OnVisibilityChangedListener": "androidx/design/widget/FloatingActionButton$OnVisibilityChangedListener",
-      "android/support/v4/app/FragmentManagerImpl$PopBackStackState": "androidx/app/FragmentManagerImpl$PopBackStackState",
-      "android/support/v7/media/MediaRouterJellybeanMr1$ActiveScanWorkaround": "androidx/media/MediaRouterJellybeanMr1$ActiveScanWorkaround",
-      "android/support/v17/leanback/widget/TitleViewAdapter": "androidx/leanback/widget/TitleViewAdapter",
-      "android/support/design/widget/TabLayout": "androidx/design/widget/TabLayout",
-      "android/support/v4/view/MenuItemCompat$MenuVersionImpl": "androidx/view/MenuItemCompat$MenuVersionImpl",
-      "android/support/v7/app/MediaRouteButton$MediaRouterCallback": "androidx/app/MediaRouteButton$MediaRouterCallback",
-      "android/support/v4/media/MediaDescriptionCompatApi21$Builder": "androidx/media/MediaDescriptionCompatApi21$Builder",
-      "android/support/design/widget/TabLayout$TabGravity": "androidx/design/widget/TabLayout$TabGravity",
-      "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter",
-      "android/support/v7/widget/RecyclerView$RecycledViewPool$ScrapData": "androidx/widget/RecyclerView$RecycledViewPool$ScrapData",
-      "android/support/v17/leanback/media/MediaControllerAdapter": "androidx/leanback/media/MediaControllerAdapter",
-      "android/support/wear/internal/widget/drawer/MultiPagePresenter$Ui": "androidx/wear/internal/widget/drawer/MultiPagePresenter$Ui",
-      "android/support/v7/app/ToolbarActionBar": "androidx/app/ToolbarActionBar",
-      "android/support/v7/widget/ViewBoundsCheck$Callback": "androidx/widget/ViewBoundsCheck$Callback",
-      "android/support/text/emoji/widget/EmojiExtractEditText": "androidx/text/emoji/widget/EmojiExtractEditText",
-      "android/support/v4/app/FrameMetricsAggregator": "androidx/app/FrameMetricsAggregator",
-      "android/support/constraint/R": "androidx/constraint/R",
-      "android/support/v7/mediarouter/R$string": "androidx/mediarouter/R$string",
-      "android/support/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable": "androidx/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable",
-      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperApi21Impl": "androidx/leanback/transition/TransitionHelper$TransitionHelperApi21Impl",
-      "android/support/v7/widget/LinearLayoutManager": "androidx/widget/LinearLayoutManager",
-      "android/support/graphics/drawable/VectorDrawableCompat$VGroup": "androidx/graphics/drawable/VectorDrawableCompat$VGroup",
-      "android/support/v17/leanback/app/BackgroundManager": "androidx/leanback/app/BackgroundManager",
-      "android/support/v17/leanback/app/VideoFragmentGlueHost": "androidx/leanback/app/VideoFragmentGlueHost",
-      "android/support/v4/net/ConnectivityManagerCompat": "androidx/net/ConnectivityManagerCompat",
-      "android/support/annotation/NonNull": "androidx/annotation/NonNull",
-      "android/support/transition/ImageViewUtilsApi21": "androidx/transition/ImageViewUtilsApi21",
-      "android/support/v7/widget/Toolbar$SavedState": "androidx/widget/Toolbar$SavedState",
-      "android/support/v7/util/ThreadUtil$BackgroundCallback": "androidx/util/ThreadUtil$BackgroundCallback",
-      "android/support/v17/leanback/app/BaseFragment": "androidx/leanback/app/BaseFragment",
-      "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl",
-      "android/support/v7/media/MediaRouterJellybeanMr2$UserRouteInfo": "androidx/media/MediaRouterJellybeanMr2$UserRouteInfo",
-      "android/support/v7/widget/DefaultItemAnimator$ChangeInfo": "androidx/widget/DefaultItemAnimator$ChangeInfo",
-      "android/support/v4/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi14Impl": "androidx/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi14Impl",
-      "android/support/v7/cardview/R": "androidx/cardview/R",
-      "android/support/v4/app/NotificationCompat": "androidx/app/NotificationCompat",
-      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperKitkatImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperKitkatImpl",
-      "android/support/v4/widget/CircularProgressDrawable$Ring": "androidx/widget/CircularProgressDrawable$Ring",
-      "android/support/v17/leanback/app/BrowseSupportFragment$ListRowFragmentFactory": "androidx/leanback/app/BrowseSupportFragment$ListRowFragmentFactory",
-      "android/support/v7/widget/LinearLayoutManager$AnchorInfo": "androidx/widget/LinearLayoutManager$AnchorInfo",
-      "android/support/v4/media/MediaBrowserCompatApi26$SubscriptionCallbackProxy": "androidx/media/MediaBrowserCompatApi26$SubscriptionCallbackProxy",
-      "android/support/v4/view/ViewCompat$ViewCompatApi19Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi19Impl",
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat",
-      "android/support/v4/os/IResultReceiver$Stub$Proxy": "androidx/os/IResultReceiver$Stub$Proxy",
-      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$BoundData": "androidx/leanback/widget/PlaybackTransportRowPresenter$BoundData",
-      "android/support/transition/TransitionSet": "androidx/transition/TransitionSet",
-      "android/support/v7/graphics/drawable/DrawableWrapper": "androidx/graphics/drawable/DrawableWrapper",
-      "android/support/v7/media/MediaRouterJellybean$UserRouteInfo": "androidx/media/MediaRouterJellybean$UserRouteInfo",
-      "android/support/v7/app/MediaRouteActionProvider": "androidx/app/MediaRouteActionProvider",
-      "android/support/compat/R$layout": "androidx/compat/R$layout",
-      "android/support/v17/leanback/widget/ViewHolderTask": "androidx/leanback/widget/ViewHolderTask",
-      "android/support/v7/graphics/ColorCutQuantizer$Vbox": "androidx/graphics/ColorCutQuantizer$Vbox",
-      "android/support/text/emoji/EmojiProcessor$CodepointIndexFinder": "androidx/text/emoji/EmojiProcessor$CodepointIndexFinder",
-      "android/support/v4/content/CursorLoader": "androidx/content/CursorLoader",
-      "android/support/text/emoji/widget/EditTextAttributeHelper": "androidx/text/emoji/widget/EditTextAttributeHelper",
-      "android/support/wear/internal/widget/ResourcesUtil": "androidx/wear/internal/widget/ResourcesUtil",
-      "android/support/wear/R$array": "androidx/wear/R$array",
-      "android/support/v7/widget/RecyclerView$RecycledViewPool": "androidx/widget/RecyclerView$RecycledViewPool",
-      "android/support/transition/ImageViewUtilsApi14": "androidx/transition/ImageViewUtilsApi14",
-      "android/support/v7/gridlayout/R": "androidx/gridlayout/R",
-      "android/support/text/emoji/FontRequestEmojiCompatConfig": "androidx/text/emoji/FontRequestEmojiCompatConfig",
-      "android/support/text/emoji/EmojiMetadata": "androidx/text/emoji/EmojiMetadata",
-      "android/support/v4/widget/SlidingPaneLayout$DisableLayerRunnable": "androidx/widget/SlidingPaneLayout$DisableLayerRunnable",
-      "android/support/v4/util/Pools$SynchronizedPool": "androidx/util/Pools$SynchronizedPool",
-      "android/support/v17/leanback/graphics/BoundsRule$ValueRule": "androidx/leanback/graphics/BoundsRule$ValueRule",
-      "android/support/v7/widget/ActivityChooserView$ActivityChooserViewAdapter": "androidx/widget/ActivityChooserView$ActivityChooserViewAdapter",
-      "android/support/v7/mediarouter/R": "androidx/mediarouter/R",
-      "android/support/text/emoji/FontRequestEmojiCompatConfig$ExponentialBackoffRetryPolicy": "androidx/text/emoji/FontRequestEmojiCompatConfig$ExponentialBackoffRetryPolicy",
-      "android/support/v7/widget/AppCompatImageView": "androidx/widget/AppCompatImageView",
-      "android/support/v17/preference/R$layout": "androidx/leanback/preference/R$layout",
-      "android/support/v4/provider/FontsContractCompat$FontFamilyResult$FontResultStatus": "androidx/provider/FontsContractCompat$FontFamilyResult$FontResultStatus",
-      "android/support/graphics/drawable/VectorDrawableCompat$VPathRenderer": "androidx/graphics/drawable/VectorDrawableCompat$VPathRenderer",
-      "android/support/v4/app/JobIntentService$CompatWorkEnqueuer": "androidx/app/JobIntentService$CompatWorkEnqueuer",
-      "android/support/v17/leanback/app/BrowseSupportFragment$SetSelectionRunnable": "androidx/leanback/app/BrowseSupportFragment$SetSelectionRunnable",
-      "android/support/v4/media/MediaDescriptionCompatApi23$Builder": "androidx/media/MediaDescriptionCompatApi23$Builder",
-      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter": "androidx/leanback/widget/DetailsOverviewRowPresenter",
-      "android/support/text/emoji/FontRequestEmojiCompatConfig$RetryPolicy": "androidx/text/emoji/FontRequestEmojiCompatConfig$RetryPolicy",
-      "android/support/v7/widget/ScrollingTabContainerView$TabView": "androidx/widget/ScrollingTabContainerView$TabView",
-      "android/support/annotation/DrawableRes": "androidx/annotation/DrawableRes",
-      "android/support/v4/view/ViewPager$LayoutParams": "androidx/view/ViewPager$LayoutParams",
-      "android/support/v17/leanback/widget/MediaItemActionPresenter$ViewHolder": "androidx/leanback/widget/MediaItemActionPresenter$ViewHolder",
-      "android/support/v7/app/AlertDialog$Builder": "androidx/app/AlertDialog$Builder",
-      "android/support/v4/util/Preconditions": "androidx/util/Preconditions",
-      "android/support/v4/app/FragmentTabHost": "androidx/app/FragmentTabHost",
-      "android/support/v17/leanback/widget/BaseGridView$OnTouchInterceptListener": "androidx/leanback/widget/BaseGridView$OnTouchInterceptListener",
-      "android/support/text/emoji/EmojiCompat$ListenerDispatcher": "androidx/text/emoji/EmojiCompat$ListenerDispatcher",
-      "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuListener": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuListener",
-      "android/support/v4/app/INotificationSideChannel$Stub$Proxy": "androidx/app/INotificationSideChannel$Stub$Proxy",
-      "android/support/media/tv/TvContractCompat$Programs$Genres$Genre": "androidx/media/tv/TvContractCompat$Programs$Genres$Genre",
-      "android/support/text/emoji/widget/EmojiTextWatcher$InitCallbackImpl": "androidx/text/emoji/widget/EmojiTextWatcher$InitCallbackImpl",
-      "android/support/v17/leanback/widget/ParallaxTarget$DirectPropertyTarget": "androidx/leanback/widget/ParallaxTarget$DirectPropertyTarget",
-      "android/support/v7/app/ToolbarActionBar$ToolbarCallbackWrapper": "androidx/app/ToolbarActionBar$ToolbarCallbackWrapper",
-      "android/support/v4/widget/CompoundButtonCompat": "androidx/widget/CompoundButtonCompat",
-      "android/support/v4/content/ContentResolverCompat": "androidx/content/ContentResolverCompat",
-      "android/support/v17/leanback/widget/NonOverlappingRelativeLayout": "androidx/leanback/widget/NonOverlappingRelativeLayout",
-      "android/support/text/emoji/EmojiCompat$MetadataRepoLoaderCallback": "androidx/text/emoji/EmojiCompat$MetadataRepoLoaderCallback",
-      "android/support/v4/app/FragmentStatePagerAdapter": "androidx/app/FragmentStatePagerAdapter",
-      "android/support/v17/leanback/app/PlaybackSupportFragment": "androidx/leanback/app/PlaybackSupportFragment",
-      "android/support/v7/app/OverlayListView": "androidx/app/OverlayListView",
-      "android/support/v7/mediarouter/R$styleable": "androidx/mediarouter/R$styleable",
-      "android/support/v7/widget/DrawableUtils": "androidx/widget/DrawableUtils",
-      "android/support/v4/content/ModernAsyncTask$AsyncTaskResult": "androidx/content/ModernAsyncTask$AsyncTaskResult",
-      "android/support/v4/app/SharedElementCallback": "androidx/app/SharedElementCallback",
-      "android/support/text/emoji/widget/EmojiKeyListener": "androidx/text/emoji/widget/EmojiKeyListener",
-      "android/support/v17/leanback/transition/FadeAndShortSlide$CalculateSlide": "androidx/leanback/transition/FadeAndShortSlide$CalculateSlide",
-      "android/support/v7/widget/ActionMenuPresenter$ActionButtonSubmenu": "androidx/widget/ActionMenuPresenter$ActionButtonSubmenu",
-      "android/support/v4/media/MediaMetadataCompat$Builder": "androidx/media/MediaMetadataCompat$Builder",
-      "android/support/design/widget/BottomSheetBehavior$SavedState": "androidx/design/widget/BottomSheetBehavior$SavedState",
-      "android/support/v4/media/session/MediaControllerCompatApi21$PlaybackInfo": "androidx/media/session/MediaControllerCompatApi21$PlaybackInfo",
-      "android/support/v7/widget/ActionMenuPresenter$PopupPresenterCallback": "androidx/widget/ActionMenuPresenter$PopupPresenterCallback",
-      "android/support/media/ExifInterface$ByteOrderedDataOutputStream": "androidx/media/ExifInterface$ByteOrderedDataOutputStream",
-      "android/support/v17/leanback/widget/Grid$Location": "androidx/leanback/widget/Grid$Location",
-      "android/support/v7/media/MediaRouterJellybeanMr1$CallbackProxy": "androidx/media/MediaRouterJellybeanMr1$CallbackProxy",
-      "android/support/v17/leanback/R$raw": "androidx/leanback/R$raw",
-      "android/support/media/tv/TvContractCompat$PreviewProgramColumns": "androidx/media/tv/TvContractCompat$PreviewProgramColumns",
-      "android/support/v17/leanback/widget/SeekBar$AccessibilitySeekListener": "androidx/leanback/widget/SeekBar$AccessibilitySeekListener",
-      "android/support/v4/print/PrintHelper$PrintHelperVersionImpl": "androidx/print/PrintHelper$PrintHelperVersionImpl",
-      "android/support/v17/leanback/app/ProgressBarManager": "androidx/leanback/app/ProgressBarManager",
-      "android/support/v7/app/MediaRouteChooserDialogFragment": "androidx/app/MediaRouteChooserDialogFragment",
-      "android/support/v4/content/FileProvider$SimplePathStrategy": "androidx/content/FileProvider$SimplePathStrategy",
-      "android/support/v17/leanback/app/BackgroundManager$BackgroundContinuityService": "androidx/leanback/app/BackgroundManager$BackgroundContinuityService",
-      "android/support/v4/media/session/IMediaSession$Stub": "androidx/media/session/IMediaSession$Stub",
-      "android/support/v4/widget/TintableImageSourceView": "androidx/widget/TintableImageSourceView",
-      "android/support/transition/ViewOverlayApi14$OverlayViewGroup": "androidx/transition/ViewOverlayApi14$OverlayViewGroup",
-      "android/support/design/widget/FloatingActionButtonImpl": "androidx/design/widget/FloatingActionButtonImpl",
-      "android/support/text/emoji/widget/EmojiEditableFactory": "androidx/text/emoji/widget/EmojiEditableFactory",
-      "android/support/transition/Visibility$Mode": "androidx/transition/Visibility$Mode",
-      "android/support/v17/leanback/widget/PagingIndicator$Dot": "androidx/leanback/widget/PagingIndicator$Dot",
-      "android/support/design/internal/NavigationSubMenu": "androidx/design/internal/NavigationSubMenu",
-      "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder",
-      "android/support/v4/media/AudioAttributesCompat$AudioManagerHidden": "androidx/media/AudioAttributesCompat$AudioManagerHidden",
-      "android/support/v7/preference/CheckBoxPreference": "androidx/preference/CheckBoxPreference",
-      "android/support/design/widget/FloatingActionButtonLollipop$AlwaysStatefulGradientDrawable": "androidx/design/widget/FloatingActionButtonLollipop$AlwaysStatefulGradientDrawable",
-      "android/support/v4/media/RatingCompat$StarStyle": "androidx/media/RatingCompat$StarStyle",
-      "android/support/v7/preference/PreferenceGroup$PreferencePositionCallback": "androidx/preference/PreferenceGroup$PreferencePositionCallback",
-      "android/support/design/widget/BottomNavigationView": "androidx/design/widget/BottomNavigationView",
-      "android/support/v17/leanback/media/MediaPlayerAdapter": "androidx/leanback/media/MediaPlayerAdapter",
-      "android/support/v7/widget/SuggestionsAdapter$ChildViewCache": "androidx/widget/SuggestionsAdapter$ChildViewCache",
-      "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi21": "androidx/media/session/MediaSessionCompat$Callback$StubApi21",
-      "android/support/v7/widget/ListPopupWindow$PopupScrollListener": "androidx/widget/ListPopupWindow$PopupScrollListener",
-      "android/support/v4/app/NotificationCompat$MessagingStyle": "androidx/app/NotificationCompat$MessagingStyle",
-      "android/support/wear/widget/SwipeDismissLayout$OnSwipeProgressChangedListener": "androidx/wear/widget/SwipeDismissLayout$OnSwipeProgressChangedListener",
-      "android/support/v7/media/RemotePlaybackClient$OnMessageReceivedListener": "androidx/media/RemotePlaybackClient$OnMessageReceivedListener",
-      "android/support/v7/util/MessageThreadUtil$SyncQueueItem": "androidx/util/MessageThreadUtil$SyncQueueItem",
-      "android/support/v4/view/MarginLayoutParamsCompat": "androidx/view/MarginLayoutParamsCompat",
-      "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi24": "androidx/media/session/MediaSessionCompat$Callback$StubApi24",
-      "android/support/v17/leanback/widget/CheckableImageView": "androidx/leanback/widget/CheckableImageView",
-      "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi23": "androidx/media/session/MediaSessionCompat$Callback$StubApi23",
-      "android/support/v7/widget/ThemeUtils": "androidx/widget/ThemeUtils",
-      "android/support/v7/preference/Preference$BaseSavedState": "androidx/preference/Preference$BaseSavedState",
-      "android/support/v4/widget/DrawerLayout$AccessibilityDelegate": "androidx/widget/DrawerLayout$AccessibilityDelegate",
-      "android/support/v4/app/ActivityOptionsCompat": "androidx/app/ActivityOptionsCompat",
-      "android/support/v4/media/session/PlaybackStateCompat$State": "androidx/media/session/PlaybackStateCompat$State",
-      "android/support/v7/widget/RecyclerView$ItemAnimator$ItemHolderInfo": "androidx/widget/RecyclerView$ItemAnimator$ItemHolderInfo",
-      "android/support/constraint/solver/widgets/ConstraintAnchor$Type": "androidx/constraint/solver/widgets/ConstraintAnchor$Type",
-      "android/support/v4/widget/TextViewCompat$TextViewCompatApi17Impl": "androidx/widget/TextViewCompat$TextViewCompatApi17Impl",
-      "android/support/v17/leanback/widget/ImeKeyMonitor": "androidx/leanback/widget/ImeKeyMonitor",
-      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapter": "androidx/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapter",
-      "android/support/v4/app/ActivityCompat": "androidx/app/legacy/ActivityCompat",
-      "android/support/v4/util/ObjectsCompat": "androidx/util/ObjectsCompat",
-      "android/support/v4/app/SupportActivity$ExtraData": "androidx/app/SupportActivity$ExtraData",
-      "android/support/v4/media/MediaBrowserProtocol": "androidx/media/MediaBrowserProtocol",
-      "android/support/design/widget/CollapsingTextHelper": "androidx/design/widget/CollapsingTextHelper",
-      "android/support/v14/preference/SwitchPreference$Listener": "androidx/preference/SwitchPreference$Listener",
-      "android/support/v7/preference/SwitchPreferenceCompat$Listener": "androidx/preference/SwitchPreferenceCompat$Listener",
-      "android/support/wear/internal/widget/drawer/SinglePageUi": "androidx/wear/internal/widget/drawer/SinglePageUi",
-      "android/support/v4/view/NestedScrollingChild2": "androidx/view/NestedScrollingChild2",
-      "android/support/customtabs/ICustomTabsService": "androidx/browser/customtabs/ICustomTabsService",
-      "android/support/text/emoji/widget/EmojiAppCompatTextView": "androidx/text/emoji/widget/EmojiAppCompatTextView",
-      "android/support/v7/media/MediaRouterJellybean$RouteGroup": "androidx/media/MediaRouterJellybean$RouteGroup",
-      "android/support/v4/widget/DrawerLayout": "androidx/widget/DrawerLayout",
-      "android/support/v4/os/CancellationSignal$OnCancelListener": "androidx/os/CancellationSignal$OnCancelListener",
-      "android/support/v4/view/ViewCompat$ViewCompatApi17Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi17Impl",
-      "android/support/v4/app/JobIntentService$CompatJobEngine": "androidx/app/JobIntentService$CompatJobEngine",
-      "android/support/v4/media/MediaBrowserCompat$CustomActionCallback": "androidx/media/MediaBrowserCompat$CustomActionCallback",
-      "android/support/v4/media/app/NotificationCompat$DecoratedMediaCustomViewStyle": "androidx/media/app/NotificationCompat$DecoratedMediaCustomViewStyle",
-      "android/support/v7/app/ActionBarDrawerToggle$Delegate": "androidx/app/ActionBarDrawerToggle$Delegate",
-      "android/support/v17/leanback/R$anim": "androidx/leanback/R$anim",
-      "android/support/v13/app/FragmentCompat$FragmentCompatBaseImpl": "androidx/app/FragmentCompat$FragmentCompatBaseImpl",
-      "android/support/v7/widget/SearchView$OnCloseListener": "androidx/widget/SearchView$OnCloseListener",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$OnPlaybackProgressCallback": "androidx/leanback/widget/PlaybackControlsRow$OnPlaybackProgressCallback",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$MoreActions": "androidx/leanback/widget/PlaybackControlsRow$MoreActions",
-      "android/support/v7/widget/ActivityChooserModel$ActivityResolveInfo": "androidx/widget/ActivityChooserModel$ActivityResolveInfo",
-      "android/support/annotation/AnimRes": "androidx/annotation/AnimRes",
-      "android/support/animation/Force": "androidx/animation/Force",
-      "android/support/v17/leanback/util/StateMachine$Event": "androidx/leanback/util/StateMachine$Event",
-      "android/support/v17/leanback/app/BrowseFragment$MainFragmentRowsAdapter": "androidx/leanback/app/BrowseFragment$MainFragmentRowsAdapter",
-      "android/support/v4/graphics/BitmapCompat": "androidx/graphics/BitmapCompat",
-      "android/support/v4/app/NotificationCompat$NotificationVisibility": "androidx/app/NotificationCompat$NotificationVisibility",
-      "android/support/v17/leanback/app/PlaybackFragment$SetSelectionRunnable": "androidx/leanback/app/PlaybackFragment$SetSelectionRunnable",
-      "android/support/v7/media/RegisteredMediaRouteProviderWatcher$Callback": "androidx/media/RegisteredMediaRouteProviderWatcher$Callback",
-      "android/support/v4/view/ViewCompat$FocusDirection": "androidx/view/legacy/ViewCompat$FocusDirection",
-      "android/support/design/widget/BottomSheetBehavior$SettleRunnable": "androidx/design/widget/BottomSheetBehavior$SettleRunnable",
-      "android/support/v17/leanback/widget/RoundedRectHelperApi21$RoundedRectOutlineProvider": "androidx/leanback/widget/RoundedRectHelperApi21$RoundedRectOutlineProvider",
-      "android/support/wear/widget/drawer/FlingWatcherFactory": "androidx/wear/widget/drawer/FlingWatcherFactory",
-      "android/support/v4/app/NotificationManagerCompat$Task": "androidx/app/NotificationManagerCompat$Task",
-      "android/support/animation/FlingAnimation$DragForce": "androidx/animation/FlingAnimation$DragForce",
-      "android/support/v7/widget/GridLayout$MutableInt": "androidx/widget/GridLayout$MutableInt",
-      "android/support/v7/util/DiffUtil": "androidx/util/DiffUtil",
-      "android/support/v4/app/FragmentManagerImpl$OpGenerator": "androidx/app/FragmentManagerImpl$OpGenerator",
-      "android/support/v4/view/ViewPager": "androidx/widget/ViewPager",
-      "android/support/v7/widget/TintTypedArray": "androidx/widget/TintTypedArray",
-      "android/support/text/emoji/widget/EmojiAppCompatEditText": "androidx/text/emoji/widget/EmojiAppCompatEditText",
-      "android/support/v4/view/ViewGroupCompat$ViewGroupCompatApi21Impl": "androidx/view/ViewGroupCompat$ViewGroupCompatApi21Impl",
-      "android/support/v4/media/MediaBrowserServiceCompat$ConnectionRecord": "androidx/media/MediaBrowserServiceCompat$ConnectionRecord",
-      "android/support/v7/view/menu/ActionMenuItemView": "androidx/view/menu/ActionMenuItemView",
-      "android/support/v4/app/NotificationCompatExtras": "androidx/app/NotificationCompatExtras",
-      "android/support/v7/view/menu/ListMenuPresenter": "androidx/view/menu/ListMenuPresenter",
-      "android/support/v14/preference/R": "androidx/preference/R",
-      "android/support/annotation/RequiresPermission": "androidx/annotation/RequiresPermission",
-      "android/support/v4/app/JobIntentService$GenericWorkItem": "androidx/app/JobIntentService$GenericWorkItem",
-      "android/support/v7/widget/RecyclerView$SmoothScroller$Action": "androidx/widget/RecyclerView$SmoothScroller$Action",
-      "android/support/design/R$attr": "androidx/design/R$attr",
-      "android/support/v4/content/SharedPreferencesCompat$EditorCompat$Helper": "androidx/content/SharedPreferencesCompat$EditorCompat$Helper",
-      "android/support/constraint/solver/widgets/ConstraintWidget": "androidx/constraint/solver/widgets/ConstraintWidget",
-      "android/support/design/widget/NavigationView": "androidx/design/widget/NavigationView",
-      "android/support/v4/media/session/PlaybackStateCompatApi22": "androidx/media/session/PlaybackStateCompatApi22",
-      "android/support/v4/media/session/PlaybackStateCompatApi21": "androidx/media/session/PlaybackStateCompatApi21",
-      "android/support/media/instantvideo/preload/InstantVideoPreloadManager$InternalVideoPreloaderFactory": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$InternalVideoPreloaderFactory",
-      "android/support/design/widget/BaseTransientBottomBar": "androidx/design/widget/BaseTransientBottomBar",
-      "android/support/wear/internal/widget/drawer/WearableNavigationDrawerPresenter": "androidx/wear/internal/widget/drawer/WearableNavigationDrawerPresenter",
-      "android/support/v4/media/session/MediaControllerCompat$Callback$StubApi21": "androidx/media/session/MediaControllerCompat$Callback$StubApi21",
-      "android/support/wear/widget/drawer/ScrollViewFlingWatcher": "androidx/wear/widget/drawer/ScrollViewFlingWatcher",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$FastForwardAction": "androidx/leanback/widget/PlaybackControlsRow$FastForwardAction",
-      "android/support/v7/widget/ActionBarOverlayLayout": "androidx/widget/ActionBarOverlayLayout",
-      "android/support/v4/app/FragmentTabHost$TabInfo": "androidx/app/FragmentTabHost$TabInfo",
-      "android/support/v7/widget/GridLayout$Bounds": "androidx/widget/GridLayout$Bounds",
-      "android/support/v7/app/ActionBar$OnMenuVisibilityListener": "androidx/app/ActionBar$OnMenuVisibilityListener",
-      "android/support/customtabs/PostMessageServiceConnection": "androidx/browser/customtabs/PostMessageServiceConnection",
-      "android/support/design/widget/TextInputLayout$TextInputAccessibilityDelegate": "androidx/design/widget/TextInputLayout$TextInputAccessibilityDelegate",
-      "android/support/v7/preference/Preference$OnPreferenceClickListener": "androidx/preference/Preference$OnPreferenceClickListener",
-      "android/support/v7/media/MediaRouterJellybean$RouteCategory": "androidx/media/MediaRouterJellybean$RouteCategory",
-      "android/support/v4/text/TextDirectionHeuristicCompat": "androidx/text/TextDirectionHeuristicCompat",
-      "android/support/v4/view/PointerIconCompat": "androidx/view/PointerIconCompat",
-      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuAdapter": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuAdapter",
-      "android/support/v17/leanback/widget/BaseCardView$AnimationBase": "androidx/leanback/widget/BaseCardView$AnimationBase",
-      "android/support/v7/widget/ScrollingTabContainerView": "androidx/widget/ScrollingTabContainerView",
-      "android/support/v4/text/util/LinkifyCompat": "androidx/text/util/LinkifyCompat",
-      "android/support/annotation/RequiresPermission$Read": "androidx/annotation/RequiresPermission$Read",
-      "android/support/customtabs/CustomTabsService$Result": "androidx/browser/customtabs/CustomTabsService$Result",
-      "android/support/v7/app/MediaRouteControllerDialog": "androidx/app/MediaRouteControllerDialog",
-      "android/support/v17/leanback/app/BrowseFragment": "androidx/leanback/app/BrowseFragment",
-      "android/support/v17/leanback/widget/OnChildViewHolderSelectedListener": "androidx/leanback/widget/OnChildViewHolderSelectedListener",
-      "android/support/design/internal/NavigationMenuPresenter$SubheaderViewHolder": "androidx/design/internal/NavigationMenuPresenter$SubheaderViewHolder",
-      "android/support/v7/mediarouter/R$attr": "androidx/mediarouter/R$attr",
-      "android/support/v7/widget/ActivityChooserView$Callbacks": "androidx/widget/ActivityChooserView$Callbacks",
-      "android/support/v4/widget/TextViewCompat$TextViewCompatApi16Impl": "androidx/widget/TextViewCompat$TextViewCompatApi16Impl",
-      "android/support/v4/content/AsyncTaskLoader$LoadTask": "androidx/content/AsyncTaskLoader$LoadTask",
-      "android/support/v17/leanback/widget/GuidedActionAdapter$ActionOnFocusListener": "androidx/leanback/widget/GuidedActionAdapter$ActionOnFocusListener",
-      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl": "androidx/media/SystemMediaRouteProvider$LegacyImpl",
-      "android/support/transition/ViewUtils": "androidx/transition/ViewUtils",
-      "android/support/v17/leanback/app/RowsSupportFragment$RowViewHolderExtra": "androidx/leanback/app/RowsSupportFragment$RowViewHolderExtra",
-      "android/support/v17/leanback/widget/ActionPresenterSelector$TwoLineActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$TwoLineActionPresenter",
-      "android/support/v7/recyclerview/R$dimen": "androidx/recyclerview/R$dimen",
-      "android/support/v7/app/TwilightCalculator": "androidx/app/TwilightCalculator",
-      "android/support/v17/leanback/widget/ResizingTextView": "androidx/leanback/widget/ResizingTextView",
-      "android/support/design/widget/ViewUtilsLollipop": "androidx/design/widget/ViewUtilsLollipop",
-      "android/support/media/tv/TvContractCompat$PreviewProgramColumns$Availability": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$Availability",
-      "android/support/v7/media/RemotePlaybackClient$ActionCallback": "androidx/media/RemotePlaybackClient$ActionCallback",
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$Listener": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$Listener",
-      "android/support/v4/app/FragmentManagerImpl$AnimatorOnHWLayerIfNeededListener": "androidx/app/FragmentManagerImpl$AnimatorOnHWLayerIfNeededListener",
-      "android/support/v17/leanback/transition/TransitionHelper": "androidx/leanback/transition/TransitionHelper",
-      "android/support/v7/view/SupportActionModeWrapper$CallbackWrapper": "androidx/view/SupportActionModeWrapper$CallbackWrapper",
-      "android/support/v13/app/FragmentStatePagerAdapter": "androidx/app/legacy/FragmentStatePagerAdapter",
-      "android/support/v7/graphics/Palette$PaletteAsyncListener": "androidx/graphics/Palette$PaletteAsyncListener",
-      "android/support/v4/media/MediaBrowserServiceCompat": "androidx/media/MediaBrowserServiceCompat",
-      "android/support/v4/widget/NestedScrollView": "androidx/widget/NestedScrollView",
-      "android/support/v4/media/MediaBrowserCompat$ItemCallback$StubApi23": "androidx/media/MediaBrowserCompat$ItemCallback$StubApi23",
-      "android/support/v4/text/BidiFormatter$DirectionalityEstimator": "androidx/text/BidiFormatter$DirectionalityEstimator",
-      "android/support/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader",
-      "android/support/transition/ChangeClipBounds": "androidx/transition/ChangeClipBounds",
-      "android/support/v7/widget/PositionMap": "androidx/widget/PositionMap",
-      "android/support/v17/leanback/widget/ItemBridgeAdapter$ViewHolder": "androidx/leanback/widget/ItemBridgeAdapter$ViewHolder",
-      "android/support/v7/widget/TintContextWrapper": "androidx/widget/TintContextWrapper",
-      "android/support/v7/widget/MenuItemHoverListener": "androidx/widget/MenuItemHoverListener",
-      "android/support/v4/app/RemoteInputCompatBase": "androidx/app/RemoteInputCompatBase",
-      "android/support/v17/leanback/media/SurfaceHolderGlueHost": "androidx/leanback/media/SurfaceHolderGlueHost",
-      "android/support/v7/widget/LinearLayoutManager$LayoutChunkResult": "androidx/widget/LinearLayoutManager$LayoutChunkResult",
-      "android/support/v7/view/menu/MenuPresenter": "androidx/view/menu/MenuPresenter",
-      "android/support/v7/media/MediaRouterJellybean": "androidx/media/MediaRouterJellybean",
-      "android/support/annotation/ArrayRes": "androidx/annotation/ArrayRes",
-      "android/support/v4/media/session/MediaSessionCompat$ResultReceiverWrapper": "androidx/media/session/MediaSessionCompat$ResultReceiverWrapper",
-      "android/support/v17/leanback/widget/FocusHighlightHelper": "androidx/leanback/widget/FocusHighlightHelper",
-      "android/support/v4/media/session/MediaControllerCompatApi21$TransportControls": "androidx/media/session/MediaControllerCompatApi21$TransportControls",
-      "android/support/v4/media/MediaBrowserCompatApi21$SubscriptionCallbackProxy": "androidx/media/MediaBrowserCompatApi21$SubscriptionCallbackProxy",
-      "android/support/v7/mediarouter/R$dimen": "androidx/mediarouter/R$dimen",
-      "android/support/v4/app/NotificationManagerCompat$CancelTask": "androidx/app/NotificationManagerCompat$CancelTask",
-      "android/support/design/widget/BottomSheetBehavior$BottomSheetCallback": "androidx/design/widget/BottomSheetBehavior$BottomSheetCallback",
-      "android/support/v4/os/LocaleListCompat": "androidx/os/LocaleListCompat",
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection",
-      "android/support/design/internal/BottomNavigationPresenter": "androidx/design/internal/BottomNavigationPresenter",
-      "android/support/v7/view/SupportMenuInflater": "androidx/view/SupportMenuInflater",
-      "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi16Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi16Impl",
-      "android/support/transition/AutoTransition": "androidx/transition/AutoTransition",
-      "android/support/v7/widget/RoundRectDrawable": "androidx/widget/RoundRectDrawable",
-      "android/support/graphics/drawable/VectorDrawableCompat$VFullPath": "androidx/graphics/drawable/VectorDrawableCompat$VFullPath",
-      "android/support/v4/widget/ListViewAutoScrollHelper": "androidx/widget/ListViewAutoScrollHelper",
-      "android/support/v4/media/MediaBrowserCompatApi21$MediaItem": "androidx/media/MediaBrowserCompatApi21$MediaItem",
-      "android/support/transition/FloatArrayEvaluator": "androidx/transition/FloatArrayEvaluator",
-      "android/support/design/widget/CollapsingToolbarLayout$OffsetUpdateListener": "androidx/design/widget/CollapsingToolbarLayout$OffsetUpdateListener",
-      "android/support/v7/preference/PreferenceManager$OnPreferenceTreeClickListener": "androidx/preference/PreferenceManager$OnPreferenceTreeClickListener",
-      "android/support/v17/leanback/widget/Parallax": "androidx/leanback/widget/Parallax",
-      "android/support/v4/media/MediaBrowserCompat$ConnectionCallback$StubApi21": "androidx/media/MediaBrowserCompat$ConnectionCallback$StubApi21",
-      "android/support/v4/os/CancellationSignal": "androidx/os/CancellationSignal",
-      "android/support/v17/leanback/media/PlaybackGlue$PlayerCallback": "androidx/leanback/media/PlaybackGlue$PlayerCallback",
-      "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatApi21Impl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatApi21Impl",
-      "android/support/design/internal/BottomNavigationItemView": "androidx/design/internal/BottomNavigationItemView",
-      "android/support/v4/view/ViewGroupCompat$ViewGroupCompatApi18Impl": "androidx/view/ViewGroupCompat$ViewGroupCompatApi18Impl",
-      "android/support/text/emoji/flatbuffer/Struct": "androidx/text/emoji/flatbuffer/Struct",
-      "android/support/v17/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter": "androidx/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter",
-      "android/support/v4/view/ViewCompat$ViewCompatApi21Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi21Impl",
-      "android/support/v17/leanback/widget/SearchEditText$OnKeyboardDismissListener": "androidx/leanback/widget/SearchEditText$OnKeyboardDismissListener",
-      "android/support/annotation/AttrRes": "androidx/annotation/AttrRes",
-      "android/support/v17/leanback/app/BrowseFragment$FragmentHostImpl": "androidx/leanback/app/BrowseFragment$FragmentHostImpl",
-      "android/support/v4/graphics/PathParser": "androidx/graphics/PathParser",
-      "android/support/v17/leanback/app/BackgroundManager$BitmapDrawable": "androidx/leanback/app/BackgroundManager$BitmapDrawable",
-      "android/support/v4/util/MapCollections$ArrayIterator": "androidx/util/MapCollections$ArrayIterator",
-      "android/support/v4/view/AsyncLayoutInflater": "androidx/view/AsyncLayoutInflater",
-      "android/support/v4/media/MediaBrowserServiceCompat$Result": "androidx/media/MediaBrowserServiceCompat$Result",
-      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImpl": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImpl",
-      "android/support/v17/leanback/app/RowsFragment$MainFragmentAdapter": "androidx/leanback/app/RowsFragment$MainFragmentAdapter",
-      "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout": "androidx/internal/widget/OutlineOnlyWithChildrenFrameLayout",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21$ExtraSession": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi21$ExtraSession",
-      "android/support/v17/leanback/util/MathUtil": "androidx/leanback/util/MathUtil",
-      "android/support/v4/app/RemoteInputCompatBase$RemoteInput$Factory": "androidx/app/RemoteInputCompatBase$RemoteInput$Factory",
-      "android/support/animation/DynamicAnimation": "androidx/animation/DynamicAnimation",
-      "android/support/transition/Visibility": "androidx/transition/Visibility",
-      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi21Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi21Impl",
-      "android/support/v7/app/AppCompatViewInflater": "androidx/app/AppCompatViewInflater",
-      "android/support/v7/widget/ListPopupWindow$PopupTouchInterceptor": "androidx/widget/ListPopupWindow$PopupTouchInterceptor",
-      "android/support/v4/app/ServiceCompat$StopForegroundFlags": "androidx/app/ServiceCompat$StopForegroundFlags",
-      "android/support/graphics/drawable/VectorDrawableCompat$VClipPath": "androidx/graphics/drawable/VectorDrawableCompat$VClipPath",
-      "android/support/v7/app/MediaRouteControllerDialog$VolumeGroupAdapter": "androidx/app/MediaRouteControllerDialog$VolumeGroupAdapter",
-      "android/support/design/R$style": "androidx/design/R$style",
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi26": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi26",
-      "android/support/constraint/R$styleable": "androidx/constraint/R$styleable",
-      "android/support/v7/media/MediaRouterJellybeanMr1$RouteInfo": "androidx/media/MediaRouterJellybeanMr1$RouteInfo",
-      "android/support/v4/widget/CircleImageView$OvalShadow": "androidx/widget/CircleImageView$OvalShadow",
-      "android/support/v7/preference/ListPreferenceDialogFragmentCompat": "androidx/preference/ListPreferenceDialogFragmentCompat",
-      "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceStartFragmentCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceStartFragmentCallback",
-      "android/support/v4/view/PagerTitleStrip$PageListener": "androidx/view/PagerTitleStrip$PageListener",
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21",
-      "android/support/v7/app/AppCompatDelegate$ApplyableNightMode": "androidx/app/AppCompatDelegate$ApplyableNightMode",
-      "android/support/customtabs/ICustomTabsCallback": "androidx/browser/customtabs/ICustomTabsCallback",
-      "android/support/v17/preference/LeanbackListPreferenceDialogFragment": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment",
-      "android/support/v17/leanback/widget/PresenterSwitcher": "androidx/leanback/widget/PresenterSwitcher",
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi23": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi23",
-      "android/support/v17/leanback/widget/ShadowOverlayHelper$Options": "androidx/leanback/widget/ShadowOverlayHelper$Options",
-      "android/support/v4/text/TextDirectionHeuristicsCompat$FirstStrong": "androidx/text/TextDirectionHeuristicsCompat$FirstStrong",
-      "android/support/v7/widget/AppCompatSeekBar": "androidx/widget/AppCompatSeekBar",
-      "android/support/v17/leanback/widget/Util": "androidx/leanback/widget/Util",
-      "android/support/v4/util/MapCollections": "androidx/util/MapCollections",
-      "android/support/v4/widget/NestedScrollView$SavedState": "androidx/widget/NestedScrollView$SavedState",
-      "android/support/v7/widget/SimpleItemAnimator": "androidx/widget/SimpleItemAnimator",
-      "android/support/v4/media/MediaMetadataCompatApi21$Builder": "androidx/media/MediaMetadataCompatApi21$Builder",
-      "android/support/design/widget/DrawableUtils": "androidx/design/widget/DrawableUtils",
-      "android/support/wear/internal/widget/drawer/SinglePagePresenter": "androidx/wear/internal/widget/drawer/SinglePagePresenter",
-      "android/support/v4/app/FragmentContainer": "androidx/app/FragmentContainer",
-      "android/support/v7/media/MediaRouteProviderDescriptor": "androidx/media/MediaRouteProviderDescriptor",
-      "android/support/v4/media/session/PlaybackStateCompat$Actions": "androidx/media/session/PlaybackStateCompat$Actions",
-      "android/support/v14/preference/ListPreferenceDialogFragment": "androidx/preference/ListPreferenceDialogFragment",
-      "android/support/v4/widget/SwipeRefreshLayout$OnChildScrollUpCallback": "androidx/widget/SwipeRefreshLayout$OnChildScrollUpCallback",
-      "android/support/v4/media/AudioAttributesCompatApi21": "androidx/media/AudioAttributesCompatApi21",
-      "android/support/v7/media/MediaRouter$Callback": "androidx/media/MediaRouter$Callback",
-      "android/support/v4/content/pm/ShortcutInfoCompat$Builder": "androidx/content/pm/ShortcutInfoCompat$Builder",
-      "android/support/v7/util/SortedList$BatchedCallback": "androidx/util/SortedList$BatchedCallback",
-      "android/support/v7/cardview/R$style": "androidx/cardview/R$style",
-      "android/support/v7/media/MediaRouter$GlobalMediaRouter$ProviderCallback": "androidx/media/MediaRouter$GlobalMediaRouter$ProviderCallback",
-      "android/support/v4/widget/SimpleCursorAdapter$ViewBinder": "androidx/widget/SimpleCursorAdapter$ViewBinder",
-      "android/support/v7/util/TileList$Tile": "androidx/util/TileList$Tile",
-      "android/support/v17/leanback/widget/ItemBridgeAdapter$AdapterListener": "androidx/leanback/widget/ItemBridgeAdapter$AdapterListener",
-      "android/support/v4/widget/SlidingPaneLayout$DragHelperCallback": "androidx/widget/SlidingPaneLayout$DragHelperCallback",
-      "android/support/v4/media/MediaBrowserCompat$SearchResultReceiver": "androidx/media/MediaBrowserCompat$SearchResultReceiver",
-      "android/support/v17/leanback/widget/PlaybackRowPresenter": "androidx/leanback/widget/PlaybackRowPresenter",
-      "android/support/v7/media/MediaRouteProvider$ProviderMetadata": "androidx/media/MediaRouteProvider$ProviderMetadata",
-      "android/support/text/emoji/flatbuffer/MetadataList": "androidx/text/emoji/flatbuffer/MetadataList",
-      "android/support/v4/provider/TreeDocumentFile": "androidx/provider/TreeDocumentFile",
-      "android/support/v7/media/MediaSessionStatus$Builder": "androidx/media/MediaSessionStatus$Builder",
-      "android/support/text/emoji/widget/EmojiTextWatcher": "androidx/text/emoji/widget/EmojiTextWatcher",
-      "android/support/v17/leanback/app/GuidedStepSupportFragment": "androidx/leanback/app/GuidedStepSupportFragment",
-      "android/support/v17/leanback/widget/BrowseFrameLayout$OnFocusSearchListener": "androidx/leanback/widget/BrowseFrameLayout$OnFocusSearchListener",
-      "android/support/animation/AnimationHandler": "androidx/animation/AnimationHandler",
-      "android/support/wear/widget/drawer/WearableActionDrawerView": "androidx/wear/widget/drawer/WearableActionDrawerView",
-      "android/support/v4/media/MediaBrowserCompat$CustomActionResultReceiver": "androidx/media/MediaBrowserCompat$CustomActionResultReceiver",
-      "android/support/v7/widget/AppCompatSeekBarHelper": "androidx/widget/AppCompatSeekBarHelper",
-      "android/support/v4/widget/SlidingPaneLayout$AccessibilityDelegate": "androidx/widget/SlidingPaneLayout$AccessibilityDelegate",
-      "android/support/v17/leanback/widget/TitleViewAdapter$Provider": "androidx/leanback/widget/TitleViewAdapter$Provider",
-      "android/support/v7/widget/GridLayoutManager$SpanSizeLookup": "androidx/widget/GridLayoutManager$SpanSizeLookup",
-      "android/support/v4/content/res/ResourcesCompat$FontCallback": "androidx/content/res/ResourcesCompat$FontCallback",
-      "android/support/v4/util/CircularArray": "androidx/util/CircularArray",
-      "android/support/v17/leanback/util/StateMachine$State": "androidx/leanback/util/StateMachine$State",
-      "android/support/text/emoji/widget/EmojiTextView": "androidx/text/emoji/widget/EmojiTextView",
-      "android/support/v4/widget/CursorAdapter$MyDataSetObserver": "androidx/widget/CursorAdapter$MyDataSetObserver",
-      "android/support/v4/os/LocaleListCompat$LocaleListCompatBaseImpl": "androidx/os/LocaleListCompat$LocaleListCompatBaseImpl",
-      "android/support/v4/app/TaskStackBuilder$SupportParentable": "androidx/app/TaskStackBuilder$SupportParentable",
-      "android/support/v17/leanback/media/PlaybackControlGlue": "androidx/leanback/media/PlaybackControlGlue",
-      "android/support/v17/leanback/widget/GuidedActionEditText": "androidx/leanback/widget/GuidedActionEditText",
-      "android/support/v4/util/Pools$SimplePool": "androidx/util/Pools$SimplePool",
-      "android/support/v17/leanback/widget/ControlButtonPresenterSelector$ControlButtonPresenter": "androidx/leanback/widget/ControlButtonPresenterSelector$ControlButtonPresenter",
-      "android/support/v17/leanback/widget/PlaybackControlsPresenter$ViewHolder": "androidx/leanback/widget/PlaybackControlsPresenter$ViewHolder",
-      "android/support/wear/widget/drawer/WearableDrawerLayout": "androidx/wear/widget/drawer/WearableDrawerLayout",
-      "android/support/v7/widget/ActionBarContainer": "androidx/widget/ActionBarContainer",
-      "android/support/v7/widget/ShareActionProvider$ShareActivityChooserModelPolicy": "androidx/widget/ShareActionProvider$ShareActivityChooserModelPolicy",
-      "android/support/transition/ObjectAnimatorUtilsApi21": "androidx/transition/ObjectAnimatorUtilsApi21",
-      "android/support/v17/leanback/widget/BaseOnItemViewSelectedListener": "androidx/leanback/widget/BaseOnItemViewSelectedListener",
-      "android/support/v7/widget/StaggeredGridLayoutManager$LayoutParams": "androidx/widget/StaggeredGridLayoutManager$LayoutParams",
-      "android/support/v7/mediarouter/R$interpolator": "androidx/mediarouter/R$interpolator",
-      "android/support/v4/media/VolumeProviderCompatApi21": "androidx/media/VolumeProviderCompatApi21",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$PictureInPictureAction": "androidx/leanback/widget/PlaybackControlsRow$PictureInPictureAction",
-      "android/support/v7/util/MessageThreadUtil": "androidx/util/MessageThreadUtil",
-      "android/support/v4/util/LogWriter": "androidx/util/LogWriter",
-      "android/support/v7/preference/PreferenceDialogFragmentCompat": "androidx/preference/PreferenceDialogFragmentCompat",
-      "android/support/transition/ViewOverlayApi14": "androidx/transition/ViewOverlayApi14",
-      "android/support/v4/graphics/TypefaceCompatUtil": "androidx/graphics/TypefaceCompatUtil",
-      "android/support/media/tv/BasePreviewProgram": "androidx/media/tv/BasePreviewProgram",
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$DetailsOverviewRowListener": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$DetailsOverviewRowListener",
-      "android/support/v7/widget/AlertDialogLayout": "androidx/widget/AlertDialogLayout",
-      "android/support/v7/widget/ActionBarOverlayLayout$LayoutParams": "androidx/widget/ActionBarOverlayLayout$LayoutParams",
-      "android/support/v4/view/NestedScrollingParentHelper": "androidx/view/NestedScrollingParentHelper",
-      "android/support/transition/ObjectAnimatorUtilsApi14": "androidx/transition/ObjectAnimatorUtilsApi14",
-      "android/support/text/emoji/EmojiCompat": "androidx/text/emoji/EmojiCompat",
-      "android/support/v4/media/MediaBrowserServiceCompatApi23$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi23$ServiceCompatProxy",
-      "android/support/v17/leanback/widget/FocusHighlightHelper$FocusAnimator": "androidx/leanback/widget/FocusHighlightHelper$FocusAnimator",
-      "android/support/v17/leanback/app/PlaybackSupportFragment$SetSelectionRunnable": "androidx/leanback/app/PlaybackSupportFragment$SetSelectionRunnable",
-      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi23Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi23Impl",
-      "android/support/v7/preference/SwitchPreferenceCompat": "androidx/preference/SwitchPreferenceCompat",
-      "android/support/wear/widget/drawer/FlingWatcherFactory$FlingListener": "androidx/wear/widget/drawer/FlingWatcherFactory$FlingListener",
-      "android/support/v7/widget/ShareActionProvider": "androidx/widget/ShareActionProvider",
-      "android/support/v7/content/res/AppCompatResources": "androidx/content/res/AppCompatResources",
-      "android/support/transition/ViewOverlayApi18": "androidx/transition/ViewOverlayApi18",
-      "android/support/v7/widget/ListPopupWindow$ResizePopupRunnable": "androidx/widget/ListPopupWindow$ResizePopupRunnable",
-      "android/support/compat/R$integer": "androidx/compat/R$integer",
-      "android/support/v4/app/ActionBarDrawerToggle$SlideDrawable": "androidx/app/legacy/ActionBarDrawerToggle$SlideDrawable",
-      "android/support/transition/ChangeTransform$PathAnimatorMatrix": "androidx/transition/ChangeTransform$PathAnimatorMatrix",
-      "android/support/v17/leanback/graphics/ColorFilterDimmer": "androidx/leanback/graphics/ColorFilterDimmer",
-      "android/support/v7/media/MediaRouteDescriptor": "androidx/media/MediaRouteDescriptor",
-      "android/support/v14/preference/PreferenceFragment$ScrollToPreferenceObserver": "androidx/preference/PreferenceFragment$ScrollToPreferenceObserver",
-      "android/support/v4/media/MediaBrowserCompatApi21$SubscriptionCallback": "androidx/media/MediaBrowserCompatApi21$SubscriptionCallback",
-      "android/support/v7/view/menu/MenuHelper": "androidx/view/menu/MenuHelper",
-      "android/support/v17/leanback/widget/SpeechOrbView": "androidx/leanback/widget/SpeechOrbView",
-      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteController": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteController",
-      "android/support/v7/widget/FitWindowsFrameLayout": "androidx/widget/FitWindowsFrameLayout",
-      "android/support/v7/preference/TwoStatePreference$SavedState": "androidx/preference/TwoStatePreference$SavedState",
-      "android/support/v17/leanback/widget/ShadowOverlayHelper$Builder": "androidx/leanback/widget/ShadowOverlayHelper$Builder",
-      "android/support/v17/leanback/widget/InvisibleRowPresenter": "androidx/leanback/widget/InvisibleRowPresenter",
-      "android/support/design/internal/NavigationMenuPresenter$SeparatorViewHolder": "androidx/design/internal/NavigationMenuPresenter$SeparatorViewHolder",
-      "android/support/design/widget/BaseTransientBottomBar$Duration": "androidx/design/widget/BaseTransientBottomBar$Duration",
-      "android/support/v7/widget/helper/ItemTouchUIUtilImpl": "androidx/widget/helper/ItemTouchUIUtilImpl",
-      "android/support/v17/leanback/widget/GuidedActionsRelativeLayout$InterceptKeyEventListener": "androidx/leanback/widget/GuidedActionsRelativeLayout$InterceptKeyEventListener",
-      "android/support/v4/os/IResultReceiver": "androidx/os/IResultReceiver",
-      "android/support/v17/leanback/widget/ShadowHelperApi21": "androidx/leanback/widget/ShadowHelperApi21",
-      "android/support/v17/leanback/widget/RowPresenter": "androidx/leanback/widget/RowPresenter",
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase",
-      "android/support/v4/app/BackStackRecord": "androidx/app/BackStackRecord",
-      "android/support/v4/view/WindowInsetsCompat": "androidx/view/WindowInsetsCompat",
-      "android/support/graphics/drawable/AnimatedVectorDrawableCompat": "androidx/graphics/drawable/AnimatedVectorDrawableCompat",
-      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter": "androidx/leanback/widget/PlaybackControlsRowPresenter",
-      "android/support/transition/VisibilityPropagation": "androidx/transition/VisibilityPropagation",
-      "android/support/v17/leanback/media/PlaybackTransportControlGlue": "androidx/leanback/media/PlaybackTransportControlGlue",
-      "android/support/wear/widget/BoxInsetLayout$LayoutParams$BoxedEdges": "androidx/wear/widget/BoxInsetLayout$LayoutParams$BoxedEdges",
-      "android/support/annotation/LayoutRes": "androidx/annotation/LayoutRes",
-      "android/support/v4/widget/CursorAdapter": "androidx/widget/CursorAdapter",
-      "android/support/wear/ambient/AmbientMode$AmbientCallback": "androidx/wear/ambient/AmbientMode$AmbientCallback",
-      "android/support/v4/media/MediaBrowserServiceCompatApi21$BrowserRoot": "androidx/media/MediaBrowserServiceCompatApi21$BrowserRoot",
-      "android/support/v7/view/menu/MenuItemWrapperJB": "androidx/view/menu/MenuItemWrapperJB",
-      "android/support/text/emoji/widget/EmojiAppCompatButton": "androidx/text/emoji/widget/EmojiAppCompatButton",
-      "android/support/v4/view/ActionProvider$SubUiVisibilityListener": "androidx/view/ActionProvider$SubUiVisibilityListener",
-      "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem$MenuItemChangedListener": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem$MenuItemChangedListener",
-      "android/support/v4/media/MediaBrowserCompat$ServiceBinderWrapper": "androidx/media/MediaBrowserCompat$ServiceBinderWrapper",
-      "android/support/v13/app/ActivityCompat": "androidx/app/ActivityCompat",
-      "android/support/v4/widget/ImageViewCompat$LollipopViewCompatImpl": "androidx/widget/ImageViewCompat$LollipopViewCompatImpl",
-      "android/support/annotation/UiThread": "androidx/annotation/UiThread",
-      "android/support/v4/media/session/MediaControllerCompatApi24": "androidx/media/session/MediaControllerCompatApi24",
-      "android/support/v7/media/RemoteControlClientCompat$JellybeanImpl$VolumeCallbackWrapper": "androidx/media/RemoteControlClientCompat$JellybeanImpl$VolumeCallbackWrapper",
-      "android/support/v4/media/session/MediaControllerCompatApi23": "androidx/media/session/MediaControllerCompatApi23",
-      "android/support/v4/media/session/MediaControllerCompatApi21": "androidx/media/session/MediaControllerCompatApi21",
-      "android/support/v4/print/PrintHelper$ScaleMode": "androidx/print/PrintHelper$ScaleMode",
-      "android/support/v7/widget/SearchView$SavedState": "androidx/widget/SearchView$SavedState",
-      "android/support/v7/widget/AppCompatDrawableManager$AvdcInflateDelegate": "androidx/widget/AppCompatDrawableManager$AvdcInflateDelegate",
-      "android/support/v7/preference/TwoStatePreference": "androidx/preference/TwoStatePreference",
-      "android/support/text/emoji/EmojiCompat$LoadState": "androidx/text/emoji/EmojiCompat$LoadState",
-      "android/support/v17/leanback/widget/HorizontalGridView": "androidx/leanback/widget/HorizontalGridView",
-      "android/support/v7/view/menu/ListMenuItemView": "androidx/view/menu/ListMenuItemView",
-      "android/support/transition/Styleable$TransitionSet": "androidx/transition/Styleable$TransitionSet",
-      "android/support/v17/leanback/app/PlaybackFragment$OnFadeCompleteListener": "androidx/leanback/app/PlaybackFragment$OnFadeCompleteListener",
-      "android/support/v7/widget/ActivityChooserModel$PersistHistoryAsyncTask": "androidx/widget/ActivityChooserModel$PersistHistoryAsyncTask",
-      "android/support/v4/util/ArraySet": "androidx/util/ArraySet",
-      "android/support/v7/widget/FastScroller$AnimationState": "androidx/widget/FastScroller$AnimationState",
-      "android/support/v7/widget/RecyclerView$ChildDrawingOrderCallback": "androidx/widget/RecyclerView$ChildDrawingOrderCallback",
-      "android/support/text/emoji/flatbuffer/Constants": "androidx/text/emoji/flatbuffer/Constants",
-      "android/support/v4/widget/DrawerLayout$LayoutParams": "androidx/widget/DrawerLayout$LayoutParams",
-      "android/support/v4/app/TaskStackBuilder": "androidx/app/TaskStackBuilder",
-      "android/support/v7/widget/ListPopupWindow$PopupDataSetObserver": "androidx/widget/ListPopupWindow$PopupDataSetObserver",
-      "android/support/v4/media/session/MediaSessionCompatApi24$CallbackProxy": "androidx/media/session/MediaSessionCompatApi24$CallbackProxy",
-      "android/support/v17/leanback/app/RowsSupportFragment$MainFragmentRowsAdapter": "androidx/leanback/app/RowsSupportFragment$MainFragmentRowsAdapter",
-      "android/support/v17/leanback/widget/picker/DatePicker": "androidx/leanback/widget/picker/DatePicker",
-      "android/support/v17/leanback/widget/SearchBar$SearchBarPermissionListener": "androidx/leanback/widget/SearchBar$SearchBarPermissionListener",
-      "android/support/v7/media/MediaItemMetadata": "androidx/media/MediaItemMetadata",
-      "android/support/v17/leanback/widget/ListRowPresenter": "androidx/leanback/widget/ListRowPresenter",
-      "android/support/v17/leanback/media/PlaybackBannerControlGlue$ACTION_": "androidx/leanback/media/PlaybackBannerControlGlue$ACTION_",
-      "android/support/v4/app/RemoteInput": "androidx/app/RemoteInput",
-      "android/support/text/emoji/MetadataListReader$ByteBufferReader": "androidx/text/emoji/MetadataListReader$ByteBufferReader",
-      "android/support/v17/leanback/widget/SearchEditText": "androidx/leanback/widget/SearchEditText",
-      "android/support/v4/app/NotificationCompat$CarExtender$UnreadConversation$Builder": "androidx/app/NotificationCompat$CarExtender$UnreadConversation$Builder",
-      "android/support/v7/preference/SeekBarPreference": "androidx/preference/SeekBarPreference",
-      "android/support/v17/leanback/R$transition": "androidx/leanback/R$transition",
-      "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory": "androidx/graphics/drawable/RoundedBitmapDrawableFactory",
-      "android/support/v7/widget/PositionMap$ContainerHelpers": "androidx/widget/PositionMap$ContainerHelpers",
-      "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerWrapper": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerWrapper",
-      "android/support/design/widget/ViewUtils": "androidx/design/widget/ViewUtils",
-      "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatApi23Impl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatApi23Impl",
-      "android/support/v7/widget/StaggeredGridLayoutManager$SavedState": "androidx/widget/StaggeredGridLayoutManager$SavedState",
-      "android/support/transition/PathMotion": "androidx/transition/PathMotion",
-      "android/support/wear/widget/drawer/WearableDrawerView": "androidx/wear/widget/drawer/WearableDrawerView",
-      "android/support/v4/media/VolumeProviderCompat$ControlType": "androidx/media/VolumeProviderCompat$ControlType",
-      "android/support/v4/view/animation/PathInterpolatorApi14": "androidx/view/animation/PathInterpolatorApi14",
-      "android/support/animation/AnimationHandler$FrameCallbackProvider16": "androidx/animation/AnimationHandler$FrameCallbackProvider16",
-      "android/support/v4/view/animation/FastOutSlowInInterpolator": "androidx/view/animation/FastOutSlowInInterpolator",
-      "android/support/animation/AnimationHandler$FrameCallbackProvider14": "androidx/animation/AnimationHandler$FrameCallbackProvider14",
-      "android/support/customtabs/CustomTabsServiceConnection": "androidx/browser/customtabs/CustomTabsServiceConnection",
-      "android/support/v17/leanback/app/BackgroundFragment": "androidx/leanback/app/BackgroundFragment",
-      "android/support/v17/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight": "androidx/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight",
-      "android/support/v17/leanback/app/HeadersFragment$OnHeaderClickedListener": "androidx/leanback/app/HeadersFragment$OnHeaderClickedListener",
-      "android/support/v7/media/MediaRouter$RouteInfo": "androidx/media/MediaRouter$RouteInfo",
-      "android/support/v14/preference/PreferenceFragment": "androidx/preference/PreferenceFragment",
-      "android/support/v4/media/session/PlaybackStateCompat$MediaKeyAction": "androidx/media/session/PlaybackStateCompat$MediaKeyAction",
-      "android/support/v17/leanback/widget/TitleView": "androidx/leanback/widget/TitleView",
-      "android/support/graphics/drawable/VectorDrawableCompat$VPath": "androidx/graphics/drawable/VectorDrawableCompat$VPath",
-      "android/support/v17/leanback/widget/AbstractMediaItemPresenter$ViewHolder": "androidx/leanback/widget/AbstractMediaItemPresenter$ViewHolder",
-      "android/support/v17/leanback/widget/BrowseRowsFrameLayout": "androidx/leanback/widget/BrowseRowsFrameLayout",
-      "android/support/v7/content/res/AppCompatResources$ColorStateListCacheEntry": "androidx/content/res/AppCompatResources$ColorStateListCacheEntry",
-      "android/support/design/R$dimen": "androidx/design/R$dimen",
-      "android/support/v7/preference/PreferenceInflater": "androidx/preference/PreferenceInflater",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$PlayPauseAction": "androidx/leanback/widget/PlaybackControlsRow$PlayPauseAction",
-      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter": "androidx/leanback/widget/PlaybackTransportRowPresenter",
-      "android/support/wear/widget/CircledImageView": "androidx/wear/widget/CircledImageView",
-      "android/support/v7/media/MediaRouterJellybean$SelectRouteWorkaround": "androidx/media/MediaRouterJellybean$SelectRouteWorkaround",
-      "android/support/v17/leanback/widget/ListRowHoverCardView": "androidx/leanback/widget/ListRowHoverCardView",
-      "android/support/v7/media/MediaRouterJellybean$GetDefaultRouteWorkaround": "androidx/media/MediaRouterJellybean$GetDefaultRouteWorkaround",
-      "android/support/text/emoji/widget/SpannableBuilder$WatcherWrapper": "androidx/text/emoji/widget/SpannableBuilder$WatcherWrapper",
-      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$AdapterSingle": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$AdapterSingle",
-      "android/support/v17/leanback/app/OnboardingFragment": "androidx/leanback/app/OnboardingFragment",
-      "android/support/v7/view/menu/MenuPresenter$Callback": "androidx/view/menu/MenuPresenter$Callback",
-      "android/support/v4/graphics/drawable/DrawableWrapperApi14$DrawableWrapperStateBase": "androidx/graphics/drawable/DrawableWrapperApi14$DrawableWrapperStateBase",
-      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable",
-      "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder": "androidx/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder",
-      "android/support/v7/view/menu/MenuItemWrapperICS$OnMenuItemClickListenerWrapper": "androidx/view/menu/MenuItemWrapperICS$OnMenuItemClickListenerWrapper",
-      "android/support/v7/widget/ContentFrameLayout$OnAttachListener": "androidx/widget/ContentFrameLayout$OnAttachListener",
-      "android/support/v17/leanback/widget/StaticShadowHelper": "androidx/leanback/widget/StaticShadowHelper",
-      "android/support/v7/widget/RecyclerView$OnScrollListener": "androidx/widget/RecyclerView$OnScrollListener",
-      "android/support/v17/leanback/graphics/FitWidthBitmapDrawable$BitmapState": "androidx/leanback/graphics/FitWidthBitmapDrawable$BitmapState",
-      "android/support/v17/leanback/widget/SeekBar": "androidx/leanback/widget/SeekBar",
-      "android/support/v4/widget/SlidingPaneLayout$SimplePanelSlideListener": "androidx/widget/SlidingPaneLayout$SimplePanelSlideListener",
-      "android/support/v17/leanback/widget/RowContainerView": "androidx/leanback/widget/RowContainerView",
-      "android/support/v7/widget/ForwardingListener$DisallowIntercept": "androidx/widget/ForwardingListener$DisallowIntercept",
-      "android/support/v7/app/AppCompatDelegateImplBase": "androidx/app/AppCompatDelegateImplBase",
-      "android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost": "androidx/leanback/app/PlaybackSupportFragmentGlueHost",
-      "android/support/transition/Styleable$Transition": "androidx/transition/Styleable$Transition",
-      "android/support/v7/widget/ActionMenuPresenter": "androidx/widget/ActionMenuPresenter",
-      "android/support/v7/app/ActionBar$DisplayOptions": "androidx/app/ActionBar$DisplayOptions",
-      "android/support/v4/app/ShareCompat$IntentBuilder": "androidx/app/ShareCompat$IntentBuilder",
-      "android/support/v4/media/MediaMetadataCompat$LongKey": "androidx/media/MediaMetadataCompat$LongKey",
-      "android/support/v4/media/AudioAttributesCompatApi21$Wrapper": "androidx/media/AudioAttributesCompatApi21$Wrapper",
-      "android/support/v17/leanback/widget/DetailsOverviewRow": "androidx/leanback/widget/DetailsOverviewRow",
-      "android/support/annotation/IdRes": "androidx/annotation/IdRes",
-      "android/support/v7/widget/ActivityChooserModel$HistoricalRecord": "androidx/widget/ActivityChooserModel$HistoricalRecord",
-      "android/support/v17/leanback/widget/SearchOrbView$Colors": "androidx/leanback/widget/SearchOrbView$Colors",
-      "android/support/v7/content/res/GrowingArrayUtils": "androidx/content/res/GrowingArrayUtils",
-      "android/support/text/emoji/MetadataRepo$Node": "androidx/text/emoji/MetadataRepo$Node",
-      "android/support/v17/leanback/app/BrowseFragment$MainFragmentItemViewSelectedListener": "androidx/leanback/app/BrowseFragment$MainFragmentItemViewSelectedListener",
-      "android/support/v17/leanback/app/SearchSupportFragment$ExternalQuery": "androidx/leanback/app/SearchSupportFragment$ExternalQuery",
-      "android/support/v17/leanback/widget/ShadowHelperJbmr2$ShadowImpl": "androidx/leanback/widget/ShadowHelperJbmr2$ShadowImpl",
-      "android/support/wear/widget/drawer/PageIndicatorView": "androidx/wear/widget/drawer/PageIndicatorView",
-      "android/support/v17/leanback/app/VerticalGridSupportFragment": "androidx/leanback/app/VerticalGridSupportFragment",
-      "android/support/v7/preference/PreferenceGroupAdapter$PreferenceLayout": "androidx/preference/PreferenceGroupAdapter$PreferenceLayout",
-      "android/support/v7/preference/internal/AbstractMultiSelectListPreference": "androidx/preference/internal/AbstractMultiSelectListPreference",
-      "android/support/v7/media/MediaRouteProviderDescriptor$Builder": "androidx/media/MediaRouteProviderDescriptor$Builder",
-      "android/support/v4/app/NotificationCompatSideChannelService": "androidx/app/NotificationCompatSideChannelService",
-      "android/support/v7/widget/GridLayoutManager": "androidx/widget/GridLayoutManager",
-      "android/support/v4/media/AudioAttributesCompat$AttributeUsage": "androidx/media/AudioAttributesCompat$AttributeUsage",
-      "android/support/v4/util/Pools$Pool": "androidx/util/Pools$Pool",
-      "android/support/transition/SidePropagation": "androidx/transition/SidePropagation",
-      "android/support/v17/leanback/widget/PlaybackSeekUi$Client": "androidx/leanback/widget/PlaybackSeekUi$Client",
-      "android/support/media/tv/TvContractCompat$Channels": "androidx/media/tv/TvContractCompat$Channels",
-      "android/support/v7/appcompat/R$style": "androidx/appcompat/R$style",
-      "android/support/v4/app/INotificationSideChannel$Stub": "androidx/app/INotificationSideChannel$Stub",
-      "android/support/compat/R$string": "androidx/compat/R$string",
-      "android/support/v4/os/EnvironmentCompat": "androidx/os/EnvironmentCompat",
-      "android/support/wear/ambient/SharedLibraryVersion": "androidx/wear/ambient/SharedLibraryVersion",
-      "android/support/v7/view/menu/MenuBuilder$Callback": "androidx/view/menu/MenuBuilder$Callback",
-      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapterProvider": "androidx/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapterProvider",
-      "android/support/v17/leanback/R": "androidx/leanback/R",
-      "android/support/transition/Slide": "androidx/transition/Slide",
-      "android/support/v4/os/ParcelableCompat$ParcelableCompatCreatorHoneycombMR2": "androidx/os/ParcelableCompat$ParcelableCompatCreatorHoneycombMR2",
-      "android/support/v17/leanback/widget/PlaybackSeekUi": "androidx/leanback/widget/PlaybackSeekUi",
-      "android/support/v4/view/ViewPropertyAnimatorUpdateListener": "androidx/view/ViewPropertyAnimatorUpdateListener",
-      "android/support/v4/widget/EdgeEffectCompat$EdgeEffectBaseImpl": "androidx/widget/EdgeEffectCompat$EdgeEffectBaseImpl",
-      "android/support/v7/widget/ForwardingListener$TriggerLongPress": "androidx/widget/ForwardingListener$TriggerLongPress",
-      "android/support/v4/app/ActivityCompat$SharedElementCallback23Impl": "androidx/app/legacy/ActivityCompat$SharedElementCallback23Impl",
-      "android/support/v4/media/MediaBrowserCompatApi21$ConnectionCallback": "androidx/media/MediaBrowserCompatApi21$ConnectionCallback",
-      "android/support/v4/content/Loader$ForceLoadContentObserver": "androidx/content/Loader$ForceLoadContentObserver",
-      "android/support/v7/widget/ScrollingTabContainerView$TabClickListener": "androidx/widget/ScrollingTabContainerView$TabClickListener",
-      "android/support/v4/widget/TextViewCompat$TextViewCompatApi27Impl": "androidx/widget/TextViewCompat$TextViewCompatApi27Impl",
-      "android/support/v17/leanback/widget/GridLayoutManager$OnLayoutCompleteListener": "androidx/leanback/widget/GridLayoutManager$OnLayoutCompleteListener",
-      "android/support/v4/provider/SelfDestructiveThread$ReplyCallback": "androidx/provider/SelfDestructiveThread$ReplyCallback",
-      "android/support/v4/media/VolumeProviderCompat$Callback": "androidx/media/VolumeProviderCompat$Callback",
-      "android/support/v4/app/NotificationCompat$CarExtender$UnreadConversation": "androidx/app/NotificationCompat$CarExtender$UnreadConversation",
-      "android/support/graphics/drawable/AnimatorInflaterCompat": "androidx/graphics/drawable/AnimatorInflaterCompat",
-      "android/support/compat/R$id": "androidx/compat/R$id",
-      "android/support/v17/leanback/app/DetailsFragment$WaitEnterTransitionTimeout": "androidx/leanback/app/DetailsFragment$WaitEnterTransitionTimeout",
-      "android/support/media/tv/TvContractCompat$Channels$ServiceType": "androidx/media/tv/TvContractCompat$Channels$ServiceType",
-      "android/support/v17/leanback/widget/Presenter$ViewHolder": "androidx/leanback/widget/Presenter$ViewHolder",
-      "android/support/text/emoji/EmojiCompat$Config": "androidx/text/emoji/EmojiCompat$Config",
-      "android/support/v17/leanback/app/BackgroundManager$ChangeBackgroundRunnable": "androidx/leanback/app/BackgroundManager$ChangeBackgroundRunnable",
-      "android/support/v17/leanback/util/StateMachine$Transition": "androidx/leanback/util/StateMachine$Transition",
-      "android/support/v17/leanback/widget/picker/TimePicker": "androidx/leanback/widget/picker/TimePicker",
-      "android/support/v7/media/RegisteredMediaRouteProvider$Controller": "androidx/media/RegisteredMediaRouteProvider$Controller",
-      "android/support/text/emoji/TypefaceEmojiSpan": "androidx/text/emoji/TypefaceEmojiSpan",
-      "android/support/wear/widget/SwipeDismissFrameLayout": "androidx/wear/widget/SwipeDismissFrameLayout",
-      "android/support/v4/media/MediaBrowserCompatUtils": "androidx/media/MediaBrowserCompatUtils",
-      "android/support/v17/leanback/app/HeadersSupportFragment": "androidx/leanback/app/HeadersSupportFragment",
-      "android/support/v7/widget/SearchView$OnQueryTextListener": "androidx/widget/SearchView$OnQueryTextListener",
-      "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter": "androidx/leanback/widget/AbstractMediaListHeaderPresenter",
-      "android/support/design/widget/BaseTransientBottomBar$OnLayoutChangeListener": "androidx/design/widget/BaseTransientBottomBar$OnLayoutChangeListener",
-      "android/support/v14/preference/R$styleable": "androidx/preference/R$styleable",
-      "android/support/v17/leanback/transition/SlideKitkat": "androidx/leanback/transition/SlideKitkat",
-      "android/support/animation/AnimationHandler$AnimationFrameCallbackProvider": "androidx/animation/AnimationHandler$AnimationFrameCallbackProvider",
-      "android/support/v7/view/menu/ActionMenuItem": "androidx/view/menu/ActionMenuItem",
-      "android/support/v4/view/animation/PathInterpolatorCompat": "androidx/view/animation/PathInterpolatorCompat",
-      "android/support/v7/util/AsyncListUtil$DataCallback": "androidx/util/AsyncListUtil$DataCallback",
-      "android/support/v17/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter": "androidx/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter",
-      "android/support/v7/mediarouter/R$style": "androidx/mediarouter/R$style",
-      "android/support/customtabs/IPostMessageService$Stub": "androidx/browser/customtabs/IPostMessageService$Stub",
-      "android/support/wear/widget/CircularProgressLayout$OnTimerFinishedListener": "androidx/wear/widget/CircularProgressLayout$OnTimerFinishedListener",
-      "android/support/v7/widget/ActivityChooserModel$OnChooseActivityListener": "androidx/widget/ActivityChooserModel$OnChooseActivityListener",
-      "android/support/v4/graphics/drawable/DrawableWrapperApi21": "androidx/graphics/drawable/DrawableWrapperApi21",
-      "android/support/design/widget/FloatingActionButton$Size": "androidx/design/widget/FloatingActionButton$Size",
-      "android/support/v4/provider/DocumentFile": "androidx/provider/DocumentFile",
-      "android/support/v7/app/AppCompatDelegateImplBase$AppCompatWindowCallbackBase": "androidx/app/AppCompatDelegateImplBase$AppCompatWindowCallbackBase",
-      "android/support/annotation/AnyThread": "androidx/annotation/AnyThread",
-      "android/support/v13/app/FragmentCompat$FragmentCompatApi24Impl": "androidx/app/FragmentCompat$FragmentCompatApi24Impl",
-      "android/support/wear/ambient/SharedLibraryVersion$VersionHolder": "androidx/wear/ambient/SharedLibraryVersion$VersionHolder",
-      "android/support/v7/app/WindowDecorActionBar$ActionModeImpl": "androidx/app/WindowDecorActionBar$ActionModeImpl",
-      "android/support/constraint/solver/widgets/Guideline": "androidx/constraint/solver/widgets/Guideline",
-      "android/support/v17/leanback/widget/NonOverlappingView": "androidx/leanback/widget/NonOverlappingView",
-      "android/support/v7/preference/ListPreference": "androidx/preference/ListPreference",
-      "android/support/v17/leanback/widget/ShadowOverlayContainer": "androidx/leanback/widget/ShadowOverlayContainer",
-      "android/support/design/internal/NavigationMenuItemView": "androidx/design/internal/NavigationMenuItemView",
-      "android/support/v17/leanback/widget/ArrayObjectAdapter": "androidx/leanback/widget/ArrayObjectAdapter",
-      "android/support/v17/leanback/widget/CursorObjectAdapter": "androidx/leanback/widget/CursorObjectAdapter",
-      "android/support/v17/leanback/R$style": "androidx/leanback/R$style",
-      "android/support/v4/media/MediaBrowserCompatApi21": "androidx/media/MediaBrowserCompatApi21",
-      "android/support/v4/media/MediaBrowserCompatApi23": "androidx/media/MediaBrowserCompatApi23",
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper",
-      "android/support/v7/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener": "androidx/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener",
-      "android/support/v4/media/MediaBrowserCompatApi26": "androidx/media/MediaBrowserCompatApi26",
-      "android/support/v4/print/PrintHelper$Orientation": "androidx/print/PrintHelper$Orientation",
-      "android/support/v4/view/ViewPager$PageTransformer": "androidx/view/ViewPager$PageTransformer",
-      "android/support/transition/ViewGroupOverlayImpl": "androidx/transition/ViewGroupOverlayImpl",
-      "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi23Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi23Impl",
-      "android/support/v4/view/ViewPropertyAnimatorListener": "androidx/view/ViewPropertyAnimatorListener",
-      "android/support/transition/Styleable$ChangeBounds": "androidx/transition/Styleable$ChangeBounds",
-      "android/support/annotation/Keep": "androidx/annotation/Keep",
-      "android/support/v4/app/NotificationCompat$DecoratedCustomViewStyle": "androidx/app/NotificationCompat$DecoratedCustomViewStyle",
-      "android/support/v4/app/ShareCompat$IntentReader": "androidx/app/ShareCompat$IntentReader",
-      "android/support/v17/leanback/widget/ActionPresenterSelector$ActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$ActionPresenter",
-      "android/support/v7/util/MessageThreadUtil$MessageQueue": "androidx/util/MessageThreadUtil$MessageQueue",
-      "android/support/annotation/Px": "androidx/annotation/Px",
-      "android/support/v17/leanback/app/SearchFragment$SearchResultProvider": "androidx/leanback/app/SearchFragment$SearchResultProvider",
-      "android/support/v7/app/AppCompatDelegateImplV9$ListMenuDecorView": "androidx/app/AppCompatDelegateImplV9$ListMenuDecorView",
-      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperStubImpl$TransitionStub": "androidx/leanback/transition/TransitionHelper$TransitionHelperStubImpl$TransitionStub",
-      "android/support/v7/app/AppCompatDelegate": "androidx/app/AppCompatDelegate",
-      "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapter": "androidx/leanback/app/BrowseFragment$MainFragmentAdapter",
-      "android/support/v17/leanback/widget/ParallaxEffect$IntEffect": "androidx/leanback/widget/ParallaxEffect$IntEffect",
-      "android/support/v7/widget/GridLayout$Alignment": "androidx/widget/GridLayout$Alignment",
-      "android/support/v7/widget/helper/ItemTouchHelper$RecoverAnimation": "androidx/widget/helper/ItemTouchHelper$RecoverAnimation",
-      "android/support/v17/leanback/widget/picker/Picker": "androidx/leanback/widget/picker/Picker",
-      "android/support/v7/gridlayout/R$styleable": "androidx/gridlayout/R$styleable",
-      "android/support/v4/app/FragmentPagerAdapter": "androidx/app/FragmentPagerAdapter",
-      "android/support/v4/graphics/TypefaceCompatBaseImpl$StyleExtractor": "androidx/graphics/TypefaceCompatBaseImpl$StyleExtractor",
-      "android/support/v17/leanback/widget/SearchBar": "androidx/leanback/widget/SearchBar",
-      "android/support/wear/widget/drawer/WearableDrawerController": "androidx/wear/widget/drawer/WearableDrawerController",
-      "android/support/design/widget/FloatingActionButtonImpl$DisabledElevationAnimation": "androidx/design/widget/FloatingActionButtonImpl$DisabledElevationAnimation",
-      "android/support/annotation/FloatRange": "androidx/annotation/FloatRange",
-      "android/support/media/ExifInterface$ByteOrderedDataInputStream": "androidx/media/ExifInterface$ByteOrderedDataInputStream",
-      "android/support/v7/widget/TooltipCompat$Api26ViewCompatImpl": "androidx/widget/TooltipCompat$Api26ViewCompatImpl",
-      "android/support/v7/widget/RecyclerViewAccessibilityDelegate": "androidx/widget/RecyclerViewAccessibilityDelegate",
-      "android/support/v7/widget/AppCompatTextView": "androidx/widget/AppCompatTextView",
-      "android/support/transition/ChangeImageTransform": "androidx/transition/ChangeImageTransform",
-      "android/support/v4/app/SuperNotCalledException": "androidx/app/SuperNotCalledException",
-      "android/support/text/emoji/widget/EmojiTextViewHelper$HelperInternal19": "androidx/text/emoji/widget/EmojiTextViewHelper$HelperInternal19",
-      "android/support/v7/widget/GapWorker$LayoutPrefetchRegistryImpl": "androidx/widget/GapWorker$LayoutPrefetchRegistryImpl",
-      "android/support/v7/app/AppCompatDelegateImplV14$AppCompatWindowCallbackV14": "androidx/app/AppCompatDelegateImplV14$AppCompatWindowCallbackV14",
-      "android/support/v4/widget/TextViewCompat$TextViewCompatApi23Impl": "androidx/widget/TextViewCompat$TextViewCompatApi23Impl",
-      "android/support/v17/leanback/widget/ParallaxEffect$FloatEffect": "androidx/leanback/widget/ParallaxEffect$FloatEffect",
-      "android/support/v4/media/session/MediaSessionCompat": "androidx/media/session/MediaSessionCompat",
-      "android/support/v17/leanback/app/BrowseSupportFragment$FragmentHostImpl": "androidx/leanback/app/BrowseSupportFragment$FragmentHostImpl",
-      "android/support/design/widget/ShadowDrawableWrapper": "androidx/design/widget/ShadowDrawableWrapper",
-      "android/support/design/internal/NavigationMenuPresenter$HeaderViewHolder": "androidx/design/internal/NavigationMenuPresenter$HeaderViewHolder",
-      "android/support/v7/widget/PopupMenu": "androidx/widget/PopupMenu",
-      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$ViewHolder": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$ViewHolder",
-      "android/support/annotation/BoolRes": "androidx/annotation/BoolRes",
-      "android/support/v7/media/RemotePlaybackClient": "androidx/media/RemotePlaybackClient",
-      "android/support/v4/view/LayoutInflaterCompat$LayoutInflaterCompatApi21Impl": "androidx/view/LayoutInflaterCompat$LayoutInflaterCompatApi21Impl",
-      "android/support/v7/preference/AndroidResources": "androidx/preference/AndroidResources",
-      "android/support/v7/app/AlertController$AlertParams$OnPrepareListViewListener": "androidx/app/AlertController$AlertParams$OnPrepareListViewListener",
-      "android/support/wear/widget/drawer/WearableNavigationDrawerView": "androidx/wear/widget/drawer/WearableNavigationDrawerView",
-      "android/support/v4/media/session/PlaybackStateCompat$ErrorCode": "androidx/media/session/PlaybackStateCompat$ErrorCode",
-      "android/support/v7/widget/ActionMenuView$ActionMenuPresenterCallback": "androidx/widget/ActionMenuView$ActionMenuPresenterCallback",
-      "android/support/v7/app/AlertController": "androidx/app/AlertController",
-      "android/support/v7/widget/FitWindowsViewGroup$OnFitSystemWindowsListener": "androidx/widget/FitWindowsViewGroup$OnFitSystemWindowsListener",
-      "android/support/v4/app/NotificationBuilderWithBuilderAccessor": "androidx/app/NotificationBuilderWithBuilderAccessor",
-      "android/support/v4/view/AbsSavedState": "androidx/view/AbsSavedState",
-      "android/support/v7/media/MediaRouteProvider$ProviderHandler": "androidx/media/MediaRouteProvider$ProviderHandler",
-      "android/support/v7/widget/AbsActionBarView$VisibilityAnimListener": "androidx/widget/AbsActionBarView$VisibilityAnimListener",
-      "android/support/design/internal/TextScale": "androidx/design/internal/TextScale",
-      "android/support/v7/widget/RecyclerViewAccessibilityDelegate$ItemDelegate": "androidx/widget/RecyclerViewAccessibilityDelegate$ItemDelegate",
-      "android/support/v4/widget/SlidingPaneLayout": "androidx/widget/SlidingPaneLayout",
-      "android/support/v17/leanback/widget/ScaleFrameLayout": "androidx/leanback/widget/ScaleFrameLayout",
-      "android/support/v4/app/FragmentTransaction": "androidx/app/FragmentTransaction",
-      "android/support/graphics/drawable/AnimatorInflaterCompat$PathDataEvaluator": "androidx/graphics/drawable/AnimatorInflaterCompat$PathDataEvaluator",
-      "android/support/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder": "androidx/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder",
-      "android/support/wear/ambient/AmbientDelegate": "androidx/wear/ambient/AmbientDelegate",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsUpAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsUpAction",
-      "android/support/v7/widget/AppCompatSpinner": "androidx/widget/AppCompatSpinner",
-      "android/support/design/widget/NavigationView$SavedState": "androidx/design/widget/NavigationView$SavedState",
+      "android/support/annotation/RestrictTo$Scope": "androidx/annotation/RestrictTo$Scope",
       "android/support/v17/leanback/animation/LogDecelerateInterpolator": "androidx/leanback/animation/LogDecelerateInterpolator",
-      "android/support/v4/media/session/MediaControllerCompatApi21$Callback": "androidx/media/session/MediaControllerCompatApi21$Callback",
-      "android/support/v7/widget/helper/ItemTouchHelper": "androidx/widget/helper/ItemTouchHelper",
-      "android/support/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableCompatState": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableCompatState",
-      "android/support/v4/graphics/drawable/DrawableWrapperApi14$DrawableWrapperState": "androidx/graphics/drawable/DrawableWrapperApi14$DrawableWrapperState",
-      "android/support/v4/util/DebugUtils": "androidx/util/DebugUtils",
-      "android/support/customtabs/CustomTabsCallback": "androidx/browser/customtabs/CustomTabsCallback",
-      "android/support/v13/app/FragmentCompat": "androidx/app/FragmentCompat",
-      "android/support/v7/widget/RecyclerView$ViewFlinger": "androidx/widget/RecyclerView$ViewFlinger",
-      "android/support/v17/leanback/app/BrowseFragment$SetSelectionRunnable": "androidx/leanback/app/BrowseFragment$SetSelectionRunnable",
-      "android/support/customtabs/CustomTabsIntent$Builder": "androidx/browser/customtabs/CustomTabsIntent$Builder",
-      "android/support/v4/util/MapCollections$ValuesCollection": "androidx/util/MapCollections$ValuesCollection",
-      "android/support/v17/leanback/widget/StaggeredGrid": "androidx/leanback/widget/StaggeredGrid",
-      "android/support/v13/app/FragmentTabHost$SavedState": "androidx/app/legacy/FragmentTabHost$SavedState",
-      "android/support/v4/media/MediaBrowserServiceCompatApi23": "androidx/media/MediaBrowserServiceCompatApi23",
-      "android/support/v4/media/session/MediaButtonReceiver": "androidx/media/session/MediaButtonReceiver",
-      "android/support/v17/leanback/graphics/CompositeDrawable$CompositeState": "androidx/leanback/graphics/CompositeDrawable$CompositeState",
-      "android/support/transition/WindowIdApi14": "androidx/transition/WindowIdApi14",
-      "android/support/v4/media/MediaBrowserServiceCompatApi26": "androidx/media/MediaBrowserServiceCompatApi26",
-      "android/support/v4/media/MediaBrowserServiceCompatApi21": "androidx/media/MediaBrowserServiceCompatApi21",
-      "android/support/transition/WindowIdApi18": "androidx/transition/WindowIdApi18",
-      "android/support/v7/graphics/ColorCutQuantizer": "androidx/graphics/palette/ColorCutQuantizer",
-      "android/support/v4/media/session/MediaSessionCompatApi23$Callback": "androidx/media/session/MediaSessionCompatApi23$Callback",
-      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter": "androidx/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter",
-      "android/support/v7/app/MediaRouteButton$RemoteIndicatorLoader": "androidx/app/MediaRouteButton$RemoteIndicatorLoader",
-      "android/support/v7/preference/ListPreference$SavedState": "androidx/preference/ListPreference$SavedState",
-      "android/support/v7/media/RegisteredMediaRouteProvider$ReceiveHandler": "androidx/media/RegisteredMediaRouteProvider$ReceiveHandler",
-      "android/support/v17/leanback/widget/MediaRowFocusView": "androidx/leanback/widget/MediaRowFocusView",
-      "android/support/v14/preference/PreferenceFragment$OnPreferenceDisplayDialogCallback": "androidx/preference/PreferenceFragment$OnPreferenceDisplayDialogCallback",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$HighQualityAction": "androidx/leanback/widget/PlaybackControlsRow$HighQualityAction",
-      "android/support/v17/leanback/app/BaseRowSupportFragment": "androidx/leanback/app/BaseRowSupportFragment",
-      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentItemViewSelectedListener": "androidx/leanback/app/BrowseSupportFragment$MainFragmentItemViewSelectedListener",
-      "android/support/v17/leanback/widget/StreamingTextView": "androidx/leanback/widget/StreamingTextView",
-      "android/support/transition/GhostViewImpl$Creator": "androidx/transition/GhostViewImpl$Creator",
-      "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem",
-      "android/support/v4/media/MediaBrowserCompat$Subscription": "androidx/media/MediaBrowserCompat$Subscription",
-      "android/support/v4/view/PagerTitleStrip$SingleLineAllCapsTransform": "androidx/view/PagerTitleStrip$SingleLineAllCapsTransform",
-      "android/support/v4/media/session/MediaControllerCompatApi24$TransportControls": "androidx/media/session/MediaControllerCompatApi24$TransportControls",
-      "android/support/v7/app/ActionBarDrawerToggleHoneycomb": "androidx/app/ActionBarDrawerToggleHoneycomb",
-      "android/support/v4/graphics/TypefaceCompatBaseImpl": "androidx/graphics/TypefaceCompatBaseImpl",
-      "android/support/transition/TranslationAnimationCreator": "androidx/transition/TranslationAnimationCreator",
-      "android/support/v7/app/MediaRouteChooserDialog": "androidx/app/MediaRouteChooserDialog",
-      "android/support/v17/leanback/widget/Parallax$FloatPropertyMarkerValue": "androidx/leanback/widget/Parallax$FloatPropertyMarkerValue",
-      "android/support/v4/widget/FocusStrategy$SequentialComparator": "androidx/widget/FocusStrategy$SequentialComparator",
-      "android/support/v4/media/MediaMetadataCompat$TextKey": "androidx/media/MediaMetadataCompat$TextKey",
-      "android/support/v17/leanback/app/BrowseSupportFragment": "androidx/leanback/app/BrowseSupportFragment",
-      "android/support/v7/widget/ListViewCompat$GateKeeperDrawable": "androidx/widget/internal/ListViewCompat$GateKeeperDrawable",
-      "android/support/v4/media/session/MediaControllerCompatApi23$TransportControls": "androidx/media/session/MediaControllerCompatApi23$TransportControls",
-      "android/support/v13/view/inputmethod/InputConnectionCompat$InputContentInfoCompatApi25Impl": "androidx/view/inputmethod/InputConnectionCompat$InputContentInfoCompatApi25Impl",
-      "android/support/v7/preference/PreferenceManager$OnDisplayPreferenceDialogListener": "androidx/preference/PreferenceManager$OnDisplayPreferenceDialogListener",
-      "android/support/v7/media/MediaRouterJellybeanMr1$IsConnectingWorkaround": "androidx/media/MediaRouterJellybeanMr1$IsConnectingWorkaround",
-      "android/support/v4/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper": "androidx/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper",
-      "android/support/v7/widget/RecyclerView$ItemDecoration": "androidx/widget/RecyclerView$ItemDecoration",
-      "android/support/v4/widget/Space": "androidx/widget/Space",
-      "android/support/v17/leanback/app/BrowseSupportFragment$ExpandPreLayout": "androidx/leanback/app/BrowseSupportFragment$ExpandPreLayout",
-      "android/support/media/tv/TvContractCompat$ProgramColumns": "androidx/media/tv/TvContractCompat$ProgramColumns",
-      "android/support/v7/widget/DecorToolbar": "androidx/widget/DecorToolbar",
-      "android/support/design/widget/CheckableImageButton": "androidx/design/widget/CheckableImageButton",
-      "android/support/v4/widget/ImageViewCompat": "androidx/widget/ImageViewCompat",
-      "android/support/v7/preference/UnPressableLinearLayout": "androidx/preference/UnPressableLinearLayout",
-      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnPreSwipeListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnPreSwipeListener",
-      "android/support/v4/widget/CircularProgressDrawable": "androidx/widget/CircularProgressDrawable",
-      "android/support/design/R$string": "androidx/design/R$string",
-      "android/support/design/R$color": "androidx/design/R$color",
-      "android/support/v7/widget/TintInfo": "androidx/widget/TintInfo",
-      "android/support/v17/leanback/widget/HeaderItem": "androidx/leanback/widget/HeaderItem",
-      "android/support/v7/media/MediaRouter$RouteInfo$ConnectionState": "androidx/media/MediaRouter$RouteInfo$ConnectionState",
-      "android/support/v7/widget/DialogTitle": "androidx/widget/DialogTitle",
-      "android/support/v17/leanback/media/PlaybackTransportControlGlue$UpdatePlaybackStateHandler": "androidx/leanback/media/PlaybackTransportControlGlue$UpdatePlaybackStateHandler",
-      "android/support/v7/widget/RecyclerView$LayoutParams": "androidx/widget/RecyclerView$LayoutParams",
-      "android/support/v4/media/session/PlaybackStateCompatApi21$CustomAction": "androidx/media/session/PlaybackStateCompatApi21$CustomAction",
-      "android/support/customtabs/CustomTabsService": "androidx/browser/customtabs/CustomTabsService",
-      "android/support/v17/leanback/widget/GuidanceStylist$Guidance": "androidx/leanback/widget/GuidanceStylist$Guidance",
-      "android/support/v4/view/ViewCompat$ViewCompatApi23Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi23Impl",
-      "android/support/wear/widget/WearableLinearLayoutManager": "androidx/wear/widget/WearableLinearLayoutManager",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$MultiAction": "androidx/leanback/widget/PlaybackControlsRow$MultiAction",
-      "android/support/v17/leanback/R$integer": "androidx/leanback/R$integer",
-      "android/support/v4/content/ModernAsyncTask$WorkerRunnable": "androidx/content/ModernAsyncTask$WorkerRunnable",
-      "android/support/v4/app/FragmentTabHost$DummyTabFactory": "androidx/app/FragmentTabHost$DummyTabFactory",
-      "android/support/v7/widget/AppCompatSpinner$DropDownAdapter": "androidx/widget/AppCompatSpinner$DropDownAdapter",
-      "android/support/v7/app/ToolbarActionBar$MenuBuilderCallback": "androidx/app/ToolbarActionBar$MenuBuilderCallback",
-      "android/support/v4/content/Loader": "androidx/content/Loader",
-      "android/support/v7/widget/MenuPopupWindow": "androidx/widget/MenuPopupWindow",
-      "android/support/v4/graphics/BitmapCompat$BitmapCompatApi19Impl": "androidx/graphics/BitmapCompat$BitmapCompatApi19Impl",
-      "android/support/v4/app/FrameMetricsAggregator$MetricType": "androidx/app/FrameMetricsAggregator$MetricType",
-      "android/support/v17/leanback/widget/picker/PickerUtility$TimeConstant": "androidx/leanback/widget/picker/PickerUtility$TimeConstant",
-      "android/support/v4/view/NestedScrollingParent2": "androidx/view/NestedScrollingParent2",
-      "android/support/design/widget/Snackbar$SnackbarLayout": "androidx/design/widget/Snackbar$SnackbarLayout",
-      "android/support/v4/app/LoaderManager": "androidx/app/LoaderManager",
-      "android/support/v17/leanback/app/BaseSupportFragment": "androidx/leanback/app/BaseSupportFragment",
-      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuItem",
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat",
-      "android/support/text/emoji/MetadataRepo": "androidx/text/emoji/MetadataRepo",
-      "android/support/v17/leanback/widget/ItemAlignment": "androidx/leanback/widget/ItemAlignment",
-      "android/support/design/widget/TextInputEditText": "androidx/design/widget/TextInputEditText",
-      "android/support/v4/app/FragmentTransitionImpl": "androidx/app/FragmentTransitionImpl",
-      "android/support/animation/SpringAnimation": "androidx/animation/SpringAnimation",
-      "android/support/annotation/CheckResult": "androidx/annotation/CheckResult",
-      "android/support/v7/widget/AppCompatSpinner$DropdownPopup": "androidx/widget/AppCompatSpinner$DropdownPopup",
-      "android/support/v7/widget/ActivityChooserModel$ActivitySorter": "androidx/widget/ActivityChooserModel$ActivitySorter",
-      "android/support/wear/widget/drawer/WearableDrawerLayout$ClosePeekRunnable": "androidx/wear/widget/drawer/WearableDrawerLayout$ClosePeekRunnable",
-      "android/support/design/widget/TextInputLayout$SavedState": "androidx/design/widget/TextInputLayout$SavedState",
-      "android/support/v17/leanback/widget/picker/PickerUtility$DateConstant": "androidx/leanback/widget/picker/PickerUtility$DateConstant",
-      "android/support/v13/app/FragmentTabHost": "androidx/app/legacy/FragmentTabHost",
-      "android/support/v7/widget/ScrollingTabContainerView$TabAdapter": "androidx/widget/ScrollingTabContainerView$TabAdapter",
-      "android/support/v7/widget/ActionBarContextView": "androidx/widget/ActionBarContextView",
-      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuHeaderItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuHeaderItem",
-      "android/support/v17/leanback/graphics/CompositeDrawable": "androidx/leanback/graphics/CompositeDrawable",
-      "android/support/v7/preference/Preference$OnPreferenceChangeListener": "androidx/preference/Preference$OnPreferenceChangeListener",
-      "android/support/v4/media/MediaBrowserServiceCompat$BrowserRoot": "androidx/media/MediaBrowserServiceCompat$BrowserRoot",
-      "android/support/text/emoji/MetadataListReader$OpenTypeReader": "androidx/text/emoji/MetadataListReader$OpenTypeReader",
-      "android/support/v7/media/MediaRouterJellybean$VolumeCallbackProxy": "androidx/media/MediaRouterJellybean$VolumeCallbackProxy",
-      "android/support/v4/app/OneShotPreDrawListener": "androidx/app/OneShotPreDrawListener",
-      "android/support/design/widget/BottomNavigationView$OnNavigationItemSelectedListener": "androidx/design/widget/BottomNavigationView$OnNavigationItemSelectedListener",
-      "android/support/v7/widget/ActionMenuView": "androidx/widget/ActionMenuView",
-      "android/support/v4/view/NestedScrollingChildHelper": "androidx/view/NestedScrollingChildHelper",
-      "android/support/percent/PercentFrameLayout": "androidx/PercentFrameLayout",
-      "android/support/annotation/AnyRes": "androidx/annotation/AnyRes",
-      "android/support/wear/widget/CircledImageView$OvalShadowPainter": "androidx/wear/widget/CircledImageView$OvalShadowPainter",
-      "android/support/media/tv/TvContractCompat$Channels$Logo": "androidx/media/tv/TvContractCompat$Channels$Logo",
-      "android/support/v4/view/animation/LookupTableInterpolator": "androidx/view/animation/LookupTableInterpolator",
-      "android/support/v7/app/MediaRouteControllerDialog$MediaControllerCallback": "androidx/app/MediaRouteControllerDialog$MediaControllerCallback",
-      "android/support/v7/widget/FitWindowsViewGroup": "androidx/widget/FitWindowsViewGroup",
-      "android/support/v7/widget/ActionBarOverlayLayout$ActionBarVisibilityCallback": "androidx/widget/ActionBarOverlayLayout$ActionBarVisibilityCallback",
-      "android/support/wear/ambient/AmbientMode": "androidx/wear/ambient/AmbientMode",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$SkipPreviousAction": "androidx/leanback/widget/PlaybackControlsRow$SkipPreviousAction",
-      "android/support/v4/app/NotificationCompat$Builder": "androidx/app/NotificationCompat$Builder",
-      "android/support/design/R$layout": "androidx/design/R$layout",
-      "android/support/transition/FragmentTransitionSupport": "androidx/transition/FragmentTransitionSupport",
-      "android/support/v4/app/Fragment$AnimationInfo": "androidx/app/Fragment$AnimationInfo",
-      "android/support/transition/ChangeTransform": "androidx/transition/ChangeTransform",
-      "android/support/v4/view/ViewCompat$FocusRelativeDirection": "androidx/view/legacy/ViewCompat$FocusRelativeDirection",
-      "android/support/customtabs/CustomTabsSessionToken$MockCallback": "androidx/browser/customtabs/CustomTabsSessionToken$MockCallback",
-      "android/support/v4/app/TaskStackBuilder$TaskStackBuilderBaseImpl": "androidx/app/TaskStackBuilder$TaskStackBuilderBaseImpl",
-      "android/support/v4/media/AudioAttributesCompat$Builder": "androidx/media/AudioAttributesCompat$Builder",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsAction",
-      "android/support/v7/media/MediaItemStatus$Builder": "androidx/media/MediaItemStatus$Builder",
-      "android/support/v17/leanback/app/OnboardingSupportFragment": "androidx/leanback/app/OnboardingSupportFragment",
-      "android/support/v7/widget/LinearLayoutCompat$OrientationMode": "androidx/widget/LinearLayoutCompat$OrientationMode",
-      "android/support/v7/widget/AppCompatImageButton": "androidx/widget/AppCompatImageButton",
-      "android/support/v7/app/AppCompatViewInflater$DeclaredOnClickListener": "androidx/app/AppCompatViewInflater$DeclaredOnClickListener",
-      "android/support/v7/view/SupportMenuInflater$InflatedOnMenuItemClickListener": "androidx/view/SupportMenuInflater$InflatedOnMenuItemClickListener",
-      "android/support/v4/widget/ContentLoadingProgressBar": "androidx/widget/ContentLoadingProgressBar",
-      "android/support/v4/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi17Impl": "androidx/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi17Impl",
-      "android/support/v17/leanback/app/BrowseFragment$ListRowFragmentFactory": "androidx/leanback/app/BrowseFragment$ListRowFragmentFactory",
-      "android/support/v7/app/MediaRouteChooserDialog$RouteAdapter": "androidx/app/MediaRouteChooserDialog$RouteAdapter",
-      "android/support/v7/view/ContextThemeWrapper": "androidx/view/ContextThemeWrapper",
-      "android/support/design/widget/CoordinatorLayout$OnPreDrawListener": "androidx/design/widget/CoordinatorLayout$OnPreDrawListener",
-      "android/support/v4/util/ContainerHelpers": "androidx/util/ContainerHelpers",
-      "android/support/design/widget/SnackbarManager$Callback": "androidx/design/widget/SnackbarManager$Callback",
-      "android/support/design/internal/ForegroundLinearLayout": "androidx/design/internal/ForegroundLinearLayout",
-      "android/support/v4/app/NotificationCompatJellybean": "androidx/app/NotificationCompatJellybean",
-      "android/support/design/widget/CoordinatorLayout$Behavior": "androidx/design/widget/CoordinatorLayout$Behavior",
-      "android/support/compat/R$dimen": "androidx/compat/R$dimen",
-      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterProvider": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterProvider",
-      "android/support/wear/widget/SwipeDismissLayout$OnDismissedListener": "androidx/wear/widget/SwipeDismissLayout$OnDismissedListener",
-      "android/support/v7/recyclerview/R": "androidx/recyclerview/R",
-      "android/support/v4/widget/SlidingPaneLayout$LayoutParams": "androidx/widget/SlidingPaneLayout$LayoutParams",
-      "android/support/v7/app/ToolbarActionBar$ActionMenuPresenterCallback": "androidx/app/ToolbarActionBar$ActionMenuPresenterCallback",
-      "android/support/v4/widget/DrawerLayout$DrawerListener": "androidx/widget/DrawerLayout$DrawerListener",
-      "android/support/v4/net/ConnectivityManagerCompat$RestrictBackgroundStatus": "androidx/net/ConnectivityManagerCompat$RestrictBackgroundStatus",
-      "android/support/v4/media/MediaMetadataCompat$RatingKey": "androidx/media/MediaMetadataCompat$RatingKey",
-      "android/support/v4/view/ActionProvider": "androidx/view/ActionProvider",
-      "android/support/v7/app/MediaRouteControllerDialogFragment": "androidx/app/MediaRouteControllerDialogFragment",
-      "android/support/v7/widget/TooltipCompatHandler": "androidx/widget/TooltipCompatHandler",
-      "android/support/design/widget/TabLayout$TabLayoutOnPageChangeListener": "androidx/design/widget/TabLayout$TabLayoutOnPageChangeListener",
-      "android/support/v7/widget/RecyclerView$ItemAnimatorRestoreListener": "androidx/widget/RecyclerView$ItemAnimatorRestoreListener",
-      "android/support/app/recommendation/ContentRecommendation$ContentType": "androidx/app/recommendation/ContentRecommendation$ContentType",
-      "android/support/v7/app/AlertController$AlertParams": "androidx/app/AlertController$AlertParams",
-      "android/support/v4/widget/DrawerLayout$SimpleDrawerListener": "androidx/widget/DrawerLayout$SimpleDrawerListener",
-      "android/support/v17/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight": "androidx/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight",
-      "android/support/v7/app/MediaRouteChooserDialog$MediaRouterCallback": "androidx/app/MediaRouteChooserDialog$MediaRouterCallback",
-      "android/support/v4/view/ViewCompat$ImportantForAccessibility": "androidx/view/legacy/ViewCompat$ImportantForAccessibility",
-      "android/support/v7/media/MediaRouterJellybean$RouteInfo": "androidx/media/MediaRouterJellybean$RouteInfo",
-      "android/support/v17/leanback/widget/SpeechRecognitionCallback": "androidx/leanback/widget/SpeechRecognitionCallback",
-      "android/support/v4/media/MediaBrowserCompatApi26$SubscriptionCallback": "androidx/media/MediaBrowserCompatApi26$SubscriptionCallback",
-      "android/support/media/tv/Program": "androidx/media/tv/Program",
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat",
-      "android/support/v4/app/FragmentTransitionCompat21": "androidx/app/FragmentTransitionCompat21",
-      "android/support/v7/media/MediaRouteSelector$Builder": "androidx/media/MediaRouteSelector$Builder",
-      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat": "androidx/hardware/fingerprint/FingerprintManagerCompat",
-      "android/support/v17/leanback/app/HeadersFragment": "androidx/leanback/app/HeadersFragment",
-      "android/support/v17/leanback/R$dimen": "androidx/leanback/R$dimen",
-      "android/support/v4/content/res/ResourcesCompat": "androidx/content/res/ResourcesCompat",
-      "android/support/v4/view/ViewPager$SavedState": "androidx/view/ViewPager$SavedState",
-      "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperJbmr2Impl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperJbmr2Impl",
-      "android/support/v4/widget/SwipeRefreshLayout": "androidx/widget/SwipeRefreshLayout",
-      "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperVersionImpl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperVersionImpl",
-      "android/support/v4/os/ResultReceiver": "androidx/os/ResultReceiver",
-      "android/support/v17/leanback/widget/BaseCardView$InfoOffsetAnimation": "androidx/leanback/widget/BaseCardView$InfoOffsetAnimation",
-      "android/support/design/widget/SwipeDismissBehavior$SettleRunnable": "androidx/design/widget/SwipeDismissBehavior$SettleRunnable",
-      "android/support/v13/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl": "androidx/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl",
-      "android/support/v17/leanback/widget/FacetProvider": "androidx/leanback/widget/FacetProvider",
-      "android/support/v7/widget/FitWindowsLinearLayout": "androidx/widget/FitWindowsLinearLayout",
-      "android/support/v4/widget/SwipeProgressBar": "androidx/widget/SwipeProgressBar",
-      "android/support/v7/widget/ActionMenuPresenter$OverflowPopup": "androidx/widget/ActionMenuPresenter$OverflowPopup",
-      "android/support/v7/widget/AppCompatImageHelper": "androidx/widget/AppCompatImageHelper",
-      "android/support/v4/text/TextDirectionHeuristicsCompat": "androidx/text/TextDirectionHeuristicsCompat",
-      "android/support/compat/R$color": "androidx/compat/R$color",
-      "android/support/transition/Transition$EpicenterCallback": "androidx/transition/Transition$EpicenterCallback",
-      "android/support/transition/PropertyValuesHolderUtilsApi14": "androidx/transition/PropertyValuesHolderUtilsApi14",
-      "android/support/v17/leanback/widget/ObjectAdapter$DataObservable": "androidx/leanback/widget/ObjectAdapter$DataObservable",
-      "android/support/multidex/ZipUtil": "androidx/multidex/ZipUtil",
-      "android/support/v7/view/menu/MenuDialogHelper": "androidx/view/menu/MenuDialogHelper",
-      "android/support/v17/preference/R$id": "androidx/leanback/preference/R$id",
-      "android/support/v4/app/BundleCompat": "androidx/app/BundleCompat",
-      "android/support/v4/media/session/IMediaSession$Stub$Proxy": "androidx/media/session/IMediaSession$Stub$Proxy",
-      "android/support/v7/widget/AppCompatTextHelper": "androidx/widget/AppCompatTextHelper",
-      "android/support/v7/view/ActionMode$Callback": "androidx/view/ActionMode$Callback",
-      "android/support/v17/leanback/app/RowsSupportFragment": "androidx/leanback/app/RowsSupportFragment",
-      "android/support/v17/leanback/app/GuidedStepFragment$DummyFragment": "androidx/leanback/app/GuidedStepFragment$DummyFragment",
-      "android/support/v7/widget/util/SortedListAdapterCallback": "androidx/widget/util/SortedListAdapterCallback",
-      "android/support/design/internal/BottomNavigationPresenter$SavedState": "androidx/design/internal/BottomNavigationPresenter$SavedState",
-      "android/support/v7/widget/LinearSmoothScroller": "androidx/widget/LinearSmoothScroller",
-      "android/support/v17/leanback/media/MediaPlayerGlue$VideoPlayerSurfaceHolderCallback": "androidx/leanback/media/MediaPlayerGlue$VideoPlayerSurfaceHolderCallback",
-      "android/support/v7/preference/Preference": "androidx/preference/Preference",
-      "android/support/v4/os/UserManagerCompat": "androidx/os/UserManagerCompat",
-      "android/support/v7/widget/GridLayoutManager$DefaultSpanSizeLookup": "androidx/widget/GridLayoutManager$DefaultSpanSizeLookup",
-      "android/support/v17/leanback/app/PlaybackFragment": "androidx/leanback/app/PlaybackFragment",
-      "android/support/transition/ViewOverlayImpl": "androidx/transition/ViewOverlayImpl",
-      "android/support/transition/ViewOverlayApi14$OverlayViewGroup$TouchInterceptor": "androidx/transition/ViewOverlayApi14$OverlayViewGroup$TouchInterceptor",
-      "android/support/v7/view/menu/MenuAdapter": "androidx/view/menu/MenuAdapter",
-      "android/support/v4/app/NotificationCompat$MessagingStyle$Message": "androidx/app/NotificationCompat$MessagingStyle$Message",
-      "android/support/v4/graphics/drawable/DrawableWrapperApi21$DrawableWrapperStateLollipop": "androidx/graphics/drawable/DrawableWrapperApi21$DrawableWrapperStateLollipop",
-      "android/support/v17/leanback/widget/ItemAlignmentFacet$ItemAlignmentDef": "androidx/leanback/widget/ItemAlignmentFacet$ItemAlignmentDef",
-      "android/support/v4/content/SharedPreferencesCompat": "androidx/content/SharedPreferencesCompat",
-      "android/support/v4/app/FragmentManager$BackStackEntry": "androidx/app/FragmentManager$BackStackEntry",
-      "android/support/transition/PropertyValuesHolderUtilsApi21": "androidx/transition/PropertyValuesHolderUtilsApi21",
-      "android/support/v17/leanback/R$color": "androidx/leanback/R$color",
-      "android/support/v7/view/menu/MenuView": "androidx/view/menu/MenuView",
-      "android/support/transition/Transition": "androidx/transition/Transition",
-      "android/support/v17/leanback/app/PlaybackFragmentGlueHost": "androidx/leanback/app/PlaybackFragmentGlueHost",
-      "android/support/v7/graphics/Target": "androidx/graphics/palette/Target",
-      "android/support/v7/view/StandaloneActionMode": "androidx/view/StandaloneActionMode",
-      "android/support/v13/view/DragAndDropPermissionsCompat$Api24DragAndDropPermissionsCompatImpl": "androidx/view/DragAndDropPermissionsCompat$Api24DragAndDropPermissionsCompatImpl",
-      "android/support/v7/widget/ViewInfoStore$ProcessCallback": "androidx/widget/ViewInfoStore$ProcessCallback",
-      "android/support/v4/media/session/MediaSessionCompatApi24": "androidx/media/session/MediaSessionCompatApi24",
-      "android/support/v4/widget/CursorFilter": "androidx/widget/CursorFilter",
-      "android/support/v4/media/session/MediaSessionCompatApi23": "androidx/media/session/MediaSessionCompatApi23",
-      "android/support/v4/media/session/MediaSessionCompatApi22": "androidx/media/session/MediaSessionCompatApi22",
-      "android/support/v7/app/ActionBarDrawerToggle$DelegateProvider": "androidx/app/ActionBarDrawerToggle$DelegateProvider",
-      "android/support/v4/media/session/MediaSessionCompatApi21": "androidx/media/session/MediaSessionCompatApi21",
-      "android/support/v7/widget/RecyclerView$OnItemTouchListener": "androidx/widget/RecyclerView$OnItemTouchListener",
-      "android/support/v4/media/MediaBrowserServiceCompat$ServiceHandler": "androidx/media/MediaBrowserServiceCompat$ServiceHandler",
-      "android/support/v4/view/PagerTitleStrip": "androidx/widget/PagerTitleStrip",
-      "android/support/v17/leanback/media/MediaPlayerAdapter$VideoPlayerSurfaceHolderCallback": "androidx/leanback/media/MediaPlayerAdapter$VideoPlayerSurfaceHolderCallback",
-      "android/support/v7/widget/ButtonBarLayout": "androidx/widget/ButtonBarLayout",
-      "android/support/annotation/PluralsRes": "androidx/annotation/PluralsRes",
-      "android/support/v7/appcompat/R$styleable": "androidx/appcompat/R$styleable",
-      "android/support/v7/widget/Toolbar": "androidx/widget/Toolbar",
-      "android/support/v17/leanback/app/DetailsFragmentBackgroundController": "androidx/leanback/app/DetailsFragmentBackgroundController",
-      "android/support/v7/view/menu/CascadingMenuPopup$CascadingMenuInfo": "androidx/view/menu/CascadingMenuPopup$CascadingMenuInfo",
-      "android/support/wear/widget/RoundedDrawable": "androidx/wear/widget/RoundedDrawable",
-      "android/support/v4/math/MathUtils": "androidx/math/MathUtils",
-      "android/support/design/widget/FloatingActionButton": "androidx/design/widget/FloatingActionButton",
-      "android/support/v7/mediarouter/R$drawable": "androidx/mediarouter/R$drawable",
-      "android/support/v4/view/MenuCompat": "androidx/view/MenuCompat",
-      "android/support/v17/leanback/widget/ListRowPresenter$SelectItemViewHolderTask": "androidx/leanback/widget/ListRowPresenter$SelectItemViewHolderTask",
-      "android/support/v7/appcompat/R$color": "androidx/appcompat/R$color",
-      "android/support/media/tv/BaseProgram$Builder": "androidx/media/tv/BaseProgram$Builder",
-      "android/support/v17/leanback/widget/ControlButtonPresenterSelector": "androidx/leanback/widget/ControlButtonPresenterSelector",
-      "android/support/v4/util/MapCollections$KeySet": "androidx/util/MapCollections$KeySet",
-      "android/support/annotation/XmlRes": "androidx/annotation/XmlRes",
-      "android/support/v7/widget/RecyclerView$LayoutManager$Properties": "androidx/widget/RecyclerView$LayoutManager$Properties",
-      "android/support/v4/media/MediaBrowserCompat$ConnectionCallback$ConnectionCallbackInternal": "androidx/media/MediaBrowserCompat$ConnectionCallback$ConnectionCallbackInternal",
-      "android/support/v4/app/RemoteInput$Builder": "androidx/app/RemoteInput$Builder",
-      "android/support/wear/widget/WearableRecyclerView": "androidx/wear/widget/WearableRecyclerView",
-      "android/support/v7/app/AppCompatDialog": "androidx/app/AppCompatDialog",
-      "android/support/v4/app/NotificationManagerCompat$SideChannelManager$ListenerRecord": "androidx/app/NotificationManagerCompat$SideChannelManager$ListenerRecord",
-      "android/support/v4/print/PrintHelper$OnPrintFinishCallback": "androidx/print/PrintHelper$OnPrintFinishCallback",
-      "android/support/v17/leanback/app/FragmentUtil": "androidx/leanback/app/FragmentUtil",
-      "android/support/v17/leanback/widget/RowPresenter$ContainerViewHolder": "androidx/leanback/widget/RowPresenter$ContainerViewHolder",
-      "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi24": "androidx/media/session/MediaControllerCompat$TransportControlsApi24",
-      "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatImpl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatImpl",
-      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$ViewHolder$OnItemClickListener": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$ViewHolder$OnItemClickListener",
+      "android/support/v17/leanback/app/BackgroundFragment": "androidx/leanback/app/BackgroundFragment",
+      "android/support/v17/leanback/app/BackgroundManager": "androidx/leanback/app/BackgroundManager",
+      "android/support/v17/leanback/app/BackgroundManager$1$1": "androidx/leanback/app/BackgroundManager$1$1",
+      "android/support/v17/leanback/app/BackgroundManager$1": "androidx/leanback/app/BackgroundManager$1",
       "android/support/v17/leanback/app/BackgroundManager$TranslucentLayerDrawable": "androidx/leanback/app/BackgroundManager$TranslucentLayerDrawable",
-      "android/support/v4/app/FragmentManagerState": "androidx/app/FragmentManagerState",
-      "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi23": "androidx/media/session/MediaControllerCompat$TransportControlsApi23",
-      "android/support/v4/view/AsyncLayoutInflater$BasicInflater": "androidx/view/AsyncLayoutInflater$BasicInflater",
-      "android/support/v7/appcompat/R$dimen": "androidx/appcompat/R$dimen",
-      "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi21": "androidx/media/session/MediaControllerCompat$TransportControlsApi21",
-      "android/support/wear/widget/CircularProgressLayout": "androidx/wear/widget/CircularProgressLayout",
-      "android/support/v7/media/SystemMediaRouteProvider$JellybeanMr1Impl": "androidx/media/SystemMediaRouteProvider$JellybeanMr1Impl",
-      "android/support/customtabs/ICustomTabsCallback$Stub": "androidx/browser/customtabs/ICustomTabsCallback$Stub",
-      "android/support/v17/leanback/widget/RowPresenter$ViewHolder": "androidx/leanback/widget/RowPresenter$ViewHolder",
-      "android/support/v7/widget/RecyclerView$LayoutManager$LayoutPrefetchRegistry": "androidx/widget/RecyclerView$LayoutManager$LayoutPrefetchRegistry",
-      "android/support/v4/media/MediaBrowserServiceCompatApi23$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi23$MediaBrowserServiceAdaptor",
-      "android/support/v17/leanback/app/ListRowDataAdapter": "androidx/leanback/app/ListRowDataAdapter",
-      "android/support/v4/graphics/drawable/DrawableWrapper": "androidx/graphics/drawable/internal/DrawableWrapper",
-      "android/support/v7/widget/SuggestionsAdapter": "androidx/widget/SuggestionsAdapter",
-      "android/support/v4/widget/TextViewCompat": "androidx/widget/TextViewCompat",
-      "android/support/animation/FlingAnimation": "androidx/animation/FlingAnimation",
-      "android/support/media/tv/PreviewProgram$Builder": "androidx/media/tv/PreviewProgram$Builder",
-      "android/support/v7/widget/RecyclerView$AdapterDataObservable": "androidx/widget/RecyclerView$AdapterDataObservable",
-      "android/support/v17/leanback/app/BaseRowSupportFragment$LateSelectionObserver": "androidx/leanback/app/BaseRowSupportFragment$LateSelectionObserver",
-      "android/support/design/internal/SnackbarContentLayout": "androidx/design/internal/SnackbarContentLayout",
-      "android/support/v17/leanback/widget/BaseGridView$OnMotionInterceptListener": "androidx/leanback/widget/BaseGridView$OnMotionInterceptListener",
-      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder",
-      "android/support/v7/widget/CardViewBaseImpl": "androidx/widget/CardViewBaseImpl",
-      "android/support/v4/provider/FontsContractCompat$FontFamilyResult": "androidx/provider/FontsContractCompat$FontFamilyResult",
-      "android/support/v4/os/ResultReceiver$MyRunnable": "androidx/os/ResultReceiver$MyRunnable",
-      "android/support/v7/media/MediaRouteProvider$RouteController": "androidx/media/MediaRouteProvider$RouteController",
-      "android/support/v14/preference/PreferenceFragment$DividerDecoration": "androidx/preference/PreferenceFragment$DividerDecoration",
-      "android/support/text/emoji/flatbuffer/MetadataItem": "androidx/text/emoji/flatbuffer/MetadataItem",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi18": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi18",
-      "android/support/v7/widget/ToolbarWidgetWrapper": "androidx/widget/ToolbarWidgetWrapper",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi19": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi19",
-      "android/support/v7/widget/helper/ItemTouchHelper$ItemTouchHelperGestureListener": "androidx/widget/helper/ItemTouchHelper$ItemTouchHelperGestureListener",
-      "android/support/v7/appcompat/R$layout": "androidx/appcompat/R$layout",
-      "android/support/text/emoji/widget/EmojiEditTextHelper$HelperInternal19": "androidx/text/emoji/widget/EmojiEditTextHelper$HelperInternal19",
+      "android/support/v17/leanback/R$id": "androidx/leanback/R$id",
+      "android/support/v17/leanback/R": "androidx/leanback/R",
+      "android/support/v17/leanback/app/BackgroundManager$2": "androidx/leanback/app/BackgroundManager$2",
+      "android/support/v17/leanback/app/BackgroundManager$BackgroundContinuityService": "androidx/leanback/app/BackgroundManager$BackgroundContinuityService",
+      "android/support/v4/content/ContextCompat": "androidx/content/ContextCompat",
       "android/support/v17/leanback/app/BackgroundManager$BitmapDrawable$ConstantState": "androidx/leanback/app/BackgroundManager$BitmapDrawable$ConstantState",
-      "android/support/design/widget/FloatingActionButtonImpl$ShadowAnimatorImpl": "androidx/design/widget/FloatingActionButtonImpl$ShadowAnimatorImpl",
-      "android/support/v7/widget/FastScroller$AnimatorListener": "androidx/widget/FastScroller$AnimatorListener",
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter",
-      "android/support/v4/app/NotificationCompat$WearableExtender": "androidx/app/NotificationCompat$WearableExtender",
-      "android/support/v17/leanback/widget/FocusHighlightHandler": "androidx/leanback/widget/FocusHighlightHandler",
-      "android/support/transition/Slide$GravityFlag": "androidx/transition/Slide$GravityFlag",
-      "android/support/v4/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener": "androidx/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener",
-      "android/support/v4/widget/ListViewCompat": "androidx/widget/ListViewCompat",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi21",
-      "android/support/graphics/drawable/Animatable2Compat$AnimationCallback": "androidx/graphics/drawable/Animatable2Compat$AnimationCallback",
-      "android/support/v17/leanback/widget/ControlButtonPresenterSelector$ActionViewHolder": "androidx/leanback/widget/ControlButtonPresenterSelector$ActionViewHolder",
-      "android/support/transition/GhostViewApi14$Creator": "androidx/transition/GhostViewApi14$Creator",
-      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi19Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi19Impl",
-      "android/support/v17/leanback/widget/GuidedActionsStylist": "androidx/leanback/widget/GuidedActionsStylist",
-      "android/support/v4/app/ActivityCompat$SharedElementCallback21Impl": "androidx/app/legacy/ActivityCompat$SharedElementCallback21Impl",
-      "android/support/v17/leanback/app/BrowseFragment$FragmentFactory": "androidx/leanback/app/BrowseFragment$FragmentFactory",
-      "android/support/v7/widget/DefaultItemAnimator$MoveInfo": "androidx/widget/DefaultItemAnimator$MoveInfo",
-      "android/support/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloader": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloader",
-      "android/support/v4/media/MediaBrowserCompat": "androidx/media/MediaBrowserCompat",
-      "android/support/v7/media/MediaRouter$RouteGroup": "androidx/media/MediaRouter$RouteGroup",
-      "android/support/v4/view/ViewCompat$OverScroll": "androidx/view/legacy/ViewCompat$OverScroll",
-      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver": "androidx/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver",
-      "android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21": "androidx/leanback/preference/LeanbackPreferenceFragmentTransitionHelperApi21",
-      "android/support/v17/leanback/widget/BaseGridView$OnUnhandledKeyListener": "androidx/leanback/widget/BaseGridView$OnUnhandledKeyListener",
-      "android/support/v7/view/menu/ActionMenuItemView$ActionMenuItemForwardingListener": "androidx/view/menu/ActionMenuItemView$ActionMenuItemForwardingListener",
-      "android/support/v17/leanback/transition/FadeAndShortSlide": "androidx/leanback/transition/FadeAndShortSlide",
-      "android/support/v7/app/NavItemSelectedListener": "androidx/app/NavItemSelectedListener",
-      "android/support/v4/content/pm/ShortcutManagerCompat": "androidx/content/pm/ShortcutManagerCompat",
-      "android/support/v4/app/FragmentActivity$HostCallbacks": "androidx/app/FragmentActivity$HostCallbacks",
-      "android/support/design/widget/CoordinatorLayout$LayoutParams": "androidx/design/widget/CoordinatorLayout$LayoutParams",
-      "android/support/v4/view/MenuItemCompat$MenuItemCompatApi26Impl": "androidx/view/MenuItemCompat$MenuItemCompatApi26Impl",
-      "android/support/transition/ViewGroupOverlayApi18": "androidx/transition/ViewGroupOverlayApi18",
-      "android/support/v17/preference/LeanbackSettingsFragment": "androidx/leanback/preference/LeanbackSettingsFragment",
-      "android/support/v17/leanback/widget/RowHeaderPresenter$ViewHolder": "androidx/leanback/widget/RowHeaderPresenter$ViewHolder",
-      "android/support/wear/ambient/AmbientMode$AmbientController": "androidx/wear/ambient/AmbientMode$AmbientController",
-      "android/support/v7/cardview/R$color": "androidx/cardview/R$color",
-      "android/support/annotation/MenuRes": "androidx/annotation/MenuRes",
-      "android/support/v7/media/MediaRouterJellybeanMr2": "androidx/media/MediaRouterJellybeanMr2",
-      "android/support/v7/widget/GridLayout$PackedMap": "androidx/widget/GridLayout$PackedMap",
-      "android/support/v7/media/MediaRouterJellybeanMr1": "androidx/media/MediaRouterJellybeanMr1",
-      "android/support/transition/ViewGroupOverlayApi14": "androidx/transition/ViewGroupOverlayApi14",
-      "android/support/v7/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo": "androidx/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo",
-      "android/support/wear/widget/drawer/FlingWatcherFactory$FlingWatcher": "androidx/wear/widget/drawer/FlingWatcherFactory$FlingWatcher",
-      "android/support/v17/leanback/widget/SparseArrayObjectAdapter": "androidx/leanback/widget/SparseArrayObjectAdapter",
-      "android/support/v4/media/session/MediaSessionCompatApi21$CallbackProxy": "androidx/media/session/MediaSessionCompatApi21$CallbackProxy",
-      "android/support/v4/app/NotificationCompat$CarExtender": "androidx/app/NotificationCompat$CarExtender",
-      "android/support/v17/leanback/widget/PlaybackControlsRowView$OnUnhandledKeyListener": "androidx/leanback/widget/PlaybackControlsRowView$OnUnhandledKeyListener",
-      "android/support/v7/view/menu/MenuPopupHelper": "androidx/view/menu/MenuPopupHelper",
-      "android/support/v17/leanback/app/VideoSupportFragment": "androidx/leanback/app/VideoSupportFragment",
-      "android/support/media/tv/Channel": "androidx/media/tv/Channel",
-      "android/support/v4/media/AudioAttributesCompat$AttributeContentType": "androidx/media/AudioAttributesCompat$AttributeContentType",
-      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper$TransitionTimeOutRunnable": "androidx/leanback/widget/DetailsOverviewSharedElementHelper$TransitionTimeOutRunnable",
-      "android/support/v17/leanback/app/BrowseSupportFragment$BrowseTransitionListener": "androidx/leanback/app/BrowseSupportFragment$BrowseTransitionListener",
-      "android/support/v4/view/ViewPager$ViewPositionComparator": "androidx/view/ViewPager$ViewPositionComparator",
-      "android/support/v4/app/NotificationCompat$Action": "androidx/app/NotificationCompat$Action",
-      "android/support/v7/preference/PreferenceManager$SimplePreferenceComparisonCallback": "androidx/preference/PreferenceManager$SimplePreferenceComparisonCallback",
-      "android/support/media/tv/TvContractCompat$BaseTvColumns": "androidx/media/tv/TvContractCompat$BaseTvColumns",
-      "android/support/v4/media/session/PlaybackStateCompat$ShuffleMode": "androidx/media/session/PlaybackStateCompat$ShuffleMode",
-      "android/support/v7/app/WindowDecorActionBar$TabImpl": "androidx/app/WindowDecorActionBar$TabImpl",
-      "android/support/graphics/drawable/VectorDrawableCompat$VectorDrawableDelegateState": "androidx/graphics/drawable/VectorDrawableCompat$VectorDrawableDelegateState",
-      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl": "androidx/media/SystemMediaRouteProvider$JellybeanImpl",
-      "android/support/v7/widget/VectorEnabledTintResources": "androidx/widget/VectorEnabledTintResources",
-      "android/support/v7/preference/EditTextPreferenceDialogFragmentCompat": "androidx/preference/EditTextPreferenceDialogFragmentCompat",
-      "android/support/v4/graphics/drawable/DrawableWrapperApi19$DrawableWrapperStateKitKat": "androidx/graphics/drawable/DrawableWrapperApi19$DrawableWrapperStateKitKat",
-      "android/support/v17/leanback/transition/TransitionHelperKitkat$CustomChangeBounds": "androidx/leanback/transition/TransitionHelperKitkat$CustomChangeBounds",
-      "android/support/v4/app/FragmentManagerImpl$StartEnterTransitionListener": "androidx/app/FragmentManagerImpl$StartEnterTransitionListener",
-      "android/support/v4/view/LayoutInflaterCompat$LayoutInflaterCompatBaseImpl": "androidx/view/LayoutInflaterCompat$LayoutInflaterCompatBaseImpl",
-      "android/support/v7/view/SupportMenuInflater$MenuState": "androidx/view/SupportMenuInflater$MenuState",
-      "android/support/v17/leanback/app/GuidedStepFragment": "androidx/leanback/app/GuidedStepFragment",
-      "android/support/v17/leanback/widget/PagingIndicator": "androidx/leanback/widget/PagingIndicator",
-      "android/support/v7/app/MediaRouteControllerDialog$MediaRouterCallback": "androidx/app/MediaRouteControllerDialog$MediaRouterCallback",
-      "android/support/design/widget/CoordinatorLayout$DefaultBehavior": "androidx/design/widget/CoordinatorLayout$DefaultBehavior",
-      "android/support/v4/os/LocaleListInterface": "androidx/os/LocaleListInterface",
-      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$AuthenticationCallback": "androidx/hardware/fingerprint/FingerprintManagerCompat$AuthenticationCallback",
-      "android/support/v17/leanback/widget/Parallax$FloatProperty": "androidx/leanback/widget/Parallax$FloatProperty",
-      "android/support/v4/app/NotificationCompat$Style": "androidx/app/NotificationCompat$Style",
-      "android/support/v4/app/FrameMetricsAggregator$FrameMetricsApi24Impl": "androidx/app/FrameMetricsAggregator$FrameMetricsApi24Impl",
-      "android/support/v17/leanback/app/HeadersSupportFragment$OnHeaderClickedListener": "androidx/leanback/app/HeadersSupportFragment$OnHeaderClickedListener",
-      "android/support/v7/preference/PreferenceManager$OnNavigateToScreenListener": "androidx/preference/PreferenceManager$OnNavigateToScreenListener",
-      "android/support/v7/widget/AdapterHelper": "androidx/widget/AdapterHelper",
-      "android/support/v17/leanback/transition/SlideKitkat$CalculateSlideHorizontal": "androidx/leanback/transition/SlideKitkat$CalculateSlideHorizontal",
-      "android/support/v4/graphics/ColorUtils": "androidx/graphics/ColorUtils",
-      "android/support/v7/widget/ActionMenuPresenter$OverflowMenuButton": "androidx/widget/ActionMenuPresenter$OverflowMenuButton",
-      "android/support/v7/widget/ListPopupWindow": "androidx/widget/ListPopupWindow",
-      "android/support/v4/media/MediaBrowserServiceCompatApi21$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi21$MediaBrowserServiceAdaptor",
-      "android/support/v17/leanback/widget/Row": "androidx/leanback/widget/Row",
-      "android/support/v17/leanback/widget/ShadowOverlayHelper": "androidx/leanback/widget/ShadowOverlayHelper",
-      "android/support/wear/internal/widget/drawer/MultiPagePresenter": "androidx/wear/internal/widget/drawer/MultiPagePresenter",
-      "android/support/animation/SpringForce": "androidx/animation/SpringForce",
-      "android/support/customtabs/ICustomTabsService$Stub$Proxy": "androidx/browser/customtabs/ICustomTabsService$Stub$Proxy",
-      "android/support/annotation/StringDef": "androidx/annotation/StringDef",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImpl": "androidx/media/session/MediaControllerCompat$MediaControllerImpl",
-      "android/support/design/widget/CircularBorderDrawableLollipop": "androidx/design/widget/CircularBorderDrawableLollipop",
-      "android/support/v17/leanback/widget/ControlBarPresenter$BoundData": "androidx/leanback/widget/ControlBarPresenter$BoundData",
-      "android/support/v7/widget/RecyclerView$Orientation": "androidx/widget/RecyclerView$Orientation",
-      "android/support/v7/media/MediaRouteProviderService$ReceiveHandler": "androidx/media/MediaRouteProviderService$ReceiveHandler",
-      "android/support/v4/view/ViewPropertyAnimatorListenerAdapter": "androidx/view/ViewPropertyAnimatorListenerAdapter",
-      "android/support/v7/graphics/Palette$Swatch": "androidx/graphics/Palette$Swatch",
-      "android/support/v17/leanback/widget/GridLayoutManager": "androidx/leanback/widget/GridLayoutManager",
-      "android/support/v17/leanback/media/PlaybackGlue": "androidx/leanback/media/PlaybackGlue",
-      "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperApi21Impl": "androidx/leanback/widget/ShadowHelper$ShadowHelperApi21Impl",
-      "android/support/v4/view/ViewCompat": "androidx/view/legacy/ViewCompat",
-      "android/support/v17/leanback/widget/BackgroundHelper": "androidx/leanback/widget/BackgroundHelper",
-      "android/support/design/widget/AppBarLayout$OnOffsetChangedListener": "androidx/design/widget/AppBarLayout$OnOffsetChangedListener",
-      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplJellybeanMr2": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplJellybeanMr2",
-      "android/support/v7/appcompat/R$attr": "androidx/appcompat/R$attr",
-      "android/support/transition/TransitionValuesMaps": "androidx/transition/TransitionValuesMaps",
-      "android/support/v4/view/ViewConfigurationCompat": "androidx/view/ViewConfigurationCompat",
-      "android/support/v4/media/MediaBrowserServiceCompat$ServiceCallbacks": "androidx/media/MediaBrowserServiceCompat$ServiceCallbacks",
-      "android/support/v4/widget/AutoSizeableTextView": "androidx/widget/AutoSizeableTextView",
-      "android/support/v4/view/ViewCompat$LayerType": "androidx/view/legacy/ViewCompat$LayerType",
-      "android/support/v17/leanback/widget/DividerRow": "androidx/leanback/widget/DividerRow",
-      "android/support/v7/widget/ActionMenuPresenter$SavedState": "androidx/widget/ActionMenuPresenter$SavedState",
-      "android/support/design/internal/NavigationMenu": "androidx/design/internal/NavigationMenu",
-      "android/support/v7/preference/Preference$OnPreferenceChangeInternalListener": "androidx/preference/Preference$OnPreferenceChangeInternalListener",
-      "android/support/v4/app/JobIntentService": "androidx/app/JobIntentService",
-      "android/support/v4/app/Fragment": "androidx/app/Fragment",
-      "android/support/v17/leanback/app/BrowseSupportFragment$BackStackListener": "androidx/leanback/app/BrowseSupportFragment$BackStackListener",
-      "android/support/v7/widget/RecyclerView$OnChildAttachStateChangeListener": "androidx/widget/RecyclerView$OnChildAttachStateChangeListener",
-      "android/support/v17/leanback/widget/PlaybackSeekDataProvider": "androidx/leanback/widget/PlaybackSeekDataProvider",
-      "android/support/content/ContentPager": "androidx/content/ContentPager",
-      "android/support/v4/util/MapCollections$MapIterator": "androidx/util/MapCollections$MapIterator",
-      "android/support/app/recommendation/ContentRecommendation": "androidx/app/recommendation/ContentRecommendation",
-      "android/support/v7/app/ActionBar$OnNavigationListener": "androidx/app/ActionBar$OnNavigationListener",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase",
-      "android/support/transition/Styleable$ChangeTransform": "androidx/transition/Styleable$ChangeTransform",
-      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$DefaultRouteController": "androidx/media/SystemMediaRouteProvider$LegacyImpl$DefaultRouteController",
-      "android/support/v4/net/DatagramSocketWrapper$DatagramSocketImplWrapper": "androidx/net/DatagramSocketWrapper$DatagramSocketImplWrapper",
-      "android/support/v17/leanback/R$layout": "androidx/leanback/R$layout",
-      "android/support/v4/app/FragmentHostCallback": "androidx/app/FragmentHostCallback",
-      "android/support/v7/widget/StaggeredGridLayoutManager$AnchorInfo": "androidx/widget/StaggeredGridLayoutManager$AnchorInfo",
-      "android/support/v7/widget/RecyclerView$State": "androidx/widget/RecyclerView$State",
-      "android/support/v7/media/MediaRouterJellybean$Callback": "androidx/media/MediaRouterJellybean$Callback",
-      "android/support/v14/preference/MultiSelectListPreferenceDialogFragment": "androidx/preference/MultiSelectListPreferenceDialogFragment",
-      "android/support/v4/media/MediaBrowserServiceCompatApi21$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi21$ServiceCompatProxy",
-      "android/support/v4/text/util/LinkifyCompat$LinkSpec": "androidx/text/util/LinkifyCompat$LinkSpec",
-      "android/support/v4/app/NotificationManagerCompat$ServiceConnectedEvent": "androidx/app/NotificationManagerCompat$ServiceConnectedEvent",
-      "android/support/v4/graphics/drawable/IconCompat": "androidx/graphics/drawable/IconCompat",
-      "android/support/v17/leanback/graphics/ColorOverlayDimmer": "androidx/leanback/graphics/ColorOverlayDimmer",
-      "android/support/v17/leanback/R$styleable": "androidx/leanback/R$styleable",
-      "android/support/v4/view/AccessibilityDelegateCompat": "androidx/view/AccessibilityDelegateCompat",
-      "android/support/v7/cardview/R$dimen": "androidx/cardview/R$dimen",
-      "android/support/wear/widget/SwipeDismissFrameLayout$Callback": "androidx/wear/widget/SwipeDismissFrameLayout$Callback",
-      "android/support/transition/ArcMotion": "androidx/transition/ArcMotion",
-      "android/support/mediacompat/R$layout": "androidx/mediacompat/R$layout",
-      "android/support/v4/view/ViewPager$ItemInfo": "androidx/view/ViewPager$ItemInfo",
-      "android/support/v4/app/FragmentActivity": "androidx/app/FragmentActivity",
-      "android/support/animation/FloatPropertyCompat": "androidx/animation/FloatPropertyCompat",
-      "android/support/v17/leanback/widget/ObjectAdapter$DataObserver": "androidx/leanback/widget/ObjectAdapter$DataObserver",
-      "android/support/design/widget/AppBarLayout$LayoutParams$ScrollFlags": "androidx/design/widget/AppBarLayout$LayoutParams$ScrollFlags",
-      "android/support/v7/widget/AbsActionBarView": "androidx/widget/AbsActionBarView",
-      "android/support/v4/media/app/NotificationCompat": "androidx/media/app/NotificationCompat",
-      "android/support/v17/leanback/media/PlayerAdapter": "androidx/leanback/media/PlayerAdapter",
-      "android/support/v17/leanback/widget/GridLayoutManager$SavedState": "androidx/leanback/widget/GridLayoutManager$SavedState",
-      "android/support/transition/Fade": "androidx/transition/Fade",
-      "android/support/v17/leanback/R$animator": "androidx/leanback/R$animator",
-      "android/support/v4/view/ViewCompat$ScrollAxis": "androidx/view/legacy/ViewCompat$ScrollAxis",
-      "android/support/v17/leanback/widget/GuidedActionEditText$NoPaddingDrawable": "androidx/leanback/widget/GuidedActionEditText$NoPaddingDrawable",
-      "android/support/v7/widget/GridLayout$Axis": "androidx/widget/GridLayout$Axis",
-      "android/support/v4/app/FragmentManagerImpl$AnimationListenerWrapper": "androidx/app/FragmentManagerImpl$AnimationListenerWrapper",
-      "android/support/v4/view/ViewParentCompat$ViewParentCompatBaseImpl": "androidx/view/ViewParentCompat$ViewParentCompatBaseImpl",
-      "android/support/v7/util/DiffUtil$Snake": "androidx/util/DiffUtil$Snake",
-      "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState": "androidx/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState",
-      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder",
-      "android/support/v4/media/RatingCompat$Style": "androidx/media/RatingCompat$Style",
-      "android/support/v7/widget/GridLayout$Spec": "androidx/widget/GridLayout$Spec",
-      "android/support/constraint/solver/widgets/ConstraintAnchor": "androidx/constraint/solver/widgets/ConstraintAnchor",
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$TransitionTimeOutRunnable": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$TransitionTimeOutRunnable",
-      "android/support/v4/view/LayoutInflaterFactory": "androidx/view/LayoutInflaterFactory",
-      "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterProvider": "androidx/leanback/app/BrowseFragment$MainFragmentAdapterProvider",
-      "android/support/v7/app/OverlayListView$OverlayObject$OnAnimationEndListener": "androidx/app/OverlayListView$OverlayObject$OnAnimationEndListener",
-      "android/support/v7/app/AlertController$RecycleListView": "androidx/app/AlertController$RecycleListView",
-      "android/support/v4/view/ViewCompat$ViewCompatApi18Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi18Impl",
-      "android/support/v4/text/TextUtilsCompat": "androidx/text/TextUtilsCompat",
-      "android/support/v17/leanback/widget/Action": "androidx/leanback/widget/Action",
-      "android/support/v7/widget/RecyclerView$ItemAnimator$AdapterChanges": "androidx/widget/RecyclerView$ItemAnimator$AdapterChanges",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerExtraData": "androidx/media/session/MediaControllerCompat$MediaControllerExtraData",
-      "android/support/v4/media/session/MediaControllerCompat$TransportControlsBase": "androidx/media/session/MediaControllerCompat$TransportControlsBase",
-      "android/support/v13/view/inputmethod/InputConnectionCompat$InputConnectionCompatImpl": "androidx/view/inputmethod/InputConnectionCompat$InputConnectionCompatImpl",
-      "android/support/v4/media/ParceledListSliceAdapterApi21": "androidx/media/ParceledListSliceAdapterApi21",
-      "android/support/v17/leanback/widget/ItemBridgeAdapter": "androidx/leanback/widget/ItemBridgeAdapter",
-      "android/support/v13/view/inputmethod/InputConnectionCompat": "androidx/view/inputmethod/InputConnectionCompat",
-      "android/support/v4/widget/ResourceCursorAdapter": "androidx/widget/ResourceCursorAdapter",
-      "android/support/v7/view/WindowCallbackWrapper": "androidx/view/WindowCallbackWrapper",
-      "android/support/v7/widget/AdapterHelper$UpdateOp": "androidx/widget/AdapterHelper$UpdateOp",
-      "android/support/v4/content/res/FontResourcesParserCompat$FontFileResourceEntry": "androidx/content/res/FontResourcesParserCompat$FontFileResourceEntry",
-      "android/support/v4/app/NavUtils": "androidx/app/NavUtils",
-      "android/support/v4/internal/view/SupportMenuItem": "androidx/internal/view/SupportMenuItem",
-      "android/support/v7/widget/FastScroller$DragState": "androidx/widget/FastScroller$DragState",
-      "android/support/annotation/Size": "androidx/annotation/Size",
-      "android/support/wear/widget/drawer/WearableNavigationDrawerView$OnItemSelectedListener": "androidx/wear/widget/drawer/WearableNavigationDrawerView$OnItemSelectedListener",
-      "android/support/transition/WindowIdImpl": "androidx/transition/WindowIdImpl",
-      "android/support/v7/media/RemoteControlClientCompat$LegacyImpl": "androidx/media/RemoteControlClientCompat$LegacyImpl",
-      "android/support/transition/Slide$CalculateSlideVertical": "androidx/transition/Slide$CalculateSlideVertical",
-      "android/support/v17/leanback/app/VideoFragment": "androidx/leanback/app/VideoFragment",
-      "android/support/v4/widget/NestedScrollView$OnScrollChangeListener": "androidx/widget/NestedScrollView$OnScrollChangeListener",
-      "android/support/v7/media/MediaRouter$CallbackFlags": "androidx/media/MediaRouter$CallbackFlags",
-      "android/support/customtabs/IPostMessageService": "androidx/browser/customtabs/IPostMessageService",
-      "android/support/v4/util/AtomicFile": "androidx/util/AtomicFile",
-      "android/support/v4/provider/DocumentsContractApi19": "androidx/provider/DocumentsContractApi19",
-      "android/support/v17/leanback/widget/picker/Picker$ViewHolder": "androidx/leanback/widget/picker/Picker$ViewHolder",
-      "android/support/v4/widget/AutoScrollHelper": "androidx/widget/AutoScrollHelper",
-      "android/support/v4/widget/DrawerLayout$LockMode": "androidx/widget/DrawerLayout$LockMode",
-      "android/support/v17/leanback/transition/SlideKitkat$CalculateSlideVertical": "androidx/leanback/transition/SlideKitkat$CalculateSlideVertical",
-      "android/support/v4/os/BuildCompat": "androidx/os/BuildCompat",
-      "android/support/wear/ambient/SharedLibraryVersion$PresenceHolder": "androidx/wear/ambient/SharedLibraryVersion$PresenceHolder",
-      "android/support/transition/ObjectAnimatorUtilsImpl": "androidx/transition/ObjectAnimatorUtilsImpl",
-      "android/support/v7/widget/SearchView$OnSuggestionListener": "androidx/widget/SearchView$OnSuggestionListener",
-      "android/support/design/internal/NavigationMenuPresenter": "androidx/design/internal/NavigationMenuPresenter",
-      "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperVersionImpl": "androidx/leanback/widget/ShadowHelper$ShadowHelperVersionImpl",
-      "android/support/v7/media/RemotePlaybackClient$ItemActionCallback": "androidx/media/RemotePlaybackClient$ItemActionCallback",
-      "android/support/annotation/Dimension": "androidx/annotation/Dimension",
-      "android/support/v13/view/DragStartHelper$OnDragStartListener": "androidx/view/DragStartHelper$OnDragStartListener",
-      "android/support/text/emoji/R$id": "androidx/text/emoji/R$id",
-      "android/support/wear/widget/CurvingLayoutCallback": "androidx/wear/widget/CurvingLayoutCallback",
-      "android/support/v17/leanback/app/RowsFragment": "androidx/leanback/app/RowsFragment",
-      "android/support/v7/widget/TooltipCompat": "androidx/widget/TooltipCompat",
-      "android/support/v7/widget/SnapHelper": "androidx/widget/SnapHelper",
-      "android/support/v7/mediarouter/R$layout": "androidx/mediarouter/R$layout",
-      "android/support/transition/R$id": "androidx/transition/R$id",
-      "android/support/v4/graphics/BitmapCompat$BitmapCompatBaseImpl": "androidx/graphics/BitmapCompat$BitmapCompatBaseImpl",
-      "android/support/v4/media/VolumeProviderCompatApi21$Delegate": "androidx/media/VolumeProviderCompatApi21$Delegate",
-      "android/support/v17/leanback/widget/SearchBar$SearchBarListener": "androidx/leanback/widget/SearchBar$SearchBarListener",
-      "android/support/v17/leanback/app/SearchFragment": "androidx/leanback/app/SearchFragment",
-      "android/support/v4/view/LayoutInflaterCompat": "androidx/view/LayoutInflaterCompat",
-      "android/support/v7/widget/CardViewApi21Impl": "androidx/widget/CardViewApi21Impl",
-      "android/support/v17/leanback/widget/VideoSurfaceView": "androidx/leanback/widget/VideoSurfaceView",
-      "android/support/transition/GhostViewImpl": "androidx/transition/GhostViewImpl",
-      "android/support/transition/ChangeBounds": "androidx/transition/ChangeBounds",
-      "android/support/v17/leanback/app/HeadersFragment$OnHeaderViewSelectedListener": "androidx/leanback/app/HeadersFragment$OnHeaderViewSelectedListener",
-      "android/support/media/tv/PreviewProgram": "androidx/media/tv/PreviewProgram",
-      "android/support/annotation/RequiresApi": "androidx/annotation/RequiresApi",
-      "android/support/app/recommendation/RecommendationExtender": "androidx/app/recommendation/RecommendationExtender",
-      "android/support/v17/leanback/app/ErrorSupportFragment": "androidx/leanback/app/ErrorSupportFragment",
-      "android/support/v17/leanback/media/MediaPlayerGlue": "androidx/leanback/media/MediaPlayerGlue",
-      "android/support/v4/media/session/MediaSessionCompatApi21$QueueItem": "androidx/media/session/MediaSessionCompatApi21$QueueItem",
-      "android/support/v17/leanback/widget/AbstractMediaItemPresenter": "androidx/leanback/widget/AbstractMediaItemPresenter",
-      "android/support/annotation/StyleableRes": "androidx/annotation/StyleableRes",
-      "android/support/v4/media/session/PlaybackStateCompat$CustomAction": "androidx/media/session/PlaybackStateCompat$CustomAction",
-      "android/support/wear/widget/drawer/WearableDrawerLayout$TopDrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$TopDrawerDraggerCallback",
-      "android/support/v17/leanback/app/PermissionHelper": "androidx/leanback/app/PermissionHelper",
-      "android/support/transition/R": "androidx/transition/R",
-      "android/support/v17/leanback/transition/SlideKitkat$SlideAnimatorListener": "androidx/leanback/transition/SlideKitkat$SlideAnimatorListener",
-      "android/support/v7/graphics/drawable/DrawerArrowDrawable": "androidx/graphics/drawable/DrawerArrowDrawable",
-      "android/support/v17/leanback/widget/ClassPresenterSelector": "androidx/leanback/widget/ClassPresenterSelector",
-      "android/support/v17/leanback/widget/ControlBarPresenter$OnControlSelectedListener": "androidx/leanback/widget/ControlBarPresenter$OnControlSelectedListener",
-      "android/support/v4/app/NotificationCompat$GroupAlertBehavior": "androidx/app/NotificationCompat$GroupAlertBehavior",
-      "android/support/text/emoji/widget/EmojiInputFilter$InitCallbackImpl": "androidx/text/emoji/widget/EmojiInputFilter$InitCallbackImpl",
-      "android/support/v7/appcompat/R$bool": "androidx/appcompat/R$bool",
-      "android/support/v4/widget/TextViewCompat$AutoSizeTextType": "androidx/widget/TextViewCompat$AutoSizeTextType",
-      "android/support/v4/app/NotificationCompat$BadgeIconType": "androidx/app/NotificationCompat$BadgeIconType",
-      "android/support/v4/app/NotificationCompat$BigTextStyle": "androidx/app/NotificationCompat$BigTextStyle",
-      "android/support/annotation/ColorInt": "androidx/annotation/ColorInt",
-      "android/support/text/emoji/EmojiSpan": "androidx/text/emoji/EmojiSpan",
-      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener",
-      "android/support/percent/PercentRelativeLayout": "androidx/PercentRelativeLayout",
-      "android/support/text/emoji/widget/EmojiInputFilter": "androidx/text/emoji/widget/EmojiInputFilter",
-      "android/support/media/tv/TvContractCompat$PreviewPrograms": "androidx/media/tv/TvContractCompat$PreviewPrograms",
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder",
-      "android/support/v17/leanback/app/BrowseFragment$BackStackListener": "androidx/leanback/app/BrowseFragment$BackStackListener",
-      "android/support/text/emoji/EmojiProcessor$ProcessorSm": "androidx/text/emoji/EmojiProcessor$ProcessorSm",
-      "android/support/v4/view/ViewCompat$ViewCompatBaseImpl": "androidx/view/legacy/ViewCompat$ViewCompatBaseImpl",
-      "android/support/design/internal/BottomNavigationMenu": "androidx/design/internal/BottomNavigationMenu",
-      "android/support/v7/view/menu/BaseMenuWrapper": "androidx/view/menu/BaseMenuWrapper",
-      "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory$DefaultRoundedBitmapDrawable": "androidx/graphics/drawable/RoundedBitmapDrawableFactory$DefaultRoundedBitmapDrawable",
-      "android/support/v17/leanback/widget/OnItemViewClickedListener": "androidx/leanback/widget/OnItemViewClickedListener",
-      "android/support/v4/app/ShareCompat": "androidx/app/ShareCompat",
-      "android/support/v4/app/DialogFragment": "androidx/app/DialogFragment",
-      "android/support/v4/os/ConfigurationCompat": "androidx/os/ConfigurationCompat",
+      "android/support/v17/leanback/app/BackgroundManager$BitmapDrawable": "androidx/leanback/app/BackgroundManager$BitmapDrawable",
+      "android/support/annotation/NonNull": "androidx/annotation/NonNull",
+      "android/support/v17/leanback/app/BackgroundManager$ChangeBackgroundRunnable": "androidx/leanback/app/BackgroundManager$ChangeBackgroundRunnable",
+      "android/support/v17/leanback/app/BackgroundManager$DrawableWrapper": "androidx/leanback/app/BackgroundManager$DrawableWrapper",
+      "android/support/v17/leanback/app/BackgroundManager$EmptyDrawable": "androidx/leanback/app/BackgroundManager$EmptyDrawable",
       "android/support/v4/graphics/drawable/DrawableCompat": "androidx/graphics/drawable/DrawableCompat",
-      "android/support/v17/leanback/widget/PlaybackTransportRowView": "androidx/leanback/widget/PlaybackTransportRowView",
-      "android/support/annotation/ColorRes": "androidx/annotation/ColorRes",
-      "android/support/v4/database/DatabaseUtilsCompat": "androidx/database/DatabaseUtilsCompat",
-      "android/support/v7/app/AppCompatDelegateImplBase$ActionBarDrawableToggleImpl": "androidx/app/AppCompatDelegateImplBase$ActionBarDrawableToggleImpl",
-      "android/support/v7/widget/ForwardingListener": "androidx/widget/ForwardingListener",
-      "android/support/annotation/NavigationRes": "androidx/annotation/NavigationRes",
-      "android/support/v4/widget/TextViewCompat$TextViewCompatApi18Impl": "androidx/widget/TextViewCompat$TextViewCompatApi18Impl",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$Command": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$Command",
-      "android/support/transition/Styleable$ArcMotion": "androidx/transition/Styleable$ArcMotion",
-      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperStubImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperStubImpl",
-      "android/support/text/emoji/widget/EmojiEditTextHelper$HelperInternal": "androidx/text/emoji/widget/EmojiEditTextHelper$HelperInternal",
-      "android/support/wear/widget/BezierSCurveInterpolator": "androidx/wear/widget/BezierSCurveInterpolator",
-      "android/support/v4/view/NestedScrollingParent": "androidx/view/NestedScrollingParent",
-      "android/support/v7/widget/ListPopupWindow$ListSelectorHider": "androidx/widget/ListPopupWindow$ListSelectorHider",
-      "android/support/transition/PathProperty": "androidx/transition/PathProperty",
-      "android/support/v4/provider/FontsContractCompat$FontInfo": "androidx/provider/FontsContractCompat$FontInfo",
-      "android/support/v17/leanback/widget/PlaybackControlsRow": "androidx/leanback/widget/PlaybackControlsRow",
-      "android/support/v17/leanback/widget/Presenter": "androidx/leanback/widget/Presenter",
-      "android/support/v17/leanback/app/VerticalGridFragment": "androidx/leanback/app/VerticalGridFragment",
-      "android/support/v4/app/LoaderManagerImpl$LoaderInfo": "androidx/app/LoaderManagerImpl$LoaderInfo",
-      "android/support/v7/widget/RoundRectDrawableWithShadow": "androidx/widget/RoundRectDrawableWithShadow",
-      "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState": "androidx/app/AppCompatDelegateImplV9$PanelFeatureState",
-      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$UserRouteRecord": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$UserRouteRecord",
-      "android/support/v4/view/accessibility/AccessibilityManagerCompat": "androidx/view/accessibility/AccessibilityManagerCompat",
-      "android/support/v4/view/ScrollingView": "androidx/view/ScrollingView",
-      "android/support/customtabs/CustomTabsIntent": "androidx/browser/customtabs/CustomTabsIntent",
-      "android/support/v17/leanback/transition/TransitionListener": "androidx/leanback/transition/TransitionListener",
-      "android/support/annotation/DimenRes": "androidx/annotation/DimenRes",
-      "android/support/v17/leanback/widget/Parallax$IntProperty": "androidx/leanback/widget/Parallax$IntProperty",
-      "android/support/v4/app/FragmentManagerImpl$AnimationOrAnimator": "androidx/app/FragmentManagerImpl$AnimationOrAnimator",
-      "android/support/v4/widget/TextViewCompat$TextViewCompatBaseImpl": "androidx/widget/TextViewCompat$TextViewCompatBaseImpl",
-      "android/support/v17/leanback/app/BrowseFragment$ExpandPreLayout": "androidx/leanback/app/BrowseFragment$ExpandPreLayout",
-      "android/support/v13/view/DragAndDropPermissionsCompat$BaseDragAndDropPermissionsCompatImpl": "androidx/view/DragAndDropPermissionsCompat$BaseDragAndDropPermissionsCompatImpl",
-      "android/support/multidex/MultiDexExtractor": "androidx/multidex/MultiDexExtractor",
-      "android/support/v17/leanback/widget/GuidedDatePickerAction$Builder": "androidx/leanback/widget/GuidedDatePickerAction$Builder",
-      "android/support/v7/widget/AppCompatRatingBar": "androidx/widget/AppCompatRatingBar",
-      "android/support/wear/R$string": "androidx/wear/R$string",
-      "android/support/v7/app/AppCompatDelegateImplN": "androidx/app/AppCompatDelegateImplN",
-      "android/support/v17/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller": "androidx/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller",
-      "android/support/v17/leanback/widget/GuidedActionItemContainer": "androidx/leanback/widget/GuidedActionItemContainer",
-      "android/support/transition/ObjectAnimatorUtils": "androidx/transition/ObjectAnimatorUtils",
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat",
-      "android/support/design/widget/CoordinatorLayout$DispatchChangeEvent": "androidx/design/widget/CoordinatorLayout$DispatchChangeEvent",
-      "android/support/annotation/HalfFloat": "androidx/annotation/HalfFloat",
-      "android/support/v4/view/ViewCompat$ViewCompatApi16Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi16Impl",
-      "android/support/v7/text/AllCapsTransformationMethod": "androidx/text/AllCapsTransformationMethod",
-      "android/support/v4/app/FragmentController": "androidx/app/FragmentController",
-      "android/support/v17/leanback/app/SearchSupportFragment$SearchResultProvider": "androidx/leanback/app/SearchSupportFragment$SearchResultProvider",
-      "android/support/v17/leanback/widget/RoundedRectHelper$StubImpl": "androidx/leanback/widget/RoundedRectHelper$StubImpl",
-      "android/support/v4/graphics/drawable/RoundedBitmapDrawable": "androidx/graphics/drawable/RoundedBitmapDrawable",
-      "android/support/v4/widget/ScrollerCompat": "androidx/widget/ScrollerCompat",
-      "android/support/v17/leanback/widget/RoundedRectHelper$Api21Impl": "androidx/leanback/widget/RoundedRectHelper$Api21Impl",
-      "android/support/wear/internal/widget/drawer/SinglePagePresenter$Ui": "androidx/wear/internal/widget/drawer/SinglePagePresenter$Ui",
-      "android/support/v7/app/AppCompatDelegateImplV14$AutoNightModeManager": "androidx/app/AppCompatDelegateImplV14$AutoNightModeManager",
-      "android/support/v17/leanback/widget/ImeKeyMonitor$ImeKeyListener": "androidx/leanback/widget/ImeKeyMonitor$ImeKeyListener",
-      "android/support/v4/view/InputDeviceCompat": "androidx/view/InputDeviceCompat",
-      "android/support/wear/widget/CircularProgressLayoutController": "androidx/wear/widget/CircularProgressLayoutController",
-      "android/support/v17/leanback/widget/PlaybackTransportRowView$OnUnhandledKeyListener": "androidx/leanback/widget/PlaybackTransportRowView$OnUnhandledKeyListener",
-      "android/support/v4/view/ViewCompat$AccessibilityLiveRegion": "androidx/view/legacy/ViewCompat$AccessibilityLiveRegion",
-      "android/support/v13/app/FragmentCompat$FragmentCompatImpl": "androidx/app/FragmentCompat$FragmentCompatImpl",
-      "android/support/design/widget/Snackbar": "androidx/design/widget/Snackbar",
-      "android/support/v7/preference/PreferenceGroupAdapter": "androidx/preference/PreferenceGroupAdapter",
-      "android/support/v4/view/MenuItemCompat": "androidx/view/MenuItemCompat",
-      "android/support/v7/widget/ChildHelper$Bucket": "androidx/widget/ChildHelper$Bucket",
-      "android/support/v7/util/DiffUtil$DiffResult": "androidx/util/DiffUtil$DiffResult",
-      "android/support/v13/app/FragmentCompat$PermissionCompatDelegate": "androidx/app/FragmentCompat$PermissionCompatDelegate",
-      "android/support/v4/view/MotionEventCompat": "androidx/view/MotionEventCompat",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction": "androidx/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction",
-      "android/support/v4/app/FragmentState": "androidx/app/FragmentState",
-      "android/support/v7/widget/CardView": "androidx/widget/CardView",
-      "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatApi25Impl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatApi25Impl",
-      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatBaseImpl": "androidx/widget/PopupWindowCompat$PopupWindowCompatBaseImpl",
-      "android/support/media/tv/TvContractCompat$PreviewProgramColumns$Type": "androidx/media/tv/TvContractCompat$PreviewProgramColumns$Type",
-      "android/support/v4/media/session/MediaSessionCompat$OnActiveChangeListener": "androidx/media/session/MediaSessionCompat$OnActiveChangeListener",
-      "android/support/design/widget/BottomSheetBehavior": "androidx/design/widget/BottomSheetBehavior",
-      "android/support/customtabs/CustomTabsSession": "androidx/browser/customtabs/CustomTabsSession",
-      "android/support/v7/media/RemotePlaybackClient$StatusCallback": "androidx/media/RemotePlaybackClient$StatusCallback",
-      "android/support/v17/leanback/app/HeadersSupportFragment$OnHeaderViewSelectedListener": "androidx/leanback/app/HeadersSupportFragment$OnHeaderViewSelectedListener",
-      "android/support/v4/view/ViewPager$OnPageChangeListener": "androidx/view/ViewPager$OnPageChangeListener",
-      "android/support/v4/app/BackStackRecord$Op": "androidx/app/BackStackRecord$Op",
-      "android/support/media/ExifInterface$ExifAttribute": "androidx/media/ExifInterface$ExifAttribute",
-      "android/support/transition/ChangeBounds$ViewBounds": "androidx/transition/ChangeBounds$ViewBounds",
-      "android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground": "androidx/leanback/widget/NonOverlappingLinearLayoutWithForeground",
-      "android/support/v4/app/NotificationCompat$BigPictureStyle": "androidx/app/NotificationCompat$BigPictureStyle",
-      "android/support/design/widget/FloatingActionButton$ShadowDelegateImpl": "androidx/design/widget/FloatingActionButton$ShadowDelegateImpl",
-      "android/support/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloaderFactory": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$VideoPreloaderFactory",
-      "android/support/v7/app/MediaRouteDialogHelper": "androidx/app/MediaRouteDialogHelper",
-      "android/support/media/ExifInterface$ExifTag": "androidx/media/ExifInterface$ExifTag",
-      "android/support/v17/leanback/widget/BaseCardView$InfoHeightAnimation": "androidx/leanback/widget/BaseCardView$InfoHeightAnimation",
-      "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatApi25Impl": "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatApi25Impl",
-      "android/support/transition/TransitionSet$TransitionSetListener": "androidx/transition/TransitionSet$TransitionSetListener",
-      "android/support/v17/leanback/transition/SlideKitkat$CalculateSlide": "androidx/leanback/transition/SlideKitkat$CalculateSlide",
-      "android/support/v4/app/ActivityCompat$OnRequestPermissionsResultCallback": "androidx/app/legacy/ActivityCompat$OnRequestPermissionsResultCallback",
-      "android/support/v7/widget/AppCompatRadioButton": "androidx/widget/AppCompatRadioButton",
-      "android/support/v4/app/TaskStackBuilder$TaskStackBuilderApi16Impl": "androidx/app/TaskStackBuilder$TaskStackBuilderApi16Impl",
-      "android/support/v7/media/MediaRouter$RouteInfo$PlaybackVolume": "androidx/media/MediaRouter$RouteInfo$PlaybackVolume",
-      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$AdapterMulti": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$AdapterMulti",
-      "android/support/v4/print/PrintHelper$PrintHelperApi19": "androidx/print/PrintHelper$PrintHelperApi19",
-      "android/support/v7/media/MediaRouter$RouteInfo$DeviceType": "androidx/media/MediaRouter$RouteInfo$DeviceType",
-      "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback": "androidx/media/MediaBrowserCompat$SubscriptionCallback",
-      "android/support/v4/media/MediaBrowserCompat$MediaItem$Flags": "androidx/media/MediaBrowserCompat$MediaItem$Flags",
-      "android/support/v17/leanback/R$attr": "androidx/leanback/R$attr",
-      "android/support/v7/media/MediaRouteDescriptor$Builder": "androidx/media/MediaRouteDescriptor$Builder",
-      "android/support/v7/media/MediaRouteProviderService": "androidx/media/MediaRouteProviderService",
-      "android/support/v4/app/ActivityCompat$RequestPermissionsRequestCodeValidator": "androidx/app/legacy/ActivityCompat$RequestPermissionsRequestCodeValidator",
-      "android/support/v17/leanback/widget/ControlBar$OnChildFocusedListener": "androidx/leanback/widget/ControlBar$OnChildFocusedListener",
-      "android/support/v7/media/MediaRouterApi24$RouteInfo": "androidx/media/MediaRouterApi24$RouteInfo",
-      "android/support/v4/app/JobIntentService$WorkEnqueuer": "androidx/app/JobIntentService$WorkEnqueuer",
-      "android/support/v7/preference/DialogPreference$TargetFragment": "androidx/preference/DialogPreference$TargetFragment",
-      "android/support/wear/widget/BoxInsetLayout$LayoutParams": "androidx/wear/widget/BoxInsetLayout$LayoutParams",
-      "android/support/v4/util/SimpleArrayMap": "androidx/util/SimpleArrayMap",
-      "android/support/v4/widget/EdgeEffectCompat": "androidx/widget/EdgeEffectCompat",
-      "android/support/v13/app/FragmentCompat$FragmentCompatApi15Impl": "androidx/app/FragmentCompat$FragmentCompatApi15Impl",
-      "android/support/v4/print/PrintHelper$PrintHelperApi23": "androidx/print/PrintHelper$PrintHelperApi23",
-      "android/support/percent/R$styleable": "androidx/R$styleable",
-      "android/support/v4/print/PrintHelper$PrintHelperApi24": "androidx/print/PrintHelper$PrintHelperApi24",
-      "android/support/v4/content/res/FontResourcesParserCompat": "androidx/content/res/FontResourcesParserCompat",
-      "android/support/design/widget/SnackbarManager$SnackbarRecord": "androidx/design/widget/SnackbarManager$SnackbarRecord",
-      "android/support/v7/util/DiffUtil$Range": "androidx/util/DiffUtil$Range",
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImpl": "androidx/media/MediaBrowserCompat$MediaBrowserImpl",
-      "android/support/v4/print/PrintHelper$PrintHelperApi20": "androidx/print/PrintHelper$PrintHelperApi20",
-      "android/support/v4/media/session/PlaybackStateCompat$RepeatMode": "androidx/media/session/PlaybackStateCompat$RepeatMode",
-      "android/support/v7/media/MediaRouteProviderProtocol": "androidx/media/MediaRouteProviderProtocol",
-      "android/support/transition/Transition$ArrayListManager": "androidx/transition/Transition$ArrayListManager",
-      "android/support/text/emoji/widget/EmojiButton": "androidx/text/emoji/widget/EmojiButton",
-      "android/support/v4/view/ActionProvider$VisibilityListener": "androidx/view/ActionProvider$VisibilityListener",
-      "android/support/v7/widget/AppCompatProgressBarHelper": "androidx/widget/AppCompatProgressBarHelper",
-      "android/support/v7/widget/LinearLayoutCompat": "androidx/widget/LinearLayoutCompat",
-      "android/support/v4/app/Fragment$OnStartEnterTransitionListener": "androidx/app/Fragment$OnStartEnterTransitionListener",
-      "android/support/v7/app/AppCompatDialogFragment": "androidx/app/AppCompatDialogFragment",
-      "android/support/graphics/drawable/Animatable2Compat": "androidx/graphics/drawable/Animatable2Compat",
-      "android/support/design/widget/TabLayout$PagerAdapterObserver": "androidx/design/widget/TabLayout$PagerAdapterObserver",
-      "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem": "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem",
-      "android/support/v4/content/pm/ShortcutInfoCompat": "androidx/content/pm/ShortcutInfoCompat",
-      "android/support/v4/view/ScaleGestureDetectorCompat": "androidx/view/ScaleGestureDetectorCompat",
-      "android/support/v17/leanback/widget/ShadowHelperApi21$ShadowImpl": "androidx/leanback/widget/ShadowHelperApi21$ShadowImpl",
-      "android/support/v7/appcompat/R$id": "androidx/appcompat/R$id",
-      "android/support/v17/leanback/transition/Scale": "androidx/leanback/transition/Scale",
-      "android/support/v7/widget/ViewBoundsCheck": "androidx/widget/ViewBoundsCheck",
-      "android/support/design/widget/BottomSheetBehavior$State": "androidx/design/widget/BottomSheetBehavior$State",
-      "android/support/v7/app/ActionBarDrawerToggle$JellybeanMr2Delegate": "androidx/app/ActionBarDrawerToggle$JellybeanMr2Delegate",
-      "android/support/v7/internal/widget/PreferenceImageView": "androidx/internal/widget/PreferenceImageView",
-      "android/support/content/ContentPager$CursorCache": "androidx/content/ContentPager$CursorCache",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler",
-      "android/support/v4/app/NotificationCompat$Action$Extender": "androidx/app/NotificationCompat$Action$Extender",
-      "android/support/v7/widget/Toolbar$OnMenuItemClickListener": "androidx/widget/Toolbar$OnMenuItemClickListener",
-      "android/support/multidex/MultiDex$V4": "androidx/multidex/MultiDex$V4",
-      "android/support/v4/app/ActionBarDrawerToggle": "androidx/app/legacy/ActionBarDrawerToggle",
-      "android/support/v7/media/RemoteControlClientCompat": "androidx/media/RemoteControlClientCompat",
-      "android/support/v4/media/app/NotificationCompat$MediaStyle": "androidx/media/app/NotificationCompat$MediaStyle",
-      "android/support/v17/leanback/transition/TransitionEpicenterCallback": "androidx/leanback/transition/TransitionEpicenterCallback",
-      "android/support/v4/content/LocalBroadcastManager$ReceiverRecord": "androidx/content/LocalBroadcastManager$ReceiverRecord",
-      "android/support/v7/view/menu/BaseMenuPresenter": "androidx/view/menu/BaseMenuPresenter",
-      "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListener": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListener",
-      "android/support/design/widget/TabLayout$AdapterChangeListener": "androidx/design/widget/TabLayout$AdapterChangeListener",
-      "android/support/v7/widget/RecyclerView$RecyclerListener": "androidx/widget/RecyclerView$RecyclerListener",
-      "android/support/media/tv/ChannelLogoUtils": "androidx/media/tv/ChannelLogoUtils",
-      "android/support/v4/media/session/PlaybackStateCompat$CustomAction$Builder": "androidx/media/session/PlaybackStateCompat$CustomAction$Builder",
-      "android/support/v17/leanback/widget/GuidedActionAdapter": "androidx/leanback/widget/GuidedActionAdapter",
-      "android/support/v17/leanback/widget/ItemBridgeAdapter$Wrapper": "androidx/leanback/widget/ItemBridgeAdapter$Wrapper",
-      "android/support/v17/leanback/widget/DetailsOverviewRow$Listener": "androidx/leanback/widget/DetailsOverviewRow$Listener",
-      "android/support/annotation/InterpolatorRes": "androidx/annotation/InterpolatorRes",
-      "android/support/v4/widget/CursorAdapter$ChangeObserver": "androidx/widget/CursorAdapter$ChangeObserver",
-      "android/support/v4/widget/SimpleCursorAdapter$CursorToStringConverter": "androidx/widget/SimpleCursorAdapter$CursorToStringConverter",
-      "android/support/v7/widget/helper/ItemTouchUIUtilImpl$BaseImpl": "androidx/widget/helper/ItemTouchUIUtilImpl$BaseImpl",
-      "android/support/v4/provider/RawDocumentFile": "androidx/provider/RawDocumentFile",
-      "android/support/text/emoji/widget/EmojiExtractTextLayout$ButtonOnclickListener": "androidx/text/emoji/widget/EmojiExtractTextLayout$ButtonOnclickListener",
-      "android/support/v7/view/menu/MenuItemWrapperJB$ActionProviderWrapperJB": "androidx/view/menu/MenuItemWrapperJB$ActionProviderWrapperJB",
-      "android/support/media/tv/TvContractCompat$RecordedPrograms": "androidx/media/tv/TvContractCompat$RecordedPrograms",
-      "android/support/v17/leanback/widget/picker/Picker$PickerValueListener": "androidx/leanback/widget/picker/Picker$PickerValueListener",
-      "android/support/v4/media/session/IMediaControllerCallback$Stub": "androidx/media/session/IMediaControllerCallback$Stub",
-      "android/support/v7/preference/PreferenceManager": "androidx/preference/PreferenceManager",
-      "android/support/transition/GhostViewApi21$Creator": "androidx/transition/GhostViewApi21$Creator",
-      "android/support/v7/widget/ActionMenuView$ActionMenuChildView": "androidx/widget/ActionMenuView$ActionMenuChildView",
-      "android/support/v17/leanback/app/GuidedStepSupportFragment$DummyFragment": "androidx/leanback/app/GuidedStepSupportFragment$DummyFragment",
-      "android/support/v4/app/BaseFragmentActivityApi14": "androidx/app/BaseFragmentActivityApi14",
-      "android/support/v14/preference/SwitchPreference": "androidx/preference/SwitchPreference",
-      "android/support/v4/app/BaseFragmentActivityApi16": "androidx/app/BaseFragmentActivityApi16",
-      "android/support/v7/preference/PreferenceFragmentCompat$ScrollToPreferenceObserver": "androidx/preference/PreferenceFragmentCompat$ScrollToPreferenceObserver",
-      "android/support/v4/graphics/PaintCompat": "androidx/graphics/PaintCompat",
-      "android/support/v4/media/AudioAttributesCompat": "androidx/media/AudioAttributesCompat",
-      "android/support/v4/media/session/MediaSessionCompat$QueueItem": "androidx/media/session/MediaSessionCompat$QueueItem",
-      "android/support/transition/Transition$AnimationInfo": "androidx/transition/Transition$AnimationInfo",
-      "android/support/v7/app/MediaRouteControllerDialog$VolumeChangeListener": "androidx/app/MediaRouteControllerDialog$VolumeChangeListener",
-      "android/support/v4/widget/DrawerLayout$ViewDragCallback": "androidx/widget/DrawerLayout$ViewDragCallback",
-      "android/support/design/widget/FloatingActionButtonImpl$ResetElevationAnimation": "androidx/design/widget/FloatingActionButtonImpl$ResetElevationAnimation",
-      "android/support/design/widget/TabLayout$OnTabSelectedListener": "androidx/design/widget/TabLayout$OnTabSelectedListener",
-      "android/support/annotation/VisibleForTesting": "androidx/annotation/VisibleForTesting",
-      "android/support/v4/app/NotificationCompatSideChannelService$NotificationSideChannelStub": "androidx/app/NotificationCompatSideChannelService$NotificationSideChannelStub",
-      "android/support/annotation/RawRes": "androidx/annotation/RawRes",
-      "android/support/design/R$anim": "androidx/design/R$anim",
-      "android/support/transition/Transition$MatchOrder": "androidx/transition/Transition$MatchOrder",
-      "android/support/v7/widget/RecyclerView$SimpleOnItemTouchListener": "androidx/widget/RecyclerView$SimpleOnItemTouchListener",
-      "android/support/transition/AnimatorUtilsImpl": "androidx/transition/AnimatorUtilsImpl",
-      "android/support/v4/view/OnApplyWindowInsetsListener": "androidx/view/OnApplyWindowInsetsListener",
-      "android/support/wear/widget/SwipeDismissLayout": "androidx/wear/widget/SwipeDismissLayout",
-      "android/support/mediacompat/R$color": "androidx/mediacompat/R$color",
-      "android/support/v7/preference/PreferenceManager$PreferenceComparisonCallback": "androidx/preference/PreferenceManager$PreferenceComparisonCallback",
-      "android/support/v7/widget/ActionMenuView$OnMenuItemClickListener": "androidx/widget/ActionMenuView$OnMenuItemClickListener",
-      "android/support/v7/widget/TooltipCompat$BaseViewCompatImpl": "androidx/widget/TooltipCompat$BaseViewCompatImpl",
-      "android/support/wear/widget/drawer/WearableNavigationDrawerView$NavigationStyle": "androidx/wear/widget/drawer/WearableNavigationDrawerView$NavigationStyle",
-      "android/support/transition/PatternPathMotion": "androidx/transition/PatternPathMotion",
-      "android/support/transition/Styleable$TransitionTarget": "androidx/transition/Styleable$TransitionTarget",
-      "android/support/mediacompat/R": "androidx/mediacompat/R",
-      "android/support/v7/media/MediaRouterJellybeanMr1$Callback": "androidx/media/MediaRouterJellybeanMr1$Callback",
-      "android/support/v17/leanback/widget/ControlBarPresenter$OnControlClickedListener": "androidx/leanback/widget/ControlBarPresenter$OnControlClickedListener",
-      "android/support/v4/view/LayoutInflaterCompat$Factory2Wrapper": "androidx/view/LayoutInflaterCompat$Factory2Wrapper",
-      "android/support/v7/widget/GridLayoutManager$LayoutParams": "androidx/widget/GridLayoutManager$LayoutParams",
-      "android/support/v7/widget/GridLayout": "androidx/widget/GridLayout",
-      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl",
-      "android/support/v7/widget/AppCompatCheckBox": "androidx/widget/AppCompatCheckBox",
-      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImpl": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImpl",
-      "android/support/v17/preference/BaseLeanbackPreferenceFragment": "androidx/leanback/preference/BaseLeanbackPreferenceFragment",
-      "android/support/v17/leanback/app/GuidedStepRootLayout": "androidx/leanback/app/GuidedStepRootLayout",
-      "android/support/v4/app/FragmentManager$FragmentLifecycleCallbacks": "androidx/app/FragmentManager$FragmentLifecycleCallbacks",
-      "android/support/v4/media/MediaMetadataCompatApi21": "androidx/media/MediaMetadataCompatApi21",
-      "android/support/v7/app/MediaRouterThemeHelper": "androidx/app/MediaRouterThemeHelper",
-      "android/support/v4/util/MapCollections$EntrySet": "androidx/util/MapCollections$EntrySet",
-      "android/support/v7/widget/ViewBoundsCheck$ViewBounds": "androidx/widget/ViewBoundsCheck$ViewBounds",
-      "android/support/design/widget/HeaderScrollingViewBehavior": "androidx/design/widget/HeaderScrollingViewBehavior",
-      "android/support/v7/app/ActionBarDrawerToggle$IcsDelegate": "androidx/app/ActionBarDrawerToggle$IcsDelegate",
-      "android/support/v4/media/session/ParcelableVolumeInfo": "androidx/media/session/ParcelableVolumeInfo",
-      "android/support/v17/leanback/widget/GuidedAction$Builder": "androidx/leanback/widget/GuidedAction$Builder",
-      "android/support/v7/view/menu/CascadingMenuPopup": "androidx/view/menu/CascadingMenuPopup",
-      "android/support/v7/view/menu/MenuPopup": "androidx/view/menu/MenuPopup",
-      "android/support/v7/app/AlertDialog": "androidx/app/AlertDialog",
-      "android/support/v7/widget/RecyclerView$SavedState": "androidx/widget/RecyclerView$SavedState",
-      "android/support/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder": "androidx/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder",
-      "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatBaseImpl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatBaseImpl",
-      "android/support/v17/leanback/app/VideoSupportFragmentGlueHost": "androidx/leanback/app/VideoSupportFragmentGlueHost",
-      "android/support/text/emoji/EmojiProcessor": "androidx/text/emoji/EmojiProcessor",
-      "android/support/v17/leanback/widget/ActionPresenterSelector": "androidx/leanback/widget/ActionPresenterSelector",
-      "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatImpl": "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatImpl",
-      "android/support/text/emoji/widget/EmojiExtractTextLayout": "androidx/text/emoji/widget/EmojiExtractTextLayout",
-      "android/support/v17/leanback/widget/GuidedAction": "androidx/leanback/widget/GuidedAction",
+      "android/support/v17/leanback/R$color": "androidx/leanback/R$color",
+      "android/support/v17/leanback/R$drawable": "androidx/leanback/R$drawable",
+      "android/support/v4/view/animation/FastOutLinearInInterpolator": "androidx/view/animation/FastOutLinearInInterpolator",
+      "android/support/v17/leanback/widget/BackgroundHelper": "androidx/leanback/widget/BackgroundHelper",
+      "android/support/annotation/ColorInt": "androidx/annotation/ColorInt",
+      "android/support/v17/leanback/app/BaseFragment$1": "androidx/leanback/app/BaseFragment$1",
+      "android/support/v17/leanback/util/StateMachine$State": "androidx/leanback/util/StateMachine$State",
+      "android/support/v17/leanback/app/BaseFragment": "androidx/leanback/app/BaseFragment",
+      "android/support/v17/leanback/util/StateMachine": "androidx/leanback/util/StateMachine",
+      "android/support/v17/leanback/app/ProgressBarManager": "androidx/leanback/app/ProgressBarManager",
+      "android/support/v17/leanback/app/BaseFragment$2": "androidx/leanback/app/BaseFragment$2",
+      "android/support/v17/leanback/app/BaseFragment$3": "androidx/leanback/app/BaseFragment$3",
+      "android/support/v17/leanback/app/BaseFragment$4": "androidx/leanback/app/BaseFragment$4",
+      "android/support/v17/leanback/app/BaseFragment$5": "androidx/leanback/app/BaseFragment$5",
       "android/support/v17/leanback/util/StateMachine$Condition": "androidx/leanback/util/StateMachine$Condition",
-      "android/support/text/emoji/flatbuffer/Table": "androidx/text/emoji/flatbuffer/Table",
-      "android/support/v4/os/OperationCanceledException": "androidx/os/OperationCanceledException",
-      "android/support/v7/media/RegisteredMediaRouteProvider$PrivateHandler": "androidx/media/RegisteredMediaRouteProvider$PrivateHandler",
-      "android/support/v7/widget/RecyclerView$Adapter": "androidx/widget/RecyclerView$Adapter",
-      "android/support/v7/util/ListUpdateCallback": "androidx/util/ListUpdateCallback",
-      "android/support/v4/media/MediaDescriptionCompatApi21": "androidx/media/MediaDescriptionCompatApi21",
-      "android/support/v4/view/ViewCompat$FocusRealDirection": "androidx/view/legacy/ViewCompat$FocusRealDirection",
-      "android/support/v4/media/session/MediaControllerCompat$Callback": "androidx/media/session/MediaControllerCompat$Callback",
-      "android/support/v4/media/MediaDescriptionCompatApi23": "androidx/media/MediaDescriptionCompatApi23",
-      "android/support/v4/view/accessibility/AccessibilityEventCompat": "androidx/view/accessibility/AccessibilityEventCompat",
-      "android/support/text/emoji/FontRequestEmojiCompatConfig$FontProviderHelper": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontProviderHelper",
-      "android/support/v4/app/NotificationCompat$Action$Builder": "androidx/app/NotificationCompat$Action$Builder",
-      "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi16": "androidx/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi16",
-      "android/support/annotation/AnimatorRes": "androidx/annotation/AnimatorRes",
-      "android/support/v17/leanback/widget/GuidanceStylist": "androidx/leanback/widget/GuidanceStylist",
-      "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperStubImpl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperStubImpl",
-      "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi19": "androidx/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi19",
-      "android/support/v7/util/ThreadUtil": "androidx/util/ThreadUtil",
-      "android/support/content/InMemoryCursor$ObserverRelay": "androidx/content/InMemoryCursor$ObserverRelay",
-      "android/support/wear/R$drawable": "androidx/wear/R$drawable",
-      "android/support/constraint/ConstraintLayout$LayoutParams": "androidx/constraint/ConstraintLayout$LayoutParams",
-      "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup": "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup",
-      "android/support/v17/leanback/app/SearchFragment$ExternalQuery": "androidx/leanback/app/SearchFragment$ExternalQuery",
-      "android/support/media/tv/TvContractCompat$Programs$Genres": "androidx/media/tv/TvContractCompat$Programs$Genres",
-      "android/support/v13/view/inputmethod/InputConnectionCompat$OnCommitContentListener": "androidx/view/inputmethod/InputConnectionCompat$OnCommitContentListener",
-      "android/support/content/ContentPager$CursorDisposition": "androidx/content/ContentPager$CursorDisposition",
-      "android/support/v4/view/AsyncLayoutInflater$OnInflateFinishedListener": "androidx/view/AsyncLayoutInflater$OnInflateFinishedListener",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplBase": "androidx/media/session/MediaControllerCompat$MediaControllerImplBase",
-      "android/support/v4/util/PatternsCompat": "androidx/util/PatternsCompat",
-      "android/support/v4/media/MediaBrowserServiceCompat$ServiceCallbacksCompat": "androidx/media/MediaBrowserServiceCompat$ServiceCallbacksCompat",
-      "android/support/v7/widget/AppCompatCompoundButtonHelper$DirectSetButtonDrawableInterface": "androidx/widget/AppCompatCompoundButtonHelper$DirectSetButtonDrawableInterface",
-      "android/support/v17/leanback/media/PlaybackGlueHost": "androidx/leanback/media/PlaybackGlueHost",
-      "android/support/v4/content/ModernAsyncTask": "androidx/content/ModernAsyncTask",
-      "android/support/v4/view/ViewCompat$ViewCompatApi15Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi15Impl",
-      "android/support/v4/os/ResultReceiver$MyResultReceiver": "androidx/os/ResultReceiver$MyResultReceiver",
-      "android/support/v7/widget/helper/ItemTouchHelper$Callback": "androidx/widget/helper/ItemTouchHelper$Callback",
-      "android/support/v17/leanback/app/BrowseFragment$MainFragmentRowsAdapterProvider": "androidx/leanback/app/BrowseFragment$MainFragmentRowsAdapterProvider",
-      "android/support/annotation/Nullable": "androidx/annotation/Nullable",
-      "android/support/v4/os/IResultReceiver$Stub": "androidx/os/IResultReceiver$Stub",
-      "android/support/v7/widget/Toolbar$ExpandedActionViewMenuPresenter": "androidx/widget/Toolbar$ExpandedActionViewMenuPresenter",
-      "android/support/v17/leanback/widget/picker/PickerUtility": "androidx/leanback/widget/picker/PickerUtility",
-      "android/support/v4/view/ViewPager$MyAccessibilityDelegate": "androidx/view/ViewPager$MyAccessibilityDelegate",
-      "android/support/v4/app/FragmentTransaction$Transit": "androidx/app/FragmentTransaction$Transit",
-      "android/support/v7/widget/DefaultItemAnimator": "androidx/widget/DefaultItemAnimator",
-      "android/support/v4/view/PagerAdapter": "androidx/widget/PagerAdapter",
-      "android/support/v7/media/MediaRouteProviderService$PrivateHandler": "androidx/media/MediaRouteProviderService$PrivateHandler",
-      "android/support/v4/media/session/IMediaControllerCallback$Stub$Proxy": "androidx/media/session/IMediaControllerCallback$Stub$Proxy",
-      "android/support/v4/media/RatingCompat": "androidx/media/RatingCompat",
-      "android/support/v7/widget/GridLayout$Assoc": "androidx/widget/GridLayout$Assoc",
-      "android/support/v17/leanback/app/DetailsSupportFragment$SetSelectionRunnable": "androidx/leanback/app/DetailsSupportFragment$SetSelectionRunnable",
-      "android/support/v7/util/DiffUtil$Callback": "androidx/util/DiffUtil$Callback",
-      "android/support/v7/widget/ActivityChooserModel$ActivityChooserModelClient": "androidx/widget/ActivityChooserModel$ActivityChooserModelClient",
-      "android/support/v7/widget/PagerSnapHelper": "androidx/widget/PagerSnapHelper",
-      "android/support/v17/leanback/widget/GridLayoutManager$LayoutParams": "androidx/leanback/widget/GridLayoutManager$LayoutParams",
-      "android/support/percent/R": "androidx/R",
-      "android/support/transition/Styleable$Fade": "androidx/transition/Styleable$Fade",
-      "android/support/design/widget/FloatingActionButtonLollipop": "androidx/design/widget/FloatingActionButtonLollipop",
-      "android/support/v17/leanback/widget/ActionPresenterSelector$OneLineActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$OneLineActionPresenter",
-      "android/support/transition/ViewUtilsApi22": "androidx/transition/ViewUtilsApi22",
-      "android/support/v7/widget/LinearLayoutCompat$LayoutParams": "androidx/widget/LinearLayoutCompat$LayoutParams",
-      "android/support/transition/ViewUtilsApi21": "androidx/transition/ViewUtilsApi21",
+      "android/support/v17/leanback/transition/TransitionHelper": "androidx/leanback/transition/TransitionHelper",
+      "android/support/v17/leanback/app/BaseFragment$6": "androidx/leanback/app/BaseFragment$6",
+      "android/support/v17/leanback/util/StateMachine$Event": "androidx/leanback/util/StateMachine$Event",
+      "android/support/v17/leanback/app/FragmentUtil": "androidx/leanback/app/FragmentUtil",
+      "android/support/v17/leanback/app/BaseFragment$7": "androidx/leanback/app/BaseFragment$7",
+      "android/support/v17/leanback/transition/TransitionListener": "androidx/leanback/transition/TransitionListener",
       "android/support/v17/leanback/app/BrandedFragment": "androidx/leanback/app/BrandedFragment",
-      "android/support/text/emoji/bundled/BundledEmojiCompatConfig$BundledMetadataLoader": "androidx/text/emoji/bundled/BundledEmojiCompatConfig$BundledMetadataLoader",
-      "android/support/v17/preference/R": "androidx/leanback/preference/R",
-      "android/support/v4/content/res/TypedArrayUtils": "androidx/content/res/TypedArrayUtils",
-      "android/support/v7/app/ActionBar$LayoutParams": "androidx/app/ActionBar$LayoutParams",
-      "android/support/transition/Visibility$DisappearListener": "androidx/transition/Visibility$DisappearListener",
-      "android/support/v7/view/menu/MenuView$ItemView": "androidx/view/menu/MenuView$ItemView",
-      "android/support/text/emoji/flatbuffer/FlatBufferBuilder": "androidx/text/emoji/flatbuffer/FlatBufferBuilder",
+      "android/support/annotation/Nullable": "androidx/annotation/Nullable",
+      "android/support/v17/leanback/app/BaseRowFragment$1": "androidx/leanback/app/BaseRowFragment$1",
+      "android/support/v17/leanback/widget/OnChildViewHolderSelectedListener": "androidx/leanback/widget/OnChildViewHolderSelectedListener",
+      "android/support/v17/leanback/app/BaseRowFragment": "androidx/leanback/app/BaseRowFragment",
+      "android/support/v7/widget/RecyclerView$ViewHolder": "androidx/widget/recyclerview/RecyclerView$ViewHolder",
+      "android/support/v7/widget/RecyclerView": "androidx/widget/recyclerview/RecyclerView",
       "android/support/v17/leanback/app/BaseRowFragment$LateSelectionObserver": "androidx/leanback/app/BaseRowFragment$LateSelectionObserver",
-      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener",
-      "android/support/v4/content/PermissionChecker$PermissionResult": "androidx/content/PermissionChecker$PermissionResult",
-      "android/support/v7/media/MediaRouter$ControlRequestCallback": "androidx/media/MediaRouter$ControlRequestCallback",
-      "android/support/wear/widget/drawer/WearableNavigationDrawerView$WearableNavigationDrawerAdapter": "androidx/wear/widget/drawer/WearableNavigationDrawerView$WearableNavigationDrawerAdapter",
+      "android/support/v7/widget/RecyclerView$AdapterDataObserver": "androidx/widget/recyclerview/RecyclerView$AdapterDataObserver",
+      "android/support/v17/leanback/widget/ItemBridgeAdapter": "androidx/leanback/widget/ItemBridgeAdapter",
+      "android/support/v17/leanback/widget/VerticalGridView": "androidx/leanback/widget/VerticalGridView",
+      "android/support/v7/widget/RecyclerView$Adapter": "androidx/widget/recyclerview/RecyclerView$Adapter",
+      "android/support/v17/leanback/widget/ObjectAdapter": "androidx/leanback/widget/ObjectAdapter",
+      "android/support/v17/leanback/widget/PresenterSelector": "androidx/leanback/widget/PresenterSelector",
+      "android/support/v17/leanback/widget/Row": "androidx/leanback/widget/Row",
+      "android/support/v17/leanback/widget/ListRow": "androidx/leanback/widget/ListRow",
+      "android/support/v17/leanback/app/BaseRowSupportFragment$1": "androidx/leanback/app/BaseRowSupportFragment$1",
+      "android/support/v17/leanback/app/BaseRowSupportFragment": "androidx/leanback/app/BaseRowSupportFragment",
+      "android/support/v17/leanback/app/BaseRowSupportFragment$LateSelectionObserver": "androidx/leanback/app/BaseRowSupportFragment$LateSelectionObserver",
+      "android/support/v4/app/Fragment": "androidx/app/Fragment",
+      "android/support/v17/leanback/app/BaseSupportFragment$1": "androidx/leanback/app/BaseSupportFragment$1",
+      "android/support/v17/leanback/app/BaseSupportFragment": "androidx/leanback/app/BaseSupportFragment",
+      "android/support/v17/leanback/app/BaseSupportFragment$2": "androidx/leanback/app/BaseSupportFragment$2",
+      "android/support/v17/leanback/app/BaseSupportFragment$3": "androidx/leanback/app/BaseSupportFragment$3",
+      "android/support/v17/leanback/app/BaseSupportFragment$4": "androidx/leanback/app/BaseSupportFragment$4",
+      "android/support/v17/leanback/app/BaseSupportFragment$5": "androidx/leanback/app/BaseSupportFragment$5",
+      "android/support/v17/leanback/app/BaseSupportFragment$6": "androidx/leanback/app/BaseSupportFragment$6",
+      "android/support/v17/leanback/app/BaseSupportFragment$7": "androidx/leanback/app/BaseSupportFragment$7",
+      "android/support/v17/leanback/app/BrandedSupportFragment": "androidx/leanback/app/BrandedSupportFragment",
+      "android/support/v17/leanback/widget/SearchOrbView$Colors": "androidx/leanback/widget/SearchOrbView$Colors",
+      "android/support/v17/leanback/widget/SearchOrbView": "androidx/leanback/widget/SearchOrbView",
+      "android/support/v17/leanback/widget/TitleViewAdapter$Provider": "androidx/leanback/widget/TitleViewAdapter$Provider",
+      "android/support/v17/leanback/widget/TitleViewAdapter": "androidx/leanback/widget/TitleViewAdapter",
+      "android/support/v17/leanback/R$attr": "androidx/leanback/R$attr",
+      "android/support/v17/leanback/R$layout": "androidx/leanback/R$layout",
+      "android/support/v17/leanback/widget/TitleHelper": "androidx/leanback/widget/TitleHelper",
+      "android/support/v17/leanback/app/BrowseFragment$1": "androidx/leanback/app/BrowseFragment$1",
+      "android/support/v17/leanback/app/BrowseFragment": "androidx/leanback/app/BrowseFragment",
+      "android/support/v17/leanback/app/BrowseFragment$10": "androidx/leanback/app/BrowseFragment$10",
+      "android/support/v17/leanback/app/HeadersFragment$OnHeaderClickedListener": "androidx/leanback/app/HeadersFragment$OnHeaderClickedListener",
+      "android/support/v17/leanback/widget/RowHeaderPresenter$ViewHolder": "androidx/leanback/widget/RowHeaderPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/RowHeaderPresenter": "androidx/leanback/widget/RowHeaderPresenter",
+      "android/support/v17/leanback/app/HeadersFragment": "androidx/leanback/app/HeadersFragment",
+      "android/support/v17/leanback/app/BrowseFragment$11": "androidx/leanback/app/BrowseFragment$11",
+      "android/support/v17/leanback/app/HeadersFragment$OnHeaderViewSelectedListener": "androidx/leanback/app/HeadersFragment$OnHeaderViewSelectedListener",
+      "android/support/v17/leanback/app/BrowseFragment$12": "androidx/leanback/app/BrowseFragment$12",
+      "android/support/v7/widget/RecyclerView$OnScrollListener": "androidx/widget/recyclerview/RecyclerView$OnScrollListener",
+      "android/support/v17/leanback/app/BrowseFragment$2": "androidx/leanback/app/BrowseFragment$2",
+      "android/support/v17/leanback/widget/Presenter": "androidx/leanback/widget/Presenter",
+      "android/support/v17/leanback/app/BrowseFragment$3": "androidx/leanback/app/BrowseFragment$3",
+      "android/support/v17/leanback/app/BrowseFragment$BrowseTransitionListener": "androidx/leanback/app/BrowseFragment$BrowseTransitionListener",
+      "android/support/v17/leanback/app/BrowseFragment$BackStackListener": "androidx/leanback/app/BrowseFragment$BackStackListener",
+      "android/support/v17/leanback/app/BrowseFragment$4": "androidx/leanback/app/BrowseFragment$4",
+      "android/support/v17/leanback/widget/BrowseFrameLayout$OnFocusSearchListener": "androidx/leanback/widget/BrowseFrameLayout$OnFocusSearchListener",
+      "android/support/v17/leanback/widget/BrowseFrameLayout": "androidx/leanback/widget/BrowseFrameLayout",
+      "android/support/v4/view/ViewCompat": "androidx/view/ViewCompat",
+      "android/support/v17/leanback/app/BrowseFragment$5": "androidx/leanback/app/BrowseFragment$5",
+      "android/support/v17/leanback/widget/BrowseFrameLayout$OnChildFocusListener": "androidx/leanback/widget/BrowseFrameLayout$OnChildFocusListener",
+      "android/support/v17/leanback/app/BrowseFragment$6": "androidx/leanback/app/BrowseFragment$6",
+      "android/support/v17/leanback/app/BrowseFragment$7": "androidx/leanback/app/BrowseFragment$7",
+      "android/support/v17/leanback/app/BrowseFragment$8": "androidx/leanback/app/BrowseFragment$8",
+      "android/support/v17/leanback/app/BrowseFragment$9": "androidx/leanback/app/BrowseFragment$9",
+      "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapter": "androidx/leanback/app/BrowseFragment$MainFragmentAdapter",
+      "android/support/v17/leanback/app/BrowseFragment$ExpandPreLayout": "androidx/leanback/app/BrowseFragment$ExpandPreLayout",
+      "android/support/v17/leanback/app/BrowseFragment$FragmentFactory": "androidx/leanback/app/BrowseFragment$FragmentFactory",
+      "android/support/v17/leanback/app/BrowseFragment$FragmentHost": "androidx/leanback/app/BrowseFragment$FragmentHost",
+      "android/support/v17/leanback/app/BrowseFragment$FragmentHostImpl": "androidx/leanback/app/BrowseFragment$FragmentHostImpl",
+      "android/support/v17/leanback/app/BrowseFragment$ListRowFragmentFactory": "androidx/leanback/app/BrowseFragment$ListRowFragmentFactory",
+      "android/support/v17/leanback/app/RowsFragment": "androidx/leanback/app/RowsFragment",
+      "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterProvider": "androidx/leanback/app/BrowseFragment$MainFragmentAdapterProvider",
+      "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterRegistry": "androidx/leanback/app/BrowseFragment$MainFragmentAdapterRegistry",
+      "android/support/v17/leanback/widget/PageRow": "androidx/leanback/widget/PageRow",
+      "android/support/v17/leanback/app/BrowseFragment$MainFragmentItemViewSelectedListener": "androidx/leanback/app/BrowseFragment$MainFragmentItemViewSelectedListener",
+      "android/support/v17/leanback/widget/OnItemViewSelectedListener": "androidx/leanback/widget/OnItemViewSelectedListener",
+      "android/support/v17/leanback/app/BrowseFragment$MainFragmentRowsAdapter": "androidx/leanback/app/BrowseFragment$MainFragmentRowsAdapter",
+      "android/support/v17/leanback/widget/Presenter$ViewHolder": "androidx/leanback/widget/Presenter$ViewHolder",
+      "android/support/v17/leanback/widget/RowPresenter$ViewHolder": "androidx/leanback/widget/RowPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/RowPresenter": "androidx/leanback/widget/RowPresenter",
+      "android/support/v17/leanback/widget/Presenter$ViewHolderTask": "androidx/leanback/widget/Presenter$ViewHolderTask",
+      "android/support/v17/leanback/widget/OnItemViewClickedListener": "androidx/leanback/widget/OnItemViewClickedListener",
+      "android/support/v17/leanback/app/BrowseFragment$MainFragmentRowsAdapterProvider": "androidx/leanback/app/BrowseFragment$MainFragmentRowsAdapterProvider",
+      "android/support/v17/leanback/app/BrowseFragment$SetSelectionRunnable": "androidx/leanback/app/BrowseFragment$SetSelectionRunnable",
+      "android/support/v17/leanback/R$styleable": "androidx/leanback/R$styleable",
+      "android/support/v17/leanback/R$dimen": "androidx/leanback/R$dimen",
+      "android/support/v17/leanback/R$fraction": "androidx/leanback/R$fraction",
+      "android/support/v17/leanback/R$transition": "androidx/leanback/R$transition",
+      "android/support/v17/leanback/app/ListRowDataAdapter": "androidx/leanback/app/ListRowDataAdapter",
+      "android/support/v17/leanback/widget/ScaleFrameLayout": "androidx/leanback/widget/ScaleFrameLayout",
+      "android/support/v17/leanback/widget/InvisibleRowPresenter": "androidx/leanback/widget/InvisibleRowPresenter",
+      "android/support/v17/leanback/app/BrowseSupportFragment$1": "androidx/leanback/app/BrowseSupportFragment$1",
+      "android/support/v17/leanback/app/BrowseSupportFragment": "androidx/leanback/app/BrowseSupportFragment",
+      "android/support/v17/leanback/app/BrowseSupportFragment$10": "androidx/leanback/app/BrowseSupportFragment$10",
+      "android/support/v17/leanback/app/HeadersSupportFragment$OnHeaderClickedListener": "androidx/leanback/app/HeadersSupportFragment$OnHeaderClickedListener",
+      "android/support/v17/leanback/app/HeadersSupportFragment": "androidx/leanback/app/HeadersSupportFragment",
+      "android/support/v17/leanback/app/BrowseSupportFragment$11": "androidx/leanback/app/BrowseSupportFragment$11",
+      "android/support/v17/leanback/app/HeadersSupportFragment$OnHeaderViewSelectedListener": "androidx/leanback/app/HeadersSupportFragment$OnHeaderViewSelectedListener",
+      "android/support/v17/leanback/app/BrowseSupportFragment$12": "androidx/leanback/app/BrowseSupportFragment$12",
+      "android/support/v4/app/FragmentManager": "androidx/app/FragmentManager",
+      "android/support/v4/app/FragmentTransaction": "androidx/app/FragmentTransaction",
+      "android/support/v17/leanback/app/BrowseSupportFragment$2": "androidx/leanback/app/BrowseSupportFragment$2",
+      "android/support/v17/leanback/app/BrowseSupportFragment$3": "androidx/leanback/app/BrowseSupportFragment$3",
+      "android/support/v4/app/FragmentManager$BackStackEntry": "androidx/app/FragmentManager$BackStackEntry",
+      "android/support/v17/leanback/app/BrowseSupportFragment$BrowseTransitionListener": "androidx/leanback/app/BrowseSupportFragment$BrowseTransitionListener",
+      "android/support/v17/leanback/app/BrowseSupportFragment$BackStackListener": "androidx/leanback/app/BrowseSupportFragment$BackStackListener",
+      "android/support/v17/leanback/app/BrowseSupportFragment$4": "androidx/leanback/app/BrowseSupportFragment$4",
+      "android/support/v17/leanback/app/BrowseSupportFragment$5": "androidx/leanback/app/BrowseSupportFragment$5",
+      "android/support/v17/leanback/app/BrowseSupportFragment$6": "androidx/leanback/app/BrowseSupportFragment$6",
+      "android/support/v17/leanback/app/BrowseSupportFragment$7": "androidx/leanback/app/BrowseSupportFragment$7",
+      "android/support/v17/leanback/app/BrowseSupportFragment$8": "androidx/leanback/app/BrowseSupportFragment$8",
+      "android/support/v17/leanback/app/BrowseSupportFragment$9": "androidx/leanback/app/BrowseSupportFragment$9",
+      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapter": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapter",
+      "android/support/v4/app/FragmentManager$OnBackStackChangedListener": "androidx/app/FragmentManager$OnBackStackChangedListener",
+      "android/support/v17/leanback/app/BrowseSupportFragment$ExpandPreLayout": "androidx/leanback/app/BrowseSupportFragment$ExpandPreLayout",
+      "android/support/v17/leanback/app/BrowseSupportFragment$FragmentFactory": "androidx/leanback/app/BrowseSupportFragment$FragmentFactory",
+      "android/support/v17/leanback/app/BrowseSupportFragment$FragmentHost": "androidx/leanback/app/BrowseSupportFragment$FragmentHost",
+      "android/support/v17/leanback/app/BrowseSupportFragment$FragmentHostImpl": "androidx/leanback/app/BrowseSupportFragment$FragmentHostImpl",
+      "android/support/v17/leanback/app/BrowseSupportFragment$ListRowFragmentFactory": "androidx/leanback/app/BrowseSupportFragment$ListRowFragmentFactory",
+      "android/support/v17/leanback/app/RowsSupportFragment": "androidx/leanback/app/RowsSupportFragment",
+      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterProvider": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterProvider",
+      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry": "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry",
+      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentItemViewSelectedListener": "androidx/leanback/app/BrowseSupportFragment$MainFragmentItemViewSelectedListener",
+      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapter": "androidx/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapter",
+      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapterProvider": "androidx/leanback/app/BrowseSupportFragment$MainFragmentRowsAdapterProvider",
+      "android/support/v17/leanback/app/BrowseSupportFragment$SetSelectionRunnable": "androidx/leanback/app/BrowseSupportFragment$SetSelectionRunnable",
+      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper$1": "androidx/leanback/app/DetailsBackgroundVideoHelper$1",
+      "android/support/v17/leanback/widget/ParallaxTarget": "androidx/leanback/widget/ParallaxTarget",
+      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper": "androidx/leanback/app/DetailsBackgroundVideoHelper",
+      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper$2": "androidx/leanback/app/DetailsBackgroundVideoHelper$2",
+      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper$3": "androidx/leanback/app/DetailsBackgroundVideoHelper$3",
+      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper$4": "androidx/leanback/app/DetailsBackgroundVideoHelper$4",
+      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper$PlaybackControlStateCallback": "androidx/leanback/app/DetailsBackgroundVideoHelper$PlaybackControlStateCallback",
+      "android/support/v17/leanback/media/PlaybackGlue$PlayerCallback": "androidx/leanback/media/PlaybackGlue$PlayerCallback",
+      "android/support/v17/leanback/media/PlaybackGlue": "androidx/leanback/media/PlaybackGlue",
+      "android/support/v17/leanback/widget/Parallax$IntProperty": "androidx/leanback/widget/Parallax$IntProperty",
+      "android/support/v17/leanback/widget/Parallax": "androidx/leanback/widget/Parallax",
+      "android/support/v17/leanback/widget/Parallax$PropertyMarkerValue": "androidx/leanback/widget/Parallax$PropertyMarkerValue",
+      "android/support/v17/leanback/widget/DetailsParallax": "androidx/leanback/widget/DetailsParallax",
+      "android/support/v17/leanback/widget/ParallaxEffect": "androidx/leanback/widget/ParallaxEffect",
+      "android/support/v17/leanback/app/DetailsFragment$1": "androidx/leanback/app/DetailsFragment$1",
+      "android/support/v17/leanback/app/DetailsFragment": "androidx/leanback/app/DetailsFragment",
+      "android/support/v17/leanback/app/DetailsFragment$10": "androidx/leanback/app/DetailsFragment$10",
+      "android/support/v17/leanback/app/DetailsFragment$11": "androidx/leanback/app/DetailsFragment$11",
+      "android/support/v17/leanback/widget/ItemBridgeAdapter$AdapterListener": "androidx/leanback/widget/ItemBridgeAdapter$AdapterListener",
+      "android/support/v17/leanback/widget/ItemBridgeAdapter$ViewHolder": "androidx/leanback/widget/ItemBridgeAdapter$ViewHolder",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter",
+      "android/support/v17/leanback/app/DetailsFragment$12": "androidx/leanback/app/DetailsFragment$12",
+      "android/support/v17/leanback/app/DetailsFragment$13": "androidx/leanback/app/DetailsFragment$13",
+      "android/support/v17/leanback/app/DetailsFragment$14": "androidx/leanback/app/DetailsFragment$14",
+      "android/support/v17/leanback/app/DetailsFragmentBackgroundController": "androidx/leanback/app/DetailsFragmentBackgroundController",
+      "android/support/v17/leanback/app/DetailsFragment$15": "androidx/leanback/app/DetailsFragment$15",
+      "android/support/v17/leanback/app/DetailsFragment$2": "androidx/leanback/app/DetailsFragment$2",
+      "android/support/v17/leanback/app/DetailsFragment$3": "androidx/leanback/app/DetailsFragment$3",
+      "android/support/v17/leanback/app/DetailsFragment$WaitEnterTransitionTimeout": "androidx/leanback/app/DetailsFragment$WaitEnterTransitionTimeout",
+      "android/support/v17/leanback/app/DetailsFragment$4": "androidx/leanback/app/DetailsFragment$4",
+      "android/support/v17/leanback/app/DetailsFragment$5": "androidx/leanback/app/DetailsFragment$5",
+      "android/support/v17/leanback/app/DetailsFragment$6": "androidx/leanback/app/DetailsFragment$6",
+      "android/support/v17/leanback/app/DetailsFragment$7": "androidx/leanback/app/DetailsFragment$7",
+      "android/support/v17/leanback/app/DetailsFragment$8": "androidx/leanback/app/DetailsFragment$8",
+      "android/support/v17/leanback/app/DetailsFragment$9": "androidx/leanback/app/DetailsFragment$9",
+      "android/support/v17/leanback/widget/BaseOnItemViewSelectedListener": "androidx/leanback/widget/BaseOnItemViewSelectedListener",
+      "android/support/v17/leanback/app/DetailsFragment$SetSelectionRunnable": "androidx/leanback/app/DetailsFragment$SetSelectionRunnable",
+      "android/support/v17/leanback/widget/ItemAlignmentFacet$ItemAlignmentDef": "androidx/leanback/widget/ItemAlignmentFacet$ItemAlignmentDef",
+      "android/support/v17/leanback/widget/ItemAlignmentFacet": "androidx/leanback/widget/ItemAlignmentFacet",
+      "android/support/v17/leanback/widget/BaseOnItemViewClickedListener": "androidx/leanback/widget/BaseOnItemViewClickedListener",
+      "android/support/annotation/CallSuper": "androidx/annotation/CallSuper",
+      "android/support/v17/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget": "androidx/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget",
+      "android/support/v17/leanback/widget/DetailsParallaxDrawable": "androidx/leanback/widget/DetailsParallaxDrawable",
+      "android/support/v17/leanback/graphics/FitWidthBitmapDrawable": "androidx/leanback/graphics/FitWidthBitmapDrawable",
+      "android/support/v17/leanback/media/PlaybackGlueHost": "androidx/leanback/media/PlaybackGlueHost",
+      "android/support/v17/leanback/app/VideoFragment": "androidx/leanback/app/VideoFragment",
+      "android/support/v17/leanback/app/VideoFragmentGlueHost": "androidx/leanback/app/VideoFragmentGlueHost",
+      "android/support/v17/leanback/app/DetailsSupportFragment$1": "androidx/leanback/app/DetailsSupportFragment$1",
+      "android/support/v17/leanback/app/DetailsSupportFragment": "androidx/leanback/app/DetailsSupportFragment",
+      "android/support/v17/leanback/app/DetailsSupportFragment$10": "androidx/leanback/app/DetailsSupportFragment$10",
+      "android/support/v17/leanback/app/DetailsSupportFragment$11": "androidx/leanback/app/DetailsSupportFragment$11",
+      "android/support/v17/leanback/app/DetailsSupportFragment$12": "androidx/leanback/app/DetailsSupportFragment$12",
+      "android/support/v17/leanback/app/DetailsSupportFragment$13": "androidx/leanback/app/DetailsSupportFragment$13",
+      "android/support/v17/leanback/app/DetailsSupportFragment$14": "androidx/leanback/app/DetailsSupportFragment$14",
+      "android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController": "androidx/leanback/app/DetailsSupportFragmentBackgroundController",
+      "android/support/v17/leanback/app/DetailsSupportFragment$15": "androidx/leanback/app/DetailsSupportFragment$15",
+      "android/support/v17/leanback/app/DetailsSupportFragment$2": "androidx/leanback/app/DetailsSupportFragment$2",
+      "android/support/v17/leanback/app/DetailsSupportFragment$3": "androidx/leanback/app/DetailsSupportFragment$3",
+      "android/support/v17/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout": "androidx/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout",
+      "android/support/v4/app/FragmentActivity": "androidx/app/FragmentActivity",
+      "android/support/v17/leanback/app/DetailsSupportFragment$4": "androidx/leanback/app/DetailsSupportFragment$4",
+      "android/support/v17/leanback/app/DetailsSupportFragment$5": "androidx/leanback/app/DetailsSupportFragment$5",
+      "android/support/v17/leanback/app/DetailsSupportFragment$6": "androidx/leanback/app/DetailsSupportFragment$6",
+      "android/support/v17/leanback/app/DetailsSupportFragment$7": "androidx/leanback/app/DetailsSupportFragment$7",
+      "android/support/v17/leanback/app/DetailsSupportFragment$8": "androidx/leanback/app/DetailsSupportFragment$8",
+      "android/support/v17/leanback/app/DetailsSupportFragment$9": "androidx/leanback/app/DetailsSupportFragment$9",
+      "android/support/v17/leanback/app/DetailsSupportFragment$SetSelectionRunnable": "androidx/leanback/app/DetailsSupportFragment$SetSelectionRunnable",
+      "android/support/v17/leanback/app/VideoSupportFragment": "androidx/leanback/app/VideoSupportFragment",
+      "android/support/v17/leanback/app/VideoSupportFragmentGlueHost": "androidx/leanback/app/VideoSupportFragmentGlueHost",
+      "android/support/v17/leanback/app/ErrorFragment": "androidx/leanback/app/ErrorFragment",
+      "android/support/v17/leanback/app/ErrorSupportFragment": "androidx/leanback/app/ErrorSupportFragment",
+      "android/support/annotation/RequiresApi": "androidx/annotation/RequiresApi",
+      "android/support/v17/leanback/app/GuidedStepFragment$1": "androidx/leanback/app/GuidedStepFragment$1",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$EditListener": "androidx/leanback/widget/GuidedActionAdapter$EditListener",
+      "android/support/v17/leanback/app/GuidedStepFragment": "androidx/leanback/app/GuidedStepFragment",
+      "android/support/v17/leanback/widget/GuidedActionAdapter": "androidx/leanback/widget/GuidedActionAdapter",
+      "android/support/v17/leanback/widget/GuidedAction": "androidx/leanback/widget/GuidedAction",
+      "android/support/v17/leanback/app/GuidedStepFragment$2": "androidx/leanback/app/GuidedStepFragment$2",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$ClickListener": "androidx/leanback/widget/GuidedActionAdapter$ClickListener",
+      "android/support/v17/leanback/app/GuidedStepFragment$3": "androidx/leanback/app/GuidedStepFragment$3",
+      "android/support/v17/leanback/app/GuidedStepFragment$4": "androidx/leanback/app/GuidedStepFragment$4",
+      "android/support/v17/leanback/widget/GuidedActionsStylist": "androidx/leanback/widget/GuidedActionsStylist",
+      "android/support/v17/leanback/app/GuidedStepFragment$DummyFragment": "androidx/leanback/app/GuidedStepFragment$DummyFragment",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$FocusListener": "androidx/leanback/widget/GuidedActionAdapter$FocusListener",
+      "android/support/v17/leanback/widget/GuidanceStylist$Guidance": "androidx/leanback/widget/GuidanceStylist$Guidance",
+      "android/support/v17/leanback/widget/GuidanceStylist": "androidx/leanback/widget/GuidanceStylist",
+      "android/support/v17/leanback/widget/GuidedActionAdapterGroup": "androidx/leanback/widget/GuidedActionAdapterGroup",
+      "android/support/v17/leanback/widget/DiffCallback": "androidx/leanback/widget/DiffCallback",
+      "android/support/v17/leanback/app/GuidedStepRootLayout": "androidx/leanback/app/GuidedStepRootLayout",
+      "android/support/v17/leanback/widget/NonOverlappingLinearLayout": "androidx/leanback/widget/NonOverlappingLinearLayout",
+      "android/support/v4/app/ActivityCompat": "androidx/app/ActivityCompat",
+      "android/support/v17/leanback/widget/Util": "androidx/leanback/widget/Util",
+      "android/support/v17/leanback/app/GuidedStepSupportFragment$1": "androidx/leanback/app/GuidedStepSupportFragment$1",
+      "android/support/v17/leanback/app/GuidedStepSupportFragment": "androidx/leanback/app/GuidedStepSupportFragment",
+      "android/support/v17/leanback/app/GuidedStepSupportFragment$2": "androidx/leanback/app/GuidedStepSupportFragment$2",
+      "android/support/v17/leanback/app/GuidedStepSupportFragment$3": "androidx/leanback/app/GuidedStepSupportFragment$3",
+      "android/support/v17/leanback/app/GuidedStepSupportFragment$4": "androidx/leanback/app/GuidedStepSupportFragment$4",
+      "android/support/v17/leanback/app/GuidedStepSupportFragment$DummyFragment": "androidx/leanback/app/GuidedStepSupportFragment$DummyFragment",
+      "android/support/v17/leanback/app/HeadersFragment$1$1": "androidx/leanback/app/HeadersFragment$1$1",
+      "android/support/v17/leanback/app/HeadersFragment$1": "androidx/leanback/app/HeadersFragment$1",
+      "android/support/v17/leanback/widget/ItemBridgeAdapter$Wrapper": "androidx/leanback/widget/ItemBridgeAdapter$Wrapper",
+      "android/support/v17/leanback/app/HeadersFragment$2": "androidx/leanback/app/HeadersFragment$2",
+      "android/support/v17/leanback/app/HeadersFragment$3": "androidx/leanback/app/HeadersFragment$3",
+      "android/support/v17/leanback/app/HeadersFragment$NoOverlappingFrameLayout": "androidx/leanback/app/HeadersFragment$NoOverlappingFrameLayout",
+      "android/support/v17/leanback/widget/FocusHighlightHelper": "androidx/leanback/widget/FocusHighlightHelper",
+      "android/support/v17/leanback/widget/ClassPresenterSelector": "androidx/leanback/widget/ClassPresenterSelector",
+      "android/support/v17/leanback/widget/DividerRow": "androidx/leanback/widget/DividerRow",
+      "android/support/v17/leanback/widget/DividerPresenter": "androidx/leanback/widget/DividerPresenter",
+      "android/support/v17/leanback/widget/SectionRow": "androidx/leanback/widget/SectionRow",
+      "android/support/v17/leanback/app/HeadersSupportFragment$1$1": "androidx/leanback/app/HeadersSupportFragment$1$1",
+      "android/support/v17/leanback/app/HeadersSupportFragment$1": "androidx/leanback/app/HeadersSupportFragment$1",
+      "android/support/v17/leanback/app/HeadersSupportFragment$2": "androidx/leanback/app/HeadersSupportFragment$2",
+      "android/support/v17/leanback/app/HeadersSupportFragment$3": "androidx/leanback/app/HeadersSupportFragment$3",
+      "android/support/v17/leanback/app/HeadersSupportFragment$NoOverlappingFrameLayout": "androidx/leanback/app/HeadersSupportFragment$NoOverlappingFrameLayout",
+      "android/support/v17/leanback/app/ListRowDataAdapter$QueueBasedDataObserver": "androidx/leanback/app/ListRowDataAdapter$QueueBasedDataObserver",
+      "android/support/v17/leanback/widget/ObjectAdapter$DataObserver": "androidx/leanback/widget/ObjectAdapter$DataObserver",
+      "android/support/v17/leanback/app/ListRowDataAdapter$SimpleDataObserver": "androidx/leanback/app/ListRowDataAdapter$SimpleDataObserver",
+      "android/support/v17/leanback/app/OnboardingFragment$1": "androidx/leanback/app/OnboardingFragment$1",
+      "android/support/v17/leanback/app/OnboardingFragment": "androidx/leanback/app/OnboardingFragment",
+      "android/support/v17/leanback/app/OnboardingFragment$2": "androidx/leanback/app/OnboardingFragment$2",
+      "android/support/v17/leanback/app/OnboardingFragment$3": "androidx/leanback/app/OnboardingFragment$3",
+      "android/support/v17/leanback/app/OnboardingFragment$4": "androidx/leanback/app/OnboardingFragment$4",
+      "android/support/v17/leanback/app/OnboardingFragment$5": "androidx/leanback/app/OnboardingFragment$5",
+      "android/support/v17/leanback/app/OnboardingFragment$6": "androidx/leanback/app/OnboardingFragment$6",
+      "android/support/v17/leanback/app/OnboardingFragment$7": "androidx/leanback/app/OnboardingFragment$7",
+      "android/support/v17/leanback/widget/PagingIndicator": "androidx/leanback/widget/PagingIndicator",
+      "android/support/v17/leanback/app/OnboardingFragment$8": "androidx/leanback/app/OnboardingFragment$8",
+      "android/support/v17/leanback/R$animator": "androidx/leanback/R$animator",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$1": "androidx/leanback/app/OnboardingSupportFragment$1",
+      "android/support/v17/leanback/app/OnboardingSupportFragment": "androidx/leanback/app/OnboardingSupportFragment",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$2": "androidx/leanback/app/OnboardingSupportFragment$2",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$3": "androidx/leanback/app/OnboardingSupportFragment$3",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$4": "androidx/leanback/app/OnboardingSupportFragment$4",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$5": "androidx/leanback/app/OnboardingSupportFragment$5",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$6": "androidx/leanback/app/OnboardingSupportFragment$6",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$7": "androidx/leanback/app/OnboardingSupportFragment$7",
+      "android/support/v17/leanback/app/OnboardingSupportFragment$8": "androidx/leanback/app/OnboardingSupportFragment$8",
+      "android/support/v17/leanback/app/PermissionHelper": "androidx/leanback/app/PermissionHelper",
+      "android/support/v17/leanback/app/PlaybackFragment$1": "androidx/leanback/app/PlaybackFragment$1",
+      "android/support/v17/leanback/app/PlaybackFragment": "androidx/leanback/app/PlaybackFragment",
+      "android/support/v17/leanback/widget/PlaybackRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackRowPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/PlaybackRowPresenter": "androidx/leanback/widget/PlaybackRowPresenter",
+      "android/support/v17/leanback/app/PlaybackFragment$10": "androidx/leanback/app/PlaybackFragment$10",
+      "android/support/v17/leanback/widget/PlaybackSeekUi$Client": "androidx/leanback/widget/PlaybackSeekUi$Client",
+      "android/support/v17/leanback/widget/PlaybackSeekUi": "androidx/leanback/widget/PlaybackSeekUi",
+      "android/support/v17/leanback/app/PlaybackFragment$11": "androidx/leanback/app/PlaybackFragment$11",
+      "android/support/v17/leanback/widget/PlaybackSeekDataProvider": "androidx/leanback/widget/PlaybackSeekDataProvider",
+      "android/support/v17/leanback/app/PlaybackFragment$2": "androidx/leanback/app/PlaybackFragment$2",
+      "android/support/v17/leanback/app/PlaybackFragment$3": "androidx/leanback/app/PlaybackFragment$3",
+      "android/support/v17/leanback/app/PlaybackFragment$OnFadeCompleteListener": "androidx/leanback/app/PlaybackFragment$OnFadeCompleteListener",
+      "android/support/v17/leanback/app/PlaybackFragment$4": "androidx/leanback/app/PlaybackFragment$4",
+      "android/support/v17/leanback/app/PlaybackFragment$5": "androidx/leanback/app/PlaybackFragment$5",
+      "android/support/v17/leanback/widget/BaseGridView$OnTouchInterceptListener": "androidx/leanback/widget/BaseGridView$OnTouchInterceptListener",
+      "android/support/v17/leanback/widget/BaseGridView": "androidx/leanback/widget/BaseGridView",
+      "android/support/v17/leanback/app/PlaybackFragment$6": "androidx/leanback/app/PlaybackFragment$6",
+      "android/support/v17/leanback/widget/BaseGridView$OnKeyInterceptListener": "androidx/leanback/widget/BaseGridView$OnKeyInterceptListener",
+      "android/support/v17/leanback/app/PlaybackFragment$7": "androidx/leanback/app/PlaybackFragment$7",
+      "android/support/v17/leanback/app/PlaybackFragment$8": "androidx/leanback/app/PlaybackFragment$8",
+      "android/support/v17/leanback/app/PlaybackFragment$9": "androidx/leanback/app/PlaybackFragment$9",
+      "android/support/v17/leanback/app/PlaybackFragment$SetSelectionRunnable": "androidx/leanback/app/PlaybackFragment$SetSelectionRunnable",
+      "android/support/v17/leanback/media/PlaybackGlueHost$HostCallback": "androidx/leanback/media/PlaybackGlueHost$HostCallback",
+      "android/support/v17/leanback/R$string": "androidx/leanback/R$string",
+      "android/support/v17/leanback/R$integer": "androidx/leanback/R$integer",
+      "android/support/v17/leanback/widget/ArrayObjectAdapter": "androidx/leanback/widget/ArrayObjectAdapter",
+      "android/support/v17/leanback/widget/SparseArrayObjectAdapter": "androidx/leanback/widget/SparseArrayObjectAdapter",
+      "android/support/v17/leanback/app/PlaybackFragmentGlueHost$1": "androidx/leanback/app/PlaybackFragmentGlueHost$1",
+      "android/support/v17/leanback/app/PlaybackFragmentGlueHost": "androidx/leanback/app/PlaybackFragmentGlueHost",
+      "android/support/v17/leanback/widget/OnActionClickedListener": "androidx/leanback/widget/OnActionClickedListener",
+      "android/support/v17/leanback/widget/Action": "androidx/leanback/widget/Action",
+      "android/support/v17/leanback/app/PlaybackFragmentGlueHost$2": "androidx/leanback/app/PlaybackFragmentGlueHost$2",
+      "android/support/v17/leanback/media/PlaybackGlueHost$PlayerCallback": "androidx/leanback/media/PlaybackGlueHost$PlayerCallback",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$1": "androidx/leanback/app/PlaybackSupportFragment$1",
+      "android/support/v17/leanback/app/PlaybackSupportFragment": "androidx/leanback/app/PlaybackSupportFragment",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$10": "androidx/leanback/app/PlaybackSupportFragment$10",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$11": "androidx/leanback/app/PlaybackSupportFragment$11",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$2": "androidx/leanback/app/PlaybackSupportFragment$2",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$3": "androidx/leanback/app/PlaybackSupportFragment$3",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$OnFadeCompleteListener": "androidx/leanback/app/PlaybackSupportFragment$OnFadeCompleteListener",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$4": "androidx/leanback/app/PlaybackSupportFragment$4",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$5": "androidx/leanback/app/PlaybackSupportFragment$5",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$6": "androidx/leanback/app/PlaybackSupportFragment$6",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$7": "androidx/leanback/app/PlaybackSupportFragment$7",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$8": "androidx/leanback/app/PlaybackSupportFragment$8",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$9": "androidx/leanback/app/PlaybackSupportFragment$9",
+      "android/support/v17/leanback/app/PlaybackSupportFragment$SetSelectionRunnable": "androidx/leanback/app/PlaybackSupportFragment$SetSelectionRunnable",
+      "android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost$1": "androidx/leanback/app/PlaybackSupportFragmentGlueHost$1",
+      "android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost": "androidx/leanback/app/PlaybackSupportFragmentGlueHost",
+      "android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost$2": "androidx/leanback/app/PlaybackSupportFragmentGlueHost$2",
+      "android/support/v17/leanback/app/ProgressBarManager$1": "androidx/leanback/app/ProgressBarManager$1",
+      "android/support/v17/leanback/app/RowsFragment$1": "androidx/leanback/app/RowsFragment$1",
+      "android/support/v17/leanback/app/RowsFragment$RowViewHolderExtra": "androidx/leanback/app/RowsFragment$RowViewHolderExtra",
+      "android/support/v17/leanback/app/RowsFragment$2$1": "androidx/leanback/app/RowsFragment$2$1",
+      "android/support/v17/leanback/app/RowsFragment$2": "androidx/leanback/app/RowsFragment$2",
+      "android/support/v17/leanback/widget/ViewHolderTask": "androidx/leanback/widget/ViewHolderTask",
+      "android/support/v17/leanback/app/RowsFragment$MainFragmentAdapter": "androidx/leanback/app/RowsFragment$MainFragmentAdapter",
+      "android/support/v17/leanback/app/RowsFragment$MainFragmentRowsAdapter": "androidx/leanback/app/RowsFragment$MainFragmentRowsAdapter",
+      "android/support/v7/widget/RecyclerView$RecycledViewPool": "androidx/widget/recyclerview/RecyclerView$RecycledViewPool",
+      "android/support/v17/leanback/widget/ListRowPresenter$ViewHolder": "androidx/leanback/widget/ListRowPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/ListRowPresenter": "androidx/leanback/widget/ListRowPresenter",
+      "android/support/v17/leanback/widget/HorizontalGridView": "androidx/leanback/widget/HorizontalGridView",
+      "android/support/v17/leanback/app/RowsSupportFragment$1": "androidx/leanback/app/RowsSupportFragment$1",
+      "android/support/v17/leanback/app/RowsSupportFragment$RowViewHolderExtra": "androidx/leanback/app/RowsSupportFragment$RowViewHolderExtra",
+      "android/support/v17/leanback/app/RowsSupportFragment$2$1": "androidx/leanback/app/RowsSupportFragment$2$1",
+      "android/support/v17/leanback/app/RowsSupportFragment$2": "androidx/leanback/app/RowsSupportFragment$2",
+      "android/support/v17/leanback/app/RowsSupportFragment$MainFragmentAdapter": "androidx/leanback/app/RowsSupportFragment$MainFragmentAdapter",
+      "android/support/v17/leanback/app/RowsSupportFragment$MainFragmentRowsAdapter": "androidx/leanback/app/RowsSupportFragment$MainFragmentRowsAdapter",
+      "android/support/v17/leanback/app/SearchFragment$1": "androidx/leanback/app/SearchFragment$1",
+      "android/support/v17/leanback/app/SearchFragment": "androidx/leanback/app/SearchFragment",
+      "android/support/v17/leanback/app/SearchFragment$2": "androidx/leanback/app/SearchFragment$2",
+      "android/support/v17/leanback/app/SearchFragment$3": "androidx/leanback/app/SearchFragment$3",
+      "android/support/v17/leanback/app/SearchFragment$SearchResultProvider": "androidx/leanback/app/SearchFragment$SearchResultProvider",
+      "android/support/v17/leanback/app/SearchFragment$4": "androidx/leanback/app/SearchFragment$4",
+      "android/support/v17/leanback/widget/SearchBar": "androidx/leanback/widget/SearchBar",
+      "android/support/v17/leanback/app/SearchFragment$5": "androidx/leanback/app/SearchFragment$5",
+      "android/support/v17/leanback/widget/SearchBar$SearchBarPermissionListener": "androidx/leanback/widget/SearchBar$SearchBarPermissionListener",
+      "android/support/v17/leanback/app/SearchFragment$6": "androidx/leanback/app/SearchFragment$6",
+      "android/support/v17/leanback/widget/SearchBar$SearchBarListener": "androidx/leanback/widget/SearchBar$SearchBarListener",
+      "android/support/v17/leanback/app/SearchFragment$7": "androidx/leanback/app/SearchFragment$7",
+      "android/support/v17/leanback/app/SearchFragment$ExternalQuery": "androidx/leanback/app/SearchFragment$ExternalQuery",
+      "android/support/v17/leanback/widget/SpeechRecognitionCallback": "androidx/leanback/widget/SpeechRecognitionCallback",
+      "android/support/v17/leanback/app/SearchSupportFragment$1": "androidx/leanback/app/SearchSupportFragment$1",
+      "android/support/v17/leanback/app/SearchSupportFragment": "androidx/leanback/app/SearchSupportFragment",
+      "android/support/v17/leanback/app/SearchSupportFragment$2": "androidx/leanback/app/SearchSupportFragment$2",
+      "android/support/v17/leanback/app/SearchSupportFragment$3": "androidx/leanback/app/SearchSupportFragment$3",
+      "android/support/v17/leanback/app/SearchSupportFragment$SearchResultProvider": "androidx/leanback/app/SearchSupportFragment$SearchResultProvider",
+      "android/support/v17/leanback/app/SearchSupportFragment$4": "androidx/leanback/app/SearchSupportFragment$4",
+      "android/support/v17/leanback/app/SearchSupportFragment$5": "androidx/leanback/app/SearchSupportFragment$5",
+      "android/support/v17/leanback/app/SearchSupportFragment$6": "androidx/leanback/app/SearchSupportFragment$6",
+      "android/support/v17/leanback/app/SearchSupportFragment$7": "androidx/leanback/app/SearchSupportFragment$7",
+      "android/support/v17/leanback/app/SearchSupportFragment$ExternalQuery": "androidx/leanback/app/SearchSupportFragment$ExternalQuery",
+      "android/support/v17/leanback/app/VerticalGridFragment$1": "androidx/leanback/app/VerticalGridFragment$1",
+      "android/support/v17/leanback/app/VerticalGridFragment": "androidx/leanback/app/VerticalGridFragment",
+      "android/support/v17/leanback/app/VerticalGridFragment$2": "androidx/leanback/app/VerticalGridFragment$2",
+      "android/support/v17/leanback/widget/VerticalGridPresenter$ViewHolder": "androidx/leanback/widget/VerticalGridPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/VerticalGridPresenter": "androidx/leanback/widget/VerticalGridPresenter",
+      "android/support/v17/leanback/app/VerticalGridFragment$3": "androidx/leanback/app/VerticalGridFragment$3",
+      "android/support/v17/leanback/widget/OnChildLaidOutListener": "androidx/leanback/widget/OnChildLaidOutListener",
+      "android/support/v17/leanback/app/VerticalGridFragment$4": "androidx/leanback/app/VerticalGridFragment$4",
+      "android/support/v17/leanback/app/VerticalGridSupportFragment$1": "androidx/leanback/app/VerticalGridSupportFragment$1",
+      "android/support/v17/leanback/app/VerticalGridSupportFragment": "androidx/leanback/app/VerticalGridSupportFragment",
+      "android/support/v17/leanback/app/VerticalGridSupportFragment$2": "androidx/leanback/app/VerticalGridSupportFragment$2",
+      "android/support/v17/leanback/app/VerticalGridSupportFragment$3": "androidx/leanback/app/VerticalGridSupportFragment$3",
+      "android/support/v17/leanback/app/VerticalGridSupportFragment$4": "androidx/leanback/app/VerticalGridSupportFragment$4",
+      "android/support/v17/leanback/app/VideoFragment$1": "androidx/leanback/app/VideoFragment$1",
+      "android/support/v17/leanback/media/SurfaceHolderGlueHost": "androidx/leanback/media/SurfaceHolderGlueHost",
+      "android/support/v17/leanback/app/VideoSupportFragment$1": "androidx/leanback/app/VideoSupportFragment$1",
+      "android/support/v17/leanback/database/CursorMapper": "androidx/leanback/database/CursorMapper",
+      "android/support/v17/leanback/graphics/BoundsRule$ValueRule": "androidx/leanback/graphics/BoundsRule$ValueRule",
+      "android/support/v17/leanback/graphics/BoundsRule": "androidx/leanback/graphics/BoundsRule",
+      "android/support/v17/leanback/graphics/ColorFilterCache": "androidx/leanback/graphics/ColorFilterCache",
+      "android/support/v17/leanback/graphics/ColorFilterDimmer": "androidx/leanback/graphics/ColorFilterDimmer",
+      "android/support/v17/leanback/graphics/ColorOverlayDimmer": "androidx/leanback/graphics/ColorOverlayDimmer",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$1": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$1",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable",
+      "android/support/v17/leanback/graphics/CompositeDrawable": "androidx/leanback/graphics/CompositeDrawable",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$2": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$2",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$3": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$3",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$4": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$4",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$5": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$5",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$6": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$6",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$7": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$7",
+      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable$8": "androidx/leanback/graphics/CompositeDrawable$ChildDrawable$8",
+      "android/support/v17/leanback/graphics/CompositeDrawable$CompositeState": "androidx/leanback/graphics/CompositeDrawable$CompositeState",
+      "android/support/v17/leanback/graphics/FitWidthBitmapDrawable$1": "androidx/leanback/graphics/FitWidthBitmapDrawable$1",
+      "android/support/v17/leanback/graphics/FitWidthBitmapDrawable$2": "androidx/leanback/graphics/FitWidthBitmapDrawable$2",
+      "android/support/v17/leanback/graphics/FitWidthBitmapDrawable$BitmapState": "androidx/leanback/graphics/FitWidthBitmapDrawable$BitmapState",
+      "android/support/v17/leanback/media/MediaControllerAdapter$1": "androidx/leanback/media/MediaControllerAdapter$1",
+      "android/support/v17/leanback/media/MediaControllerAdapter": "androidx/leanback/media/MediaControllerAdapter",
+      "android/support/v17/leanback/media/PlayerAdapter$Callback": "androidx/leanback/media/PlayerAdapter$Callback",
+      "android/support/v17/leanback/media/PlayerAdapter": "androidx/leanback/media/PlayerAdapter",
+      "android/support/v17/leanback/media/MediaControllerAdapter$2": "androidx/leanback/media/MediaControllerAdapter$2",
+      "android/support/v4/media/session/MediaControllerCompat$Callback": "androidx/media/session/MediaControllerCompat$Callback",
+      "android/support/v4/media/session/MediaControllerCompat": "androidx/media/session/MediaControllerCompat",
+      "android/support/v4/media/session/PlaybackStateCompat": "androidx/media/session/PlaybackStateCompat",
+      "android/support/v4/media/MediaMetadataCompat": "androidx/media/MediaMetadataCompat",
+      "android/support/v4/media/session/MediaControllerCompat$TransportControls": "androidx/media/session/MediaControllerCompat$TransportControls",
+      "android/support/v4/media/MediaDescriptionCompat": "androidx/media/MediaDescriptionCompat",
+      "android/support/v17/leanback/media/MediaControllerGlue$1": "androidx/leanback/media/MediaControllerGlue$1",
+      "android/support/v17/leanback/media/MediaControllerGlue": "androidx/leanback/media/MediaControllerGlue",
+      "android/support/v17/leanback/media/PlaybackControlGlue": "androidx/leanback/media/PlaybackControlGlue",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$1": "androidx/leanback/media/MediaPlayerAdapter$1",
+      "android/support/v17/leanback/media/MediaPlayerAdapter": "androidx/leanback/media/MediaPlayerAdapter",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$2": "androidx/leanback/media/MediaPlayerAdapter$2",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$3": "androidx/leanback/media/MediaPlayerAdapter$3",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$4": "androidx/leanback/media/MediaPlayerAdapter$4",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$5": "androidx/leanback/media/MediaPlayerAdapter$5",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$6": "androidx/leanback/media/MediaPlayerAdapter$6",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$7": "androidx/leanback/media/MediaPlayerAdapter$7",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$8": "androidx/leanback/media/MediaPlayerAdapter$8",
+      "android/support/v17/leanback/media/MediaPlayerAdapter$VideoPlayerSurfaceHolderCallback": "androidx/leanback/media/MediaPlayerAdapter$VideoPlayerSurfaceHolderCallback",
+      "android/support/v17/leanback/media/MediaPlayerGlue$1": "androidx/leanback/media/MediaPlayerGlue$1",
+      "android/support/v17/leanback/media/MediaPlayerGlue": "androidx/leanback/media/MediaPlayerGlue",
+      "android/support/v17/leanback/media/MediaPlayerGlue$2": "androidx/leanback/media/MediaPlayerGlue$2",
+      "android/support/v17/leanback/media/MediaPlayerGlue$3": "androidx/leanback/media/MediaPlayerGlue$3",
+      "android/support/v17/leanback/media/MediaPlayerGlue$4": "androidx/leanback/media/MediaPlayerGlue$4",
+      "android/support/v17/leanback/media/MediaPlayerGlue$5": "androidx/leanback/media/MediaPlayerGlue$5",
+      "android/support/v17/leanback/widget/PlaybackControlsRow": "androidx/leanback/widget/PlaybackControlsRow",
+      "android/support/v17/leanback/media/MediaPlayerGlue$VideoPlayerSurfaceHolderCallback": "androidx/leanback/media/MediaPlayerGlue$VideoPlayerSurfaceHolderCallback",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsDownAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsDownAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsUpAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsUpAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$RepeatAction": "androidx/leanback/widget/PlaybackControlsRow$RepeatAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$RewindAction": "androidx/leanback/widget/PlaybackControlsRow$RewindAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$FastForwardAction": "androidx/leanback/widget/PlaybackControlsRow$FastForwardAction",
+      "android/support/v17/leanback/media/PlaybackBannerControlGlue$1": "androidx/leanback/media/PlaybackBannerControlGlue$1",
+      "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter",
+      "android/support/v17/leanback/media/PlaybackBannerControlGlue": "androidx/leanback/media/PlaybackBannerControlGlue",
+      "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder",
+      "android/support/v17/leanback/media/PlaybackBannerControlGlue$2": "androidx/leanback/media/PlaybackBannerControlGlue$2",
+      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter": "androidx/leanback/widget/PlaybackControlsRowPresenter",
+      "android/support/v17/leanback/media/PlaybackBannerControlGlue$ACTION_": "androidx/leanback/media/PlaybackBannerControlGlue$ACTION_",
+      "android/support/v17/leanback/media/PlaybackBannerControlGlue$SPEED": "androidx/leanback/media/PlaybackBannerControlGlue$SPEED",
+      "android/support/v17/leanback/media/PlaybackBaseControlGlue": "androidx/leanback/media/PlaybackBaseControlGlue",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$PlayPauseAction": "androidx/leanback/widget/PlaybackControlsRow$PlayPauseAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$SkipNextAction": "androidx/leanback/widget/PlaybackControlsRow$SkipNextAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$SkipPreviousAction": "androidx/leanback/widget/PlaybackControlsRow$SkipPreviousAction",
+      "android/support/v17/leanback/media/PlaybackBaseControlGlue$1": "androidx/leanback/media/PlaybackBaseControlGlue$1",
+      "android/support/v17/leanback/widget/ControlButtonPresenterSelector": "androidx/leanback/widget/ControlButtonPresenterSelector",
+      "android/support/v17/leanback/media/PlaybackControlGlue$1": "androidx/leanback/media/PlaybackControlGlue$1",
+      "android/support/v17/leanback/media/PlaybackControlGlue$2": "androidx/leanback/media/PlaybackControlGlue$2",
+      "android/support/v17/leanback/media/PlaybackControlGlue$UpdatePlaybackStateHandler": "androidx/leanback/media/PlaybackControlGlue$UpdatePlaybackStateHandler",
+      "android/support/v17/leanback/media/PlaybackGlue$1": "androidx/leanback/media/PlaybackGlue$1",
+      "android/support/v17/leanback/media/PlaybackGlue$2": "androidx/leanback/media/PlaybackGlue$2",
+      "android/support/v17/leanback/media/PlaybackTransportControlGlue$1": "androidx/leanback/media/PlaybackTransportControlGlue$1",
+      "android/support/v17/leanback/media/PlaybackTransportControlGlue": "androidx/leanback/media/PlaybackTransportControlGlue",
+      "android/support/v17/leanback/media/PlaybackTransportControlGlue$2": "androidx/leanback/media/PlaybackTransportControlGlue$2",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter": "androidx/leanback/widget/PlaybackTransportRowPresenter",
+      "android/support/v17/leanback/media/PlaybackTransportControlGlue$SeekUiClient": "androidx/leanback/media/PlaybackTransportControlGlue$SeekUiClient",
+      "android/support/v17/leanback/media/PlaybackTransportControlGlue$UpdatePlaybackStateHandler": "androidx/leanback/media/PlaybackTransportControlGlue$UpdatePlaybackStateHandler",
+      "android/support/v17/leanback/system/Settings$Customizations": "androidx/leanback/system/Settings$Customizations",
+      "android/support/v17/leanback/system/Settings": "androidx/leanback/system/Settings",
+      "android/support/v17/leanback/widget/ShadowOverlayContainer": "androidx/leanback/widget/ShadowOverlayContainer",
+      "android/support/v17/leanback/transition/FadeAndShortSlide$1": "androidx/leanback/transition/FadeAndShortSlide$1",
+      "android/support/v17/leanback/transition/FadeAndShortSlide$CalculateSlide": "androidx/leanback/transition/FadeAndShortSlide$CalculateSlide",
+      "android/support/v17/leanback/transition/FadeAndShortSlide": "androidx/leanback/transition/FadeAndShortSlide",
+      "android/support/v17/leanback/transition/FadeAndShortSlide$2": "androidx/leanback/transition/FadeAndShortSlide$2",
+      "android/support/v17/leanback/transition/FadeAndShortSlide$3": "androidx/leanback/transition/FadeAndShortSlide$3",
+      "android/support/v17/leanback/transition/FadeAndShortSlide$4": "androidx/leanback/transition/FadeAndShortSlide$4",
+      "android/support/v17/leanback/transition/FadeAndShortSlide$5": "androidx/leanback/transition/FadeAndShortSlide$5",
+      "android/support/v17/leanback/transition/FadeAndShortSlide$6": "androidx/leanback/transition/FadeAndShortSlide$6",
+      "android/support/v17/leanback/transition/TranslationAnimationCreator": "androidx/leanback/transition/TranslationAnimationCreator",
+      "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperDefault": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperDefault",
+      "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperVersion": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperVersion",
+      "android/support/v17/leanback/transition/LeanbackTransitionHelper": "androidx/leanback/transition/LeanbackTransitionHelper",
+      "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperKitKatImpl": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperKitKatImpl",
+      "android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat": "androidx/leanback/transition/LeanbackTransitionHelperKitKat",
+      "android/support/v17/leanback/R$anim": "androidx/leanback/R$anim",
+      "android/support/v17/leanback/transition/SlideKitkat": "androidx/leanback/transition/SlideKitkat",
+      "android/support/v17/leanback/transition/ParallaxTransition$1": "androidx/leanback/transition/ParallaxTransition$1",
+      "android/support/v17/leanback/transition/ParallaxTransition": "androidx/leanback/transition/ParallaxTransition",
+      "android/support/v17/leanback/transition/Scale$1": "androidx/leanback/transition/Scale$1",
+      "android/support/v17/leanback/transition/Scale": "androidx/leanback/transition/Scale",
+      "android/support/v17/leanback/transition/SlideKitkat$1": "androidx/leanback/transition/SlideKitkat$1",
+      "android/support/v17/leanback/transition/SlideKitkat$CalculateSlideHorizontal": "androidx/leanback/transition/SlideKitkat$CalculateSlideHorizontal",
+      "android/support/v17/leanback/transition/SlideKitkat$2": "androidx/leanback/transition/SlideKitkat$2",
+      "android/support/v17/leanback/transition/SlideKitkat$CalculateSlideVertical": "androidx/leanback/transition/SlideKitkat$CalculateSlideVertical",
+      "android/support/v17/leanback/transition/SlideKitkat$3": "androidx/leanback/transition/SlideKitkat$3",
+      "android/support/v17/leanback/transition/SlideKitkat$4": "androidx/leanback/transition/SlideKitkat$4",
+      "android/support/v17/leanback/transition/SlideKitkat$5": "androidx/leanback/transition/SlideKitkat$5",
+      "android/support/v17/leanback/transition/SlideKitkat$6": "androidx/leanback/transition/SlideKitkat$6",
+      "android/support/v17/leanback/transition/SlideKitkat$CalculateSlide": "androidx/leanback/transition/SlideKitkat$CalculateSlide",
+      "android/support/v17/leanback/transition/SlideKitkat$SlideAnimatorListener": "androidx/leanback/transition/SlideKitkat$SlideAnimatorListener",
+      "android/support/v17/leanback/transition/SlideNoPropagation": "androidx/leanback/transition/SlideNoPropagation",
+      "android/support/v17/leanback/transition/TransitionEpicenterCallback": "androidx/leanback/transition/TransitionEpicenterCallback",
+      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperApi21Impl": "androidx/leanback/transition/TransitionHelper$TransitionHelperApi21Impl",
+      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperKitkatImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperKitkatImpl",
+      "android/support/v17/leanback/transition/TransitionHelperApi21": "androidx/leanback/transition/TransitionHelperApi21",
+      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperStubImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperStubImpl",
+      "android/support/v17/leanback/transition/TransitionHelperKitkat": "androidx/leanback/transition/TransitionHelperKitkat",
+      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperStubImpl$TransitionStub": "androidx/leanback/transition/TransitionHelper$TransitionHelperStubImpl$TransitionStub",
+      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperVersionImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperVersionImpl",
+      "android/support/v17/leanback/transition/TransitionHelperApi21$1": "androidx/leanback/transition/TransitionHelperApi21$1",
+      "android/support/v17/leanback/transition/TransitionHelperKitkat$1": "androidx/leanback/transition/TransitionHelperKitkat$1",
+      "android/support/v17/leanback/transition/TransitionHelperKitkat$CustomChangeBounds": "androidx/leanback/transition/TransitionHelperKitkat$CustomChangeBounds",
+      "android/support/v17/leanback/transition/TranslationAnimationCreator$TransitionPositionListener": "androidx/leanback/transition/TranslationAnimationCreator$TransitionPositionListener",
+      "android/support/v17/leanback/util/MathUtil": "androidx/leanback/util/MathUtil",
+      "android/support/v17/leanback/util/StateMachine$Transition": "androidx/leanback/util/StateMachine$Transition",
+      "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder$1": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder$2": "androidx/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder$2",
+      "android/support/v17/leanback/widget/AbstractMediaItemPresenter$1": "androidx/leanback/widget/AbstractMediaItemPresenter$1",
+      "android/support/v17/leanback/widget/AbstractMediaItemPresenter": "androidx/leanback/widget/AbstractMediaItemPresenter",
+      "android/support/v17/leanback/widget/AbstractMediaItemPresenter$ViewHolder$1": "androidx/leanback/widget/AbstractMediaItemPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/AbstractMediaItemPresenter$ViewHolder": "androidx/leanback/widget/AbstractMediaItemPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/AbstractMediaItemPresenter$ViewHolder$2": "androidx/leanback/widget/AbstractMediaItemPresenter$ViewHolder$2",
+      "android/support/v17/leanback/widget/AbstractMediaItemPresenter$ViewHolder$3": "androidx/leanback/widget/AbstractMediaItemPresenter$ViewHolder$3",
+      "android/support/v17/leanback/widget/AbstractMediaItemPresenter$ViewHolder$4": "androidx/leanback/widget/AbstractMediaItemPresenter$ViewHolder$4",
+      "android/support/v17/leanback/widget/MultiActionsProvider$MultiAction": "androidx/leanback/widget/MultiActionsProvider$MultiAction",
+      "android/support/v17/leanback/widget/MultiActionsProvider": "androidx/leanback/widget/MultiActionsProvider",
+      "android/support/v17/leanback/widget/MediaItemActionPresenter": "androidx/leanback/widget/MediaItemActionPresenter",
+      "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder": "androidx/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter": "androidx/leanback/widget/AbstractMediaListHeaderPresenter",
+      "android/support/v17/leanback/widget/ActionPresenterSelector$ActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$ActionPresenter",
+      "android/support/v17/leanback/widget/ActionPresenterSelector": "androidx/leanback/widget/ActionPresenterSelector",
+      "android/support/v17/leanback/widget/ActionPresenterSelector$ActionViewHolder": "androidx/leanback/widget/ActionPresenterSelector$ActionViewHolder",
+      "android/support/v17/leanback/widget/ActionPresenterSelector$OneLineActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$OneLineActionPresenter",
+      "android/support/v17/leanback/widget/ActionPresenterSelector$TwoLineActionPresenter": "androidx/leanback/widget/ActionPresenterSelector$TwoLineActionPresenter",
+      "android/support/v17/leanback/widget/ArrayObjectAdapter$1": "androidx/leanback/widget/ArrayObjectAdapter$1",
+      "android/support/v7/util/DiffUtil$Callback": "androidx/widget/recyclerview/DiffUtil$Callback",
+      "android/support/v7/util/DiffUtil": "androidx/widget/recyclerview/DiffUtil",
+      "android/support/v17/leanback/widget/ArrayObjectAdapter$2": "androidx/leanback/widget/ArrayObjectAdapter$2",
+      "android/support/v7/util/ListUpdateCallback": "androidx/widget/recyclerview/ListUpdateCallback",
+      "android/support/v7/util/DiffUtil$DiffResult": "androidx/widget/recyclerview/DiffUtil$DiffResult",
+      "android/support/v17/leanback/widget/BaseCardView$1": "androidx/leanback/widget/BaseCardView$1",
+      "android/support/v17/leanback/widget/BaseCardView": "androidx/leanback/widget/BaseCardView",
+      "android/support/v17/leanback/widget/BaseCardView$2": "androidx/leanback/widget/BaseCardView$2",
+      "android/support/v17/leanback/widget/BaseCardView$3": "androidx/leanback/widget/BaseCardView$3",
+      "android/support/v17/leanback/widget/BaseCardView$4": "androidx/leanback/widget/BaseCardView$4",
+      "android/support/v17/leanback/widget/BaseCardView$AnimationBase": "androidx/leanback/widget/BaseCardView$AnimationBase",
+      "android/support/annotation/VisibleForTesting": "androidx/annotation/VisibleForTesting",
+      "android/support/v17/leanback/widget/BaseCardView$InfoAlphaAnimation": "androidx/leanback/widget/BaseCardView$InfoAlphaAnimation",
+      "android/support/v17/leanback/widget/BaseCardView$InfoHeightAnimation": "androidx/leanback/widget/BaseCardView$InfoHeightAnimation",
+      "android/support/v17/leanback/widget/BaseCardView$InfoOffsetAnimation": "androidx/leanback/widget/BaseCardView$InfoOffsetAnimation",
+      "android/support/v17/leanback/widget/BaseCardView$LayoutParams": "androidx/leanback/widget/BaseCardView$LayoutParams",
+      "android/support/v17/leanback/widget/BaseGridView$1": "androidx/leanback/widget/BaseGridView$1",
+      "android/support/v7/widget/RecyclerView$RecyclerListener": "androidx/widget/recyclerview/RecyclerView$RecyclerListener",
+      "android/support/v17/leanback/widget/GridLayoutManager": "androidx/leanback/widget/GridLayoutManager",
+      "android/support/v17/leanback/widget/BaseGridView$2": "androidx/leanback/widget/BaseGridView$2",
+      "android/support/v17/leanback/widget/BaseGridView$3": "androidx/leanback/widget/BaseGridView$3",
+      "android/support/v17/leanback/widget/BaseGridView$OnMotionInterceptListener": "androidx/leanback/widget/BaseGridView$OnMotionInterceptListener",
+      "android/support/v17/leanback/widget/BaseGridView$OnUnhandledKeyListener": "androidx/leanback/widget/BaseGridView$OnUnhandledKeyListener",
+      "android/support/v7/widget/RecyclerView$ItemAnimator": "androidx/widget/recyclerview/RecyclerView$ItemAnimator",
+      "android/support/v7/widget/RecyclerView$LayoutManager": "androidx/widget/recyclerview/RecyclerView$LayoutManager",
+      "android/support/v17/leanback/widget/WindowAlignment$Axis": "androidx/leanback/widget/WindowAlignment$Axis",
+      "android/support/v17/leanback/widget/WindowAlignment": "androidx/leanback/widget/WindowAlignment",
+      "android/support/v7/widget/SimpleItemAnimator": "androidx/widget/recyclerview/SimpleItemAnimator",
+      "android/support/v17/leanback/widget/OnChildSelectedListener": "androidx/leanback/widget/OnChildSelectedListener",
+      "android/support/v17/leanback/widget/ViewsStateBundle": "androidx/leanback/widget/ViewsStateBundle",
+      "android/support/v17/leanback/widget/BrowseRowsFrameLayout": "androidx/leanback/widget/BrowseRowsFrameLayout",
+      "android/support/v17/leanback/widget/CheckableImageView": "androidx/leanback/widget/CheckableImageView",
+      "android/support/v17/leanback/widget/ControlBar$OnChildFocusedListener": "androidx/leanback/widget/ControlBar$OnChildFocusedListener",
+      "android/support/v17/leanback/widget/ControlBar": "androidx/leanback/widget/ControlBar",
+      "android/support/v17/leanback/widget/ControlBarPresenter$BoundData": "androidx/leanback/widget/ControlBarPresenter$BoundData",
+      "android/support/v17/leanback/widget/ControlBarPresenter": "androidx/leanback/widget/ControlBarPresenter",
+      "android/support/v17/leanback/widget/ControlBarPresenter$OnControlClickedListener": "androidx/leanback/widget/ControlBarPresenter$OnControlClickedListener",
+      "android/support/v17/leanback/widget/ControlBarPresenter$OnControlSelectedListener": "androidx/leanback/widget/ControlBarPresenter$OnControlSelectedListener",
+      "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder$1": "androidx/leanback/widget/ControlBarPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder": "androidx/leanback/widget/ControlBarPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder$2": "androidx/leanback/widget/ControlBarPresenter$ViewHolder$2",
+      "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder$3": "androidx/leanback/widget/ControlBarPresenter$ViewHolder$3",
+      "android/support/v17/leanback/widget/ControlButtonPresenterSelector$ActionViewHolder": "androidx/leanback/widget/ControlButtonPresenterSelector$ActionViewHolder",
+      "android/support/v17/leanback/widget/ControlButtonPresenterSelector$ControlButtonPresenter": "androidx/leanback/widget/ControlButtonPresenterSelector$ControlButtonPresenter",
+      "android/support/v17/leanback/widget/CursorObjectAdapter": "androidx/leanback/widget/CursorObjectAdapter",
+      "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder": "androidx/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter": "androidx/leanback/widget/DetailsOverviewLogoPresenter",
+      "android/support/v17/leanback/widget/DetailsOverviewRow": "androidx/leanback/widget/DetailsOverviewRow",
+      "android/support/v17/leanback/widget/DetailsOverviewRow$Listener": "androidx/leanback/widget/DetailsOverviewRow$Listener",
+      "android/support/v17/leanback/widget/HeaderItem": "androidx/leanback/widget/HeaderItem",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$1": "androidx/leanback/widget/DetailsOverviewRowPresenter$1",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter": "androidx/leanback/widget/DetailsOverviewRowPresenter",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter$1": "androidx/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter$1",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter": "androidx/leanback/widget/DetailsOverviewRowPresenter$ActionsItemBridgeAdapter",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$1": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$2": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$2",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$3": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$3",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$4": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$4",
+      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$5": "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder$5",
+      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper": "androidx/leanback/widget/DetailsOverviewSharedElementHelper",
+      "android/support/v17/leanback/widget/RoundedRectHelper": "androidx/leanback/widget/RoundedRectHelper",
+      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper$1": "androidx/leanback/widget/DetailsOverviewSharedElementHelper$1",
+      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper$2$1": "androidx/leanback/widget/DetailsOverviewSharedElementHelper$2$1",
+      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper$2": "androidx/leanback/widget/DetailsOverviewSharedElementHelper$2",
+      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper$TransitionTimeOutRunnable": "androidx/leanback/widget/DetailsOverviewSharedElementHelper$TransitionTimeOutRunnable",
+      "android/support/v4/app/SharedElementCallback": "androidx/app/SharedElementCallback",
+      "android/support/v17/leanback/widget/RecyclerViewParallax": "androidx/leanback/widget/RecyclerViewParallax",
+      "android/support/v17/leanback/widget/RecyclerViewParallax$ChildPositionProperty": "androidx/leanback/widget/RecyclerViewParallax$ChildPositionProperty",
+      "android/support/v17/leanback/widget/FacetProvider": "androidx/leanback/widget/FacetProvider",
+      "android/support/v17/leanback/widget/FacetProviderAdapter": "androidx/leanback/widget/FacetProviderAdapter",
+      "android/support/v17/leanback/widget/FocusHighlight": "androidx/leanback/widget/FocusHighlight",
+      "android/support/v17/leanback/widget/FocusHighlightHandler": "androidx/leanback/widget/FocusHighlightHandler",
+      "android/support/v17/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight": "androidx/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight",
+      "android/support/v17/leanback/widget/FocusHighlightHelper$FocusAnimator": "androidx/leanback/widget/FocusHighlightHelper$FocusAnimator",
+      "android/support/v17/leanback/widget/ShadowOverlayHelper": "androidx/leanback/widget/ShadowOverlayHelper",
+      "android/support/v17/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight$HeaderFocusAnimator": "androidx/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight$HeaderFocusAnimator",
+      "android/support/v17/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight": "androidx/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight",
+      "android/support/v17/leanback/widget/ForegroundHelper": "androidx/leanback/widget/ForegroundHelper",
+      "android/support/v17/leanback/widget/FragmentAnimationProvider": "androidx/leanback/widget/FragmentAnimationProvider",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$1": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$1",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter$1": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter$1",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$Listener": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$Listener",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$1": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$2": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$2",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$3": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$3",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$4": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$4",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$DetailsOverviewRowListener": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder$DetailsOverviewRowListener",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$1$1": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$1$1",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$1": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$1",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$2": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$2",
+      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$TransitionTimeOutRunnable": "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper$TransitionTimeOutRunnable",
+      "android/support/v17/leanback/widget/Grid$Location": "androidx/leanback/widget/Grid$Location",
+      "android/support/v17/leanback/widget/Grid": "androidx/leanback/widget/Grid",
+      "android/support/v17/leanback/widget/Grid$Provider": "androidx/leanback/widget/Grid$Provider",
+      "android/support/v7/widget/RecyclerView$LayoutManager$LayoutPrefetchRegistry": "androidx/widget/recyclerview/RecyclerView$LayoutManager$LayoutPrefetchRegistry",
+      "android/support/v4/util/CircularIntArray": "androidx/util/CircularIntArray",
+      "android/support/v17/leanback/widget/SingleRow": "androidx/leanback/widget/SingleRow",
+      "android/support/v17/leanback/widget/StaggeredGridDefault": "androidx/leanback/widget/StaggeredGridDefault",
+      "android/support/v17/leanback/widget/GridLayoutManager$1": "androidx/leanback/widget/GridLayoutManager$1",
+      "android/support/v17/leanback/widget/GridLayoutManager$2": "androidx/leanback/widget/GridLayoutManager$2",
+      "android/support/v17/leanback/widget/GridLayoutManager$LayoutParams": "androidx/leanback/widget/GridLayoutManager$LayoutParams",
+      "android/support/v7/widget/RecyclerView$State": "androidx/widget/recyclerview/RecyclerView$State",
+      "android/support/v17/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller": "androidx/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller",
+      "android/support/v7/widget/RecyclerView$Recycler": "androidx/widget/recyclerview/RecyclerView$Recycler",
+      "android/support/v17/leanback/widget/GridLayoutManager$3": "androidx/leanback/widget/GridLayoutManager$3",
+      "android/support/v17/leanback/widget/GridLayoutManager$4": "androidx/leanback/widget/GridLayoutManager$4",
+      "android/support/v17/leanback/widget/GridLayoutManager$GridLinearSmoothScroller": "androidx/leanback/widget/GridLayoutManager$GridLinearSmoothScroller",
+      "android/support/v7/widget/LinearSmoothScroller": "androidx/widget/recyclerview/LinearSmoothScroller",
+      "android/support/v7/widget/RecyclerView$SmoothScroller": "androidx/widget/recyclerview/RecyclerView$SmoothScroller",
+      "android/support/v7/widget/RecyclerView$SmoothScroller$Action": "androidx/widget/recyclerview/RecyclerView$SmoothScroller$Action",
+      "android/support/v7/widget/RecyclerView$LayoutParams": "androidx/widget/recyclerview/RecyclerView$LayoutParams",
+      "android/support/v17/leanback/widget/ItemAlignmentFacetHelper": "androidx/leanback/widget/ItemAlignmentFacetHelper",
+      "android/support/v17/leanback/widget/GridLayoutManager$OnLayoutCompleteListener": "androidx/leanback/widget/GridLayoutManager$OnLayoutCompleteListener",
+      "android/support/v17/leanback/widget/GridLayoutManager$SavedState$1": "androidx/leanback/widget/GridLayoutManager$SavedState$1",
+      "android/support/v17/leanback/widget/GridLayoutManager$SavedState": "androidx/leanback/widget/GridLayoutManager$SavedState",
+      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat",
+      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat",
+      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat",
+      "android/support/v17/leanback/widget/ItemAlignment$Axis": "androidx/leanback/widget/ItemAlignment$Axis",
+      "android/support/v17/leanback/widget/ItemAlignment": "androidx/leanback/widget/ItemAlignment",
+      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionItemInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionItemInfoCompat",
+      "android/support/v7/widget/OrientationHelper": "androidx/widget/recyclerview/OrientationHelper",
+      "android/support/v17/leanback/widget/GuidanceStylingRelativeLayout": "androidx/leanback/widget/GuidanceStylingRelativeLayout",
+      "android/support/v17/leanback/widget/GuidedAction$Builder": "androidx/leanback/widget/GuidedAction$Builder",
+      "android/support/v17/leanback/widget/GuidedAction$BuilderBase": "androidx/leanback/widget/GuidedAction$BuilderBase",
+      "android/support/annotation/StringRes": "androidx/annotation/StringRes",
+      "android/support/annotation/DrawableRes": "androidx/annotation/DrawableRes",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$1": "androidx/leanback/widget/GuidedActionAdapter$1",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$ViewHolder": "androidx/leanback/widget/GuidedActionsStylist$ViewHolder",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$2": "androidx/leanback/widget/GuidedActionAdapter$2",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$ActionEditListener": "androidx/leanback/widget/GuidedActionAdapter$ActionEditListener",
+      "android/support/v17/leanback/widget/ImeKeyMonitor$ImeKeyListener": "androidx/leanback/widget/ImeKeyMonitor$ImeKeyListener",
+      "android/support/v17/leanback/widget/ImeKeyMonitor": "androidx/leanback/widget/ImeKeyMonitor",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$ActionOnFocusListener": "androidx/leanback/widget/GuidedActionAdapter$ActionOnFocusListener",
+      "android/support/v17/leanback/widget/GuidedActionAdapter$ActionOnKeyListener": "androidx/leanback/widget/GuidedActionAdapter$ActionOnKeyListener",
+      "android/support/v17/leanback/widget/GuidedActionDiffCallback": "androidx/leanback/widget/GuidedActionDiffCallback",
+      "android/support/v17/leanback/widget/GuidedActionEditText$NoPaddingDrawable": "androidx/leanback/widget/GuidedActionEditText$NoPaddingDrawable",
+      "android/support/v17/leanback/widget/GuidedActionEditText": "androidx/leanback/widget/GuidedActionEditText",
+      "android/support/v17/leanback/widget/GuidedActionItemContainer": "androidx/leanback/widget/GuidedActionItemContainer",
+      "android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground": "androidx/leanback/widget/NonOverlappingLinearLayoutWithForeground",
+      "android/support/v17/leanback/widget/GuidedActionsRelativeLayout$InterceptKeyEventListener": "androidx/leanback/widget/GuidedActionsRelativeLayout$InterceptKeyEventListener",
+      "android/support/v17/leanback/widget/GuidedActionsRelativeLayout": "androidx/leanback/widget/GuidedActionsRelativeLayout",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$1": "androidx/leanback/widget/GuidedActionsStylist$1",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$2": "androidx/leanback/widget/GuidedActionsStylist$2",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$3": "androidx/leanback/widget/GuidedActionsStylist$3",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$4": "androidx/leanback/widget/GuidedActionsStylist$4",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$5": "androidx/leanback/widget/GuidedActionsStylist$5",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$6": "androidx/leanback/widget/GuidedActionsStylist$6",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$7": "androidx/leanback/widget/GuidedActionsStylist$7",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$ViewHolder$1": "androidx/leanback/widget/GuidedActionsStylist$ViewHolder$1",
+      "android/support/v17/leanback/widget/GuidedActionsStylist$ViewHolder$2": "androidx/leanback/widget/GuidedActionsStylist$ViewHolder$2",
+      "android/support/v17/leanback/widget/GuidedDatePickerAction": "androidx/leanback/widget/GuidedDatePickerAction",
+      "android/support/v17/leanback/widget/picker/DatePicker": "androidx/leanback/widget/picker/DatePicker",
+      "android/support/v17/leanback/widget/GuidedDatePickerAction$Builder": "androidx/leanback/widget/GuidedDatePickerAction$Builder",
+      "android/support/v17/leanback/widget/GuidedDatePickerAction$BuilderBase": "androidx/leanback/widget/GuidedDatePickerAction$BuilderBase",
+      "android/support/v17/leanback/widget/HorizontalHoverCardSwitcher": "androidx/leanback/widget/HorizontalHoverCardSwitcher",
+      "android/support/v17/leanback/widget/PresenterSwitcher": "androidx/leanback/widget/PresenterSwitcher",
+      "android/support/v17/leanback/widget/ImageCardView": "androidx/leanback/widget/ImageCardView",
+      "android/support/v17/leanback/R$style": "androidx/leanback/R$style",
+      "android/support/v17/leanback/widget/ItemBridgeAdapter$1": "androidx/leanback/widget/ItemBridgeAdapter$1",
+      "android/support/v17/leanback/widget/ItemBridgeAdapter$OnFocusChangeListener": "androidx/leanback/widget/ItemBridgeAdapter$OnFocusChangeListener",
+      "android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper": "androidx/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper",
+      "android/support/v17/leanback/widget/ListRowHoverCardView": "androidx/leanback/widget/ListRowHoverCardView",
+      "android/support/v17/leanback/widget/ListRowPresenter$1": "androidx/leanback/widget/ListRowPresenter$1",
+      "android/support/v17/leanback/widget/ListRowPresenter$2": "androidx/leanback/widget/ListRowPresenter$2",
+      "android/support/v17/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter$1": "androidx/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter$1",
+      "android/support/v17/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter": "androidx/leanback/widget/ListRowPresenter$ListRowPresenterItemBridgeAdapter",
+      "android/support/v17/leanback/widget/ListRowPresenter$SelectItemViewHolderTask$1": "androidx/leanback/widget/ListRowPresenter$SelectItemViewHolderTask$1",
+      "android/support/v17/leanback/widget/ListRowPresenter$SelectItemViewHolderTask": "androidx/leanback/widget/ListRowPresenter$SelectItemViewHolderTask",
+      "android/support/v17/leanback/widget/ShadowOverlayHelper$Options": "androidx/leanback/widget/ShadowOverlayHelper$Options",
+      "android/support/v17/leanback/widget/ShadowOverlayHelper$Builder": "androidx/leanback/widget/ShadowOverlayHelper$Builder",
+      "android/support/v17/leanback/widget/ListRowView": "androidx/leanback/widget/ListRowView",
+      "android/support/v17/leanback/widget/MediaItemActionPresenter$ViewHolder": "androidx/leanback/widget/MediaItemActionPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/MediaNowPlayingView": "androidx/leanback/widget/MediaNowPlayingView",
+      "android/support/v17/leanback/widget/MediaRowFocusView": "androidx/leanback/widget/MediaRowFocusView",
+      "android/support/v17/leanback/widget/NonOverlappingFrameLayout": "androidx/leanback/widget/NonOverlappingFrameLayout",
+      "android/support/v17/leanback/widget/NonOverlappingRelativeLayout": "androidx/leanback/widget/NonOverlappingRelativeLayout",
+      "android/support/v17/leanback/widget/NonOverlappingView": "androidx/leanback/widget/NonOverlappingView",
+      "android/support/v17/leanback/widget/ObjectAdapter$DataObservable": "androidx/leanback/widget/ObjectAdapter$DataObservable",
+      "android/support/v17/leanback/widget/SinglePresenterSelector": "androidx/leanback/widget/SinglePresenterSelector",
+      "android/support/v17/leanback/widget/PagingIndicator$1": "androidx/leanback/widget/PagingIndicator$1",
+      "android/support/v17/leanback/widget/PagingIndicator$Dot": "androidx/leanback/widget/PagingIndicator$Dot",
+      "android/support/v17/leanback/widget/PagingIndicator$2": "androidx/leanback/widget/PagingIndicator$2",
+      "android/support/v17/leanback/widget/PagingIndicator$3": "androidx/leanback/widget/PagingIndicator$3",
+      "android/support/v17/leanback/widget/Parallax$FloatProperty": "androidx/leanback/widget/Parallax$FloatProperty",
+      "android/support/v17/leanback/widget/Parallax$FloatPropertyMarkerValue": "androidx/leanback/widget/Parallax$FloatPropertyMarkerValue",
+      "android/support/v17/leanback/widget/Parallax$IntPropertyMarkerValue": "androidx/leanback/widget/Parallax$IntPropertyMarkerValue",
+      "android/support/v17/leanback/widget/ParallaxEffect$IntEffect": "androidx/leanback/widget/ParallaxEffect$IntEffect",
+      "android/support/v17/leanback/widget/ParallaxEffect$FloatEffect": "androidx/leanback/widget/ParallaxEffect$FloatEffect",
+      "android/support/v17/leanback/widget/ParallaxTarget$DirectPropertyTarget": "androidx/leanback/widget/ParallaxTarget$DirectPropertyTarget",
+      "android/support/v17/leanback/widget/PersistentFocusWrapper$SavedState$1": "androidx/leanback/widget/PersistentFocusWrapper$SavedState$1",
+      "android/support/v17/leanback/widget/PersistentFocusWrapper$SavedState": "androidx/leanback/widget/PersistentFocusWrapper$SavedState",
+      "android/support/v17/leanback/widget/PersistentFocusWrapper": "androidx/leanback/widget/PersistentFocusWrapper",
+      "android/support/v17/leanback/widget/PlaybackControlsPresenter$BoundData": "androidx/leanback/widget/PlaybackControlsPresenter$BoundData",
+      "android/support/v17/leanback/widget/PlaybackControlsPresenter": "androidx/leanback/widget/PlaybackControlsPresenter",
+      "android/support/v17/leanback/widget/PlaybackControlsPresenter$ViewHolder$1": "androidx/leanback/widget/PlaybackControlsPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/PlaybackControlsPresenter$ViewHolder": "androidx/leanback/widget/PlaybackControlsPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/PlaybackControlsPresenter$ViewHolder$2": "androidx/leanback/widget/PlaybackControlsPresenter$ViewHolder$2",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$MoreActions": "androidx/leanback/widget/PlaybackControlsRow$MoreActions",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction": "androidx/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$MultiAction": "androidx/leanback/widget/PlaybackControlsRow$MultiAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$HighQualityAction": "androidx/leanback/widget/PlaybackControlsRow$HighQualityAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$OnPlaybackProgressCallback": "androidx/leanback/widget/PlaybackControlsRow$OnPlaybackProgressCallback",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$PictureInPictureAction": "androidx/leanback/widget/PlaybackControlsRow$PictureInPictureAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRow$ShuffleAction": "androidx/leanback/widget/PlaybackControlsRow$ShuffleAction",
+      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$1": "androidx/leanback/widget/PlaybackControlsRowPresenter$1",
+      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackControlsRowPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$BoundData": "androidx/leanback/widget/PlaybackControlsRowPresenter$BoundData",
+      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$2": "androidx/leanback/widget/PlaybackControlsRowPresenter$2",
+      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$3": "androidx/leanback/widget/PlaybackControlsRowPresenter$3",
+      "android/support/v17/leanback/widget/PlaybackControlsRowView$OnUnhandledKeyListener": "androidx/leanback/widget/PlaybackControlsRowView$OnUnhandledKeyListener",
+      "android/support/v17/leanback/widget/PlaybackControlsRowView": "androidx/leanback/widget/PlaybackControlsRowView",
+      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$ViewHolder$1": "androidx/leanback/widget/PlaybackControlsRowPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/ShadowHelper": "androidx/leanback/widget/ShadowHelper",
+      "android/support/v17/leanback/widget/PlaybackSeekDataProvider$ResultCallback": "androidx/leanback/widget/PlaybackSeekDataProvider$ResultCallback",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$1": "androidx/leanback/widget/PlaybackTransportRowPresenter$1",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$BoundData": "androidx/leanback/widget/PlaybackTransportRowPresenter$BoundData",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$2": "androidx/leanback/widget/PlaybackTransportRowPresenter$2",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$3": "androidx/leanback/widget/PlaybackTransportRowPresenter$3",
+      "android/support/v17/leanback/widget/PlaybackTransportRowView$OnUnhandledKeyListener": "androidx/leanback/widget/PlaybackTransportRowView$OnUnhandledKeyListener",
+      "android/support/v17/leanback/widget/PlaybackTransportRowView": "androidx/leanback/widget/PlaybackTransportRowView",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$1": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$1",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$2": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$2",
+      "android/support/v17/leanback/widget/ThumbsBar": "androidx/leanback/widget/ThumbsBar",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$3": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$3",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$4": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$4",
+      "android/support/v17/leanback/widget/SeekBar": "androidx/leanback/widget/SeekBar",
+      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$5": "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder$5",
+      "android/support/v17/leanback/widget/SeekBar$AccessibilitySeekListener": "androidx/leanback/widget/SeekBar$AccessibilitySeekListener",
+      "android/support/v17/leanback/widget/RecyclerViewParallax$1": "androidx/leanback/widget/RecyclerViewParallax$1",
+      "android/support/v17/leanback/widget/RecyclerViewParallax$2": "androidx/leanback/widget/RecyclerViewParallax$2",
+      "android/support/v7/widget/RecyclerView$LayoutManager$Properties": "androidx/widget/recyclerview/RecyclerView$LayoutManager$Properties",
+      "android/support/v17/leanback/widget/ResizingTextView": "androidx/leanback/widget/ResizingTextView",
+      "android/support/v17/leanback/widget/RoundedRectHelper$Api21Impl": "androidx/leanback/widget/RoundedRectHelper$Api21Impl",
+      "android/support/v17/leanback/widget/RoundedRectHelper$Impl": "androidx/leanback/widget/RoundedRectHelper$Impl",
+      "android/support/v17/leanback/widget/RoundedRectHelperApi21": "androidx/leanback/widget/RoundedRectHelperApi21",
+      "android/support/v17/leanback/widget/RoundedRectHelper$StubImpl": "androidx/leanback/widget/RoundedRectHelper$StubImpl",
+      "android/support/v17/leanback/widget/RoundedRectHelperApi21$RoundedRectOutlineProvider": "androidx/leanback/widget/RoundedRectHelperApi21$RoundedRectOutlineProvider",
+      "android/support/v17/leanback/widget/RowContainerView": "androidx/leanback/widget/RowContainerView",
+      "android/support/v17/leanback/widget/RowHeaderView": "androidx/leanback/widget/RowHeaderView",
+      "android/support/v17/leanback/widget/RowPresenter$ContainerViewHolder": "androidx/leanback/widget/RowPresenter$ContainerViewHolder",
+      "android/support/v17/leanback/widget/SearchBar$1": "androidx/leanback/widget/SearchBar$1",
+      "android/support/v17/leanback/widget/SearchBar$10": "androidx/leanback/widget/SearchBar$10",
+      "android/support/v17/leanback/widget/SearchBar$2": "androidx/leanback/widget/SearchBar$2",
+      "android/support/v17/leanback/widget/SearchEditText": "androidx/leanback/widget/SearchEditText",
+      "android/support/v17/leanback/widget/SearchBar$3": "androidx/leanback/widget/SearchBar$3",
+      "android/support/v17/leanback/widget/SearchBar$4": "androidx/leanback/widget/SearchBar$4",
+      "android/support/v17/leanback/widget/SearchEditText$OnKeyboardDismissListener": "androidx/leanback/widget/SearchEditText$OnKeyboardDismissListener",
+      "android/support/v17/leanback/widget/SearchBar$5$1": "androidx/leanback/widget/SearchBar$5$1",
+      "android/support/v17/leanback/widget/SearchBar$5": "androidx/leanback/widget/SearchBar$5",
+      "android/support/v17/leanback/widget/SearchBar$5$2": "androidx/leanback/widget/SearchBar$5$2",
+      "android/support/v17/leanback/widget/SearchBar$5$3": "androidx/leanback/widget/SearchBar$5$3",
+      "android/support/v17/leanback/widget/SpeechOrbView": "androidx/leanback/widget/SpeechOrbView",
+      "android/support/v17/leanback/widget/SearchBar$6": "androidx/leanback/widget/SearchBar$6",
+      "android/support/v17/leanback/widget/SearchBar$7": "androidx/leanback/widget/SearchBar$7",
+      "android/support/v17/leanback/widget/SearchBar$8": "androidx/leanback/widget/SearchBar$8",
+      "android/support/v17/leanback/widget/SearchBar$9": "androidx/leanback/widget/SearchBar$9",
+      "android/support/v17/leanback/R$raw": "androidx/leanback/R$raw",
+      "android/support/v17/leanback/widget/StreamingTextView": "androidx/leanback/widget/StreamingTextView",
+      "android/support/v17/leanback/widget/SearchOrbView$1": "androidx/leanback/widget/SearchOrbView$1",
+      "android/support/v17/leanback/widget/SearchOrbView$2": "androidx/leanback/widget/SearchOrbView$2",
+      "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperApi21Impl": "androidx/leanback/widget/ShadowHelper$ShadowHelperApi21Impl",
+      "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperVersionImpl": "androidx/leanback/widget/ShadowHelper$ShadowHelperVersionImpl",
+      "android/support/v17/leanback/widget/ShadowHelperApi21": "androidx/leanback/widget/ShadowHelperApi21",
+      "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperStubImpl": "androidx/leanback/widget/ShadowHelper$ShadowHelperStubImpl",
+      "android/support/v17/leanback/widget/ShadowHelperApi21$1": "androidx/leanback/widget/ShadowHelperApi21$1",
+      "android/support/v17/leanback/widget/ShadowHelperApi21$ShadowImpl": "androidx/leanback/widget/ShadowHelperApi21$ShadowImpl",
+      "android/support/v17/leanback/widget/ShadowHelperJbmr2$ShadowImpl": "androidx/leanback/widget/ShadowHelperJbmr2$ShadowImpl",
+      "android/support/v17/leanback/widget/ShadowHelperJbmr2": "androidx/leanback/widget/ShadowHelperJbmr2",
+      "android/support/v17/leanback/widget/StaticShadowHelper": "androidx/leanback/widget/StaticShadowHelper",
+      "android/support/v17/leanback/widget/StaggeredGrid$Location": "androidx/leanback/widget/StaggeredGrid$Location",
+      "android/support/v17/leanback/widget/StaggeredGrid": "androidx/leanback/widget/StaggeredGrid",
+      "android/support/v4/util/CircularArray": "androidx/util/CircularArray",
+      "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperJbmr2Impl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperJbmr2Impl",
+      "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperVersionImpl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperVersionImpl",
+      "android/support/v17/leanback/widget/StaticShadowHelper$ShadowHelperStubImpl": "androidx/leanback/widget/StaticShadowHelper$ShadowHelperStubImpl",
+      "android/support/v17/leanback/widget/StreamingTextView$1": "androidx/leanback/widget/StreamingTextView$1",
+      "android/support/v17/leanback/widget/StreamingTextView$DottySpan": "androidx/leanback/widget/StreamingTextView$DottySpan",
+      "android/support/v17/leanback/widget/TitleHelper$1": "androidx/leanback/widget/TitleHelper$1",
+      "android/support/v17/leanback/widget/TitleHelper$2": "androidx/leanback/widget/TitleHelper$2",
+      "android/support/v17/leanback/widget/TitleHelper$3": "androidx/leanback/widget/TitleHelper$3",
+      "android/support/v17/leanback/widget/TitleView$1": "androidx/leanback/widget/TitleView$1",
+      "android/support/v17/leanback/widget/TitleView": "androidx/leanback/widget/TitleView",
+      "android/support/v17/leanback/widget/VerticalGridPresenter$1": "androidx/leanback/widget/VerticalGridPresenter$1",
+      "android/support/v17/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter$1": "androidx/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter$1",
+      "android/support/v17/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter": "androidx/leanback/widget/VerticalGridPresenter$VerticalGridItemBridgeAdapter",
+      "android/support/v17/leanback/widget/VideoSurfaceView": "androidx/leanback/widget/VideoSurfaceView",
+      "android/support/v4/util/LruCache": "androidx/util/LruCache",
+      "android/support/v17/leanback/widget/Visibility": "androidx/leanback/widget/Visibility",
+      "android/support/v17/leanback/widget/picker/DatePicker$1": "androidx/leanback/widget/picker/DatePicker$1",
+      "android/support/v17/leanback/widget/picker/Picker": "androidx/leanback/widget/picker/Picker",
+      "android/support/v17/leanback/widget/picker/PickerUtility$DateConstant": "androidx/leanback/widget/picker/PickerUtility$DateConstant",
+      "android/support/v17/leanback/widget/picker/PickerUtility": "androidx/leanback/widget/picker/PickerUtility",
+      "android/support/v17/leanback/widget/picker/PickerColumn": "androidx/leanback/widget/picker/PickerColumn",
+      "android/support/v17/leanback/widget/picker/Picker$1": "androidx/leanback/widget/picker/Picker$1",
+      "android/support/v17/leanback/widget/picker/Picker$PickerScrollArrayAdapter": "androidx/leanback/widget/picker/Picker$PickerScrollArrayAdapter",
+      "android/support/v17/leanback/widget/picker/Picker$ViewHolder": "androidx/leanback/widget/picker/Picker$ViewHolder",
+      "android/support/v17/leanback/widget/picker/Picker$PickerValueListener": "androidx/leanback/widget/picker/Picker$PickerValueListener",
+      "android/support/v17/leanback/widget/picker/PickerUtility$1": "androidx/leanback/widget/picker/PickerUtility$1",
+      "android/support/v17/leanback/widget/picker/PickerUtility$TimeConstant": "androidx/leanback/widget/picker/PickerUtility$TimeConstant",
+      "android/support/v17/leanback/widget/picker/TimePicker": "androidx/leanback/widget/picker/TimePicker",
+      "android/support/annotation/IntRange": "androidx/annotation/IntRange",
+      "android/support/graphics/drawable/Animatable2Compat$AnimationCallback$1": "androidx/graphics/drawable/Animatable2Compat$AnimationCallback$1",
+      "android/support/graphics/drawable/Animatable2Compat$AnimationCallback": "androidx/graphics/drawable/Animatable2Compat$AnimationCallback",
+      "android/support/graphics/drawable/Animatable2Compat": "androidx/graphics/drawable/Animatable2Compat",
+      "android/support/graphics/drawable/AnimatedVectorDrawableCompat$1": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$1",
+      "android/support/graphics/drawable/AnimatedVectorDrawableCompat": "androidx/graphics/drawable/AnimatedVectorDrawableCompat",
+      "android/support/graphics/drawable/AnimatedVectorDrawableCompat$2": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$2",
+      "android/support/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableCompatState": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableCompatState",
+      "android/support/graphics/drawable/VectorDrawableCompat": "androidx/graphics/drawable/VectorDrawableCompat",
+      "android/support/v4/util/ArrayMap": "androidx/util/ArrayMap",
+      "android/support/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableDelegateState": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableDelegateState",
+      "android/support/graphics/drawable/VectorDrawableCommon": "androidx/graphics/drawable/VectorDrawableCommon",
+      "android/support/v4/content/res/ResourcesCompat": "androidx/content/res/ResourcesCompat",
+      "android/support/graphics/drawable/AndroidResources": "androidx/graphics/drawable/AndroidResources",
+      "android/support/v4/content/res/TypedArrayUtils": "androidx/content/res/TypedArrayUtils",
+      "android/support/graphics/drawable/AnimatorInflaterCompat": "androidx/graphics/drawable/AnimatorInflaterCompat",
+      "android/support/graphics/drawable/AnimationUtilsCompat": "androidx/graphics/drawable/AnimationUtilsCompat",
+      "android/support/v4/view/animation/FastOutSlowInInterpolator": "androidx/view/animation/FastOutSlowInInterpolator",
+      "android/support/v4/view/animation/LinearOutSlowInInterpolator": "androidx/view/animation/LinearOutSlowInInterpolator",
+      "android/support/graphics/drawable/PathInterpolatorCompat": "androidx/graphics/drawable/PathInterpolatorCompat",
+      "android/support/graphics/drawable/AnimatorInflaterCompat$1": "androidx/graphics/drawable/AnimatorInflaterCompat$1",
+      "android/support/graphics/drawable/AnimatorInflaterCompat$PathDataEvaluator": "androidx/graphics/drawable/AnimatorInflaterCompat$PathDataEvaluator",
+      "android/support/v4/graphics/PathParser$PathDataNode": "androidx/graphics/PathParser$PathDataNode",
+      "android/support/v4/graphics/PathParser": "androidx/graphics/PathParser",
+      "android/support/annotation/AnimatorRes": "androidx/annotation/AnimatorRes",
+      "android/support/graphics/drawable/ArgbEvaluator": "androidx/graphics/drawable/ArgbEvaluator",
+      "android/support/v14/preference/EditTextPreferenceDialogFragment": "androidx/preference/EditTextPreferenceDialogFragment",
+      "android/support/v14/preference/PreferenceDialogFragment": "androidx/preference/PreferenceDialogFragment",
+      "android/support/v7/preference/EditTextPreference": "androidx/preference/EditTextPreference",
+      "android/support/v7/preference/DialogPreference": "androidx/preference/DialogPreference",
+      "android/support/v14/preference/ListPreferenceDialogFragment$1": "androidx/preference/ListPreferenceDialogFragment$1",
+      "android/support/v14/preference/ListPreferenceDialogFragment": "androidx/preference/ListPreferenceDialogFragment",
+      "android/support/v7/preference/ListPreference": "androidx/preference/ListPreference",
+      "android/support/v14/preference/MultiSelectListPreference$SavedState$1": "androidx/preference/MultiSelectListPreference$SavedState$1",
+      "android/support/v14/preference/MultiSelectListPreference$SavedState": "androidx/preference/MultiSelectListPreference$SavedState",
+      "android/support/v14/preference/MultiSelectListPreference": "androidx/preference/MultiSelectListPreference",
+      "android/support/v7/preference/Preference$BaseSavedState": "androidx/preference/Preference$BaseSavedState",
+      "android/support/v7/preference/Preference": "androidx/preference/Preference",
+      "android/support/v7/preference/internal/AbstractMultiSelectListPreference": "androidx/preference/internal/AbstractMultiSelectListPreference",
+      "android/support/v7/preference/R$styleable": "androidx/preference/R$styleable",
+      "android/support/v7/preference/R": "androidx/preference/R",
+      "android/support/v7/preference/R$attr": "androidx/preference/R$attr",
+      "android/support/annotation/ArrayRes": "androidx/annotation/ArrayRes",
+      "android/support/v14/preference/MultiSelectListPreferenceDialogFragment$1": "androidx/preference/MultiSelectListPreferenceDialogFragment$1",
+      "android/support/v14/preference/MultiSelectListPreferenceDialogFragment": "androidx/preference/MultiSelectListPreferenceDialogFragment",
+      "android/support/v7/preference/DialogPreference$TargetFragment": "androidx/preference/DialogPreference$TargetFragment",
+      "android/support/annotation/LayoutRes": "androidx/annotation/LayoutRes",
+      "android/support/v14/preference/PreferenceFragment$1": "androidx/preference/PreferenceFragment$1",
+      "android/support/v14/preference/PreferenceFragment": "androidx/preference/PreferenceFragment",
+      "android/support/v14/preference/PreferenceFragment$2": "androidx/preference/PreferenceFragment$2",
+      "android/support/v14/preference/PreferenceFragment$3": "androidx/preference/PreferenceFragment$3",
+      "android/support/v7/preference/PreferenceGroup$PreferencePositionCallback": "androidx/preference/PreferenceGroup$PreferencePositionCallback",
+      "android/support/v7/preference/PreferenceGroup": "androidx/preference/PreferenceGroup",
+      "android/support/v14/preference/PreferenceFragment$ScrollToPreferenceObserver": "androidx/preference/PreferenceFragment$ScrollToPreferenceObserver",
+      "android/support/v14/preference/PreferenceFragment$DividerDecoration": "androidx/preference/PreferenceFragment$DividerDecoration",
+      "android/support/v7/widget/RecyclerView$ItemDecoration": "androidx/widget/recyclerview/RecyclerView$ItemDecoration",
+      "android/support/v7/preference/PreferenceViewHolder": "androidx/preference/PreferenceViewHolder",
+      "android/support/v14/preference/PreferenceFragment$OnPreferenceDisplayDialogCallback": "androidx/preference/PreferenceFragment$OnPreferenceDisplayDialogCallback",
+      "android/support/v14/preference/PreferenceFragment$OnPreferenceStartFragmentCallback": "androidx/preference/PreferenceFragment$OnPreferenceStartFragmentCallback",
+      "android/support/v14/preference/PreferenceFragment$OnPreferenceStartScreenCallback": "androidx/preference/PreferenceFragment$OnPreferenceStartScreenCallback",
+      "android/support/v7/preference/PreferenceScreen": "androidx/preference/PreferenceScreen",
+      "android/support/v7/preference/PreferenceManager$OnPreferenceTreeClickListener": "androidx/preference/PreferenceManager$OnPreferenceTreeClickListener",
+      "android/support/v7/preference/PreferenceManager$OnDisplayPreferenceDialogListener": "androidx/preference/PreferenceManager$OnDisplayPreferenceDialogListener",
+      "android/support/v7/preference/PreferenceManager$OnNavigateToScreenListener": "androidx/preference/PreferenceManager$OnNavigateToScreenListener",
+      "android/support/v7/preference/PreferenceManager": "androidx/preference/PreferenceManager",
+      "android/support/v7/preference/R$layout": "androidx/preference/R$layout",
+      "android/support/annotation/XmlRes": "androidx/annotation/XmlRes",
+      "android/support/v7/preference/PreferenceRecyclerViewAccessibilityDelegate": "androidx/preference/PreferenceRecyclerViewAccessibilityDelegate",
+      "android/support/v7/widget/RecyclerViewAccessibilityDelegate": "androidx/widget/recyclerview/RecyclerViewAccessibilityDelegate",
+      "android/support/v7/widget/LinearLayoutManager": "androidx/widget/recyclerview/LinearLayoutManager",
+      "android/support/v7/preference/PreferenceGroupAdapter": "androidx/preference/PreferenceGroupAdapter",
+      "android/support/v14/preference/SwitchPreference$1": "androidx/preference/SwitchPreference$1",
+      "android/support/v14/preference/SwitchPreference": "androidx/preference/SwitchPreference",
+      "android/support/v14/preference/SwitchPreference$Listener": "androidx/preference/SwitchPreference$Listener",
+      "android/support/v7/preference/TwoStatePreference": "androidx/preference/TwoStatePreference",
+      "android/support/v7/internal/widget/PreferenceImageView": "androidx/preference/internal/PreferenceImageView",
+      "android/support/v7/preference/AndroidResources": "androidx/preference/AndroidResources",
+      "android/support/v7/preference/CheckBoxPreference$1": "androidx/preference/CheckBoxPreference$1",
+      "android/support/v7/preference/CheckBoxPreference": "androidx/preference/CheckBoxPreference",
+      "android/support/v7/preference/CheckBoxPreference$Listener": "androidx/preference/CheckBoxPreference$Listener",
+      "android/support/v7/preference/CollapsiblePreferenceGroupController$1": "androidx/preference/CollapsiblePreferenceGroupController$1",
+      "android/support/v7/preference/Preference$OnPreferenceClickListener": "androidx/preference/Preference$OnPreferenceClickListener",
+      "android/support/v7/preference/CollapsiblePreferenceGroupController": "androidx/preference/CollapsiblePreferenceGroupController",
+      "android/support/v7/preference/CollapsiblePreferenceGroupController$ExpandButton": "androidx/preference/CollapsiblePreferenceGroupController$ExpandButton",
+      "android/support/v7/preference/R$drawable": "androidx/preference/R$drawable",
+      "android/support/v7/preference/R$string": "androidx/preference/R$string",
+      "android/support/v7/preference/CollapsiblePreferenceGroupController$SavedState$1": "androidx/preference/CollapsiblePreferenceGroupController$SavedState$1",
+      "android/support/v7/preference/CollapsiblePreferenceGroupController$SavedState": "androidx/preference/CollapsiblePreferenceGroupController$SavedState",
+      "android/support/v7/preference/PreferenceGroup$PreferenceInstanceStateCallback": "androidx/preference/PreferenceGroup$PreferenceInstanceStateCallback",
+      "android/support/v7/preference/DropDownPreference$1": "androidx/preference/DropDownPreference$1",
+      "android/support/v7/preference/DropDownPreference": "androidx/preference/DropDownPreference",
+      "android/support/v7/preference/R$id": "androidx/preference/R$id",
+      "android/support/v7/preference/EditTextPreference$SavedState$1": "androidx/preference/EditTextPreference$SavedState$1",
+      "android/support/v7/preference/EditTextPreference$SavedState": "androidx/preference/EditTextPreference$SavedState",
+      "android/support/v7/preference/EditTextPreferenceDialogFragmentCompat": "androidx/preference/EditTextPreferenceDialogFragmentCompat",
+      "android/support/v7/preference/PreferenceDialogFragmentCompat": "androidx/preference/PreferenceDialogFragmentCompat",
+      "android/support/v7/preference/ListPreference$SavedState$1": "androidx/preference/ListPreference$SavedState$1",
+      "android/support/v7/preference/ListPreference$SavedState": "androidx/preference/ListPreference$SavedState",
+      "android/support/v7/preference/ListPreferenceDialogFragmentCompat$1": "androidx/preference/ListPreferenceDialogFragmentCompat$1",
+      "android/support/v7/preference/ListPreferenceDialogFragmentCompat": "androidx/preference/ListPreferenceDialogFragmentCompat",
+      "android/support/v7/app/AlertDialog$Builder": "androidx/app/AlertDialog$Builder",
+      "android/support/v7/app/AlertDialog": "androidx/app/AlertDialog",
+      "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat$1": "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat$1",
+      "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat": "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat",
+      "android/support/v7/preference/Preference$1": "androidx/preference/Preference$1",
+      "android/support/v7/preference/Preference$BaseSavedState$1": "androidx/preference/Preference$BaseSavedState$1",
+      "android/support/v7/preference/Preference$OnPreferenceChangeInternalListener": "androidx/preference/Preference$OnPreferenceChangeInternalListener",
+      "android/support/v7/preference/Preference$OnPreferenceChangeListener": "androidx/preference/Preference$OnPreferenceChangeListener",
+      "android/support/v7/preference/PreferenceDataStore": "androidx/preference/PreferenceDataStore",
+      "android/support/v7/preference/PreferenceCategory": "androidx/preference/PreferenceCategory",
+      "android/support/v4/app/DialogFragment": "androidx/app/DialogFragment",
+      "android/support/v7/preference/PreferenceFragmentCompat$1": "androidx/preference/PreferenceFragmentCompat$1",
+      "android/support/v7/preference/PreferenceFragmentCompat": "androidx/preference/PreferenceFragmentCompat",
+      "android/support/v7/preference/PreferenceFragmentCompat$2": "androidx/preference/PreferenceFragmentCompat$2",
+      "android/support/v7/preference/PreferenceFragmentCompat$3": "androidx/preference/PreferenceFragmentCompat$3",
+      "android/support/v7/preference/PreferenceFragmentCompat$ScrollToPreferenceObserver": "androidx/preference/PreferenceFragmentCompat$ScrollToPreferenceObserver",
+      "android/support/v7/preference/PreferenceFragmentCompat$DividerDecoration": "androidx/preference/PreferenceFragmentCompat$DividerDecoration",
+      "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceDisplayDialogCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceDisplayDialogCallback",
+      "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceStartFragmentCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceStartFragmentCallback",
+      "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceStartScreenCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceStartScreenCallback",
+      "android/support/v7/preference/PreferenceGroup$1": "androidx/preference/PreferenceGroup$1",
+      "android/support/v4/util/SimpleArrayMap": "androidx/util/SimpleArrayMap",
+      "android/support/v7/preference/PreferenceGroupAdapter$1": "androidx/preference/PreferenceGroupAdapter$1",
+      "android/support/v7/preference/PreferenceGroupAdapter$2": "androidx/preference/PreferenceGroupAdapter$2",
+      "android/support/v7/preference/PreferenceManager$PreferenceComparisonCallback": "androidx/preference/PreferenceManager$PreferenceComparisonCallback",
+      "android/support/v7/preference/PreferenceGroupAdapter$PreferenceLayout": "androidx/preference/PreferenceGroupAdapter$PreferenceLayout",
+      "android/support/v7/preference/PreferenceInflater": "androidx/preference/PreferenceInflater",
+      "android/support/v7/preference/PreferenceManager$SimplePreferenceComparisonCallback": "androidx/preference/PreferenceManager$SimplePreferenceComparisonCallback",
+      "android/support/v7/preference/PreferenceRecyclerViewAccessibilityDelegate$1": "androidx/preference/PreferenceRecyclerViewAccessibilityDelegate$1",
+      "android/support/v4/view/AccessibilityDelegateCompat": "androidx/view/AccessibilityDelegateCompat",
+      "android/support/annotation/IdRes": "androidx/annotation/IdRes",
+      "android/support/v7/preference/SeekBarPreference$1": "androidx/preference/SeekBarPreference$1",
+      "android/support/v7/preference/SeekBarPreference": "androidx/preference/SeekBarPreference",
+      "android/support/v7/preference/SeekBarPreference$2": "androidx/preference/SeekBarPreference$2",
+      "android/support/v7/preference/SeekBarPreference$SavedState$1": "androidx/preference/SeekBarPreference$SavedState$1",
+      "android/support/v7/preference/SeekBarPreference$SavedState": "androidx/preference/SeekBarPreference$SavedState",
+      "android/support/v7/preference/SwitchPreferenceCompat$1": "androidx/preference/SwitchPreferenceCompat$1",
+      "android/support/v7/preference/SwitchPreferenceCompat": "androidx/preference/SwitchPreferenceCompat",
+      "android/support/v7/preference/SwitchPreferenceCompat$Listener": "androidx/preference/SwitchPreferenceCompat$Listener",
+      "android/support/v7/widget/SwitchCompat": "androidx/widget/SwitchCompat",
+      "android/support/v7/preference/TwoStatePreference$SavedState$1": "androidx/preference/TwoStatePreference$SavedState$1",
+      "android/support/v7/preference/TwoStatePreference$SavedState": "androidx/preference/TwoStatePreference$SavedState",
+      "android/support/v7/preference/UnPressableLinearLayout": "androidx/preference/UnPressableLinearLayout",
+      "android/arch/persistence/room/migration/bundle/ForeignKeyBundle": "androidx/persistence/room/migration/bundle/ForeignKeyBundle",
+      "android/arch/persistence/room/migration/bundle/SchemaEquality": "androidx/persistence/room/migration/bundle/SchemaEquality",
+      "android/arch/persistence/room/migration/bundle/SchemaBundle": "androidx/persistence/room/migration/bundle/SchemaBundle",
+      "android/arch/persistence/room/migration/bundle/DatabaseBundle": "androidx/persistence/room/migration/bundle/DatabaseBundle",
+      "android/arch/persistence/room/migration/bundle/SchemaEqualityUtil": "androidx/persistence/room/migration/bundle/SchemaEqualityUtil",
+      "android/arch/persistence/room/migration/bundle/PrimaryKeyBundle": "androidx/persistence/room/migration/bundle/PrimaryKeyBundle",
+      "android/arch/persistence/room/migration/bundle/EntityBundle": "androidx/persistence/room/migration/bundle/EntityBundle",
+      "android/arch/persistence/room/migration/bundle/FieldBundle": "androidx/persistence/room/migration/bundle/FieldBundle",
+      "android/arch/persistence/room/migration/bundle/IndexBundle": "androidx/persistence/room/migration/bundle/IndexBundle",
+      "android/arch/persistence/room/migration/bundle/BundleUtil": "androidx/persistence/room/migration/bundle/BundleUtil",
+      "android/support/design/widget/CoordinatorLayout$1": "androidx/widget/CoordinatorLayout$1",
+      "android/support/v4/view/OnApplyWindowInsetsListener": "androidx/view/OnApplyWindowInsetsListener",
+      "android/support/design/widget/CoordinatorLayout": "androidx/widget/CoordinatorLayout",
+      "android/support/v4/view/WindowInsetsCompat": "androidx/view/WindowInsetsCompat",
+      "android/support/design/widget/CoordinatorLayout$Behavior": "androidx/widget/CoordinatorLayout$Behavior",
+      "android/support/design/widget/CoordinatorLayout$LayoutParams": "androidx/widget/CoordinatorLayout$LayoutParams",
+      "android/support/annotation/FloatRange": "androidx/annotation/FloatRange",
+      "android/support/design/widget/CoordinatorLayout$DefaultBehavior": "androidx/widget/CoordinatorLayout$DefaultBehavior",
+      "android/support/design/widget/CoordinatorLayout$DispatchChangeEvent": "androidx/widget/CoordinatorLayout$DispatchChangeEvent",
+      "android/support/design/widget/CoordinatorLayout$HierarchyChangeListener": "androidx/widget/CoordinatorLayout$HierarchyChangeListener",
+      "android/support/coreui/R$styleable": "androidx/coreui/R$styleable",
+      "android/support/coreui/R": "androidx/coreui/R",
+      "android/support/v4/view/GravityCompat": "androidx/view/GravityCompat",
+      "android/support/design/widget/CoordinatorLayout$OnPreDrawListener": "androidx/widget/CoordinatorLayout$OnPreDrawListener",
+      "android/support/design/widget/CoordinatorLayout$SavedState$1": "androidx/widget/CoordinatorLayout$SavedState$1",
+      "android/support/design/widget/CoordinatorLayout$SavedState": "androidx/widget/CoordinatorLayout$SavedState",
+      "android/support/v4/view/AbsSavedState": "androidx/view/AbsSavedState",
+      "android/support/design/widget/CoordinatorLayout$ViewElevationComparator": "androidx/widget/CoordinatorLayout$ViewElevationComparator",
+      "android/support/v4/view/NestedScrollingParent2": "androidx/view/NestedScrollingParent2",
+      "android/support/v4/util/Pools$Pool": "androidx/util/Pools$Pool",
+      "android/support/v4/util/Pools": "androidx/util/Pools",
+      "android/support/v4/util/Pools$SynchronizedPool": "androidx/util/Pools$SynchronizedPool",
+      "android/support/coreui/R$attr": "androidx/coreui/R$attr",
+      "android/support/coreui/R$style": "androidx/coreui/R$style",
+      "android/support/v4/widget/DirectedAcyclicGraph": "androidx/widget/DirectedAcyclicGraph",
+      "android/support/v4/view/NestedScrollingParentHelper": "androidx/view/NestedScrollingParentHelper",
+      "android/support/v4/util/ObjectsCompat": "androidx/util/ObjectsCompat",
+      "android/support/v4/widget/ViewGroupUtils": "androidx/widget/ViewGroupUtils",
+      "android/support/v4/math/MathUtils": "androidx/math/MathUtils",
+      "android/support/v4/app/ActionBarDrawerToggle$Delegate": "androidx/legacy/app/ActionBarDrawerToggle$Delegate",
+      "android/support/v4/app/ActionBarDrawerToggle": "androidx/legacy/app/ActionBarDrawerToggle",
+      "android/support/v4/app/ActionBarDrawerToggle$DelegateProvider": "androidx/legacy/app/ActionBarDrawerToggle$DelegateProvider",
+      "android/support/v4/app/ActionBarDrawerToggle$SetIndicatorInfo": "androidx/legacy/app/ActionBarDrawerToggle$SetIndicatorInfo",
+      "android/support/v4/app/ActionBarDrawerToggle$SlideDrawable": "androidx/legacy/app/ActionBarDrawerToggle$SlideDrawable",
+      "android/support/v4/widget/DrawerLayout$DrawerListener": "androidx/widget/DrawerLayout$DrawerListener",
+      "android/support/v4/widget/DrawerLayout": "androidx/widget/DrawerLayout",
+      "android/support/v4/view/AbsSavedState$1": "androidx/view/AbsSavedState$1",
+      "android/support/v4/view/AbsSavedState$2": "androidx/view/AbsSavedState$2",
+      "android/support/v4/view/AsyncLayoutInflater$1": "androidx/view/AsyncLayoutInflater$1",
+      "android/support/v4/view/AsyncLayoutInflater": "androidx/view/AsyncLayoutInflater",
+      "android/support/v4/view/AsyncLayoutInflater$InflateRequest": "androidx/view/AsyncLayoutInflater$InflateRequest",
+      "android/support/v4/view/AsyncLayoutInflater$OnInflateFinishedListener": "androidx/view/AsyncLayoutInflater$OnInflateFinishedListener",
+      "android/support/v4/view/AsyncLayoutInflater$InflateThread": "androidx/view/AsyncLayoutInflater$InflateThread",
+      "android/support/v4/view/AsyncLayoutInflater$BasicInflater": "androidx/view/AsyncLayoutInflater$BasicInflater",
+      "android/support/annotation/UiThread": "androidx/annotation/UiThread",
+      "android/support/v4/view/NestedScrollingChildHelper": "androidx/view/NestedScrollingChildHelper",
+      "android/support/v4/view/ViewParentCompat": "androidx/view/ViewParentCompat",
+      "android/support/v4/view/PagerAdapter": "androidx/widget/PagerAdapter",
+      "android/support/v4/view/PagerTabStrip$1": "androidx/widget/PagerTabStrip$1",
+      "android/support/v4/view/PagerTabStrip": "androidx/widget/PagerTabStrip",
+      "android/support/v4/view/ViewPager": "androidx/widget/ViewPager",
+      "android/support/v4/view/PagerTabStrip$2": "androidx/widget/PagerTabStrip$2",
+      "android/support/v4/view/PagerTitleStrip": "androidx/widget/PagerTitleStrip",
+      "android/support/annotation/ColorRes": "androidx/annotation/ColorRes",
+      "android/support/v4/view/PagerTitleStrip$PageListener": "androidx/widget/PagerTitleStrip$PageListener",
+      "android/support/v4/view/ViewPager$OnPageChangeListener": "androidx/widget/ViewPager$OnPageChangeListener",
+      "android/support/v4/view/ViewPager$OnAdapterChangeListener": "androidx/widget/ViewPager$OnAdapterChangeListener",
+      "android/support/v4/view/PagerTitleStrip$SingleLineAllCapsTransform": "androidx/widget/PagerTitleStrip$SingleLineAllCapsTransform",
+      "android/support/v4/view/ViewPager$DecorView": "androidx/widget/ViewPager$DecorView",
+      "android/support/v4/widget/TextViewCompat": "androidx/widget/TextViewCompat",
+      "android/support/v4/view/ViewPager$1": "androidx/widget/ViewPager$1",
+      "android/support/v4/view/ViewPager$ItemInfo": "androidx/widget/ViewPager$ItemInfo",
+      "android/support/v4/view/ViewPager$2": "androidx/widget/ViewPager$2",
+      "android/support/v4/view/ViewPager$3": "androidx/widget/ViewPager$3",
+      "android/support/v4/view/ViewPager$4": "androidx/widget/ViewPager$4",
+      "android/support/v4/view/ViewPager$LayoutParams": "androidx/widget/ViewPager$LayoutParams",
+      "android/support/v4/view/ViewPager$MyAccessibilityDelegate": "androidx/widget/ViewPager$MyAccessibilityDelegate",
+      "android/support/v4/view/ViewPager$PageTransformer": "androidx/widget/ViewPager$PageTransformer",
+      "android/support/v4/view/ViewPager$PagerObserver": "androidx/widget/ViewPager$PagerObserver",
+      "android/support/v4/view/ViewPager$SavedState$1": "androidx/widget/ViewPager$SavedState$1",
+      "android/support/v4/view/ViewPager$SavedState": "androidx/widget/ViewPager$SavedState",
+      "android/support/v4/view/ViewPager$SimpleOnPageChangeListener": "androidx/widget/ViewPager$SimpleOnPageChangeListener",
+      "android/support/v4/view/ViewPager$ViewPositionComparator": "androidx/widget/ViewPager$ViewPositionComparator",
+      "android/support/v4/view/animation/LookupTableInterpolator": "androidx/view/animation/LookupTableInterpolator",
+      "android/support/v4/widget/AutoScrollHelper$ClampedScroller": "androidx/widget/AutoScrollHelper$ClampedScroller",
+      "android/support/v4/widget/AutoScrollHelper": "androidx/widget/AutoScrollHelper",
+      "android/support/v4/widget/AutoScrollHelper$ScrollAnimationRunnable": "androidx/widget/AutoScrollHelper$ScrollAnimationRunnable",
+      "android/support/v4/widget/CircleImageView$OvalShadow": "androidx/widget/CircleImageView$OvalShadow",
+      "android/support/v4/widget/CircleImageView": "androidx/widget/CircleImageView",
+      "android/support/v4/widget/CircularProgressDrawable$1": "androidx/widget/CircularProgressDrawable$1",
+      "android/support/v4/widget/CircularProgressDrawable": "androidx/widget/CircularProgressDrawable",
+      "android/support/v4/widget/CircularProgressDrawable$Ring": "androidx/widget/CircularProgressDrawable$Ring",
+      "android/support/v4/widget/CircularProgressDrawable$2": "androidx/widget/CircularProgressDrawable$2",
+      "android/support/v4/widget/CircularProgressDrawable$ProgressDrawableSize": "androidx/widget/CircularProgressDrawable$ProgressDrawableSize",
+      "android/support/v4/util/Preconditions": "androidx/util/Preconditions",
+      "android/support/v4/widget/ContentLoadingProgressBar$1": "androidx/widget/ContentLoadingProgressBar$1",
+      "android/support/v4/widget/ContentLoadingProgressBar": "androidx/widget/ContentLoadingProgressBar",
+      "android/support/v4/widget/ContentLoadingProgressBar$2": "androidx/widget/ContentLoadingProgressBar$2",
+      "android/support/v4/widget/CursorAdapter$ChangeObserver": "androidx/widget/CursorAdapter$ChangeObserver",
+      "android/support/v4/widget/CursorAdapter": "androidx/widget/CursorAdapter",
+      "android/support/v4/widget/CursorAdapter$MyDataSetObserver": "androidx/widget/CursorAdapter$MyDataSetObserver",
+      "android/support/v4/widget/CursorFilter$CursorFilterClient": "androidx/widget/CursorFilter$CursorFilterClient",
+      "android/support/v4/widget/CursorFilter": "androidx/widget/CursorFilter",
+      "android/support/v4/util/Pools$SimplePool": "androidx/util/Pools$SimplePool",
+      "android/support/v4/widget/DrawerLayout$1": "androidx/widget/DrawerLayout$1",
+      "android/support/v4/widget/DrawerLayout$AccessibilityDelegate": "androidx/widget/DrawerLayout$AccessibilityDelegate",
+      "android/support/v4/widget/DrawerLayout$ChildAccessibilityDelegate": "androidx/widget/DrawerLayout$ChildAccessibilityDelegate",
+      "android/support/v4/widget/DrawerLayout$EdgeGravity": "androidx/widget/DrawerLayout$EdgeGravity",
+      "android/support/v4/widget/DrawerLayout$LayoutParams": "androidx/widget/DrawerLayout$LayoutParams",
+      "android/support/v4/widget/DrawerLayout$LockMode": "androidx/widget/DrawerLayout$LockMode",
+      "android/support/v4/widget/DrawerLayout$SavedState$1": "androidx/widget/DrawerLayout$SavedState$1",
+      "android/support/v4/widget/DrawerLayout$SavedState": "androidx/widget/DrawerLayout$SavedState",
+      "android/support/v4/widget/DrawerLayout$SimpleDrawerListener": "androidx/widget/DrawerLayout$SimpleDrawerListener",
+      "android/support/v4/widget/DrawerLayout$State": "androidx/widget/DrawerLayout$State",
+      "android/support/v4/widget/DrawerLayout$ViewDragCallback$1": "androidx/widget/DrawerLayout$ViewDragCallback$1",
+      "android/support/v4/widget/DrawerLayout$ViewDragCallback": "androidx/widget/DrawerLayout$ViewDragCallback",
+      "android/support/v4/widget/ViewDragHelper$Callback": "androidx/widget/ViewDragHelper$Callback",
+      "android/support/v4/widget/ViewDragHelper": "androidx/widget/ViewDragHelper",
+      "android/support/v4/widget/ExploreByTouchHelper$1": "androidx/widget/ExploreByTouchHelper$1",
+      "android/support/v4/widget/FocusStrategy$BoundsAdapter": "androidx/widget/FocusStrategy$BoundsAdapter",
+      "android/support/v4/widget/ExploreByTouchHelper": "androidx/widget/ExploreByTouchHelper",
+      "android/support/v4/widget/FocusStrategy": "androidx/widget/FocusStrategy",
+      "android/support/v4/widget/ExploreByTouchHelper$2": "androidx/widget/ExploreByTouchHelper$2",
+      "android/support/v4/widget/FocusStrategy$CollectionAdapter": "androidx/widget/FocusStrategy$CollectionAdapter",
+      "android/support/v4/util/SparseArrayCompat": "androidx/util/SparseArrayCompat",
+      "android/support/v4/widget/ExploreByTouchHelper$MyNodeProvider": "androidx/widget/ExploreByTouchHelper$MyNodeProvider",
+      "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat": "androidx/view/accessibility/AccessibilityNodeProviderCompat",
+      "android/support/v4/view/accessibility/AccessibilityEventCompat": "androidx/view/accessibility/AccessibilityEventCompat",
+      "android/support/v4/view/accessibility/AccessibilityRecordCompat": "androidx/view/accessibility/AccessibilityRecordCompat",
+      "android/support/v4/widget/FocusStrategy$SequentialComparator": "androidx/widget/FocusStrategy$SequentialComparator",
+      "android/support/v4/widget/ListViewAutoScrollHelper": "androidx/widget/ListViewAutoScrollHelper",
+      "android/support/v4/widget/ListViewCompat": "androidx/widget/ListViewCompat",
+      "android/support/v4/widget/NestedScrollView$AccessibilityDelegate": "androidx/widget/NestedScrollView$AccessibilityDelegate",
+      "android/support/v4/widget/NestedScrollView": "androidx/widget/NestedScrollView",
+      "android/support/v4/widget/NestedScrollView$OnScrollChangeListener": "androidx/widget/NestedScrollView$OnScrollChangeListener",
+      "android/support/v4/widget/NestedScrollView$SavedState$1": "androidx/widget/NestedScrollView$SavedState$1",
+      "android/support/v4/widget/NestedScrollView$SavedState": "androidx/widget/NestedScrollView$SavedState",
+      "android/support/v4/view/NestedScrollingParent": "androidx/view/NestedScrollingParent",
+      "android/support/v4/view/NestedScrollingChild2": "androidx/view/NestedScrollingChild2",
+      "android/support/v4/view/ScrollingView": "androidx/view/ScrollingView",
+      "android/support/v4/widget/EdgeEffectCompat": "androidx/widget/EdgeEffectCompat",
+      "android/support/v4/widget/ResourceCursorAdapter": "androidx/widget/ResourceCursorAdapter",
+      "android/support/v4/widget/SimpleCursorAdapter$CursorToStringConverter": "androidx/widget/SimpleCursorAdapter$CursorToStringConverter",
+      "android/support/v4/widget/SimpleCursorAdapter": "androidx/widget/SimpleCursorAdapter",
+      "android/support/v4/widget/SimpleCursorAdapter$ViewBinder": "androidx/widget/SimpleCursorAdapter$ViewBinder",
+      "android/support/v4/widget/SlidingPaneLayout$AccessibilityDelegate": "androidx/widget/SlidingPaneLayout$AccessibilityDelegate",
+      "android/support/v4/widget/SlidingPaneLayout": "androidx/widget/SlidingPaneLayout",
+      "android/support/v4/widget/SlidingPaneLayout$DisableLayerRunnable": "androidx/widget/SlidingPaneLayout$DisableLayerRunnable",
+      "android/support/v4/widget/SlidingPaneLayout$DragHelperCallback": "androidx/widget/SlidingPaneLayout$DragHelperCallback",
+      "android/support/v4/widget/SlidingPaneLayout$LayoutParams": "androidx/widget/SlidingPaneLayout$LayoutParams",
+      "android/support/v4/widget/SlidingPaneLayout$PanelSlideListener": "androidx/widget/SlidingPaneLayout$PanelSlideListener",
+      "android/support/v4/widget/SlidingPaneLayout$SavedState$1": "androidx/widget/SlidingPaneLayout$SavedState$1",
+      "android/support/v4/widget/SlidingPaneLayout$SavedState": "androidx/widget/SlidingPaneLayout$SavedState",
+      "android/support/v4/widget/SlidingPaneLayout$SimplePanelSlideListener": "androidx/widget/SlidingPaneLayout$SimplePanelSlideListener",
+      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImpl": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImpl",
+      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplBase": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplBase",
+      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplJB": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplJB",
+      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplJBMR1": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplJBMR1",
+      "android/support/v4/widget/Space": "androidx/widget/Space",
+      "android/support/v4/widget/SwipeProgressBar": "androidx/widget/SwipeProgressBar",
+      "android/support/v4/widget/SwipeRefreshLayout$1": "androidx/widget/SwipeRefreshLayout$1",
+      "android/support/v4/widget/SwipeRefreshLayout": "androidx/widget/SwipeRefreshLayout",
+      "android/support/v4/widget/SwipeRefreshLayout$OnRefreshListener": "androidx/widget/SwipeRefreshLayout$OnRefreshListener",
+      "android/support/v4/widget/SwipeRefreshLayout$2": "androidx/widget/SwipeRefreshLayout$2",
+      "android/support/v4/widget/SwipeRefreshLayout$3": "androidx/widget/SwipeRefreshLayout$3",
+      "android/support/v4/widget/SwipeRefreshLayout$4": "androidx/widget/SwipeRefreshLayout$4",
+      "android/support/v4/widget/SwipeRefreshLayout$5": "androidx/widget/SwipeRefreshLayout$5",
+      "android/support/v4/widget/SwipeRefreshLayout$6": "androidx/widget/SwipeRefreshLayout$6",
+      "android/support/v4/widget/SwipeRefreshLayout$7": "androidx/widget/SwipeRefreshLayout$7",
+      "android/support/v4/widget/SwipeRefreshLayout$8": "androidx/widget/SwipeRefreshLayout$8",
+      "android/support/v4/widget/SwipeRefreshLayout$OnChildScrollUpCallback": "androidx/widget/SwipeRefreshLayout$OnChildScrollUpCallback",
+      "android/support/v4/view/NestedScrollingChild": "androidx/view/NestedScrollingChild",
+      "android/support/v4/widget/ViewDragHelper$1": "androidx/widget/ViewDragHelper$1",
+      "android/support/v4/widget/ViewDragHelper$2": "androidx/widget/ViewDragHelper$2",
+      "android/support/annotation/StyleableRes": "androidx/annotation/StyleableRes",
+      "android/support/v4/graphics/drawable/TintAwareDrawable": "androidx/graphics/drawable/TintAwareDrawable",
+      "android/support/graphics/drawable/VectorDrawableCompat$VClipPath": "androidx/graphics/drawable/VectorDrawableCompat$VClipPath",
+      "android/support/graphics/drawable/VectorDrawableCompat$VPath": "androidx/graphics/drawable/VectorDrawableCompat$VPath",
+      "android/support/graphics/drawable/VectorDrawableCompat$VFullPath": "androidx/graphics/drawable/VectorDrawableCompat$VFullPath",
+      "android/support/graphics/drawable/VectorDrawableCompat$VGroup": "androidx/graphics/drawable/VectorDrawableCompat$VGroup",
+      "android/support/graphics/drawable/VectorDrawableCompat$VPathRenderer": "androidx/graphics/drawable/VectorDrawableCompat$VPathRenderer",
+      "android/support/graphics/drawable/VectorDrawableCompat$VectorDrawableCompatState": "androidx/graphics/drawable/VectorDrawableCompat$VectorDrawableCompatState",
+      "android/support/graphics/drawable/VectorDrawableCompat$VectorDrawableDelegateState": "androidx/graphics/drawable/VectorDrawableCompat$VectorDrawableDelegateState",
+      "android/support/v7/app/ActionBar$DisplayOptions": "androidx/app/ActionBar$DisplayOptions",
+      "android/support/v7/app/ActionBar": "androidx/app/ActionBar",
+      "android/support/v7/app/ActionBar$LayoutParams": "androidx/app/ActionBar$LayoutParams",
+      "android/support/v7/appcompat/R$styleable": "androidx/appcompat/R$styleable",
+      "android/support/v7/appcompat/R": "androidx/appcompat/R",
+      "android/support/v7/app/ActionBar$NavigationMode": "androidx/app/ActionBar$NavigationMode",
+      "android/support/v7/app/ActionBar$OnMenuVisibilityListener": "androidx/app/ActionBar$OnMenuVisibilityListener",
+      "android/support/v7/app/ActionBar$OnNavigationListener": "androidx/app/ActionBar$OnNavigationListener",
+      "android/support/v7/app/ActionBar$Tab": "androidx/app/ActionBar$Tab",
+      "android/support/v7/app/ActionBar$TabListener": "androidx/app/ActionBar$TabListener",
+      "android/support/v7/view/ActionMode$Callback": "androidx/view/ActionMode$Callback",
+      "android/support/v7/view/ActionMode": "androidx/view/ActionMode",
+      "android/support/v7/app/ActionBarDrawerToggle$1": "androidx/app/ActionBarDrawerToggle$1",
+      "android/support/v7/app/ActionBarDrawerToggle": "androidx/app/ActionBarDrawerToggle",
+      "android/support/v7/widget/Toolbar": "androidx/widget/Toolbar",
+      "android/support/v7/graphics/drawable/DrawerArrowDrawable": "androidx/graphics/drawable/DrawerArrowDrawable",
+      "android/support/v7/app/ActionBarDrawerToggle$Delegate": "androidx/app/ActionBarDrawerToggle$Delegate",
+      "android/support/v7/app/ActionBarDrawerToggle$DelegateProvider": "androidx/app/ActionBarDrawerToggle$DelegateProvider",
+      "android/support/v7/app/ActionBarDrawerToggle$IcsDelegate": "androidx/app/ActionBarDrawerToggle$IcsDelegate",
+      "android/support/v7/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo": "androidx/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo",
+      "android/support/v7/app/ActionBarDrawerToggleHoneycomb": "androidx/app/ActionBarDrawerToggleHoneycomb",
+      "android/support/v7/app/ActionBarDrawerToggle$JellybeanMr2Delegate": "androidx/app/ActionBarDrawerToggle$JellybeanMr2Delegate",
+      "android/support/v7/app/ActionBarDrawerToggle$ToolbarCompatDelegate": "androidx/app/ActionBarDrawerToggle$ToolbarCompatDelegate",
+      "android/support/v7/app/AlertController$1": "androidx/app/AlertController$1",
+      "android/support/v7/app/AlertController": "androidx/app/AlertController",
+      "android/support/v7/app/AlertController$ButtonHandler": "androidx/app/AlertController$ButtonHandler",
+      "android/support/v7/app/AppCompatDialog": "androidx/app/AppCompatDialog",
+      "android/support/v7/app/AlertController$2": "androidx/app/AlertController$2",
+      "android/support/v7/app/AlertController$3": "androidx/app/AlertController$3",
+      "android/support/v7/app/AlertController$4": "androidx/app/AlertController$4",
+      "android/support/v7/app/AlertController$5": "androidx/app/AlertController$5",
+      "android/support/v7/app/AlertController$AlertParams$1": "androidx/app/AlertController$AlertParams$1",
+      "android/support/v7/app/AlertController$AlertParams": "androidx/app/AlertController$AlertParams",
+      "android/support/v7/app/AlertController$RecycleListView": "androidx/app/AlertController$RecycleListView",
+      "android/support/v7/app/AlertController$AlertParams$2": "androidx/app/AlertController$AlertParams$2",
+      "android/support/v7/app/AlertController$AlertParams$3": "androidx/app/AlertController$AlertParams$3",
+      "android/support/v7/app/AlertController$AlertParams$4": "androidx/app/AlertController$AlertParams$4",
+      "android/support/v7/app/AlertController$AlertParams$OnPrepareListViewListener": "androidx/app/AlertController$AlertParams$OnPrepareListViewListener",
+      "android/support/v7/app/AlertController$CheckedItemAdapter": "androidx/app/AlertController$CheckedItemAdapter",
+      "android/support/v7/widget/LinearLayoutCompat$LayoutParams": "androidx/widget/LinearLayoutCompat$LayoutParams",
+      "android/support/v7/widget/LinearLayoutCompat": "androidx/widget/LinearLayoutCompat",
+      "android/support/v7/appcompat/R$attr": "androidx/appcompat/R$attr",
+      "android/support/v7/appcompat/R$id": "androidx/appcompat/R$id",
+      "android/support/annotation/StyleRes": "androidx/annotation/StyleRes",
+      "android/support/annotation/AttrRes": "androidx/annotation/AttrRes",
+      "android/support/v7/app/AppCompatActivity": "androidx/app/AppCompatActivity",
+      "android/support/v7/app/AppCompatCallback": "androidx/app/AppCompatCallback",
+      "android/support/v4/app/TaskStackBuilder$SupportParentable": "androidx/app/TaskStackBuilder$SupportParentable",
+      "android/support/v4/app/TaskStackBuilder": "androidx/app/TaskStackBuilder",
+      "android/support/v7/app/AppCompatDelegate": "androidx/app/AppCompatDelegate",
+      "android/support/v4/app/NavUtils": "androidx/app/NavUtils",
+      "android/support/v7/widget/VectorEnabledTintResources": "androidx/widget/VectorEnabledTintResources",
+      "android/support/v7/app/AppCompatDelegate$ApplyableNightMode": "androidx/app/AppCompatDelegate$ApplyableNightMode",
+      "android/support/v7/app/AppCompatDelegate$NightMode": "androidx/app/AppCompatDelegate$NightMode",
+      "android/support/v7/app/AppCompatDelegateImplN": "androidx/app/AppCompatDelegateImplN",
+      "android/support/v7/app/AppCompatDelegateImplV23": "androidx/app/AppCompatDelegateImplV23",
+      "android/support/v7/app/AppCompatDelegateImplV14": "androidx/app/AppCompatDelegateImplV14",
+      "android/support/v7/app/AppCompatDelegateImplV11": "androidx/app/AppCompatDelegateImplV11",
+      "android/support/v7/app/AppCompatDelegateImplV9": "androidx/app/AppCompatDelegateImplV9",
+      "android/support/v7/app/AppCompatDelegateImplBase$1": "androidx/app/AppCompatDelegateImplBase$1",
+      "android/support/v7/app/AppCompatDelegateImplBase": "androidx/app/AppCompatDelegateImplBase",
+      "android/support/v7/app/AppCompatDelegateImplBase$ActionBarDrawableToggleImpl": "androidx/app/AppCompatDelegateImplBase$ActionBarDrawableToggleImpl",
+      "android/support/v7/widget/TintTypedArray": "androidx/widget/TintTypedArray",
+      "android/support/v7/app/AppCompatDelegateImplBase$AppCompatWindowCallbackBase": "androidx/app/AppCompatDelegateImplBase$AppCompatWindowCallbackBase",
+      "android/support/v7/view/WindowCallbackWrapper": "androidx/view/WindowCallbackWrapper",
+      "android/support/v7/view/menu/MenuBuilder": "androidx/view/menu/MenuBuilder",
+      "android/support/v7/view/SupportMenuInflater": "androidx/view/SupportMenuInflater",
+      "android/support/v7/app/AppCompatDelegateImplN$AppCompatWindowCallbackN": "androidx/app/AppCompatDelegateImplN$AppCompatWindowCallbackN",
+      "android/support/v7/app/AppCompatDelegateImplV23$AppCompatWindowCallbackV23": "androidx/app/AppCompatDelegateImplV23$AppCompatWindowCallbackV23",
+      "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState": "androidx/app/AppCompatDelegateImplV9$PanelFeatureState",
+      "android/support/v7/app/AppCompatDelegateImplV14$AppCompatWindowCallbackV14": "androidx/app/AppCompatDelegateImplV14$AppCompatWindowCallbackV14",
+      "android/support/v7/view/SupportActionModeWrapper$CallbackWrapper": "androidx/view/SupportActionModeWrapper$CallbackWrapper",
+      "android/support/v7/view/SupportActionModeWrapper": "androidx/view/SupportActionModeWrapper",
+      "android/support/v7/app/AppCompatDelegateImplV14$AutoNightModeManager$1": "androidx/app/AppCompatDelegateImplV14$AutoNightModeManager$1",
+      "android/support/v7/app/AppCompatDelegateImplV14$AutoNightModeManager": "androidx/app/AppCompatDelegateImplV14$AutoNightModeManager",
+      "android/support/v7/app/TwilightManager": "androidx/app/TwilightManager",
+      "android/support/v7/app/ResourcesFlusher": "androidx/app/ResourcesFlusher",
+      "android/support/v7/app/AppCompatDelegateImplV9$1": "androidx/app/AppCompatDelegateImplV9$1",
+      "android/support/v7/app/AppCompatDelegateImplV9$2": "androidx/app/AppCompatDelegateImplV9$2",
+      "android/support/v7/app/AppCompatDelegateImplV9$3": "androidx/app/AppCompatDelegateImplV9$3",
+      "android/support/v7/widget/FitWindowsViewGroup$OnFitSystemWindowsListener": "androidx/widget/FitWindowsViewGroup$OnFitSystemWindowsListener",
+      "android/support/v7/widget/FitWindowsViewGroup": "androidx/widget/FitWindowsViewGroup",
+      "android/support/v7/app/AppCompatDelegateImplV9$4": "androidx/app/AppCompatDelegateImplV9$4",
+      "android/support/v7/widget/ContentFrameLayout$OnAttachListener": "androidx/widget/ContentFrameLayout$OnAttachListener",
+      "android/support/v7/widget/ContentFrameLayout": "androidx/widget/ContentFrameLayout",
+      "android/support/v7/app/AppCompatDelegateImplV9$5$1": "androidx/app/AppCompatDelegateImplV9$5$1",
+      "android/support/v4/view/ViewPropertyAnimatorListenerAdapter": "androidx/view/ViewPropertyAnimatorListenerAdapter",
+      "android/support/v7/app/AppCompatDelegateImplV9$5": "androidx/app/AppCompatDelegateImplV9$5",
+      "android/support/v7/widget/ActionBarContextView": "androidx/widget/ActionBarContextView",
+      "android/support/v4/view/ViewPropertyAnimatorCompat": "androidx/view/ViewPropertyAnimatorCompat",
+      "android/support/v4/view/ViewPropertyAnimatorListener": "androidx/view/ViewPropertyAnimatorListener",
+      "android/support/v7/app/AppCompatDelegateImplV9$6": "androidx/app/AppCompatDelegateImplV9$6",
+      "android/support/v7/app/AppCompatDelegateImplV9$ActionMenuPresenterCallback": "androidx/app/AppCompatDelegateImplV9$ActionMenuPresenterCallback",
+      "android/support/v7/view/menu/MenuPresenter$Callback": "androidx/view/menu/MenuPresenter$Callback",
+      "android/support/v7/view/menu/MenuPresenter": "androidx/view/menu/MenuPresenter",
+      "android/support/v7/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9$1": "androidx/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9$1",
+      "android/support/v7/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9": "androidx/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9",
+      "android/support/v7/app/AppCompatDelegateImplV9$ListMenuDecorView": "androidx/app/AppCompatDelegateImplV9$ListMenuDecorView",
+      "android/support/v7/content/res/AppCompatResources": "androidx/content/res/AppCompatResources",
+      "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState$1": "androidx/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState$1",
+      "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState": "androidx/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState",
+      "android/support/v7/appcompat/R$style": "androidx/appcompat/R$style",
+      "android/support/v7/appcompat/R$layout": "androidx/appcompat/R$layout",
+      "android/support/v7/view/menu/ListMenuPresenter": "androidx/view/menu/ListMenuPresenter",
+      "android/support/v7/view/ContextThemeWrapper": "androidx/view/ContextThemeWrapper",
+      "android/support/v7/view/menu/MenuView": "androidx/view/menu/MenuView",
+      "android/support/v7/app/AppCompatDelegateImplV9$PanelMenuPresenterCallback": "androidx/app/AppCompatDelegateImplV9$PanelMenuPresenterCallback",
+      "android/support/v7/view/menu/MenuBuilder$Callback": "androidx/view/menu/MenuBuilder$Callback",
+      "android/support/v7/appcompat/R$color": "androidx/appcompat/R$color",
+      "android/support/v7/widget/DecorContentParent": "androidx/widget/DecorContentParent",
+      "android/support/v7/app/AppCompatViewInflater": "androidx/app/AppCompatViewInflater",
+      "android/support/v7/app/WindowDecorActionBar": "androidx/app/WindowDecorActionBar",
+      "android/support/v7/app/ToolbarActionBar": "androidx/app/ToolbarActionBar",
+      "android/support/v7/widget/AppCompatDrawableManager": "androidx/widget/AppCompatDrawableManager",
+      "android/support/v7/widget/ViewUtils": "androidx/widget/ViewUtils",
+      "android/support/v4/widget/PopupWindowCompat": "androidx/widget/PopupWindowCompat",
+      "android/support/v7/widget/ViewStubCompat": "androidx/widget/ViewStubCompat",
+      "android/support/v7/view/StandaloneActionMode": "androidx/view/StandaloneActionMode",
+      "android/support/v4/view/LayoutInflaterCompat": "androidx/view/LayoutInflaterCompat",
+      "android/support/v7/app/AppCompatDialogFragment": "androidx/app/AppCompatDialogFragment",
+      "android/support/v7/app/AppCompatViewInflater$DeclaredOnClickListener": "androidx/app/AppCompatViewInflater$DeclaredOnClickListener",
+      "android/support/v7/widget/TintContextWrapper": "androidx/widget/TintContextWrapper",
+      "android/support/v7/widget/AppCompatTextView": "androidx/widget/AppCompatTextView",
+      "android/support/v7/widget/AppCompatImageView": "androidx/widget/AppCompatImageView",
+      "android/support/v7/widget/AppCompatButton": "androidx/widget/AppCompatButton",
+      "android/support/v7/widget/AppCompatEditText": "androidx/widget/AppCompatEditText",
+      "android/support/v7/widget/AppCompatSpinner": "androidx/widget/AppCompatSpinner",
+      "android/support/v7/widget/AppCompatImageButton": "androidx/widget/AppCompatImageButton",
+      "android/support/v7/widget/AppCompatCheckBox": "androidx/widget/AppCompatCheckBox",
+      "android/support/v7/widget/AppCompatRadioButton": "androidx/widget/AppCompatRadioButton",
+      "android/support/v7/widget/AppCompatCheckedTextView": "androidx/widget/AppCompatCheckedTextView",
+      "android/support/v7/widget/AppCompatAutoCompleteTextView": "androidx/widget/AppCompatAutoCompleteTextView",
+      "android/support/v7/widget/AppCompatMultiAutoCompleteTextView": "androidx/widget/AppCompatMultiAutoCompleteTextView",
+      "android/support/v7/widget/AppCompatRatingBar": "androidx/widget/AppCompatRatingBar",
+      "android/support/v7/widget/AppCompatSeekBar": "androidx/widget/AppCompatSeekBar",
+      "android/support/v7/app/NavItemSelectedListener": "androidx/app/NavItemSelectedListener",
+      "android/support/v7/app/ToolbarActionBar$1": "androidx/app/ToolbarActionBar$1",
+      "android/support/v7/app/ToolbarActionBar$2": "androidx/app/ToolbarActionBar$2",
+      "android/support/v7/widget/Toolbar$OnMenuItemClickListener": "androidx/widget/Toolbar$OnMenuItemClickListener",
+      "android/support/v7/app/ToolbarActionBar$ActionMenuPresenterCallback": "androidx/app/ToolbarActionBar$ActionMenuPresenterCallback",
+      "android/support/v7/widget/DecorToolbar": "androidx/widget/DecorToolbar",
+      "android/support/v7/app/ToolbarActionBar$MenuBuilderCallback": "androidx/app/ToolbarActionBar$MenuBuilderCallback",
+      "android/support/v7/app/ToolbarActionBar$ToolbarCallbackWrapper": "androidx/app/ToolbarActionBar$ToolbarCallbackWrapper",
+      "android/support/v7/widget/ToolbarWidgetWrapper": "androidx/widget/ToolbarWidgetWrapper",
+      "android/support/v7/app/TwilightCalculator": "androidx/app/TwilightCalculator",
+      "android/support/v7/app/TwilightManager$TwilightState": "androidx/app/TwilightManager$TwilightState",
+      "android/support/v4/content/PermissionChecker": "androidx/content/PermissionChecker",
+      "android/support/annotation/RequiresPermission": "androidx/annotation/RequiresPermission",
+      "android/support/v7/app/WindowDecorActionBar$1": "androidx/app/WindowDecorActionBar$1",
+      "android/support/v7/widget/ActionBarContainer": "androidx/widget/ActionBarContainer",
+      "android/support/v7/view/ViewPropertyAnimatorCompatSet": "androidx/view/ViewPropertyAnimatorCompatSet",
+      "android/support/v7/widget/ActionBarOverlayLayout": "androidx/widget/ActionBarOverlayLayout",
+      "android/support/v7/app/WindowDecorActionBar$2": "androidx/app/WindowDecorActionBar$2",
+      "android/support/v7/app/WindowDecorActionBar$3": "androidx/app/WindowDecorActionBar$3",
+      "android/support/v4/view/ViewPropertyAnimatorUpdateListener": "androidx/view/ViewPropertyAnimatorUpdateListener",
+      "android/support/v7/app/WindowDecorActionBar$ActionModeImpl": "androidx/app/WindowDecorActionBar$ActionModeImpl",
+      "android/support/v7/view/menu/SubMenuBuilder": "androidx/view/menu/SubMenuBuilder",
+      "android/support/v7/view/menu/MenuPopupHelper": "androidx/view/menu/MenuPopupHelper",
+      "android/support/v7/app/WindowDecorActionBar$TabImpl": "androidx/app/WindowDecorActionBar$TabImpl",
+      "android/support/v7/widget/ScrollingTabContainerView": "androidx/widget/ScrollingTabContainerView",
+      "android/support/v7/widget/ActionBarOverlayLayout$ActionBarVisibilityCallback": "androidx/widget/ActionBarOverlayLayout$ActionBarVisibilityCallback",
+      "android/support/v7/view/ActionBarPolicy": "androidx/view/ActionBarPolicy",
+      "android/support/v7/content/res/AppCompatColorStateListInflater": "androidx/content/res/AppCompatColorStateListInflater",
+      "android/support/v7/content/res/GrowingArrayUtils": "androidx/content/res/GrowingArrayUtils",
+      "android/support/v4/graphics/ColorUtils": "androidx/graphics/ColorUtils",
+      "android/support/v7/content/res/AppCompatResources$ColorStateListCacheEntry": "androidx/content/res/AppCompatResources$ColorStateListCacheEntry",
+      "android/support/v7/graphics/drawable/DrawableWrapper": "androidx/graphics/drawable/DrawableWrapper",
+      "android/support/v7/graphics/drawable/DrawerArrowDrawable$ArrowDirection": "androidx/graphics/drawable/DrawerArrowDrawable$ArrowDirection",
+      "android/support/v7/text/AllCapsTransformationMethod": "androidx/text/AllCapsTransformationMethod",
+      "android/support/v7/appcompat/R$bool": "androidx/appcompat/R$bool",
+      "android/support/v7/appcompat/R$dimen": "androidx/appcompat/R$dimen",
+      "android/support/v7/view/CollapsibleActionView": "androidx/view/CollapsibleActionView",
+      "android/support/v4/internal/view/SupportMenuItem": "androidx/internal/view/SupportMenuItem",
+      "android/support/v7/view/menu/MenuWrapperFactory": "androidx/view/menu/MenuWrapperFactory",
+      "android/support/v4/internal/view/SupportMenu": "androidx/internal/view/SupportMenu",
+      "android/support/v7/view/SupportMenuInflater$InflatedOnMenuItemClickListener": "androidx/view/SupportMenuInflater$InflatedOnMenuItemClickListener",
+      "android/support/v7/view/SupportMenuInflater$MenuState": "androidx/view/SupportMenuInflater$MenuState",
+      "android/support/v4/view/ActionProvider": "androidx/view/ActionProvider",
+      "android/support/v7/widget/DrawableUtils": "androidx/widget/DrawableUtils",
+      "android/support/v7/view/menu/MenuItemImpl": "androidx/view/menu/MenuItemImpl",
+      "android/support/v7/view/menu/MenuItemWrapperICS": "androidx/view/menu/MenuItemWrapperICS",
+      "android/support/v4/view/MenuItemCompat": "androidx/view/MenuItemCompat",
+      "android/support/v7/view/ViewPropertyAnimatorCompatSet$1": "androidx/view/ViewPropertyAnimatorCompatSet$1",
+      "android/support/v7/view/menu/ActionMenuItem": "androidx/view/menu/ActionMenuItem",
+      "android/support/v7/view/menu/ActionMenuItemView$ActionMenuItemForwardingListener": "androidx/view/menu/ActionMenuItemView$ActionMenuItemForwardingListener",
+      "android/support/v7/widget/ForwardingListener": "androidx/widget/ForwardingListener",
+      "android/support/v7/view/menu/ActionMenuItemView": "androidx/view/menu/ActionMenuItemView",
+      "android/support/v7/view/menu/ActionMenuItemView$PopupCallback": "androidx/view/menu/ActionMenuItemView$PopupCallback",
+      "android/support/v7/view/menu/MenuBuilder$ItemInvoker": "androidx/view/menu/MenuBuilder$ItemInvoker",
+      "android/support/v7/view/menu/ShowableListMenu": "androidx/view/menu/ShowableListMenu",
+      "android/support/v7/view/menu/MenuView$ItemView": "androidx/view/menu/MenuView$ItemView",
+      "android/support/v7/widget/ActionMenuView$ActionMenuChildView": "androidx/widget/ActionMenuView$ActionMenuChildView",
+      "android/support/v7/widget/ActionMenuView": "androidx/widget/ActionMenuView",
+      "android/support/v7/widget/TooltipCompat": "androidx/widget/TooltipCompat",
+      "android/support/v7/view/menu/BaseMenuPresenter": "androidx/view/menu/BaseMenuPresenter",
+      "android/support/v7/view/menu/BaseMenuWrapper": "androidx/view/menu/BaseMenuWrapper",
+      "android/support/v7/view/menu/BaseWrapper": "androidx/view/menu/BaseWrapper",
+      "android/support/v4/internal/view/SupportSubMenu": "androidx/internal/view/SupportSubMenu",
+      "android/support/v7/view/menu/CascadingMenuPopup$1": "androidx/view/menu/CascadingMenuPopup$1",
+      "android/support/v7/view/menu/CascadingMenuPopup": "androidx/view/menu/CascadingMenuPopup",
+      "android/support/v7/view/menu/CascadingMenuPopup$CascadingMenuInfo": "androidx/view/menu/CascadingMenuPopup$CascadingMenuInfo",
+      "android/support/v7/widget/MenuPopupWindow": "androidx/widget/MenuPopupWindow",
+      "android/support/v7/view/menu/CascadingMenuPopup$2": "androidx/view/menu/CascadingMenuPopup$2",
+      "android/support/v7/view/menu/CascadingMenuPopup$3$1": "androidx/view/menu/CascadingMenuPopup$3$1",
+      "android/support/v7/view/menu/CascadingMenuPopup$3": "androidx/view/menu/CascadingMenuPopup$3",
+      "android/support/v7/widget/MenuItemHoverListener": "androidx/widget/MenuItemHoverListener",
+      "android/support/v7/view/menu/CascadingMenuPopup$HorizPosition": "androidx/view/menu/CascadingMenuPopup$HorizPosition",
+      "android/support/v7/view/menu/MenuPopup": "androidx/view/menu/MenuPopup",
+      "android/support/v7/view/menu/MenuAdapter": "androidx/view/menu/MenuAdapter",
+      "android/support/v7/view/menu/ExpandedMenuView": "androidx/view/menu/ExpandedMenuView",
+      "android/support/v7/view/menu/ListMenuItemView": "androidx/view/menu/ListMenuItemView",
+      "android/support/v7/view/menu/ListMenuPresenter$MenuAdapter": "androidx/view/menu/ListMenuPresenter$MenuAdapter",
+      "android/support/v7/view/menu/MenuDialogHelper": "androidx/view/menu/MenuDialogHelper",
+      "android/support/v7/view/menu/MenuHelper": "androidx/view/menu/MenuHelper",
+      "android/support/v7/view/menu/MenuItemImpl$1": "androidx/view/menu/MenuItemImpl$1",
+      "android/support/v4/view/ActionProvider$VisibilityListener": "androidx/view/ActionProvider$VisibilityListener",
+      "android/support/v7/view/menu/MenuItemWrapperICS$ActionProviderWrapper": "androidx/view/menu/MenuItemWrapperICS$ActionProviderWrapper",
+      "android/support/v7/view/menu/MenuItemWrapperICS$CollapsibleActionViewWrapper": "androidx/view/menu/MenuItemWrapperICS$CollapsibleActionViewWrapper",
+      "android/support/v7/view/menu/MenuItemWrapperICS$OnActionExpandListenerWrapper": "androidx/view/menu/MenuItemWrapperICS$OnActionExpandListenerWrapper",
+      "android/support/v7/view/menu/MenuItemWrapperICS$OnMenuItemClickListenerWrapper": "androidx/view/menu/MenuItemWrapperICS$OnMenuItemClickListenerWrapper",
+      "android/support/v7/view/menu/MenuItemWrapperJB$ActionProviderWrapperJB": "androidx/view/menu/MenuItemWrapperJB$ActionProviderWrapperJB",
+      "android/support/v7/view/menu/MenuItemWrapperJB": "androidx/view/menu/MenuItemWrapperJB",
+      "android/support/v7/view/menu/MenuPopupHelper$1": "androidx/view/menu/MenuPopupHelper$1",
+      "android/support/v7/view/menu/StandardMenuPopup": "androidx/view/menu/StandardMenuPopup",
+      "android/support/v7/view/menu/MenuWrapperICS": "androidx/view/menu/MenuWrapperICS",
+      "android/support/v7/view/menu/SubMenuWrapperICS": "androidx/view/menu/SubMenuWrapperICS",
+      "android/support/v7/view/menu/StandardMenuPopup$1": "androidx/view/menu/StandardMenuPopup$1",
+      "android/support/v7/view/menu/StandardMenuPopup$2": "androidx/view/menu/StandardMenuPopup$2",
+      "android/support/v7/widget/AbsActionBarView$1": "androidx/widget/AbsActionBarView$1",
+      "android/support/v7/widget/AbsActionBarView": "androidx/widget/AbsActionBarView",
+      "android/support/v7/widget/AbsActionBarView$VisibilityAnimListener": "androidx/widget/AbsActionBarView$VisibilityAnimListener",
+      "android/support/v7/widget/ActionMenuPresenter": "androidx/widget/ActionMenuPresenter",
+      "android/support/v7/widget/ActionBarBackgroundDrawable": "androidx/widget/ActionBarBackgroundDrawable",
+      "android/support/v7/widget/ActionBarBackgroundDrawableV21": "androidx/widget/ActionBarBackgroundDrawableV21",
+      "android/support/v7/widget/ActionBarContextView$1": "androidx/widget/ActionBarContextView$1",
+      "android/support/v7/widget/ActionBarOverlayLayout$1": "androidx/widget/ActionBarOverlayLayout$1",
+      "android/support/v7/widget/ActionBarOverlayLayout$2": "androidx/widget/ActionBarOverlayLayout$2",
+      "android/support/v7/widget/ActionBarOverlayLayout$3": "androidx/widget/ActionBarOverlayLayout$3",
+      "android/support/v7/widget/ActionBarOverlayLayout$LayoutParams": "androidx/widget/ActionBarOverlayLayout$LayoutParams",
+      "android/support/v7/widget/ActionMenuPresenter$ActionButtonSubmenu": "androidx/widget/ActionMenuPresenter$ActionButtonSubmenu",
+      "android/support/v7/widget/ActionMenuPresenter$OverflowMenuButton": "androidx/widget/ActionMenuPresenter$OverflowMenuButton",
+      "android/support/v7/widget/ActionMenuPresenter$PopupPresenterCallback": "androidx/widget/ActionMenuPresenter$PopupPresenterCallback",
+      "android/support/v7/widget/ActionMenuPresenter$ActionMenuPopupCallback": "androidx/widget/ActionMenuPresenter$ActionMenuPopupCallback",
+      "android/support/v7/widget/ActionMenuPresenter$OpenOverflowRunnable": "androidx/widget/ActionMenuPresenter$OpenOverflowRunnable",
+      "android/support/v7/widget/ActionMenuPresenter$OverflowPopup": "androidx/widget/ActionMenuPresenter$OverflowPopup",
+      "android/support/v7/widget/ActionMenuPresenter$OverflowMenuButton$1": "androidx/widget/ActionMenuPresenter$OverflowMenuButton$1",
+      "android/support/v7/widget/ActionMenuPresenter$SavedState$1": "androidx/widget/ActionMenuPresenter$SavedState$1",
+      "android/support/v7/widget/ActionMenuPresenter$SavedState": "androidx/widget/ActionMenuPresenter$SavedState",
+      "android/support/v4/view/ActionProvider$SubUiVisibilityListener": "androidx/view/ActionProvider$SubUiVisibilityListener",
+      "android/support/v7/widget/ActionMenuView$LayoutParams": "androidx/widget/ActionMenuView$LayoutParams",
+      "android/support/v7/widget/ActionMenuView$ActionMenuPresenterCallback": "androidx/widget/ActionMenuView$ActionMenuPresenterCallback",
+      "android/support/v7/widget/ActionMenuView$MenuBuilderCallback": "androidx/widget/ActionMenuView$MenuBuilderCallback",
+      "android/support/v7/widget/ActionMenuView$OnMenuItemClickListener": "androidx/widget/ActionMenuView$OnMenuItemClickListener",
+      "android/support/v7/widget/ActivityChooserModel$ActivityChooserModelClient": "androidx/widget/ActivityChooserModel$ActivityChooserModelClient",
+      "android/support/v7/widget/ActivityChooserModel": "androidx/widget/ActivityChooserModel",
+      "android/support/v7/widget/ActivityChooserModel$ActivityResolveInfo": "androidx/widget/ActivityChooserModel$ActivityResolveInfo",
+      "android/support/v7/widget/ActivityChooserModel$ActivitySorter": "androidx/widget/ActivityChooserModel$ActivitySorter",
+      "android/support/v7/widget/ActivityChooserModel$HistoricalRecord": "androidx/widget/ActivityChooserModel$HistoricalRecord",
+      "android/support/v7/widget/ActivityChooserModel$DefaultSorter": "androidx/widget/ActivityChooserModel$DefaultSorter",
+      "android/support/v7/widget/ActivityChooserModel$OnChooseActivityListener": "androidx/widget/ActivityChooserModel$OnChooseActivityListener",
+      "android/support/v7/widget/ActivityChooserModel$PersistHistoryAsyncTask": "androidx/widget/ActivityChooserModel$PersistHistoryAsyncTask",
+      "android/support/v7/widget/ActivityChooserView$1": "androidx/widget/ActivityChooserView$1",
+      "android/support/v7/widget/ActivityChooserView": "androidx/widget/ActivityChooserView",
+      "android/support/v7/widget/ActivityChooserView$ActivityChooserViewAdapter": "androidx/widget/ActivityChooserView$ActivityChooserViewAdapter",
+      "android/support/v7/widget/ActivityChooserView$2": "androidx/widget/ActivityChooserView$2",
+      "android/support/v7/widget/ListPopupWindow": "androidx/widget/ListPopupWindow",
+      "android/support/v7/widget/ActivityChooserView$3": "androidx/widget/ActivityChooserView$3",
+      "android/support/v7/widget/ActivityChooserView$4": "androidx/widget/ActivityChooserView$4",
+      "android/support/v7/widget/ActivityChooserView$5": "androidx/widget/ActivityChooserView$5",
+      "android/support/v7/appcompat/R$string": "androidx/appcompat/R$string",
+      "android/support/v7/widget/ActivityChooserView$Callbacks": "androidx/widget/ActivityChooserView$Callbacks",
+      "android/support/v7/widget/ActivityChooserView$InnerLayout": "androidx/widget/ActivityChooserView$InnerLayout",
+      "android/support/v7/widget/AlertDialogLayout": "androidx/widget/AlertDialogLayout",
+      "android/support/v4/view/TintableBackgroundView": "androidx/view/TintableBackgroundView",
+      "android/support/v7/widget/AppCompatBackgroundHelper": "androidx/widget/AppCompatBackgroundHelper",
+      "android/support/v7/widget/AppCompatTextHelper": "androidx/widget/AppCompatTextHelper",
+      "android/support/v7/widget/AppCompatHintHelper": "androidx/widget/AppCompatHintHelper",
+      "android/support/v7/widget/TintInfo": "androidx/widget/TintInfo",
+      "android/support/v4/widget/AutoSizeableTextView": "androidx/widget/AutoSizeableTextView",
+      "android/support/v4/widget/TintableCompoundButton": "androidx/widget/TintableCompoundButton",
+      "android/support/v7/widget/AppCompatCompoundButtonHelper": "androidx/widget/AppCompatCompoundButtonHelper",
+      "android/support/v7/widget/AppCompatCompoundButtonHelper$DirectSetButtonDrawableInterface": "androidx/widget/AppCompatCompoundButtonHelper$DirectSetButtonDrawableInterface",
+      "android/support/v4/widget/CompoundButtonCompat": "androidx/widget/CompoundButtonCompat",
+      "android/support/v7/widget/AppCompatDrawableManager$AvdcInflateDelegate": "androidx/widget/AppCompatDrawableManager$AvdcInflateDelegate",
+      "android/support/v7/widget/AppCompatDrawableManager$InflateDelegate": "androidx/widget/AppCompatDrawableManager$InflateDelegate",
+      "android/support/v7/widget/AppCompatDrawableManager$ColorFilterLruCache": "androidx/widget/AppCompatDrawableManager$ColorFilterLruCache",
+      "android/support/v7/widget/AppCompatDrawableManager$VdcInflateDelegate": "androidx/widget/AppCompatDrawableManager$VdcInflateDelegate",
+      "android/support/v7/appcompat/R$drawable": "androidx/appcompat/R$drawable",
+      "android/support/v4/util/LongSparseArray": "androidx/util/LongSparseArray",
+      "android/support/v7/widget/ThemeUtils": "androidx/widget/ThemeUtils",
+      "android/support/v7/widget/WithHint": "androidx/widget/WithHint",
+      "android/support/v4/widget/TintableImageSourceView": "androidx/widget/TintableImageSourceView",
+      "android/support/v7/widget/AppCompatImageHelper": "androidx/widget/AppCompatImageHelper",
+      "android/support/v4/widget/ImageViewCompat": "androidx/widget/ImageViewCompat",
+      "android/support/v7/widget/AppCompatPopupWindow": "androidx/widget/AppCompatPopupWindow",
+      "android/support/v7/widget/AppCompatProgressBarHelper": "androidx/widget/AppCompatProgressBarHelper",
+      "android/support/v4/graphics/drawable/WrappedDrawable": "androidx/graphics/drawable/WrappedDrawable",
+      "android/support/v7/widget/AppCompatSeekBarHelper": "androidx/widget/AppCompatSeekBarHelper",
+      "android/support/v7/widget/AppCompatSpinner$1": "androidx/widget/AppCompatSpinner$1",
+      "android/support/v7/widget/AppCompatSpinner$DropdownPopup": "androidx/widget/AppCompatSpinner$DropdownPopup",
+      "android/support/v7/widget/AppCompatSpinner$DropDownAdapter": "androidx/widget/AppCompatSpinner$DropDownAdapter",
+      "android/support/v7/widget/ThemedSpinnerAdapter": "androidx/widget/ThemedSpinnerAdapter",
+      "android/support/v7/widget/AppCompatSpinner$DropdownPopup$1": "androidx/widget/AppCompatSpinner$DropdownPopup$1",
+      "android/support/v7/widget/AppCompatSpinner$DropdownPopup$2": "androidx/widget/AppCompatSpinner$DropdownPopup$2",
+      "android/support/v7/widget/AppCompatSpinner$DropdownPopup$3": "androidx/widget/AppCompatSpinner$DropdownPopup$3",
+      "android/support/v7/widget/AppCompatTextHelper$1": "androidx/widget/AppCompatTextHelper$1",
+      "android/support/v4/content/res/ResourcesCompat$FontCallback": "androidx/content/res/ResourcesCompat$FontCallback",
+      "android/support/v7/widget/AppCompatTextViewAutoSizeHelper": "androidx/widget/AppCompatTextViewAutoSizeHelper",
+      "android/support/v7/widget/AppCompatTextHelperV17": "androidx/widget/AppCompatTextHelperV17",
+      "android/support/v7/widget/ButtonBarLayout": "androidx/widget/ButtonBarLayout",
+      "android/support/v7/widget/DialogTitle": "androidx/widget/DialogTitle",
+      "android/support/v7/widget/DropDownListView$GateKeeperDrawable": "androidx/widget/DropDownListView$GateKeeperDrawable",
+      "android/support/v7/widget/DropDownListView": "androidx/widget/DropDownListView",
+      "android/support/v7/widget/FitWindowsFrameLayout": "androidx/widget/FitWindowsFrameLayout",
+      "android/support/v7/widget/FitWindowsLinearLayout": "androidx/widget/FitWindowsLinearLayout",
+      "android/support/v7/widget/ForwardingListener$DisallowIntercept": "androidx/widget/ForwardingListener$DisallowIntercept",
+      "android/support/v7/widget/ForwardingListener$TriggerLongPress": "androidx/widget/ForwardingListener$TriggerLongPress",
+      "android/support/v7/widget/LinearLayoutCompat$DividerMode": "androidx/widget/LinearLayoutCompat$DividerMode",
+      "android/support/v7/widget/LinearLayoutCompat$OrientationMode": "androidx/widget/LinearLayoutCompat$OrientationMode",
+      "android/support/v7/widget/ListPopupWindow$1": "androidx/widget/ListPopupWindow$1",
+      "android/support/v7/widget/ListPopupWindow$2": "androidx/widget/ListPopupWindow$2",
+      "android/support/v7/widget/ListPopupWindow$3": "androidx/widget/ListPopupWindow$3",
+      "android/support/v7/widget/ListPopupWindow$ListSelectorHider": "androidx/widget/ListPopupWindow$ListSelectorHider",
+      "android/support/v7/widget/ListPopupWindow$PopupDataSetObserver": "androidx/widget/ListPopupWindow$PopupDataSetObserver",
+      "android/support/v7/widget/ListPopupWindow$PopupScrollListener": "androidx/widget/ListPopupWindow$PopupScrollListener",
+      "android/support/v7/widget/ListPopupWindow$ResizePopupRunnable": "androidx/widget/ListPopupWindow$ResizePopupRunnable",
+      "android/support/v7/widget/ListPopupWindow$PopupTouchInterceptor": "androidx/widget/ListPopupWindow$PopupTouchInterceptor",
+      "android/support/v7/widget/MenuPopupWindow$MenuDropDownListView": "androidx/widget/MenuPopupWindow$MenuDropDownListView",
+      "android/support/v7/widget/PopupMenu$1": "androidx/widget/PopupMenu$1",
+      "android/support/v7/widget/PopupMenu": "androidx/widget/PopupMenu",
+      "android/support/v7/widget/PopupMenu$OnMenuItemClickListener": "androidx/widget/PopupMenu$OnMenuItemClickListener",
+      "android/support/v7/widget/PopupMenu$2": "androidx/widget/PopupMenu$2",
+      "android/support/v7/widget/PopupMenu$OnDismissListener": "androidx/widget/PopupMenu$OnDismissListener",
+      "android/support/v7/widget/PopupMenu$3": "androidx/widget/PopupMenu$3",
+      "android/support/annotation/MenuRes": "androidx/annotation/MenuRes",
+      "android/support/v7/widget/ResourcesWrapper": "androidx/widget/ResourcesWrapper",
+      "android/support/v7/widget/RtlSpacingHelper": "androidx/widget/RtlSpacingHelper",
+      "android/support/v7/widget/ScrollingTabContainerView$1": "androidx/widget/ScrollingTabContainerView$1",
+      "android/support/v7/widget/ScrollingTabContainerView$TabAdapter": "androidx/widget/ScrollingTabContainerView$TabAdapter",
+      "android/support/v7/widget/ScrollingTabContainerView$TabView": "androidx/widget/ScrollingTabContainerView$TabView",
+      "android/support/v7/widget/ScrollingTabContainerView$TabClickListener": "androidx/widget/ScrollingTabContainerView$TabClickListener",
+      "android/support/v7/widget/ScrollingTabContainerView$VisibilityAnimListener": "androidx/widget/ScrollingTabContainerView$VisibilityAnimListener",
+      "android/support/v7/widget/SearchView$1": "androidx/widget/SearchView$1",
+      "android/support/v7/widget/SearchView": "androidx/widget/SearchView",
+      "android/support/v7/widget/SearchView$10": "androidx/widget/SearchView$10",
+      "android/support/v7/widget/SearchView$2": "androidx/widget/SearchView$2",
+      "android/support/v7/widget/SuggestionsAdapter": "androidx/widget/SuggestionsAdapter",
+      "android/support/v7/widget/SearchView$3": "androidx/widget/SearchView$3",
+      "android/support/v7/widget/SearchView$4": "androidx/widget/SearchView$4",
+      "android/support/v7/widget/SearchView$5": "androidx/widget/SearchView$5",
+      "android/support/v7/widget/SearchView$SearchAutoComplete": "androidx/widget/SearchView$SearchAutoComplete",
+      "android/support/v7/widget/SearchView$6": "androidx/widget/SearchView$6",
+      "android/support/v7/widget/SearchView$7": "androidx/widget/SearchView$7",
+      "android/support/v7/widget/SearchView$8": "androidx/widget/SearchView$8",
+      "android/support/v7/widget/SearchView$9": "androidx/widget/SearchView$9",
+      "android/support/v7/widget/SearchView$AutoCompleteTextViewReflector": "androidx/widget/SearchView$AutoCompleteTextViewReflector",
+      "android/support/v7/widget/SearchView$OnCloseListener": "androidx/widget/SearchView$OnCloseListener",
+      "android/support/v7/widget/SearchView$OnQueryTextListener": "androidx/widget/SearchView$OnQueryTextListener",
+      "android/support/v7/widget/SearchView$OnSuggestionListener": "androidx/widget/SearchView$OnSuggestionListener",
+      "android/support/v7/widget/SearchView$SavedState$1": "androidx/widget/SearchView$SavedState$1",
+      "android/support/v7/widget/SearchView$SavedState": "androidx/widget/SearchView$SavedState",
+      "android/support/v7/widget/SearchView$SearchAutoComplete$1": "androidx/widget/SearchView$SearchAutoComplete$1",
+      "android/support/v7/widget/SearchView$UpdatableTouchDelegate": "androidx/widget/SearchView$UpdatableTouchDelegate",
+      "android/support/v7/widget/ShareActionProvider$OnShareTargetSelectedListener": "androidx/widget/ShareActionProvider$OnShareTargetSelectedListener",
+      "android/support/v7/widget/ShareActionProvider": "androidx/widget/ShareActionProvider",
+      "android/support/v7/widget/ShareActionProvider$ShareActivityChooserModelPolicy": "androidx/widget/ShareActionProvider$ShareActivityChooserModelPolicy",
+      "android/support/v7/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener": "androidx/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener",
+      "android/support/v7/widget/SuggestionsAdapter$ChildViewCache": "androidx/widget/SuggestionsAdapter$ChildViewCache",
+      "android/support/v7/widget/SwitchCompat$1": "androidx/widget/SwitchCompat$1",
+      "android/support/v7/widget/ThemedSpinnerAdapter$Helper": "androidx/widget/ThemedSpinnerAdapter$Helper",
+      "android/support/v7/widget/TintResources": "androidx/widget/TintResources",
+      "android/support/v7/widget/Toolbar$1": "androidx/widget/Toolbar$1",
+      "android/support/v7/widget/Toolbar$2": "androidx/widget/Toolbar$2",
+      "android/support/v7/widget/Toolbar$3": "androidx/widget/Toolbar$3",
+      "android/support/v7/widget/Toolbar$ExpandedActionViewMenuPresenter": "androidx/widget/Toolbar$ExpandedActionViewMenuPresenter",
+      "android/support/v7/widget/Toolbar$LayoutParams": "androidx/widget/Toolbar$LayoutParams",
+      "android/support/v7/widget/Toolbar$SavedState$1": "androidx/widget/Toolbar$SavedState$1",
+      "android/support/v7/widget/Toolbar$SavedState": "androidx/widget/Toolbar$SavedState",
+      "android/support/v4/view/MarginLayoutParamsCompat": "androidx/view/MarginLayoutParamsCompat",
+      "android/support/v7/widget/ToolbarWidgetWrapper$1": "androidx/widget/ToolbarWidgetWrapper$1",
+      "android/support/v7/widget/ToolbarWidgetWrapper$2": "androidx/widget/ToolbarWidgetWrapper$2",
+      "android/support/v7/widget/TooltipCompatHandler": "androidx/widget/TooltipCompatHandler",
+      "android/support/v7/widget/TooltipCompatHandler$1": "androidx/widget/TooltipCompatHandler$1",
+      "android/support/v7/widget/TooltipCompatHandler$2": "androidx/widget/TooltipCompatHandler$2",
+      "android/support/v7/widget/TooltipPopup": "androidx/widget/TooltipPopup",
+      "android/support/v7/widget/ViewStubCompat$OnInflateListener": "androidx/widget/ViewStubCompat$OnInflateListener",
+      "android/support/content/ContentPager$1": "androidx/util/contentpaging/ContentPager$1",
+      "android/support/content/ContentPager$QueryRunner$Callback": "androidx/util/contentpaging/ContentPager$QueryRunner$Callback",
+      "android/support/content/ContentPager": "androidx/util/contentpaging/ContentPager",
+      "android/support/content/ContentPager$QueryRunner": "androidx/util/contentpaging/ContentPager$QueryRunner",
+      "android/support/content/Query": "androidx/util/contentpaging/Query",
+      "android/support/annotation/WorkerThread": "androidx/annotation/WorkerThread",
+      "android/support/annotation/MainThread": "androidx/annotation/MainThread",
+      "android/support/content/ContentPager$ContentCallback": "androidx/util/contentpaging/ContentPager$ContentCallback",
+      "android/support/content/ContentPager$CursorCache": "androidx/util/contentpaging/ContentPager$CursorCache",
+      "android/support/annotation/GuardedBy": "androidx/annotation/GuardedBy",
+      "android/support/content/ContentPager$CursorDisposition": "androidx/util/contentpaging/ContentPager$CursorDisposition",
+      "android/support/content/ContentPager$CursorView": "androidx/util/contentpaging/ContentPager$CursorView",
+      "android/support/content/ContentPager$Stats": "androidx/util/contentpaging/ContentPager$Stats",
+      "android/support/annotation/RequiresPermission$Read": "androidx/annotation/RequiresPermission$Read",
+      "android/support/content/InMemoryCursor": "androidx/util/contentpaging/InMemoryCursor",
+      "android/support/content/InMemoryCursor$ObserverRelay": "androidx/util/contentpaging/InMemoryCursor$ObserverRelay",
+      "android/support/content/LoaderQueryRunner$1$1": "androidx/util/contentpaging/LoaderQueryRunner$1$1",
+      "android/support/content/LoaderQueryRunner$1": "androidx/util/contentpaging/LoaderQueryRunner$1",
+      "android/support/content/LoaderQueryRunner": "androidx/util/contentpaging/LoaderQueryRunner",
+      "android/arch/lifecycle/LifecycleRegistry$1": "androidx/lifecycle/LifecycleRegistry$1",
+      "android/arch/lifecycle/LifecycleRegistry": "androidx/lifecycle/LifecycleRegistry",
+      "android/arch/lifecycle/Lifecycle$State": "androidx/lifecycle/Lifecycle$State",
+      "android/arch/lifecycle/Lifecycle": "androidx/lifecycle/Lifecycle",
+      "android/arch/lifecycle/Lifecycle$Event": "androidx/lifecycle/Lifecycle$Event",
+      "android/arch/lifecycle/LifecycleRegistry$ObserverWithState": "androidx/lifecycle/LifecycleRegistry$ObserverWithState",
+      "android/arch/lifecycle/GenericLifecycleObserver": "androidx/lifecycle/GenericLifecycleObserver",
+      "android/arch/lifecycle/LifecycleObserver": "androidx/lifecycle/LifecycleObserver",
+      "android/arch/lifecycle/Lifecycling": "androidx/lifecycle/Lifecycling",
+      "android/arch/lifecycle/LifecycleOwner": "androidx/lifecycle/LifecycleOwner",
+      "android/arch/core/internal/SafeIterableMap$IteratorWithAdditions": "androidx/core/internal/SafeIterableMap$IteratorWithAdditions",
+      "android/arch/core/internal/SafeIterableMap": "androidx/core/internal/SafeIterableMap",
+      "android/arch/core/internal/FastSafeIterableMap": "androidx/core/internal/FastSafeIterableMap",
+      "android/arch/lifecycle/LifecycleRegistryOwner": "androidx/lifecycle/LifecycleRegistryOwner",
+      "android/arch/lifecycle/ReportFragment$ActivityInitializationListener": "androidx/lifecycle/ReportFragment$ActivityInitializationListener",
+      "android/arch/lifecycle/ReportFragment": "androidx/lifecycle/ReportFragment",
+      "android/arch/lifecycle/EmptyActivityLifecycleCallbacks": "androidx/lifecycle/EmptyActivityLifecycleCallbacks",
+      "android/arch/lifecycle/HolderFragment$HolderFragmentManager$1": "androidx/lifecycle/HolderFragment$HolderFragmentManager$1",
+      "android/arch/lifecycle/HolderFragment$HolderFragmentManager": "androidx/lifecycle/HolderFragment$HolderFragmentManager",
+      "android/arch/lifecycle/HolderFragment": "androidx/lifecycle/HolderFragment",
+      "android/arch/lifecycle/HolderFragment$HolderFragmentManager$2": "androidx/lifecycle/HolderFragment$HolderFragmentManager$2",
+      "android/support/v4/app/FragmentManager$FragmentLifecycleCallbacks": "androidx/app/FragmentManager$FragmentLifecycleCallbacks",
+      "android/arch/lifecycle/ViewModelStoreOwner": "androidx/lifecycle/ViewModelStoreOwner",
+      "android/arch/lifecycle/ViewModelStore": "androidx/lifecycle/ViewModelStore",
+      "android/arch/lifecycle/LifecycleDispatcher$DestructionReportFragment": "androidx/lifecycle/LifecycleDispatcher$DestructionReportFragment",
+      "android/arch/lifecycle/LifecycleDispatcher": "androidx/lifecycle/LifecycleDispatcher",
+      "android/arch/lifecycle/LifecycleDispatcher$DispatcherActivityCallback": "androidx/lifecycle/LifecycleDispatcher$DispatcherActivityCallback",
+      "android/arch/lifecycle/LifecycleDispatcher$FragmentCallback": "androidx/lifecycle/LifecycleDispatcher$FragmentCallback",
+      "android/arch/lifecycle/LifecycleService": "androidx/lifecycle/LifecycleService",
+      "android/arch/lifecycle/ServiceLifecycleDispatcher": "androidx/lifecycle/ServiceLifecycleDispatcher",
+      "android/arch/lifecycle/ProcessLifecycleOwner$1": "androidx/lifecycle/ProcessLifecycleOwner$1",
+      "android/arch/lifecycle/ProcessLifecycleOwner": "androidx/lifecycle/ProcessLifecycleOwner",
+      "android/arch/lifecycle/ProcessLifecycleOwner$2": "androidx/lifecycle/ProcessLifecycleOwner$2",
+      "android/arch/lifecycle/ProcessLifecycleOwner$3": "androidx/lifecycle/ProcessLifecycleOwner$3",
+      "android/arch/lifecycle/ProcessLifecycleOwnerInitializer": "androidx/lifecycle/ProcessLifecycleOwnerInitializer",
+      "android/arch/lifecycle/ServiceLifecycleDispatcher$DispatchRunnable": "androidx/lifecycle/ServiceLifecycleDispatcher$DispatchRunnable",
+      "android/arch/lifecycle/ViewModelProviders$DefaultFactory": "androidx/lifecycle/ViewModelProviders$DefaultFactory",
+      "android/arch/lifecycle/ViewModelProvider$AndroidViewModelFactory": "androidx/lifecycle/ViewModelProvider$AndroidViewModelFactory",
+      "android/arch/lifecycle/ViewModelProviders": "androidx/lifecycle/ViewModelProviders",
+      "android/arch/lifecycle/ViewModelProvider": "androidx/lifecycle/ViewModelProvider",
+      "android/arch/lifecycle/ViewModelProvider$Factory": "androidx/lifecycle/ViewModelProvider$Factory",
+      "android/arch/lifecycle/ViewModelStores": "androidx/lifecycle/ViewModelStores",
+      "android/support/v4/media/AudioAttributesCompat$1": "androidx/media/AudioAttributesCompat$1",
+      "android/support/v4/media/AudioAttributesCompat": "androidx/media/AudioAttributesCompat",
+      "android/support/v4/media/AudioAttributesCompat$AttributeContentType": "androidx/media/AudioAttributesCompat$AttributeContentType",
+      "android/support/v4/media/AudioAttributesCompat$AttributeUsage": "androidx/media/AudioAttributesCompat$AttributeUsage",
+      "android/support/v4/media/AudioAttributesCompat$AudioManagerHidden": "androidx/media/AudioAttributesCompat$AudioManagerHidden",
+      "android/support/v4/media/AudioAttributesCompat$Builder": "androidx/media/AudioAttributesCompat$Builder",
+      "android/support/v4/media/AudioAttributesCompatApi21$Wrapper": "androidx/media/AudioAttributesCompatApi21$Wrapper",
+      "android/support/v4/media/AudioAttributesCompatApi21": "androidx/media/AudioAttributesCompatApi21",
+      "android/support/v4/media/MediaBrowserCompat$CallbackHandler": "androidx/media/MediaBrowserCompat$CallbackHandler",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserServiceCallbackImpl": "androidx/media/MediaBrowserCompat$MediaBrowserServiceCallbackImpl",
+      "android/support/v4/media/MediaBrowserCompat": "androidx/media/MediaBrowserCompat",
+      "android/support/v4/media/session/MediaSessionCompat$Token": "androidx/media/session/MediaSessionCompat$Token",
+      "android/support/v4/media/session/MediaSessionCompat": "androidx/media/session/MediaSessionCompat",
+      "android/support/v4/media/MediaBrowserCompat$ConnectionCallback$ConnectionCallbackInternal": "androidx/media/MediaBrowserCompat$ConnectionCallback$ConnectionCallbackInternal",
+      "android/support/v4/media/MediaBrowserCompat$ConnectionCallback": "androidx/media/MediaBrowserCompat$ConnectionCallback",
+      "android/support/v4/media/MediaBrowserCompat$ConnectionCallback$StubApi21": "androidx/media/MediaBrowserCompat$ConnectionCallback$StubApi21",
+      "android/support/v4/media/MediaBrowserCompatApi21$ConnectionCallback": "androidx/media/MediaBrowserCompatApi21$ConnectionCallback",
+      "android/support/v4/media/MediaBrowserCompatApi21": "androidx/media/MediaBrowserCompatApi21",
+      "android/support/v4/media/MediaBrowserCompat$CustomActionCallback": "androidx/media/MediaBrowserCompat$CustomActionCallback",
+      "android/support/v4/media/MediaBrowserCompat$CustomActionResultReceiver": "androidx/media/MediaBrowserCompat$CustomActionResultReceiver",
+      "android/support/v4/os/ResultReceiver": "androidx/os/ResultReceiver",
+      "android/support/v4/media/MediaBrowserCompat$ItemCallback$StubApi23": "androidx/media/MediaBrowserCompat$ItemCallback$StubApi23",
+      "android/support/v4/media/MediaBrowserCompatApi23$ItemCallback": "androidx/media/MediaBrowserCompatApi23$ItemCallback",
+      "android/support/v4/media/MediaBrowserCompat$ItemCallback": "androidx/media/MediaBrowserCompat$ItemCallback",
+      "android/support/v4/media/MediaBrowserCompat$MediaItem": "androidx/media/MediaBrowserCompat$MediaItem",
+      "android/support/v4/media/MediaBrowserCompatApi23": "androidx/media/MediaBrowserCompatApi23",
+      "android/support/v4/media/MediaBrowserCompat$ItemReceiver": "androidx/media/MediaBrowserCompat$ItemReceiver",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImpl": "androidx/media/MediaBrowserCompat$MediaBrowserImpl",
+      "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback": "androidx/media/MediaBrowserCompat$SubscriptionCallback",
+      "android/support/v4/media/MediaBrowserCompat$SearchCallback": "androidx/media/MediaBrowserCompat$SearchCallback",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$1": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21$1",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$2": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21$2",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$3": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21$3",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$4": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21$4",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$5": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21$5",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$6": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21$6",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi21$7": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi21$7",
+      "android/support/v4/media/MediaBrowserCompat$Subscription": "androidx/media/MediaBrowserCompat$Subscription",
+      "android/support/v4/media/MediaBrowserCompat$ServiceBinderWrapper": "androidx/media/MediaBrowserCompat$ServiceBinderWrapper",
+      "android/support/v4/media/MediaBrowserCompat$SearchResultReceiver": "androidx/media/MediaBrowserCompat$SearchResultReceiver",
+      "android/support/v4/media/session/IMediaSession$Stub": "androidx/media/session/IMediaSession$Stub",
+      "android/support/v4/media/session/IMediaSession": "androidx/media/session/IMediaSession",
+      "android/support/v4/app/BundleCompat": "androidx/app/BundleCompat",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi23": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi23",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplApi26": "androidx/media/MediaBrowserCompat$MediaBrowserImplApi26",
+      "android/support/v4/media/MediaBrowserCompatApi26": "androidx/media/MediaBrowserCompatApi26",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$1": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$1",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$2": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$2",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$3": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$3",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$4": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$4",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$5": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$5",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$6": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$6",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection$1": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection$1",
+      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection$2": "androidx/media/MediaBrowserCompat$MediaBrowserImplBase$MediaServiceConnection$2",
+      "android/support/v4/media/MediaBrowserCompat$MediaItem$1": "androidx/media/MediaBrowserCompat$MediaItem$1",
+      "android/support/v4/media/MediaBrowserCompat$MediaItem$Flags": "androidx/media/MediaBrowserCompat$MediaItem$Flags",
+      "android/support/v4/media/MediaBrowserCompatApi21$MediaItem": "androidx/media/MediaBrowserCompatApi21$MediaItem",
+      "android/support/v4/media/MediaBrowserCompatUtils": "androidx/media/MediaBrowserCompatUtils",
+      "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback$StubApi21": "androidx/media/MediaBrowserCompat$SubscriptionCallback$StubApi21",
+      "android/support/v4/media/MediaBrowserCompatApi21$SubscriptionCallback": "androidx/media/MediaBrowserCompatApi21$SubscriptionCallback",
+      "android/support/v4/media/MediaBrowserCompat$SubscriptionCallback$StubApi26": "androidx/media/MediaBrowserCompat$SubscriptionCallback$StubApi26",
+      "android/support/v4/media/MediaBrowserCompatApi26$SubscriptionCallback": "androidx/media/MediaBrowserCompatApi26$SubscriptionCallback",
+      "android/support/v4/media/MediaBrowserCompatApi21$ConnectionCallbackProxy": "androidx/media/MediaBrowserCompatApi21$ConnectionCallbackProxy",
+      "android/support/v4/media/MediaBrowserCompatApi21$SubscriptionCallbackProxy": "androidx/media/MediaBrowserCompatApi21$SubscriptionCallbackProxy",
+      "android/support/v4/media/MediaBrowserCompatApi23$ItemCallbackProxy": "androidx/media/MediaBrowserCompatApi23$ItemCallbackProxy",
+      "android/support/v4/media/MediaBrowserCompatApi26$SubscriptionCallbackProxy": "androidx/media/MediaBrowserCompatApi26$SubscriptionCallbackProxy",
+      "android/support/v4/media/MediaBrowserProtocol": "androidx/media/MediaBrowserProtocol",
+      "android/support/v4/media/MediaBrowserServiceCompat$1": "androidx/media/MediaBrowserServiceCompat$1",
+      "android/support/v4/media/MediaBrowserServiceCompat$Result": "androidx/media/MediaBrowserServiceCompat$Result",
+      "android/support/v4/media/MediaBrowserServiceCompat": "androidx/media/MediaBrowserServiceCompat",
+      "android/support/v4/media/MediaBrowserServiceCompat$ConnectionRecord": "androidx/media/MediaBrowserServiceCompat$ConnectionRecord",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceCallbacks": "androidx/media/MediaBrowserServiceCompat$ServiceCallbacks",
+      "android/support/v4/media/MediaBrowserServiceCompat$2": "androidx/media/MediaBrowserServiceCompat$2",
+      "android/support/v4/media/MediaBrowserServiceCompat$3": "androidx/media/MediaBrowserServiceCompat$3",
+      "android/support/v4/media/MediaBrowserServiceCompat$4": "androidx/media/MediaBrowserServiceCompat$4",
+      "android/support/v4/media/MediaBrowserServiceCompat$BrowserRoot": "androidx/media/MediaBrowserServiceCompat$BrowserRoot",
+      "android/support/v4/media/MediaBrowserServiceCompat$ConnectionRecord$1": "androidx/media/MediaBrowserServiceCompat$ConnectionRecord$1",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceHandler": "androidx/media/MediaBrowserServiceCompat$ServiceHandler",
+      "android/support/v4/util/Pair": "androidx/util/Pair",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImpl": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImpl",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21$1": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21$1",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21",
+      "android/support/v4/media/MediaBrowserServiceCompatApi21": "androidx/media/MediaBrowserServiceCompatApi21",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21$2": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21$2",
+      "android/support/v4/media/MediaBrowserServiceCompatApi21$ResultWrapper": "androidx/media/MediaBrowserServiceCompatApi21$ResultWrapper",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21$3": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21$3",
+      "android/support/v4/media/MediaBrowserServiceCompatApi21$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi21$ServiceCompatProxy",
+      "android/support/v4/media/MediaBrowserServiceCompatApi21$BrowserRoot": "androidx/media/MediaBrowserServiceCompatApi21$BrowserRoot",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23$1": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23$1",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23",
+      "android/support/v4/media/MediaBrowserServiceCompatApi23$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi23$ServiceCompatProxy",
+      "android/support/v4/media/MediaBrowserServiceCompatApi23": "androidx/media/MediaBrowserServiceCompatApi23",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26$1": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26$1",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26",
+      "android/support/v4/media/MediaBrowserServiceCompatApi26$ResultWrapper": "androidx/media/MediaBrowserServiceCompatApi26$ResultWrapper",
+      "android/support/v4/media/MediaBrowserServiceCompatApi26": "androidx/media/MediaBrowserServiceCompatApi26",
+      "android/support/v4/media/MediaBrowserServiceCompatApi26$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi26$ServiceCompatProxy",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase$1": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase$1",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase",
+      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase$2": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase$2",
+      "android/support/v4/media/MediaBrowserServiceCompat$ResultFlags": "androidx/media/MediaBrowserServiceCompat$ResultFlags",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$1": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$1",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$2": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$2",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$3": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$3",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$4": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$4",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$5": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$5",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$6": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$6",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$7": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$7",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$8": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$8",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceBinderImpl$9": "androidx/media/MediaBrowserServiceCompat$ServiceBinderImpl$9",
+      "android/support/v4/media/MediaBrowserServiceCompat$ServiceCallbacksCompat": "androidx/media/MediaBrowserServiceCompat$ServiceCallbacksCompat",
+      "android/support/v4/media/MediaBrowserServiceCompatApi21$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi21$MediaBrowserServiceAdaptor",
+      "android/support/v4/media/MediaBrowserServiceCompatApi23$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi23$MediaBrowserServiceAdaptor",
+      "android/support/v4/media/MediaBrowserServiceCompatApi26$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi26$MediaBrowserServiceAdaptor",
+      "android/support/v4/media/MediaDescriptionCompat$1": "androidx/media/MediaDescriptionCompat$1",
+      "android/support/v4/media/MediaDescriptionCompatApi21": "androidx/media/MediaDescriptionCompatApi21",
+      "android/support/v4/media/MediaDescriptionCompat$Builder": "androidx/media/MediaDescriptionCompat$Builder",
+      "android/support/v4/media/MediaDescriptionCompatApi21$Builder": "androidx/media/MediaDescriptionCompatApi21$Builder",
+      "android/support/v4/media/MediaDescriptionCompatApi23$Builder": "androidx/media/MediaDescriptionCompatApi23$Builder",
+      "android/support/v4/media/MediaDescriptionCompatApi23": "androidx/media/MediaDescriptionCompatApi23",
+      "android/support/v4/media/MediaMetadataCompat$1": "androidx/media/MediaMetadataCompat$1",
+      "android/support/v4/media/MediaMetadataCompat$BitmapKey": "androidx/media/MediaMetadataCompat$BitmapKey",
+      "android/support/v4/media/MediaMetadataCompat$Builder": "androidx/media/MediaMetadataCompat$Builder",
+      "android/support/v4/media/RatingCompat": "androidx/media/RatingCompat",
+      "android/support/v4/media/MediaMetadataCompat$LongKey": "androidx/media/MediaMetadataCompat$LongKey",
+      "android/support/v4/media/MediaMetadataCompat$RatingKey": "androidx/media/MediaMetadataCompat$RatingKey",
+      "android/support/v4/media/MediaMetadataCompat$TextKey": "androidx/media/MediaMetadataCompat$TextKey",
+      "android/support/v4/media/MediaMetadataCompatApi21": "androidx/media/MediaMetadataCompatApi21",
+      "android/support/v4/media/MediaMetadataCompatApi21$Builder": "androidx/media/MediaMetadataCompatApi21$Builder",
+      "android/support/v4/media/ParceledListSliceAdapterApi21": "androidx/media/ParceledListSliceAdapterApi21",
+      "android/support/v4/media/RatingCompat$1": "androidx/media/RatingCompat$1",
+      "android/support/v4/media/RatingCompat$StarStyle": "androidx/media/RatingCompat$StarStyle",
+      "android/support/v4/media/RatingCompat$Style": "androidx/media/RatingCompat$Style",
+      "android/support/v4/media/VolumeProviderCompat$1": "androidx/media/VolumeProviderCompat$1",
+      "android/support/v4/media/VolumeProviderCompatApi21$Delegate": "androidx/media/VolumeProviderCompatApi21$Delegate",
+      "android/support/v4/media/VolumeProviderCompat": "androidx/media/VolumeProviderCompat",
+      "android/support/v4/media/VolumeProviderCompatApi21": "androidx/media/VolumeProviderCompatApi21",
+      "android/support/v4/media/VolumeProviderCompat$Callback": "androidx/media/VolumeProviderCompat$Callback",
+      "android/support/v4/media/VolumeProviderCompat$ControlType": "androidx/media/VolumeProviderCompat$ControlType",
+      "android/support/v4/media/VolumeProviderCompatApi21$1": "androidx/media/VolumeProviderCompatApi21$1",
+      "android/support/v4/media/app/NotificationCompat$DecoratedMediaCustomViewStyle": "androidx/media/app/NotificationCompat$DecoratedMediaCustomViewStyle",
+      "android/support/v4/media/app/NotificationCompat$MediaStyle": "androidx/media/app/NotificationCompat$MediaStyle",
+      "android/support/v4/media/app/NotificationCompat": "androidx/media/app/NotificationCompat",
+      "android/support/v4/app/NotificationCompat$Builder": "androidx/app/NotificationCompat$Builder",
+      "android/support/v4/app/NotificationCompat": "androidx/app/NotificationCompat",
+      "android/support/mediacompat/R$layout": "androidx/mediacompat/R$layout",
+      "android/support/mediacompat/R": "androidx/mediacompat/R",
+      "android/support/mediacompat/R$color": "androidx/mediacompat/R$color",
+      "android/support/mediacompat/R$id": "androidx/mediacompat/R$id",
+      "android/support/v4/app/NotificationBuilderWithBuilderAccessor": "androidx/app/NotificationBuilderWithBuilderAccessor",
+      "android/support/v4/app/NotificationCompat$Style": "androidx/app/NotificationCompat$Style",
+      "android/support/v4/app/NotificationCompat$Action": "androidx/app/NotificationCompat$Action",
+      "android/support/mediacompat/R$integer": "androidx/mediacompat/R$integer",
+      "android/support/v4/media/session/IMediaControllerCallback$Stub$Proxy": "androidx/media/session/IMediaControllerCallback$Stub$Proxy",
+      "android/support/v4/media/session/IMediaControllerCallback": "androidx/media/session/IMediaControllerCallback",
+      "android/support/v4/media/session/IMediaControllerCallback$Stub": "androidx/media/session/IMediaControllerCallback$Stub",
+      "android/support/v4/media/session/MediaSessionCompat$QueueItem": "androidx/media/session/MediaSessionCompat$QueueItem",
+      "android/support/v4/media/session/ParcelableVolumeInfo": "androidx/media/session/ParcelableVolumeInfo",
+      "android/support/v4/media/session/IMediaSession$Stub$Proxy": "androidx/media/session/IMediaSession$Stub$Proxy",
+      "android/support/v4/media/session/MediaSessionCompat$ResultReceiverWrapper": "androidx/media/session/MediaSessionCompat$ResultReceiverWrapper",
+      "android/support/v4/media/session/MediaButtonReceiver$MediaButtonConnectionCallback": "androidx/media/session/MediaButtonReceiver$MediaButtonConnectionCallback",
+      "android/support/v4/media/session/MediaButtonReceiver": "androidx/media/session/MediaButtonReceiver",
+      "android/support/v4/media/session/MediaControllerCompat$Callback$MessageHandler": "androidx/media/session/MediaControllerCompat$Callback$MessageHandler",
+      "android/support/v4/media/session/MediaControllerCompat$PlaybackInfo": "androidx/media/session/MediaControllerCompat$PlaybackInfo",
+      "android/support/v4/media/session/MediaControllerCompat$Callback$StubApi21": "androidx/media/session/MediaControllerCompat$Callback$StubApi21",
+      "android/support/v4/media/session/MediaControllerCompatApi21$Callback": "androidx/media/session/MediaControllerCompatApi21$Callback",
+      "android/support/v4/media/session/MediaControllerCompatApi21": "androidx/media/session/MediaControllerCompatApi21",
+      "android/support/v4/media/session/MediaControllerCompat$Callback$StubCompat": "androidx/media/session/MediaControllerCompat$Callback$StubCompat",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerExtraData": "androidx/media/session/MediaControllerCompat$MediaControllerExtraData",
+      "android/support/v4/app/SupportActivity$ExtraData": "androidx/app/SupportActivity$ExtraData",
+      "android/support/v4/app/SupportActivity": "androidx/app/SupportActivity",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImpl": "androidx/media/session/MediaControllerCompat$MediaControllerImpl",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraBinderRequestResultReceiver": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraBinderRequestResultReceiver",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraCallback": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraCallback",
+      "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi21": "androidx/media/session/MediaControllerCompat$TransportControlsApi21",
+      "android/support/v4/media/session/MediaControllerCompatApi21$PlaybackInfo": "androidx/media/session/MediaControllerCompatApi21$PlaybackInfo",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi23": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi23",
+      "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi23": "androidx/media/session/MediaControllerCompat$TransportControlsApi23",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi24": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi24",
+      "android/support/v4/media/session/MediaControllerCompat$TransportControlsApi24": "androidx/media/session/MediaControllerCompat$TransportControlsApi24",
+      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplBase": "androidx/media/session/MediaControllerCompat$MediaControllerImplBase",
+      "android/support/v4/media/session/MediaControllerCompat$TransportControlsBase": "androidx/media/session/MediaControllerCompat$TransportControlsBase",
+      "android/support/v4/media/session/PlaybackStateCompat$CustomAction": "androidx/media/session/PlaybackStateCompat$CustomAction",
+      "android/support/v4/media/session/MediaControllerCompatApi21$TransportControls": "androidx/media/session/MediaControllerCompatApi21$TransportControls",
+      "android/support/v4/media/session/MediaControllerCompatApi23$TransportControls": "androidx/media/session/MediaControllerCompatApi23$TransportControls",
+      "android/support/v4/media/session/MediaControllerCompatApi23": "androidx/media/session/MediaControllerCompatApi23",
+      "android/support/v4/media/session/MediaControllerCompatApi24$TransportControls": "androidx/media/session/MediaControllerCompatApi24$TransportControls",
+      "android/support/v4/media/session/MediaControllerCompatApi24": "androidx/media/session/MediaControllerCompatApi24",
+      "android/support/v4/media/session/MediaControllerCompatApi21$CallbackProxy": "androidx/media/session/MediaControllerCompatApi21$CallbackProxy",
+      "android/support/v4/media/session/MediaSessionCompat$1": "androidx/media/session/MediaSessionCompat$1",
+      "android/support/v4/media/session/MediaSessionCompat$Callback": "androidx/media/session/MediaSessionCompat$Callback",
+      "android/support/v4/media/session/MediaSessionCompat$2": "androidx/media/session/MediaSessionCompat$2",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImpl": "androidx/media/session/MediaSessionCompat$MediaSessionImpl",
+      "android/support/v4/media/session/MediaSessionCompat$Callback$CallbackHandler": "androidx/media/session/MediaSessionCompat$Callback$CallbackHandler",
+      "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi21": "androidx/media/session/MediaSessionCompat$Callback$StubApi21",
+      "android/support/v4/media/session/MediaSessionCompatApi21$Callback": "androidx/media/session/MediaSessionCompatApi21$Callback",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi21",
+      "android/support/v4/media/session/MediaSessionCompatApi21": "androidx/media/session/MediaSessionCompatApi21",
+      "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi23": "androidx/media/session/MediaSessionCompat$Callback$StubApi23",
+      "android/support/v4/media/session/MediaSessionCompatApi23$Callback": "androidx/media/session/MediaSessionCompatApi23$Callback",
+      "android/support/v4/media/session/MediaSessionCompatApi23": "androidx/media/session/MediaSessionCompatApi23",
+      "android/support/v4/media/session/MediaSessionCompat$Callback$StubApi24": "androidx/media/session/MediaSessionCompat$Callback$StubApi24",
+      "android/support/v4/media/session/MediaSessionCompatApi24$Callback": "androidx/media/session/MediaSessionCompatApi24$Callback",
+      "android/support/v4/media/session/MediaSessionCompatApi24": "androidx/media/session/MediaSessionCompatApi24",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi18$1": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi18$1",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi18": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi18",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi19$1": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi19$1",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi19": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi19",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi21$ExtraSession": "androidx/media/session/MediaSessionCompat$MediaSessionImplApi21$ExtraSession",
+      "android/support/v4/media/session/MediaSessionCompatApi22": "androidx/media/session/MediaSessionCompatApi22",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$1": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$1",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$Command": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$Command",
+      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MediaSessionStub": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MediaSessionStub",
+      "android/support/v4/media/session/MediaSessionCompat$OnActiveChangeListener": "androidx/media/session/MediaSessionCompat$OnActiveChangeListener",
+      "android/support/v4/media/session/MediaSessionCompat$QueueItem$1": "androidx/media/session/MediaSessionCompat$QueueItem$1",
+      "android/support/v4/media/session/MediaSessionCompatApi21$QueueItem": "androidx/media/session/MediaSessionCompatApi21$QueueItem",
+      "android/support/v4/media/session/MediaSessionCompat$ResultReceiverWrapper$1": "androidx/media/session/MediaSessionCompat$ResultReceiverWrapper$1",
+      "android/support/v4/media/session/MediaSessionCompat$SessionFlags": "androidx/media/session/MediaSessionCompat$SessionFlags",
+      "android/support/v4/media/session/MediaSessionCompat$Token$1": "androidx/media/session/MediaSessionCompat$Token$1",
+      "android/support/v4/media/session/PlaybackStateCompat$Builder": "androidx/media/session/PlaybackStateCompat$Builder",
+      "android/support/v4/media/session/MediaSessionCompatApi21$CallbackProxy": "androidx/media/session/MediaSessionCompatApi21$CallbackProxy",
+      "android/support/v4/media/session/MediaSessionCompatApi23$CallbackProxy": "androidx/media/session/MediaSessionCompatApi23$CallbackProxy",
+      "android/support/v4/media/session/MediaSessionCompatApi24$CallbackProxy": "androidx/media/session/MediaSessionCompatApi24$CallbackProxy",
+      "android/support/v4/media/session/ParcelableVolumeInfo$1": "androidx/media/session/ParcelableVolumeInfo$1",
+      "android/support/v4/media/session/PlaybackStateCompat$1": "androidx/media/session/PlaybackStateCompat$1",
+      "android/support/v4/media/session/PlaybackStateCompat$Actions": "androidx/media/session/PlaybackStateCompat$Actions",
+      "android/support/v4/media/session/PlaybackStateCompat$CustomAction$1": "androidx/media/session/PlaybackStateCompat$CustomAction$1",
+      "android/support/v4/media/session/PlaybackStateCompat$CustomAction$Builder": "androidx/media/session/PlaybackStateCompat$CustomAction$Builder",
+      "android/support/v4/media/session/PlaybackStateCompatApi21$CustomAction": "androidx/media/session/PlaybackStateCompatApi21$CustomAction",
+      "android/support/v4/media/session/PlaybackStateCompatApi21": "androidx/media/session/PlaybackStateCompatApi21",
+      "android/support/v4/media/session/PlaybackStateCompat$ErrorCode": "androidx/media/session/PlaybackStateCompat$ErrorCode",
+      "android/support/v4/media/session/PlaybackStateCompat$MediaKeyAction": "androidx/media/session/PlaybackStateCompat$MediaKeyAction",
+      "android/support/v4/media/session/PlaybackStateCompat$RepeatMode": "androidx/media/session/PlaybackStateCompat$RepeatMode",
+      "android/support/v4/media/session/PlaybackStateCompat$ShuffleMode": "androidx/media/session/PlaybackStateCompat$ShuffleMode",
+      "android/support/v4/media/session/PlaybackStateCompat$State": "androidx/media/session/PlaybackStateCompat$State",
+      "android/support/v4/media/session/PlaybackStateCompatApi22": "androidx/media/session/PlaybackStateCompatApi22",
+      "android/arch/lifecycle/ObserversCollector": "androidx/lifecycle/ObserversCollector",
+      "android/arch/lifecycle/Validator": "androidx/lifecycle/Validator",
+      "android/arch/lifecycle/model/LifecycleObserverInfo": "androidx/lifecycle/model/LifecycleObserverInfo",
+      "android/arch/lifecycle/Elements_extKt": "androidx/lifecycle/Elements_extKt",
+      "android/arch/lifecycle/model/AdapterClassKt": "androidx/lifecycle/model/AdapterClassKt",
+      "android/arch/lifecycle/OnLifecycleEvent": "androidx/lifecycle/OnLifecycleEvent",
+      "android/arch/lifecycle/model/EventMethod": "androidx/lifecycle/model/EventMethod",
+      "android/arch/lifecycle/WriterKt": "androidx/lifecycle/WriterKt",
+      "android/arch/lifecycle/WriterKt$generateParamString$1": "androidx/lifecycle/WriterKt$generateParamString$1",
+      "android/arch/lifecycle/model/AdapterClass": "androidx/lifecycle/model/AdapterClass",
+      "android/arch/lifecycle/model/EventMethodCall": "androidx/lifecycle/model/EventMethodCall",
+      "android/arch/lifecycle/GeneratedAdapter": "androidx/lifecycle/GeneratedAdapter",
+      "android/arch/lifecycle/LifecycleProcessor": "androidx/lifecycle/LifecycleProcessor",
+      "android/arch/lifecycle/MethodCallsLogger": "androidx/lifecycle/MethodCallsLogger",
+      "android/arch/lifecycle/TransformationKt": "androidx/lifecycle/TransformationKt",
+      "android/arch/lifecycle/TransformationKt$flattenObservers$1": "androidx/lifecycle/TransformationKt$flattenObservers$1",
+      "android/arch/lifecycle/model/InputModel": "androidx/lifecycle/model/InputModel",
+      "android/arch/lifecycle/ErrorMessages": "androidx/lifecycle/ErrorMessages",
+      "android/arch/lifecycle/Input_collectorKt": "androidx/lifecycle/Input_collectorKt",
+      "android/arch/persistence/db/framework/FrameworkSQLiteDatabase$1": "androidx/persistence/db/framework/FrameworkSQLiteDatabase$1",
+      "android/arch/persistence/db/framework/FrameworkSQLiteDatabase": "androidx/persistence/db/framework/FrameworkSQLiteDatabase",
+      "android/arch/persistence/db/SupportSQLiteQuery": "androidx/persistence/db/SupportSQLiteQuery",
+      "android/arch/persistence/db/framework/FrameworkSQLiteProgram": "androidx/persistence/db/framework/FrameworkSQLiteProgram",
+      "android/arch/persistence/db/SupportSQLiteProgram": "androidx/persistence/db/SupportSQLiteProgram",
+      "android/arch/persistence/db/framework/FrameworkSQLiteDatabase$2": "androidx/persistence/db/framework/FrameworkSQLiteDatabase$2",
+      "android/arch/persistence/db/SupportSQLiteDatabase": "androidx/persistence/db/SupportSQLiteDatabase",
+      "android/arch/persistence/db/SupportSQLiteStatement": "androidx/persistence/db/SupportSQLiteStatement",
+      "android/arch/persistence/db/framework/FrameworkSQLiteStatement": "androidx/persistence/db/framework/FrameworkSQLiteStatement",
+      "android/arch/persistence/db/SimpleSQLiteQuery": "androidx/persistence/db/SimpleSQLiteQuery",
+      "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper$OpenHelper$1": "androidx/persistence/db/framework/FrameworkSQLiteOpenHelper$OpenHelper$1",
+      "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper$OpenHelper": "androidx/persistence/db/framework/FrameworkSQLiteOpenHelper$OpenHelper",
+      "android/arch/persistence/db/SupportSQLiteOpenHelper$Callback": "androidx/persistence/db/SupportSQLiteOpenHelper$Callback",
+      "android/arch/persistence/db/SupportSQLiteOpenHelper": "androidx/persistence/db/SupportSQLiteOpenHelper",
+      "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper": "androidx/persistence/db/framework/FrameworkSQLiteOpenHelper",
+      "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory": "androidx/persistence/db/framework/FrameworkSQLiteOpenHelperFactory",
+      "android/arch/persistence/db/SupportSQLiteOpenHelper$Factory": "androidx/persistence/db/SupportSQLiteOpenHelper$Factory",
+      "android/arch/persistence/db/SupportSQLiteOpenHelper$Configuration": "androidx/persistence/db/SupportSQLiteOpenHelper$Configuration",
+      "android/arch/lifecycle/DefaultLifecycleObserver": "androidx/lifecycle/DefaultLifecycleObserver",
+      "android/arch/lifecycle/FullLifecycleObserver": "androidx/lifecycle/FullLifecycleObserver",
+      "android/support/v4/app/BackStackRecord$Op": "androidx/app/BackStackRecord$Op",
+      "android/support/v4/app/BackStackRecord": "androidx/app/BackStackRecord",
+      "android/support/v4/app/FragmentManagerImpl$OpGenerator": "androidx/app/FragmentManagerImpl$OpGenerator",
+      "android/support/v4/app/Fragment$OnStartEnterTransitionListener": "androidx/app/Fragment$OnStartEnterTransitionListener",
+      "android/support/v4/app/FragmentManagerImpl": "androidx/app/FragmentManagerImpl",
+      "android/support/v4/app/FragmentHostCallback": "androidx/app/FragmentHostCallback",
+      "android/support/v4/app/FragmentTransition": "androidx/app/FragmentTransition",
+      "android/support/v4/util/LogWriter": "androidx/util/LogWriter",
+      "android/support/v4/app/BackStackState$1": "androidx/app/BackStackState$1",
+      "android/support/v4/app/BackStackState": "androidx/app/BackStackState",
+      "android/support/v4/app/BaseFragmentActivityApi14": "androidx/app/BaseFragmentActivityApi14",
+      "android/support/v4/app/BaseFragmentActivityApi16": "androidx/app/BaseFragmentActivityApi16",
+      "android/support/v4/app/DialogFragment$DialogStyle": "androidx/app/DialogFragment$DialogStyle",
+      "android/support/v4/app/Fragment$1": "androidx/app/Fragment$1",
+      "android/support/v4/app/Fragment$2": "androidx/app/Fragment$2",
+      "android/support/v4/app/FragmentContainer": "androidx/app/FragmentContainer",
+      "android/support/v4/app/Fragment$AnimationInfo": "androidx/app/Fragment$AnimationInfo",
+      "android/support/v4/app/Fragment$InstantiationException": "androidx/app/Fragment$InstantiationException",
+      "android/support/v4/app/Fragment$SavedState$1": "androidx/app/Fragment$SavedState$1",
+      "android/support/v4/app/Fragment$SavedState": "androidx/app/Fragment$SavedState",
+      "android/support/v4/app/FragmentManagerNonConfig": "androidx/app/FragmentManagerNonConfig",
+      "android/support/v4/app/LoaderManagerImpl": "androidx/app/LoaderManagerImpl",
+      "android/support/v4/app/SuperNotCalledException": "androidx/app/SuperNotCalledException",
+      "android/support/v4/util/DebugUtils": "androidx/util/DebugUtils",
+      "android/support/v4/app/LoaderManager": "androidx/app/LoaderManager",
+      "android/support/v4/app/FragmentActivity$1": "androidx/app/FragmentActivity$1",
+      "android/support/v4/app/FragmentController": "androidx/app/FragmentController",
+      "android/support/v4/app/FragmentActivity$HostCallbacks": "androidx/app/FragmentActivity$HostCallbacks",
+      "android/support/v4/app/FragmentActivity$NonConfigurationInstances": "androidx/app/FragmentActivity$NonConfigurationInstances",
+      "android/support/v4/app/ActivityCompat$OnRequestPermissionsResultCallback": "androidx/app/ActivityCompat$OnRequestPermissionsResultCallback",
+      "android/support/v4/app/ActivityCompat$RequestPermissionsRequestCodeValidator": "androidx/app/ActivityCompat$RequestPermissionsRequestCodeValidator",
+      "android/support/v4/app/ActivityCompat$PermissionCompatDelegate": "androidx/app/ActivityCompat$PermissionCompatDelegate",
+      "android/support/v4/app/FragmentManagerImpl$1": "androidx/app/FragmentManagerImpl$1",
+      "android/support/v4/app/FragmentManagerImpl$2$1": "androidx/app/FragmentManagerImpl$2$1",
+      "android/support/v4/app/FragmentManagerImpl$2": "androidx/app/FragmentManagerImpl$2",
+      "android/support/v4/app/FragmentManagerImpl$AnimationListenerWrapper": "androidx/app/FragmentManagerImpl$AnimationListenerWrapper",
+      "android/support/v4/app/FragmentManagerImpl$AnimationOrAnimator": "androidx/app/FragmentManagerImpl$AnimationOrAnimator",
+      "android/support/v4/app/FragmentManagerImpl$3": "androidx/app/FragmentManagerImpl$3",
+      "android/support/v4/app/FragmentManagerImpl$4": "androidx/app/FragmentManagerImpl$4",
+      "android/support/v4/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener$1": "androidx/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener$1",
+      "android/support/v4/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener": "androidx/app/FragmentManagerImpl$AnimateOnHWLayerIfNeededListener",
+      "android/support/v4/app/FragmentManagerImpl$AnimatorOnHWLayerIfNeededListener": "androidx/app/FragmentManagerImpl$AnimatorOnHWLayerIfNeededListener",
+      "android/support/v4/app/FragmentManagerImpl$FragmentTag": "androidx/app/FragmentManagerImpl$FragmentTag",
+      "android/support/v4/app/FragmentManagerImpl$PopBackStackState": "androidx/app/FragmentManagerImpl$PopBackStackState",
+      "android/support/v4/app/FragmentManagerImpl$StartEnterTransitionListener": "androidx/app/FragmentManagerImpl$StartEnterTransitionListener",
+      "android/support/v4/util/ArraySet": "androidx/util/ArraySet",
+      "android/support/v4/app/FragmentState": "androidx/app/FragmentState",
+      "android/support/v4/app/FragmentManagerState": "androidx/app/FragmentManagerState",
+      "android/support/v4/app/FragmentManagerState$1": "androidx/app/FragmentManagerState$1",
+      "android/support/v4/app/FragmentPagerAdapter": "androidx/app/FragmentPagerAdapter",
+      "android/support/v4/app/FragmentState$1": "androidx/app/FragmentState$1",
+      "android/support/v4/app/FragmentStatePagerAdapter": "androidx/app/FragmentStatePagerAdapter",
+      "android/support/v4/app/FragmentTabHost$DummyTabFactory": "androidx/app/FragmentTabHost$DummyTabFactory",
+      "android/support/v4/app/FragmentTabHost": "androidx/app/FragmentTabHost",
+      "android/support/v4/app/FragmentTabHost$SavedState$1": "androidx/app/FragmentTabHost$SavedState$1",
+      "android/support/v4/app/FragmentTabHost$SavedState": "androidx/app/FragmentTabHost$SavedState",
+      "android/support/v4/app/FragmentTabHost$TabInfo": "androidx/app/FragmentTabHost$TabInfo",
+      "android/support/v4/app/FragmentTransaction$Transit": "androidx/app/FragmentTransaction$Transit",
+      "android/support/annotation/AnimRes": "androidx/annotation/AnimRes",
+      "android/support/v4/app/FragmentTransition$1": "androidx/app/FragmentTransition$1",
+      "android/support/v4/app/FragmentTransitionImpl": "androidx/app/FragmentTransitionImpl",
+      "android/support/v4/app/FragmentTransition$2": "androidx/app/FragmentTransition$2",
+      "android/support/v4/app/FragmentTransition$3": "androidx/app/FragmentTransition$3",
+      "android/support/v4/app/FragmentTransition$FragmentContainerTransition": "androidx/app/FragmentTransition$FragmentContainerTransition",
+      "android/support/v4/app/FragmentTransition$4": "androidx/app/FragmentTransition$4",
+      "android/support/v4/app/OneShotPreDrawListener": "androidx/app/OneShotPreDrawListener",
+      "android/support/v4/app/FragmentTransitionCompat21": "androidx/app/FragmentTransitionCompat21",
+      "android/support/v4/app/FragmentTransitionCompat21$1": "androidx/app/FragmentTransitionCompat21$1",
+      "android/support/v4/app/FragmentTransitionCompat21$2": "androidx/app/FragmentTransitionCompat21$2",
+      "android/support/v4/app/FragmentTransitionCompat21$3": "androidx/app/FragmentTransitionCompat21$3",
+      "android/support/v4/app/FragmentTransitionCompat21$4": "androidx/app/FragmentTransitionCompat21$4",
+      "android/support/v4/app/FragmentTransitionImpl$1": "androidx/app/FragmentTransitionImpl$1",
+      "android/support/v4/app/FragmentTransitionImpl$2": "androidx/app/FragmentTransitionImpl$2",
+      "android/support/v4/app/FragmentTransitionImpl$3": "androidx/app/FragmentTransitionImpl$3",
+      "android/support/v4/view/ViewGroupCompat": "androidx/view/ViewGroupCompat",
+      "android/support/v4/app/ListFragment$1": "androidx/app/ListFragment$1",
+      "android/support/v4/app/ListFragment": "androidx/app/ListFragment",
+      "android/support/v4/app/ListFragment$2": "androidx/app/ListFragment$2",
+      "android/support/v4/app/LoaderManager$LoaderCallbacks": "androidx/app/LoaderManager$LoaderCallbacks",
+      "android/support/v4/content/Loader": "androidx/content/Loader",
+      "android/support/v4/app/LoaderManagerImpl$LoaderInfo": "androidx/app/LoaderManagerImpl$LoaderInfo",
+      "android/support/v4/content/Loader$OnLoadCompleteListener": "androidx/content/Loader$OnLoadCompleteListener",
+      "android/support/v4/content/Loader$OnLoadCanceledListener": "androidx/content/Loader$OnLoadCanceledListener",
+      "android/arch/paging/LivePagedListBuilder$1$1": "androidx/paging/LivePagedListBuilder$1$1",
+      "android/arch/paging/DataSource$InvalidatedCallback": "androidx/paging/DataSource$InvalidatedCallback",
+      "android/arch/paging/LivePagedListBuilder$1": "androidx/paging/LivePagedListBuilder$1",
+      "android/arch/paging/DataSource": "androidx/paging/DataSource",
+      "android/arch/lifecycle/ComputableLiveData": "androidx/lifecycle/ComputableLiveData",
+      "android/arch/paging/PagedList": "androidx/paging/PagedList",
+      "android/arch/paging/LivePagedListBuilder": "androidx/paging/LivePagedListBuilder",
+      "android/arch/paging/PagedList$Config": "androidx/paging/PagedList$Config",
+      "android/arch/paging/PagedList$BoundaryCallback": "androidx/paging/PagedList$BoundaryCallback",
+      "android/arch/paging/DataSource$Factory": "androidx/paging/DataSource$Factory",
+      "android/arch/lifecycle/LiveData": "androidx/lifecycle/LiveData",
+      "android/arch/paging/PagedList$Builder": "androidx/paging/PagedList$Builder",
+      "android/arch/paging/PagedList$Config$Builder": "androidx/paging/PagedList$Config$Builder",
+      "android/arch/core/executor/ArchTaskExecutor": "androidx/core/executor/ArchTaskExecutor",
+      "android/support/annotation/AnyThread": "androidx/annotation/AnyThread",
+      "android/arch/paging/LivePagedListProvider": "androidx/paging/LivePagedListProvider",
+      "android/arch/paging/PagedListAdapter$1": "androidx/paging/PagedListAdapter$1",
+      "android/arch/paging/PagedListAdapterHelper$PagedListListener": "androidx/paging/PagedListAdapterHelper$PagedListListener",
+      "android/arch/paging/PagedListAdapter": "androidx/paging/PagedListAdapter",
+      "android/arch/paging/PagedListAdapterHelper": "androidx/paging/PagedListAdapterHelper",
+      "android/support/v7/recyclerview/extensions/ListAdapterHelper$AdapterCallback": "androidx/widget/recyclerview/ListAdapterHelper$AdapterCallback",
+      "android/support/v7/recyclerview/extensions/ListAdapterHelper": "androidx/widget/recyclerview/ListAdapterHelper",
+      "android/support/v7/recyclerview/extensions/DiffCallback": "androidx/widget/recyclerview/DiffCallback",
+      "android/support/v7/recyclerview/extensions/ListAdapterConfig": "androidx/widget/recyclerview/ListAdapterConfig",
+      "android/arch/paging/PagedListAdapterHelper$1": "androidx/paging/PagedListAdapterHelper$1",
+      "android/arch/paging/PagedList$Callback": "androidx/paging/PagedList$Callback",
+      "android/arch/paging/PagedListAdapterHelper$2$1": "androidx/paging/PagedListAdapterHelper$2$1",
+      "android/arch/paging/PagedListAdapterHelper$2": "androidx/paging/PagedListAdapterHelper$2",
+      "android/arch/paging/PagedStorage": "androidx/paging/PagedStorage",
+      "android/arch/paging/PagedStorageDiffHelper": "androidx/paging/PagedStorageDiffHelper",
+      "android/support/v7/recyclerview/extensions/ListAdapterConfig$Builder": "androidx/widget/recyclerview/ListAdapterConfig$Builder",
+      "android/arch/paging/PagedStorageDiffHelper$1": "androidx/paging/PagedStorageDiffHelper$1",
+      "android/arch/paging/PagedStorageDiffHelper$OffsettingListUpdateCallback": "androidx/paging/PagedStorageDiffHelper$OffsettingListUpdateCallback",
+      "android/support/v7/recyclerview/extensions/ListAdapter": "androidx/widget/recyclerview/ListAdapter",
+      "android/support/v7/recyclerview/extensions/ListAdapterConfig$1": "androidx/widget/recyclerview/ListAdapterConfig$1",
+      "android/support/v7/recyclerview/extensions/ListAdapterHelper$1$1": "androidx/widget/recyclerview/ListAdapterHelper$1$1",
+      "android/support/v7/recyclerview/extensions/ListAdapterHelper$1": "androidx/widget/recyclerview/ListAdapterHelper$1",
+      "android/support/v7/recyclerview/extensions/ListAdapterHelper$1$2": "androidx/widget/recyclerview/ListAdapterHelper$1$2",
+      "android/arch/paging/TiledPagedList$2": "androidx/paging/TiledPagedList$2",
+      "android/arch/paging/TiledPagedList": "androidx/paging/TiledPagedList",
+      "android/arch/paging/PageResult$Receiver": "androidx/paging/PageResult$Receiver",
+      "android/arch/paging/PageResult": "androidx/paging/PageResult",
+      "android/arch/paging/PositionalDataSource": "androidx/paging/PositionalDataSource",
+      "android/arch/paging/PagedList$1": "androidx/paging/PagedList$1",
+      "android/arch/paging/PositionalDataSource$ContiguousWithoutPlaceholdersWrapper": "androidx/paging/PositionalDataSource$ContiguousWithoutPlaceholdersWrapper",
+      "android/arch/paging/PositionalDataSource$LoadRangeCallback": "androidx/paging/PositionalDataSource$LoadRangeCallback",
+      "android/arch/paging/PositionalDataSource$LoadInitialCallback": "androidx/paging/PositionalDataSource$LoadInitialCallback",
+      "android/arch/paging/PositionalDataSource$LoadRangeParams": "androidx/paging/PositionalDataSource$LoadRangeParams",
+      "android/arch/paging/PositionalDataSource$LoadInitialParams": "androidx/paging/PositionalDataSource$LoadInitialParams",
+      "android/arch/paging/ContiguousDataSource": "androidx/paging/ContiguousDataSource",
+      "android/arch/paging/PageKeyedDataSource$LoadInitialParams": "androidx/paging/PageKeyedDataSource$LoadInitialParams",
+      "android/arch/paging/PageKeyedDataSource": "androidx/paging/PageKeyedDataSource",
+      "android/arch/paging/ItemKeyedDataSource$LoadParams": "androidx/paging/ItemKeyedDataSource$LoadParams",
+      "android/arch/paging/ItemKeyedDataSource": "androidx/paging/ItemKeyedDataSource",
+      "android/arch/paging/PagedStorage$Callback": "androidx/paging/PagedStorage$Callback",
+      "android/arch/paging/DataSource$BaseLoadCallback": "androidx/paging/DataSource$BaseLoadCallback",
+      "android/arch/paging/DataSource$BaseLoadCallback$1": "androidx/paging/DataSource$BaseLoadCallback$1",
+      "android/arch/paging/TiledPagedList$1": "androidx/paging/TiledPagedList$1",
+      "android/arch/paging/ListDataSource": "androidx/paging/ListDataSource",
+      "android/arch/paging/PagedList$2": "androidx/paging/PagedList$2",
+      "android/arch/paging/ContiguousPagedList$3": "androidx/paging/ContiguousPagedList$3",
+      "android/arch/paging/ContiguousPagedList": "androidx/paging/ContiguousPagedList",
+      "android/arch/paging/ItemKeyedDataSource$LoadInitialParams": "androidx/paging/ItemKeyedDataSource$LoadInitialParams",
+      "android/arch/paging/PageKeyedDataSource$LoadCallback": "androidx/paging/PageKeyedDataSource$LoadCallback",
+      "android/arch/paging/PageKeyedDataSource$LoadParams": "androidx/paging/PageKeyedDataSource$LoadParams",
+      "android/arch/paging/PageResult$ResultType": "androidx/paging/PageResult$ResultType",
+      "android/arch/paging/PageKeyedDataSource$LoadInitialCallback": "androidx/paging/PageKeyedDataSource$LoadInitialCallback",
+      "android/arch/paging/ContiguousPagedList$2": "androidx/paging/ContiguousPagedList$2",
+      "android/arch/paging/ContiguousPagedList$1": "androidx/paging/ContiguousPagedList$1",
+      "android/arch/paging/ItemKeyedDataSource$LoadCallback": "androidx/paging/ItemKeyedDataSource$LoadCallback",
+      "android/arch/paging/ItemKeyedDataSource$LoadInitialCallback": "androidx/paging/ItemKeyedDataSource$LoadInitialCallback",
+      "android/arch/paging/SnapshotPagedList": "androidx/paging/SnapshotPagedList",
+      "android/arch/paging/TiledDataSource": "androidx/paging/TiledDataSource",
+      "android/support/text/emoji/widget/EmojiAppCompatButton": "androidx/text/emoji/widget/EmojiAppCompatButton",
+      "android/support/text/emoji/widget/EmojiTextViewHelper": "androidx/text/emoji/widget/EmojiTextViewHelper",
+      "android/support/text/emoji/widget/EmojiAppCompatEditText": "androidx/text/emoji/widget/EmojiAppCompatEditText",
+      "android/support/text/emoji/widget/EmojiEditTextHelper": "androidx/text/emoji/widget/EmojiEditTextHelper",
+      "android/support/text/emoji/widget/EditTextAttributeHelper": "androidx/text/emoji/widget/EditTextAttributeHelper",
+      "android/support/text/emoji/widget/EmojiAppCompatTextView": "androidx/text/emoji/widget/EmojiAppCompatTextView",
+      "android/support/annotation/AnyRes": "androidx/annotation/AnyRes",
+      "android/support/annotation/BinderThread": "androidx/annotation/BinderThread",
+      "android/support/annotation/BoolRes": "androidx/annotation/BoolRes",
+      "android/support/annotation/CheckResult": "androidx/annotation/CheckResult",
+      "android/support/annotation/ColorLong": "androidx/annotation/ColorLong",
+      "android/support/annotation/DimenRes": "androidx/annotation/DimenRes",
+      "android/support/annotation/Dimension": "androidx/annotation/Dimension",
+      "android/support/annotation/FontRes": "androidx/annotation/FontRes",
+      "android/support/annotation/FractionRes": "androidx/annotation/FractionRes",
+      "android/support/annotation/HalfFloat": "androidx/annotation/HalfFloat",
+      "android/support/annotation/IntDef": "androidx/annotation/IntDef",
+      "android/support/annotation/IntegerRes": "androidx/annotation/IntegerRes",
+      "android/support/annotation/InterpolatorRes": "androidx/annotation/InterpolatorRes",
+      "android/support/annotation/Keep": "androidx/annotation/Keep",
+      "android/support/annotation/LongDef": "androidx/annotation/LongDef",
+      "android/support/annotation/NavigationRes": "androidx/annotation/NavigationRes",
+      "android/support/annotation/PluralsRes": "androidx/annotation/PluralsRes",
+      "android/support/annotation/Px": "androidx/annotation/Px",
+      "android/support/annotation/RawRes": "androidx/annotation/RawRes",
+      "android/support/annotation/RequiresPermission$Write": "androidx/annotation/RequiresPermission$Write",
+      "android/support/annotation/Size": "androidx/annotation/Size",
+      "android/support/annotation/StringDef": "androidx/annotation/StringDef",
+      "android/support/annotation/TransitionRes": "androidx/annotation/TransitionRes",
+      "android/support/v7/util/AsyncListUtil$1": "androidx/widget/recyclerview/AsyncListUtil$1",
+      "android/support/v7/util/ThreadUtil$MainThreadCallback": "androidx/widget/recyclerview/ThreadUtil$MainThreadCallback",
+      "android/support/v7/util/AsyncListUtil": "androidx/widget/recyclerview/AsyncListUtil",
+      "android/support/v7/util/TileList$Tile": "androidx/widget/recyclerview/TileList$Tile",
+      "android/support/v7/util/TileList": "androidx/widget/recyclerview/TileList",
+      "android/support/v7/util/ThreadUtil": "androidx/widget/recyclerview/ThreadUtil",
+      "android/support/v7/util/AsyncListUtil$ViewCallback": "androidx/widget/recyclerview/AsyncListUtil$ViewCallback",
+      "android/support/v7/util/ThreadUtil$BackgroundCallback": "androidx/widget/recyclerview/ThreadUtil$BackgroundCallback",
+      "android/support/v7/util/AsyncListUtil$2": "androidx/widget/recyclerview/AsyncListUtil$2",
+      "android/support/v7/util/AsyncListUtil$DataCallback": "androidx/widget/recyclerview/AsyncListUtil$DataCallback",
+      "android/support/v7/util/MessageThreadUtil": "androidx/widget/recyclerview/MessageThreadUtil",
+      "android/support/v7/util/BatchingListUpdateCallback": "androidx/widget/recyclerview/BatchingListUpdateCallback",
+      "android/support/v7/util/DiffUtil$1": "androidx/widget/recyclerview/DiffUtil$1",
+      "android/support/v7/util/DiffUtil$Snake": "androidx/widget/recyclerview/DiffUtil$Snake",
+      "android/support/v7/util/DiffUtil$DiffResult$1": "androidx/widget/recyclerview/DiffUtil$DiffResult$1",
+      "android/support/v7/util/DiffUtil$PostponedUpdate": "androidx/widget/recyclerview/DiffUtil$PostponedUpdate",
+      "android/support/v7/util/DiffUtil$ItemCallback": "androidx/widget/recyclerview/DiffUtil$ItemCallback",
+      "android/support/v7/util/DiffUtil$Range": "androidx/widget/recyclerview/DiffUtil$Range",
+      "android/support/v7/util/MessageThreadUtil$1$1": "androidx/widget/recyclerview/MessageThreadUtil$1$1",
+      "android/support/v7/util/MessageThreadUtil$1": "androidx/widget/recyclerview/MessageThreadUtil$1",
+      "android/support/v7/util/MessageThreadUtil$SyncQueueItem": "androidx/widget/recyclerview/MessageThreadUtil$SyncQueueItem",
+      "android/support/v7/util/MessageThreadUtil$MessageQueue": "androidx/widget/recyclerview/MessageThreadUtil$MessageQueue",
+      "android/support/v7/util/MessageThreadUtil$2$1": "androidx/widget/recyclerview/MessageThreadUtil$2$1",
+      "android/support/v7/util/MessageThreadUtil$2": "androidx/widget/recyclerview/MessageThreadUtil$2",
+      "android/support/v7/util/SortedList$BatchedCallback": "androidx/widget/recyclerview/SortedList$BatchedCallback",
+      "android/support/v7/util/SortedList$Callback": "androidx/widget/recyclerview/SortedList$Callback",
+      "android/support/v7/util/SortedList": "androidx/widget/recyclerview/SortedList",
+      "android/support/v7/widget/AdapterHelper$Callback": "androidx/widget/recyclerview/AdapterHelper$Callback",
+      "android/support/v7/widget/AdapterHelper$UpdateOp": "androidx/widget/recyclerview/AdapterHelper$UpdateOp",
+      "android/support/v7/widget/AdapterHelper": "androidx/widget/recyclerview/AdapterHelper",
+      "android/support/v7/widget/OpReorderer$Callback": "androidx/widget/recyclerview/OpReorderer$Callback",
+      "android/support/v7/widget/OpReorderer": "androidx/widget/recyclerview/OpReorderer",
+      "android/support/v7/widget/ChildHelper$Bucket": "androidx/widget/recyclerview/ChildHelper$Bucket",
+      "android/support/v7/widget/ChildHelper": "androidx/widget/recyclerview/ChildHelper",
+      "android/support/v7/widget/ChildHelper$Callback": "androidx/widget/recyclerview/ChildHelper$Callback",
+      "android/support/v7/widget/DefaultItemAnimator$1": "androidx/widget/recyclerview/DefaultItemAnimator$1",
+      "android/support/v7/widget/DefaultItemAnimator": "androidx/widget/recyclerview/DefaultItemAnimator",
+      "android/support/v7/widget/DefaultItemAnimator$MoveInfo": "androidx/widget/recyclerview/DefaultItemAnimator$MoveInfo",
+      "android/support/v7/widget/DefaultItemAnimator$2": "androidx/widget/recyclerview/DefaultItemAnimator$2",
+      "android/support/v7/widget/DefaultItemAnimator$ChangeInfo": "androidx/widget/recyclerview/DefaultItemAnimator$ChangeInfo",
+      "android/support/v7/widget/DefaultItemAnimator$3": "androidx/widget/recyclerview/DefaultItemAnimator$3",
+      "android/support/v7/widget/DefaultItemAnimator$4": "androidx/widget/recyclerview/DefaultItemAnimator$4",
+      "android/support/v7/widget/DefaultItemAnimator$5": "androidx/widget/recyclerview/DefaultItemAnimator$5",
+      "android/support/v7/widget/DefaultItemAnimator$6": "androidx/widget/recyclerview/DefaultItemAnimator$6",
+      "android/support/v7/widget/DefaultItemAnimator$7": "androidx/widget/recyclerview/DefaultItemAnimator$7",
+      "android/support/v7/widget/DefaultItemAnimator$8": "androidx/widget/recyclerview/DefaultItemAnimator$8",
+      "android/support/v7/widget/DividerItemDecoration": "androidx/widget/recyclerview/DividerItemDecoration",
+      "android/support/v7/widget/FastScroller$1": "androidx/widget/recyclerview/FastScroller$1",
+      "android/support/v7/widget/FastScroller": "androidx/widget/recyclerview/FastScroller",
+      "android/support/v7/widget/FastScroller$2": "androidx/widget/recyclerview/FastScroller$2",
+      "android/support/v7/widget/FastScroller$AnimationState": "androidx/widget/recyclerview/FastScroller$AnimationState",
+      "android/support/v7/widget/FastScroller$AnimatorListener": "androidx/widget/recyclerview/FastScroller$AnimatorListener",
+      "android/support/v7/widget/FastScroller$AnimatorUpdater": "androidx/widget/recyclerview/FastScroller$AnimatorUpdater",
+      "android/support/v7/widget/FastScroller$DragState": "androidx/widget/recyclerview/FastScroller$DragState",
+      "android/support/v7/widget/FastScroller$State": "androidx/widget/recyclerview/FastScroller$State",
+      "android/support/v7/widget/RecyclerView$OnItemTouchListener": "androidx/widget/recyclerview/RecyclerView$OnItemTouchListener",
+      "android/support/v7/widget/GapWorker$1": "androidx/widget/recyclerview/GapWorker$1",
+      "android/support/v7/widget/GapWorker$Task": "androidx/widget/recyclerview/GapWorker$Task",
+      "android/support/v7/widget/GapWorker": "androidx/widget/recyclerview/GapWorker",
+      "android/support/v7/widget/GapWorker$LayoutPrefetchRegistryImpl": "androidx/widget/recyclerview/GapWorker$LayoutPrefetchRegistryImpl",
+      "android/support/v4/os/TraceCompat": "androidx/os/TraceCompat",
+      "android/support/v7/widget/GridLayoutManager$DefaultSpanSizeLookup": "androidx/widget/recyclerview/GridLayoutManager$DefaultSpanSizeLookup",
+      "android/support/v7/widget/GridLayoutManager$SpanSizeLookup": "androidx/widget/recyclerview/GridLayoutManager$SpanSizeLookup",
+      "android/support/v7/widget/GridLayoutManager": "androidx/widget/recyclerview/GridLayoutManager",
+      "android/support/v7/widget/GridLayoutManager$LayoutParams": "androidx/widget/recyclerview/GridLayoutManager$LayoutParams",
+      "android/support/v7/widget/LinearLayoutManager$AnchorInfo": "androidx/widget/recyclerview/LinearLayoutManager$AnchorInfo",
+      "android/support/v7/widget/LinearLayoutManager$LayoutState": "androidx/widget/recyclerview/LinearLayoutManager$LayoutState",
+      "android/support/v7/widget/LinearLayoutManager$LayoutChunkResult": "androidx/widget/recyclerview/LinearLayoutManager$LayoutChunkResult",
+      "android/support/v7/widget/LinearLayoutManager$SavedState": "androidx/widget/recyclerview/LinearLayoutManager$SavedState",
+      "android/support/v7/widget/LayoutState": "androidx/widget/recyclerview/LayoutState",
+      "android/support/v7/widget/LinearLayoutManager$SavedState$1": "androidx/widget/recyclerview/LinearLayoutManager$SavedState$1",
+      "android/support/v7/widget/helper/ItemTouchHelper$ViewDropHandler": "androidx/widget/recyclerview/ItemTouchHelper$ViewDropHandler",
+      "android/support/v7/widget/RecyclerView$SmoothScroller$ScrollVectorProvider": "androidx/widget/recyclerview/RecyclerView$SmoothScroller$ScrollVectorProvider",
+      "android/support/v7/widget/helper/ItemTouchHelper": "androidx/widget/recyclerview/ItemTouchHelper",
+      "android/support/v7/widget/ScrollbarHelper": "androidx/widget/recyclerview/ScrollbarHelper",
+      "android/support/v7/widget/ViewBoundsCheck": "androidx/widget/recyclerview/ViewBoundsCheck",
+      "android/support/v7/widget/LinearSnapHelper": "androidx/widget/recyclerview/LinearSnapHelper",
+      "android/support/v7/widget/SnapHelper": "androidx/widget/recyclerview/SnapHelper",
+      "android/support/v7/widget/OrientationHelper$1": "androidx/widget/recyclerview/OrientationHelper$1",
+      "android/support/v7/widget/OrientationHelper$2": "androidx/widget/recyclerview/OrientationHelper$2",
+      "android/support/v7/widget/PagerSnapHelper$1": "androidx/widget/recyclerview/PagerSnapHelper$1",
+      "android/support/v7/widget/PagerSnapHelper": "androidx/widget/recyclerview/PagerSnapHelper",
+      "android/support/v7/widget/PositionMap$ContainerHelpers": "androidx/widget/recyclerview/PositionMap$ContainerHelpers",
+      "android/support/v7/widget/PositionMap": "androidx/widget/recyclerview/PositionMap",
+      "android/support/v7/widget/RecyclerView$1": "androidx/widget/recyclerview/RecyclerView$1",
+      "android/support/v7/widget/RecyclerView$2": "androidx/widget/recyclerview/RecyclerView$2",
+      "android/support/v7/widget/RecyclerView$3": "androidx/widget/recyclerview/RecyclerView$3",
+      "android/support/v7/widget/RecyclerView$4": "androidx/widget/recyclerview/RecyclerView$4",
+      "android/support/v7/widget/ViewInfoStore$ProcessCallback": "androidx/widget/recyclerview/ViewInfoStore$ProcessCallback",
+      "android/support/v7/widget/RecyclerView$ItemAnimator$ItemHolderInfo": "androidx/widget/recyclerview/RecyclerView$ItemAnimator$ItemHolderInfo",
+      "android/support/v7/widget/ViewInfoStore": "androidx/widget/recyclerview/ViewInfoStore",
+      "android/support/v7/widget/RecyclerView$5": "androidx/widget/recyclerview/RecyclerView$5",
+      "android/support/v7/widget/RecyclerView$6": "androidx/widget/recyclerview/RecyclerView$6",
+      "android/support/v7/widget/RecyclerView$AdapterDataObservable": "androidx/widget/recyclerview/RecyclerView$AdapterDataObservable",
+      "android/support/v7/widget/RecyclerView$ChildDrawingOrderCallback": "androidx/widget/recyclerview/RecyclerView$ChildDrawingOrderCallback",
+      "android/support/v7/widget/RecyclerView$EdgeEffectFactory$EdgeDirection": "androidx/widget/recyclerview/RecyclerView$EdgeEffectFactory$EdgeDirection",
+      "android/support/v7/widget/RecyclerView$EdgeEffectFactory": "androidx/widget/recyclerview/RecyclerView$EdgeEffectFactory",
+      "android/support/v7/widget/RecyclerView$ItemAnimator$AdapterChanges": "androidx/widget/recyclerview/RecyclerView$ItemAnimator$AdapterChanges",
+      "android/support/v7/widget/RecyclerView$ItemAnimator$ItemAnimatorFinishedListener": "androidx/widget/recyclerview/RecyclerView$ItemAnimator$ItemAnimatorFinishedListener",
+      "android/support/v7/widget/RecyclerView$ItemAnimator$ItemAnimatorListener": "androidx/widget/recyclerview/RecyclerView$ItemAnimator$ItemAnimatorListener",
+      "android/support/v7/widget/RecyclerView$ItemAnimatorRestoreListener": "androidx/widget/recyclerview/RecyclerView$ItemAnimatorRestoreListener",
+      "android/support/v7/widget/RecyclerView$LayoutManager$1": "androidx/widget/recyclerview/RecyclerView$LayoutManager$1",
+      "android/support/v7/widget/ViewBoundsCheck$Callback": "androidx/widget/recyclerview/ViewBoundsCheck$Callback",
+      "android/support/v7/widget/RecyclerView$LayoutManager$2": "androidx/widget/recyclerview/RecyclerView$LayoutManager$2",
+      "android/support/v7/recyclerview/R$styleable": "androidx/recyclerview/R$styleable",
+      "android/support/v7/recyclerview/R": "androidx/recyclerview/R",
+      "android/support/v7/widget/RecyclerView$OnChildAttachStateChangeListener": "androidx/widget/recyclerview/RecyclerView$OnChildAttachStateChangeListener",
+      "android/support/v7/widget/RecyclerView$OnFlingListener": "androidx/widget/recyclerview/RecyclerView$OnFlingListener",
+      "android/support/v7/widget/RecyclerView$Orientation": "androidx/widget/recyclerview/RecyclerView$Orientation",
+      "android/support/v7/widget/RecyclerView$RecycledViewPool$ScrapData": "androidx/widget/recyclerview/RecyclerView$RecycledViewPool$ScrapData",
+      "android/support/v7/widget/RecyclerView$ViewCacheExtension": "androidx/widget/recyclerview/RecyclerView$ViewCacheExtension",
+      "android/support/v7/widget/RecyclerView$RecyclerViewDataObserver": "androidx/widget/recyclerview/RecyclerView$RecyclerViewDataObserver",
+      "android/support/v7/widget/RecyclerView$SavedState$1": "androidx/widget/recyclerview/RecyclerView$SavedState$1",
+      "android/support/v7/widget/RecyclerView$SavedState": "androidx/widget/recyclerview/RecyclerView$SavedState",
+      "android/support/v7/widget/RecyclerView$SimpleOnItemTouchListener": "androidx/widget/recyclerview/RecyclerView$SimpleOnItemTouchListener",
+      "android/support/v7/widget/RecyclerView$ViewFlinger": "androidx/widget/recyclerview/RecyclerView$ViewFlinger",
+      "android/support/v7/widget/RecyclerView$State$LayoutState": "androidx/widget/recyclerview/RecyclerView$State$LayoutState",
+      "android/support/v7/recyclerview/R$dimen": "androidx/recyclerview/R$dimen",
+      "android/support/v4/view/ViewConfigurationCompat": "androidx/view/ViewConfigurationCompat",
+      "android/support/v4/view/MotionEventCompat": "androidx/view/MotionEventCompat",
+      "android/support/v7/widget/RecyclerViewAccessibilityDelegate$ItemDelegate": "androidx/widget/recyclerview/RecyclerViewAccessibilityDelegate$ItemDelegate",
+      "android/support/v7/widget/SnapHelper$1": "androidx/widget/recyclerview/SnapHelper$1",
+      "android/support/v7/widget/SnapHelper$2": "androidx/widget/recyclerview/SnapHelper$2",
+      "android/support/v7/widget/StaggeredGridLayoutManager$1": "androidx/widget/recyclerview/StaggeredGridLayoutManager$1",
+      "android/support/v7/widget/StaggeredGridLayoutManager": "androidx/widget/recyclerview/StaggeredGridLayoutManager",
+      "android/support/v7/widget/StaggeredGridLayoutManager$AnchorInfo": "androidx/widget/recyclerview/StaggeredGridLayoutManager$AnchorInfo",
+      "android/support/v7/widget/StaggeredGridLayoutManager$Span": "androidx/widget/recyclerview/StaggeredGridLayoutManager$Span",
+      "android/support/v7/widget/StaggeredGridLayoutManager$LayoutParams": "androidx/widget/recyclerview/StaggeredGridLayoutManager$LayoutParams",
+      "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem$1": "androidx/widget/recyclerview/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem$1",
+      "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem": "androidx/widget/recyclerview/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem",
+      "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup": "androidx/widget/recyclerview/StaggeredGridLayoutManager$LazySpanLookup",
+      "android/support/v7/widget/StaggeredGridLayoutManager$SavedState$1": "androidx/widget/recyclerview/StaggeredGridLayoutManager$SavedState$1",
+      "android/support/v7/widget/StaggeredGridLayoutManager$SavedState": "androidx/widget/recyclerview/StaggeredGridLayoutManager$SavedState",
+      "android/support/v7/widget/ViewBoundsCheck$BoundFlags": "androidx/widget/recyclerview/ViewBoundsCheck$BoundFlags",
+      "android/support/v7/widget/ViewBoundsCheck$ViewBounds": "androidx/widget/recyclerview/ViewBoundsCheck$ViewBounds",
+      "android/support/v7/widget/ViewInfoStore$InfoRecord": "androidx/widget/recyclerview/ViewInfoStore$InfoRecord",
+      "android/support/v7/widget/helper/ItemTouchHelper$1": "androidx/widget/recyclerview/ItemTouchHelper$1",
+      "android/support/v7/widget/helper/ItemTouchHelper$2": "androidx/widget/recyclerview/ItemTouchHelper$2",
+      "android/support/v7/widget/helper/ItemTouchHelper$RecoverAnimation": "androidx/widget/recyclerview/ItemTouchHelper$RecoverAnimation",
+      "android/support/v7/widget/helper/ItemTouchHelper$Callback": "androidx/widget/recyclerview/ItemTouchHelper$Callback",
+      "android/support/v4/view/GestureDetectorCompat": "androidx/view/GestureDetectorCompat",
+      "android/support/v7/widget/helper/ItemTouchHelper$3": "androidx/widget/recyclerview/ItemTouchHelper$3",
+      "android/support/v7/widget/helper/ItemTouchHelper$4": "androidx/widget/recyclerview/ItemTouchHelper$4",
+      "android/support/v7/widget/helper/ItemTouchHelper$5": "androidx/widget/recyclerview/ItemTouchHelper$5",
+      "android/support/v7/widget/helper/ItemTouchHelper$Callback$1": "androidx/widget/recyclerview/ItemTouchHelper$Callback$1",
+      "android/support/v7/widget/helper/ItemTouchHelper$Callback$2": "androidx/widget/recyclerview/ItemTouchHelper$Callback$2",
+      "android/support/v7/widget/helper/ItemTouchUIUtilImpl$Api21Impl": "androidx/widget/recyclerview/ItemTouchUIUtilImpl$Api21Impl",
+      "android/support/v7/widget/helper/ItemTouchUIUtilImpl": "androidx/widget/recyclerview/ItemTouchUIUtilImpl",
+      "android/support/v7/widget/helper/ItemTouchUIUtilImpl$BaseImpl": "androidx/widget/recyclerview/ItemTouchUIUtilImpl$BaseImpl",
+      "android/support/v7/widget/helper/ItemTouchUIUtil": "androidx/widget/recyclerview/ItemTouchUIUtil",
+      "android/support/v7/widget/helper/ItemTouchHelper$ItemTouchHelperGestureListener": "androidx/widget/recyclerview/ItemTouchHelper$ItemTouchHelperGestureListener",
+      "android/support/v7/widget/helper/ItemTouchHelper$RecoverAnimation$1": "androidx/widget/recyclerview/ItemTouchHelper$RecoverAnimation$1",
+      "android/support/v7/widget/helper/ItemTouchHelper$SimpleCallback": "androidx/widget/recyclerview/ItemTouchHelper$SimpleCallback",
+      "android/support/v7/recyclerview/R$id": "androidx/recyclerview/R$id",
+      "android/support/v7/widget/util/SortedListAdapterCallback": "androidx/widget/recyclerview/SortedListAdapterCallback",
+      "android/arch/persistence/db/SupportSQLiteOpenHelper$Configuration$Builder": "androidx/persistence/db/SupportSQLiteOpenHelper$Configuration$Builder",
+      "android/arch/persistence/db/SupportSQLiteQueryBuilder": "androidx/persistence/db/SupportSQLiteQueryBuilder",
+      "android/support/v7/graphics/ColorCutQuantizer$1": "androidx/graphics/palette/ColorCutQuantizer$1",
+      "android/support/v7/graphics/ColorCutQuantizer$Vbox": "androidx/graphics/palette/ColorCutQuantizer$Vbox",
+      "android/support/v7/graphics/ColorCutQuantizer": "androidx/graphics/palette/ColorCutQuantizer",
+      "android/support/v7/graphics/Palette$Swatch": "androidx/graphics/palette/Palette$Swatch",
+      "android/support/v7/graphics/Palette": "androidx/graphics/palette/Palette",
+      "android/support/v7/graphics/Palette$Filter": "androidx/graphics/palette/Palette$Filter",
+      "android/support/v7/graphics/Palette$1": "androidx/graphics/palette/Palette$1",
+      "android/support/v7/graphics/Palette$Builder$1": "androidx/graphics/palette/Palette$Builder$1",
+      "android/support/v7/graphics/Palette$Builder": "androidx/graphics/palette/Palette$Builder",
+      "android/support/v7/graphics/Palette$PaletteAsyncListener": "androidx/graphics/palette/Palette$PaletteAsyncListener",
+      "android/support/v7/graphics/Target": "androidx/graphics/palette/Target",
+      "android/support/v7/graphics/Target$Builder": "androidx/graphics/palette/Target$Builder",
+      "android/support/v13/view/DragAndDropPermissionsCompat": "androidx/view/DragAndDropPermissionsCompat",
+      "android/support/v13/view/DragStartHelper$1": "androidx/view/DragStartHelper$1",
+      "android/support/v13/view/DragStartHelper": "androidx/view/DragStartHelper",
+      "android/support/v13/view/DragStartHelper$2": "androidx/view/DragStartHelper$2",
+      "android/support/v13/view/DragStartHelper$OnDragStartListener": "androidx/view/DragStartHelper$OnDragStartListener",
+      "android/support/v13/view/inputmethod/EditorInfoCompat": "androidx/view/inputmethod/EditorInfoCompat",
+      "android/support/v13/view/inputmethod/InputConnectionCompat$1": "androidx/view/inputmethod/InputConnectionCompat$1",
+      "android/support/v13/view/inputmethod/InputConnectionCompat": "androidx/view/inputmethod/InputConnectionCompat",
+      "android/support/v13/view/inputmethod/InputConnectionCompat$OnCommitContentListener": "androidx/view/inputmethod/InputConnectionCompat$OnCommitContentListener",
       "android/support/v13/view/inputmethod/InputContentInfoCompat": "androidx/view/inputmethod/InputContentInfoCompat",
+      "android/support/v13/view/inputmethod/InputConnectionCompat$2": "androidx/view/inputmethod/InputConnectionCompat$2",
+      "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatApi25Impl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatApi25Impl",
+      "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatImpl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatImpl",
+      "android/support/v13/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatBaseImpl": "androidx/view/inputmethod/InputContentInfoCompat$InputContentInfoCompatBaseImpl",
+      "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": "androidx/accessibilityservice/AccessibilityServiceInfoCompat",
+      "android/support/v4/app/ActivityCompat$1": "androidx/app/ActivityCompat$1",
+      "android/support/v4/app/ActivityCompat$SharedElementCallback21Impl": "androidx/app/ActivityCompat$SharedElementCallback21Impl",
+      "android/support/v4/app/ActivityCompat$SharedElementCallback23Impl$1": "androidx/app/ActivityCompat$SharedElementCallback23Impl$1",
+      "android/support/v4/app/SharedElementCallback$OnSharedElementsReadyListener": "androidx/app/SharedElementCallback$OnSharedElementsReadyListener",
+      "android/support/v4/app/ActivityCompat$SharedElementCallback23Impl": "androidx/app/ActivityCompat$SharedElementCallback23Impl",
+      "android/support/v4/app/ActivityManagerCompat": "androidx/app/ActivityManagerCompat",
+      "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi16Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi16Impl",
+      "android/support/v4/app/ActivityOptionsCompat": "androidx/app/ActivityOptionsCompat",
+      "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi23Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi23Impl",
+      "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi24Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi24Impl",
+      "android/support/v4/app/AlarmManagerCompat": "androidx/app/AlarmManagerCompat",
+      "android/support/v4/app/AppOpsManagerCompat": "androidx/app/AppOpsManagerCompat",
+      "android/support/v4/app/BundleCompat$BundleCompatBaseImpl": "androidx/app/BundleCompat$BundleCompatBaseImpl",
+      "android/support/v4/app/INotificationSideChannel$Stub$Proxy": "androidx/app/INotificationSideChannel$Stub$Proxy",
+      "android/support/v4/app/INotificationSideChannel": "androidx/app/INotificationSideChannel",
+      "android/support/v4/app/INotificationSideChannel$Stub": "androidx/app/INotificationSideChannel$Stub",
+      "android/support/v4/app/JobIntentService$CommandProcessor": "androidx/app/JobIntentService$CommandProcessor",
+      "android/support/v4/app/JobIntentService": "androidx/app/JobIntentService",
+      "android/support/v4/app/JobIntentService$GenericWorkItem": "androidx/app/JobIntentService$GenericWorkItem",
+      "android/support/v4/app/JobIntentService$CompatJobEngine": "androidx/app/JobIntentService$CompatJobEngine",
+      "android/support/v4/app/JobIntentService$CompatWorkEnqueuer": "androidx/app/JobIntentService$CompatWorkEnqueuer",
+      "android/support/v4/app/JobIntentService$WorkEnqueuer": "androidx/app/JobIntentService$WorkEnqueuer",
+      "android/support/v4/app/JobIntentService$CompatWorkItem": "androidx/app/JobIntentService$CompatWorkItem",
+      "android/support/v4/app/JobIntentService$JobServiceEngineImpl$WrapperWorkItem": "androidx/app/JobIntentService$JobServiceEngineImpl$WrapperWorkItem",
+      "android/support/v4/app/JobIntentService$JobServiceEngineImpl": "androidx/app/JobIntentService$JobServiceEngineImpl",
+      "android/support/v4/app/JobIntentService$JobWorkEnqueuer": "androidx/app/JobIntentService$JobWorkEnqueuer",
+      "android/support/v4/app/NotificationCompat$Action$Builder": "androidx/app/NotificationCompat$Action$Builder",
+      "android/support/v4/app/NotificationCompat$Action$Extender": "androidx/app/NotificationCompat$Action$Extender",
+      "android/support/v4/app/RemoteInput": "androidx/app/RemoteInput",
+      "android/support/v4/app/NotificationCompat$Action$WearableExtender": "androidx/app/NotificationCompat$Action$WearableExtender",
+      "android/support/v4/app/NotificationCompat$BadgeIconType": "androidx/app/NotificationCompat$BadgeIconType",
+      "android/support/v4/app/NotificationCompat$BigPictureStyle": "androidx/app/NotificationCompat$BigPictureStyle",
+      "android/support/v4/app/NotificationCompat$BigTextStyle": "androidx/app/NotificationCompat$BigTextStyle",
+      "android/support/v4/app/NotificationCompat$Extender": "androidx/app/NotificationCompat$Extender",
+      "android/support/v4/app/NotificationCompatBuilder": "androidx/app/NotificationCompatBuilder",
+      "android/support/v4/app/NotificationCompat$CarExtender$UnreadConversation$Builder": "androidx/app/NotificationCompat$CarExtender$UnreadConversation$Builder",
+      "android/support/v4/app/NotificationCompat$CarExtender": "androidx/app/NotificationCompat$CarExtender",
+      "android/support/v4/app/NotificationCompat$CarExtender$UnreadConversation": "androidx/app/NotificationCompat$CarExtender$UnreadConversation",
+      "android/support/v4/app/NotificationCompat$DecoratedCustomViewStyle": "androidx/app/NotificationCompat$DecoratedCustomViewStyle",
+      "android/support/compat/R$layout": "androidx/compat/R$layout",
+      "android/support/compat/R": "androidx/compat/R",
+      "android/support/compat/R$id": "androidx/compat/R$id",
+      "android/support/compat/R$color": "androidx/compat/R$color",
+      "android/support/v4/app/NotificationCompat$GroupAlertBehavior": "androidx/app/NotificationCompat$GroupAlertBehavior",
+      "android/support/v4/app/NotificationCompat$InboxStyle": "androidx/app/NotificationCompat$InboxStyle",
+      "android/support/v4/app/NotificationCompat$MessagingStyle$Message": "androidx/app/NotificationCompat$MessagingStyle$Message",
+      "android/support/v4/app/NotificationCompat$MessagingStyle": "androidx/app/NotificationCompat$MessagingStyle",
+      "android/support/v4/text/BidiFormatter": "androidx/text/BidiFormatter",
+      "android/support/v4/app/NotificationCompat$NotificationVisibility": "androidx/app/NotificationCompat$NotificationVisibility",
+      "android/support/v4/app/NotificationCompat$StreamType": "androidx/app/NotificationCompat$StreamType",
+      "android/support/compat/R$drawable": "androidx/compat/R$drawable",
+      "android/support/compat/R$dimen": "androidx/compat/R$dimen",
+      "android/support/compat/R$integer": "androidx/compat/R$integer",
+      "android/support/compat/R$string": "androidx/compat/R$string",
+      "android/support/v4/app/NotificationCompat$WearableExtender": "androidx/app/NotificationCompat$WearableExtender",
+      "android/support/v4/app/NotificationCompatJellybean": "androidx/app/NotificationCompatJellybean",
+      "android/support/v4/app/NotificationCompatExtras": "androidx/app/NotificationCompatExtras",
+      "android/support/v4/app/NotificationCompatSideChannelService$NotificationSideChannelStub": "androidx/app/NotificationCompatSideChannelService$NotificationSideChannelStub",
+      "android/support/v4/app/NotificationCompatSideChannelService": "androidx/app/NotificationCompatSideChannelService",
+      "android/support/v4/app/NotificationManagerCompat$CancelTask": "androidx/app/NotificationManagerCompat$CancelTask",
+      "android/support/v4/app/NotificationManagerCompat$Task": "androidx/app/NotificationManagerCompat$Task",
+      "android/support/v4/app/NotificationManagerCompat": "androidx/app/NotificationManagerCompat",
+      "android/support/v4/app/NotificationManagerCompat$NotifyTask": "androidx/app/NotificationManagerCompat$NotifyTask",
+      "android/support/v4/app/NotificationManagerCompat$ServiceConnectedEvent": "androidx/app/NotificationManagerCompat$ServiceConnectedEvent",
+      "android/support/v4/app/NotificationManagerCompat$SideChannelManager$ListenerRecord": "androidx/app/NotificationManagerCompat$SideChannelManager$ListenerRecord",
+      "android/support/v4/app/NotificationManagerCompat$SideChannelManager": "androidx/app/NotificationManagerCompat$SideChannelManager",
+      "android/support/v4/app/RemoteInput$Builder": "androidx/app/RemoteInput$Builder",
+      "android/support/v4/app/RemoteInputCompatBase$RemoteInput": "androidx/app/RemoteInputCompatBase$RemoteInput",
+      "android/support/v4/app/RemoteInputCompatBase": "androidx/app/RemoteInputCompatBase",
+      "android/support/v4/app/RemoteInputCompatBase$RemoteInput$Factory": "androidx/app/RemoteInputCompatBase$RemoteInput$Factory",
+      "android/support/v4/app/ServiceCompat$StopForegroundFlags": "androidx/app/ServiceCompat$StopForegroundFlags",
+      "android/support/v4/app/ServiceCompat": "androidx/app/ServiceCompat",
+      "android/support/v4/app/ShareCompat$IntentBuilder": "androidx/app/ShareCompat$IntentBuilder",
+      "android/support/v4/app/ShareCompat": "androidx/app/ShareCompat",
+      "android/support/v4/app/ShareCompat$IntentReader": "androidx/app/ShareCompat$IntentReader",
+      "android/support/v4/content/ContentResolverCompat": "androidx/content/ContentResolverCompat",
+      "android/support/v4/os/CancellationSignal": "androidx/os/CancellationSignal",
+      "android/support/v4/os/OperationCanceledException": "androidx/os/OperationCanceledException",
+      "android/support/v4/content/IntentCompat": "androidx/content/IntentCompat",
+      "android/support/v4/content/SharedPreferencesCompat$EditorCompat$Helper": "androidx/content/SharedPreferencesCompat$EditorCompat$Helper",
+      "android/support/v4/content/SharedPreferencesCompat$EditorCompat": "androidx/content/SharedPreferencesCompat$EditorCompat",
+      "android/support/v4/content/SharedPreferencesCompat": "androidx/content/SharedPreferencesCompat",
+      "android/support/v4/content/pm/ActivityInfoCompat": "androidx/content/pm/ActivityInfoCompat",
+      "android/support/v4/content/pm/ShortcutInfoCompat$1": "androidx/content/pm/ShortcutInfoCompat$1",
+      "android/support/v4/content/pm/ShortcutInfoCompat": "androidx/content/pm/ShortcutInfoCompat",
+      "android/support/v4/content/pm/ShortcutInfoCompat$Builder": "androidx/content/pm/ShortcutInfoCompat$Builder",
+      "android/support/v4/graphics/drawable/IconCompat": "androidx/graphics/drawable/IconCompat",
+      "android/support/v4/content/pm/ShortcutManagerCompat$1": "androidx/content/pm/ShortcutManagerCompat$1",
+      "android/support/v4/content/pm/ShortcutManagerCompat": "androidx/content/pm/ShortcutManagerCompat",
+      "android/support/v4/content/res/ConfigurationHelper": "androidx/content/res/ConfigurationHelper",
+      "android/support/v4/content/res/FontResourcesParserCompat$FamilyResourceEntry": "androidx/content/res/FontResourcesParserCompat$FamilyResourceEntry",
+      "android/support/v4/content/res/FontResourcesParserCompat": "androidx/content/res/FontResourcesParserCompat",
+      "android/support/v4/content/res/FontResourcesParserCompat$FetchStrategy": "androidx/content/res/FontResourcesParserCompat$FetchStrategy",
+      "android/support/v4/content/res/FontResourcesParserCompat$FontFamilyFilesResourceEntry": "androidx/content/res/FontResourcesParserCompat$FontFamilyFilesResourceEntry",
+      "android/support/v4/content/res/FontResourcesParserCompat$FontFileResourceEntry": "androidx/content/res/FontResourcesParserCompat$FontFileResourceEntry",
+      "android/support/v4/content/res/FontResourcesParserCompat$ProviderResourceEntry": "androidx/content/res/FontResourcesParserCompat$ProviderResourceEntry",
+      "android/support/v4/provider/FontRequest": "androidx/provider/FontRequest",
+      "android/support/compat/R$styleable": "androidx/compat/R$styleable",
+      "android/support/v4/content/res/ResourcesCompat$FontCallback$1": "androidx/content/res/ResourcesCompat$FontCallback$1",
+      "android/support/v4/content/res/ResourcesCompat$FontCallback$2": "androidx/content/res/ResourcesCompat$FontCallback$2",
+      "android/support/v4/provider/FontsContractCompat$FontRequestCallback": "androidx/provider/FontsContractCompat$FontRequestCallback",
+      "android/support/v4/provider/FontsContractCompat": "androidx/provider/FontsContractCompat",
+      "android/support/v4/graphics/TypefaceCompat": "androidx/graphics/TypefaceCompat",
+      "android/support/v4/database/DatabaseUtilsCompat": "androidx/database/DatabaseUtilsCompat",
+      "android/support/v4/graphics/BitmapCompat$BitmapCompatApi18Impl": "androidx/graphics/BitmapCompat$BitmapCompatApi18Impl",
+      "android/support/v4/graphics/BitmapCompat$BitmapCompatBaseImpl": "androidx/graphics/BitmapCompat$BitmapCompatBaseImpl",
+      "android/support/v4/graphics/BitmapCompat": "androidx/graphics/BitmapCompat",
+      "android/support/v4/graphics/BitmapCompat$BitmapCompatApi19Impl": "androidx/graphics/BitmapCompat$BitmapCompatApi19Impl",
+      "android/support/v4/graphics/PaintCompat": "androidx/graphics/PaintCompat",
+      "android/support/v4/graphics/PathParser$ExtractFloatResult": "androidx/graphics/PathParser$ExtractFloatResult",
+      "android/support/v4/graphics/TypefaceCompat$TypefaceCompatImpl": "androidx/graphics/TypefaceCompat$TypefaceCompatImpl",
+      "android/support/v4/provider/FontsContractCompat$FontInfo": "androidx/provider/FontsContractCompat$FontInfo",
+      "android/support/v4/graphics/TypefaceCompatApi26Impl": "androidx/graphics/TypefaceCompatApi26Impl",
+      "android/support/v4/graphics/TypefaceCompatApi24Impl": "androidx/graphics/TypefaceCompatApi24Impl",
+      "android/support/v4/graphics/TypefaceCompatApi21Impl": "androidx/graphics/TypefaceCompatApi21Impl",
+      "android/support/v4/graphics/TypefaceCompatBaseImpl": "androidx/graphics/TypefaceCompatBaseImpl",
+      "android/support/v4/graphics/TypefaceCompatUtil": "androidx/graphics/TypefaceCompatUtil",
+      "android/support/v4/graphics/TypefaceCompatBaseImpl$1": "androidx/graphics/TypefaceCompatBaseImpl$1",
+      "android/support/v4/graphics/TypefaceCompatBaseImpl$StyleExtractor": "androidx/graphics/TypefaceCompatBaseImpl$StyleExtractor",
+      "android/support/v4/graphics/TypefaceCompatBaseImpl$2": "androidx/graphics/TypefaceCompatBaseImpl$2",
+      "android/support/v4/graphics/drawable/WrappedDrawableApi21": "androidx/graphics/drawable/WrappedDrawableApi21",
+      "android/support/v4/graphics/drawable/WrappedDrawableApi19": "androidx/graphics/drawable/WrappedDrawableApi19",
+      "android/support/v4/graphics/drawable/WrappedDrawableApi14": "androidx/graphics/drawable/WrappedDrawableApi14",
+      "android/support/v4/graphics/drawable/WrappedDrawableApi14$DrawableWrapperState": "androidx/graphics/drawable/WrappedDrawableApi14$DrawableWrapperState",
+      "android/support/v4/graphics/drawable/WrappedDrawableApi14$DrawableWrapperStateBase": "androidx/graphics/drawable/WrappedDrawableApi14$DrawableWrapperStateBase",
+      "android/support/v4/graphics/drawable/WrappedDrawableApi19$DrawableWrapperStateKitKat": "androidx/graphics/drawable/WrappedDrawableApi19$DrawableWrapperStateKitKat",
+      "android/support/v4/graphics/drawable/WrappedDrawableApi21$DrawableWrapperStateLollipop": "androidx/graphics/drawable/WrappedDrawableApi21$DrawableWrapperStateLollipop",
+      "android/support/v4/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi14Impl": "androidx/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi14Impl",
+      "android/support/v4/hardware/display/DisplayManagerCompat": "androidx/hardware/display/DisplayManagerCompat",
+      "android/support/v4/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi17Impl": "androidx/hardware/display/DisplayManagerCompat$DisplayManagerCompatApi17Impl",
+      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$1": "androidx/hardware/fingerprint/FingerprintManagerCompat$1",
+      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat": "androidx/hardware/fingerprint/FingerprintManagerCompat",
+      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$AuthenticationCallback": "androidx/hardware/fingerprint/FingerprintManagerCompat$AuthenticationCallback",
+      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$AuthenticationResult": "androidx/hardware/fingerprint/FingerprintManagerCompat$AuthenticationResult",
+      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$CryptoObject": "androidx/hardware/fingerprint/FingerprintManagerCompat$CryptoObject",
+      "android/support/v4/net/ConnectivityManagerCompat$RestrictBackgroundStatus": "androidx/net/ConnectivityManagerCompat$RestrictBackgroundStatus",
+      "android/support/v4/net/ConnectivityManagerCompat": "androidx/net/ConnectivityManagerCompat",
+      "android/support/v4/net/DatagramSocketWrapper$DatagramSocketImplWrapper": "androidx/net/DatagramSocketWrapper$DatagramSocketImplWrapper",
+      "android/support/v4/net/DatagramSocketWrapper": "androidx/net/DatagramSocketWrapper",
+      "android/support/v4/net/TrafficStatsCompat": "androidx/net/TrafficStatsCompat",
+      "android/support/v4/os/BuildCompat": "androidx/os/BuildCompat",
+      "android/support/v4/os/CancellationSignal$OnCancelListener": "androidx/os/CancellationSignal$OnCancelListener",
+      "android/support/v4/os/ConfigurationCompat": "androidx/os/ConfigurationCompat",
+      "android/support/v4/os/LocaleListCompat": "androidx/os/LocaleListCompat",
+      "android/support/v4/os/EnvironmentCompat": "androidx/os/EnvironmentCompat",
+      "android/support/v4/os/IResultReceiver$Stub$Proxy": "androidx/os/IResultReceiver$Stub$Proxy",
+      "android/support/v4/os/IResultReceiver": "androidx/os/IResultReceiver",
+      "android/support/v4/os/IResultReceiver$Stub": "androidx/os/IResultReceiver$Stub",
+      "android/support/v4/os/LocaleHelper": "androidx/os/LocaleHelper",
+      "android/support/v4/os/LocaleListCompat$LocaleListCompatApi24Impl": "androidx/os/LocaleListCompat$LocaleListCompatApi24Impl",
+      "android/support/v4/os/LocaleListInterface": "androidx/os/LocaleListInterface",
+      "android/support/v4/os/LocaleListCompat$LocaleListCompatBaseImpl": "androidx/os/LocaleListCompat$LocaleListCompatBaseImpl",
+      "android/support/v4/os/LocaleListHelper": "androidx/os/LocaleListHelper",
+      "android/support/v4/os/ParcelableCompat$ParcelableCompatCreatorHoneycombMR2": "androidx/os/ParcelableCompat$ParcelableCompatCreatorHoneycombMR2",
+      "android/support/v4/os/ParcelableCompat": "androidx/os/ParcelableCompat",
+      "android/support/v4/os/ParcelableCompatCreatorCallbacks": "androidx/os/ParcelableCompatCreatorCallbacks",
+      "android/support/v4/os/ResultReceiver$1": "androidx/os/ResultReceiver$1",
+      "android/support/v4/os/ResultReceiver$MyResultReceiver": "androidx/os/ResultReceiver$MyResultReceiver",
+      "android/support/v4/os/ResultReceiver$MyRunnable": "androidx/os/ResultReceiver$MyRunnable",
+      "android/support/v4/os/UserManagerCompat": "androidx/os/UserManagerCompat",
+      "android/support/v4/provider/FontsContractCompat$1": "androidx/provider/FontsContractCompat$1",
+      "android/support/v4/provider/FontsContractCompat$TypefaceResult": "androidx/provider/FontsContractCompat$TypefaceResult",
+      "android/support/v4/provider/FontsContractCompat$2": "androidx/provider/FontsContractCompat$2",
+      "android/support/v4/provider/SelfDestructiveThread$ReplyCallback": "androidx/provider/SelfDestructiveThread$ReplyCallback",
+      "android/support/v4/provider/SelfDestructiveThread": "androidx/provider/SelfDestructiveThread",
+      "android/support/v4/provider/FontsContractCompat$3": "androidx/provider/FontsContractCompat$3",
+      "android/support/v4/provider/FontsContractCompat$4$1": "androidx/provider/FontsContractCompat$4$1",
+      "android/support/v4/provider/FontsContractCompat$4": "androidx/provider/FontsContractCompat$4",
+      "android/support/v4/provider/FontsContractCompat$4$2": "androidx/provider/FontsContractCompat$4$2",
+      "android/support/v4/provider/FontsContractCompat$4$3": "androidx/provider/FontsContractCompat$4$3",
+      "android/support/v4/provider/FontsContractCompat$4$4": "androidx/provider/FontsContractCompat$4$4",
+      "android/support/v4/provider/FontsContractCompat$4$5": "androidx/provider/FontsContractCompat$4$5",
+      "android/support/v4/provider/FontsContractCompat$4$6": "androidx/provider/FontsContractCompat$4$6",
+      "android/support/v4/provider/FontsContractCompat$4$7": "androidx/provider/FontsContractCompat$4$7",
+      "android/support/v4/provider/FontsContractCompat$4$8": "androidx/provider/FontsContractCompat$4$8",
+      "android/support/v4/provider/FontsContractCompat$4$9": "androidx/provider/FontsContractCompat$4$9",
+      "android/support/v4/provider/FontsContractCompat$FontFamilyResult": "androidx/provider/FontsContractCompat$FontFamilyResult",
+      "android/support/v4/provider/FontsContractCompat$5": "androidx/provider/FontsContractCompat$5",
+      "android/support/v4/provider/FontsContractCompat$Columns": "androidx/provider/FontsContractCompat$Columns",
+      "android/support/v4/provider/FontsContractCompat$FontFamilyResult$FontResultStatus": "androidx/provider/FontsContractCompat$FontFamilyResult$FontResultStatus",
+      "android/support/v4/provider/FontsContractCompat$FontRequestCallback$FontRequestFailReason": "androidx/provider/FontsContractCompat$FontRequestCallback$FontRequestFailReason",
+      "android/support/v4/provider/SelfDestructiveThread$1": "androidx/provider/SelfDestructiveThread$1",
+      "android/support/v4/provider/SelfDestructiveThread$2$1": "androidx/provider/SelfDestructiveThread$2$1",
+      "android/support/v4/provider/SelfDestructiveThread$2": "androidx/provider/SelfDestructiveThread$2",
+      "android/support/v4/provider/SelfDestructiveThread$3": "androidx/provider/SelfDestructiveThread$3",
+      "android/support/v4/text/BidiFormatter$1": "androidx/text/BidiFormatter$1",
+      "android/support/v4/text/BidiFormatter$Builder": "androidx/text/BidiFormatter$Builder",
+      "android/support/v4/text/TextDirectionHeuristicCompat": "androidx/text/TextDirectionHeuristicCompat",
+      "android/support/v4/text/BidiFormatter$DirectionalityEstimator": "androidx/text/BidiFormatter$DirectionalityEstimator",
+      "android/support/v4/text/TextDirectionHeuristicsCompat": "androidx/text/TextDirectionHeuristicsCompat",
+      "android/support/v4/text/TextUtilsCompat": "androidx/text/TextUtilsCompat",
+      "android/support/v4/text/ICUCompat": "androidx/text/ICUCompat",
+      "android/support/v4/text/TextDirectionHeuristicsCompat$AnyStrong": "androidx/text/TextDirectionHeuristicsCompat$AnyStrong",
+      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionAlgorithm": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionAlgorithm",
+      "android/support/v4/text/TextDirectionHeuristicsCompat$FirstStrong": "androidx/text/TextDirectionHeuristicsCompat$FirstStrong",
+      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicImpl": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicImpl",
+      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicInternal": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicInternal",
+      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale": "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale",
+      "android/support/v4/text/util/LinkifyCompat$1": "androidx/text/util/LinkifyCompat$1",
+      "android/support/v4/text/util/LinkifyCompat$LinkSpec": "androidx/text/util/LinkifyCompat$LinkSpec",
+      "android/support/v4/text/util/LinkifyCompat": "androidx/text/util/LinkifyCompat",
+      "android/support/v4/text/util/LinkifyCompat$LinkifyMask": "androidx/text/util/LinkifyCompat$LinkifyMask",
+      "android/support/v4/util/PatternsCompat": "androidx/util/PatternsCompat",
+      "android/support/v4/util/ArrayMap$1": "androidx/util/ArrayMap$1",
+      "android/support/v4/util/MapCollections": "androidx/util/MapCollections",
+      "android/support/v4/util/ArraySet$1": "androidx/util/ArraySet$1",
+      "android/support/v4/util/ContainerHelpers": "androidx/util/ContainerHelpers",
+      "android/support/v4/util/AtomicFile": "androidx/util/AtomicFile",
+      "android/support/v4/util/MapCollections$ArrayIterator": "androidx/util/MapCollections$ArrayIterator",
+      "android/support/v4/util/MapCollections$EntrySet": "androidx/util/MapCollections$EntrySet",
+      "android/support/v4/util/MapCollections$MapIterator": "androidx/util/MapCollections$MapIterator",
+      "android/support/v4/util/MapCollections$KeySet": "androidx/util/MapCollections$KeySet",
+      "android/support/v4/util/MapCollections$ValuesCollection": "androidx/util/MapCollections$ValuesCollection",
+      "android/support/v4/util/TimeUtils": "androidx/util/TimeUtils",
+      "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl$1": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl$1",
+      "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateApi16Impl",
+      "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl",
+      "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl$1": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl$1",
+      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImpl": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImpl",
+      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase$GestureHandler": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase$GestureHandler",
+      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase",
+      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplJellybeanMr2": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplJellybeanMr2",
+      "android/support/v4/view/InputDeviceCompat": "androidx/view/InputDeviceCompat",
+      "android/support/v4/view/LayoutInflaterCompat$Factory2Wrapper": "androidx/view/LayoutInflaterCompat$Factory2Wrapper",
+      "android/support/v4/view/LayoutInflaterFactory": "androidx/view/LayoutInflaterFactory",
+      "android/support/v4/view/LayoutInflaterCompat$LayoutInflaterCompatApi21Impl": "androidx/view/LayoutInflaterCompat$LayoutInflaterCompatApi21Impl",
+      "android/support/v4/view/LayoutInflaterCompat$LayoutInflaterCompatBaseImpl": "androidx/view/LayoutInflaterCompat$LayoutInflaterCompatBaseImpl",
+      "android/support/v4/view/MenuCompat": "androidx/view/MenuCompat",
+      "android/support/v4/view/MenuItemCompat$1": "androidx/view/MenuItemCompat$1",
+      "android/support/v4/view/MenuItemCompat$OnActionExpandListener": "androidx/view/MenuItemCompat$OnActionExpandListener",
+      "android/support/v4/view/MenuItemCompat$MenuItemCompatApi26Impl": "androidx/view/MenuItemCompat$MenuItemCompatApi26Impl",
+      "android/support/v4/view/MenuItemCompat$MenuItemCompatBaseImpl": "androidx/view/MenuItemCompat$MenuItemCompatBaseImpl",
+      "android/support/v4/view/MenuItemCompat$MenuVersionImpl": "androidx/view/MenuItemCompat$MenuVersionImpl",
+      "android/support/v4/view/PointerIconCompat": "androidx/view/PointerIconCompat",
+      "android/support/v4/view/ScaleGestureDetectorCompat": "androidx/view/ScaleGestureDetectorCompat",
+      "android/support/v4/view/VelocityTrackerCompat": "androidx/view/VelocityTrackerCompat",
+      "android/support/v4/view/ViewCompat$AccessibilityLiveRegion": "androidx/view/ViewCompat$AccessibilityLiveRegion",
+      "android/support/v4/view/ViewCompat$AutofillImportance": "androidx/view/ViewCompat$AutofillImportance",
+      "android/support/v4/view/ViewCompat$FocusDirection": "androidx/view/ViewCompat$FocusDirection",
+      "android/support/v4/view/ViewCompat$FocusRealDirection": "androidx/view/ViewCompat$FocusRealDirection",
+      "android/support/v4/view/ViewCompat$FocusRelativeDirection": "androidx/view/ViewCompat$FocusRelativeDirection",
+      "android/support/v4/view/ViewCompat$ImportantForAccessibility": "androidx/view/ViewCompat$ImportantForAccessibility",
+      "android/support/v4/view/ViewCompat$LayerType": "androidx/view/ViewCompat$LayerType",
+      "android/support/v4/view/ViewCompat$LayoutDirectionMode": "androidx/view/ViewCompat$LayoutDirectionMode",
+      "android/support/v4/view/ViewCompat$NestedScrollType": "androidx/view/ViewCompat$NestedScrollType",
+      "android/support/v4/view/ViewCompat$OverScroll": "androidx/view/ViewCompat$OverScroll",
+      "android/support/v4/view/ViewCompat$ResolvedLayoutDirectionMode": "androidx/view/ViewCompat$ResolvedLayoutDirectionMode",
+      "android/support/v4/view/ViewCompat$ScrollAxis": "androidx/view/ViewCompat$ScrollAxis",
+      "android/support/v4/view/ViewCompat$ScrollIndicators": "androidx/view/ViewCompat$ScrollIndicators",
+      "android/support/v4/view/ViewCompat$ViewCompatApi15Impl": "androidx/view/ViewCompat$ViewCompatApi15Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatBaseImpl": "androidx/view/ViewCompat$ViewCompatBaseImpl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi16Impl": "androidx/view/ViewCompat$ViewCompatApi16Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi17Impl": "androidx/view/ViewCompat$ViewCompatApi17Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi18Impl": "androidx/view/ViewCompat$ViewCompatApi18Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi19Impl": "androidx/view/ViewCompat$ViewCompatApi19Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi21Impl$1": "androidx/view/ViewCompat$ViewCompatApi21Impl$1",
+      "android/support/v4/view/ViewCompat$ViewCompatApi21Impl": "androidx/view/ViewCompat$ViewCompatApi21Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi23Impl": "androidx/view/ViewCompat$ViewCompatApi23Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi24Impl": "androidx/view/ViewCompat$ViewCompatApi24Impl",
+      "android/support/v4/view/ViewCompat$ViewCompatApi26Impl": "androidx/view/ViewCompat$ViewCompatApi26Impl",
+      "android/support/v4/view/ViewGroupCompat$ViewGroupCompatApi18Impl": "androidx/view/ViewGroupCompat$ViewGroupCompatApi18Impl",
+      "android/support/v4/view/ViewGroupCompat$ViewGroupCompatBaseImpl": "androidx/view/ViewGroupCompat$ViewGroupCompatBaseImpl",
+      "android/support/v4/view/ViewGroupCompat$ViewGroupCompatApi21Impl": "androidx/view/ViewGroupCompat$ViewGroupCompatApi21Impl",
+      "android/support/v4/view/ViewParentCompat$ViewParentCompatApi19Impl": "androidx/view/ViewParentCompat$ViewParentCompatApi19Impl",
+      "android/support/v4/view/ViewParentCompat$ViewParentCompatBaseImpl": "androidx/view/ViewParentCompat$ViewParentCompatBaseImpl",
+      "android/support/v4/view/ViewParentCompat$ViewParentCompatApi21Impl": "androidx/view/ViewParentCompat$ViewParentCompatApi21Impl",
+      "android/support/v4/view/ViewPropertyAnimatorCompat$1": "androidx/view/ViewPropertyAnimatorCompat$1",
+      "android/support/v4/view/ViewPropertyAnimatorCompat$2": "androidx/view/ViewPropertyAnimatorCompat$2",
+      "android/support/v4/view/ViewPropertyAnimatorCompat$ViewPropertyAnimatorListenerApi14": "androidx/view/ViewPropertyAnimatorCompat$ViewPropertyAnimatorListenerApi14",
+      "android/support/v4/view/WindowCompat": "androidx/view/WindowCompat",
+      "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListener": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListener",
+      "android/support/v4/view/accessibility/AccessibilityManagerCompat": "androidx/view/accessibility/AccessibilityManagerCompat",
+      "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerCompat": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerCompat",
+      "android/support/v4/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerWrapper": "androidx/view/accessibility/AccessibilityManagerCompat$AccessibilityStateChangeListenerWrapper",
+      "android/support/v4/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListener": "androidx/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListener",
+      "android/support/v4/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper": "androidx/view/accessibility/AccessibilityManagerCompat$TouchExplorationStateChangeListenerWrapper",
+      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat": "androidx/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat",
+      "android/support/v4/view/accessibility/AccessibilityWindowInfoCompat": "androidx/view/accessibility/AccessibilityWindowInfoCompat",
+      "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi16": "androidx/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi16",
+      "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi19": "androidx/view/accessibility/AccessibilityNodeProviderCompat$AccessibilityNodeProviderApi19",
+      "android/support/v4/view/animation/PathInterpolatorApi14": "androidx/view/animation/PathInterpolatorApi14",
+      "android/support/v4/view/animation/PathInterpolatorCompat": "androidx/view/animation/PathInterpolatorCompat",
+      "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatApi21Impl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatApi21Impl",
+      "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl",
+      "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatApi23Impl": "androidx/widget/CompoundButtonCompat$CompoundButtonCompatApi23Impl",
+      "android/support/v4/widget/EdgeEffectCompat$EdgeEffectApi21Impl": "androidx/widget/EdgeEffectCompat$EdgeEffectApi21Impl",
+      "android/support/v4/widget/EdgeEffectCompat$EdgeEffectBaseImpl": "androidx/widget/EdgeEffectCompat$EdgeEffectBaseImpl",
+      "android/support/v4/widget/ImageViewCompat$BaseViewCompatImpl": "androidx/widget/ImageViewCompat$BaseViewCompatImpl",
+      "android/support/v4/widget/ImageViewCompat$ImageViewCompatImpl": "androidx/widget/ImageViewCompat$ImageViewCompatImpl",
+      "android/support/v4/widget/ImageViewCompat$LollipopViewCompatImpl": "androidx/widget/ImageViewCompat$LollipopViewCompatImpl",
+      "android/support/v4/widget/ListPopupWindowCompat": "androidx/widget/ListPopupWindowCompat",
+      "android/support/v4/widget/PopupMenuCompat": "androidx/widget/PopupMenuCompat",
+      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi19Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi19Impl",
+      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatBaseImpl": "androidx/widget/PopupWindowCompat$PopupWindowCompatBaseImpl",
+      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi21Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi21Impl",
+      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi23Impl": "androidx/widget/PopupWindowCompat$PopupWindowCompatApi23Impl",
+      "android/support/v4/widget/ScrollerCompat": "androidx/widget/ScrollerCompat",
+      "android/support/v4/widget/TextViewCompat$AutoSizeTextType": "androidx/widget/TextViewCompat$AutoSizeTextType",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatApi16Impl": "androidx/widget/TextViewCompat$TextViewCompatApi16Impl",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatBaseImpl": "androidx/widget/TextViewCompat$TextViewCompatBaseImpl",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatApi17Impl": "androidx/widget/TextViewCompat$TextViewCompatApi17Impl",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatApi18Impl": "androidx/widget/TextViewCompat$TextViewCompatApi18Impl",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatApi23Impl": "androidx/widget/TextViewCompat$TextViewCompatApi23Impl",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatApi26Impl$1": "androidx/widget/TextViewCompat$TextViewCompatApi26Impl$1",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatApi26Impl": "androidx/widget/TextViewCompat$TextViewCompatApi26Impl",
+      "android/support/v4/widget/TextViewCompat$TextViewCompatApi27Impl": "androidx/widget/TextViewCompat$TextViewCompatApi27Impl",
+      "android/support/v13/app/ActivityCompat": "androidx/legacy/app/ActivityCompat",
+      "android/support/v13/app/FragmentCompat$FragmentCompatApi15Impl": "androidx/legacy/app/FragmentCompat$FragmentCompatApi15Impl",
+      "android/support/v13/app/FragmentCompat$FragmentCompatBaseImpl": "androidx/legacy/app/FragmentCompat$FragmentCompatBaseImpl",
+      "android/support/v13/app/FragmentCompat": "androidx/legacy/app/FragmentCompat",
+      "android/support/v13/app/FragmentCompat$FragmentCompatApi23Impl": "androidx/legacy/app/FragmentCompat$FragmentCompatApi23Impl",
+      "android/support/v13/app/FragmentCompat$FragmentCompatApi24Impl": "androidx/legacy/app/FragmentCompat$FragmentCompatApi24Impl",
+      "android/support/v13/app/FragmentCompat$FragmentCompatBaseImpl$1": "androidx/legacy/app/FragmentCompat$FragmentCompatBaseImpl$1",
+      "android/support/v13/app/FragmentCompat$OnRequestPermissionsResultCallback": "androidx/legacy/app/FragmentCompat$OnRequestPermissionsResultCallback",
+      "android/support/v13/app/FragmentCompat$FragmentCompatImpl": "androidx/legacy/app/FragmentCompat$FragmentCompatImpl",
+      "android/support/v13/app/FragmentCompat$PermissionCompatDelegate": "androidx/legacy/app/FragmentCompat$PermissionCompatDelegate",
+      "android/support/v13/app/FragmentPagerAdapter": "androidx/legacy/app/FragmentPagerAdapter",
+      "android/support/v13/app/FragmentStatePagerAdapter": "androidx/legacy/app/FragmentStatePagerAdapter",
+      "android/support/v13/app/FragmentTabHost$DummyTabFactory": "androidx/legacy/app/FragmentTabHost$DummyTabFactory",
+      "android/support/v13/app/FragmentTabHost": "androidx/legacy/app/FragmentTabHost",
+      "android/support/v13/app/FragmentTabHost$SavedState$1": "androidx/legacy/app/FragmentTabHost$SavedState$1",
+      "android/support/v13/app/FragmentTabHost$SavedState": "androidx/legacy/app/FragmentTabHost$SavedState",
+      "android/support/v13/app/FragmentTabHost$TabInfo": "androidx/legacy/app/FragmentTabHost$TabInfo",
+      "android/support/v13/view/ViewCompat": "androidx/legacy/view/ViewCompat",
+      "android/arch/core/executor/JunitTaskExecutorRule$1": "androidx/core/executor/JunitTaskExecutorRule$1",
+      "android/arch/core/executor/JunitTaskExecutorRule": "androidx/core/executor/JunitTaskExecutorRule",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread": "androidx/core/executor/TaskExecutorWithFakeMainThread",
+      "android/arch/core/executor/TaskExecutor": "androidx/core/executor/TaskExecutor",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread$1": "androidx/core/executor/TaskExecutorWithFakeMainThread$1",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread$LoggingThread": "androidx/core/executor/TaskExecutorWithFakeMainThread$LoggingThread",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread$2": "androidx/core/executor/TaskExecutorWithFakeMainThread$2",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread$3": "androidx/core/executor/TaskExecutorWithFakeMainThread$3",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread$4": "androidx/core/executor/TaskExecutorWithFakeMainThread$4",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread$LoggingThread$1": "androidx/core/executor/TaskExecutorWithFakeMainThread$LoggingThread$1",
+      "android/arch/core/executor/testing/CountingTaskExecutorRule$1": "androidx/core/executor/testing/CountingTaskExecutorRule$1",
+      "android/arch/core/executor/DefaultTaskExecutor": "androidx/core/executor/DefaultTaskExecutor",
+      "android/arch/core/executor/testing/CountingTaskExecutorRule": "androidx/core/executor/testing/CountingTaskExecutorRule",
+      "android/arch/core/executor/testing/CountingTaskExecutorRule$CountingRunnable": "androidx/core/executor/testing/CountingTaskExecutorRule$CountingRunnable",
+      "android/arch/core/executor/testing/InstantTaskExecutorRule$1": "androidx/core/executor/testing/InstantTaskExecutorRule$1",
+      "android/arch/core/executor/testing/InstantTaskExecutorRule": "androidx/core/executor/testing/InstantTaskExecutorRule",
+      "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout$1": "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout$1",
+      "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout": "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout",
+      "android/support/v17/preference/BaseLeanbackPreferenceFragment": "androidx/leanback/preference/BaseLeanbackPreferenceFragment",
+      "android/support/v17/preference/R$layout": "androidx/leanback/preference/R$layout",
+      "android/support/v17/preference/R": "androidx/leanback/preference/R",
+      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$AdapterMulti": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$AdapterMulti",
+      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$ViewHolder": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$ViewHolder",
+      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$ViewHolder$OnItemClickListener": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$ViewHolder$OnItemClickListener",
+      "android/support/v17/preference/LeanbackListPreferenceDialogFragment": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment",
+      "android/support/v17/preference/LeanbackListPreferenceDialogFragment$AdapterSingle": "androidx/leanback/preference/LeanbackListPreferenceDialogFragment$AdapterSingle",
+      "android/support/v17/preference/R$id": "androidx/leanback/preference/R$id",
+      "android/support/v17/preference/LeanbackPreferenceDialogFragment": "androidx/leanback/preference/LeanbackPreferenceDialogFragment",
+      "android/support/v17/preference/LeanbackPreferenceFragmentTransitionHelperApi21": "androidx/leanback/preference/LeanbackPreferenceFragmentTransitionHelperApi21",
+      "android/support/v17/preference/LeanbackPreferenceFragment": "androidx/leanback/preference/LeanbackPreferenceFragment",
+      "android/support/v17/preference/LeanbackSettingsFragment$1": "androidx/leanback/preference/LeanbackSettingsFragment$1",
+      "android/support/v17/preference/LeanbackSettingsFragment": "androidx/leanback/preference/LeanbackSettingsFragment",
+      "android/support/v17/preference/LeanbackSettingsFragment$DummyFragment": "androidx/leanback/preference/LeanbackSettingsFragment$DummyFragment",
+      "android/support/v17/preference/LeanbackSettingsFragment$RootViewOnKeyListener": "androidx/leanback/preference/LeanbackSettingsFragment$RootViewOnKeyListener",
+      "android/support/v17/preference/LeanbackSettingsRootView": "androidx/leanback/preference/LeanbackSettingsRootView",
+      "android/support/percent/PercentFrameLayout$LayoutParams": "androidx/widget/PercentFrameLayout$LayoutParams",
+      "android/support/percent/PercentLayoutHelper$PercentLayoutParams": "androidx/widget/PercentLayoutHelper$PercentLayoutParams",
+      "android/support/percent/PercentLayoutHelper$PercentLayoutInfo": "androidx/widget/PercentLayoutHelper$PercentLayoutInfo",
+      "android/support/percent/PercentLayoutHelper": "androidx/widget/PercentLayoutHelper",
+      "android/support/percent/PercentFrameLayout": "androidx/widget/PercentFrameLayout",
+      "android/support/percent/PercentLayoutHelper$PercentMarginLayoutParams": "androidx/widget/PercentLayoutHelper$PercentMarginLayoutParams",
+      "android/support/percent/R$styleable": "androidx/widget/R$styleable",
+      "android/support/percent/R": "androidx/widget/R",
+      "android/support/percent/PercentRelativeLayout$LayoutParams": "androidx/widget/PercentRelativeLayout$LayoutParams",
+      "android/support/percent/PercentRelativeLayout": "androidx/widget/PercentRelativeLayout",
+      "android/support/app/recommendation/ContentRecommendation$1": "androidx/app/recommendation/ContentRecommendation$1",
+      "android/support/app/recommendation/ContentRecommendation": "androidx/app/recommendation/ContentRecommendation",
+      "android/support/app/recommendation/ContentRecommendation$Builder": "androidx/app/recommendation/ContentRecommendation$Builder",
+      "android/support/app/recommendation/ContentRecommendation$IntentData": "androidx/app/recommendation/ContentRecommendation$IntentData",
+      "android/support/app/recommendation/ContentRecommendation$ContentMaturity": "androidx/app/recommendation/ContentRecommendation$ContentMaturity",
+      "android/support/app/recommendation/ContentRecommendation$ContentPricing": "androidx/app/recommendation/ContentRecommendation$ContentPricing",
+      "android/support/app/recommendation/ContentRecommendation$ContentStatus": "androidx/app/recommendation/ContentRecommendation$ContentStatus",
+      "android/support/app/recommendation/ContentRecommendation$ContentType": "androidx/app/recommendation/ContentRecommendation$ContentType",
+      "android/support/app/recommendation/ContentRecommendation$IntentType": "androidx/app/recommendation/ContentRecommendation$IntentType",
+      "android/support/app/recommendation/RecommendationExtender": "androidx/app/recommendation/RecommendationExtender",
+      "android/support/media/tv/BasePreviewProgram$AspectRatio": "androidx/media/tv/BasePreviewProgram$AspectRatio",
+      "android/support/media/tv/BasePreviewProgram": "androidx/media/tv/BasePreviewProgram",
+      "android/support/media/tv/BasePreviewProgram$Availability": "androidx/media/tv/BasePreviewProgram$Availability",
+      "android/support/media/tv/BasePreviewProgram$Builder": "androidx/media/tv/BasePreviewProgram$Builder",
+      "android/support/media/tv/BaseProgram$Builder": "androidx/media/tv/BaseProgram$Builder",
+      "android/support/media/tv/BaseProgram": "androidx/media/tv/BaseProgram",
+      "android/support/media/tv/TvContractCompat$PreviewPrograms": "androidx/media/tv/TvContractCompat$PreviewPrograms",
+      "android/support/media/tv/TvContractCompat": "androidx/media/tv/TvContractCompat",
+      "android/support/media/tv/BasePreviewProgram$InteractionType": "androidx/media/tv/BasePreviewProgram$InteractionType",
+      "android/support/media/tv/BasePreviewProgram$Type": "androidx/media/tv/BasePreviewProgram$Type",
+      "android/support/media/tv/TvContractCompat$PreviewProgramColumns": "androidx/media/tv/TvContractCompat$PreviewProgramColumns",
+      "android/support/media/tv/CollectionUtils": "androidx/media/tv/CollectionUtils",
+      "android/support/media/tv/TvContractCompat$BaseTvColumns": "androidx/media/tv/TvContractCompat$BaseTvColumns",
+      "android/support/media/tv/TvContractCompat$Programs": "androidx/media/tv/TvContractCompat$Programs",
+      "android/support/media/tv/TvContractCompat$ProgramColumns": "androidx/media/tv/TvContractCompat$ProgramColumns",
+      "android/support/media/tv/TvContractCompat$Programs$Genres": "androidx/media/tv/TvContractCompat$Programs$Genres",
+      "android/support/media/tv/TvContractUtils": "androidx/media/tv/TvContractUtils",
+      "android/support/media/tv/BaseProgram$ReviewRatingStyle": "androidx/media/tv/BaseProgram$ReviewRatingStyle",
+      "android/support/media/tv/Channel$1": "androidx/media/tv/Channel$1",
+      "android/support/media/tv/Channel": "androidx/media/tv/Channel",
+      "android/support/media/tv/Channel$Builder": "androidx/media/tv/Channel$Builder",
+      "android/support/media/tv/TvContractCompat$Channels": "androidx/media/tv/TvContractCompat$Channels",
+      "android/support/media/tv/ChannelLogoUtils": "androidx/media/tv/ChannelLogoUtils",
+      "android/support/media/tv/PreviewProgram$1": "androidx/media/tv/PreviewProgram$1",
+      "android/support/media/tv/PreviewProgram": "androidx/media/tv/PreviewProgram",
+      "android/support/media/tv/PreviewProgram$Builder": "androidx/media/tv/PreviewProgram$Builder",
+      "android/support/media/tv/Program$1": "androidx/media/tv/Program$1",
+      "android/support/media/tv/Program": "androidx/media/tv/Program",
+      "android/support/media/tv/Program$Builder": "androidx/media/tv/Program$Builder",
+      "android/support/media/tv/TvContractCompat$Channels$Logo": "androidx/media/tv/TvContractCompat$Channels$Logo",
+      "android/support/media/tv/TvContractCompat$Channels$ServiceType": "androidx/media/tv/TvContractCompat$Channels$ServiceType",
+      "android/support/media/tv/TvContractCompat$Channels$Type": "androidx/media/tv/TvContractCompat$Channels$Type",
+      "android/support/media/tv/TvContractCompat$Channels$VideoFormat": "androidx/media/tv/TvContractCompat$Channels$VideoFormat",
+      "android/support/media/tv/TvContractCompat$Channels$VideoResolution": "androidx/media/tv/TvContractCompat$Channels$VideoResolution",
+      "android/support/media/tv/TvContractCompat$Programs$Genres$Genre": "androidx/media/tv/TvContractCompat$Programs$Genres$Genre",
+      "android/support/media/tv/TvContractCompat$RecordedPrograms": "androidx/media/tv/TvContractCompat$RecordedPrograms",
+      "android/support/media/tv/TvContractCompat$WatchNextPrograms": "androidx/media/tv/TvContractCompat$WatchNextPrograms",
+      "android/support/media/tv/WatchNextProgram$1": "androidx/media/tv/WatchNextProgram$1",
+      "android/support/media/tv/WatchNextProgram": "androidx/media/tv/WatchNextProgram",
+      "android/support/media/tv/WatchNextProgram$Builder": "androidx/media/tv/WatchNextProgram$Builder",
+      "android/support/media/tv/WatchNextProgram$WatchNextType": "androidx/media/tv/WatchNextProgram$WatchNextType",
+      "android/support/v7/widget/CardView$1": "androidx/widget/CardView$1",
+      "android/support/v7/widget/CardViewDelegate": "androidx/widget/CardViewDelegate",
+      "android/support/v7/widget/CardView": "androidx/widget/CardView",
+      "android/support/v7/cardview/R$attr": "androidx/cardview/R$attr",
+      "android/support/v7/cardview/R": "androidx/cardview/R",
+      "android/support/v7/cardview/R$styleable": "androidx/cardview/R$styleable",
+      "android/support/v7/cardview/R$style": "androidx/cardview/R$style",
+      "android/support/v7/cardview/R$color": "androidx/cardview/R$color",
+      "android/support/v7/widget/CardViewImpl": "androidx/widget/CardViewImpl",
+      "android/support/v7/widget/CardViewApi21Impl": "androidx/widget/CardViewApi21Impl",
+      "android/support/v7/widget/CardViewApi17Impl": "androidx/widget/CardViewApi17Impl",
+      "android/support/v7/widget/CardViewBaseImpl": "androidx/widget/CardViewBaseImpl",
+      "android/support/v7/widget/CardViewApi17Impl$1": "androidx/widget/CardViewApi17Impl$1",
+      "android/support/v7/widget/RoundRectDrawableWithShadow$RoundRectHelper": "androidx/widget/RoundRectDrawableWithShadow$RoundRectHelper",
+      "android/support/v7/widget/RoundRectDrawableWithShadow": "androidx/widget/RoundRectDrawableWithShadow",
+      "android/support/v7/widget/RoundRectDrawable": "androidx/widget/RoundRectDrawable",
+      "android/support/v7/widget/CardViewBaseImpl$1": "androidx/widget/CardViewBaseImpl$1",
+      "android/support/v7/cardview/R$dimen": "androidx/cardview/R$dimen",
+      "android/arch/lifecycle/LiveData$1": "androidx/lifecycle/LiveData$1",
+      "android/arch/lifecycle/LiveData$AlwaysActiveObserver": "androidx/lifecycle/LiveData$AlwaysActiveObserver",
+      "android/arch/lifecycle/LiveData$ObserverWrapper": "androidx/lifecycle/LiveData$ObserverWrapper",
+      "android/arch/lifecycle/Observer": "androidx/lifecycle/Observer",
+      "android/arch/lifecycle/LiveData$LifecycleBoundObserver": "androidx/lifecycle/LiveData$LifecycleBoundObserver",
+      "android/arch/lifecycle/MutableLiveData": "androidx/lifecycle/MutableLiveData",
+      "android/arch/lifecycle/LiveDataReactiveStreams$LiveDataPublisher$LiveDataSubscription$1": "androidx/lifecycle/LiveDataReactiveStreams$LiveDataPublisher$LiveDataSubscription$1",
+      "android/arch/lifecycle/LiveDataReactiveStreams$LiveDataPublisher$LiveDataSubscription": "androidx/lifecycle/LiveDataReactiveStreams$LiveDataPublisher$LiveDataSubscription",
+      "android/arch/lifecycle/LiveDataReactiveStreams$LiveDataPublisher": "androidx/lifecycle/LiveDataReactiveStreams$LiveDataPublisher",
+      "android/arch/lifecycle/LiveDataReactiveStreams": "androidx/lifecycle/LiveDataReactiveStreams",
+      "android/arch/lifecycle/LiveDataReactiveStreams$LiveDataPublisher$LiveDataSubscription$2": "androidx/lifecycle/LiveDataReactiveStreams$LiveDataPublisher$LiveDataSubscription$2",
+      "android/arch/lifecycle/LiveDataReactiveStreams$PublisherLiveData$LiveDataSubscriber$1": "androidx/lifecycle/LiveDataReactiveStreams$PublisherLiveData$LiveDataSubscriber$1",
+      "android/arch/lifecycle/LiveDataReactiveStreams$PublisherLiveData$LiveDataSubscriber": "androidx/lifecycle/LiveDataReactiveStreams$PublisherLiveData$LiveDataSubscriber",
+      "android/arch/lifecycle/LiveDataReactiveStreams$PublisherLiveData": "androidx/lifecycle/LiveDataReactiveStreams$PublisherLiveData",
+      "android/support/v7/app/MediaRouteActionProvider$MediaRouterCallback": "androidx/app/MediaRouteActionProvider$MediaRouterCallback",
+      "android/support/v7/media/MediaRouter$Callback": "androidx/media/MediaRouter$Callback",
+      "android/support/v7/app/MediaRouteActionProvider": "androidx/app/MediaRouteActionProvider",
+      "android/support/v7/media/MediaRouter$RouteInfo": "androidx/media/MediaRouter$RouteInfo",
+      "android/support/v7/media/MediaRouter": "androidx/media/MediaRouter",
+      "android/support/v7/media/MediaRouter$ProviderInfo": "androidx/media/MediaRouter$ProviderInfo",
+      "android/support/v7/media/MediaRouteSelector": "androidx/media/MediaRouteSelector",
+      "android/support/v7/app/MediaRouteDialogFactory": "androidx/app/MediaRouteDialogFactory",
+      "android/support/v7/app/MediaRouteButton": "androidx/app/MediaRouteButton",
+      "android/support/v7/app/MediaRouteButton$MediaRouterCallback": "androidx/app/MediaRouteButton$MediaRouterCallback",
+      "android/support/v7/app/MediaRouteButton$RemoteIndicatorLoader": "androidx/app/MediaRouteButton$RemoteIndicatorLoader",
+      "android/support/v7/mediarouter/R$attr": "androidx/mediarouter/R$attr",
+      "android/support/v7/mediarouter/R": "androidx/mediarouter/R",
+      "android/support/v7/mediarouter/R$styleable": "androidx/mediarouter/R$styleable",
+      "android/support/v7/mediarouter/R$string": "androidx/mediarouter/R$string",
+      "android/support/v7/app/MediaRouterThemeHelper": "androidx/app/MediaRouterThemeHelper",
+      "android/support/v7/app/MediaRouteChooserDialogFragment": "androidx/app/MediaRouteChooserDialogFragment",
+      "android/support/v7/app/MediaRouteControllerDialogFragment": "androidx/app/MediaRouteControllerDialogFragment",
+      "android/support/v7/app/MediaRouteChooserDialog$1": "androidx/app/MediaRouteChooserDialog$1",
+      "android/support/v7/app/MediaRouteChooserDialog": "androidx/app/MediaRouteChooserDialog",
+      "android/support/v7/app/MediaRouteChooserDialog$MediaRouterCallback": "androidx/app/MediaRouteChooserDialog$MediaRouterCallback",
+      "android/support/v7/app/MediaRouteChooserDialog$RouteAdapter": "androidx/app/MediaRouteChooserDialog$RouteAdapter",
+      "android/support/v7/media/MediaRouter$RouteGroup": "androidx/media/MediaRouter$RouteGroup",
+      "android/support/v7/mediarouter/R$layout": "androidx/mediarouter/R$layout",
+      "android/support/v7/mediarouter/R$id": "androidx/mediarouter/R$id",
+      "android/support/v7/app/MediaRouteChooserDialog$RouteComparator": "androidx/app/MediaRouteChooserDialog$RouteComparator",
+      "android/support/v7/app/MediaRouteDialogHelper": "androidx/app/MediaRouteDialogHelper",
+      "android/support/v7/app/MediaRouteControllerDialog$1": "androidx/app/MediaRouteControllerDialog$1",
+      "android/support/v7/app/MediaRouteControllerDialog": "androidx/app/MediaRouteControllerDialog",
+      "android/support/v7/app/MediaRouteControllerDialog$10": "androidx/app/MediaRouteControllerDialog$10",
+      "android/support/v7/app/OverlayListView$OverlayObject$OnAnimationEndListener": "androidx/app/OverlayListView$OverlayObject$OnAnimationEndListener",
+      "android/support/v7/app/OverlayListView$OverlayObject": "androidx/app/OverlayListView$OverlayObject",
+      "android/support/v7/app/OverlayListView": "androidx/app/OverlayListView",
+      "android/support/v7/app/MediaRouteControllerDialog$VolumeGroupAdapter": "androidx/app/MediaRouteControllerDialog$VolumeGroupAdapter",
+      "android/support/v7/app/MediaRouteControllerDialog$11": "androidx/app/MediaRouteControllerDialog$11",
+      "android/support/v7/app/MediaRouteControllerDialog$12": "androidx/app/MediaRouteControllerDialog$12",
+      "android/support/v7/app/MediaRouteControllerDialog$2": "androidx/app/MediaRouteControllerDialog$2",
+      "android/support/v7/app/MediaRouteControllerDialog$3": "androidx/app/MediaRouteControllerDialog$3",
+      "android/support/v7/app/MediaRouteControllerDialog$4": "androidx/app/MediaRouteControllerDialog$4",
+      "android/support/v7/app/MediaRouteControllerDialog$5": "androidx/app/MediaRouteControllerDialog$5",
+      "android/support/v7/app/MediaRouteControllerDialog$6": "androidx/app/MediaRouteControllerDialog$6",
+      "android/support/v7/app/MediaRouteControllerDialog$7": "androidx/app/MediaRouteControllerDialog$7",
+      "android/support/v7/app/MediaRouteControllerDialog$8": "androidx/app/MediaRouteControllerDialog$8",
+      "android/support/v7/app/MediaRouteControllerDialog$9": "androidx/app/MediaRouteControllerDialog$9",
+      "android/support/v7/app/MediaRouteControllerDialog$ClickListener": "androidx/app/MediaRouteControllerDialog$ClickListener",
+      "android/support/v7/app/MediaRouteControllerDialog$FetchArtTask": "androidx/app/MediaRouteControllerDialog$FetchArtTask",
+      "android/support/v7/app/MediaRouteControllerDialog$MediaControllerCallback": "androidx/app/MediaRouteControllerDialog$MediaControllerCallback",
+      "android/support/v7/app/MediaRouteControllerDialog$MediaRouterCallback": "androidx/app/MediaRouteControllerDialog$MediaRouterCallback",
+      "android/support/v7/app/MediaRouteControllerDialog$VolumeChangeListener$1": "androidx/app/MediaRouteControllerDialog$VolumeChangeListener$1",
+      "android/support/v7/app/MediaRouteControllerDialog$VolumeChangeListener": "androidx/app/MediaRouteControllerDialog$VolumeChangeListener",
+      "android/support/v7/app/MediaRouteVolumeSlider": "androidx/app/MediaRouteVolumeSlider",
+      "android/support/v7/mediarouter/R$dimen": "androidx/mediarouter/R$dimen",
+      "android/support/v7/mediarouter/R$interpolator": "androidx/mediarouter/R$interpolator",
+      "android/support/v7/mediarouter/R$integer": "androidx/mediarouter/R$integer",
+      "android/support/v7/app/MediaRouteExpandCollapseButton": "androidx/app/MediaRouteExpandCollapseButton",
+      "android/support/v7/app/MediaRouteDiscoveryFragment$1": "androidx/app/MediaRouteDiscoveryFragment$1",
+      "android/support/v7/app/MediaRouteDiscoveryFragment": "androidx/app/MediaRouteDiscoveryFragment",
+      "android/support/v7/app/MediaRouteExpandCollapseButton$1": "androidx/app/MediaRouteExpandCollapseButton$1",
+      "android/support/v7/mediarouter/R$drawable": "androidx/mediarouter/R$drawable",
+      "android/support/v7/app/MediaRouterThemeHelper$ControllerColorType": "androidx/app/MediaRouterThemeHelper$ControllerColorType",
+      "android/support/v7/mediarouter/R$style": "androidx/mediarouter/R$style",
+      "android/support/v7/media/MediaControlIntent": "androidx/media/MediaControlIntent",
+      "android/support/v7/media/MediaItemMetadata": "androidx/media/MediaItemMetadata",
+      "android/support/v7/media/MediaItemStatus$Builder": "androidx/media/MediaItemStatus$Builder",
+      "android/support/v7/media/MediaItemStatus": "androidx/media/MediaItemStatus",
+      "android/support/v7/media/MediaRouteDescriptor$Builder": "androidx/media/MediaRouteDescriptor$Builder",
+      "android/support/v7/media/MediaRouteDescriptor": "androidx/media/MediaRouteDescriptor",
+      "android/support/v7/media/MediaRouteDiscoveryRequest": "androidx/media/MediaRouteDiscoveryRequest",
+      "android/support/v7/media/MediaRouteProvider$Callback": "androidx/media/MediaRouteProvider$Callback",
+      "android/support/v7/media/MediaRouteProvider": "androidx/media/MediaRouteProvider",
+      "android/support/v7/media/MediaRouteProviderDescriptor": "androidx/media/MediaRouteProviderDescriptor",
+      "android/support/v7/media/MediaRouteProvider$ProviderHandler": "androidx/media/MediaRouteProvider$ProviderHandler",
+      "android/support/v7/media/MediaRouteProvider$ProviderMetadata": "androidx/media/MediaRouteProvider$ProviderMetadata",
+      "android/support/v7/media/MediaRouteProvider$RouteController": "androidx/media/MediaRouteProvider$RouteController",
+      "android/support/v7/media/MediaRouter$ControlRequestCallback": "androidx/media/MediaRouter$ControlRequestCallback",
+      "android/support/v7/media/MediaRouteProviderDescriptor$1": "androidx/media/MediaRouteProviderDescriptor$1",
+      "android/support/v7/media/MediaRouteProviderDescriptor$Builder": "androidx/media/MediaRouteProviderDescriptor$Builder",
+      "android/support/v7/media/MediaRouteProviderProtocol": "androidx/media/MediaRouteProviderProtocol",
+      "android/support/v7/media/MediaRouteProviderService$1": "androidx/media/MediaRouteProviderService$1",
+      "android/support/v7/media/MediaRouteProviderService": "androidx/media/MediaRouteProviderService",
+      "android/support/v7/media/MediaRouteProviderService$ClientRecord": "androidx/media/MediaRouteProviderService$ClientRecord",
+      "android/support/v7/media/MediaRouteProviderService$PrivateHandler": "androidx/media/MediaRouteProviderService$PrivateHandler",
+      "android/support/v7/media/MediaRouteProviderService$ProviderCallback": "androidx/media/MediaRouteProviderService$ProviderCallback",
+      "android/support/v7/media/MediaRouteProviderService$ReceiveHandler": "androidx/media/MediaRouteProviderService$ReceiveHandler",
+      "android/support/v7/media/MediaRouteSelector$Builder": "androidx/media/MediaRouteSelector$Builder",
+      "android/support/v7/media/MediaRouter$1": "androidx/media/MediaRouter$1",
+      "android/support/v7/media/MediaRouter$CallbackFlags": "androidx/media/MediaRouter$CallbackFlags",
+      "android/support/v7/media/MediaRouter$CallbackRecord": "androidx/media/MediaRouter$CallbackRecord",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$1": "androidx/media/MediaRouter$GlobalMediaRouter$1",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter": "androidx/media/MediaRouter$GlobalMediaRouter",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$CallbackHandler": "androidx/media/MediaRouter$GlobalMediaRouter$CallbackHandler",
+      "android/support/v7/media/SystemMediaRouteProvider": "androidx/media/SystemMediaRouteProvider",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord$1$1": "androidx/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord$1$1",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord$1": "androidx/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord$1",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord": "androidx/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord$1$2": "androidx/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord$1$2",
+      "android/support/v7/media/RemoteControlClientCompat$PlaybackInfo": "androidx/media/RemoteControlClientCompat$PlaybackInfo",
+      "android/support/v7/media/RemoteControlClientCompat": "androidx/media/RemoteControlClientCompat",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$ProviderCallback": "androidx/media/MediaRouter$GlobalMediaRouter$ProviderCallback",
+      "android/support/v7/media/MediaRouter$GlobalMediaRouter$RemoteControlClientRecord": "androidx/media/MediaRouter$GlobalMediaRouter$RemoteControlClientRecord",
+      "android/support/v7/media/RemoteControlClientCompat$VolumeCallback": "androidx/media/RemoteControlClientCompat$VolumeCallback",
+      "android/support/v7/media/SystemMediaRouteProvider$SyncCallback": "androidx/media/SystemMediaRouteProvider$SyncCallback",
+      "android/support/v7/media/RegisteredMediaRouteProviderWatcher$Callback": "androidx/media/RegisteredMediaRouteProviderWatcher$Callback",
+      "android/support/v7/media/RegisteredMediaRouteProviderWatcher": "androidx/media/RegisteredMediaRouteProviderWatcher",
+      "android/support/v7/media/MediaRouter$RouteInfo$ConnectionState": "androidx/media/MediaRouter$RouteInfo$ConnectionState",
+      "android/support/v7/media/MediaRouter$RouteInfo$DeviceType": "androidx/media/MediaRouter$RouteInfo$DeviceType",
+      "android/support/v7/media/MediaRouter$RouteInfo$PlaybackType": "androidx/media/MediaRouter$RouteInfo$PlaybackType",
+      "android/support/v7/media/MediaRouter$RouteInfo$PlaybackVolume": "androidx/media/MediaRouter$RouteInfo$PlaybackVolume",
+      "android/support/v7/media/MediaRouterApi24$RouteInfo": "androidx/media/MediaRouterApi24$RouteInfo",
+      "android/support/v7/media/MediaRouterApi24": "androidx/media/MediaRouterApi24",
+      "android/support/v7/media/MediaRouterJellybean$Callback": "androidx/media/MediaRouterJellybean$Callback",
+      "android/support/v7/media/MediaRouterJellybean": "androidx/media/MediaRouterJellybean",
+      "android/support/v7/media/MediaRouterJellybean$CallbackProxy": "androidx/media/MediaRouterJellybean$CallbackProxy",
+      "android/support/v7/media/MediaRouterJellybean$GetDefaultRouteWorkaround": "androidx/media/MediaRouterJellybean$GetDefaultRouteWorkaround",
+      "android/support/v7/media/MediaRouterJellybean$RouteCategory": "androidx/media/MediaRouterJellybean$RouteCategory",
+      "android/support/v7/media/MediaRouterJellybean$RouteGroup": "androidx/media/MediaRouterJellybean$RouteGroup",
+      "android/support/v7/media/MediaRouterJellybean$RouteInfo": "androidx/media/MediaRouterJellybean$RouteInfo",
+      "android/support/v7/media/MediaRouterJellybean$SelectRouteWorkaround": "androidx/media/MediaRouterJellybean$SelectRouteWorkaround",
+      "android/support/v7/media/MediaRouterJellybean$UserRouteInfo": "androidx/media/MediaRouterJellybean$UserRouteInfo",
+      "android/support/v7/media/MediaRouterJellybean$VolumeCallback": "androidx/media/MediaRouterJellybean$VolumeCallback",
+      "android/support/v7/media/MediaRouterJellybean$VolumeCallbackProxy": "androidx/media/MediaRouterJellybean$VolumeCallbackProxy",
+      "android/support/v7/media/MediaRouterJellybeanMr1$ActiveScanWorkaround": "androidx/media/MediaRouterJellybeanMr1$ActiveScanWorkaround",
+      "android/support/v7/media/MediaRouterJellybeanMr1": "androidx/media/MediaRouterJellybeanMr1",
+      "android/support/v7/media/MediaRouterJellybeanMr1$Callback": "androidx/media/MediaRouterJellybeanMr1$Callback",
+      "android/support/v7/media/MediaRouterJellybeanMr1$CallbackProxy": "androidx/media/MediaRouterJellybeanMr1$CallbackProxy",
+      "android/support/v7/media/MediaRouterJellybeanMr1$IsConnectingWorkaround": "androidx/media/MediaRouterJellybeanMr1$IsConnectingWorkaround",
+      "android/support/v7/media/MediaRouterJellybeanMr1$RouteInfo": "androidx/media/MediaRouterJellybeanMr1$RouteInfo",
+      "android/support/v7/media/MediaRouterJellybeanMr2$RouteInfo": "androidx/media/MediaRouterJellybeanMr2$RouteInfo",
+      "android/support/v7/media/MediaRouterJellybeanMr2": "androidx/media/MediaRouterJellybeanMr2",
+      "android/support/v7/media/MediaRouterJellybeanMr2$UserRouteInfo": "androidx/media/MediaRouterJellybeanMr2$UserRouteInfo",
+      "android/support/v7/media/MediaSessionStatus$Builder": "androidx/media/MediaSessionStatus$Builder",
+      "android/support/v7/media/MediaSessionStatus": "androidx/media/MediaSessionStatus",
+      "android/support/v7/media/RegisteredMediaRouteProvider$Connection$1": "androidx/media/RegisteredMediaRouteProvider$Connection$1",
+      "android/support/v7/media/RegisteredMediaRouteProvider$Connection": "androidx/media/RegisteredMediaRouteProvider$Connection",
+      "android/support/v7/media/RegisteredMediaRouteProvider": "androidx/media/RegisteredMediaRouteProvider",
+      "android/support/v7/media/RegisteredMediaRouteProvider$Connection$2": "androidx/media/RegisteredMediaRouteProvider$Connection$2",
+      "android/support/v7/media/RegisteredMediaRouteProvider$ReceiveHandler": "androidx/media/RegisteredMediaRouteProvider$ReceiveHandler",
+      "android/support/v7/media/RegisteredMediaRouteProvider$PrivateHandler": "androidx/media/RegisteredMediaRouteProvider$PrivateHandler",
+      "android/support/v7/media/RegisteredMediaRouteProvider$Controller": "androidx/media/RegisteredMediaRouteProvider$Controller",
+      "android/support/v7/media/RegisteredMediaRouteProviderWatcher$1": "androidx/media/RegisteredMediaRouteProviderWatcher$1",
+      "android/support/v7/media/RegisteredMediaRouteProviderWatcher$2": "androidx/media/RegisteredMediaRouteProviderWatcher$2",
+      "android/support/v7/media/RemoteControlClientCompat$JellybeanImpl$VolumeCallbackWrapper": "androidx/media/RemoteControlClientCompat$JellybeanImpl$VolumeCallbackWrapper",
+      "android/support/v7/media/RemoteControlClientCompat$JellybeanImpl": "androidx/media/RemoteControlClientCompat$JellybeanImpl",
+      "android/support/v7/media/RemoteControlClientCompat$LegacyImpl": "androidx/media/RemoteControlClientCompat$LegacyImpl",
+      "android/support/v7/media/RemotePlaybackClient$1": "androidx/media/RemotePlaybackClient$1",
+      "android/support/v7/media/RemotePlaybackClient": "androidx/media/RemotePlaybackClient",
+      "android/support/v7/media/RemotePlaybackClient$ItemActionCallback": "androidx/media/RemotePlaybackClient$ItemActionCallback",
+      "android/support/v7/media/RemotePlaybackClient$ActionCallback": "androidx/media/RemotePlaybackClient$ActionCallback",
+      "android/support/v7/media/RemotePlaybackClient$2": "androidx/media/RemotePlaybackClient$2",
+      "android/support/v7/media/RemotePlaybackClient$SessionActionCallback": "androidx/media/RemotePlaybackClient$SessionActionCallback",
+      "android/support/v7/media/RemotePlaybackClient$ActionReceiver": "androidx/media/RemotePlaybackClient$ActionReceiver",
+      "android/support/v7/media/RemotePlaybackClient$StatusCallback": "androidx/media/RemotePlaybackClient$StatusCallback",
+      "android/support/v7/media/RemotePlaybackClient$OnMessageReceivedListener": "androidx/media/RemotePlaybackClient$OnMessageReceivedListener",
+      "android/support/v7/media/SystemMediaRouteProvider$Api24Impl": "androidx/media/SystemMediaRouteProvider$Api24Impl",
+      "android/support/v7/media/SystemMediaRouteProvider$JellybeanMr2Impl": "androidx/media/SystemMediaRouteProvider$JellybeanMr2Impl",
+      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl": "androidx/media/SystemMediaRouteProvider$JellybeanImpl",
+      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteRecord": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteRecord",
+      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteController": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteController",
+      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$UserRouteRecord": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$UserRouteRecord",
+      "android/support/v7/media/SystemMediaRouteProvider$JellybeanMr1Impl": "androidx/media/SystemMediaRouteProvider$JellybeanMr1Impl",
+      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$DefaultRouteController": "androidx/media/SystemMediaRouteProvider$LegacyImpl$DefaultRouteController",
+      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl": "androidx/media/SystemMediaRouteProvider$LegacyImpl",
+      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver": "androidx/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver",
+      "android/support/transition/AnimatorUtils": "androidx/transition/AnimatorUtils",
+      "android/support/transition/AnimatorUtilsImpl": "androidx/transition/AnimatorUtilsImpl",
+      "android/support/transition/AnimatorUtilsApi19": "androidx/transition/AnimatorUtilsApi19",
+      "android/support/transition/AnimatorUtilsApi14": "androidx/transition/AnimatorUtilsApi14",
+      "android/support/transition/AnimatorUtilsApi14$AnimatorPauseListenerCompat": "androidx/transition/AnimatorUtilsApi14$AnimatorPauseListenerCompat",
+      "android/support/transition/ArcMotion": "androidx/transition/ArcMotion",
+      "android/support/transition/PathMotion": "androidx/transition/PathMotion",
+      "android/support/transition/Styleable$ArcMotion": "androidx/transition/Styleable$ArcMotion",
+      "android/support/transition/Styleable": "androidx/transition/Styleable",
+      "android/support/transition/AutoTransition": "androidx/transition/AutoTransition",
+      "android/support/transition/TransitionSet": "androidx/transition/TransitionSet",
+      "android/support/transition/Fade": "androidx/transition/Fade",
+      "android/support/transition/Transition": "androidx/transition/Transition",
+      "android/support/transition/ChangeBounds": "androidx/transition/ChangeBounds",
+      "android/support/transition/ChangeBounds$1": "androidx/transition/ChangeBounds$1",
+      "android/support/transition/ChangeBounds$10": "androidx/transition/ChangeBounds$10",
+      "android/support/transition/TransitionValues": "androidx/transition/TransitionValues",
+      "android/support/transition/ViewUtils": "androidx/transition/ViewUtils",
+      "android/support/transition/ViewOverlayImpl": "androidx/transition/ViewOverlayImpl",
+      "android/support/transition/ChangeBounds$2": "androidx/transition/ChangeBounds$2",
+      "android/support/transition/ChangeBounds$ViewBounds": "androidx/transition/ChangeBounds$ViewBounds",
+      "android/support/transition/ChangeBounds$3": "androidx/transition/ChangeBounds$3",
+      "android/support/transition/ChangeBounds$4": "androidx/transition/ChangeBounds$4",
+      "android/support/transition/ChangeBounds$5": "androidx/transition/ChangeBounds$5",
+      "android/support/transition/ChangeBounds$6": "androidx/transition/ChangeBounds$6",
+      "android/support/transition/ChangeBounds$7": "androidx/transition/ChangeBounds$7",
+      "android/support/transition/ChangeBounds$8": "androidx/transition/ChangeBounds$8",
+      "android/support/transition/ChangeBounds$9": "androidx/transition/ChangeBounds$9",
+      "android/support/transition/TransitionListenerAdapter": "androidx/transition/TransitionListenerAdapter",
+      "android/support/transition/Transition$TransitionListener": "androidx/transition/Transition$TransitionListener",
+      "android/support/transition/ViewGroupUtils": "androidx/transition/ViewGroupUtils",
+      "android/support/transition/Styleable$ChangeBounds": "androidx/transition/Styleable$ChangeBounds",
+      "android/support/transition/RectEvaluator": "androidx/transition/RectEvaluator",
+      "android/support/transition/ObjectAnimatorUtils": "androidx/transition/ObjectAnimatorUtils",
+      "android/support/transition/TransitionUtils": "androidx/transition/TransitionUtils",
+      "android/support/transition/PropertyValuesHolderUtils": "androidx/transition/PropertyValuesHolderUtils",
+      "android/support/transition/ChangeClipBounds$1": "androidx/transition/ChangeClipBounds$1",
+      "android/support/transition/ChangeClipBounds": "androidx/transition/ChangeClipBounds",
+      "android/support/transition/ChangeImageTransform$1": "androidx/transition/ChangeImageTransform$1",
+      "android/support/transition/ChangeImageTransform": "androidx/transition/ChangeImageTransform",
+      "android/support/transition/ChangeImageTransform$2": "androidx/transition/ChangeImageTransform$2",
+      "android/support/transition/ImageViewUtils": "androidx/transition/ImageViewUtils",
+      "android/support/transition/ChangeImageTransform$3": "androidx/transition/ChangeImageTransform$3",
+      "android/support/transition/TransitionUtils$MatrixEvaluator": "androidx/transition/TransitionUtils$MatrixEvaluator",
+      "android/support/transition/MatrixUtils": "androidx/transition/MatrixUtils",
+      "android/support/transition/ChangeScroll": "androidx/transition/ChangeScroll",
+      "android/support/transition/ChangeTransform$1": "androidx/transition/ChangeTransform$1",
+      "android/support/transition/ChangeTransform$PathAnimatorMatrix": "androidx/transition/ChangeTransform$PathAnimatorMatrix",
+      "android/support/transition/ChangeTransform": "androidx/transition/ChangeTransform",
+      "android/support/transition/ChangeTransform$2": "androidx/transition/ChangeTransform$2",
+      "android/support/transition/ChangeTransform$3": "androidx/transition/ChangeTransform$3",
+      "android/support/transition/ChangeTransform$Transforms": "androidx/transition/ChangeTransform$Transforms",
+      "android/support/transition/R$id": "androidx/transition/R$id",
+      "android/support/transition/R": "androidx/transition/R",
+      "android/support/transition/ChangeTransform$GhostListener": "androidx/transition/ChangeTransform$GhostListener",
+      "android/support/transition/GhostViewImpl": "androidx/transition/GhostViewImpl",
+      "android/support/transition/GhostViewUtils": "androidx/transition/GhostViewUtils",
+      "android/support/transition/Styleable$ChangeTransform": "androidx/transition/Styleable$ChangeTransform",
+      "android/support/transition/FloatArrayEvaluator": "androidx/transition/FloatArrayEvaluator",
+      "android/support/transition/CircularPropagation": "androidx/transition/CircularPropagation",
+      "android/support/transition/VisibilityPropagation": "androidx/transition/VisibilityPropagation",
+      "android/support/transition/Explode": "androidx/transition/Explode",
+      "android/support/transition/Visibility": "androidx/transition/Visibility",
+      "android/support/transition/TransitionPropagation": "androidx/transition/TransitionPropagation",
+      "android/support/transition/TranslationAnimationCreator": "androidx/transition/TranslationAnimationCreator",
+      "android/support/transition/Fade$1": "androidx/transition/Fade$1",
+      "android/support/transition/Fade$FadeAnimatorListener": "androidx/transition/Fade$FadeAnimatorListener",
+      "android/support/transition/Styleable$Fade": "androidx/transition/Styleable$Fade",
+      "android/support/transition/FragmentTransitionSupport$1": "androidx/transition/FragmentTransitionSupport$1",
+      "android/support/transition/Transition$EpicenterCallback": "androidx/transition/Transition$EpicenterCallback",
+      "android/support/transition/FragmentTransitionSupport": "androidx/transition/FragmentTransitionSupport",
+      "android/support/transition/FragmentTransitionSupport$2": "androidx/transition/FragmentTransitionSupport$2",
+      "android/support/transition/FragmentTransitionSupport$3": "androidx/transition/FragmentTransitionSupport$3",
+      "android/support/transition/FragmentTransitionSupport$4": "androidx/transition/FragmentTransitionSupport$4",
+      "android/support/transition/TransitionManager": "androidx/transition/TransitionManager",
+      "android/support/transition/GhostViewApi14$1": "androidx/transition/GhostViewApi14$1",
+      "android/support/transition/GhostViewApi14": "androidx/transition/GhostViewApi14",
+      "android/support/transition/GhostViewApi14$Creator": "androidx/transition/GhostViewApi14$Creator",
+      "android/support/transition/GhostViewImpl$Creator": "androidx/transition/GhostViewImpl$Creator",
+      "android/support/transition/GhostViewApi21$1": "androidx/transition/GhostViewApi21$1",
+      "android/support/transition/GhostViewApi21": "androidx/transition/GhostViewApi21",
+      "android/support/transition/GhostViewApi21$Creator": "androidx/transition/GhostViewApi21$Creator",
+      "android/support/transition/ImageViewUtilsImpl": "androidx/transition/ImageViewUtilsImpl",
+      "android/support/transition/ImageViewUtilsApi21": "androidx/transition/ImageViewUtilsApi21",
+      "android/support/transition/ImageViewUtilsApi14": "androidx/transition/ImageViewUtilsApi14",
+      "android/support/transition/ImageViewUtilsApi14$1": "androidx/transition/ImageViewUtilsApi14$1",
+      "android/support/transition/MatrixUtils$1": "androidx/transition/MatrixUtils$1",
+      "android/support/transition/ObjectAnimatorUtilsImpl": "androidx/transition/ObjectAnimatorUtilsImpl",
+      "android/support/transition/ObjectAnimatorUtilsApi21": "androidx/transition/ObjectAnimatorUtilsApi21",
+      "android/support/transition/ObjectAnimatorUtilsApi14": "androidx/transition/ObjectAnimatorUtilsApi14",
+      "android/support/transition/PathProperty": "androidx/transition/PathProperty",
+      "android/support/transition/PatternPathMotion": "androidx/transition/PatternPathMotion",
+      "android/support/transition/Styleable$PatternPathMotion": "androidx/transition/Styleable$PatternPathMotion",
+      "android/support/transition/PropertyValuesHolderUtilsImpl": "androidx/transition/PropertyValuesHolderUtilsImpl",
+      "android/support/transition/PropertyValuesHolderUtilsApi21": "androidx/transition/PropertyValuesHolderUtilsApi21",
+      "android/support/transition/PropertyValuesHolderUtilsApi14": "androidx/transition/PropertyValuesHolderUtilsApi14",
+      "android/support/transition/Scene": "androidx/transition/Scene",
+      "android/support/transition/SidePropagation": "androidx/transition/SidePropagation",
+      "android/support/transition/Slide$1": "androidx/transition/Slide$1",
+      "android/support/transition/Slide$CalculateSlideHorizontal": "androidx/transition/Slide$CalculateSlideHorizontal",
+      "android/support/transition/Slide": "androidx/transition/Slide",
+      "android/support/transition/Slide$2": "androidx/transition/Slide$2",
+      "android/support/transition/Slide$3": "androidx/transition/Slide$3",
+      "android/support/transition/Slide$CalculateSlideVertical": "androidx/transition/Slide$CalculateSlideVertical",
+      "android/support/transition/Slide$4": "androidx/transition/Slide$4",
+      "android/support/transition/Slide$5": "androidx/transition/Slide$5",
+      "android/support/transition/Slide$6": "androidx/transition/Slide$6",
+      "android/support/transition/Slide$CalculateSlide": "androidx/transition/Slide$CalculateSlide",
+      "android/support/transition/Slide$GravityFlag": "androidx/transition/Slide$GravityFlag",
+      "android/support/transition/Styleable$Slide": "androidx/transition/Styleable$Slide",
+      "android/support/transition/Styleable$Transition": "androidx/transition/Styleable$Transition",
+      "android/support/transition/Styleable$TransitionManager": "androidx/transition/Styleable$TransitionManager",
+      "android/support/transition/Styleable$TransitionSet": "androidx/transition/Styleable$TransitionSet",
+      "android/support/transition/Styleable$TransitionTarget": "androidx/transition/Styleable$TransitionTarget",
+      "android/support/transition/Styleable$VisibilityTransition": "androidx/transition/Styleable$VisibilityTransition",
+      "android/support/transition/Transition$1": "androidx/transition/Transition$1",
+      "android/support/transition/Transition$2": "androidx/transition/Transition$2",
+      "android/support/transition/Transition$3": "androidx/transition/Transition$3",
+      "android/support/transition/Transition$AnimationInfo": "androidx/transition/Transition$AnimationInfo",
+      "android/support/transition/WindowIdImpl": "androidx/transition/WindowIdImpl",
+      "android/support/transition/Transition$ArrayListManager": "androidx/transition/Transition$ArrayListManager",
+      "android/support/transition/Transition$MatchOrder": "androidx/transition/Transition$MatchOrder",
+      "android/support/transition/TransitionValuesMaps": "androidx/transition/TransitionValuesMaps",
+      "android/support/transition/TransitionInflater": "androidx/transition/TransitionInflater",
+      "android/support/transition/TransitionManager$MultiListener$1": "androidx/transition/TransitionManager$MultiListener$1",
+      "android/support/transition/TransitionManager$MultiListener": "androidx/transition/TransitionManager$MultiListener",
+      "android/support/transition/TransitionSet$1": "androidx/transition/TransitionSet$1",
+      "android/support/transition/TransitionSet$TransitionSetListener": "androidx/transition/TransitionSet$TransitionSetListener",
+      "android/support/transition/TranslationAnimationCreator$1": "androidx/transition/TranslationAnimationCreator$1",
+      "android/support/transition/TranslationAnimationCreator$TransitionPositionListener": "androidx/transition/TranslationAnimationCreator$TransitionPositionListener",
+      "android/support/transition/ViewGroupOverlayApi14": "androidx/transition/ViewGroupOverlayApi14",
+      "android/support/transition/ViewOverlayApi14": "androidx/transition/ViewOverlayApi14",
+      "android/support/transition/ViewGroupOverlayImpl": "androidx/transition/ViewGroupOverlayImpl",
+      "android/support/transition/ViewOverlayApi14$OverlayViewGroup": "androidx/transition/ViewOverlayApi14$OverlayViewGroup",
+      "android/support/transition/ViewGroupOverlayApi18": "androidx/transition/ViewGroupOverlayApi18",
+      "android/support/transition/ViewGroupUtilsImpl": "androidx/transition/ViewGroupUtilsImpl",
+      "android/support/transition/ViewGroupUtilsApi18": "androidx/transition/ViewGroupUtilsApi18",
+      "android/support/transition/ViewGroupUtilsApi14": "androidx/transition/ViewGroupUtilsApi14",
+      "android/support/transition/ViewGroupUtilsApi14$1": "androidx/transition/ViewGroupUtilsApi14$1",
+      "android/support/transition/ViewOverlayApi14$OverlayViewGroup$TouchInterceptor": "androidx/transition/ViewOverlayApi14$OverlayViewGroup$TouchInterceptor",
+      "android/support/transition/ViewOverlayApi18": "androidx/transition/ViewOverlayApi18",
+      "android/support/transition/ViewUtils$1": "androidx/transition/ViewUtils$1",
+      "android/support/transition/ViewUtils$2": "androidx/transition/ViewUtils$2",
+      "android/support/transition/ViewUtilsImpl": "androidx/transition/ViewUtilsImpl",
+      "android/support/transition/ViewUtilsApi22": "androidx/transition/ViewUtilsApi22",
+      "android/support/transition/ViewUtilsApi21": "androidx/transition/ViewUtilsApi21",
       "android/support/transition/ViewUtilsApi19": "androidx/transition/ViewUtilsApi19",
       "android/support/transition/ViewUtilsApi18": "androidx/transition/ViewUtilsApi18",
-      "android/support/v7/widget/AppCompatDrawableManager$InflateDelegate": "androidx/widget/AppCompatDrawableManager$InflateDelegate",
-      "android/support/v13/view/DragAndDropPermissionsCompat": "androidx/view/DragAndDropPermissionsCompat",
-      "android/support/v4/content/res/FontResourcesParserCompat$FontFamilyFilesResourceEntry": "androidx/content/res/FontResourcesParserCompat$FontFamilyFilesResourceEntry",
       "android/support/transition/ViewUtilsApi14": "androidx/transition/ViewUtilsApi14",
-      "android/support/v7/view/menu/MenuItemWrapperICS": "androidx/view/menu/MenuItemWrapperICS",
-      "android/support/design/widget/CollapsingToolbarLayout": "androidx/design/widget/CollapsingToolbarLayout",
-      "android/support/v4/util/ArrayMap": "androidx/util/ArrayMap",
-      "android/support/v17/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget": "androidx/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget",
-      "android/support/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter": "androidx/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter",
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserServiceCallbackImpl": "androidx/media/MediaBrowserCompat$MediaBrowserServiceCallbackImpl",
-      "android/support/wear/widget/SimpleAnimatorListener": "androidx/wear/widget/SimpleAnimatorListener",
-      "android/support/v17/leanback/widget/FacetProviderAdapter": "androidx/leanback/widget/FacetProviderAdapter",
-      "android/support/v4/widget/SlidingPaneLayout$SlidingPanelLayoutImplJBMR1": "androidx/widget/SlidingPaneLayout$SlidingPanelLayoutImplJBMR1",
-      "android/support/v7/widget/SearchView": "androidx/widget/SearchView",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MediaSessionStub": "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MediaSessionStub",
-      "android/support/v7/widget/TooltipCompat$ViewCompatImpl": "androidx/widget/TooltipCompat$ViewCompatImpl",
-      "android/support/v13/view/DragAndDropPermissionsCompat$DragAndDropPermissionsCompatImpl": "androidx/view/DragAndDropPermissionsCompat$DragAndDropPermissionsCompatImpl",
-      "android/support/customtabs/IPostMessageService$Stub$Proxy": "androidx/browser/customtabs/IPostMessageService$Stub$Proxy",
-      "android/support/v17/leanback/widget/ItemAlignment$Axis": "androidx/leanback/widget/ItemAlignment$Axis",
-      "android/support/v7/widget/RecyclerView$ViewHolder": "androidx/widget/RecyclerView$ViewHolder",
-      "android/support/v7/widget/GapWorker": "androidx/widget/GapWorker",
-      "android/support/v7/media/MediaItemStatus": "androidx/media/MediaItemStatus",
-      "android/support/transition/Explode": "androidx/transition/Explode",
-      "android/support/v17/leanback/widget/GuidedActionAdapter$ActionEditListener": "androidx/leanback/widget/GuidedActionAdapter$ActionEditListener",
-      "android/support/v4/text/BidiFormatter": "androidx/text/BidiFormatter",
-      "android/support/v7/widget/CardViewApi17Impl": "androidx/widget/CardViewApi17Impl",
-      "android/support/v7/media/MediaRouter$RouteInfo$PlaybackType": "androidx/media/MediaRouter$RouteInfo$PlaybackType",
-      "android/support/v4/view/ViewGroupCompat$ViewGroupCompatBaseImpl": "androidx/view/ViewGroupCompat$ViewGroupCompatBaseImpl",
-      "android/support/v4/view/ViewParentCompat$ViewParentCompatApi21Impl": "androidx/view/ViewParentCompat$ViewParentCompatApi21Impl",
-      "android/support/v7/widget/StaggeredGridLayoutManager": "androidx/widget/StaggeredGridLayoutManager",
-      "android/support/v4/widget/FocusStrategy": "androidx/widget/FocusStrategy",
-      "android/support/customtabs/ICustomTabsCallback$Stub$Proxy": "androidx/browser/customtabs/ICustomTabsCallback$Stub$Proxy",
-      "android/support/v7/media/MediaRouteProvider": "androidx/media/MediaRouteProvider",
-      "android/support/v4/net/DatagramSocketWrapper": "androidx/net/DatagramSocketWrapper",
-      "android/support/design/widget/SnackbarManager": "androidx/design/widget/SnackbarManager",
-      "android/support/v17/leanback/media/MediaControllerGlue": "androidx/leanback/media/MediaControllerGlue",
-      "android/support/v7/widget/PopupMenu$OnMenuItemClickListener": "androidx/widget/PopupMenu$OnMenuItemClickListener",
-      "android/support/v7/widget/helper/ItemTouchUIUtilImpl$Api21Impl": "androidx/widget/helper/ItemTouchUIUtilImpl$Api21Impl",
-      "android/support/text/emoji/widget/EmojiTextViewHelper": "androidx/text/emoji/widget/EmojiTextViewHelper",
-      "android/support/v4/media/session/MediaSessionCompat$Callback": "androidx/media/session/MediaSessionCompat$Callback",
-      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuTextItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuTextItem",
-      "android/support/v13/app/FragmentCompat$OnRequestPermissionsResultCallback": "androidx/app/FragmentCompat$OnRequestPermissionsResultCallback",
-      "android/support/design/widget/AppBarLayout$Behavior$DragCallback": "androidx/design/widget/AppBarLayout$Behavior$DragCallback",
-      "android/support/text/emoji/widget/EmojiEditTextHelper": "androidx/text/emoji/widget/EmojiEditTextHelper",
-      "android/support/v7/widget/AppCompatTextHelperV17": "androidx/widget/AppCompatTextHelperV17",
-      "android/support/v4/widget/SimpleCursorAdapter": "androidx/widget/SimpleCursorAdapter",
-      "android/support/mediacompat/R$integer": "androidx/mediacompat/R$integer",
-      "android/support/v17/leanback/widget/Grid$Provider": "androidx/leanback/widget/Grid$Provider",
-      "android/support/v13/view/ViewCompat": "androidx/view/ViewCompat",
-      "android/support/v14/preference/MultiSelectListPreference$SavedState": "androidx/preference/MultiSelectListPreference$SavedState",
-      "android/support/v4/view/NestedScrollingChild": "androidx/view/NestedScrollingChild",
-      "android/support/v4/app/FragmentTransition": "androidx/app/FragmentTransition",
-      "android/support/v4/app/NotificationCompat$Action$WearableExtender": "androidx/app/NotificationCompat$Action$WearableExtender",
-      "android/support/v17/preference/LeanbackPreferenceDialogFragment": "androidx/leanback/preference/LeanbackPreferenceDialogFragment",
-      "android/support/annotation/WorkerThread": "androidx/annotation/WorkerThread",
-      "android/support/v7/app/MediaRouteDialogFactory": "androidx/app/MediaRouteDialogFactory",
-      "android/support/v7/view/ActionMode": "androidx/view/ActionMode",
-      "android/support/v4/provider/FontsContractCompat$FontRequestCallback$FontRequestFailReason": "androidx/provider/FontsContractCompat$FontRequestCallback$FontRequestFailReason",
-      "android/support/v17/leanback/R$drawable": "androidx/leanback/R$drawable",
-      "android/support/annotation/StringRes": "androidx/annotation/StringRes",
-      "android/support/v4/app/RemoteInputCompatBase$RemoteInput": "androidx/app/RemoteInputCompatBase$RemoteInput",
-      "android/support/v13/app/FragmentTabHost$TabInfo": "androidx/app/legacy/FragmentTabHost$TabInfo",
-      "android/support/v7/app/ActionBarDrawerToggle$ToolbarCompatDelegate": "androidx/app/ActionBarDrawerToggle$ToolbarCompatDelegate",
-      "android/support/v7/widget/PopupMenu$OnDismissListener": "androidx/widget/PopupMenu$OnDismissListener",
-      "android/support/transition/AnimatorUtilsApi14$AnimatorPauseListenerCompat": "androidx/transition/AnimatorUtilsApi14$AnimatorPauseListenerCompat",
-      "android/support/v4/app/JobIntentService$CommandProcessor": "androidx/app/JobIntentService$CommandProcessor",
-      "android/support/v17/leanback/widget/VerticalGridView": "androidx/leanback/widget/VerticalGridView",
-      "android/support/v4/app/FragmentManager": "androidx/app/FragmentManager",
-      "android/support/v4/app/BackStackState": "androidx/app/BackStackState",
-      "android/support/text/emoji/R": "androidx/text/emoji/R",
-      "android/support/v4/media/session/MediaSessionCompatApi21$Callback": "androidx/media/session/MediaSessionCompatApi21$Callback",
-      "android/support/transition/ChangeScroll": "androidx/transition/ChangeScroll",
-      "android/support/v4/view/ViewCompat$LayoutDirectionMode": "androidx/view/legacy/ViewCompat$LayoutDirectionMode",
-      "android/support/v7/widget/AdapterHelper$Callback": "androidx/widget/AdapterHelper$Callback",
-      "android/support/wear/R$layout": "androidx/wear/R$layout",
-      "android/support/v17/leanback/widget/GuidedActionAdapter$ClickListener": "androidx/leanback/widget/GuidedActionAdapter$ClickListener",
-      "android/support/v4/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraCallback": "androidx/media/session/MediaControllerCompat$MediaControllerImplApi21$ExtraCallback",
-      "android/support/customtabs/ICustomTabsService$Stub": "androidx/browser/customtabs/ICustomTabsService$Stub",
-      "android/support/v17/leanback/widget/ListRowView": "androidx/leanback/widget/ListRowView",
-      "android/support/v7/widget/ActivityChooserView": "androidx/widget/ActivityChooserView",
-      "android/support/v4/os/TraceCompat": "androidx/os/TraceCompat",
-      "android/support/transition/ImageViewUtils": "androidx/transition/ImageViewUtils",
-      "android/support/v4/app/FragmentManager$OnBackStackChangedListener": "androidx/app/FragmentManager$OnBackStackChangedListener",
-      "android/support/v7/app/AppCompatDelegateImplV23$AppCompatWindowCallbackV23": "androidx/app/AppCompatDelegateImplV23$AppCompatWindowCallbackV23",
-      "android/support/transition/GhostViewApi14": "androidx/transition/GhostViewApi14",
-      "android/support/design/widget/SwipeDismissBehavior$SwipeDirection": "androidx/design/widget/SwipeDismissBehavior$SwipeDirection",
-      "android/support/v17/leanback/widget/SearchOrbView": "androidx/leanback/widget/SearchOrbView",
-      "android/support/v4/app/NotificationManagerCompat$NotifyTask": "androidx/app/NotificationManagerCompat$NotifyTask",
-      "android/support/v4/util/LruCache": "androidx/util/LruCache",
-      "android/support/v7/widget/ActionMenuView$LayoutParams": "androidx/widget/ActionMenuView$LayoutParams",
-      "android/support/v7/widget/helper/ItemTouchHelper$ViewDropHandler": "androidx/widget/helper/ItemTouchHelper$ViewDropHandler",
-      "android/support/v7/content/res/AppCompatColorStateListInflater": "androidx/content/res/AppCompatColorStateListInflater",
-      "android/support/v7/widget/ActionMenuPresenter$OpenOverflowRunnable": "androidx/widget/ActionMenuPresenter$OpenOverflowRunnable",
-      "android/support/v7/media/MediaRouter$GlobalMediaRouter$CallbackHandler": "androidx/media/MediaRouter$GlobalMediaRouter$CallbackHandler",
-      "android/support/design/widget/AppBarLayout$Behavior": "androidx/design/widget/AppBarLayout$Behavior",
-      "android/support/v4/widget/ExploreByTouchHelper": "androidx/widget/ExploreByTouchHelper",
-      "android/support/transition/PropertyValuesHolderUtilsImpl": "androidx/transition/PropertyValuesHolderUtilsImpl",
-      "android/support/v14/preference/PreferenceDialogFragment": "androidx/preference/PreferenceDialogFragment",
-      "android/support/transition/GhostViewApi21": "androidx/transition/GhostViewApi21",
-      "android/support/text/emoji/MetadataListReader$InputStreamOpenTypeReader": "androidx/text/emoji/MetadataListReader$InputStreamOpenTypeReader",
-      "android/support/transition/RectEvaluator": "androidx/transition/RectEvaluator",
-      "android/support/v4/view/VelocityTrackerCompat": "androidx/view/VelocityTrackerCompat",
-      "android/support/v7/widget/AppCompatAutoCompleteTextView": "androidx/widget/AppCompatAutoCompleteTextView",
-      "android/support/v7/media/MediaRouterJellybean$VolumeCallback": "androidx/media/MediaRouterJellybean$VolumeCallback",
-      "android/support/media/tv/WatchNextProgram": "androidx/media/tv/WatchNextProgram",
-      "android/support/wear/internal/widget/drawer/MultiPageUi$NavigationPagerAdapter": "androidx/wear/internal/widget/drawer/MultiPageUi$NavigationPagerAdapter",
-      "android/support/v4/widget/ExploreByTouchHelper$MyNodeProvider": "androidx/widget/ExploreByTouchHelper$MyNodeProvider",
-      "android/support/v7/widget/RecyclerView$AdapterDataObserver": "androidx/widget/RecyclerView$AdapterDataObserver",
-      "android/support/v4/media/session/IMediaSession": "androidx/media/session/IMediaSession",
-      "android/support/v17/preference/LeanbackSettingsRootView": "androidx/leanback/preference/LeanbackSettingsRootView",
-      "android/support/v7/widget/AppCompatButton": "androidx/widget/AppCompatButton",
-      "android/support/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour": "androidx/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour",
-      "android/support/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableDelegateState": "androidx/graphics/drawable/AnimatedVectorDrawableCompat$AnimatedVectorDrawableDelegateState",
-      "android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController": "androidx/leanback/app/DetailsSupportFragmentBackgroundController",
-      "android/support/v17/leanback/widget/ThumbsBar": "androidx/leanback/widget/ThumbsBar",
-      "android/support/v4/media/session/MediaSessionCompat$Token": "androidx/media/session/MediaSessionCompat$Token",
-      "android/support/v7/mediarouter/R$integer": "androidx/mediarouter/R$integer",
-      "android/support/v7/app/WindowDecorActionBar": "androidx/app/WindowDecorActionBar",
-      "android/support/v4/app/Fragment$SavedState": "androidx/app/Fragment$SavedState",
-      "android/support/v17/leanback/widget/StaggeredGrid$Location": "androidx/leanback/widget/StaggeredGrid$Location",
-      "android/support/v17/leanback/widget/DiffCallback": "androidx/leanback/widget/DiffCallback",
-      "android/support/v4/os/ParcelableCompat": "androidx/os/ParcelableCompat",
-      "android/support/transition/ViewGroupUtils": "androidx/transition/ViewGroupUtils",
-      "android/support/v7/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord": "androidx/media/MediaRouter$GlobalMediaRouter$MediaSessionRecord",
-      "android/support/v7/widget/ViewBoundsCheck$BoundFlags": "androidx/widget/ViewBoundsCheck$BoundFlags",
-      "android/support/wear/R": "androidx/wear/R",
-      "android/support/v17/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout": "androidx/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout",
-      "android/support/v4/widget/ViewDragHelper$Callback": "androidx/widget/ViewDragHelper$Callback",
-      "android/support/v7/widget/DropDownListView": "androidx/widget/DropDownListView",
-      "android/support/v17/leanback/transition/TransitionHelper$TransitionHelperVersionImpl": "androidx/leanback/transition/TransitionHelper$TransitionHelperVersionImpl",
-      "android/support/transition/TransitionUtils$MatrixEvaluator": "androidx/transition/TransitionUtils$MatrixEvaluator",
-      "android/support/v4/hardware/display/DisplayManagerCompat": "androidx/hardware/display/DisplayManagerCompat",
-      "android/support/media/tv/TvContractCompat$Channels$VideoResolution": "androidx/media/tv/TvContractCompat$Channels$VideoResolution",
-      "android/support/v4/app/NotificationCompatBuilder": "androidx/app/NotificationCompatBuilder",
-      "android/support/v4/media/session/MediaControllerCompat$TransportControls": "androidx/media/session/MediaControllerCompat$TransportControls",
-      "android/support/v7/view/menu/SubMenuBuilder": "androidx/view/menu/SubMenuBuilder",
-      "android/support/v4/media/session/MediaSessionCompatApi23$CallbackProxy": "androidx/media/session/MediaSessionCompatApi23$CallbackProxy",
-      "android/support/v7/recyclerview/R$id": "androidx/recyclerview/R$id",
-      "android/support/wear/widget/WearableLinearLayoutManager$LayoutCallback": "androidx/wear/widget/WearableLinearLayoutManager$LayoutCallback",
-      "android/support/v17/leanback/widget/PresenterSelector": "androidx/leanback/widget/PresenterSelector",
-      "android/support/v4/app/JobIntentService$JobServiceEngineImpl": "androidx/app/JobIntentService$JobServiceEngineImpl",
-      "android/support/v4/app/ActionBarDrawerToggle$DelegateProvider": "androidx/app/legacy/ActionBarDrawerToggle$DelegateProvider",
-      "android/support/v17/leanback/widget/GuidedActionsRelativeLayout": "androidx/leanback/widget/GuidedActionsRelativeLayout",
-      "android/support/v7/widget/RecyclerView$LayoutManager": "androidx/widget/RecyclerView$LayoutManager",
-      "android/support/v4/print/PrintHelper": "androidx/print/PrintHelper",
-      "android/support/v7/util/AsyncListUtil": "androidx/util/AsyncListUtil",
-      "android/support/transition/TransitionListenerAdapter": "androidx/transition/TransitionListenerAdapter",
-      "android/support/v7/view/menu/MenuItemWrapperICS$ActionProviderWrapper": "androidx/view/menu/MenuItemWrapperICS$ActionProviderWrapper",
-      "android/support/v7/app/TwilightManager": "androidx/app/TwilightManager",
-      "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperDefault": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperDefault",
-      "android/support/v4/app/NotificationCompat$InboxStyle": "androidx/app/NotificationCompat$InboxStyle",
-      "android/support/v14/preference/MultiSelectListPreference": "androidx/preference/MultiSelectListPreference",
-      "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl": "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl",
-      "android/support/v7/preference/SeekBarPreference$SavedState": "androidx/preference/SeekBarPreference$SavedState",
-      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$BoundData": "androidx/leanback/widget/PlaybackControlsRowPresenter$BoundData",
-      "android/support/customtabs/CustomTabsSessionToken": "androidx/browser/customtabs/CustomTabsSessionToken",
-      "android/support/v4/media/session/MediaControllerCompat$PlaybackInfo": "androidx/media/session/MediaControllerCompat$PlaybackInfo",
-      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper": "androidx/leanback/app/DetailsBackgroundVideoHelper",
-      "android/support/v17/leanback/app/RowsFragment$MainFragmentRowsAdapter": "androidx/leanback/app/RowsFragment$MainFragmentRowsAdapter",
-      "android/support/v7/app/OverlayListView$OverlayObject": "androidx/app/OverlayListView$OverlayObject",
-      "android/support/v4/provider/SingleDocumentFile": "androidx/provider/SingleDocumentFile",
-      "android/support/v7/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9": "androidx/app/AppCompatDelegateImplV9$ActionModeCallbackWrapperV9",
-      "android/support/v4/widget/TintableCompoundButton": "androidx/widget/TintableCompoundButton",
-      "android/support/v7/graphics/Target$Builder": "androidx/graphics/Target$Builder",
-      "android/support/v17/leanback/widget/NonOverlappingFrameLayout": "androidx/leanback/widget/NonOverlappingFrameLayout",
-      "android/support/annotation/IntegerRes": "androidx/annotation/IntegerRes",
-      "android/support/media/tv/CollectionUtils": "androidx/media/tv/CollectionUtils",
-      "android/support/v4/provider/FontsContractCompat$FontRequestCallback": "androidx/provider/FontsContractCompat$FontRequestCallback",
-      "android/support/design/internal/BottomNavigationMenuView": "androidx/design/internal/BottomNavigationMenuView",
-      "android/support/v4/graphics/drawable/RoundedBitmapDrawable21": "androidx/graphics/drawable/RoundedBitmapDrawable21",
-      "android/support/design/widget/CoordinatorLayout$SavedState": "androidx/design/widget/CoordinatorLayout$SavedState",
-      "android/support/media/tv/TvContractCompat": "androidx/media/tv/TvContractCompat",
-      "android/support/v7/media/RemoteControlClientCompat$PlaybackInfo": "androidx/media/RemoteControlClientCompat$PlaybackInfo",
-      "android/support/v7/app/AppCompatDelegateImplV9$ActionMenuPresenterCallback": "androidx/app/AppCompatDelegateImplV9$ActionMenuPresenterCallback",
-      "android/support/v17/leanback/widget/StreamingTextView$DottySpan": "androidx/leanback/widget/StreamingTextView$DottySpan",
-      "android/support/v7/view/menu/ActionMenuItemView$PopupCallback": "androidx/view/menu/ActionMenuItemView$PopupCallback",
-      "android/support/percent/PercentLayoutHelper": "androidx/PercentLayoutHelper",
-      "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperVersion": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperVersion",
-      "android/support/v17/leanback/widget/VerticalGridPresenter$ViewHolder": "androidx/leanback/widget/VerticalGridPresenter$ViewHolder",
-      "android/support/media/tv/BaseProgram": "androidx/media/tv/BaseProgram",
-      "android/support/v4/view/ViewGroupCompat": "androidx/view/ViewGroupCompat",
-      "android/support/media/instantvideo/preload/InstantVideoPreloadManager$AsyncTaskVideoPreloader": "androidx/media/instantvideo/preload/InstantVideoPreloadManager$AsyncTaskVideoPreloader",
-      "android/support/v4/widget/FocusStrategy$CollectionAdapter": "androidx/widget/FocusStrategy$CollectionAdapter",
-      "android/support/v7/util/SortedList$Callback": "androidx/util/SortedList$Callback",
-      "android/support/v17/leanback/widget/Parallax$PropertyMarkerValue": "androidx/leanback/widget/Parallax$PropertyMarkerValue",
-      "android/support/v4/text/TextDirectionHeuristicsCompat$AnyStrong": "androidx/text/TextDirectionHeuristicsCompat$AnyStrong",
-      "android/support/v14/preference/PreferenceFragment$OnPreferenceStartScreenCallback": "androidx/preference/PreferenceFragment$OnPreferenceStartScreenCallback",
-      "android/support/v17/leanback/widget/picker/PickerColumn": "androidx/leanback/widget/picker/PickerColumn",
-      "android/support/transition/TransitionPropagation": "androidx/transition/TransitionPropagation",
-      "android/support/v17/leanback/widget/WindowAlignment": "androidx/leanback/widget/WindowAlignment",
-      "android/support/v17/leanback/transition/TranslationAnimationCreator": "androidx/leanback/transition/TranslationAnimationCreator",
-      "android/support/v7/media/MediaRouterApi24": "androidx/media/MediaRouterApi24",
-      "android/support/transition/Styleable$Slide": "androidx/transition/Styleable$Slide",
-      "android/support/v7/view/menu/StandardMenuPopup": "androidx/view/menu/StandardMenuPopup",
-      "android/support/v4/widget/PopupMenuCompat": "androidx/widget/PopupMenuCompat",
-      "android/support/design/widget/CollapsingToolbarLayout$LayoutParams$CollapseMode": "androidx/design/widget/CollapsingToolbarLayout$LayoutParams$CollapseMode",
-      "android/support/v17/leanback/widget/ObjectAdapter": "androidx/leanback/widget/ObjectAdapter",
-      "android/support/v4/view/GestureDetectorCompat": "androidx/view/GestureDetectorCompat",
-      "android/support/v17/leanback/widget/Parallax$IntPropertyMarkerValue": "androidx/leanback/widget/Parallax$IntPropertyMarkerValue",
-      "android/support/v4/view/ViewCompat$ViewCompatApi26Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi26Impl",
-      "android/support/v7/media/RemoteControlClientCompat$VolumeCallback": "androidx/media/RemoteControlClientCompat$VolumeCallback",
-      "android/support/design/widget/AnimationUtils": "androidx/design/widget/AnimationUtils",
-      "android/support/v4/view/ViewCompat$ScrollIndicators": "androidx/view/legacy/ViewCompat$ScrollIndicators",
-      "android/support/media/tv/WatchNextProgram$Builder": "androidx/media/tv/WatchNextProgram$Builder",
-      "android/support/v7/graphics/Palette$Filter": "androidx/graphics/Palette$Filter",
-      "android/support/annotation/BinderThread": "androidx/annotation/BinderThread",
-      "android/support/v17/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight$HeaderFocusAnimator": "androidx/leanback/widget/FocusHighlightHelper$HeaderItemFocusHighlight$HeaderFocusAnimator",
-      "android/support/media/tv/Program$Builder": "androidx/media/tv/Program$Builder",
-      "android/support/v4/hardware/fingerprint/FingerprintManagerCompat$AuthenticationResult": "androidx/hardware/fingerprint/FingerprintManagerCompat$AuthenticationResult",
-      "android/support/v4/os/LocaleListCompat$LocaleListCompatApi24Impl": "androidx/os/LocaleListCompat$LocaleListCompatApi24Impl",
-      "android/support/v17/leanback/widget/GuidedActionAdapter$FocusListener": "androidx/leanback/widget/GuidedActionAdapter$FocusListener",
-      "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder": "androidx/leanback/widget/ControlBarPresenter$ViewHolder",
-      "android/support/v7/graphics/drawable/DrawerArrowDrawable$ArrowDirection": "androidx/graphics/drawable/DrawerArrowDrawable$ArrowDirection",
-      "android/support/v4/view/ViewPager$DecorView": "androidx/view/ViewPager$DecorView",
-      "android/support/v4/view/ViewParentCompat$ViewParentCompatApi19Impl": "androidx/view/ViewParentCompat$ViewParentCompatApi19Impl",
-      "android/support/v7/widget/StaggeredGridLayoutManager$Span": "androidx/widget/StaggeredGridLayoutManager$Span",
-      "android/support/wear/widget/ProgressDrawable": "androidx/wear/widget/ProgressDrawable",
-      "android/support/v7/media/MediaRouterJellybeanMr2$RouteInfo": "androidx/media/MediaRouterJellybeanMr2$RouteInfo",
-      "android/support/v4/graphics/PathParser$PathDataNode": "androidx/graphics/PathParser$PathDataNode",
-      "android/support/v17/leanback/graphics/ColorFilterCache": "androidx/leanback/graphics/ColorFilterCache",
-      "android/support/text/emoji/EmojiCompat$InitCallback": "androidx/text/emoji/EmojiCompat$InitCallback",
-      "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterRegistry": "androidx/leanback/app/BrowseFragment$MainFragmentAdapterRegistry",
-      "android/support/transition/PropertyValuesHolderUtils": "androidx/transition/PropertyValuesHolderUtils",
-      "android/support/v7/widget/ActivityChooserModel$DefaultSorter": "androidx/widget/ActivityChooserModel$DefaultSorter",
-      "android/support/v7/app/AlertController$CheckedItemAdapter": "androidx/app/AlertController$CheckedItemAdapter",
-      "android/support/design/widget/TabItem": "androidx/design/widget/TabItem",
-      "android/support/v4/media/MediaBrowserCompatApi21$ConnectionCallbackProxy": "androidx/media/MediaBrowserCompatApi21$ConnectionCallbackProxy",
-      "android/support/content/LoaderQueryRunner": "androidx/content/LoaderQueryRunner",
-      "android/support/v17/leanback/app/BrowseSupportFragment$FragmentFactory": "androidx/leanback/app/BrowseSupportFragment$FragmentFactory",
-      "android/support/v7/app/AppCompatDelegateImplN$AppCompatWindowCallbackN": "androidx/app/AppCompatDelegateImplN$AppCompatWindowCallbackN",
-      "android/support/wear/widget/drawer/WearableDrawerLayout$DrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$DrawerDraggerCallback",
-      "android/support/v7/widget/OpReorderer": "androidx/widget/OpReorderer",
-      "android/support/media/instantvideo/preload/InstantVideoPreloadManager": "androidx/media/instantvideo/preload/InstantVideoPreloadManager",
-      "android/support/v4/view/ViewPropertyAnimatorCompat": "androidx/view/ViewPropertyAnimatorCompat",
-      "android/support/v13/app/FragmentCompat$FragmentCompatApi23Impl": "androidx/app/FragmentCompat$FragmentCompatApi23Impl",
-      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi23",
-      "android/support/v4/internal/view/SupportSubMenu": "androidx/internal/view/SupportSubMenu",
-      "android/support/text/emoji/EmojiProcessor$Action": "androidx/text/emoji/EmojiProcessor$Action",
-      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi21",
-      "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder": "androidx/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder",
-      "android/support/v7/widget/OrientationHelper": "androidx/widget/OrientationHelper",
-      "android/support/v4/app/FragmentTransition$FragmentContainerTransition": "androidx/app/FragmentTransition$FragmentContainerTransition",
-      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplApi26",
-      "android/support/v7/preference/PreferenceViewHolder": "androidx/preference/PreferenceViewHolder",
-      "android/support/graphics/drawable/VectorDrawableCommon": "androidx/graphics/drawable/VectorDrawableCommon",
-      "android/support/v4/view/animation/FastOutLinearInInterpolator": "androidx/view/animation/FastOutLinearInInterpolator",
-      "android/support/v4/media/MediaBrowserServiceCompatApi26$MediaBrowserServiceAdaptor": "androidx/media/MediaBrowserServiceCompatApi26$MediaBrowserServiceAdaptor",
-      "android/support/v7/view/SupportActionModeWrapper": "androidx/view/SupportActionModeWrapper",
-      "android/support/v7/app/AppCompatDelegateImplV11": "androidx/app/AppCompatDelegateImplV11",
-      "android/support/v7/app/AppCompatDelegateImplV14": "androidx/app/AppCompatDelegateImplV14",
-      "android/support/v4/graphics/TypefaceCompatApi26Impl": "androidx/graphics/TypefaceCompatApi26Impl",
-      "android/support/v17/leanback/media/PlaybackGlueHost$PlayerCallback": "androidx/leanback/media/PlaybackGlueHost$PlayerCallback",
-      "android/support/design/widget/BottomNavigationView$SavedState": "androidx/design/widget/BottomNavigationView$SavedState",
-      "android/support/text/emoji/R$styleable": "androidx/text/emoji/R$styleable",
-      "android/support/v4/view/animation/LinearOutSlowInInterpolator": "androidx/view/animation/LinearOutSlowInInterpolator",
-      "android/support/v7/widget/LinearLayoutManager$LayoutState": "androidx/widget/LinearLayoutManager$LayoutState",
-      "android/support/wear/widget/BoxInsetLayout": "androidx/wear/widget/BoxInsetLayout",
-      "android/support/design/widget/HeaderBehavior": "androidx/design/widget/HeaderBehavior",
-      "android/support/v17/leanback/widget/PageRow": "androidx/leanback/widget/PageRow",
-      "android/support/v7/widget/ViewStubCompat": "androidx/widget/ViewStubCompat",
-      "android/support/v7/widget/SearchView$AutoCompleteTextViewReflector": "androidx/widget/SearchView$AutoCompleteTextViewReflector",
-      "android/support/v17/leanback/widget/OnChildLaidOutListener": "androidx/leanback/widget/OnChildLaidOutListener",
-      "android/support/v7/app/TwilightManager$TwilightState": "androidx/app/TwilightManager$TwilightState",
-      "android/support/v7/widget/FastScroller": "androidx/widget/FastScroller",
-      "android/support/design/widget/CoordinatorLayout$ViewElevationComparator": "androidx/design/widget/CoordinatorLayout$ViewElevationComparator",
-      "android/support/transition/TransitionManager": "androidx/transition/TransitionManager",
-      "android/support/v7/widget/AppCompatDrawableManager": "androidx/widget/AppCompatDrawableManager",
-      "android/support/animation/DynamicAnimation$OnAnimationUpdateListener": "androidx/animation/DynamicAnimation$OnAnimationUpdateListener",
-      "android/support/v4/graphics/TypefaceCompat": "androidx/graphics/TypefaceCompat",
-      "android/support/v17/preference/LeanbackPreferenceFragment": "androidx/leanback/preference/LeanbackPreferenceFragment",
-      "android/support/v17/leanback/widget/ParallaxTarget": "androidx/leanback/widget/ParallaxTarget",
-      "android/support/annotation/StyleRes": "androidx/annotation/StyleRes",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsDownAction": "androidx/leanback/widget/PlaybackControlsRow$ThumbsDownAction",
-      "android/support/v17/leanback/media/PlaybackTransportControlGlue$SeekUiClient": "androidx/leanback/media/PlaybackTransportControlGlue$SeekUiClient",
-      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteRecord": "androidx/media/SystemMediaRouteProvider$JellybeanImpl$SystemRouteRecord",
-      "android/support/v17/leanback/widget/ShadowHelper$ShadowHelperStubImpl": "androidx/leanback/widget/ShadowHelper$ShadowHelperStubImpl",
-      "android/support/animation/DynamicAnimation$ViewProperty": "androidx/animation/DynamicAnimation$ViewProperty",
-      "android/support/v7/app/AppCompatDelegateImplV23": "androidx/app/AppCompatDelegateImplV23",
-      "android/support/v4/app/NotificationManagerCompat": "androidx/app/NotificationManagerCompat",
-      "android/support/v4/media/session/MediaControllerCompat": "androidx/media/session/MediaControllerCompat",
-      "android/support/v17/leanback/widget/GuidedDatePickerAction": "androidx/leanback/widget/GuidedDatePickerAction",
-      "android/support/v4/widget/CircularProgressDrawable$ProgressDrawableSize": "androidx/widget/CircularProgressDrawable$ProgressDrawableSize",
-      "android/support/v17/leanback/widget/Presenter$ViewHolderTask": "androidx/leanback/widget/Presenter$ViewHolderTask",
-      "android/support/text/emoji/bundled/BundledEmojiCompatConfig": "androidx/text/emoji/bundled/BundledEmojiCompatConfig",
-      "android/support/content/ContentPager$CursorView": "androidx/content/ContentPager$CursorView",
-      "android/support/transition/TranslationAnimationCreator$TransitionPositionListener": "androidx/transition/TranslationAnimationCreator$TransitionPositionListener",
-      "android/support/v7/recyclerview/R$styleable": "androidx/recyclerview/R$styleable",
-      "android/support/v17/leanback/widget/PersistentFocusWrapper": "androidx/leanback/widget/PersistentFocusWrapper",
-      "android/support/v4/view/accessibility/AccessibilityWindowInfoCompat": "androidx/view/accessibility/AccessibilityWindowInfoCompat",
-      "android/support/v17/leanback/widget/PlaybackControlsRow$RewindAction": "androidx/leanback/widget/PlaybackControlsRow$RewindAction",
-      "android/support/v7/widget/AppCompatPopupWindow": "androidx/widget/AppCompatPopupWindow",
-      "android/support/mediacompat/R$id": "androidx/mediacompat/R$id",
-      "android/support/v17/leanback/widget/ItemAlignmentFacet": "androidx/leanback/widget/ItemAlignmentFacet",
-      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase$GestureHandler": "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase$GestureHandler",
-      "android/support/v17/leanback/widget/GuidedAction$BuilderBase": "androidx/leanback/widget/GuidedAction$BuilderBase",
-      "android/support/v17/leanback/widget/RoundedRectHelper$Impl": "androidx/leanback/widget/RoundedRectHelper$Impl",
-      "android/support/v7/media/MediaRouterJellybean$CallbackProxy": "androidx/media/MediaRouterJellybean$CallbackProxy",
-      "android/support/design/widget/CollapsingToolbarLayout$LayoutParams": "androidx/design/widget/CollapsingToolbarLayout$LayoutParams",
-      "android/support/v7/preference/DialogPreference": "androidx/preference/DialogPreference",
-      "android/support/v7/preference/EditTextPreference": "androidx/preference/EditTextPreference",
-      "android/support/v4/media/MediaBrowserCompatApi23$ItemCallbackProxy": "androidx/media/MediaBrowserCompatApi23$ItemCallbackProxy",
-      "android/support/v4/text/util/LinkifyCompat$LinkifyMask": "androidx/text/util/LinkifyCompat$LinkifyMask",
-      "android/support/v7/widget/helper/ItemTouchHelper$SimpleCallback": "androidx/widget/helper/ItemTouchHelper$SimpleCallback",
-      "android/support/wear/ambient/AmbientMode$AmbientCallbackProvider": "androidx/wear/ambient/AmbientMode$AmbientCallbackProvider",
-      "android/support/v7/widget/CardViewImpl": "androidx/widget/CardViewImpl",
-      "android/support/animation/FloatValueHolder": "androidx/animation/FloatValueHolder",
-      "android/support/transition/MatrixUtils": "androidx/transition/MatrixUtils",
-      "android/support/v14/preference/PreferenceFragment$OnPreferenceStartFragmentCallback": "androidx/preference/PreferenceFragment$OnPreferenceStartFragmentCallback",
-      "android/support/v4/widget/SlidingPaneLayout$PanelSlideListener": "androidx/widget/SlidingPaneLayout$PanelSlideListener",
-      "android/support/v7/util/SortedList": "androidx/util/SortedList",
-      "android/support/v4/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl": "androidx/view/AccessibilityDelegateCompat$AccessibilityDelegateBaseImpl",
-      "android/support/v7/app/MediaRouteControllerDialog$FetchArtTask": "androidx/app/MediaRouteControllerDialog$FetchArtTask",
-      "android/support/compat/R$drawable": "androidx/compat/R$drawable",
+      "android/support/transition/WindowIdApi14": "androidx/transition/WindowIdApi14",
+      "android/support/transition/WindowIdApi18": "androidx/transition/WindowIdApi18",
+      "android/support/transition/Visibility$1": "androidx/transition/Visibility$1",
+      "android/support/transition/Visibility$DisappearListener": "androidx/transition/Visibility$DisappearListener",
+      "android/support/transition/Visibility$Mode": "androidx/transition/Visibility$Mode",
       "android/support/transition/Visibility$VisibilityInfo": "androidx/transition/Visibility$VisibilityInfo",
-      "android/support/v7/widget/ThemedSpinnerAdapter": "androidx/widget/ThemedSpinnerAdapter",
-      "android/support/v17/leanback/widget/GuidanceStylingRelativeLayout": "androidx/leanback/widget/GuidanceStylingRelativeLayout",
-      "android/support/v7/media/MediaRouter$ProviderInfo": "androidx/media/MediaRouter$ProviderInfo",
-      "android/support/v7/media/MediaControlIntent": "androidx/media/MediaControlIntent",
-      "android/support/v17/leanback/widget/ListRow": "androidx/leanback/widget/ListRow",
-      "android/support/v7/view/menu/ListMenuPresenter$MenuAdapter": "androidx/view/menu/ListMenuPresenter$MenuAdapter",
-      "android/support/v4/app/FrameMetricsAggregator$FrameMetricsBaseImpl": "androidx/app/FrameMetricsAggregator$FrameMetricsBaseImpl",
-      "android/support/design/widget/TabLayout$SlidingTabStrip": "androidx/design/widget/TabLayout$SlidingTabStrip",
-      "android/support/content/ContentPager$ContentCallback": "androidx/content/ContentPager$ContentCallback",
-      "android/support/v4/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase": "androidx/media/MediaBrowserServiceCompat$MediaBrowserServiceImplBase",
-      "android/support/v7/util/TileList": "androidx/util/TileList",
-      "android/support/v7/widget/ActionBarBackgroundDrawable": "androidx/widget/ActionBarBackgroundDrawable",
-      "android/support/v4/widget/CursorFilter$CursorFilterClient": "androidx/widget/CursorFilter$CursorFilterClient",
-      "android/support/v17/leanback/database/CursorMapper": "androidx/leanback/database/CursorMapper",
-      "android/support/v17/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperKitKatImpl": "androidx/leanback/transition/LeanbackTransitionHelper$LeanbackTransitionHelperKitKatImpl",
-      "android/support/v7/cardview/R$styleable": "androidx/cardview/R$styleable",
-      "android/support/v17/leanback/transition/TransitionHelperApi21": "androidx/leanback/transition/TransitionHelperApi21",
-      "android/support/v7/widget/ViewInfoStore": "androidx/widget/ViewInfoStore",
-      "android/support/design/widget/BaseTransientBottomBar$BaseCallback$DismissEvent": "androidx/design/widget/BaseTransientBottomBar$BaseCallback$DismissEvent",
-      "android/support/percent/PercentLayoutHelper$PercentLayoutInfo": "androidx/PercentLayoutHelper$PercentLayoutInfo",
-      "android/support/v7/app/AppCompatCallback": "androidx/app/AppCompatCallback",
-      "android/support/wear/R$style": "androidx/wear/R$style",
-      "android/support/v17/leanback/widget/ItemAlignmentFacetHelper": "androidx/leanback/widget/ItemAlignmentFacetHelper",
-      "android/support/v7/view/menu/MenuItemImpl": "androidx/view/menu/MenuItemImpl",
-      "android/support/v4/content/ContextCompat": "androidx/content/ContextCompat",
-      "android/support/percent/PercentLayoutHelper$PercentMarginLayoutParams": "androidx/PercentLayoutHelper$PercentMarginLayoutParams",
-      "android/support/v7/widget/LayoutState": "androidx/widget/LayoutState",
-      "android/support/animation/AnimationHandler$AnimationFrameCallback": "androidx/animation/AnimationHandler$AnimationFrameCallback",
-      "android/support/v17/leanback/widget/SingleRow": "androidx/leanback/widget/SingleRow",
-      "android/support/v4/content/ModernAsyncTask$InternalHandler": "androidx/content/ModernAsyncTask$InternalHandler",
-      "android/support/transition/ImageViewUtilsImpl": "androidx/transition/ImageViewUtilsImpl",
-      "android/support/v7/widget/RtlSpacingHelper": "androidx/widget/RtlSpacingHelper",
-      "android/support/v4/content/PermissionChecker": "androidx/content/PermissionChecker",
-      "android/support/v7/preference/PreferenceCategory": "androidx/preference/PreferenceCategory",
-      "android/support/annotation/IntDef": "androidx/annotation/IntDef",
-      "android/support/v4/app/BundleCompat$BundleCompatBaseImpl": "androidx/app/BundleCompat$BundleCompatBaseImpl",
-      "android/support/v7/app/MediaRouteExpandCollapseButton": "androidx/app/MediaRouteExpandCollapseButton",
-      "android/support/v17/leanback/animation/LogAccelerateInterpolator": "androidx/leanback/animation/LogAccelerateInterpolator",
-      "android/support/v13/app/FragmentPagerAdapter": "androidx/app/legacy/FragmentPagerAdapter",
-      "android/support/content/InMemoryCursor": "androidx/content/InMemoryCursor",
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter": "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ActionsItemBridgeAdapter",
-      "android/support/v7/widget/AppCompatTextViewAutoSizeHelper": "androidx/widget/AppCompatTextViewAutoSizeHelper",
-      "android/support/v7/preference/PreferenceGroup": "androidx/preference/PreferenceGroup",
-      "android/support/v7/media/RegisteredMediaRouteProvider$Connection": "androidx/media/RegisteredMediaRouteProvider$Connection",
-      "android/support/v4/os/ParcelableCompatCreatorCallbacks": "androidx/os/ParcelableCompatCreatorCallbacks",
-      "android/support/v4/media/MediaMetadataCompat$BitmapKey": "androidx/media/MediaMetadataCompat$BitmapKey",
-      "android/support/v7/app/MediaRouteActionProvider$MediaRouterCallback": "androidx/app/MediaRouteActionProvider$MediaRouterCallback",
-      "android/support/v7/view/ViewPropertyAnimatorCompatSet": "androidx/view/ViewPropertyAnimatorCompatSet",
-      "android/support/v7/widget/AppCompatMultiAutoCompleteTextView": "androidx/widget/AppCompatMultiAutoCompleteTextView",
-      "android/support/v17/leanback/widget/GridLayoutManager$GridLinearSmoothScroller": "androidx/leanback/widget/GridLayoutManager$GridLinearSmoothScroller",
-      "android/support/design/internal/NavigationMenuView": "androidx/design/internal/NavigationMenuView",
-      "android/support/v17/leanback/app/SearchSupportFragment": "androidx/leanback/app/SearchSupportFragment",
-      "android/support/v7/media/SystemMediaRouteProvider$Api24Impl": "androidx/media/SystemMediaRouteProvider$Api24Impl",
-      "android/support/v4/content/FileProvider$PathStrategy": "androidx/content/FileProvider$PathStrategy",
-      "android/support/v17/leanback/util/StateMachine": "androidx/leanback/util/StateMachine",
-      "android/support/v7/widget/AppCompatCheckedTextView": "androidx/widget/AppCompatCheckedTextView",
-      "android/support/v4/media/session/PlaybackStateCompat$Builder": "androidx/media/session/PlaybackStateCompat$Builder",
-      "android/support/v17/leanback/widget/DetailsParallaxDrawable": "androidx/leanback/widget/DetailsParallaxDrawable",
-      "android/support/v17/leanback/widget/GuidedDatePickerAction$BuilderBase": "androidx/leanback/widget/GuidedDatePickerAction$BuilderBase",
-      "android/support/v17/leanback/widget/OnItemViewSelectedListener": "androidx/leanback/widget/OnItemViewSelectedListener",
-      "android/support/v7/widget/ShareActionProvider$OnShareTargetSelectedListener": "androidx/widget/ShareActionProvider$OnShareTargetSelectedListener",
-      "android/support/v4/app/JobIntentService$CompatWorkItem": "androidx/app/JobIntentService$CompatWorkItem",
-      "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat": "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat",
-      "android/support/v17/leanback/widget/OnActionClickedListener": "androidx/leanback/widget/OnActionClickedListener",
-      "android/support/design/widget/SwipeDismissBehavior$OnDismissListener": "androidx/design/widget/SwipeDismissBehavior$OnDismissListener",
-      "android/support/design/R$id": "androidx/design/R$id",
-      "android/support/content/ContentPager$Stats": "androidx/content/ContentPager$Stats",
-      "android/support/v17/leanback/widget/SinglePresenterSelector": "androidx/leanback/widget/SinglePresenterSelector",
-      "android/support/v7/widget/GridLayout$Arc": "androidx/widget/GridLayout$Arc",
-      "android/support/v17/leanback/widget/BaseGridView$OnKeyInterceptListener": "androidx/leanback/widget/BaseGridView$OnKeyInterceptListener",
-      "android/support/customtabs/CustomTabsService$Relation": "androidx/browser/customtabs/CustomTabsService$Relation",
-      "android/support/v4/content/WakefulBroadcastReceiver": "androidx/content/WakefulBroadcastReceiver",
-      "android/support/v4/os/LocaleHelper": "androidx/os/LocaleHelper",
-      "android/support/v7/app/ActionBar$NavigationMode": "androidx/app/ActionBar$NavigationMode",
-      "android/support/v7/media/RemotePlaybackClient$ActionReceiver": "androidx/media/RemotePlaybackClient$ActionReceiver",
-      "android/support/v7/view/menu/CascadingMenuPopup$HorizPosition": "androidx/view/menu/CascadingMenuPopup$HorizPosition",
-      "android/support/v13/view/inputmethod/EditorInfoCompat": "androidx/view/inputmethod/EditorInfoCompat",
-      "android/support/v17/leanback/widget/Grid": "androidx/leanback/widget/Grid",
-      "android/support/annotation/TransitionRes": "androidx/annotation/TransitionRes",
-      "android/support/v4/media/VolumeProviderCompat": "androidx/media/VolumeProviderCompat",
-      "android/support/multidex/MultiDexApplication": "androidx/multidex/MultiDexApplication",
-      "android/support/text/emoji/EmojiCompat$MetadataRepoLoader": "androidx/text/emoji/EmojiCompat$MetadataRepoLoader",
-      "android/support/design/widget/TextInputLayout": "androidx/design/widget/TextInputLayout",
-      "android/support/v4/view/ViewCompat$ViewCompatApi24Impl": "androidx/view/legacy/ViewCompat$ViewCompatApi24Impl",
-      "android/support/v4/provider/FontRequest": "androidx/provider/FontRequest",
-      "android/support/v4/media/session/MediaButtonReceiver$MediaButtonConnectionCallback": "androidx/media/session/MediaButtonReceiver$MediaButtonConnectionCallback",
-      "android/support/v7/widget/RecyclerView$SmoothScroller$ScrollVectorProvider": "androidx/widget/RecyclerView$SmoothScroller$ScrollVectorProvider",
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImpl": "androidx/media/session/MediaSessionCompat$MediaSessionImpl",
-      "android/support/v4/content/ModernAsyncTask$Status": "androidx/content/ModernAsyncTask$Status",
-      "android/support/v7/widget/AppCompatDrawableManager$ColorFilterLruCache": "androidx/widget/AppCompatDrawableManager$ColorFilterLruCache",
-      "android/support/multidex/MultiDex": "androidx/multidex/MultiDex",
-      "android/support/wear/ambient/WearableControllerProvider": "androidx/wear/ambient/WearableControllerProvider",
-      "android/support/v17/leanback/widget/ForegroundHelper": "androidx/leanback/widget/ForegroundHelper",
-      "android/support/v4/app/DialogFragment$DialogStyle": "androidx/app/DialogFragment$DialogStyle",
-      "android/support/v4/graphics/TypefaceCompatApi24Impl": "androidx/graphics/TypefaceCompatApi24Impl",
-      "android/support/v7/app/ActionBar$Tab": "androidx/app/ActionBar$Tab",
-      "android/support/transition/CircularPropagation": "androidx/transition/CircularPropagation",
-      "android/support/v7/app/ResourcesFlusher": "androidx/app/ResourcesFlusher",
-      "android/support/text/emoji/MetadataListReader$OffsetInfo": "androidx/text/emoji/MetadataListReader$OffsetInfo",
-      "android/support/v4/app/ActivityOptionsCompat$ActivityOptionsCompatApi24Impl": "androidx/app/ActivityOptionsCompat$ActivityOptionsCompatApi24Impl",
-      "android/support/v4/content/SharedPreferencesCompat$EditorCompat": "androidx/content/SharedPreferencesCompat$EditorCompat",
-      "android/support/v7/widget/RecyclerView$OnFlingListener": "androidx/widget/RecyclerView$OnFlingListener",
+      "android/arch/persistence/room/parser/SQLiteParser$Select_coreContext": "androidx/persistence/room/parser/SQLiteParser$Select_coreContext",
+      "android/arch/persistence/room/parser/SQLiteParser": "androidx/persistence/room/parser/SQLiteParser",
+      "android/arch/persistence/room/parser/SQLiteParser$Result_columnContext": "androidx/persistence/room/parser/SQLiteParser$Result_columnContext",
+      "android/arch/persistence/room/parser/SQLiteParser$ExprContext": "androidx/persistence/room/parser/SQLiteParser$ExprContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Table_or_subqueryContext": "androidx/persistence/room/parser/SQLiteParser$Table_or_subqueryContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Join_clauseContext": "androidx/persistence/room/parser/SQLiteParser$Join_clauseContext",
+      "android/arch/persistence/room/parser/SQLiteListener": "androidx/persistence/room/parser/SQLiteListener",
+      "android/arch/persistence/room/parser/SQLiteVisitor": "androidx/persistence/room/parser/SQLiteVisitor",
+      "android/arch/persistence/room/parser/SQLiteParser$Function_nameContext": "androidx/persistence/room/parser/SQLiteParser$Function_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Any_nameContext": "androidx/persistence/room/parser/SQLiteParser$Any_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Indexed_columnContext": "androidx/persistence/room/parser/SQLiteParser$Indexed_columnContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Column_nameContext": "androidx/persistence/room/parser/SQLiteParser$Column_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Collation_nameContext": "androidx/persistence/room/parser/SQLiteParser$Collation_nameContext",
+      "android/arch/persistence/room/parser/SQLiteLexer": "androidx/persistence/room/parser/SQLiteLexer",
+      "android/arch/persistence/room/parser/SQLiteParser$KeywordContext": "androidx/persistence/room/parser/SQLiteParser$KeywordContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Create_view_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Create_view_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$View_nameContext": "androidx/persistence/room/parser/SQLiteParser$View_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Select_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Select_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Database_nameContext": "androidx/persistence/room/parser/SQLiteParser$Database_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Unary_operatorContext": "androidx/persistence/room/parser/SQLiteParser$Unary_operatorContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Table_aliasContext": "androidx/persistence/room/parser/SQLiteParser$Table_aliasContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Table_constraintContext": "androidx/persistence/room/parser/SQLiteParser$Table_constraintContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Conflict_clauseContext": "androidx/persistence/room/parser/SQLiteParser$Conflict_clauseContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Foreign_key_clauseContext": "androidx/persistence/room/parser/SQLiteParser$Foreign_key_clauseContext",
+      "android/arch/persistence/room/parser/SQLiteParser$NameContext": "androidx/persistence/room/parser/SQLiteParser$NameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Select_or_valuesContext": "androidx/persistence/room/parser/SQLiteParser$Select_or_valuesContext",
+      "android/arch/persistence/room/parser/SQLiteParser$With_clauseContext": "androidx/persistence/room/parser/SQLiteParser$With_clauseContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Compound_operatorContext": "androidx/persistence/room/parser/SQLiteParser$Compound_operatorContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Ordering_termContext": "androidx/persistence/room/parser/SQLiteParser$Ordering_termContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Update_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Update_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Qualified_table_nameContext": "androidx/persistence/room/parser/SQLiteParser$Qualified_table_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Compound_select_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Compound_select_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Analyze_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Analyze_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Table_or_index_nameContext": "androidx/persistence/room/parser/SQLiteParser$Table_or_index_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Transaction_nameContext": "androidx/persistence/room/parser/SQLiteParser$Transaction_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Savepoint_nameContext": "androidx/persistence/room/parser/SQLiteParser$Savepoint_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Pragma_nameContext": "androidx/persistence/room/parser/SQLiteParser$Pragma_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Module_nameContext": "androidx/persistence/room/parser/SQLiteParser$Module_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Trigger_nameContext": "androidx/persistence/room/parser/SQLiteParser$Trigger_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Index_nameContext": "androidx/persistence/room/parser/SQLiteParser$Index_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Foreign_tableContext": "androidx/persistence/room/parser/SQLiteParser$Foreign_tableContext",
+      "android/arch/persistence/room/parser/SQLiteParser$New_table_nameContext": "androidx/persistence/room/parser/SQLiteParser$New_table_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Table_nameContext": "androidx/persistence/room/parser/SQLiteParser$Table_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Table_function_nameContext": "androidx/persistence/room/parser/SQLiteParser$Table_function_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Schema_nameContext": "androidx/persistence/room/parser/SQLiteParser$Schema_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Column_aliasContext": "androidx/persistence/room/parser/SQLiteParser$Column_aliasContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Module_argumentContext": "androidx/persistence/room/parser/SQLiteParser$Module_argumentContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Error_messageContext": "androidx/persistence/room/parser/SQLiteParser$Error_messageContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Literal_valueContext": "androidx/persistence/room/parser/SQLiteParser$Literal_valueContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Signed_numberContext": "androidx/persistence/room/parser/SQLiteParser$Signed_numberContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Join_constraintContext": "androidx/persistence/room/parser/SQLiteParser$Join_constraintContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Join_operatorContext": "androidx/persistence/room/parser/SQLiteParser$Join_operatorContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Common_table_expressionContext": "androidx/persistence/room/parser/SQLiteParser$Common_table_expressionContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Pragma_valueContext": "androidx/persistence/room/parser/SQLiteParser$Pragma_valueContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Raise_functionContext": "androidx/persistence/room/parser/SQLiteParser$Raise_functionContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Column_constraintContext": "androidx/persistence/room/parser/SQLiteParser$Column_constraintContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Type_nameContext": "androidx/persistence/room/parser/SQLiteParser$Type_nameContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Column_defContext": "androidx/persistence/room/parser/SQLiteParser$Column_defContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Vacuum_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Vacuum_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Update_stmt_limitedContext": "androidx/persistence/room/parser/SQLiteParser$Update_stmt_limitedContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Simple_select_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Simple_select_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Savepoint_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Savepoint_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Rollback_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Rollback_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Release_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Release_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Reindex_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Reindex_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Pragma_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Pragma_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Insert_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Insert_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Factored_select_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Factored_select_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Drop_view_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Drop_view_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Drop_trigger_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Drop_trigger_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Drop_table_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Drop_table_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Drop_index_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Drop_index_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Detach_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Detach_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Delete_stmt_limitedContext": "androidx/persistence/room/parser/SQLiteParser$Delete_stmt_limitedContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Delete_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Delete_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Create_virtual_table_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Create_virtual_table_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Create_trigger_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Create_trigger_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Create_table_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Create_table_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Create_index_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Create_index_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Commit_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Commit_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Begin_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Begin_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Attach_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Attach_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Alter_table_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Alter_table_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Sql_stmtContext": "androidx/persistence/room/parser/SQLiteParser$Sql_stmtContext",
+      "android/arch/persistence/room/parser/SQLiteParser$Sql_stmt_listContext": "androidx/persistence/room/parser/SQLiteParser$Sql_stmt_listContext",
+      "android/arch/persistence/room/parser/SQLiteParser$ErrorContext": "androidx/persistence/room/parser/SQLiteParser$ErrorContext",
+      "android/arch/persistence/room/parser/SQLiteParser$ParseContext": "androidx/persistence/room/parser/SQLiteParser$ParseContext",
+      "android/arch/persistence/room/parser/SQLiteBaseVisitor": "androidx/persistence/room/parser/SQLiteBaseVisitor",
+      "android/arch/persistence/room/parser/SQLiteBaseListener": "androidx/persistence/room/parser/SQLiteBaseListener",
+      "android/arch/persistence/room/verifier/ColumnInfo": "androidx/persistence/room/verifier/ColumnInfo",
+      "android/arch/persistence/room/parser/SQLTypeAffinity": "androidx/persistence/room/parser/SQLTypeAffinity",
+      "android/arch/persistence/room/RoomProcessor$ContextBoundProcessingStep": "androidx/persistence/room/RoomProcessor$ContextBoundProcessingStep",
+      "android/arch/persistence/room/RoomProcessor": "androidx/persistence/room/RoomProcessor",
+      "android/arch/persistence/room/processor/Context": "androidx/persistence/room/processor/Context",
+      "android/arch/persistence/room/preconditions/Checks": "androidx/persistence/room/preconditions/Checks",
+      "android/arch/persistence/room/log/RLog": "androidx/persistence/room/log/RLog",
+      "android/arch/persistence/room/ext/Element_extKt": "androidx/persistence/room/ext/Element_extKt",
+      "android/arch/persistence/room/RoomProcessor$DatabaseProcessingStep": "androidx/persistence/room/RoomProcessor$DatabaseProcessingStep",
+      "android/arch/persistence/room/Database": "androidx/persistence/room/Database",
+      "android/arch/persistence/room/processor/DatabaseProcessor": "androidx/persistence/room/processor/DatabaseProcessor",
+      "android/arch/persistence/room/vo/Database": "androidx/persistence/room/vo/Database",
+      "android/arch/persistence/room/vo/DaoMethod": "androidx/persistence/room/vo/DaoMethod",
+      "android/arch/persistence/room/writer/DaoWriter": "androidx/persistence/room/writer/DaoWriter",
+      "android/arch/persistence/room/vo/Dao": "androidx/persistence/room/vo/Dao",
+      "android/arch/persistence/room/writer/DatabaseWriter": "androidx/persistence/room/writer/DatabaseWriter",
+      "android/arch/persistence/room/vo/Warning": "androidx/persistence/room/vo/Warning",
+      "android/arch/persistence/room/processor/ProcessorErrors": "androidx/persistence/room/processor/ProcessorErrors",
+      "android/arch/persistence/room/Dao": "androidx/persistence/room/Dao",
+      "android/arch/persistence/room/Entity": "androidx/persistence/room/Entity",
+      "android/arch/persistence/room/parser/SQLTypeAffinity$Companion": "androidx/persistence/room/parser/SQLTypeAffinity$Companion",
+      "android/arch/persistence/room/parser/Collate": "androidx/persistence/room/parser/Collate",
+      "android/arch/persistence/room/parser/Collate$Companion": "androidx/persistence/room/parser/Collate$Companion",
+      "android/arch/persistence/room/parser/SQLTypeAffinity$WhenMappings": "androidx/persistence/room/parser/SQLTypeAffinity$WhenMappings",
+      "android/arch/persistence/room/parser/Section$Companion": "androidx/persistence/room/parser/Section$Companion",
+      "android/arch/persistence/room/parser/Section": "androidx/persistence/room/parser/Section",
+      "android/arch/persistence/room/parser/SectionType": "androidx/persistence/room/parser/SectionType",
+      "android/arch/persistence/room/parser/ParsedQuery$sections$2": "androidx/persistence/room/parser/ParsedQuery$sections$2",
+      "android/arch/persistence/room/parser/ParsedQuery": "androidx/persistence/room/parser/ParsedQuery",
+      "android/arch/persistence/room/parser/QueryType": "androidx/persistence/room/parser/QueryType",
+      "android/arch/persistence/room/parser/ParsedQuery$queryWithReplacedBindParams$2$1": "androidx/persistence/room/parser/ParsedQuery$queryWithReplacedBindParams$2$1",
+      "android/arch/persistence/room/parser/ParsedQuery$queryWithReplacedBindParams$2": "androidx/persistence/room/parser/ParsedQuery$queryWithReplacedBindParams$2",
+      "android/arch/persistence/room/parser/ParsedQuery$WhenMappings": "androidx/persistence/room/parser/ParsedQuery$WhenMappings",
+      "android/arch/persistence/room/parser/SqlParser": "androidx/persistence/room/parser/SqlParser",
+      "android/arch/persistence/room/parser/SqlParser$Companion": "androidx/persistence/room/parser/SqlParser$Companion",
+      "android/arch/persistence/room/parser/SqlParser$Companion$parse$1": "androidx/persistence/room/parser/SqlParser$Companion$parse$1",
+      "android/arch/persistence/room/parser/ParserErrors": "androidx/persistence/room/parser/ParserErrors",
+      "android/arch/persistence/room/parser/QueryVisitor": "androidx/persistence/room/parser/QueryVisitor",
+      "android/arch/persistence/room/parser/Table": "androidx/persistence/room/parser/Table",
+      "android/arch/persistence/room/parser/ParsedQuery$errors$2": "androidx/persistence/room/parser/ParsedQuery$errors$2",
+      "android/arch/persistence/room/parser/QueryVisitor$createParsedQuery$$inlined$sortedBy$1": "androidx/persistence/room/parser/QueryVisitor$createParsedQuery$$inlined$sortedBy$1",
+      "android/arch/persistence/room/parser/ParserErrors$invalidQueryType$1": "androidx/persistence/room/parser/ParserErrors$invalidQueryType$1",
+      "android/arch/persistence/room/parser/QueryType$Companion": "androidx/persistence/room/parser/QueryType$Companion",
+      "android/arch/persistence/room/parser/ParsedQuery$bindSections$2": "androidx/persistence/room/parser/ParsedQuery$bindSections$2",
+      "android/arch/persistence/room/parser/ParsedQuery$Companion": "androidx/persistence/room/parser/ParsedQuery$Companion",
+      "android/arch/persistence/room/verifier/QueryResultInfo": "androidx/persistence/room/verifier/QueryResultInfo",
+      "android/arch/persistence/room/ext/RoomTypeNames": "androidx/persistence/room/ext/RoomTypeNames",
+      "android/arch/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_TO_BOOLEAN_VISITOR$1": "androidx/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_TO_BOOLEAN_VISITOR$1",
+      "android/arch/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_STRING_ARR_VISITOR$1": "androidx/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_STRING_ARR_VISITOR$1",
+      "android/arch/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_TO_STRING_VISITOR$1": "androidx/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_TO_STRING_VISITOR$1",
+      "android/arch/persistence/room/ext/LifecyclesTypeNames": "androidx/persistence/room/ext/LifecyclesTypeNames",
+      "android/arch/persistence/room/ext/RoomRxJava2TypeNames": "androidx/persistence/room/ext/RoomRxJava2TypeNames",
+      "android/arch/persistence/room/ext/Element_extKt$TO_LIST_OF_TYPES$1": "androidx/persistence/room/ext/Element_extKt$TO_LIST_OF_TYPES$1",
+      "android/arch/persistence/room/ext/Element_extKt$TO_TYPE$1": "androidx/persistence/room/ext/Element_extKt$TO_TYPE$1",
+      "android/arch/persistence/room/ext/Element_extKt$extendsBound$1": "androidx/persistence/room/ext/Element_extKt$extendsBound$1",
+      "android/arch/persistence/room/ext/RxJava2TypeNames": "androidx/persistence/room/ext/RxJava2TypeNames",
+      "android/arch/persistence/room/ext/ArchTypeNames": "androidx/persistence/room/ext/ArchTypeNames",
+      "android/arch/persistence/room/ext/SupportDbTypeNames": "androidx/persistence/room/ext/SupportDbTypeNames",
+      "android/arch/persistence/room/ext/AndroidTypeNames": "androidx/persistence/room/ext/AndroidTypeNames",
+      "android/arch/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_TO_INT_VISITOR$1": "androidx/persistence/room/ext/Element_extKt$ANNOTATION_VALUE_TO_INT_VISITOR$1",
+      "android/arch/persistence/room/ext/PagingTypeNames": "androidx/persistence/room/ext/PagingTypeNames",
+      "android/arch/persistence/room/ext/ReactiveStreamsTypeNames": "androidx/persistence/room/ext/ReactiveStreamsTypeNames",
+      "android/arch/persistence/room/ext/Javapoet_extKt": "androidx/persistence/room/ext/Javapoet_extKt",
+      "android/arch/persistence/room/ext/CommonTypeNames": "androidx/persistence/room/ext/CommonTypeNames",
+      "android/arch/persistence/room/solver/QueryResultBinderProvider": "androidx/persistence/room/solver/QueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/QueryResultBinder": "androidx/persistence/room/solver/query/result/QueryResultBinder",
+      "android/arch/persistence/room/solver/TypeAdapterStore$Companion$create$4": "androidx/persistence/room/solver/TypeAdapterStore$Companion$create$4",
+      "android/arch/persistence/room/solver/types/ColumnTypeAdapter": "androidx/persistence/room/solver/types/ColumnTypeAdapter",
+      "android/arch/persistence/room/solver/TypeAdapterStore$Companion": "androidx/persistence/room/solver/TypeAdapterStore$Companion",
+      "android/arch/persistence/room/solver/TypeAdapterStore": "androidx/persistence/room/solver/TypeAdapterStore",
+      "android/arch/persistence/room/solver/CodeGenScope": "androidx/persistence/room/solver/CodeGenScope",
+      "android/arch/persistence/room/solver/CodeGenScope$Companion": "androidx/persistence/room/solver/CodeGenScope$Companion",
+      "android/arch/persistence/room/writer/ClassWriter": "androidx/persistence/room/writer/ClassWriter",
+      "android/arch/persistence/room/solver/TypeAdapterStore$Companion$create$1": "androidx/persistence/room/solver/TypeAdapterStore$Companion$create$1",
+      "android/arch/persistence/room/solver/TypeAdapterStore$Companion$create$3": "androidx/persistence/room/solver/TypeAdapterStore$Companion$create$3",
+      "android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter": "androidx/persistence/room/solver/types/PrimitiveColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter$Companion": "androidx/persistence/room/solver/types/PrimitiveColumnTypeAdapter$Companion",
+      "android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter": "androidx/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter$Companion": "androidx/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter$Companion",
+      "android/arch/persistence/room/solver/types/StringColumnTypeAdapter": "androidx/persistence/room/solver/types/StringColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/ByteArrayColumnTypeAdapter": "androidx/persistence/room/solver/types/ByteArrayColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/PrimitiveBooleanToIntConverter": "androidx/persistence/room/solver/types/PrimitiveBooleanToIntConverter",
+      "android/arch/persistence/room/solver/types/TypeConverter": "androidx/persistence/room/solver/types/TypeConverter",
+      "android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter": "androidx/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter",
+      "android/arch/persistence/room/solver/TypeAdapterStore$findTypeConverter$2": "androidx/persistence/room/solver/TypeAdapterStore$findTypeConverter$2",
+      "android/arch/persistence/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider$dataSourceFactoryTypeMirror$2": "androidx/persistence/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider$dataSourceFactoryTypeMirror$2",
+      "android/arch/persistence/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/RowAdapter": "androidx/persistence/room/solver/query/result/RowAdapter",
+      "android/arch/persistence/room/solver/query/result/ListQueryResultAdapter": "androidx/persistence/room/solver/query/result/ListQueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/PositionalDataSourceQueryResultBinder": "androidx/persistence/room/solver/query/result/PositionalDataSourceQueryResultBinder",
+      "android/arch/persistence/room/solver/query/result/LivePagedListQueryResultBinder": "androidx/persistence/room/solver/query/result/LivePagedListQueryResultBinder",
+      "android/arch/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider$positionalDataSourceTypeMirror$2": "androidx/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider$positionalDataSourceTypeMirror$2",
+      "android/arch/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider$dataSourceTypeMirror$2": "androidx/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider$dataSourceTypeMirror$2",
+      "android/arch/persistence/room/solver/binderprovider/RxSingleQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/RxSingleQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder$RxType": "androidx/persistence/room/solver/query/result/RxCallableQueryResultBinder$RxType",
+      "android/arch/persistence/room/solver/binderprovider/CursorQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/CursorQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/CursorQueryResultBinder": "androidx/persistence/room/solver/query/result/CursorQueryResultBinder",
+      "android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider$hasRxJava2Artifact$2": "androidx/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider$hasRxJava2Artifact$2",
+      "android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider$flowableTypeMirror$2": "androidx/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider$flowableTypeMirror$2",
+      "android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/ObservableQueryResultBinderProvider": "androidx/persistence/room/solver/ObservableQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider$liveDataTypeMirror$2": "androidx/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider$liveDataTypeMirror$2",
+      "android/arch/persistence/room/solver/query/result/QueryResultAdapter": "androidx/persistence/room/solver/query/result/QueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder": "androidx/persistence/room/solver/query/result/LiveDataQueryResultBinder",
+      "android/arch/persistence/room/solver/binderprovider/RxMaybeQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/RxMaybeQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider$hasRxJava2Artifact$2": "androidx/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider$hasRxJava2Artifact$2",
+      "android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder": "androidx/persistence/room/solver/query/result/RxCallableQueryResultBinder",
+      "android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder": "androidx/persistence/room/solver/query/result/FlowableQueryResultBinder",
+      "android/arch/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider": "androidx/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/InstantQueryResultBinder": "androidx/persistence/room/solver/query/result/InstantQueryResultBinder",
+      "android/arch/persistence/room/solver/types/CursorValueReader": "androidx/persistence/room/solver/types/CursorValueReader",
+      "android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter$Companion$WhenMappings": "androidx/persistence/room/solver/types/PrimitiveColumnTypeAdapter$Companion$WhenMappings",
+      "android/arch/persistence/room/solver/types/CustomTypeConverterWrapper": "androidx/persistence/room/solver/types/CustomTypeConverterWrapper",
+      "android/arch/persistence/room/solver/types/CustomTypeConverterWrapper$typeConverter$1": "androidx/persistence/room/solver/types/CustomTypeConverterWrapper$typeConverter$1",
+      "android/arch/persistence/room/vo/CustomTypeConverter": "androidx/persistence/room/vo/CustomTypeConverter",
+      "android/arch/persistence/room/writer/ClassWriter$SharedFieldSpec": "androidx/persistence/room/writer/ClassWriter$SharedFieldSpec",
+      "android/arch/persistence/room/solver/types/CompositeTypeConverter": "androidx/persistence/room/solver/types/CompositeTypeConverter",
+      "android/arch/persistence/room/solver/types/CompositeAdapter": "androidx/persistence/room/solver/types/CompositeAdapter",
+      "android/arch/persistence/room/solver/types/NoOpConverter": "androidx/persistence/room/solver/types/NoOpConverter",
+      "android/arch/persistence/room/solver/types/PrimitiveBooleanToIntConverter$create$1": "androidx/persistence/room/solver/types/PrimitiveBooleanToIntConverter$create$1",
+      "android/arch/persistence/room/solver/types/PrimitiveBooleanToIntConverter$create$2": "androidx/persistence/room/solver/types/PrimitiveBooleanToIntConverter$create$2",
+      "android/arch/persistence/room/solver/types/StatementValueBinder": "androidx/persistence/room/solver/types/StatementValueBinder",
+      "android/arch/persistence/room/solver/types/ColumnTypeAdapter$outTypeName$2": "androidx/persistence/room/solver/types/ColumnTypeAdapter$outTypeName$2",
+      "android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter$create$1": "androidx/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter$create$1",
+      "android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter$create$2": "androidx/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter$create$2",
+      "android/arch/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter": "androidx/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/parameter/QueryParameterAdapter": "androidx/persistence/room/solver/query/parameter/QueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter": "androidx/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/parameter/BasicQueryParameterAdapter": "androidx/persistence/room/solver/query/parameter/BasicQueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/result/PojoRowAdapter$Mapping": "androidx/persistence/room/solver/query/result/PojoRowAdapter$Mapping",
+      "android/arch/persistence/room/solver/query/result/PojoRowAdapter": "androidx/persistence/room/solver/query/result/PojoRowAdapter",
+      "android/arch/persistence/room/vo/FieldWithIndex": "androidx/persistence/room/vo/FieldWithIndex",
+      "android/arch/persistence/room/vo/Field": "androidx/persistence/room/vo/Field",
+      "android/arch/persistence/room/solver/query/result/CursorQueryResultBinder$Companion": "androidx/persistence/room/solver/query/result/CursorQueryResultBinder$Companion",
+      "android/arch/persistence/room/solver/query/result/CursorQueryResultBinder$Companion$NO_OP_RESULT_ADAPTER$1": "androidx/persistence/room/solver/query/result/CursorQueryResultBinder$Companion$NO_OP_RESULT_ADAPTER$1",
+      "android/arch/persistence/room/solver/query/result/TransactionWrapper": "androidx/persistence/room/solver/query/result/TransactionWrapper",
+      "android/arch/persistence/room/solver/query/result/PositionalDataSourceQueryResultBinder$convertAndReturn$tableNamesList$1": "androidx/persistence/room/solver/query/result/PositionalDataSourceQueryResultBinder$convertAndReturn$tableNamesList$1",
+      "android/arch/persistence/room/solver/query/result/TransactionWrapperKt": "androidx/persistence/room/solver/query/result/TransactionWrapperKt",
+      "android/arch/persistence/room/writer/DaoWriter$Companion": "androidx/persistence/room/writer/DaoWriter$Companion",
+      "android/arch/persistence/room/solver/query/result/SingleEntityQueryResultAdapter": "androidx/persistence/room/solver/query/result/SingleEntityQueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/BaseObservableQueryResultBinder": "androidx/persistence/room/solver/query/result/BaseObservableQueryResultBinder",
+      "android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder$createAnonymousObserver$tableNamesList$1": "androidx/persistence/room/solver/query/result/LiveDataQueryResultBinder$createAnonymousObserver$tableNamesList$1",
+      "android/arch/persistence/room/solver/query/result/TransactionWrapperKt$transactionWrapper$1": "androidx/persistence/room/solver/query/result/TransactionWrapperKt$transactionWrapper$1",
+      "android/arch/persistence/room/solver/query/result/PojoRowAdapter$onCursorFinished$1": "androidx/persistence/room/solver/query/result/PojoRowAdapter$onCursorFinished$1",
+      "android/arch/persistence/room/vo/RelationCollector": "androidx/persistence/room/vo/RelationCollector",
+      "android/arch/persistence/room/vo/Pojo": "androidx/persistence/room/vo/Pojo",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter": "androidx/persistence/room/writer/FieldReadWriteWriter",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion",
+      "android/arch/persistence/room/vo/RelationCollector$Companion": "androidx/persistence/room/vo/RelationCollector$Companion",
+      "android/arch/persistence/room/solver/query/result/TransactionWrapperKt$transactionWrapper$2": "androidx/persistence/room/solver/query/result/TransactionWrapperKt$transactionWrapper$2",
+      "android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder$convertAndReturn$1$tableNamesList$1": "androidx/persistence/room/solver/query/result/FlowableQueryResultBinder$convertAndReturn$1$tableNamesList$1",
+      "android/arch/persistence/room/solver/query/result/SingleColumnRowAdapter": "androidx/persistence/room/solver/query/result/SingleColumnRowAdapter",
+      "android/arch/persistence/room/solver/query/result/ArrayQueryResultAdapter": "androidx/persistence/room/solver/query/result/ArrayQueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/EntityRowAdapter": "androidx/persistence/room/solver/query/result/EntityRowAdapter",
+      "android/arch/persistence/room/vo/Entity": "androidx/persistence/room/vo/Entity",
+      "android/arch/persistence/room/writer/EntityCursorConverterWriter": "androidx/persistence/room/writer/EntityCursorConverterWriter",
+      "android/arch/persistence/room/writer/ClassWriter$SharedMethodSpec": "androidx/persistence/room/writer/ClassWriter$SharedMethodSpec",
+      "android/arch/persistence/room/solver/TypeAdapterStore$findRowAdapter$1": "androidx/persistence/room/solver/TypeAdapterStore$findRowAdapter$1",
+      "android/arch/persistence/room/solver/TypeAdapterStore$knownColumnTypeMirrors$2": "androidx/persistence/room/solver/TypeAdapterStore$knownColumnTypeMirrors$2",
+      "android/arch/persistence/room/log/RLog$CollectingMessager": "androidx/persistence/room/log/RLog$CollectingMessager",
+      "android/arch/persistence/room/processor/EntityProcessor": "androidx/persistence/room/processor/EntityProcessor",
+      "android/arch/persistence/room/processor/PojoProcessor": "androidx/persistence/room/processor/PojoProcessor",
+      "android/arch/persistence/room/processor/FieldProcessor$BindingScope": "androidx/persistence/room/processor/FieldProcessor$BindingScope",
+      "android/arch/persistence/room/vo/EmbeddedField": "androidx/persistence/room/vo/EmbeddedField",
+      "android/arch/persistence/room/processor/TransactionMethodProcessor": "androidx/persistence/room/processor/TransactionMethodProcessor",
+      "android/arch/persistence/room/vo/TransactionMethod": "androidx/persistence/room/vo/TransactionMethod",
+      "android/arch/persistence/room/processor/ProcessorErrors$cursorPojoMismatch$unusedFieldsWarning$1": "androidx/persistence/room/processor/ProcessorErrors$cursorPojoMismatch$unusedFieldsWarning$1",
+      "android/arch/persistence/room/processor/ProcessorErrors$cursorPojoMismatch$1": "androidx/persistence/room/processor/ProcessorErrors$cursorPojoMismatch$1",
+      "android/arch/persistence/room/processor/ProcessorErrors$duplicateTypeConverters$1": "androidx/persistence/room/processor/ProcessorErrors$duplicateTypeConverters$1",
+      "android/arch/persistence/room/processor/ProcessorErrors$INVALID_ANNOTATION_COUNT_IN_DAO_METHOD$1": "androidx/persistence/room/processor/ProcessorErrors$INVALID_ANNOTATION_COUNT_IN_DAO_METHOD$1",
+      "android/arch/persistence/room/processor/ProcessorErrors$CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION$1": "androidx/persistence/room/processor/ProcessorErrors$CANNOT_USE_MORE_THAN_ONE_POJO_FIELD_ANNOTATION$1",
+      "android/arch/persistence/room/Query": "androidx/persistence/room/Query",
+      "android/arch/persistence/room/Insert": "androidx/persistence/room/Insert",
+      "android/arch/persistence/room/Delete": "androidx/persistence/room/Delete",
+      "android/arch/persistence/room/Update": "androidx/persistence/room/Update",
+      "android/arch/persistence/room/RawQuery": "androidx/persistence/room/RawQuery",
+      "android/arch/persistence/room/processor/DaoProcessor": "androidx/persistence/room/processor/DaoProcessor",
+      "android/arch/persistence/room/processor/DaoProcessor$Companion": "androidx/persistence/room/processor/DaoProcessor$Companion",
+      "android/arch/persistence/room/processor/PojoProcessor$Companion": "androidx/persistence/room/processor/PojoProcessor$Companion",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor$getInsertionType$2": "androidx/persistence/room/processor/InsertionMethodProcessor$getInsertionType$2",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor": "androidx/persistence/room/processor/InsertionMethodProcessor",
+      "android/arch/persistence/room/vo/InsertionMethod$Type": "androidx/persistence/room/vo/InsertionMethod$Type",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor$getInsertionType$1": "androidx/persistence/room/processor/InsertionMethodProcessor$getInsertionType$1",
+      "android/arch/persistence/room/processor/QueryMethodProcessor$WhenMappings": "androidx/persistence/room/processor/QueryMethodProcessor$WhenMappings",
+      "android/arch/persistence/room/processor/PojoProcessor$assignGetter$success$1": "androidx/persistence/room/processor/PojoProcessor$assignGetter$success$1",
+      "android/arch/persistence/room/processor/EntityProcessor$Companion$INDEX_VISITOR$1": "androidx/persistence/room/processor/EntityProcessor$Companion$INDEX_VISITOR$1",
+      "android/arch/persistence/room/processor/EntityProcessor$IndexInput": "androidx/persistence/room/processor/EntityProcessor$IndexInput",
+      "android/arch/persistence/room/processor/EntityProcessor$Companion": "androidx/persistence/room/processor/EntityProcessor$Companion",
+      "android/arch/persistence/room/processor/EntityProcessor$checkIndicesForForeignKeys$1": "androidx/persistence/room/processor/EntityProcessor$checkIndicesForForeignKeys$1",
+      "android/arch/persistence/room/vo/PrimaryKey": "androidx/persistence/room/vo/PrimaryKey",
+      "android/arch/persistence/room/processor/DatabaseProcessor$validateUniqueDaoClasses$check$1": "androidx/persistence/room/processor/DatabaseProcessor$validateUniqueDaoClasses$check$1",
+      "android/arch/persistence/room/processor/cache/Cache$FullKey": "androidx/persistence/room/processor/cache/Cache$FullKey",
+      "android/arch/persistence/room/processor/cache/Cache": "androidx/persistence/room/processor/cache/Cache",
+      "android/arch/persistence/room/processor/cache/Cache$PojoKey": "androidx/persistence/room/processor/cache/Cache$PojoKey",
+      "android/arch/persistence/room/processor/cache/Cache$Bucket": "androidx/persistence/room/processor/cache/Cache$Bucket",
+      "android/arch/persistence/room/processor/cache/Cache$EntityKey": "androidx/persistence/room/processor/cache/Cache$EntityKey",
+      "android/arch/persistence/room/processor/CustomConverterProcessor$ProcessResult": "androidx/persistence/room/processor/CustomConverterProcessor$ProcessResult",
+      "android/arch/persistence/room/processor/CustomConverterProcessor$ProcessResult$EMPTY": "androidx/persistence/room/processor/CustomConverterProcessor$ProcessResult$EMPTY",
+      "android/arch/persistence/room/processor/CustomConverterProcessor": "androidx/persistence/room/processor/CustomConverterProcessor",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor$getInsertionType$3": "androidx/persistence/room/processor/InsertionMethodProcessor$getInsertionType$3",
+      "android/arch/persistence/room/processor/Context$ProcessorOptions": "androidx/persistence/room/processor/Context$ProcessorOptions",
+      "android/arch/persistence/room/processor/Context$Companion": "androidx/persistence/room/processor/Context$Companion",
+      "android/arch/persistence/room/processor/DatabaseProcessor$baseClassElement$2": "androidx/persistence/room/processor/DatabaseProcessor$baseClassElement$2",
+      "android/arch/persistence/room/verifier/DatabaseVerifier": "androidx/persistence/room/verifier/DatabaseVerifier",
+      "android/arch/persistence/room/SkipQueryVerification": "androidx/persistence/room/SkipQueryVerification",
+      "android/arch/persistence/room/verifier/DatabaseVerifier$Companion": "androidx/persistence/room/verifier/DatabaseVerifier$Companion",
+      "android/arch/persistence/room/vo/ForeignKey": "androidx/persistence/room/vo/ForeignKey",
+      "android/arch/persistence/room/vo/Index": "androidx/persistence/room/vo/Index",
+      "android/arch/persistence/room/vo/ShortcutMethod": "androidx/persistence/room/vo/ShortcutMethod",
+      "android/arch/persistence/room/vo/InsertionMethod": "androidx/persistence/room/vo/InsertionMethod",
+      "android/arch/persistence/room/processor/ShortcutParameterProcessor$extractEntityType$2": "androidx/persistence/room/processor/ShortcutParameterProcessor$extractEntityType$2",
+      "android/arch/persistence/room/processor/ShortcutParameterProcessor": "androidx/persistence/room/processor/ShortcutParameterProcessor",
+      "android/arch/persistence/room/processor/PojoProcessor$assignSetter$success$2": "androidx/persistence/room/processor/PojoProcessor$assignSetter$success$2",
+      "android/arch/persistence/room/vo/Constructor": "androidx/persistence/room/vo/Constructor",
+      "android/arch/persistence/room/vo/FieldSetter": "androidx/persistence/room/vo/FieldSetter",
+      "android/arch/persistence/room/vo/CallType": "androidx/persistence/room/vo/CallType",
+      "android/arch/persistence/room/processor/PojoProcessor$assignSetter$success$1": "androidx/persistence/room/processor/PojoProcessor$assignSetter$success$1",
+      "android/arch/persistence/room/processor/PojoProcessor$chooseConstructor$failureMsg$1$paramsMatching$1": "androidx/persistence/room/processor/PojoProcessor$chooseConstructor$failureMsg$1$paramsMatching$1",
+      "android/arch/persistence/room/processor/PojoProcessor$chooseConstructor$failureMsg$1": "androidx/persistence/room/processor/PojoProcessor$chooseConstructor$failureMsg$1",
+      "android/arch/persistence/room/vo/Constructor$Param": "androidx/persistence/room/vo/Constructor$Param",
+      "android/arch/persistence/room/processor/PojoProcessor$assignGetter$success$2": "androidx/persistence/room/processor/PojoProcessor$assignGetter$success$2",
+      "android/arch/persistence/room/vo/FieldGetter": "androidx/persistence/room/vo/FieldGetter",
+      "android/arch/persistence/room/processor/PojoProcessor$process$1": "androidx/persistence/room/processor/PojoProcessor$process$1",
+      "android/arch/persistence/room/processor/EntityProcessor$Companion$FOREIGN_KEY_VISITOR$1": "androidx/persistence/room/processor/EntityProcessor$Companion$FOREIGN_KEY_VISITOR$1",
+      "android/arch/persistence/room/processor/EntityProcessor$ForeignKeyInput": "androidx/persistence/room/processor/EntityProcessor$ForeignKeyInput",
+      "android/arch/persistence/room/vo/ForeignKeyAction": "androidx/persistence/room/vo/ForeignKeyAction",
+      "android/arch/persistence/room/vo/ForeignKeyAction$Companion": "androidx/persistence/room/vo/ForeignKeyAction$Companion",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor$Companion": "androidx/persistence/room/processor/InsertionMethodProcessor$Companion",
+      "android/arch/persistence/room/vo/ShortcutQueryParameter": "androidx/persistence/room/vo/ShortcutQueryParameter",
+      "android/arch/persistence/room/processor/RawQueryMethodProcessor": "androidx/persistence/room/processor/RawQueryMethodProcessor",
+      "android/arch/persistence/room/vo/RawQueryMethod": "androidx/persistence/room/vo/RawQueryMethod",
+      "android/arch/persistence/room/vo/RawQueryMethod$RuntimeQueryParameter": "androidx/persistence/room/vo/RawQueryMethod$RuntimeQueryParameter",
+      "android/arch/persistence/room/Transaction": "androidx/persistence/room/Transaction",
+      "android/arch/persistence/room/processor/Context$CommonTypes$STRING$2": "androidx/persistence/room/processor/Context$CommonTypes$STRING$2",
+      "android/arch/persistence/room/processor/Context$CommonTypes": "androidx/persistence/room/processor/Context$CommonTypes",
+      "android/arch/persistence/room/processor/PojoProcessor$assignGetter$success$3": "androidx/persistence/room/processor/PojoProcessor$assignGetter$success$3",
+      "android/arch/persistence/room/processor/PojoProcessor$assignGetter$success$4": "androidx/persistence/room/processor/PojoProcessor$assignGetter$success$4",
+      "android/arch/persistence/room/processor/PojoProcessor$assignSetter$success$3": "androidx/persistence/room/processor/PojoProcessor$assignSetter$success$3",
+      "android/arch/persistence/room/processor/PojoProcessor$assignSetter$success$4": "androidx/persistence/room/processor/PojoProcessor$assignSetter$success$4",
+      "android/arch/persistence/room/Ignore": "androidx/persistence/room/Ignore",
+      "android/arch/persistence/room/ColumnInfo": "androidx/persistence/room/ColumnInfo",
+      "android/arch/persistence/room/Embedded": "androidx/persistence/room/Embedded",
+      "android/arch/persistence/room/Relation": "androidx/persistence/room/Relation",
+      "android/arch/persistence/room/processor/FieldProcessor": "androidx/persistence/room/processor/FieldProcessor",
+      "android/arch/persistence/room/vo/Relation": "androidx/persistence/room/vo/Relation",
+      "android/arch/persistence/room/processor/PojoProcessor$chooseConstructor$$inlined$map$lambda$1": "androidx/persistence/room/processor/PojoProcessor$chooseConstructor$$inlined$map$lambda$1",
+      "android/arch/persistence/room/vo/Constructor$FieldParam": "androidx/persistence/room/vo/Constructor$FieldParam",
+      "android/arch/persistence/room/vo/Constructor$EmbeddedParam": "androidx/persistence/room/vo/Constructor$EmbeddedParam",
+      "android/arch/persistence/room/processor/EntityProcessor$Companion$FOREIGN_KEY_LIST_VISITOR$1": "androidx/persistence/room/processor/EntityProcessor$Companion$FOREIGN_KEY_LIST_VISITOR$1",
+      "android/arch/persistence/room/processor/Context$typeAdapterStore$2": "androidx/persistence/room/processor/Context$typeAdapterStore$2",
+      "android/arch/persistence/room/processor/FieldProcessor$WhenMappings": "androidx/persistence/room/processor/FieldProcessor$WhenMappings",
+      "android/arch/persistence/room/processor/ShortcutMethodProcessor": "androidx/persistence/room/processor/ShortcutMethodProcessor",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor$Companion$SINGLE_ITEM_SET$2": "androidx/persistence/room/processor/InsertionMethodProcessor$Companion$SINGLE_ITEM_SET$2",
+      "android/arch/persistence/room/processor/CustomConverterProcessor$Companion": "androidx/persistence/room/processor/CustomConverterProcessor$Companion",
+      "android/arch/persistence/room/TypeConverter": "androidx/persistence/room/TypeConverter",
+      "android/arch/persistence/room/processor/Context$schemaOutFolder$2": "androidx/persistence/room/processor/Context$schemaOutFolder$2",
+      "android/arch/persistence/room/processor/Context$Companion$ARG_OPTIONS$2": "androidx/persistence/room/processor/Context$Companion$ARG_OPTIONS$2",
+      "android/arch/persistence/room/log/RLog$Messager": "androidx/persistence/room/log/RLog$Messager",
+      "android/arch/persistence/room/processor/SuppressWarningProcessor": "androidx/persistence/room/processor/SuppressWarningProcessor",
+      "android/arch/persistence/room/log/RLog$ProcessingEnvMessager": "androidx/persistence/room/log/RLog$ProcessingEnvMessager",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor$Companion$MULTIPLE_ITEM_SET$2": "androidx/persistence/room/processor/InsertionMethodProcessor$Companion$MULTIPLE_ITEM_SET$2",
+      "android/arch/persistence/room/processor/EntityProcessor$process$1": "androidx/persistence/room/processor/EntityProcessor$process$1",
+      "android/arch/persistence/room/processor/DeletionMethodProcessor": "androidx/persistence/room/processor/DeletionMethodProcessor",
+      "android/arch/persistence/room/vo/DeletionMethod": "androidx/persistence/room/vo/DeletionMethod",
+      "android/arch/persistence/room/processor/SuppressWarningProcessor$VISITOR": "androidx/persistence/room/processor/SuppressWarningProcessor$VISITOR",
+      "android/arch/persistence/room/vo/Warning$Companion": "androidx/persistence/room/vo/Warning$Companion",
+      "android/arch/persistence/room/processor/EntityProcessor$Companion$INDEX_LIST_VISITOR$1": "androidx/persistence/room/processor/EntityProcessor$Companion$INDEX_LIST_VISITOR$1",
+      "android/arch/persistence/room/PrimaryKey": "androidx/persistence/room/PrimaryKey",
+      "android/arch/persistence/room/vo/PrimaryKey$Companion": "androidx/persistence/room/vo/PrimaryKey$Companion",
+      "android/arch/persistence/room/processor/QueryParameterProcessor": "androidx/persistence/room/processor/QueryParameterProcessor",
+      "android/arch/persistence/room/vo/QueryParameter": "androidx/persistence/room/vo/QueryParameter",
+      "android/arch/persistence/room/processor/OnConflictProcessor": "androidx/persistence/room/processor/OnConflictProcessor",
+      "android/arch/persistence/room/processor/QueryMethodProcessor": "androidx/persistence/room/processor/QueryMethodProcessor",
+      "android/arch/persistence/room/vo/QueryMethod": "androidx/persistence/room/vo/QueryMethod",
+      "android/arch/persistence/room/processor/UpdateMethodProcessor": "androidx/persistence/room/processor/UpdateMethodProcessor",
+      "android/arch/persistence/room/vo/UpdateMethod": "androidx/persistence/room/vo/UpdateMethod",
+      "android/arch/persistence/room/verifier/DatabaseVerificaitonErrors": "androidx/persistence/room/verifier/DatabaseVerificaitonErrors",
+      "android/arch/persistence/room/processor/ShortcutParameterProcessor$extractEntityType$1": "androidx/persistence/room/processor/ShortcutParameterProcessor$extractEntityType$1",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor$Companion$VOID_SET$2": "androidx/persistence/room/processor/InsertionMethodProcessor$Companion$VOID_SET$2",
+      "android/arch/persistence/room/TypeConverters": "androidx/persistence/room/TypeConverters",
+      "android/arch/persistence/room/writer/DaoWriter$createUpdateMethods$1": "androidx/persistence/room/writer/DaoWriter$createUpdateMethods$1",
+      "android/arch/persistence/room/writer/EntityUpdateAdapterWriter": "androidx/persistence/room/writer/EntityUpdateAdapterWriter",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion$bindToStatement$1": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion$bindToStatement$1",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Node": "androidx/persistence/room/writer/FieldReadWriteWriter$Node",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion$bindToStatement$1$1": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion$bindToStatement$1$1",
+      "android/arch/persistence/room/writer/DaoWriter$PreparedStmtQuery$Companion": "androidx/persistence/room/writer/DaoWriter$PreparedStmtQuery$Companion",
+      "android/arch/persistence/room/writer/DaoWriter$PreparedStmtQuery": "androidx/persistence/room/writer/DaoWriter$PreparedStmtQuery",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion$getAllParents$1": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion$getAllParents$1",
+      "android/arch/persistence/room/writer/TableInfoValidationWriter$write$1$3$columnNames$1": "androidx/persistence/room/writer/TableInfoValidationWriter$write$1$3$columnNames$1",
+      "android/arch/persistence/room/writer/TableInfoValidationWriter": "androidx/persistence/room/writer/TableInfoValidationWriter",
+      "android/arch/persistence/room/writer/DaoWriter$InsertionMethodField": "androidx/persistence/room/writer/DaoWriter$InsertionMethodField",
+      "android/arch/persistence/room/writer/EntityInsertionAdapterWriter": "androidx/persistence/room/writer/EntityInsertionAdapterWriter",
+      "android/arch/persistence/room/writer/EntityInsertionAdapterWriter$createAnonymous$1$1$query$1": "androidx/persistence/room/writer/EntityInsertionAdapterWriter$createAnonymous$1$1$query$1",
+      "android/arch/persistence/room/writer/EntityInsertionAdapterWriter$createAnonymous$$inlined$apply$lambda$1": "androidx/persistence/room/writer/EntityInsertionAdapterWriter$createAnonymous$$inlined$apply$lambda$1",
+      "android/arch/persistence/room/vo/FieldWithIndex$Companion": "androidx/persistence/room/vo/FieldWithIndex$Companion",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$readFromCursor$1": "androidx/persistence/room/writer/FieldReadWriteWriter$readFromCursor$1",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$WhenMappings": "androidx/persistence/room/writer/FieldReadWriteWriter$WhenMappings",
+      "android/arch/persistence/room/writer/RelationCollectorMethodWriter$Companion": "androidx/persistence/room/writer/RelationCollectorMethodWriter$Companion",
+      "android/arch/persistence/room/writer/RelationCollectorMethodWriter": "androidx/persistence/room/writer/RelationCollectorMethodWriter",
+      "android/arch/persistence/room/writer/RelationCollectorMethodWriter$prepare$$inlined$apply$lambda$1": "androidx/persistence/room/writer/RelationCollectorMethodWriter$prepare$$inlined$apply$lambda$1",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion$readFromCursor$1$allNullCheck$1": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion$readFromCursor$1$allNullCheck$1",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion$readFromCursor$1": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion$readFromCursor$1",
+      "android/arch/persistence/room/writer/SQLiteOpenHelperWriter": "androidx/persistence/room/writer/SQLiteOpenHelperWriter",
+      "android/arch/persistence/room/writer/PreparedStatementWriter": "androidx/persistence/room/writer/PreparedStatementWriter",
+      "android/arch/persistence/room/writer/QueryWriter": "androidx/persistence/room/writer/QueryWriter",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion$construct$args$1": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion$construct$args$1",
+      "android/arch/persistence/room/writer/DaoWriter$PreparedStatementField": "androidx/persistence/room/writer/DaoWriter$PreparedStatementField",
+      "android/arch/persistence/room/writer/QueryWriter$createSqlQueryAndArgs$1$2": "androidx/persistence/room/writer/QueryWriter$createSqlQueryAndArgs$1$2",
+      "android/arch/persistence/room/writer/QueryWriter$WhenMappings": "androidx/persistence/room/writer/QueryWriter$WhenMappings",
+      "android/arch/persistence/room/writer/QueryWriter$bindArgs$1$1$1": "androidx/persistence/room/writer/QueryWriter$bindArgs$1$1$1",
+      "android/arch/persistence/room/writer/DaoWriter$DeleteOrUpdateAdapterField": "androidx/persistence/room/writer/DaoWriter$DeleteOrUpdateAdapterField",
+      "android/arch/persistence/room/writer/DaoWriter$createDeletionMethods$1": "androidx/persistence/room/writer/DaoWriter$createDeletionMethods$1",
+      "android/arch/persistence/room/writer/EntityDeletionAdapterWriter": "androidx/persistence/room/writer/EntityDeletionAdapterWriter",
+      "android/arch/persistence/room/writer/EntityUpdateAdapterWriter$createAnonymous$1$1$query$1": "androidx/persistence/room/writer/EntityUpdateAdapterWriter$createAnonymous$1$1$query$1",
+      "android/arch/persistence/room/writer/EntityDeletionAdapterWriter$createAnonymous$1$1$query$1": "androidx/persistence/room/writer/EntityDeletionAdapterWriter$createAnonymous$1$1$query$1",
+      "android/arch/persistence/room/writer/TableInfoValidationWriter$write$1$2$myColumnNames$1": "androidx/persistence/room/writer/TableInfoValidationWriter$write$1$2$myColumnNames$1",
+      "android/arch/persistence/room/writer/TableInfoValidationWriter$write$1$2$refColumnNames$1": "androidx/persistence/room/writer/TableInfoValidationWriter$write$1$2$refColumnNames$1",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter$Companion$readFromCursor$1$1": "androidx/persistence/room/writer/FieldReadWriteWriter$Companion$readFromCursor$1$1",
+      "android/arch/persistence/room/writer/EntityUpdateAdapterWriter$createAnonymous$1$1$query$2": "androidx/persistence/room/writer/EntityUpdateAdapterWriter$createAnonymous$1$1$query$2",
+      "android/arch/persistence/room/writer/DatabaseWriter$createCreateInvalidationTracker$1$tableNames$1": "androidx/persistence/room/writer/DatabaseWriter$createCreateInvalidationTracker$1$tableNames$1",
+      "android/arch/persistence/room/log/RLog$Messager$DefaultImpls": "androidx/persistence/room/log/RLog$Messager$DefaultImpls",
+      "android/arch/persistence/room/vo/RawQueryMethod$returnsValue$2": "androidx/persistence/room/vo/RawQueryMethod$returnsValue$2",
+      "android/arch/persistence/room/vo/Database$typeName$2": "androidx/persistence/room/vo/Database$typeName$2",
+      "android/arch/persistence/room/vo/Database$implClassName$2": "androidx/persistence/room/vo/Database$implClassName$2",
+      "android/arch/persistence/room/vo/Database$implTypeName$2": "androidx/persistence/room/vo/Database$implTypeName$2",
+      "android/arch/persistence/room/vo/Database$bundle$2": "androidx/persistence/room/vo/Database$bundle$2",
+      "android/arch/persistence/room/vo/Database$identityHash$2": "androidx/persistence/room/vo/Database$identityHash$2",
+      "android/arch/persistence/room/vo/Database$legacyIdentityHash$2": "androidx/persistence/room/vo/Database$legacyIdentityHash$2",
+      "android/arch/persistence/room/vo/FieldGetter$WhenMappings": "androidx/persistence/room/vo/FieldGetter$WhenMappings",
+      "android/arch/persistence/room/vo/ForeignKey$getIdKey$1": "androidx/persistence/room/vo/ForeignKey$getIdKey$1",
+      "android/arch/persistence/room/vo/HasSchemaIdentity": "androidx/persistence/room/vo/HasSchemaIdentity",
+      "android/arch/persistence/room/vo/PrimaryKey$toHumanReadableString$1": "androidx/persistence/room/vo/PrimaryKey$toHumanReadableString$1",
+      "android/arch/persistence/room/vo/PrimaryKey$columnNames$2": "androidx/persistence/room/vo/PrimaryKey$columnNames$2",
+      "android/arch/persistence/room/vo/Field$setterNameWithVariations$2": "androidx/persistence/room/vo/Field$setterNameWithVariations$2",
+      "android/arch/persistence/room/vo/EmbeddedField$setter$2": "androidx/persistence/room/vo/EmbeddedField$setter$2",
+      "android/arch/persistence/room/vo/CustomTypeConverter$typeName$2": "androidx/persistence/room/vo/CustomTypeConverter$typeName$2",
+      "android/arch/persistence/room/vo/ForeignKey$joinEscaped$1": "androidx/persistence/room/vo/ForeignKey$joinEscaped$1",
+      "android/arch/persistence/room/vo/QueryMethod$sectionToParamMapping$2": "androidx/persistence/room/vo/QueryMethod$sectionToParamMapping$2",
+      "android/arch/persistence/room/vo/QueryMethod$returnsValue$2": "androidx/persistence/room/vo/QueryMethod$returnsValue$2",
+      "android/arch/persistence/room/vo/Constructor$ParamType": "androidx/persistence/room/vo/Constructor$ParamType",
+      "android/arch/persistence/room/vo/Relation$pojoTypeName$2": "androidx/persistence/room/vo/Relation$pojoTypeName$2",
+      "android/arch/persistence/room/vo/Field$typeName$2": "androidx/persistence/room/vo/Field$typeName$2",
+      "android/arch/persistence/room/vo/RelationCollector$Companion$createCollectors$1$1": "androidx/persistence/room/vo/RelationCollector$Companion$createCollectors$1$1",
+      "android/arch/persistence/room/vo/Dao$implTypeName$2": "androidx/persistence/room/vo/Dao$implTypeName$2",
+      "android/arch/persistence/room/vo/Field$pathWithDotNotation$2": "androidx/persistence/room/vo/Field$pathWithDotNotation$2",
+      "android/arch/persistence/room/vo/Dao$shortcutMethods$2": "androidx/persistence/room/vo/Dao$shortcutMethods$2",
+      "android/arch/persistence/room/vo/RelationCollector$WhenMappings": "androidx/persistence/room/vo/RelationCollector$WhenMappings",
+      "android/arch/persistence/room/vo/Field$getterNameWithVariations$2": "androidx/persistence/room/vo/Field$getterNameWithVariations$2",
+      "android/arch/persistence/room/vo/Dao$implClassName$2": "androidx/persistence/room/vo/Dao$implClassName$2",
+      "android/arch/persistence/room/vo/SchemaIdentityKey$Companion$ENGLISH_SORT$1": "androidx/persistence/room/vo/SchemaIdentityKey$Companion$ENGLISH_SORT$1",
+      "android/arch/persistence/room/vo/SchemaIdentityKey": "androidx/persistence/room/vo/SchemaIdentityKey",
+      "android/arch/persistence/room/vo/EmbeddedField$getter$2": "androidx/persistence/room/vo/EmbeddedField$getter$2",
+      "android/arch/persistence/room/vo/EmbeddedField$mRootParent$2": "androidx/persistence/room/vo/EmbeddedField$mRootParent$2",
+      "android/arch/persistence/room/vo/CustomTypeConverter$methodName$2": "androidx/persistence/room/vo/CustomTypeConverter$methodName$2",
+      "android/arch/persistence/room/vo/Pojo$typeName$2": "androidx/persistence/room/vo/Pojo$typeName$2",
+      "android/arch/persistence/room/vo/CustomTypeConverter$isStatic$2": "androidx/persistence/room/vo/CustomTypeConverter$isStatic$2",
+      "android/arch/persistence/room/vo/SchemaIdentityKey$Companion": "androidx/persistence/room/vo/SchemaIdentityKey$Companion",
+      "android/arch/persistence/room/vo/FieldSetter$WhenMappings": "androidx/persistence/room/vo/FieldSetter$WhenMappings",
+      "android/arch/persistence/room/vo/Entity$createTableQuery$2": "androidx/persistence/room/vo/Entity$createTableQuery$2",
+      "android/arch/persistence/room/vo/RelationCollector$Companion$WhenMappings": "androidx/persistence/room/vo/RelationCollector$Companion$WhenMappings",
+      "android/arch/persistence/room/vo/ForeignKeyAction$Companion$mapping$2": "androidx/persistence/room/vo/ForeignKeyAction$Companion$mapping$2",
+      "android/arch/persistence/room/vo/Index$Companion": "androidx/persistence/room/vo/Index$Companion",
+      "android/arch/persistence/room/RoomMasterTable": "androidx/persistence/room/RoomMasterTable",
+      "android/arch/persistence/room/vo/RelationCollector$writeReadParentKeyCode$$inlined$apply$lambda$1": "androidx/persistence/room/vo/RelationCollector$writeReadParentKeyCode$$inlined$apply$lambda$1",
+      "android/arch/persistence/room/vo/Dao$typeName$2": "androidx/persistence/room/vo/Dao$typeName$2",
+      "android/arch/persistence/room/vo/Field$nameWithVariations$2": "androidx/persistence/room/vo/Field$nameWithVariations$2",
+      "android/arch/persistence/room/vo/Database$legacyIdentityHash$2$$special$$inlined$sortedBy$1": "androidx/persistence/room/vo/Database$legacyIdentityHash$2$$special$$inlined$sortedBy$1",
+      "android/arch/persistence/room/vo/Index$createQuery$2": "androidx/persistence/room/vo/Index$createQuery$2",
+      "android/arch/persistence/room/vo/CustomTypeConverter$fromTypeName$2": "androidx/persistence/room/vo/CustomTypeConverter$fromTypeName$2",
+      "android/arch/persistence/room/vo/Index$getIdKey$1": "androidx/persistence/room/vo/Index$getIdKey$1",
+      "android/arch/persistence/room/vo/Index$columnNames$2": "androidx/persistence/room/vo/Index$columnNames$2",
+      "android/arch/persistence/room/vo/CustomTypeConverter$toTypeName$2": "androidx/persistence/room/vo/CustomTypeConverter$toTypeName$2",
       "android/support/animation/AnimationHandler$AnimationCallbackDispatcher": "androidx/animation/AnimationHandler$AnimationCallbackDispatcher",
-      "android/support/v7/widget/ResourcesWrapper": "androidx/widget/ResourcesWrapper",
-      "android/support/v17/leanback/widget/BrowseFrameLayout$OnChildFocusListener": "androidx/leanback/widget/BrowseFrameLayout$OnChildFocusListener",
-      "android/support/v7/widget/AppCompatEditText": "androidx/widget/AppCompatEditText",
-      "android/support/media/tv/TvContractCompat$WatchNextPrograms": "androidx/media/tv/TvContractCompat$WatchNextPrograms",
-      "android/support/v4/widget/ListPopupWindowCompat": "androidx/widget/ListPopupWindowCompat",
-      "android/support/v7/preference/PreferenceFragmentCompat$OnPreferenceDisplayDialogCallback": "androidx/preference/PreferenceFragmentCompat$OnPreferenceDisplayDialogCallback",
-      "android/support/v7/util/DiffUtil$PostponedUpdate": "androidx/util/DiffUtil$PostponedUpdate",
-      "android/support/transition/TransitionManager$MultiListener": "androidx/transition/TransitionManager$MultiListener",
-      "android/support/v4/view/ViewPropertyAnimatorCompat$ViewPropertyAnimatorListenerApi14": "androidx/view/ViewPropertyAnimatorCompat$ViewPropertyAnimatorListenerApi14",
-      "android/support/v17/leanback/widget/ViewsStateBundle": "androidx/leanback/widget/ViewsStateBundle",
-      "android/support/v4/provider/FontsContractCompat$TypefaceResult": "androidx/provider/FontsContractCompat$TypefaceResult",
-      "android/support/v4/widget/DrawerLayout$State": "androidx/widget/DrawerLayout$State",
-      "android/support/v4/widget/SwipeRefreshLayout$OnRefreshListener": "androidx/widget/SwipeRefreshLayout$OnRefreshListener",
-      "android/support/media/ExifInterface$Rational": "androidx/media/ExifInterface$Rational",
-      "android/support/v4/view/ViewPager$PagerObserver": "androidx/view/ViewPager$PagerObserver",
-      "android/support/design/widget/StateListAnimator": "androidx/design/widget/StateListAnimator",
-      "android/support/v4/media/MediaBrowserCompat$CallbackHandler": "androidx/media/MediaBrowserCompat$CallbackHandler",
-      "android/support/customtabs/CustomTabsClient": "androidx/browser/customtabs/CustomTabsClient",
-      "android/support/v4/media/MediaBrowserServiceCompatApi26$ServiceCompatProxy": "androidx/media/MediaBrowserServiceCompatApi26$ServiceCompatProxy",
-      "android/support/transition/Slide$CalculateSlideHorizontal": "androidx/transition/Slide$CalculateSlideHorizontal",
-      "android/support/v17/leanback/media/PlaybackBannerControlGlue$SPEED": "androidx/leanback/media/PlaybackBannerControlGlue$SPEED",
-      "android/support/annotation/CallSuper": "androidx/annotation/CallSuper",
-      "android/support/design/widget/Snackbar$Callback": "androidx/design/widget/Snackbar$Callback",
-      "android/support/v4/app/ActivityManagerCompat": "androidx/app/ActivityManagerCompat",
-      "android/support/v17/leanback/widget/RoundedRectHelperApi21": "androidx/leanback/widget/RoundedRectHelperApi21",
-      "android/support/v7/graphics/Palette": "androidx/graphics/palette/Palette",
-      "android/support/wear/R$color": "androidx/wear/R$color",
-      "android/support/v17/leanback/widget/ItemBridgeAdapter$OnFocusChangeListener": "androidx/leanback/widget/ItemBridgeAdapter$OnFocusChangeListener",
-      "android/support/v7/media/MediaRouteProviderService$ProviderCallback": "androidx/media/MediaRouteProviderService$ProviderCallback",
-      "android/support/media/ExifInterface": "androidx/media/ExifInterface",
-      "android/support/v4/app/FragmentManagerImpl": "androidx/app/FragmentManagerImpl",
-      "android/support/v13/app/FragmentTabHost$DummyTabFactory": "androidx/app/legacy/FragmentTabHost$DummyTabFactory",
-      "android/support/app/recommendation/ContentRecommendation$Builder": "androidx/app/recommendation/ContentRecommendation$Builder",
-      "android/support/v17/leanback/widget/RowHeaderView": "androidx/leanback/widget/RowHeaderView",
-      "android/support/v4/widget/DrawerLayout$EdgeGravity": "androidx/widget/DrawerLayout$EdgeGravity",
-      "android/support/v7/view/menu/MenuWrapperICS": "androidx/view/menu/MenuWrapperICS",
-      "android/support/v7/widget/RoundRectDrawableWithShadow$RoundRectHelper": "androidx/widget/RoundRectDrawableWithShadow$RoundRectHelper",
-      "android/support/v4/media/session/MediaControllerCompat$Callback$MessageHandler": "androidx/media/session/MediaControllerCompat$Callback$MessageHandler",
-      "android/support/v4/text/ICUCompat": "androidx/text/ICUCompat",
-      "android/support/v17/leanback/widget/PlaybackSeekDataProvider$ResultCallback": "androidx/leanback/widget/PlaybackSeekDataProvider$ResultCallback",
-      "android/support/v7/widget/ViewUtils": "androidx/widget/ViewUtils",
-      "android/support/v7/appcompat/R$string": "androidx/appcompat/R$string",
-      "android/support/constraint/ConstraintLayout": "androidx/constraint/ConstraintLayout",
-      "android/support/v4/view/ViewPager$SimpleOnPageChangeListener": "androidx/view/ViewPager$SimpleOnPageChangeListener",
-      "android/support/wear/internal/widget/drawer/MultiPageUi": "androidx/wear/internal/widget/drawer/MultiPageUi",
-      "android/support/v17/leanback/media/PlayerAdapter$Callback": "androidx/leanback/media/PlayerAdapter$Callback",
-      "android/support/design/widget/BaseTransientBottomBar$ContentViewCallback": "androidx/design/widget/BaseTransientBottomBar$ContentViewCallback",
-      "android/support/annotation/RestrictTo$Scope": "androidx/annotation/RestrictTo$Scope",
-      "android/support/v4/content/AsyncTaskLoader": "androidx/content/AsyncTaskLoader",
-      "android/support/v17/leanback/widget/ParallaxEffect": "androidx/leanback/widget/ParallaxEffect",
-      "android/support/v17/leanback/app/BackgroundManager$DrawableWrapper": "androidx/leanback/app/BackgroundManager$DrawableWrapper",
-      "android/support/v4/app/ListFragment": "androidx/app/ListFragment",
-      "android/support/design/widget/DirectedAcyclicGraph": "androidx/widget/DirectedAcyclicGraph",
-      "android/support/design/widget/AppBarLayout": "androidx/design/widget/AppBarLayout",
-      "android/support/v7/media/RemoteControlClientCompat$JellybeanImpl": "androidx/media/RemoteControlClientCompat$JellybeanImpl",
-      "android/support/design/widget/ViewGroupUtils": "androidx/widget/ViewGroupUtils",
-      "android/support/design/R$styleable": "androidx/design/R$styleable",
+      "android/support/animation/AnimationHandler": "androidx/animation/AnimationHandler",
+      "android/support/animation/AnimationHandler$AnimationFrameCallbackProvider": "androidx/animation/AnimationHandler$AnimationFrameCallbackProvider",
+      "android/support/animation/AnimationHandler$AnimationFrameCallback": "androidx/animation/AnimationHandler$AnimationFrameCallback",
+      "android/support/animation/AnimationHandler$FrameCallbackProvider14$1": "androidx/animation/AnimationHandler$FrameCallbackProvider14$1",
+      "android/support/animation/AnimationHandler$FrameCallbackProvider14": "androidx/animation/AnimationHandler$FrameCallbackProvider14",
+      "android/support/animation/AnimationHandler$FrameCallbackProvider16$1": "androidx/animation/AnimationHandler$FrameCallbackProvider16$1",
+      "android/support/animation/AnimationHandler$FrameCallbackProvider16": "androidx/animation/AnimationHandler$FrameCallbackProvider16",
+      "android/support/animation/DynamicAnimation$1": "androidx/animation/DynamicAnimation$1",
+      "android/support/animation/DynamicAnimation$ViewProperty": "androidx/animation/DynamicAnimation$ViewProperty",
+      "android/support/animation/DynamicAnimation": "androidx/animation/DynamicAnimation",
+      "android/support/animation/DynamicAnimation$10": "androidx/animation/DynamicAnimation$10",
+      "android/support/animation/DynamicAnimation$11": "androidx/animation/DynamicAnimation$11",
+      "android/support/animation/DynamicAnimation$12": "androidx/animation/DynamicAnimation$12",
+      "android/support/animation/DynamicAnimation$13": "androidx/animation/DynamicAnimation$13",
+      "android/support/animation/DynamicAnimation$14": "androidx/animation/DynamicAnimation$14",
+      "android/support/animation/DynamicAnimation$15": "androidx/animation/DynamicAnimation$15",
+      "android/support/animation/FloatPropertyCompat": "androidx/animation/FloatPropertyCompat",
+      "android/support/animation/FloatValueHolder": "androidx/animation/FloatValueHolder",
+      "android/support/animation/DynamicAnimation$2": "androidx/animation/DynamicAnimation$2",
+      "android/support/animation/DynamicAnimation$3": "androidx/animation/DynamicAnimation$3",
+      "android/support/animation/DynamicAnimation$4": "androidx/animation/DynamicAnimation$4",
+      "android/support/animation/DynamicAnimation$5": "androidx/animation/DynamicAnimation$5",
+      "android/support/animation/DynamicAnimation$6": "androidx/animation/DynamicAnimation$6",
+      "android/support/animation/DynamicAnimation$7": "androidx/animation/DynamicAnimation$7",
+      "android/support/animation/DynamicAnimation$8": "androidx/animation/DynamicAnimation$8",
+      "android/support/animation/DynamicAnimation$9": "androidx/animation/DynamicAnimation$9",
+      "android/support/animation/DynamicAnimation$MassState": "androidx/animation/DynamicAnimation$MassState",
       "android/support/animation/DynamicAnimation$OnAnimationEndListener": "androidx/animation/DynamicAnimation$OnAnimationEndListener",
-      "android/support/media/tv/TvContractUtils": "androidx/media/tv/TvContractUtils",
-      "android/support/v4/app/JobIntentService$JobWorkEnqueuer": "androidx/app/JobIntentService$JobWorkEnqueuer",
-      "android/support/percent/PercentLayoutHelper$PercentLayoutParams": "androidx/PercentLayoutHelper$PercentLayoutParams",
-      "android/support/v4/util/Pair": "androidx/util/Pair",
-      "android/support/v17/leanback/transition/LeanbackTransitionHelperKitKat": "androidx/leanback/transition/LeanbackTransitionHelperKitKat",
-      "android/support/v13/view/DragStartHelper": "androidx/view/DragStartHelper",
-      "android/support/v7/widget/ListViewCompat": "androidx/widget/internal/ListViewCompat",
-      "android/support/v7/preference/CheckBoxPreference$Listener": "androidx/preference/CheckBoxPreference$Listener",
-      "android/support/v7/app/AppCompatDelegate$NightMode": "androidx/app/AppCompatDelegate$NightMode",
-      "android/support/v17/leanback/transition/SlideNoPropagation": "androidx/leanback/transition/SlideNoPropagation",
-      "android/support/v7/media/MediaRouteProviderService$ClientRecord": "androidx/media/MediaRouteProviderService$ClientRecord",
-      "android/support/graphics/drawable/VectorDrawableCompat$VectorDrawableCompatState": "androidx/graphics/drawable/VectorDrawableCompat$VectorDrawableCompatState",
+      "android/support/animation/DynamicAnimation$OnAnimationUpdateListener": "androidx/animation/DynamicAnimation$OnAnimationUpdateListener",
+      "android/support/animation/FlingAnimation$1": "androidx/animation/FlingAnimation$1",
+      "android/support/animation/FlingAnimation": "androidx/animation/FlingAnimation",
+      "android/support/animation/FlingAnimation$DragForce": "androidx/animation/FlingAnimation$DragForce",
+      "android/support/animation/Force": "androidx/animation/Force",
+      "android/support/animation/FloatPropertyCompat$1": "androidx/animation/FloatPropertyCompat$1",
+      "android/support/animation/SpringAnimation": "androidx/animation/SpringAnimation",
+      "android/support/animation/SpringForce": "androidx/animation/SpringForce",
+      "android/arch/persistence/room/EmptyResultSetException": "androidx/persistence/room/EmptyResultSetException",
+      "android/arch/persistence/room/RxRoom$1$1": "androidx/persistence/room/RxRoom$1$1",
+      "android/arch/persistence/room/InvalidationTracker$Observer": "androidx/persistence/room/InvalidationTracker$Observer",
+      "android/arch/persistence/room/RxRoom$1": "androidx/persistence/room/RxRoom$1",
+      "android/arch/persistence/room/InvalidationTracker": "androidx/persistence/room/InvalidationTracker",
+      "android/arch/persistence/room/RxRoom": "androidx/persistence/room/RxRoom",
+      "android/arch/persistence/room/RxRoom$1$2": "androidx/persistence/room/RxRoom$1$2",
+      "android/arch/persistence/room/RoomDatabase": "androidx/persistence/room/RoomDatabase",
+      "android/arch/persistence/room/RxRoom$2": "androidx/persistence/room/RxRoom$2",
+      "android/arch/persistence/room/RxRoom$Optional": "androidx/persistence/room/RxRoom$Optional",
+      "android/arch/persistence/room/RxRoom$3": "androidx/persistence/room/RxRoom$3",
+      "android/arch/persistence/room/RxRoom$4": "androidx/persistence/room/RxRoom$4",
+      "android/arch/persistence/room/RxRoom$5$1": "androidx/persistence/room/RxRoom$5$1",
+      "android/arch/persistence/room/RxRoom$5": "androidx/persistence/room/RxRoom$5",
+      "android/arch/persistence/room/RxRoom$DisposableRunnable": "androidx/persistence/room/RxRoom$DisposableRunnable",
+      "android/support/v4/app/AppLaunchChecker": "androidx/app/AppLaunchChecker",
+      "android/support/v4/app/FrameMetricsAggregator$1": "androidx/app/FrameMetricsAggregator$1",
+      "android/support/v4/app/FrameMetricsAggregator": "androidx/app/FrameMetricsAggregator",
+      "android/support/v4/app/FrameMetricsAggregator$FrameMetricsApi24Impl$1": "androidx/app/FrameMetricsAggregator$FrameMetricsApi24Impl$1",
+      "android/support/v4/app/FrameMetricsAggregator$FrameMetricsApi24Impl": "androidx/app/FrameMetricsAggregator$FrameMetricsApi24Impl",
+      "android/support/v4/app/FrameMetricsAggregator$FrameMetricsBaseImpl": "androidx/app/FrameMetricsAggregator$FrameMetricsBaseImpl",
+      "android/support/v4/app/FrameMetricsAggregator$MetricType": "androidx/app/FrameMetricsAggregator$MetricType",
+      "android/support/v4/app/TaskStackBuilder$TaskStackBuilderApi16Impl": "androidx/app/TaskStackBuilder$TaskStackBuilderApi16Impl",
+      "android/support/v4/app/TaskStackBuilder$TaskStackBuilderBaseImpl": "androidx/app/TaskStackBuilder$TaskStackBuilderBaseImpl",
+      "android/support/v4/content/AsyncTaskLoader$LoadTask": "androidx/content/AsyncTaskLoader$LoadTask",
+      "android/support/v4/content/ModernAsyncTask": "androidx/content/ModernAsyncTask",
+      "android/support/v4/content/AsyncTaskLoader": "androidx/content/AsyncTaskLoader",
+      "android/support/v4/content/CursorLoader": "androidx/content/CursorLoader",
+      "android/support/v4/content/Loader$ForceLoadContentObserver": "androidx/content/Loader$ForceLoadContentObserver",
+      "android/support/v4/content/FileProvider$PathStrategy": "androidx/content/FileProvider$PathStrategy",
+      "android/support/v4/content/FileProvider": "androidx/content/FileProvider",
+      "android/support/v4/content/FileProvider$SimplePathStrategy": "androidx/content/FileProvider$SimplePathStrategy",
+      "android/support/v4/content/LocalBroadcastManager$1": "androidx/content/LocalBroadcastManager$1",
+      "android/support/v4/content/LocalBroadcastManager": "androidx/content/LocalBroadcastManager",
+      "android/support/v4/content/LocalBroadcastManager$BroadcastRecord": "androidx/content/LocalBroadcastManager$BroadcastRecord",
+      "android/support/v4/content/LocalBroadcastManager$ReceiverRecord": "androidx/content/LocalBroadcastManager$ReceiverRecord",
+      "android/support/v4/content/MimeTypeFilter": "androidx/content/MimeTypeFilter",
+      "android/support/v4/content/ModernAsyncTask$1": "androidx/content/ModernAsyncTask$1",
+      "android/support/v4/content/ModernAsyncTask$2": "androidx/content/ModernAsyncTask$2",
+      "android/support/v4/content/ModernAsyncTask$WorkerRunnable": "androidx/content/ModernAsyncTask$WorkerRunnable",
+      "android/support/v4/content/ModernAsyncTask$3": "androidx/content/ModernAsyncTask$3",
+      "android/support/v4/content/ModernAsyncTask$4": "androidx/content/ModernAsyncTask$4",
+      "android/support/v4/content/ModernAsyncTask$Status": "androidx/content/ModernAsyncTask$Status",
+      "android/support/v4/content/ModernAsyncTask$AsyncTaskResult": "androidx/content/ModernAsyncTask$AsyncTaskResult",
+      "android/support/v4/content/ModernAsyncTask$InternalHandler": "androidx/content/ModernAsyncTask$InternalHandler",
+      "android/support/v4/content/PermissionChecker$PermissionResult": "androidx/content/PermissionChecker$PermissionResult",
+      "android/support/v4/content/WakefulBroadcastReceiver": "androidx/content/WakefulBroadcastReceiver",
+      "android/support/v4/graphics/drawable/RoundedBitmapDrawable": "androidx/graphics/drawable/RoundedBitmapDrawable",
+      "android/support/v4/graphics/drawable/RoundedBitmapDrawable21": "androidx/graphics/drawable/RoundedBitmapDrawable21",
+      "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory$DefaultRoundedBitmapDrawable": "androidx/graphics/drawable/RoundedBitmapDrawableFactory$DefaultRoundedBitmapDrawable",
+      "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory": "androidx/graphics/drawable/RoundedBitmapDrawableFactory",
+      "android/support/v4/print/PrintHelper$1": "androidx/print/PrintHelper$1",
+      "android/support/v4/print/PrintHelper": "androidx/print/PrintHelper",
+      "android/support/v4/print/PrintHelper$ColorMode": "androidx/print/PrintHelper$ColorMode",
+      "android/support/v4/print/PrintHelper$OnPrintFinishCallback": "androidx/print/PrintHelper$OnPrintFinishCallback",
+      "android/support/v4/print/PrintHelper$Orientation": "androidx/print/PrintHelper$Orientation",
+      "android/support/v4/print/PrintHelper$PrintHelperApi19$1": "androidx/print/PrintHelper$PrintHelperApi19$1",
+      "android/support/v4/print/PrintHelper$PrintHelperApi19": "androidx/print/PrintHelper$PrintHelperApi19",
+      "android/support/v4/print/PrintHelper$PrintHelperApi19$2": "androidx/print/PrintHelper$PrintHelperApi19$2",
+      "android/support/v4/print/PrintHelper$PrintHelperApi19$3$1$1": "androidx/print/PrintHelper$PrintHelperApi19$3$1$1",
+      "android/support/v4/print/PrintHelper$PrintHelperApi19$3$1": "androidx/print/PrintHelper$PrintHelperApi19$3$1",
+      "android/support/v4/print/PrintHelper$PrintHelperApi19$3": "androidx/print/PrintHelper$PrintHelperApi19$3",
+      "android/support/v4/print/PrintHelper$PrintHelperVersionImpl": "androidx/print/PrintHelper$PrintHelperVersionImpl",
+      "android/support/v4/print/PrintHelper$PrintHelperApi20": "androidx/print/PrintHelper$PrintHelperApi20",
+      "android/support/v4/print/PrintHelper$PrintHelperApi23": "androidx/print/PrintHelper$PrintHelperApi23",
+      "android/support/v4/print/PrintHelper$PrintHelperApi24": "androidx/print/PrintHelper$PrintHelperApi24",
+      "android/support/v4/print/PrintHelper$PrintHelperStub": "androidx/print/PrintHelper$PrintHelperStub",
+      "android/support/v4/print/PrintHelper$ScaleMode": "androidx/print/PrintHelper$ScaleMode",
+      "android/support/v4/provider/DocumentFile": "androidx/provider/DocumentFile",
+      "android/support/v4/provider/RawDocumentFile": "androidx/provider/RawDocumentFile",
+      "android/support/v4/provider/SingleDocumentFile": "androidx/provider/SingleDocumentFile",
+      "android/support/v4/provider/TreeDocumentFile": "androidx/provider/TreeDocumentFile",
+      "android/support/v4/provider/DocumentsContractApi19": "androidx/provider/DocumentsContractApi19",
+      "android/support/v7/widget/GridLayout$1": "androidx/widget/GridLayout$1",
+      "android/support/v7/widget/GridLayout": "androidx/widget/GridLayout",
+      "android/support/v7/widget/GridLayout$2": "androidx/widget/GridLayout$2",
+      "android/support/v7/widget/GridLayout$Alignment": "androidx/widget/GridLayout$Alignment",
+      "android/support/v7/widget/GridLayout$3": "androidx/widget/GridLayout$3",
+      "android/support/v7/widget/GridLayout$4": "androidx/widget/GridLayout$4",
+      "android/support/v7/widget/GridLayout$5": "androidx/widget/GridLayout$5",
+      "android/support/v7/widget/GridLayout$6": "androidx/widget/GridLayout$6",
+      "android/support/v7/widget/GridLayout$7$1": "androidx/widget/GridLayout$7$1",
+      "android/support/v7/widget/GridLayout$Bounds": "androidx/widget/GridLayout$Bounds",
+      "android/support/v7/widget/GridLayout$7": "androidx/widget/GridLayout$7",
+      "android/support/v7/widget/GridLayout$8": "androidx/widget/GridLayout$8",
+      "android/support/v7/widget/GridLayout$Arc": "androidx/widget/GridLayout$Arc",
+      "android/support/v7/widget/GridLayout$Interval": "androidx/widget/GridLayout$Interval",
+      "android/support/v7/widget/GridLayout$MutableInt": "androidx/widget/GridLayout$MutableInt",
+      "android/support/v7/widget/GridLayout$Assoc": "androidx/widget/GridLayout$Assoc",
+      "android/support/v7/widget/GridLayout$PackedMap": "androidx/widget/GridLayout$PackedMap",
+      "android/support/v7/widget/GridLayout$Axis$1": "androidx/widget/GridLayout$Axis$1",
+      "android/support/v7/widget/GridLayout$Axis": "androidx/widget/GridLayout$Axis",
+      "android/support/v7/widget/GridLayout$Spec": "androidx/widget/GridLayout$Spec",
+      "android/support/v7/widget/GridLayout$LayoutParams": "androidx/widget/GridLayout$LayoutParams",
+      "android/support/v7/gridlayout/R$styleable": "androidx/gridlayout/R$styleable",
+      "android/support/v7/gridlayout/R": "androidx/gridlayout/R",
+      "android/support/v7/gridlayout/R$dimen": "androidx/gridlayout/R$dimen",
+      "android/arch/lifecycle/ClassesInfoCache$CallbackInfo": "androidx/lifecycle/ClassesInfoCache$CallbackInfo",
+      "android/arch/lifecycle/ClassesInfoCache$MethodReference": "androidx/lifecycle/ClassesInfoCache$MethodReference",
+      "android/arch/lifecycle/ClassesInfoCache": "androidx/lifecycle/ClassesInfoCache",
+      "android/arch/lifecycle/ReflectiveGenericLifecycleObserver": "androidx/lifecycle/ReflectiveGenericLifecycleObserver",
+      "android/arch/lifecycle/FullLifecycleObserverAdapter": "androidx/lifecycle/FullLifecycleObserverAdapter",
+      "android/arch/lifecycle/SingleGeneratedAdapterObserver": "androidx/lifecycle/SingleGeneratedAdapterObserver",
+      "android/arch/lifecycle/CompositeGeneratedAdaptersObserver": "androidx/lifecycle/CompositeGeneratedAdaptersObserver",
+      "android/arch/lifecycle/FullLifecycleObserverAdapter$1": "androidx/lifecycle/FullLifecycleObserverAdapter$1",
+      "android/arch/persistence/room/testing/MigrationTestHelper$CreatingDelegate": "androidx/persistence/room/testing/MigrationTestHelper$CreatingDelegate",
+      "android/arch/persistence/room/testing/MigrationTestHelper$RoomOpenHelperDelegate": "androidx/persistence/room/testing/MigrationTestHelper$RoomOpenHelperDelegate",
+      "android/arch/persistence/room/testing/MigrationTestHelper": "androidx/persistence/room/testing/MigrationTestHelper",
+      "android/arch/persistence/room/testing/MigrationTestHelper$MigratingDelegate": "androidx/persistence/room/testing/MigrationTestHelper$MigratingDelegate",
+      "android/arch/persistence/room/util/TableInfo": "androidx/persistence/room/util/TableInfo",
+      "android/arch/persistence/room/RoomOpenHelper$Delegate": "androidx/persistence/room/RoomOpenHelper$Delegate",
+      "android/arch/persistence/room/RoomOpenHelper": "androidx/persistence/room/RoomOpenHelper",
+      "android/arch/persistence/room/RoomDatabase$MigrationContainer": "androidx/persistence/room/RoomDatabase$MigrationContainer",
+      "android/arch/persistence/room/util/TableInfo$Index": "androidx/persistence/room/util/TableInfo$Index",
+      "android/arch/persistence/room/util/TableInfo$ForeignKey": "androidx/persistence/room/util/TableInfo$ForeignKey",
+      "android/arch/persistence/room/util/TableInfo$Column": "androidx/persistence/room/util/TableInfo$Column",
+      "android/arch/persistence/room/DatabaseConfiguration": "androidx/persistence/room/DatabaseConfiguration",
+      "android/arch/persistence/room/migration/Migration": "androidx/persistence/room/migration/Migration",
+      "android/arch/lifecycle/ComputableLiveData$1": "androidx/lifecycle/ComputableLiveData$1",
+      "android/arch/lifecycle/ComputableLiveData$2": "androidx/lifecycle/ComputableLiveData$2",
+      "android/arch/lifecycle/ComputableLiveData$3": "androidx/lifecycle/ComputableLiveData$3",
+      "android/arch/lifecycle/MediatorLiveData$Source": "androidx/lifecycle/MediatorLiveData$Source",
+      "android/arch/lifecycle/MediatorLiveData": "androidx/lifecycle/MediatorLiveData",
+      "android/arch/lifecycle/Transformations$1": "androidx/lifecycle/Transformations$1",
+      "android/arch/lifecycle/Transformations": "androidx/lifecycle/Transformations",
+      "android/arch/core/util/Function": "androidx/core/util/Function",
+      "android/arch/lifecycle/Transformations$2$1": "androidx/lifecycle/Transformations$2$1",
+      "android/arch/lifecycle/Transformations$2": "androidx/lifecycle/Transformations$2",
+      "android/support/wear/ambient/AmbientDelegate$AmbientCallback": "androidx/wear/ambient/AmbientDelegate$AmbientCallback",
+      "android/support/wear/ambient/AmbientDelegate": "androidx/wear/ambient/AmbientDelegate",
+      "android/support/wear/ambient/WearableControllerProvider": "androidx/wear/ambient/WearableControllerProvider",
+      "android/support/wear/ambient/AmbientMode$1": "androidx/wear/ambient/AmbientMode$1",
+      "android/support/wear/ambient/AmbientMode": "androidx/wear/ambient/AmbientMode",
+      "android/support/wear/ambient/AmbientMode$AmbientCallback": "androidx/wear/ambient/AmbientMode$AmbientCallback",
+      "android/support/wear/ambient/AmbientMode$AmbientCallbackProvider": "androidx/wear/ambient/AmbientMode$AmbientCallbackProvider",
+      "android/support/wear/ambient/AmbientMode$AmbientController": "androidx/wear/ambient/AmbientMode$AmbientController",
+      "android/support/wear/ambient/AmbientModeSupport$1": "androidx/wear/ambient/AmbientModeSupport$1",
+      "android/support/wear/ambient/AmbientModeSupport": "androidx/wear/ambient/AmbientModeSupport",
+      "android/support/wear/ambient/AmbientModeSupport$AmbientCallback": "androidx/wear/ambient/AmbientModeSupport$AmbientCallback",
+      "android/support/wear/ambient/AmbientModeSupport$AmbientCallbackProvider": "androidx/wear/ambient/AmbientModeSupport$AmbientCallbackProvider",
+      "android/support/wear/ambient/AmbientModeSupport$AmbientController": "androidx/wear/ambient/AmbientModeSupport$AmbientController",
+      "android/support/wear/ambient/SharedLibraryVersion$PresenceHolder": "androidx/wear/ambient/SharedLibraryVersion$PresenceHolder",
+      "android/support/wear/ambient/SharedLibraryVersion": "androidx/wear/ambient/SharedLibraryVersion",
+      "android/support/wear/ambient/SharedLibraryVersion$VersionHolder": "androidx/wear/ambient/SharedLibraryVersion$VersionHolder",
+      "android/support/wear/ambient/WearableControllerProvider$1": "androidx/wear/ambient/WearableControllerProvider$1",
+      "android/support/wear/internal/widget/ResourcesUtil": "androidx/wear/internal/widget/ResourcesUtil",
+      "android/support/wear/internal/widget/drawer/MultiPagePresenter$Ui": "androidx/wear/internal/widget/drawer/MultiPagePresenter$Ui",
+      "android/support/wear/widget/drawer/WearableNavigationDrawerView$WearableNavigationDrawerAdapter": "androidx/wear/widget/drawer/WearableNavigationDrawerView$WearableNavigationDrawerAdapter",
+      "android/support/wear/widget/drawer/WearableNavigationDrawerView": "androidx/wear/widget/drawer/WearableNavigationDrawerView",
+      "android/support/wear/internal/widget/drawer/MultiPagePresenter": "androidx/wear/internal/widget/drawer/MultiPagePresenter",
+      "android/support/wear/internal/widget/drawer/WearableNavigationDrawerPresenter": "androidx/wear/internal/widget/drawer/WearableNavigationDrawerPresenter",
+      "android/support/wear/widget/drawer/WearableDrawerController": "androidx/wear/widget/drawer/WearableDrawerController",
+      "android/support/wear/internal/widget/drawer/MultiPageUi$1": "androidx/wear/internal/widget/drawer/MultiPageUi$1",
+      "android/support/wear/internal/widget/drawer/MultiPageUi": "androidx/wear/internal/widget/drawer/MultiPageUi",
+      "android/support/wear/internal/widget/drawer/MultiPageUi$NavigationPagerAdapter": "androidx/wear/internal/widget/drawer/MultiPageUi$NavigationPagerAdapter",
+      "android/support/wear/R$layout": "androidx/wear/R$layout",
+      "android/support/wear/R": "androidx/wear/R",
+      "android/support/wear/R$id": "androidx/wear/R$id",
+      "android/support/wear/widget/drawer/PageIndicatorView": "androidx/wear/widget/drawer/PageIndicatorView",
+      "android/support/wear/internal/widget/drawer/SinglePagePresenter$Ui": "androidx/wear/internal/widget/drawer/SinglePagePresenter$Ui",
+      "android/support/wear/internal/widget/drawer/SinglePagePresenter": "androidx/wear/internal/widget/drawer/SinglePagePresenter",
+      "android/support/wear/internal/widget/drawer/SinglePageUi$1": "androidx/wear/internal/widget/drawer/SinglePageUi$1",
+      "android/support/wear/internal/widget/drawer/SinglePageUi": "androidx/wear/internal/widget/drawer/SinglePageUi",
+      "android/support/wear/internal/widget/drawer/SinglePageUi$OnSelectedClickHandler": "androidx/wear/internal/widget/drawer/SinglePageUi$OnSelectedClickHandler",
+      "android/support/wear/widget/CircledImageView": "androidx/wear/widget/CircledImageView",
+      "android/support/wear/widget/drawer/WearableNavigationDrawerView$OnItemSelectedListener": "androidx/wear/widget/drawer/WearableNavigationDrawerView$OnItemSelectedListener",
+      "android/support/wear/utils/MetadataConstants": "androidx/wear/utils/MetadataConstants",
+      "android/support/wear/widget/BezierSCurveInterpolator": "androidx/wear/widget/BezierSCurveInterpolator",
+      "android/support/wear/widget/BoxInsetLayout$LayoutParams$BoxedEdges": "androidx/wear/widget/BoxInsetLayout$LayoutParams$BoxedEdges",
+      "android/support/wear/widget/BoxInsetLayout$LayoutParams": "androidx/wear/widget/BoxInsetLayout$LayoutParams",
+      "android/support/wear/widget/BoxInsetLayout": "androidx/wear/widget/BoxInsetLayout",
+      "android/support/wear/R$styleable": "androidx/wear/R$styleable",
+      "android/support/wear/widget/CircledImageView$1": "androidx/wear/widget/CircledImageView$1",
+      "android/support/wear/widget/CircledImageView$2": "androidx/wear/widget/CircledImageView$2",
+      "android/support/wear/widget/CircledImageView$OvalShadowPainter": "androidx/wear/widget/CircledImageView$OvalShadowPainter",
+      "android/support/wear/widget/ProgressDrawable": "androidx/wear/widget/ProgressDrawable",
+      "android/support/wear/widget/CircularProgressLayout$1": "androidx/wear/widget/CircularProgressLayout$1",
+      "android/support/wear/widget/CircularProgressLayout": "androidx/wear/widget/CircularProgressLayout",
+      "android/support/wear/widget/CircularProgressLayout$OnTimerFinishedListener": "androidx/wear/widget/CircularProgressLayout$OnTimerFinishedListener",
+      "android/support/wear/R$array": "androidx/wear/R$array",
+      "android/support/wear/R$dimen": "androidx/wear/R$dimen",
+      "android/support/wear/R$color": "androidx/wear/R$color",
+      "android/support/wear/widget/CircularProgressLayoutController": "androidx/wear/widget/CircularProgressLayoutController",
+      "android/support/wear/widget/CircularProgressLayoutController$CircularProgressTimer": "androidx/wear/widget/CircularProgressLayoutController$CircularProgressTimer",
+      "android/support/wear/widget/CurvingLayoutCallback": "androidx/wear/widget/CurvingLayoutCallback",
+      "android/support/wear/widget/WearableLinearLayoutManager$LayoutCallback": "androidx/wear/widget/WearableLinearLayoutManager$LayoutCallback",
+      "android/support/wear/widget/WearableLinearLayoutManager": "androidx/wear/widget/WearableLinearLayoutManager",
+      "android/support/wear/widget/ProgressDrawable$1": "androidx/wear/widget/ProgressDrawable$1",
+      "android/support/wear/widget/RoundedDrawable": "androidx/wear/widget/RoundedDrawable",
+      "android/support/wear/widget/ScrollManager": "androidx/wear/widget/ScrollManager",
+      "android/support/wear/widget/SimpleAnimatorListener": "androidx/wear/widget/SimpleAnimatorListener",
+      "android/support/wear/widget/SwipeDismissFrameLayout$1": "androidx/wear/widget/SwipeDismissFrameLayout$1",
+      "android/support/wear/widget/SwipeDismissFrameLayout": "androidx/wear/widget/SwipeDismissFrameLayout",
+      "android/support/wear/widget/SwipeDismissFrameLayout$Callback": "androidx/wear/widget/SwipeDismissFrameLayout$Callback",
+      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener$1": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener$1",
+      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnDismissedListener",
+      "android/support/wear/widget/SwipeDismissLayout": "androidx/wear/widget/SwipeDismissLayout",
+      "android/support/wear/widget/SwipeDismissLayout$OnDismissedListener": "androidx/wear/widget/SwipeDismissLayout$OnDismissedListener",
+      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnPreSwipeListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnPreSwipeListener",
+      "android/support/wear/widget/SwipeDismissLayout$OnPreSwipeListener": "androidx/wear/widget/SwipeDismissLayout$OnPreSwipeListener",
+      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener$1": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener$1",
+      "android/support/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener": "androidx/wear/widget/SwipeDismissFrameLayout$MyOnSwipeProgressChangedListener",
+      "android/support/wear/widget/SwipeDismissLayout$OnSwipeProgressChangedListener": "androidx/wear/widget/SwipeDismissLayout$OnSwipeProgressChangedListener",
+      "android/support/wear/widget/WearableRecyclerView": "androidx/wear/widget/WearableRecyclerView",
+      "android/support/wear/widget/WearableRecyclerView$1": "androidx/wear/widget/WearableRecyclerView$1",
+      "android/support/wear/widget/drawer/AbsListViewFlingWatcher": "androidx/wear/widget/drawer/AbsListViewFlingWatcher",
+      "android/support/wear/widget/drawer/FlingWatcherFactory$FlingWatcher": "androidx/wear/widget/drawer/FlingWatcherFactory$FlingWatcher",
+      "android/support/wear/widget/drawer/FlingWatcherFactory$FlingListener": "androidx/wear/widget/drawer/FlingWatcherFactory$FlingListener",
+      "android/support/wear/widget/drawer/FlingWatcherFactory": "androidx/wear/widget/drawer/FlingWatcherFactory",
+      "android/support/wear/widget/drawer/RecyclerViewFlingWatcher": "androidx/wear/widget/drawer/RecyclerViewFlingWatcher",
+      "android/support/wear/widget/drawer/ScrollViewFlingWatcher": "androidx/wear/widget/drawer/ScrollViewFlingWatcher",
+      "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher": "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher",
+      "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher$1": "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher$1",
+      "android/support/wear/widget/drawer/PageIndicatorView$1": "androidx/wear/widget/drawer/PageIndicatorView$1",
+      "android/support/wear/R$style": "androidx/wear/R$style",
+      "android/support/wear/widget/drawer/ScrollViewFlingWatcher$1": "androidx/wear/widget/drawer/ScrollViewFlingWatcher$1",
+      "android/support/wear/widget/drawer/WearableActionDrawerMenu$1": "androidx/wear/widget/drawer/WearableActionDrawerMenu$1",
+      "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem$MenuItemChangedListener": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem$MenuItemChangedListener",
+      "android/support/wear/widget/drawer/WearableActionDrawerMenu": "androidx/wear/widget/drawer/WearableActionDrawerMenu",
+      "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuItem",
+      "android/support/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuListener": "androidx/wear/widget/drawer/WearableActionDrawerMenu$WearableActionDrawerMenuListener",
+      "android/support/wear/widget/drawer/WearableActionDrawerView$1": "androidx/wear/widget/drawer/WearableActionDrawerView$1",
+      "android/support/wear/widget/drawer/WearableActionDrawerView": "androidx/wear/widget/drawer/WearableActionDrawerView",
+      "android/support/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder": "androidx/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder",
+      "android/support/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter$1": "androidx/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter$1",
+      "android/support/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter": "androidx/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter",
+      "android/support/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder": "androidx/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder",
+      "android/support/wear/widget/drawer/WearableDrawerView": "androidx/wear/widget/drawer/WearableDrawerView",
+      "android/support/wear/R$string": "androidx/wear/R$string",
+      "android/support/wear/R$fraction": "androidx/wear/R$fraction",
+      "android/support/wear/widget/drawer/WearableDrawerLayout": "androidx/wear/widget/drawer/WearableDrawerLayout",
+      "android/support/wear/widget/drawer/WearableDrawerLayout$1": "androidx/wear/widget/drawer/WearableDrawerLayout$1",
+      "android/support/wear/widget/drawer/WearableDrawerLayout$2": "androidx/wear/widget/drawer/WearableDrawerLayout$2",
+      "android/support/wear/widget/drawer/WearableDrawerLayout$BottomDrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$BottomDrawerDraggerCallback",
+      "android/support/wear/widget/drawer/WearableDrawerLayout$DrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$DrawerDraggerCallback",
+      "android/support/wear/widget/drawer/WearableDrawerLayout$ClosePeekRunnable": "androidx/wear/widget/drawer/WearableDrawerLayout$ClosePeekRunnable",
+      "android/support/wear/widget/drawer/WearableDrawerLayout$DrawerStateCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$DrawerStateCallback",
+      "android/support/wear/widget/drawer/WearableDrawerLayout$TopDrawerDraggerCallback": "androidx/wear/widget/drawer/WearableDrawerLayout$TopDrawerDraggerCallback",
+      "android/support/wear/widget/drawer/WearableDrawerView$1": "androidx/wear/widget/drawer/WearableDrawerView$1",
+      "android/support/wear/widget/drawer/WearableDrawerView$DrawerState": "androidx/wear/widget/drawer/WearableDrawerView$DrawerState",
+      "android/support/wear/R$drawable": "androidx/wear/R$drawable",
+      "android/support/wear/widget/drawer/WearableNavigationDrawerView$1": "androidx/wear/widget/drawer/WearableNavigationDrawerView$1",
+      "android/support/wear/widget/drawer/WearableNavigationDrawerView$2": "androidx/wear/widget/drawer/WearableNavigationDrawerView$2",
+      "android/support/wear/widget/drawer/WearableNavigationDrawerView$NavigationStyle": "androidx/wear/widget/drawer/WearableNavigationDrawerView$NavigationStyle",
+      "android/support/text/emoji/EmojiCompat$CompatInternal": "androidx/text/emoji/EmojiCompat$CompatInternal",
+      "android/support/text/emoji/EmojiCompat": "androidx/text/emoji/EmojiCompat",
+      "android/support/text/emoji/EmojiProcessor$GlyphChecker": "androidx/text/emoji/EmojiProcessor$GlyphChecker",
+      "android/support/text/emoji/EmojiProcessor": "androidx/text/emoji/EmojiProcessor",
+      "android/support/text/emoji/EmojiCompat$CompatInternal19$1": "androidx/text/emoji/EmojiCompat$CompatInternal19$1",
+      "android/support/text/emoji/EmojiCompat$MetadataRepoLoaderCallback": "androidx/text/emoji/EmojiCompat$MetadataRepoLoaderCallback",
+      "android/support/text/emoji/EmojiCompat$CompatInternal19": "androidx/text/emoji/EmojiCompat$CompatInternal19",
+      "android/support/text/emoji/MetadataRepo": "androidx/text/emoji/MetadataRepo",
+      "android/support/text/emoji/EmojiCompat$SpanFactory": "androidx/text/emoji/EmojiCompat$SpanFactory",
+      "android/support/text/emoji/EmojiCompat$MetadataRepoLoader": "androidx/text/emoji/EmojiCompat$MetadataRepoLoader",
+      "android/support/text/emoji/EmojiMetadata": "androidx/text/emoji/EmojiMetadata",
+      "android/support/text/emoji/EmojiCompat$Config": "androidx/text/emoji/EmojiCompat$Config",
+      "android/support/text/emoji/EmojiCompat$InitCallback": "androidx/text/emoji/EmojiCompat$InitCallback",
+      "android/support/text/emoji/EmojiCompat$ListenerDispatcher": "androidx/text/emoji/EmojiCompat$ListenerDispatcher",
+      "android/support/text/emoji/EmojiCompat$LoadState": "androidx/text/emoji/EmojiCompat$LoadState",
+      "android/support/text/emoji/EmojiCompat$ReplaceStrategy": "androidx/text/emoji/EmojiCompat$ReplaceStrategy",
+      "android/support/text/emoji/EmojiSpan": "androidx/text/emoji/EmojiSpan",
+      "android/support/text/emoji/TypefaceEmojiSpan": "androidx/text/emoji/TypefaceEmojiSpan",
+      "android/support/text/emoji/EmojiMetadata$HasGlyph": "androidx/text/emoji/EmojiMetadata$HasGlyph",
+      "android/support/text/emoji/EmojiProcessor$Action": "androidx/text/emoji/EmojiProcessor$Action",
+      "android/support/text/emoji/EmojiProcessor$CodepointIndexFinder": "androidx/text/emoji/EmojiProcessor$CodepointIndexFinder",
+      "android/support/text/emoji/EmojiProcessor$ProcessorSm": "androidx/text/emoji/EmojiProcessor$ProcessorSm",
+      "android/support/text/emoji/MetadataRepo$Node": "androidx/text/emoji/MetadataRepo$Node",
+      "android/support/text/emoji/widget/SpannableBuilder": "androidx/text/emoji/widget/SpannableBuilder",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig$ExponentialBackoffRetryPolicy": "androidx/text/emoji/FontRequestEmojiCompatConfig$ExponentialBackoffRetryPolicy",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig$RetryPolicy": "androidx/text/emoji/FontRequestEmojiCompatConfig$RetryPolicy",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig": "androidx/text/emoji/FontRequestEmojiCompatConfig",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig$FontProviderHelper": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontProviderHelper",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$1": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$1",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$2": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$2",
+      "android/support/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$3": "androidx/text/emoji/FontRequestEmojiCompatConfig$FontRequestMetadataLoader$3",
+      "android/support/text/emoji/MetadataListReader$ByteBufferReader": "androidx/text/emoji/MetadataListReader$ByteBufferReader",
+      "android/support/text/emoji/MetadataListReader$OpenTypeReader": "androidx/text/emoji/MetadataListReader$OpenTypeReader",
+      "android/support/text/emoji/MetadataListReader": "androidx/text/emoji/MetadataListReader",
+      "android/support/text/emoji/MetadataListReader$InputStreamOpenTypeReader": "androidx/text/emoji/MetadataListReader$InputStreamOpenTypeReader",
+      "android/support/text/emoji/MetadataListReader$OffsetInfo": "androidx/text/emoji/MetadataListReader$OffsetInfo",
+      "android/support/text/emoji/MetadataRepo$1": "androidx/text/emoji/MetadataRepo$1",
+      "android/support/text/emoji/R$styleable": "androidx/text/emoji/R$styleable",
+      "android/support/text/emoji/R": "androidx/text/emoji/R",
+      "android/support/text/emoji/widget/EmojiButton": "androidx/text/emoji/widget/EmojiButton",
+      "android/support/text/emoji/widget/EmojiEditText": "androidx/text/emoji/widget/EmojiEditText",
+      "android/support/text/emoji/widget/EmojiEditTextHelper$1": "androidx/text/emoji/widget/EmojiEditTextHelper$1",
+      "android/support/text/emoji/widget/EmojiEditTextHelper$HelperInternal": "androidx/text/emoji/widget/EmojiEditTextHelper$HelperInternal",
+      "android/support/text/emoji/widget/EmojiEditTextHelper$HelperInternal19": "androidx/text/emoji/widget/EmojiEditTextHelper$HelperInternal19",
+      "android/support/text/emoji/widget/EmojiTextWatcher": "androidx/text/emoji/widget/EmojiTextWatcher",
+      "android/support/text/emoji/widget/EmojiEditableFactory": "androidx/text/emoji/widget/EmojiEditableFactory",
+      "android/support/text/emoji/widget/EmojiKeyListener": "androidx/text/emoji/widget/EmojiKeyListener",
+      "android/support/text/emoji/widget/EmojiInputConnection": "androidx/text/emoji/widget/EmojiInputConnection",
+      "android/support/text/emoji/widget/EmojiExtractEditText": "androidx/text/emoji/widget/EmojiExtractEditText",
+      "android/support/text/emoji/widget/EmojiExtractTextLayout$ButtonOnclickListener": "androidx/text/emoji/widget/EmojiExtractTextLayout$ButtonOnclickListener",
+      "android/support/text/emoji/widget/EmojiExtractTextLayout": "androidx/text/emoji/widget/EmojiExtractTextLayout",
       "android/support/text/emoji/R$layout": "androidx/text/emoji/R$layout",
-      "android/support/v4/media/session/MediaSessionCompat$SessionFlags": "androidx/media/session/MediaSessionCompat$SessionFlags",
-      "android/support/v7/preference/PreferenceRecyclerViewAccessibilityDelegate": "androidx/preference/PreferenceRecyclerViewAccessibilityDelegate",
-      "android/support/transition/AnimatorUtils": "androidx/transition/AnimatorUtils",
-      "android/support/v17/leanback/system/Settings": "androidx/leanback/system/Settings",
-      "android/support/v4/app/FragmentActivity$NonConfigurationInstances": "androidx/app/FragmentActivity$NonConfigurationInstances",
-      "android/support/v17/leanback/widget/GuidedActionAdapter$EditListener": "androidx/leanback/widget/GuidedActionAdapter$EditListener",
-      "android/support/v7/media/MediaRouteProvider$Callback": "androidx/media/MediaRouteProvider$Callback",
-      "android/support/v7/app/AppCompatDelegateImplV9$PanelMenuPresenterCallback": "androidx/app/AppCompatDelegateImplV9$PanelMenuPresenterCallback",
-      "android/support/constraint/ConstraintSet$Constraint": "androidx/constraint/ConstraintSet$Constraint",
-      "android/support/wear/R$dimen": "androidx/wear/R$dimen"
-    },
-    "fields": {
-      "android/support/v4/view/AbsSavedState": {
-        "androidx/view/AbsSavedState": [
-          "CREATOR",
-          "EMPTY_STATE"
-        ]
-      },
-      "android/support/v4/view/PagerTabStrip": {
-        "androidx/widget/PagerTabStrip": [
-          "TAG",
-          "TAB_PADDING",
-          "TAB_SPACING",
-          "FULL_UNDERLINE_HEIGHT",
-          "MIN_PADDING_BOTTOM",
-          "MIN_STRIP_HEIGHT",
-          "MIN_TEXT_SPACING",
-          "INDICATOR_HEIGHT"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$Channels": {
-        "androidx/media/tv/TvContractCompat$Channels": [
-          "VIDEO_FORMAT_4320P",
-          "VIDEO_RESOLUTION_HD",
-          "VIDEO_RESOLUTION_ED",
-          "VIDEO_FORMAT_720P",
-          "COLUMN_TRANSIENT",
-          "VIDEO_FORMAT_TO_RESOLUTION_MAP",
-          "COLUMN_DISPLAY_NAME",
-          "VIDEO_FORMAT_240P",
-          "COLUMN_VIDEO_FORMAT",
-          "COLUMN_APP_LINK_TEXT",
-          "COLUMN_APP_LINK_POSTER_ART_URI",
-          "VIDEO_FORMAT_360P",
-          "TYPE_OTHER",
-          "COLUMN_NETWORK_AFFILIATION",
-          "TYPE_PAL",
-          "SERVICE_TYPE_OTHER",
-          "VIDEO_FORMAT_480P",
-          "VIDEO_FORMAT_480I",
-          "CONTENT_URI",
-          "TYPE_CMMB",
-          "TYPE_ATSC_C",
-          "TYPE_ATSC_T",
-          "VIDEO_RESOLUTION_FHD",
-          "COLUMN_APP_LINK_INTENT_URI",
-          "VIDEO_FORMAT_2160P",
-          "TYPE_SECAM",
-          "COLUMN_INTERNAL_PROVIDER_FLAG2",
-          "COLUMN_INTERNAL_PROVIDER_FLAG1",
-          "COLUMN_INTERNAL_PROVIDER_FLAG4",
-          "COLUMN_INTERNAL_PROVIDER_FLAG3",
-          "TYPE_T_DMB",
-          "CONTENT_TYPE",
-          "COLUMN_TRANSPORT_STREAM_ID",
-          "VIDEO_FORMAT_576P",
-          "VIDEO_FORMAT_576I",
-          "COLUMN_LOCKED",
-          "COLUMN_SERVICE_TYPE",
-          "TYPE_ISDB_S",
-          "TYPE_ISDB_T",
-          "TYPE_ISDB_C",
-          "COLUMN_DESCRIPTION",
-          "TYPE_DVB_S2",
-          "TYPE_DVB_T2",
-          "TYPE_DVB_SH",
-          "TYPE_DTMB",
-          "COLUMN_INPUT_ID",
-          "VIDEO_RESOLUTION_SD",
-          "COLUMN_VERSION_NUMBER",
-          "COLUMN_SEARCHABLE",
-          "COLUMN_SERVICE_ID",
-          "TYPE_1SEG",
-          "TYPE_DVB_C2",
-          "TYPE_DVB_C",
-          "TYPE_DVB_H",
-          "TYPE_DVB_S",
-          "TYPE_DVB_T",
-          "CONTENT_ITEM_TYPE",
-          "SERVICE_TYPE_AUDIO",
-          "TYPE_ATSC_M_H",
-          "TYPE_NTSC",
-          "COLUMN_BROWSABLE",
-          "TYPE_ISDB_TB",
-          "COLUMN_INTERNAL_PROVIDER_DATA",
-          "COLUMN_DISPLAY_NUMBER",
-          "COLUMN_SYSTEM_APPROVED",
-          "VIDEO_FORMAT_1080I",
-          "VIDEO_FORMAT_1080P",
-          "COLUMN_TYPE",
-          "VIDEO_RESOLUTION_UHD",
-          "COLUMN_APP_LINK_ICON_URI",
-          "TYPE_S_DMB",
-          "COLUMN_APP_LINK_COLOR",
-          "SERVICE_TYPE_AUDIO_VIDEO",
-          "TYPE_PREVIEW",
-          "COLUMN_ORIGINAL_NETWORK_ID",
-          "COLUMN_INTERNAL_PROVIDER_ID"
-        ]
-      },
-      "android/support/v7/widget/ViewBoundsCheck": {
-        "androidx/widget/ViewBoundsCheck": [
-          "FLAG_CVS_EQ_PVE",
-          "FLAG_CVS_EQ_PVS",
-          "GT",
-          "LT",
-          "EQ",
-          "FLAG_CVS_GT_PVS",
-          "FLAG_CVS_GT_PVE",
-          "FLAG_CVE_EQ_PVE",
-          "FLAG_CVE_EQ_PVS",
-          "MASK",
-          "CVS_PVE_POS",
-          "CVE_PVE_POS",
-          "FLAG_CVS_LT_PVE",
-          "FLAG_CVS_LT_PVS",
-          "CVS_PVS_POS",
-          "FLAG_CVE_LT_PVS",
-          "FLAG_CVE_LT_PVE",
-          "CVE_PVS_POS",
-          "FLAG_CVE_GT_PVS",
-          "FLAG_CVE_GT_PVE"
-        ]
-      },
-      "android/support/constraint/ConstraintLayout$LayoutParams": {
-        "androidx/constraint/ConstraintLayout$LayoutParams": [
-          "topToTop",
-          "goneTopMargin",
-          "verticalWeight",
-          "horizontalDimensionFixed",
-          "goneBottomMargin",
-          "matchConstraintMaxHeight",
-          "resolveGoneLeftMargin",
-          "leftMargin",
-          "MATCH_CONSTRAINT",
-          "resolvedRightToLeft",
-          "needsBaseline",
-          "startToEnd",
-          "TOP",
-          "horizontalChainStyle",
-          "guidePercent",
-          "CHAIN_SPREAD",
-          "topMargin",
-          "goneStartMargin",
-          "goneRightMargin",
-          "UNSET",
-          "HORIZONTAL",
-          "dimensionRatioValue",
-          "MATCH_CONSTRAINT_SPREAD",
-          "END",
-          "guideBegin",
-          "matchConstraintMaxWidth",
-          "verticalDimensionFixed",
-          "resolvedRightToRight",
-          "BASELINE",
-          "START",
-          "resolvedHorizontalBias",
-          "bottomToBottom",
-          "MATCH_CONSTRAINT_WRAP",
-          "startToStart",
-          "RIGHT",
-          "orientation",
-          "matchConstraintDefaultHeight",
-          "guideEnd",
-          "bottomToTop",
-          "CHAIN_PACKED",
-          "isGuideline",
-          "dimensionRatioSide",
-          "dimensionRatio",
-          "goneLeftMargin",
-          "matchConstraintMinWidth",
-          "PARENT_ID",
-          "endToStart",
-          "LEFT",
-          "horizontalBias",
-          "leftToLeft",
-          "BOTTOM",
-          "resolveGoneRightMargin",
-          "leftToRight",
-          "verticalBias",
-          "goneEndMargin",
-          "VERTICAL",
-          "rightMargin",
-          "rightToRight",
-          "resolvedLeftToLeft",
-          "topToBottom",
-          "endToEnd",
-          "matchConstraintDefaultWidth",
-          "matchConstraintMinHeight",
-          "height",
-          "CHAIN_SPREAD_INSIDE",
-          "widget",
-          "resolvedLeftToRight",
-          "baselineToBaseline",
-          "rightToLeft",
-          "verticalChainStyle",
-          "editorAbsoluteY",
-          "editorAbsoluteX",
-          "bottomMargin",
-          "width",
-          "horizontalWeight"
-        ]
-      },
-      "android/support/v4/media/session/PlaybackStateCompat": {
-        "androidx/media/session/PlaybackStateCompat": [
-          "STATE_NONE",
-          "ACTION_SET_SHUFFLE_MODE",
-          "ACTION_SKIP_TO_QUEUE_ITEM",
-          "ERROR_CODE_CONTENT_ALREADY_PLAYING",
-          "STATE_ERROR",
-          "SHUFFLE_MODE_NONE",
-          "CREATOR",
-          "STATE_SKIPPING_TO_PREVIOUS",
-          "PLAYBACK_POSITION_UNKNOWN",
-          "REPEAT_MODE_INVALID",
-          "REPEAT_MODE_GROUP",
-          "ACTION_SET_REPEAT_MODE",
-          "ACTION_SKIP_TO_PREVIOUS",
-          "ACTION_PREPARE",
-          "ERROR_CODE_SKIP_LIMIT_REACHED",
-          "REPEAT_MODE_NONE",
-          "ACTION_PREPARE_FROM_URI",
-          "STATE_PLAYING",
-          "STATE_SKIPPING_TO_NEXT",
-          "ACTION_FAST_FORWARD",
-          "ERROR_CODE_END_OF_QUEUE",
-          "ERROR_CODE_PARENTAL_CONTROL_RESTRICTED",
-          "STATE_BUFFERING",
-          "ACTION_REWIND",
-          "KEYCODE_MEDIA_PAUSE",
-          "ACTION_PLAY_FROM_MEDIA_ID",
-          "STATE_FAST_FORWARDING",
-          "ACTION_STOP",
-          "KEYCODE_MEDIA_PLAY",
-          "ACTION_PLAY",
-          "ACTION_SET_CAPTIONING_ENABLED",
-          "ERROR_CODE_NOT_SUPPORTED",
-          "STATE_STOPPED",
-          "ACTION_PLAY_PAUSE",
-          "SHUFFLE_MODE_ALL",
-          "ERROR_CODE_AUTHENTICATION_EXPIRED",
-          "ERROR_CODE_APP_ERROR",
-          "ACTION_SEEK_TO",
-          "ERROR_CODE_CONCURRENT_STREAM_LIMIT",
-          "REPEAT_MODE_ALL",
-          "ERROR_CODE_NOT_AVAILABLE_IN_REGION",
-          "ERROR_CODE_ACTION_ABORTED",
-          "STATE_CONNECTING",
-          "ACTION_SKIP_TO_NEXT",
-          "SHUFFLE_MODE_INVALID",
-          "ACTION_PLAY_FROM_SEARCH",
-          "ERROR_CODE_UNKNOWN_ERROR",
-          "ACTION_PAUSE",
-          "ACTION_PLAY_FROM_URI",
-          "REPEAT_MODE_ONE",
-          "ACTION_SET_RATING",
-          "ACTION_PREPARE_FROM_SEARCH",
-          "STATE_PAUSED",
-          "SHUFFLE_MODE_GROUP",
-          "STATE_REWINDING",
-          "ACTION_PREPARE_FROM_MEDIA_ID",
-          "ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED",
-          "STATE_SKIPPING_TO_QUEUE_ITEM",
-          "ACTION_SET_SHUFFLE_MODE_ENABLED"
-        ]
-      },
-      "android/support/v7/appcompat/R$styleable": {
-        "androidx/appcompat/R$styleable": [
-          "MenuItem_android_title",
-          "Toolbar_android_gravity",
-          "ActionMode_titleTextStyle",
-          "ActionBar_popupTheme",
-          "MenuView_android_itemTextAppearance",
-          "SearchView_goIcon",
-          "MenuItem_actionLayout",
-          "Toolbar_navigationIcon",
-          "ColorStateListItem_android_alpha",
-          "AppCompatTheme_android_windowAnimationStyle",
-          "LinearLayoutCompat_android_orientation",
-          "AppCompatTheme_windowActionBar",
-          "MenuItem_showAsAction",
-          "ColorStateListItem_android_color",
-          "ActivityChooserView_initialActivityCount",
-          "AppCompatSeekBar_tickMarkTint",
-          "CompoundButton_android_button",
-          "MenuGroup_android_orderInCategory",
-          "PopupWindow_overlapAnchor",
-          "ViewBackgroundHelper_backgroundTint",
-          "PopupWindow",
-          "Toolbar_contentInsetEndWithActions",
-          "MenuItem_android_titleCondensed",
-          "TextAppearance",
-          "MenuItem_android_id",
-          "LinearLayoutCompat_measureWithLargestChild",
-          "AppCompatTextView_autoSizeTextType",
-          "AppCompatTheme_windowMinWidthMajor",
-          "DrawerArrowToggle_color",
-          "AppCompatTheme",
-          "SwitchCompat_trackTintMode",
-          "AppCompatTheme_windowActionBarOverlay",
-          "DrawerArrowToggle_spinBars",
-          "LinearLayoutCompat",
-          "AppCompatTextHelper",
-          "ActionMode_subtitleTextStyle",
-          "Toolbar_titleTextAppearance",
-          "ActivityChooserView",
-          "LinearLayoutCompat_divider",
-          "MenuItem_android_alphabeticShortcut",
-          "Toolbar_subtitleTextColor",
-          "AppCompatImageView_tint",
-          "AppCompatTheme_windowFixedHeightMajor",
-          "LinearLayoutCompat_android_baselineAlignedChildIndex",
-          "AppCompatTheme_windowMinWidthMinor",
-          "SearchView_suggestionRowLayout",
-          "ListPopupWindow_android_dropDownHorizontalOffset",
-          "ActionBar_subtitleTextStyle",
-          "Toolbar_titleMarginEnd",
-          "Toolbar_titleMarginTop",
-          "LinearLayoutCompat_Layout",
-          "TextAppearance_android_textColor",
-          "Toolbar_subtitleTextAppearance",
-          "ActionBar_displayOptions",
-          "Toolbar_title",
-          "Spinner_android_entries",
-          "MenuItem_numericModifiers",
-          "RecycleListView",
-          "AppCompatTextHelper_android_drawableEnd",
-          "SearchView_searchHintIcon",
-          "Toolbar_collapseIcon",
-          "AppCompatImageView",
-          "MenuItem_android_icon",
-          "ActionBar_contentInsetStart",
-          "MenuItem_android_onClick",
-          "SearchView_searchIcon",
-          "MenuItem_actionViewClass",
-          "MenuGroup_android_enabled",
-          "Toolbar_subtitle",
-          "MenuGroup_android_id",
-          "TextAppearance_android_fontFamily",
-          "ViewBackgroundHelper_android_background",
-          "TextAppearance_android_textColorHint",
-          "LinearLayoutCompat_android_baselineAligned",
-          "MenuItem_contentDescription",
-          "SearchView_voiceIcon",
-          "ActionBar_background",
-          "ActionMenuItemView",
-          "SwitchCompat_switchMinWidth",
-          "AppCompatTheme_windowFixedWidthMajor",
-          "ActionMenuItemView_android_minWidth",
-          "AlertDialog_buttonPanelSideLayout",
-          "SearchView_defaultQueryHint",
-          "MenuItem_android_numericShortcut",
-          "ActionBar_homeAsUpIndicator",
-          "AppCompatTextHelper_android_drawableTop",
-          "DrawerArrowToggle_arrowHeadLength",
-          "TextAppearance_android_shadowRadius",
-          "Toolbar_titleMargins",
-          "SwitchCompat",
-          "ActionBar_height",
-          "LinearLayoutCompat_Layout_android_layout_gravity",
-          "AlertDialog_multiChoiceItemLayout",
-          "CompoundButton_buttonTint",
-          "SearchView_android_imeOptions",
-          "MenuGroup",
-          "ActionBar_customNavigationLayout",
-          "Toolbar_navigationContentDescription",
-          "Toolbar_popupTheme",
-          "View",
-          "ActionBar",
-          "SwitchCompat_android_textOff",
-          "MenuGroup_android_menuCategory",
-          "MenuItem_tooltipText",
-          "AppCompatTextView",
-          "Spinner",
-          "ViewStubCompat_android_inflatedId",
-          "Spinner_popupTheme",
-          "SearchView_closeIcon",
-          "TextAppearance_textAllCaps",
-          "SwitchCompat_trackTint",
-          "Toolbar_logoDescription",
-          "MenuView_android_itemBackground",
-          "TextAppearance_android_textSize",
-          "SearchView_queryBackground",
-          "MenuItem_android_checked",
-          "SearchView_commitIcon",
-          "LinearLayoutCompat_Layout_android_layout_weight",
-          "ViewStubCompat_android_id",
-          "AppCompatTextView_autoSizePresetSizes",
-          "ActionBar_hideOnContentScroll",
-          "Toolbar_contentInsetStartWithNavigation",
-          "AppCompatTextHelper_android_drawableBottom",
-          "PopupWindow_android_popupBackground",
-          "Toolbar_buttonGravity",
-          "AlertDialog",
-          "TextAppearance_android_textStyle",
-          "SwitchCompat_thumbTintMode",
-          "MenuItem_android_checkable",
-          "AppCompatTheme_windowFixedWidthMinor",
-          "TextAppearance_android_textColorLink",
-          "Toolbar_titleMarginStart",
-          "RecycleListView_paddingBottomNoButtons",
-          "ActionMode_closeItemLayout",
-          "Toolbar",
-          "Toolbar_collapseContentDescription",
-          "MenuItem_android_menuCategory",
-          "AppCompatTextHelper_android_textAppearance",
-          "View_theme",
-          "MenuItem_iconTintMode",
-          "Toolbar_contentInsetLeft",
-          "Toolbar_contentInsetStart",
-          "LinearLayoutCompat_android_weightSum",
-          "SwitchCompat_android_textOn",
-          "AppCompatSeekBar",
-          "MenuItem_actionProviderClass",
-          "Toolbar_titleMargin",
-          "AlertDialog_singleChoiceItemLayout",
-          "Toolbar_contentInsetRight",
-          "LinearLayoutCompat_showDividers",
-          "SwitchCompat_android_thumb",
-          "AlertDialog_showTitle",
-          "TextAppearance_android_shadowDy",
-          "TextAppearance_android_shadowDx",
-          "AppCompatTheme_windowActionModeOverlay",
-          "MenuItem_android_visible",
-          "MenuView",
-          "SearchView",
-          "MenuItem",
-          "SearchView_queryHint",
-          "SwitchCompat_thumbTint",
-          "SwitchCompat_thumbTextPadding",
-          "AlertDialog_listLayout",
-          "ActionBar_subtitle",
-          "AlertDialog_android_layout",
-          "ListPopupWindow_android_dropDownVerticalOffset",
-          "Toolbar_titleMarginBottom",
-          "AppCompatSeekBar_android_thumb",
-          "ListPopupWindow",
-          "ButtonBarLayout_allowStacking",
-          "MenuGroup_android_checkableBehavior",
-          "SwitchCompat_switchPadding",
-          "LinearLayoutCompat_android_gravity",
-          "AppCompatTheme_windowNoTitle",
-          "ActionBar_icon",
-          "AppCompatTextView_autoSizeMinTextSize",
-          "Toolbar_logo",
-          "ViewStubCompat_android_layout",
-          "MenuItem_android_enabled",
-          "MenuItem_iconTint",
-          "AppCompatTextHelper_android_drawableRight",
-          "AppCompatTheme_android_windowIsFloating",
-          "Spinner_android_popupBackground",
-          "TextAppearance_android_shadowColor",
-          "Toolbar_maxButtonHeight",
-          "TextAppearance_android_typeface",
-          "DrawerArrowToggle_drawableSize",
-          "DrawerArrowToggle_barLength",
-          "CompoundButton",
-          "ActionMode_height",
-          "DrawerArrowToggle_arrowShaftLength",
-          "DrawerArrowToggle_gapBetweenBars",
-          "SearchView_android_focusable",
-          "ActionMode",
-          "AppCompatTextHelper_android_drawableStart",
-          "SearchView_android_maxWidth",
-          "ActivityChooserView_expandActivityOverflowButtonDrawable",
-          "ActionMode_background",
-          "ActionBar_backgroundSplit",
-          "SwitchCompat_track",
-          "MenuItem_alphabeticModifiers",
-          "TextAppearance_fontFamily",
-          "DrawerArrowToggle_thickness",
-          "AppCompatTextHelper_android_drawableLeft",
-          "ActionBar_contentInsetEnd",
-          "Spinner_android_dropDownWidth",
-          "ColorStateListItem_alpha",
-          "LinearLayoutCompat_dividerPadding",
-          "ViewStubCompat",
-          "View_android_theme",
-          "ActionBar_backgroundStacked",
-          "SearchView_android_inputType",
-          "AlertDialog_listItemLayout",
-          "AppCompatTheme_panelBackground",
-          "AppCompatImageView_srcCompat",
-          "ColorStateListItem",
-          "AppCompatTheme_windowFixedHeightMinor",
-          "MenuView_preserveIconSpacing",
-          "ActionBar_logo",
-          "AppCompatSeekBar_tickMarkTintMode",
-          "SwitchCompat_showText",
-          "AppCompatTextView_autoSizeStepGranularity",
-          "Toolbar_contentInsetEnd",
-          "SearchView_submitBackground",
-          "MenuView_subMenuArrow",
-          "CompoundButton_buttonTintMode",
-          "MenuItem_android_orderInCategory",
-          "ViewBackgroundHelper_backgroundTintMode",
-          "SwitchCompat_switchTextAppearance",
-          "ActionBar_titleTextStyle",
-          "Toolbar_titleTextColor",
-          "MenuGroup_android_visible",
-          "SwitchCompat_splitTrack",
-          "ButtonBarLayout",
-          "AppCompatSeekBar_tickMark",
-          "Spinner_android_prompt",
-          "AppCompatTextView_autoSizeMaxTextSize",
-          "ActionBar_elevation",
-          "ActionBarLayout_android_layout_gravity",
-          "DrawerArrowToggle",
-          "ActionBar_title",
-          "AppCompatImageView_tintMode",
-          "SearchView_layout",
-          "ViewBackgroundHelper",
-          "RecycleListView_paddingTopNoTitle",
-          "ActionBarLayout",
-          "SearchView_iconifiedByDefault"
-        ]
-      },
-      "android/support/v17/leanback/widget/FocusHighlight": {
-        "androidx/leanback/widget/FocusHighlight": [
-          "ZOOM_FACTOR_SMALL",
-          "ZOOM_FACTOR_XSMALL",
-          "ZOOM_FACTOR_NONE",
-          "ZOOM_FACTOR_LARGE",
-          "ZOOM_FACTOR_MEDIUM"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$Command": {
-        "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$Command": [
-          "extras",
-          "command",
-          "stub"
-        ]
-      },
-      "android/support/v7/appcompat/R$attr": {
-        "androidx/appcompat/R$attr": [
-          "checkboxStyle",
-          "colorButtonNormal",
-          "editTextStyle",
-          "actionDropDownStyle",
-          "colorControlNormal",
-          "colorAccent",
-          "actionBarSize",
-          "listMenuViewStyle",
-          "buttonStyle",
-          "colorControlHighlight",
-          "panelMenuListTheme",
-          "seekBarStyle",
-          "actionModeStyle",
-          "alertDialogStyle",
-          "isLightTheme",
-          "ratingBarStyle",
-          "radioButtonStyle",
-          "actionBarTabTextStyle",
-          "alertDialogCenterButtons",
-          "actionBarStyle",
-          "listPopupWindowStyle",
-          "actionBarPopupTheme",
-          "actionOverflowButtonStyle",
-          "spinnerStyle",
-          "popupMenuStyle",
-          "colorPrimaryDark",
-          "drawerArrowStyle",
-          "actionBarWidgetTheme",
-          "alpha",
-          "actionBarTabStyle",
-          "imageButtonStyle",
-          "colorControlActivated",
-          "toolbarStyle",
-          "homeAsUpIndicator",
-          "toolbarNavigationButtonStyle",
-          "colorPrimary",
-          "actionBarTheme",
-          "actionOverflowMenuStyle",
-          "dropDownListViewStyle",
-          "actionModePopupWindowStyle",
-          "actionModeShareDrawable",
-          "dialogTheme",
-          "alertDialogTheme",
-          "searchViewStyle",
-          "colorSwitchThumbNormal",
-          "actionBarTabBarStyle",
-          "textColorSearchUrl",
-          "switchStyle",
-          "autoCompleteTextViewStyle"
-        ]
-      },
-      "android/support/v7/widget/StaggeredGridLayoutManager$Span": {
-        "androidx/widget/StaggeredGridLayoutManager$Span": [
-          "INVALID_LINE"
-        ]
-      },
-      "android/support/v4/app/NotificationManagerCompat": {
-        "androidx/app/NotificationManagerCompat": [
-          "OP_POST_NOTIFICATION",
-          "sEnabledNotificationListeners",
-          "IMPORTANCE_HIGH",
-          "SIDE_CHANNEL_RETRY_MAX_COUNT",
-          "TAG",
-          "SETTING_ENABLED_NOTIFICATION_LISTENERS",
-          "sSideChannelManager",
-          "sLock",
-          "IMPORTANCE_DEFAULT",
-          "SIDE_CHANNEL_RETRY_BASE_INTERVAL_MS",
-          "EXTRA_USE_SIDE_CHANNEL",
-          "IMPORTANCE_NONE",
-          "sEnabledNotificationListenersLock",
-          "ACTION_BIND_SIDE_CHANNEL",
-          "CHECK_OP_NO_THROW",
-          "sEnabledNotificationListenerPackages",
-          "IMPORTANCE_LOW",
-          "IMPORTANCE_MAX",
-          "MAX_SIDE_CHANNEL_SDK_VERSION",
-          "IMPORTANCE_MIN",
-          "IMPORTANCE_UNSPECIFIED"
-        ]
-      },
-      "android/support/v4/util/LruCache": {
-        "androidx/util/LruCache": [
-          "map",
-          "hitCount",
-          "missCount",
-          "maxSize",
-          "putCount",
-          "createCount",
-          "evictionCount",
-          "size"
-        ]
-      },
-      "android/support/v4/content/FileProvider": {
-        "androidx/content/FileProvider": [
-          "META_DATA_FILE_PROVIDER_PATHS",
-          "TAG_EXTERNAL_CACHE",
-          "TAG_FILES_PATH",
-          "TAG_EXTERNAL_FILES",
-          "ATTR_PATH",
-          "ATTR_NAME",
-          "DEVICE_ROOT",
-          "sCache",
-          "COLUMNS",
-          "TAG_EXTERNAL",
-          "TAG_ROOT_PATH",
-          "TAG_CACHE_PATH"
-        ]
-      },
-      "android/support/v4/media/AudioAttributesCompat": {
-        "androidx/media/AudioAttributesCompat": [
-          "FLAG_LOW_LATENCY",
-          "FLAG_DEEP_BUFFER",
-          "USAGE_NOTIFICATION",
-          "SUPPRESSIBLE_USAGES",
-          "SUPPRESSIBLE_CALL",
-          "USAGE_NOTIFICATION_COMMUNICATION_INSTANT",
-          "USAGE_NOTIFICATION_RINGTONE",
-          "USAGE_NOTIFICATION_EVENT",
-          "USAGE_VIRTUAL_SOURCE",
-          "FLAG_BYPASS_MUTE",
-          "USAGE_ASSISTANCE_SONIFICATION",
-          "CONTENT_TYPE_SPEECH",
-          "FLAG_BYPASS_INTERRUPTION_POLICY",
-          "SDK_USAGES",
-          "USAGE_GAME",
-          "USAGE_UNKNOWN",
-          "USAGE_NOTIFICATION_COMMUNICATION_DELAYED",
-          "FLAG_ALL_PUBLIC",
-          "FLAG_SCO",
-          "FLAG_SECURE",
-          "FLAG_ALL",
-          "USAGE_VOICE_COMMUNICATION",
-          "USAGE_VOICE_COMMUNICATION_SIGNALLING",
-          "USAGE_MEDIA",
-          "USAGE_ALARM",
-          "CONTENT_TYPE_MOVIE",
-          "TAG",
-          "FLAG_HW_AV_SYNC",
-          "sForceLegacyBehavior",
-          "USAGE_ASSISTANCE_NAVIGATION_GUIDANCE",
-          "FLAG_BEACON",
-          "CONTENT_TYPE_UNKNOWN",
-          "USAGE_ASSISTANT",
-          "FLAG_AUDIBILITY_ENFORCED",
-          "FLAG_HW_HOTWORD",
-          "USAGE_NOTIFICATION_COMMUNICATION_REQUEST",
-          "USAGE_ASSISTANCE_ACCESSIBILITY",
-          "CONTENT_TYPE_MUSIC",
-          "SUPPRESSIBLE_NOTIFICATION",
-          "CONTENT_TYPE_SONIFICATION"
-        ]
-      },
-      "android/support/v7/mediarouter/R$id": {
-        "androidx/mediarouter/R$id": [
-          "mr_custom_control",
-          "mr_art",
-          "mr_name",
-          "mr_control_subtitle",
-          "mr_control_title",
-          "mr_control_playback_ctrl",
-          "mr_chooser_title",
-          "mr_group_expand_collapse",
-          "mr_close",
-          "mr_chooser_list",
-          "mr_volume_group_list",
-          "mr_expandable_area",
-          "mr_chooser_route_desc",
-          "mr_chooser_route_icon",
-          "mr_control_divider",
-          "volume_item_container",
-          "mr_chooser_route_name",
-          "mr_volume_control",
-          "mr_dialog_area",
-          "mr_default_control",
-          "mr_volume_slider",
-          "mr_volume_item_icon",
-          "mr_media_main_control",
-          "mr_playback_control",
-          "mr_control_title_container"
-        ]
-      },
-      "android/support/text/emoji/flatbuffer/Table": {
-        "androidx/text/emoji/flatbuffer/Table": [
-          "UTF8_CHARSET",
-          "bb",
-          "bb_pos",
-          "UTF8_DECODER",
-          "CHAR_BUFFER"
-        ]
-      },
-      "android/support/v17/leanback/R$id": {
-        "androidx/leanback/R$id": [
-          "paused",
-          "content_container",
-          "guidedactions_item_title",
-          "container_list",
-          "lb_parallax_source",
-          "description_dock",
-          "guidedactions_list",
-          "browse_grid_dock",
-          "details_overview_image",
-          "scale_frame",
-          "details_overview_right_panel",
-          "playback_progress",
-          "guidedactions_sub_list_background",
-          "guidedactions_root2",
-          "mediaItemDetails",
-          "button_start",
-          "title_badge",
-          "lb_search_text_editor",
-          "bottom_spacer",
-          "lb_slide_transition_value",
-          "info_field",
-          "mediaItemActionsContainer",
-          "thumbs_row",
-          "controls_container",
-          "guidedactions_list_background2",
-          "guidedactions_item_content",
-          "lb_action_button",
-          "guidedactions_item_icon",
-          "guidedactions_item_checkmark",
-          "lb_control_closed_captioning",
-          "browse_grid",
-          "title_orb",
-          "details_root",
-          "guidedactions_list_background",
-          "total_time",
-          "controls_card",
-          "lb_control_more_actions",
-          "lb_control_shuffle",
-          "mediaRowSeparator",
-          "image",
-          "lb_control_fast_rewind",
-          "row_header",
-          "controls_card_right_panel",
-          "description",
-          "background_imagein",
-          "title_text",
-          "details_fragment_root",
-          "playback_fragment_background",
-          "browse_frame",
-          "title",
-          "current_time",
-          "browse_headers_dock",
-          "guidedactions_sub_list",
-          "details_overview_actions_background",
-          "background_imageout",
-          "guidedactions_item_chevron",
-          "mediaItemDuration",
-          "lb_control_skip_previous",
-          "browse_container_dock",
-          "lb_control_skip_next",
-          "mediaListHeader",
-          "main_image",
-          "lb_control_thumbs_down",
-          "mediaItemNumberViewFlipper",
-          "details_overview",
-          "actionIcon",
-          "guidedactions_item_description",
-          "guidance_container",
-          "guidedstep_background",
-          "guidedactions_activator_item",
-          "transport_row",
-          "playback_controls_dock",
-          "page_container",
-          "lb_shadow_focused",
-          "icon",
-          "guidedactions_content",
-          "playing",
-          "lb_control_high_quality",
-          "guidance_description",
-          "details_frame",
-          "guidance_icon",
-          "control_bar",
-          "page_indicator",
-          "lb_search_bar_speech_orb",
-          "details_rows_dock",
-          "row_header_description",
-          "lb_control_thumbs_up",
-          "secondary_controls_dock",
-          "button",
-          "lb_shadow_impl",
-          "lb_focus_animator",
-          "spacer",
-          "lb_search_bar_badge",
-          "initial",
-          "lb_control_repeat",
-          "guidedactions_content2",
-          "guidance_title",
-          "message",
-          "action_fragment_root",
-          "lb_shadow_normal",
-          "guidedactions_root",
-          "lb_details_description_title",
-          "guidance_breadcrumb",
-          "action_fragment",
-          "background_container",
-          "lb_row_container_header_dock",
-          "details_background_view",
-          "browse_title_group",
-          "main_icon",
-          "video_surface_container",
-          "lb_search_frame",
-          "picker",
-          "lb_control_play_pause",
-          "lb_details_description_body",
-          "controls_dock",
-          "lb_control_picture_in_picture",
-          "lb_results_frame",
-          "grid_frame",
-          "lb_control_fast_forward",
-          "details_overview_description",
-          "mediaItemRow",
-          "mediaItemName",
-          "content_fragment",
-          "details_overview_actions",
-          "more_actions_dock",
-          "fade_out_edge",
-          "label",
-          "action_fragment_background",
-          "browse_headers",
-          "foreground_container",
-          "transitionPosition",
-          "lb_search_bar",
-          "error_frame",
-          "guidedactions_list2",
-          "lb_details_description_subtitle",
-          "lb_search_bar_items",
-          "mediaRowSelector",
-          "bar3",
-          "bar2",
-          "bar1",
-          "logo",
-          "search_orb",
-          "row_content",
-          "guidedstep_background_view_root"
-        ]
-      },
-      "android/support/v17/leanback/widget/picker/Picker$ViewHolder": {
-        "androidx/leanback/widget/picker/Picker$ViewHolder": [
-          "textView",
-          "itemView"
-        ]
-      },
-      "android/support/v4/media/MediaMetadataCompat": {
-        "androidx/media/MediaMetadataCompat": [
-          "METADATA_KEY_COMPILATION",
-          "METADATA_KEY_ART",
-          "METADATA_KEY_NUM_TRACKS",
-          "METADATA_KEY_ALBUM",
-          "METADATA_TYPE_TEXT",
-          "METADATA_TYPE_LONG",
-          "METADATA_KEY_TRACK_NUMBER",
-          "METADATA_KEY_ARTIST",
-          "METADATA_KEY_DOWNLOAD_STATUS",
-          "METADATA_KEY_AUTHOR",
-          "METADATA_KEY_DATE",
-          "METADATA_KEY_DISPLAY_TITLE",
-          "METADATA_KEY_DISPLAY_DESCRIPTION",
-          "METADATA_KEY_DURATION",
-          "METADATA_KEY_YEAR",
-          "METADATA_TYPE_BITMAP",
-          "METADATA_KEY_USER_RATING",
-          "METADATA_KEY_ALBUM_ART_URI",
-          "METADATA_KEY_MEDIA_URI",
-          "METADATA_KEY_MEDIA_ID",
-          "PREFERRED_BITMAP_ORDER",
-          "CREATOR",
-          "METADATA_KEY_BT_FOLDER_TYPE",
-          "METADATA_KEY_TITLE",
-          "METADATA_KEY_DISPLAY_ICON_URI",
-          "PREFERRED_URI_ORDER",
-          "METADATA_TYPE_RATING",
-          "METADATA_KEY_WRITER",
-          "PREFERRED_DESCRIPTION_ORDER",
-          "TAG",
-          "METADATA_KEY_COMPOSER",
-          "METADATA_KEY_ALBUM_ART",
-          "METADATA_KEY_GENRE",
-          "METADATA_KEY_ART_URI",
-          "METADATA_KEY_DISPLAY_ICON",
-          "METADATA_KEY_ALBUM_ARTIST",
-          "METADATA_KEY_ADVERTISEMENT",
-          "METADATA_KEYS_TYPE",
-          "METADATA_KEY_RATING",
-          "METADATA_KEY_DISPLAY_SUBTITLE",
-          "METADATA_KEY_DISC_NUMBER"
-        ]
-      },
-      "android/support/transition/Fade": {
-        "androidx/transition/Fade": [
-          "PROPNAME_TRANSITION_ALPHA",
-          "IN",
-          "LOG_TAG",
-          "OUT"
-        ]
-      },
-      "android/support/v17/leanback/R$layout": {
-        "androidx/leanback/R$layout": [
-          "lb_rows_fragment",
-          "lb_video_surface",
-          "lb_headers_fragment",
-          "lb_image_card_view_themed_badge_left",
-          "lb_search_orb",
-          "lb_details_fragment",
-          "lb_guidedstep_fragment",
-          "lb_image_card_view",
-          "lb_details_overview",
-          "lb_playback_controls",
-          "lb_guidedactions_datepicker_item",
-          "lb_image_card_view_themed_title",
-          "lb_picker_column",
-          "lb_playback_transport_controls_row",
-          "lb_image_card_view_themed_badge_right",
-          "lb_row_media_item",
-          "lb_row_container",
-          "lb_search_bar",
-          "lb_shadow",
-          "lb_error_fragment",
-          "lb_guidedbuttonactions",
-          "lb_browse_fragment",
-          "lb_guidedactions_item",
-          "lb_browse_title",
-          "lb_list_row",
-          "lb_section_header",
-          "lb_image_card_view_themed_content",
-          "lb_action_1_line",
-          "lb_media_list_header",
-          "lb_media_item_number_view_flipper",
-          "lb_vertical_grid_fragment",
-          "lb_divider",
-          "lb_details_description",
-          "lb_playback_now_playing_bars",
-          "lb_row_media_item_action",
-          "lb_fullwidth_details_overview",
-          "lb_picker",
-          "lb_guidedstep_background",
-          "lb_guidance",
-          "lb_picker_item",
-          "lb_speech_orb",
-          "lb_vertical_grid",
-          "lb_control_button_primary",
-          "lb_search_fragment",
-          "lb_playback_fragment",
-          "lb_picker_separator",
-          "lb_onboarding_fragment",
-          "lb_playback_controls_row",
-          "lb_row_header",
-          "lb_list_row_hovercard",
-          "lb_control_bar",
-          "lb_header",
-          "lb_guidedactions",
-          "lb_action_2_lines",
-          "lb_control_button_secondary",
-          "lb_title_view",
-          "lb_fullwidth_details_overview_logo"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat": {
-        "androidx/app/NotificationCompat": [
-          "EXTRA_BACKGROUND_IMAGE_URI",
-          "FLAG_FOREGROUND_SERVICE",
-          "CATEGORY_SYSTEM",
-          "EXTRA_REMOTE_INPUT_HISTORY",
-          "EXTRA_LARGE_ICON",
-          "EXTRA_SHOW_WHEN",
-          "EXTRA_COMPACT_ACTIONS",
-          "CATEGORY_ERROR",
-          "GROUP_ALERT_CHILDREN",
-          "BADGE_ICON_LARGE",
-          "PRIORITY_DEFAULT",
-          "EXTRA_PEOPLE",
-          "STREAM_DEFAULT",
-          "VISIBILITY_PRIVATE",
-          "FLAG_ONLY_ALERT_ONCE",
-          "CATEGORY_EMAIL",
-          "DEFAULT_VIBRATE",
-          "CATEGORY_PROGRESS",
-          "FLAG_ONGOING_EVENT",
-          "EXTRA_PROGRESS_MAX",
-          "EXTRA_TITLE",
-          "CATEGORY_PROMO",
-          "EXTRA_SELF_DISPLAY_NAME",
-          "VISIBILITY_SECRET",
-          "PRIORITY_LOW",
-          "EXTRA_LARGE_ICON_BIG",
-          "CATEGORY_TRANSPORT",
-          "DEFAULT_SOUND",
-          "CATEGORY_CALL",
-          "EXTRA_SMALL_ICON",
-          "CATEGORY_RECOMMENDATION",
-          "EXTRA_PROGRESS",
-          "PRIORITY_HIGH",
-          "EXTRA_CONVERSATION_TITLE",
-          "GROUP_ALERT_SUMMARY",
-          "EXTRA_INFO_TEXT",
-          "BADGE_ICON_NONE",
-          "EXTRA_BIG_TEXT",
-          "EXTRA_TEXT_LINES",
-          "EXTRA_PICTURE",
-          "PRIORITY_MIN",
-          "FLAG_HIGH_PRIORITY",
-          "COLOR_DEFAULT",
-          "PRIORITY_MAX",
-          "EXTRA_TEMPLATE",
-          "FLAG_LOCAL_ONLY",
-          "CATEGORY_ALARM",
-          "EXTRA_SUMMARY_TEXT",
-          "BADGE_ICON_SMALL",
-          "DEFAULT_ALL",
-          "CATEGORY_STATUS",
-          "CATEGORY_EVENT",
-          "GROUP_ALERT_ALL",
-          "EXTRA_SHOW_CHRONOMETER",
-          "DEFAULT_LIGHTS",
-          "VISIBILITY_PUBLIC",
-          "CATEGORY_SOCIAL",
-          "CATEGORY_MESSAGE",
-          "FLAG_INSISTENT",
-          "CATEGORY_REMINDER",
-          "EXTRA_AUDIO_CONTENTS_URI",
-          "CATEGORY_SERVICE",
-          "EXTRA_TITLE_BIG",
-          "FLAG_AUTO_CANCEL",
-          "EXTRA_MEDIA_SESSION",
-          "EXTRA_MESSAGES",
-          "EXTRA_TEXT",
-          "FLAG_SHOW_LIGHTS",
-          "FLAG_GROUP_SUMMARY",
-          "FLAG_NO_CLEAR",
-          "EXTRA_SUB_TEXT",
-          "EXTRA_PROGRESS_INDETERMINATE"
-        ]
-      },
-      "android/support/animation/AnimationHandler": {
-        "androidx/animation/AnimationHandler": [
-          "sAnimatorHandler",
-          "FRAME_DELAY_MS"
-        ]
-      },
-      "android/support/media/ExifInterface": {
-        "androidx/media/ExifInterface": [
-          "FLAG_FLASH_RED_EYE_SUPPORTED",
-          "sTagSetForCompatibility",
-          "TAG_CUSTOM_RENDERED",
-          "TAG_SENSITIVITY_TYPE",
-          "GAIN_CONTROL_HIGH_GAIN_UP",
-          "TAG_FOCAL_PLANE_Y_RESOLUTION",
-          "LIGHT_SOURCE_OTHER",
-          "TAG_GPS_TIMESTAMP",
-          "TAG_COMPRESSION",
-          "IFD_INTEROPERABILITY_TAGS",
-          "IFD_FORMAT_DOUBLE",
-          "TAG_PIXEL_Y_DIMENSION",
-          "TAG_GPS_IMG_DIRECTION_REF",
-          "JPEG_INTERCHANGE_FORMAT_LENGTH_TAG",
-          "FLIPPED_ROTATION_ORDER",
-          "LIGHT_SOURCE_WARM_WHITE_FLUORESCENT",
-          "LIGHT_SOURCE_UNKNOWN",
-          "WHITE_BALANCE_MANUAL",
-          "TAG_SUBSEC_TIME",
-          "FILE_SOURCE_DSC",
-          "IFD_FORMAT_SSHORT",
-          "MARKER",
-          "LONGITUDE_WEST",
-          "IMAGE_TYPE_UNKNOWN",
-          "METERING_MODE_SPOT",
-          "IMAGE_TYPE_CR2",
-          "TAG_GPS_DOP",
-          "MAX_THUMBNAIL_SIZE",
-          "SENSOR_TYPE_TWO_CHIP",
-          "TAG_GPS_TRACK",
-          "SENSITIVITY_TYPE_REI_AND_ISO",
-          "SENSOR_TYPE_ONE_CHIP",
-          "GPS_MEASUREMENT_NO_DIFFERENTIAL",
-          "ORIENTATION_ROTATE_90",
-          "TAG_WHITE_POINT",
-          "PEF_SIGNATURE",
-          "TAG_GPS_IMG_DIRECTION",
-          "ORIGINAL_RESOLUTION_IMAGE",
-          "METERING_MODE_CENTER_WEIGHT_AVERAGE",
-          "TAG_ORF_CAMERA_SETTINGS_IFD_POINTER",
-          "TAG_ISO_SPEED",
-          "IMAGE_TYPE_DNG",
-          "GAIN_CONTROL_NONE",
-          "LONGITUDE_EAST",
-          "IFD_TYPE_ORF_MAKER_NOTE",
-          "TAG_DEVICE_SETTING_DESCRIPTION",
-          "TAG_BRIGHTNESS_VALUE",
-          "TAG_GPS_MAP_DATUM",
-          "METERING_MODE_MULTI_SPOT",
-          "TAG_RW2_ISO",
-          "TAG_ORF_PREVIEW_IMAGE_START",
-          "LIGHT_SOURCE_FLUORESCENT",
-          "COLOR_SPACE_S_RGB",
-          "IMAGE_TYPE_SRW",
-          "FLAG_FLASH_RETURN_LIGHT_DETECTED",
-          "SUBJECT_DISTANCE_RANGE_DISTANT_VIEW",
-          "TAG_ISO_SPEED_LATITUDE_YYY",
-          "RAF_INFO_SIZE",
-          "TAG",
-          "ORIENTATION_NORMAL",
-          "TAG_SUB_IFD_POINTER",
-          "LIGHT_SOURCE_TUNGSTEN",
-          "RESOLUTION_UNIT_CENTIMETERS",
-          "ALTITUDE_ABOVE_SEA_LEVEL",
-          "BYTE_ALIGN_MM",
-          "METERING_MODE_OTHER",
-          "TAG_EXIF_IFD_POINTER",
-          "BYTE_ALIGN_II",
-          "TAG_GPS_TRACK_REF",
-          "SHARPNESS_NORMAL",
-          "FILE_SOURCE_OTHER",
-          "TAG_OECF",
-          "SENSOR_TYPE_COLOR_SEQUENTIAL",
-          "sFormatter",
-          "FLAG_FLASH_MODE_COMPULSORY_FIRING",
-          "GPS_SPEED_KNOTS",
-          "DATA_DEFLATE_ZIP",
-          "TAG_DNG_VERSION",
-          "IMAGE_TYPE_ARW",
-          "TAG_RELATED_SOUND_FILE",
-          "TAG_BODY_SERIAL_NUMBER",
-          "EXPOSURE_PROGRAM_NOT_DEFINED",
-          "SIGNATURE_CHECK_SIZE",
-          "JPEG_INTERCHANGE_FORMAT_TAG",
-          "TAG_RW2_SENSOR_RIGHT_BORDER",
-          "TAG_CAMARA_OWNER_NAME",
-          "TAG_SPATIAL_FREQUENCY_RESPONSE",
-          "COLOR_SPACE_UNCALIBRATED",
-          "EXPOSURE_PROGRAM_NORMAL",
-          "EXPOSURE_PROGRAM_SHUTTER_PRIORITY",
-          "TAG_THUMBNAIL_LENGTH",
-          "TAG_TRANSFER_FUNCTION",
-          "IMAGE_TYPE_RW2",
-          "TAG_RW2_SENSOR_LEFT_BORDER",
-          "TAG_CFA_PATTERN",
-          "TAG_THUMBNAIL_IMAGE_LENGTH",
-          "TAG_GPS_H_POSITIONING_ERROR",
-          "sGpsTimestampPattern",
-          "PEF_MAKER_NOTE_SKIP_SIZE",
-          "IFD_FORMAT_STRING",
-          "TAG_SUBJECT_DISTANCE",
-          "TAG_GPS_SPEED_REF",
-          "SENSITIVITY_TYPE_SOS_AND_REI_AND_ISO",
-          "TAG_ORIENTATION",
-          "TAG_PHOTOMETRIC_INTERPRETATION",
-          "LIGHT_SOURCE_DAYLIGHT",
-          "TAG_MODEL",
-          "IFD_TYPE_GPS",
-          "LIGHT_SOURCE_SHADE",
-          "Y_CB_CR_POSITIONING_CO_SITED",
-          "TAG_RAF_IMAGE_SIZE",
-          "IFD_FORMAT_BYTES_PER_FORMAT",
-          "SENSITIVITY_TYPE_SOS_AND_REI",
-          "TAG_Y_RESOLUTION",
-          "TAG_GPS_DIFFERENTIAL",
-          "EXPOSURE_MODE_AUTO",
-          "MARKER_SOS",
-          "MARKER_SOI",
-          "IFD_TYPE_PREVIEW",
-          "IMAGE_TYPE_RAF",
-          "IFD_FORMAT_SBYTE",
-          "ORIENTATION_FLIP_VERTICAL",
-          "TAG_LENS_SERIAL_NUMBER",
-          "TAG_FLASHPIX_VERSION",
-          "EXIF_ASCII_PREFIX",
-          "IFD_TYPE_ORF_IMAGE_PROCESSING",
-          "TAG_ORF_IMAGE_PROCESSING_IFD_POINTER",
-          "DATA_LOSSY_JPEG",
-          "TAG_GPS_SPEED",
-          "TAG_USER_COMMENT",
-          "TAG_SUBSEC_TIME_ORIGINAL",
-          "TAG_THUMBNAIL_IMAGE_WIDTH",
-          "IFD_FORMAT_UNDEFINED",
-          "RW2_SIGNATURE",
-          "ORF_MAKER_NOTE_HEADER_2",
-          "ORF_MAKER_NOTE_HEADER_1",
-          "TAG_WHITE_BALANCE",
-          "TAG_ISO_SPEED_LATITUDE_ZZZ",
-          "TAG_PHOTOGRAPHIC_SENSITIVITY",
-          "SCENE_CAPTURE_TYPE_LANDSCAPE",
-          "MARKER_COM",
-          "TAG_HAS_THUMBNAIL",
-          "TAG_EXPOSURE_TIME",
-          "TAG_GPS_SATELLITES",
-          "TAG_COLOR_SPACE",
-          "TAG_GPS_LATITUDE_REF",
-          "IMAGE_TYPE_JPEG",
-          "START_CODE",
-          "TAG_APERTURE_VALUE",
-          "TAG_BITS_PER_SAMPLE",
-          "TAG_DIGITAL_ZOOM_RATIO",
-          "METERING_MODE_PATTERN",
-          "TAG_SHUTTER_SPEED_VALUE",
-          "DATA_PACK_BITS_COMPRESSED",
-          "sExifPointerTagMap",
-          "EXPOSURE_PROGRAM_APERTURE_PRIORITY",
-          "TAG_SAMPLES_PER_PIXEL",
-          "TAG_FILE_SOURCE",
-          "LIGHT_SOURCE_DAY_WHITE_FLUORESCENT",
-          "IFD_EXIF_TAGS",
-          "TAG_GPS_INFO_IFD_POINTER",
-          "TAG_GAMMA",
-          "IMAGE_TYPE_ORF",
-          "TAG_GAIN_CONTROL",
-          "IFD_TYPE_EXIF",
-          "TAG_SUBJECT_AREA",
-          "FORMAT_CHUNKY",
-          "ASCII",
-          "ORF_IMAGE_PROCESSING_TAGS",
-          "TAG_ORF_THUMBNAIL_IMAGE",
-          "IMAGE_TYPE_PEF",
-          "IFD_TYPE_ORF_CAMERA_SETTINGS",
-          "EXPOSURE_MODE_MANUAL",
-          "TAG_GPS_DATESTAMP",
-          "IFD_FORMAT_SRATIONAL",
-          "TAG_SUBJECT_LOCATION",
-          "FILE_SOURCE_REFLEX_SCANNER",
-          "TAG_LENS_SPECIFICATION",
-          "LIGHT_SOURCE_DAYLIGHT_FLUORESCENT",
-          "TAG_COMPONENTS_CONFIGURATION",
-          "TAG_REFERENCE_BLACK_WHITE",
-          "IMAGE_TYPE_NEF",
-          "GAIN_CONTROL_HIGH_GAIN_DOWN",
-          "LIGHT_SOURCE_ISO_STUDIO_TUNGSTEN",
-          "ORIENTATION_TRANSVERSE",
-          "IFD_FORMAT_URATIONAL",
-          "EXPOSURE_PROGRAM_LANDSCAPE_MODE",
-          "IMAGE_TYPE_NRW",
-          "TAG_FLASH",
-          "RAF_SIGNATURE",
-          "EXPOSURE_PROGRAM_ACTION",
-          "TAG_PLANAR_CONFIGURATION",
-          "LIGHT_SOURCE_CLOUDY_WEATHER",
-          "FLAG_FLASH_FIRED",
-          "EXPOSURE_MODE_AUTO_BRACKET",
-          "ORIENTATION_TRANSPOSE",
-          "REDUCED_RESOLUTION_IMAGE",
-          "WHITE_BALANCE_AUTO",
-          "TAG_FOCAL_PLANE_RESOLUTION_UNIT",
-          "PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO",
-          "DATA_UNCOMPRESSED",
-          "MARKER_EOI",
-          "TAG_SUBSEC_TIME_DIGITIZED",
-          "TAG_THUMBNAIL_DATA",
-          "TAG_GPS_DEST_BEARING_REF",
-          "EXPOSURE_PROGRAM_PORTRAIT_MODE",
-          "TAG_GPS_ALTITUDE",
-          "DATA_JPEG",
-          "TAG_GPS_DEST_LATITUDE_REF",
-          "ALTITUDE_BELOW_SEA_LEVEL",
-          "TAG_F_NUMBER",
-          "SUBJECT_DISTANCE_RANGE_UNKNOWN",
-          "TAG_SPECTRAL_SENSITIVITY",
-          "SCENE_CAPTURE_TYPE_NIGHT",
-          "TAG_PIXEL_X_DIMENSION",
-          "TAG_DEFAULT_CROP_SIZE",
-          "LIGHT_SOURCE_D75",
-          "LIGHT_SOURCE_D65",
-          "GPS_MEASUREMENT_INTERRUPTED",
-          "TAG_GPS_DEST_DISTANCE",
-          "LIGHT_SOURCE_D50",
-          "LIGHT_SOURCE_D55",
-          "ORIENTATION_ROTATE_180",
-          "SATURATION_NORMAL",
-          "TAG_THUMBNAIL_OFFSET",
-          "RESOLUTION_UNIT_INCHES",
-          "ORF_CAMERA_SETTINGS_TAGS",
-          "IFD_FORMAT_BYTE",
-          "TAG_LENS_MAKE",
-          "JPEG_SIGNATURE",
-          "EXPOSURE_PROGRAM_MANUAL",
-          "EXPOSURE_PROGRAM_CREATIVE",
-          "SUBJECT_DISTANCE_RANGE_CLOSE_VIEW",
-          "TAG_MAX_APERTURE_VALUE",
-          "DEBUG",
-          "METERING_MODE_AVERAGE",
-          "RENDERED_PROCESS_NORMAL",
-          "LIGHT_SOURCE_STANDARD_LIGHT_B",
-          "LIGHT_SOURCE_STANDARD_LIGHT_C",
-          "LIGHT_SOURCE_STANDARD_LIGHT_A",
-          "TAG_ISO_SPEED_RATINGS",
-          "TAG_STANDARD_OUTPUT_SENSITIVITY",
-          "PHOTOMETRIC_INTERPRETATION_YCBCR",
-          "TAG_ARTIST",
-          "IFD_TYPE_THUMBNAIL",
-          "PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO",
-          "FLAG_FLASH_RETURN_LIGHT_NOT_DETECTED",
-          "TAG_FOCAL_PLANE_X_RESOLUTION",
-          "TAG_LIGHT_SOURCE",
-          "MARKER_SOF1",
-          "MARKER_SOF2",
-          "MARKER_SOF0",
-          "MARKER_SOF9",
-          "MARKER_SOF7",
-          "MARKER_SOF5",
-          "MARKER_SOF6",
-          "MARKER_SOF3",
-          "sExifTagMapsForWriting",
-          "SHARPNESS_SOFT",
-          "TAG_SCENE_TYPE",
-          "TAG_GPS_DEST_LONGITUDE",
-          "sNonZeroTimePattern",
-          "GPS_DIRECTION_MAGNETIC",
-          "EXIF_TAGS",
-          "TAG_GPS_AREA_INFORMATION",
-          "FLAG_FLASH_MODE_COMPULSORY_SUPPRESSION",
-          "IFD_THUMBNAIL_TAGS",
-          "IFD_FORMAT_ULONG",
-          "TAG_INTEROPERABILITY_IFD_POINTER",
-          "TAG_SUBFILE_TYPE",
-          "TAG_RW2_SENSOR_TOP_BORDER",
-          "TAG_INTEROPERABILITY_INDEX",
-          "GPS_MEASUREMENT_3D",
-          "GPS_DIRECTION_TRUE",
-          "GPS_MEASUREMENT_2D",
-          "sExifTagMapsForReading",
-          "TAG_JPEG_INTERCHANGE_FORMAT",
-          "LATITUDE_SOUTH",
-          "PHOTOMETRIC_INTERPRETATION_RGB",
-          "BITS_PER_SAMPLE_RGB",
-          "CONTRAST_HARD",
-          "SHARPNESS_HARD",
-          "LATITUDE_NORTH",
-          "TAG_CONTRAST",
-          "ORIENTATION_FLIP_HORIZONTAL",
-          "TAG_GPS_LONGITUDE",
-          "TAG_COMPRESSED_BITS_PER_PIXEL",
-          "TAG_METERING_MODE",
-          "BITS_PER_SAMPLE_GREYSCALE_1",
-          "BITS_PER_SAMPLE_GREYSCALE_2",
-          "TAG_ROWS_PER_STRIP",
-          "GPS_DISTANCE_MILES",
-          "TAG_MAKER_NOTE",
-          "SUBJECT_DISTANCE_RANGE_MACRO",
-          "GAIN_CONTROL_LOW_GAIN_DOWN",
-          "SATURATION_HIGH",
-          "SCENE_TYPE_DIRECTLY_PHOTOGRAPHED",
-          "LIGHT_SOURCE_WHITE_FLUORESCENT",
-          "TAG_SHARPNESS",
-          "GPS_DISTANCE_KILOMETERS",
-          "TAG_GPS_LATITUDE",
-          "TAG_RW2_SENSOR_BOTTOM_BORDER",
-          "WHITEBALANCE_AUTO",
-          "TAG_SCENE_CAPTURE_TYPE",
-          "TAG_STRIP_BYTE_COUNTS",
-          "TAG_GPS_LONGITUDE_REF",
-          "GPS_MEASUREMENT_IN_PROGRESS",
-          "ORIENTATION_UNDEFINED",
-          "RAF_OFFSET_TO_JPEG_IMAGE_OFFSET",
-          "TAG_SUBJECT_DISTANCE_RANGE",
-          "ROTATION_ORDER",
-          "TAG_GPS_STATUS",
-          "ORF_MAKER_NOTE_HEADER_1_SIZE",
-          "TAG_GPS_DEST_BEARING",
-          "TAG_Y_CB_CR_COEFFICIENTS",
-          "TAG_MAKE",
-          "IFD_TYPE_PEF",
-          "TAG_RESOLUTION_UNIT",
-          "TAG_IMAGE_DESCRIPTION",
-          "SENSOR_TYPE_NOT_DEFINED",
-          "ORF_MAKER_NOTE_HEADER_2_SIZE",
-          "IFD_FORMAT_IFD",
-          "TAG_SATURATION",
-          "TAG_FOCAL_LENGTH_IN_35MM_FILM",
-          "TAG_FOCAL_LENGTH",
-          "SENSITIVITY_TYPE_SOS_AND_ISO",
-          "TAG_EXIF_VERSION",
-          "TAG_ORF_PREVIEW_IMAGE_LENGTH",
-          "GPS_MEASUREMENT_DIFFERENTIAL_CORRECTED",
-          "IFD_FORMAT_SINGLE",
-          "CONTRAST_NORMAL",
-          "TAG_PRIMARY_CHROMATICITIES",
-          "TAG_LENS_MODEL",
-          "TAG_IMAGE_LENGTH",
-          "TAG_RW2_JPG_FROM_RAW",
-          "SATURATION_LOW",
-          "TAG_SOFTWARE",
-          "IFD_TIFF_TAGS",
-          "SENSITIVITY_TYPE_ISO_SPEED",
-          "TAG_GPS_PROCESSING_METHOD",
-          "TAG_X_RESOLUTION",
-          "LIGHT_SOURCE_COOL_WHITE_FLUORESCENT",
-          "DATA_HUFFMAN_COMPRESSED",
-          "SENSOR_TYPE_THREE_CHIP",
-          "TAG_IMAGE_WIDTH",
-          "METERING_MODE_PARTIAL",
-          "SENSOR_TYPE_COLOR_SEQUENTIAL_LINEAR",
-          "LIGHT_SOURCE_FINE_WEATHER",
-          "TAG_EXPOSURE_INDEX",
-          "TAG_STRIP_OFFSETS",
-          "TAG_EXPOSURE_PROGRAM",
-          "TAG_IMAGE_UNIQUE_ID",
-          "IFD_FORMAT_USHORT",
-          "TAG_GPS_VERSION_ID",
-          "CONTRAST_SOFT",
-          "TAG_DATETIME_DIGITIZED",
-          "EXIF_POINTER_TAGS",
-          "FLAG_FLASH_NO_FLASH_FUNCTION",
-          "IFD_FORMAT_NAMES",
-          "ORF_MAKER_NOTE_TAGS",
-          "TAG_EXPOSURE_BIAS_VALUE",
-          "TAG_GPS_DEST_LONGITUDE_REF",
-          "IFD_OFFSET",
-          "ORF_SIGNATURE_1",
-          "ORF_SIGNATURE_2",
-          "METERING_MODE_UNKNOWN",
-          "GPS_SPEED_KILOMETERS_PER_HOUR",
-          "FORMAT_PLANAR",
-          "MARKER_SOF10",
-          "MARKER_SOF11",
-          "MARKER_SOF13",
-          "MARKER_SOF14",
-          "MARKER_SOF15",
-          "IFD_FORMAT_SLONG",
-          "TAG_COPYRIGHT",
-          "TAG_GPS_DEST_DISTANCE_REF",
-          "TAG_GPS_MEASURE_MODE",
-          "Y_CB_CR_POSITIONING_CENTERED",
-          "TAG_Y_CB_CR_POSITIONING",
-          "GPS_DISTANCE_NAUTICAL_MILES",
-          "WHITEBALANCE_MANUAL",
-          "GAIN_CONTROL_LOW_GAIN_UP",
-          "IDENTIFIER_EXIF_APP1",
-          "DATA_JPEG_COMPRESSED",
-          "SCENE_CAPTURE_TYPE_PORTRAIT",
-          "GPS_SPEED_MILES_PER_HOUR",
-          "IFD_TYPE_PRIMARY",
-          "TAG_Y_CB_CR_SUB_SAMPLING",
-          "TAG_GPS_ALTITUDE_REF",
-          "SENSITIVITY_TYPE_SOS",
-          "TAG_SENSING_METHOD",
-          "TAG_ORF_ASPECT_FRAME",
-          "TAG_NEW_SUBFILE_TYPE",
-          "TAG_EXPOSURE_MODE",
-          "ORIENTATION_ROTATE_270",
-          "IFD_GPS_TAGS",
-          "RAF_JPEG_LENGTH_VALUE_SIZE",
-          "TAG_FLASH_ENERGY",
-          "TAG_RECOMMENDED_EXPOSURE_INDEX",
-          "SENSOR_TYPE_TRILINEAR",
-          "SCENE_CAPTURE_TYPE_STANDARD",
-          "PEF_TAGS",
-          "SENSITIVITY_TYPE_UNKNOWN",
-          "TAG_DATETIME",
-          "TAG_JPEG_INTERCHANGE_FORMAT_LENGTH",
-          "LIGHT_SOURCE_FLASH",
-          "FLAG_FLASH_MODE_AUTO",
-          "MARKER_APP1",
-          "SENSITIVITY_TYPE_REI",
-          "TAG_DATETIME_ORIGINAL",
-          "TAG_GPS_DEST_LATITUDE",
-          "FILE_SOURCE_TRANSPARENT_SCANNER",
-          "RENDERED_PROCESS_CUSTOM",
-          "IFD_TYPE_INTEROPERABILITY"
-        ]
-      },
-      "android/support/v4/widget/ViewDragHelper": {
-        "androidx/widget/ViewDragHelper": [
-          "DIRECTION_HORIZONTAL",
-          "TAG",
-          "INVALID_POINTER",
-          "EDGE_SIZE",
-          "EDGE_LEFT",
-          "STATE_IDLE",
-          "STATE_DRAGGING",
-          "EDGE_ALL",
-          "DIRECTION_ALL",
-          "EDGE_RIGHT",
-          "sInterpolator",
-          "EDGE_TOP",
-          "STATE_SETTLING",
-          "BASE_SETTLE_DURATION",
-          "EDGE_BOTTOM",
-          "MAX_SETTLE_DURATION",
-          "DIRECTION_VERTICAL"
-        ]
-      },
-      "android/support/design/widget/NavigationView": {
-        "androidx/design/widget/NavigationView": [
-          "EMPTY_STATE_SET",
-          "CHECKED_STATE_SET",
-          "PRESENTER_NAVIGATION_VIEW_ID",
-          "DISABLED_STATE_SET"
-        ]
-      },
-      "android/support/customtabs/ICustomTabsCallback$Stub": {
-        "androidx/browser/customtabs/ICustomTabsCallback$Stub": [
-          "TRANSACTION_onMessageChannelReady",
-          "TRANSACTION_onPostMessage",
-          "TRANSACTION_onNavigationEvent",
-          "TRANSACTION_onRelationshipValidationResult",
-          "TRANSACTION_extraCallback",
-          "DESCRIPTOR"
-        ]
-      },
-      "android/support/v7/media/MediaRouterJellybeanMr1$ActiveScanWorkaround": {
-        "androidx/media/MediaRouterJellybeanMr1$ActiveScanWorkaround": [
-          "WIFI_DISPLAY_SCAN_INTERVAL"
-        ]
-      },
-      "android/support/v17/leanback/widget/GridLayoutManager$LayoutParams": {
-        "androidx/leanback/widget/GridLayoutManager$LayoutParams": [
-          "bottomMargin",
-          "leftMargin",
-          "topMargin",
-          "width",
-          "height",
-          "rightMargin"
-        ]
-      },
-      "android/support/v7/cardview/R$styleable": {
-        "androidx/cardview/R$styleable": [
-          "CardView_contentPaddingRight",
-          "CardView",
-          "CardView_android_minWidth",
-          "CardView_cardCornerRadius",
-          "CardView_contentPaddingLeft",
-          "CardView_cardBackgroundColor",
-          "CardView_contentPadding",
-          "CardView_contentPaddingBottom",
-          "CardView_cardElevation",
-          "CardView_cardUseCompatPadding",
-          "CardView_contentPaddingTop",
-          "CardView_android_minHeight",
-          "CardView_cardPreventCornerOverlap",
-          "CardView_cardMaxElevation"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ThumbsAction": {
-        "androidx/leanback/widget/PlaybackControlsRow$ThumbsAction": [
-          "INDEX_OUTLINE",
-          "OUTLINE",
-          "SOLID",
-          "INDEX_SOLID"
-        ]
-      },
-      "android/support/v4/media/session/IMediaSession$Stub": {
-        "androidx/media/session/IMediaSession$Stub": [
-          "TRANSACTION_playFromUri",
-          "TRANSACTION_playFromSearch",
-          "TRANSACTION_getRepeatMode",
-          "TRANSACTION_previous",
-          "TRANSACTION_getPlaybackState",
-          "TRANSACTION_adjustVolume",
-          "TRANSACTION_setShuffleMode",
-          "TRANSACTION_setVolumeTo",
-          "TRANSACTION_prepareFromSearch",
-          "TRANSACTION_removeQueueItemAt",
-          "TRANSACTION_playFromMediaId",
-          "TRANSACTION_getPackageName",
-          "TRANSACTION_sendCommand",
-          "TRANSACTION_isTransportControlEnabled",
-          "TRANSACTION_pause",
-          "DESCRIPTOR",
-          "TRANSACTION_rewind",
-          "TRANSACTION_getRatingType",
-          "TRANSACTION_prepareFromUri",
-          "TRANSACTION_getMetadata",
-          "TRANSACTION_addQueueItemAt",
-          "TRANSACTION_getQueueTitle",
-          "TRANSACTION_getLaunchPendingIntent",
-          "TRANSACTION_getQueue",
-          "TRANSACTION_registerCallbackListener",
-          "TRANSACTION_getShuffleMode",
-          "TRANSACTION_seekTo",
-          "TRANSACTION_prepareFromMediaId",
-          "TRANSACTION_setShuffleModeEnabledRemoved",
-          "TRANSACTION_removeQueueItem",
-          "TRANSACTION_setRepeatMode",
-          "TRANSACTION_getFlags",
-          "TRANSACTION_prepare",
-          "TRANSACTION_isShuffleModeEnabledRemoved",
-          "TRANSACTION_addQueueItem",
-          "TRANSACTION_isCaptioningEnabled",
-          "TRANSACTION_setCaptioningEnabled",
-          "TRANSACTION_rateWithExtras",
-          "TRANSACTION_stop",
-          "TRANSACTION_getVolumeAttributes",
-          "TRANSACTION_next",
-          "TRANSACTION_skipToQueueItem",
-          "TRANSACTION_rate",
-          "TRANSACTION_unregisterCallbackListener",
-          "TRANSACTION_play",
-          "TRANSACTION_getTag",
-          "TRANSACTION_sendMediaButton",
-          "TRANSACTION_sendCustomAction",
-          "TRANSACTION_fastForward",
-          "TRANSACTION_getExtras"
-        ]
-      },
-      "android/support/v4/provider/FontsContractCompat$Columns": {
-        "androidx/provider/FontsContractCompat$Columns": [
-          "TTC_INDEX",
-          "FILE_ID",
-          "RESULT_CODE",
-          "WEIGHT",
-          "ITALIC",
-          "VARIATION_SETTINGS",
-          "RESULT_CODE_OK",
-          "RESULT_CODE_MALFORMED_QUERY",
-          "RESULT_CODE_FONT_UNAVAILABLE",
-          "RESULT_CODE_FONT_NOT_FOUND"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserProtocol": {
-        "androidx/media/MediaBrowserProtocol": [
-          "DATA_CALLING_UID",
-          "EXTRA_MESSENGER_BINDER",
-          "DATA_ROOT_HINTS",
-          "CLIENT_MSG_UNREGISTER_CALLBACK_MESSENGER",
-          "EXTRA_SERVICE_VERSION",
-          "SERVICE_VERSION_1",
-          "DATA_OPTIONS",
-          "CLIENT_MSG_DISCONNECT",
-          "EXTRA_SESSION_BINDER",
-          "SERVICE_VERSION_CURRENT",
-          "CLIENT_VERSION_CURRENT",
-          "EXTRA_CLIENT_VERSION",
-          "CLIENT_VERSION_1",
-          "CLIENT_MSG_GET_MEDIA_ITEM",
-          "DATA_MEDIA_ITEM_LIST",
-          "DATA_MEDIA_SESSION_TOKEN",
-          "SERVICE_MSG_ON_CONNECT",
-          "DATA_RESULT_RECEIVER",
-          "CLIENT_MSG_SEND_CUSTOM_ACTION",
-          "CLIENT_MSG_CONNECT",
-          "SERVICE_MSG_ON_CONNECT_FAILED",
-          "SERVICE_MSG_ON_LOAD_CHILDREN",
-          "DATA_MEDIA_ITEM_ID",
-          "DATA_CALLBACK_TOKEN",
-          "DATA_SEARCH_QUERY",
-          "DATA_CUSTOM_ACTION_EXTRAS",
-          "CLIENT_MSG_SEARCH",
-          "DATA_SEARCH_EXTRAS",
-          "CLIENT_MSG_ADD_SUBSCRIPTION",
-          "DATA_CUSTOM_ACTION",
-          "CLIENT_MSG_REGISTER_CALLBACK_MESSENGER",
-          "DATA_PACKAGE_NAME",
-          "CLIENT_MSG_REMOVE_SUBSCRIPTION"
-        ]
-      },
-      "android/support/v17/leanback/R$color": {
-        "androidx/leanback/R$color": [
-          "lb_error_background_color_opaque",
-          "lb_playback_controls_background_dark",
-          "lb_default_brand_color_dark",
-          "lb_error_background_color_translucent",
-          "lb_background_protection",
-          "lb_speech_orb_recording",
-          "lb_default_brand_color",
-          "lb_page_indicator_dot",
-          "lb_search_bar_hint",
-          "lb_playback_progress_color_no_theme",
-          "lb_speech_orb_not_recording",
-          "lb_search_bar_text_speech_mode",
-          "lb_view_dim_mask_color",
-          "lb_playback_controls_background_light",
-          "lb_playback_media_row_highlight_color",
-          "lb_default_search_color",
-          "lb_playback_icon_highlight_no_theme",
-          "lb_search_bar_hint_speech_mode",
-          "lb_page_indicator_arrow_shadow",
-          "lb_speech_orb_not_recording_icon",
-          "lb_speech_orb_not_recording_pulsed",
-          "lb_search_bar_text",
-          "lb_page_indicator_arrow_background"
-        ]
-      },
-      "android/support/transition/ViewGroupUtilsApi18": {
-        "androidx/transition/ViewGroupUtilsApi18": [
-          "sSuppressLayoutMethod",
-          "TAG",
-          "sSuppressLayoutMethodFetched"
-        ]
-      },
-      "android/support/v4/text/TextDirectionHeuristicsCompat": {
-        "androidx/text/TextDirectionHeuristicsCompat": [
-          "STATE_UNKNOWN",
-          "RTL",
-          "LOCALE",
-          "ANYRTL_LTR",
-          "LTR",
-          "FIRSTSTRONG_RTL",
-          "FIRSTSTRONG_LTR",
-          "STATE_TRUE",
-          "STATE_FALSE"
-        ]
-      },
-      "android/support/v7/widget/ListViewCompat": {
-        "androidx/widget/internal/ListViewCompat": [
-          "INVALID_POSITION",
-          "NO_POSITION",
-          "STATE_SET_NOTHING"
-        ]
-      },
-      "android/support/v17/leanback/app/GuidedStepSupportFragment": {
-        "androidx/leanback/app/GuidedStepSupportFragment": [
-          "SLIDE_FROM_BOTTOM",
-          "SLIDE_FROM_SIDE",
-          "EXTRA_BUTTON_ACTION_PREFIX",
-          "TAG_LEAN_BACK_ACTIONS_FRAGMENT",
-          "ENTRY_NAME_ENTRANCE",
-          "DEBUG",
-          "UI_STYLE_DEFAULT",
-          "UI_STYLE_REPLACE",
-          "IS_FRAMEWORK_FRAGMENT",
-          "UI_STYLE_ACTIVITY_ROOT",
-          "EXTRA_UI_STYLE",
-          "UI_STYLE_ENTRANCE",
-          "entranceTransitionType",
-          "TAG",
-          "ENTRY_NAME_REPLACE",
-          "EXTRA_ACTION_PREFIX"
-        ]
-      },
-      "android/support/v7/media/MediaRouter$GlobalMediaRouter$CallbackHandler": {
-        "androidx/media/MediaRouter$GlobalMediaRouter$CallbackHandler": [
-          "MSG_TYPE_MASK",
-          "MSG_PROVIDER_REMOVED",
-          "MSG_ROUTE_SELECTED",
-          "MSG_ROUTE_VOLUME_CHANGED",
-          "MSG_PROVIDER_ADDED",
-          "MSG_TYPE_ROUTE",
-          "MSG_ROUTE_REMOVED",
-          "MSG_ROUTE_UNSELECTED",
-          "MSG_TYPE_PROVIDER",
-          "MSG_PROVIDER_CHANGED",
-          "MSG_ROUTE_ADDED",
-          "MSG_ROUTE_PRESENTATION_DISPLAY_CHANGED",
-          "MSG_ROUTE_CHANGED"
-        ]
-      },
-      "android/support/v7/view/menu/ActionMenuItem": {
-        "androidx/view/menu/ActionMenuItem": [
-          "EXCLUSIVE",
-          "CHECKED",
-          "ENABLED",
-          "CHECKABLE",
-          "NO_ICON",
-          "HIDDEN"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$WearableExtender": {
-        "androidx/app/NotificationCompat$WearableExtender": [
-          "SCREEN_TIMEOUT_LONG",
-          "KEY_FLAGS",
-          "KEY_DISMISSAL_ID",
-          "SIZE_LARGE",
-          "KEY_GRAVITY",
-          "KEY_CONTENT_ICON",
-          "FLAG_START_SCROLL_BOTTOM",
-          "DEFAULT_FLAGS",
-          "DEFAULT_CONTENT_ICON_GRAVITY",
-          "FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE",
-          "UNSET_ACTION_INDEX",
-          "DEFAULT_GRAVITY",
-          "FLAG_HINT_SHOW_BACKGROUND_ONLY",
-          "SIZE_XSMALL",
-          "KEY_CUSTOM_CONTENT_HEIGHT",
-          "FLAG_HINT_AVOID_BACKGROUND_CLIPPING",
-          "SIZE_DEFAULT",
-          "KEY_BACKGROUND",
-          "FLAG_BIG_PICTURE_AMBIENT",
-          "SCREEN_TIMEOUT_SHORT",
-          "SIZE_FULL_SCREEN",
-          "KEY_ACTIONS",
-          "EXTRA_WEARABLE_EXTENSIONS",
-          "KEY_CONTENT_ACTION_INDEX",
-          "FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY",
-          "KEY_CONTENT_ICON_GRAVITY",
-          "KEY_DISPLAY_INTENT",
-          "SIZE_SMALL",
-          "KEY_CUSTOM_SIZE_PRESET",
-          "KEY_HINT_SCREEN_TIMEOUT",
-          "FLAG_HINT_HIDE_ICON",
-          "KEY_BRIDGE_TAG",
-          "SIZE_MEDIUM",
-          "KEY_PAGES"
-        ]
-      },
-      "android/support/design/R$styleable": {
-        "androidx/design/R$styleable": [
-          "TabLayout_tabSelectedTextColor",
-          "BottomSheetBehavior_Layout_behavior_peekHeight",
-          "TextInputLayout_counterOverflowTextAppearance",
-          "BottomNavigationView_itemTextColor",
-          "ScrimInsetsFrameLayout_insetForeground",
-          "TabItem_android_icon",
-          "CoordinatorLayout",
-          "TextInputLayout_counterTextAppearance",
-          "TabLayout_tabMode",
-          "TextInputLayout_hintAnimationEnabled",
-          "TextInputLayout_passwordToggleTint",
-          "NavigationView_android_fitsSystemWindows",
-          "AppBarLayout_android_background",
-          "BottomSheetBehavior_Layout",
-          "FloatingActionButton_fabSize",
-          "TextInputLayout_android_hint",
-          "FloatingActionButton_elevation",
-          "TabItem_android_text",
-          "CollapsingToolbarLayout_expandedTitleTextAppearance",
-          "TextInputLayout_hintTextAppearance",
-          "BottomNavigationView_elevation",
-          "BottomNavigationView_itemIconTint",
-          "CollapsingToolbarLayout_collapsedTitleTextAppearance",
-          "TabLayout_tabPaddingEnd",
-          "TextInputLayout",
-          "TextInputLayout_counterEnabled",
-          "TextInputLayout_passwordToggleContentDescription",
-          "NavigationView_itemBackground",
-          "CollapsingToolbarLayout_expandedTitleMarginBottom",
-          "AppBarLayout_android_keyboardNavigationCluster",
-          "FloatingActionButton_Behavior_Layout",
-          "NavigationView_itemTextAppearance",
-          "TabLayout_tabBackground",
-          "TabLayout_tabContentStart",
-          "ScrollingViewBehavior_Layout",
-          "TabItem_android_layout",
-          "TextInputLayout_hintEnabled",
-          "CollapsingToolbarLayout_scrimVisibleHeightTrigger",
-          "TabLayout_tabPaddingTop",
-          "CoordinatorLayout_Layout_layout_anchorGravity",
-          "CoordinatorLayout_statusBarBackground",
-          "NavigationView",
-          "CollapsingToolbarLayout_expandedTitleMarginEnd",
-          "CoordinatorLayout_Layout_layout_anchor",
-          "TabLayout_tabMinWidth",
-          "TabLayout_tabPaddingStart",
-          "TextInputLayout_errorEnabled",
-          "TabLayout_tabMaxWidth",
-          "TabLayout_tabTextColor",
-          "CollapsingToolbarLayout_collapsedTitleGravity",
-          "BottomNavigationView",
-          "TabLayout_tabTextAppearance",
-          "NavigationView_itemIconTint",
-          "TabLayout_tabIndicatorColor",
-          "TabLayout",
-          "TabLayout_tabIndicatorHeight",
-          "NavigationView_headerLayout",
-          "CoordinatorLayout_Layout",
-          "BottomNavigationView_menu",
-          "CollapsingToolbarLayout_Layout_layout_collapseParallaxMultiplier",
-          "NavigationView_menu",
-          "TextInputLayout_passwordToggleDrawable",
-          "ScrimInsetsFrameLayout",
-          "CoordinatorLayout_Layout_layout_insetEdge",
-          "CollapsingToolbarLayout_titleEnabled",
-          "ForegroundLinearLayout",
-          "TabLayout_tabGravity",
-          "CollapsingToolbarLayout_contentScrim",
-          "ForegroundLinearLayout_android_foreground",
-          "CollapsingToolbarLayout_expandedTitleGravity",
-          "TextInputLayout_errorTextAppearance",
-          "TabLayout_tabPaddingBottom",
-          "CollapsingToolbarLayout",
-          "AppBarLayout",
-          "FloatingActionButton_pressedTranslationZ",
-          "FloatingActionButton_Behavior_Layout_behavior_autoHide",
-          "FloatingActionButton_useCompatPadding",
-          "NavigationView_android_maxWidth",
-          "CollapsingToolbarLayout_title",
-          "CollapsingToolbarLayout_Layout",
-          "SnackbarLayout_maxActionInlineWidth",
-          "ForegroundLinearLayout_android_foregroundGravity",
-          "AppBarLayout_android_touchscreenBlocksFocus",
-          "ScrollingViewBehavior_Layout_behavior_overlapTop",
-          "BottomSheetBehavior_Layout_behavior_skipCollapsed",
-          "CollapsingToolbarLayout_expandedTitleMarginTop",
-          "BottomNavigationView_itemBackground",
-          "FloatingActionButton_rippleColor",
-          "NavigationView_android_background",
-          "SnackbarLayout_elevation",
-          "TextInputLayout_android_textColorHint",
-          "NavigationView_itemTextColor",
-          "BottomSheetBehavior_Layout_behavior_hideable",
-          "AppBarLayout_Layout_layout_scrollInterpolator",
-          "FloatingActionButton_backgroundTint",
-          "AppBarLayout_Layout_layout_scrollFlags",
-          "CollapsingToolbarLayout_Layout_layout_collapseMode",
-          "TabLayout_tabPadding",
-          "FloatingActionButton_backgroundTintMode",
-          "CoordinatorLayout_Layout_layout_behavior",
-          "CoordinatorLayout_Layout_android_layout_gravity",
-          "AppBarLayout_elevation",
-          "ForegroundLinearLayout_foregroundInsidePadding",
-          "TabItem",
-          "AppBarLayout_expanded",
-          "FloatingActionButton",
-          "TextInputLayout_passwordToggleTintMode",
-          "SnackbarLayout_android_maxWidth",
-          "TextInputLayout_passwordToggleEnabled",
-          "CollapsingToolbarLayout_expandedTitleMargin",
-          "NavigationView_elevation",
-          "FloatingActionButton_borderWidth",
-          "CoordinatorLayout_Layout_layout_keyline",
-          "SnackbarLayout",
-          "CollapsingToolbarLayout_toolbarId",
-          "CoordinatorLayout_keylines",
-          "CollapsingToolbarLayout_scrimAnimationDuration",
-          "TextInputLayout_counterMaxLength",
-          "CoordinatorLayout_Layout_layout_dodgeInsetEdges",
-          "AppBarLayout_Layout",
-          "CollapsingToolbarLayout_statusBarScrim",
-          "CollapsingToolbarLayout_expandedTitleMarginStart"
-        ]
-      },
-      "android/support/text/emoji/MetadataListReader": {
-        "androidx/text/emoji/MetadataListReader": [
-          "META_TABLE_NAME",
-          "EMJI_TAG_DEPRECATED",
-          "EMJI_TAG"
-        ]
-      },
-      "android/support/v4/widget/DrawerLayout": {
-        "androidx/widget/DrawerLayout": [
-          "TAG",
-          "DRAWER_ELEVATION",
-          "SET_DRAWER_SHADOW_FROM_ELEVATION",
-          "STATE_DRAGGING",
-          "MIN_FLING_VELOCITY",
-          "TOUCH_SLOP_SENSITIVITY",
-          "LOCK_MODE_UNDEFINED",
-          "MIN_DRAWER_MARGIN",
-          "STATE_IDLE",
-          "THEME_ATTRS",
-          "LOCK_MODE_LOCKED_OPEN",
-          "ALLOW_EDGE_LOCK",
-          "CAN_HIDE_DESCENDANTS",
-          "CHILDREN_DISALLOW_INTERCEPT",
-          "PEEK_DELAY",
-          "LOCK_MODE_UNLOCKED",
-          "DEFAULT_SCRIM_COLOR",
-          "STATE_SETTLING",
-          "LOCK_MODE_LOCKED_CLOSED",
-          "LAYOUT_ATTRS"
-        ]
-      },
-      "android/support/v4/content/ModernAsyncTask": {
-        "androidx/content/ModernAsyncTask": [
-          "MESSAGE_POST_RESULT",
-          "MESSAGE_POST_PROGRESS",
-          "sDefaultExecutor",
-          "KEEP_ALIVE",
-          "sThreadFactory",
-          "sPoolWorkQueue",
-          "THREAD_POOL_EXECUTOR",
-          "CORE_POOL_SIZE",
-          "MAXIMUM_POOL_SIZE",
-          "sHandler",
-          "LOG_TAG"
-        ]
-      },
-      "android/support/v7/media/MediaControlIntent": {
-        "androidx/media/MediaControlIntent": [
-          "EXTRA_SESSION_STATUS_UPDATE_RECEIVER",
-          "CATEGORY_REMOTE_PLAYBACK",
-          "ACTION_START_SESSION",
-          "ACTION_PLAY",
-          "ACTION_SEEK",
-          "ERROR_UNSUPPORTED_OPERATION",
-          "ERROR_INVALID_ITEM_ID",
-          "ACTION_ENQUEUE",
-          "ACTION_SEND_MESSAGE",
-          "EXTRA_ITEM_CONTENT_POSITION",
-          "ERROR_UNKNOWN",
-          "ACTION_STOP",
-          "CATEGORY_LIVE_VIDEO",
-          "EXTRA_ITEM_STATUS_UPDATE_RECEIVER",
-          "EXTRA_ITEM_METADATA",
-          "EXTRA_SESSION_ID",
-          "EXTRA_MESSAGE",
-          "EXTRA_ITEM_HTTP_HEADERS",
-          "CATEGORY_LIVE_AUDIO",
-          "ACTION_END_SESSION",
-          "EXTRA_MESSAGE_RECEIVER",
-          "ACTION_GET_SESSION_STATUS",
-          "ACTION_REMOVE",
-          "EXTRA_ITEM_STATUS",
-          "EXTRA_ERROR_CODE",
-          "ACTION_GET_STATUS",
-          "ERROR_INVALID_SESSION_ID",
-          "EXTRA_SESSION_STATUS",
-          "EXTRA_ITEM_ID",
-          "ACTION_RESUME",
-          "ACTION_PAUSE"
-        ]
-      },
-      "android/support/design/widget/CoordinatorLayout$LayoutParams": {
-        "androidx/design/widget/CoordinatorLayout$LayoutParams": [
-          "keyline",
-          "topMargin",
-          "leftMargin",
-          "anchorGravity",
-          "bottomMargin",
-          "rightMargin",
-          "height",
-          "gravity",
-          "dodgeInsetEdges",
-          "insetEdge"
-        ]
-      },
-      "android/support/design/internal/NavigationMenuPresenter$NormalViewHolder": {
-        "androidx/design/internal/NavigationMenuPresenter$NormalViewHolder": [
-          "itemView"
-        ]
-      },
-      "android/support/v7/recyclerview/R$styleable": {
-        "androidx/recyclerview/R$styleable": [
-          "RecyclerView_fastScrollHorizontalThumbDrawable",
-          "RecyclerView_fastScrollVerticalTrackDrawable",
-          "RecyclerView_android_descendantFocusability",
-          "RecyclerView_spanCount",
-          "RecyclerView_stackFromEnd",
-          "RecyclerView_reverseLayout",
-          "RecyclerView_fastScrollVerticalThumbDrawable",
-          "RecyclerView_layoutManager",
-          "RecyclerView_android_orientation",
-          "RecyclerView",
-          "RecyclerView_fastScrollEnabled",
-          "RecyclerView_fastScrollHorizontalTrackDrawable"
-        ]
-      },
-      "android/support/v4/app/ActionBarDrawerToggle": {
-        "androidx/app/legacy/ActionBarDrawerToggle": [
-          "TAG",
-          "ID_HOME",
-          "THEME_ATTRS",
-          "TOGGLE_DRAWABLE_OFFSET"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$Axis": {
-        "androidx/widget/GridLayout$Axis": [
-          "backwardLinks",
-          "orderPreserved",
-          "trailingMargins",
-          "leadingMargins",
-          "locationsValid",
-          "groupBounds",
-          "hasWeights",
-          "groupBoundsValid",
-          "PENDING",
-          "arcsValid",
-          "trailingMarginsValid",
-          "arcs",
-          "locations",
-          "backwardLinksValid",
-          "leadingMarginsValid",
-          "maxIndex",
-          "horizontal",
-          "forwardLinksValid",
-          "definedCount",
-          "NEW",
-          "deltas",
-          "parentMax",
-          "parentMin",
-          "COMPLETE",
-          "hasWeightsValid",
-          "forwardLinks"
-        ]
-      },
-      "android/support/v4/app/BundleCompat$BundleCompatBaseImpl": {
-        "androidx/app/BundleCompat$BundleCompatBaseImpl": [
-          "sGetIBinderMethod",
-          "sGetIBinderMethodFetched",
-          "sPutIBinderMethodFetched",
-          "TAG",
-          "sPutIBinderMethod"
-        ]
-      },
-      "android/support/v7/app/AppCompatViewInflater": {
-        "androidx/app/AppCompatViewInflater": [
-          "sOnClickAttrs",
-          "sConstructorMap",
-          "sClassPrefixList",
-          "sConstructorSignature",
-          "LOG_TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/SearchBar": {
-        "androidx/leanback/widget/SearchBar": [
-          "FULL_RIGHT_VOLUME",
-          "DEBUG",
-          "DEFAULT_RATE",
-          "FULL_LEFT_VOLUME",
-          "DO_NOT_LOOP",
-          "DEFAULT_PRIORITY",
-          "TAG"
-        ]
-      },
-      "android/support/v7/appcompat/R$drawable": {
-        "androidx/appcompat/R$drawable": [
-          "abc_ic_ab_back_material",
-          "abc_text_select_handle_middle_mtrl_dark",
-          "abc_text_select_handle_left_mtrl_light",
-          "abc_textfield_activated_mtrl_alpha",
-          "abc_text_select_handle_left_mtrl_dark",
-          "abc_text_cursor_material",
-          "abc_text_select_handle_right_mtrl_light",
-          "abc_ratingbar_material",
-          "abc_ic_menu_share_mtrl_alpha",
-          "abc_ratingbar_small_material",
-          "abc_ic_menu_paste_mtrl_am_alpha",
-          "abc_textfield_search_default_mtrl_alpha",
-          "abc_menu_hardkey_panel_mtrl_mult",
-          "abc_text_select_handle_right_mtrl_dark",
-          "abc_dialog_material_background",
-          "abc_ratingbar_indicator_material",
-          "abc_btn_colored_material",
-          "abc_edit_text_material",
-          "abc_btn_borderless_material",
-          "abc_btn_check_material",
-          "abc_ab_share_pack_mtrl_alpha",
-          "abc_tab_indicator_material",
-          "abc_spinner_textfield_background_material",
-          "abc_ic_commit_search_api_mtrl_alpha",
-          "abc_textfield_default_mtrl_alpha",
-          "abc_switch_track_mtrl_alpha",
-          "abc_seekbar_thumb_material",
-          "abc_list_divider_mtrl_alpha",
-          "abc_spinner_mtrl_am_alpha",
-          "abc_btn_radio_material",
-          "abc_cab_background_top_material",
-          "abc_cab_background_top_mtrl_alpha",
-          "abc_text_select_handle_middle_mtrl_light",
-          "abc_vector_test",
-          "abc_btn_default_mtrl_shape",
-          "abc_switch_thumb_material",
-          "abc_seekbar_track_material",
-          "abc_popup_background_mtrl_mult",
-          "abc_seekbar_tick_mark_material",
-          "abc_ic_menu_copy_mtrl_am_alpha",
-          "abc_ic_menu_selectall_mtrl_alpha",
-          "abc_textfield_search_activated_mtrl_alpha",
-          "abc_cab_background_internal_bg",
-          "abc_ic_menu_cut_mtrl_alpha",
-          "abc_textfield_search_material"
-        ]
-      },
-      "android/support/v17/leanback/widget/GuidedActionsStylist": {
-        "androidx/leanback/widget/GuidedActionsStylist": [
-          "sGuidedActionItemAlignFacet",
-          "TAG",
-          "VIEW_TYPE_DEFAULT",
-          "VIEW_TYPE_DATE_PICKER"
-        ]
-      },
-      "android/support/v17/leanback/R$dimen": {
-        "androidx/leanback/R$dimen": [
-          "lb_details_v2_align_pos_for_description",
-          "lb_details_overview_image_margin_vertical",
-          "lb_search_browse_rows_align_top",
-          "lb_material_shadow_normal_z",
-          "lb_details_v2_left",
-          "lb_details_v2_description_margin_top",
-          "lb_playback_controls_child_margin_bigger",
-          "lb_details_v2_actions_height",
-          "lb_playback_transport_thumbs_height",
-          "lb_details_rows_align_top",
-          "lb_control_icon_width",
-          "lb_page_indicator_dot_radius",
-          "lb_playback_controls_z",
-          "lb_error_under_image_baseline_margin",
-          "lb_browse_rows_margin_start",
-          "lb_playback_transport_thumbs_margin",
-          "lb_playback_transport_hero_thumbs_width",
-          "lb_details_description_under_subtitle_baseline_margin",
-          "lb_rounded_rect_corner_radius",
-          "lb_search_orb_unfocused_z",
-          "lb_playback_transport_progressbar_active_bar_height",
-          "picker_item_height",
-          "lb_page_indicator_arrow_shadow_offset",
-          "lb_page_indicator_arrow_gap",
-          "lb_details_description_title_baseline",
-          "lb_details_v2_blank_height",
-          "lb_search_bar_height",
-          "lb_playback_controls_child_margin_default",
-          "lb_details_v2_logo_margin_start",
-          "lb_browse_selected_row_top_padding",
-          "lb_details_cover_drawable_parallax_movement",
-          "lb_playback_transport_hero_thumbs_height",
-          "lb_details_overview_height_small",
-          "lb_material_shadow_focused_z",
-          "lb_playback_transport_thumbs_width",
-          "lb_browse_rows_margin_top",
-          "lb_action_padding_horizontal",
-          "lb_page_indicator_arrow_radius",
-          "lb_details_description_body_line_spacing",
-          "lb_browse_expanded_selected_row_top_padding",
-          "lb_browse_header_select_scale",
-          "lb_details_v2_align_pos_for_actions",
-          "lb_action_with_icon_padding_start",
-          "lb_page_indicator_arrow_shadow_radius",
-          "lb_playback_transport_progressbar_bar_height",
-          "lb_playback_controls_child_margin_biggest",
-          "lb_playback_controls_padding_bottom",
-          "lb_browse_expanded_row_no_hovercard_bottom_padding",
-          "lb_browse_header_select_duration",
-          "lb_playback_other_rows_center_to_bottom",
-          "lb_details_overview_image_margin_horizontal",
-          "lb_search_orb_focused_z",
-          "lb_error_under_message_baseline_margin",
-          "lb_playback_major_fade_translate_y",
-          "lb_page_indicator_dot_gap",
-          "lb_details_overview_height_large",
-          "lb_details_overview_actions_fade_size",
-          "lb_action_with_icon_padding_end",
-          "lb_details_description_title_line_spacing",
-          "lb_playback_minor_fade_translate_y",
-          "lb_playback_transport_progressbar_active_radius",
-          "lb_details_description_under_title_baseline_margin"
-        ]
-      },
-      "android/support/v7/appcompat/R$layout": {
-        "androidx/appcompat/R$layout": [
-          "abc_screen_toolbar",
-          "abc_screen_simple",
-          "abc_action_mode_close_item_material",
-          "abc_dialog_title_material",
-          "abc_list_menu_item_checkbox",
-          "abc_activity_chooser_view",
-          "abc_search_dropdown_item_icons_2line",
-          "support_simple_spinner_dropdown_item",
-          "abc_list_menu_item_radio",
-          "abc_popup_menu_header_item_layout",
-          "abc_list_menu_item_layout",
-          "tooltip",
-          "abc_action_menu_layout",
-          "abc_list_menu_item_icon",
-          "abc_action_menu_item_layout",
-          "abc_action_bar_title_item",
-          "abc_popup_menu_item_layout",
-          "abc_activity_chooser_view_list_item",
-          "abc_search_view",
-          "abc_expanded_menu_layout",
-          "abc_screen_simple_overlay_action_mode"
-        ]
-      },
-      "android/support/v7/appcompat/R$id": {
-        "androidx/appcompat/R$id": [
-          "submit_area",
-          "split_action_bar",
-          "scrollIndicatorUp",
-          "search_button",
-          "contentPanel",
-          "title",
-          "action_mode_close_button",
-          "custom",
-          "search_edit_frame",
-          "decor_content_parent",
-          "action_bar_title",
-          "submenuarrow",
-          "search_voice_btn",
-          "title_template",
-          "action_bar",
-          "action_bar_subtitle",
-          "alertTitle",
-          "default_activity_button",
-          "search_close_btn",
-          "textSpacerNoTitle",
-          "action_mode_bar_stub",
-          "titleDividerNoCustom",
-          "action_bar_container",
-          "parentPanel",
-          "shortcut",
-          "icon",
-          "search_src_text",
-          "activity_chooser_view_content",
-          "search_plate",
-          "customPanel",
-          "edit_query",
-          "action_menu_presenter",
-          "spacer",
-          "scrollIndicatorDown",
-          "scrollView",
-          "message",
-          "buttonPanel",
-          "topPanel",
-          "list_item",
-          "action_context_bar",
-          "search_go_btn",
-          "textSpacerNoButtons",
-          "search_mag_icon",
-          "action_bar_activity_content",
-          "expand_activities_button",
-          "image"
-        ]
-      },
-      "android/support/v7/widget/Toolbar$LayoutParams": {
-        "androidx/widget/Toolbar$LayoutParams": [
-          "gravity",
-          "EXPANDED",
-          "width",
-          "SYSTEM",
-          "leftMargin",
-          "CUSTOM",
-          "bottomMargin",
-          "rightMargin",
-          "topMargin",
-          "height"
-        ]
-      },
-      "android/support/v4/app/NotificationCompatJellybean": {
-        "androidx/app/NotificationCompatJellybean": [
-          "KEY_LABEL",
-          "sActionIntentField",
-          "KEY_ACTION_INTENT",
-          "sActionClass",
-          "sExtrasLock",
-          "KEY_REMOTE_INPUTS",
-          "KEY_ALLOWED_DATA_TYPES",
-          "sActionsLock",
-          "KEY_CHOICES",
-          "sExtrasField",
-          "EXTRA_DATA_ONLY_REMOTE_INPUTS",
-          "sActionTitleField",
-          "sActionIconField",
-          "KEY_EXTRAS",
-          "KEY_TITLE",
-          "sActionsAccessFailed",
-          "TAG",
-          "KEY_ICON",
-          "EXTRA_ALLOW_GENERATED_REPLIES",
-          "KEY_ALLOW_FREE_FORM_INPUT",
-          "KEY_DATA_ONLY_REMOTE_INPUTS",
-          "sExtrasFieldAccessFailed",
-          "KEY_RESULT_KEY",
-          "sActionsField"
-        ]
-      },
-      "android/support/v7/widget/GridLayout": {
-        "androidx/widget/GridLayout": [
-          "RIGHT",
-          "DEFAULT_COUNT",
-          "DEFAULT_ORIENTATION",
-          "ROW_ORDER_PRESERVED",
-          "TOP",
-          "LEADING",
-          "START",
-          "BASELINE",
-          "UNDEFINED",
-          "ALIGN_BOUNDS",
-          "CENTER",
-          "MAX_SIZE",
-          "ALIGNMENT_MODE",
-          "COLUMN_COUNT",
-          "ROW_COUNT",
-          "CAN_STRETCH",
-          "USE_DEFAULT_MARGINS",
-          "FILL",
-          "HORIZONTAL",
-          "DEFAULT_CONTAINER_MARGIN",
-          "LOG_PRINTER",
-          "ALIGN_MARGINS",
-          "VERTICAL",
-          "DEFAULT_ALIGNMENT_MODE",
-          "COLUMN_ORDER_PRESERVED",
-          "ORIENTATION",
-          "LEFT",
-          "TRAILING",
-          "DEFAULT_ORDER_PRESERVED",
-          "BOTTOM",
-          "END",
-          "DEFAULT_USE_DEFAULT_MARGINS",
-          "INFLEXIBLE",
-          "UNINITIALIZED_HASH",
-          "UNDEFINED_ALIGNMENT",
-          "NO_PRINTER"
-        ]
-      },
-      "android/support/wear/widget/BoxInsetLayout$LayoutParams": {
-        "androidx/wear/widget/BoxInsetLayout$LayoutParams": [
-          "BOX_ALL",
-          "BOX_LEFT",
-          "BOX_TOP",
-          "gravity",
-          "height",
-          "topMargin",
-          "rightMargin",
-          "bottomMargin",
-          "boxedEdges",
-          "BOX_RIGHT",
-          "width",
-          "leftMargin",
-          "BOX_NONE",
-          "BOX_BOTTOM"
-        ]
-      },
-      "android/support/design/widget/TabLayout": {
-        "androidx/design/widget/TabLayout": [
-          "GRAVITY_FILL",
-          "TAB_MIN_WIDTH_MARGIN",
-          "DEFAULT_HEIGHT_WITH_TEXT_ICON",
-          "ANIMATION_DURATION",
-          "INVALID_WIDTH",
-          "FIXED_WRAP_GUTTER_MIN",
-          "MOTION_NON_ADJACENT_OFFSET",
-          "DEFAULT_HEIGHT",
-          "MODE_FIXED",
-          "SELECTED_STATE_SET",
-          "MODE_SCROLLABLE",
-          "EMPTY_STATE_SET",
-          "sTabPool",
-          "GRAVITY_CENTER",
-          "DEFAULT_GAP_TEXT_ICON"
-        ]
-      },
-      "android/support/v4/view/MotionEventCompat": {
-        "androidx/view/MotionEventCompat": [
-          "ACTION_SCROLL",
-          "AXIS_RUDDER",
-          "AXIS_BRAKE",
-          "AXIS_TOOL_MINOR",
-          "AXIS_GENERIC_3",
-          "AXIS_GENERIC_4",
-          "AXIS_GENERIC_5",
-          "AXIS_GENERIC_6",
-          "AXIS_GENERIC_7",
-          "AXIS_GENERIC_8",
-          "AXIS_GENERIC_9",
-          "AXIS_GENERIC_1",
-          "AXIS_GENERIC_2",
-          "AXIS_DISTANCE",
-          "AXIS_ORIENTATION",
-          "AXIS_LTRIGGER",
-          "AXIS_HSCROLL",
-          "ACTION_POINTER_DOWN",
-          "AXIS_TILT",
-          "AXIS_WHEEL",
-          "AXIS_Y",
-          "AXIS_Z",
-          "AXIS_X",
-          "AXIS_SCROLL",
-          "AXIS_TOUCH_MAJOR",
-          "ACTION_HOVER_ENTER",
-          "AXIS_GAS",
-          "ACTION_HOVER_MOVE",
-          "ACTION_HOVER_EXIT",
-          "AXIS_THROTTLE",
-          "AXIS_HAT_X",
-          "AXIS_HAT_Y",
-          "AXIS_SIZE",
-          "ACTION_POINTER_INDEX_SHIFT",
-          "AXIS_RTRIGGER",
-          "AXIS_RELATIVE_X",
-          "AXIS_RELATIVE_Y",
-          "AXIS_RY",
-          "AXIS_RZ",
-          "AXIS_RX",
-          "AXIS_TOUCH_MINOR",
-          "ACTION_POINTER_INDEX_MASK",
-          "BUTTON_PRIMARY",
-          "AXIS_PRESSURE",
-          "AXIS_TOOL_MAJOR",
-          "AXIS_GENERIC_13",
-          "AXIS_GENERIC_12",
-          "AXIS_GENERIC_11",
-          "AXIS_GENERIC_10",
-          "AXIS_GENERIC_16",
-          "AXIS_GENERIC_15",
-          "AXIS_GENERIC_14",
-          "ACTION_POINTER_UP",
-          "ACTION_MASK",
-          "AXIS_VSCROLL"
-        ]
-      },
-      "android/support/v4/view/PagerTitleStrip": {
-        "androidx/widget/PagerTitleStrip": [
-          "ATTRS",
-          "SIDE_ALPHA",
-          "TEXT_ATTRS",
-          "TEXT_SPACING"
-        ]
-      },
-      "android/support/v4/graphics/TypefaceCompatApi26Impl": {
-        "androidx/graphics/TypefaceCompatApi26Impl": [
-          "sAddFontFromAssetManager",
-          "sFreeze",
-          "TAG",
-          "RESOLVE_BY_FONT_TABLE",
-          "sFontFamily",
-          "ADD_FONT_FROM_ASSET_MANAGER_METHOD",
-          "sCreateFromFamiliesWithDefault",
-          "FONT_FAMILY_CLASS",
-          "ABORT_CREATION_METHOD",
-          "sFontFamilyCtor",
-          "CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD",
-          "sAbortCreation",
-          "ADD_FONT_FROM_BUFFER_METHOD",
-          "sAddFontFromBuffer",
-          "FREEZE_METHOD"
-        ]
-      },
-      "android/support/v7/app/AppCompatDelegate": {
-        "androidx/app/AppCompatDelegate": [
-          "sCompatVectorFromResourcesEnabled",
-          "MODE_NIGHT_FOLLOW_SYSTEM",
-          "MODE_NIGHT_YES",
-          "TAG",
-          "FEATURE_SUPPORT_ACTION_BAR_OVERLAY",
-          "sDefaultNightMode",
-          "MODE_NIGHT_NO",
-          "MODE_NIGHT_AUTO",
-          "FEATURE_ACTION_MODE_OVERLAY",
-          "FEATURE_SUPPORT_ACTION_BAR",
-          "MODE_NIGHT_UNSPECIFIED"
-        ]
-      },
-      "android/support/v7/view/menu/ListMenuItemView": {
-        "androidx/view/menu/ListMenuItemView": [
-          "TAG"
-        ]
-      },
-      "android/support/media/instantvideo/preload/InstantVideoPreloadManager": {
-        "androidx/media/instantvideo/preload/InstantVideoPreloadManager": [
-          "DEBUG",
-          "sInstance",
-          "TAG",
-          "DEFAULT_MAX_VIDEO_COUNT"
-        ]
-      },
-      "android/support/graphics/drawable/AndroidResources": {
-        "androidx/graphics/drawable/AndroidResources": [
-          "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET",
-          "STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_NAME",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_NAME",
-          "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_DRAWABLE",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_END",
-          "STYLEABLE_PATH_INTERPOLATOR",
-          "STYLEABLE_PROPERTY_VALUES_HOLDER_PROPERTY_NAME",
-          "STYLEABLE_KEYFRAME_INTERPOLATOR",
-          "STYLEABLE_KEYFRAME_FRACTION",
-          "STYLEABLE_ANIMATOR_REPEAT_MODE",
-          "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET_NAME",
-          "STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_WIDTH",
-          "FAST_OUT_LINEAR_IN",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_JOIN",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_PATH_DATA",
-          "STYLEABLE_VECTOR_DRAWABLE_TINT_MODE",
-          "STYLEABLE_VECTOR_DRAWABLE_TINT",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_NAME",
-          "STYLEABLE_KEYFRAME_VALUE_TYPE",
-          "STYLEABLE_PATH_INTERPOLATOR_PATH_DATA",
-          "STYLEABLE_ANIMATOR_START_OFFSET",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_COLOR",
-          "STYLEABLE_ANIMATED_VECTOR_DRAWABLE_TARGET_ANIMATION",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_ROTATION",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_WIDTH",
-          "STYLEABLE_PROPERTY_ANIMATOR_PROPERTY_Y_NAME",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_ALPHA",
-          "STYLEABLE_ANIMATOR_INTERPOLATOR",
-          "STYLEABLE_VECTOR_DRAWABLE_WIDTH",
-          "STYLEABLE_ANIMATOR_SET_ORDERING",
-          "STYLEABLE_ANIMATED_VECTOR_DRAWABLE",
-          "STYLEABLE_ANIMATOR_DURATION",
-          "STYLEABLE_VECTOR_DRAWABLE_ALPHA",
-          "STYLEABLE_VECTOR_DRAWABLE_HEIGHT",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_ALPHA",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_MITER_LIMIT",
-          "STYLEABLE_PATH_INTERPOLATOR_CONTROL_X_2",
-          "STYLEABLE_PATH_INTERPOLATOR_CONTROL_X_1",
-          "LINEAR_OUT_SLOW_IN",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_COLOR",
-          "STYLEABLE_PROPERTY_VALUES_HOLDER_VALUE_TO",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH",
-          "STYLEABLE_ANIMATOR_REMOVE_BEFORE_M_RELEASE",
-          "STYLEABLE_PATH_INTERPOLATOR_CONTROL_Y_1",
-          "STYLEABLE_PATH_INTERPOLATOR_CONTROL_Y_2",
-          "FAST_OUT_SLOW_IN",
-          "STYLEABLE_ANIMATOR_VALUE_FROM",
-          "STYLEABLE_ANIMATOR_REPEAT_COUNT",
-          "STYLEABLE_ANIMATOR_SET",
-          "STYLEABLE_PROPERTY_ANIMATOR_PATH_DATA",
-          "STYLEABLE_ANIMATOR_VALUE_TO",
-          "STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_HEIGHT",
-          "STYLEABLE_KEYFRAME",
-          "STYLEABLE_VECTOR_DRAWABLE_TYPE_ARRAY",
-          "STYLEABLE_ANIMATOR_VALUE_TYPE",
-          "STYLEABLE_PROPERTY_VALUES_HOLDER",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_X",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_OFFSET",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_Y",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_X",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_Y",
-          "STYLEABLE_VECTOR_DRAWABLE_AUTO_MIRRORED",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_START",
-          "STYLEABLE_KEYFRAME_VALUE",
-          "STYLEABLE_PROPERTY_VALUES_HOLDER_VALUE_TYPE",
-          "STYLEABLE_PROPERTY_ANIMATOR_PROPERTY_NAME",
-          "STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH",
-          "STYLEABLE_VECTOR_DRAWABLE_NAME",
-          "STYLEABLE_PROPERTY_VALUES_HOLDER_VALUE_FROM",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_Y",
-          "STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_X",
-          "STYLEABLE_ANIMATOR",
-          "STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_PATH_DATA",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_CAP",
-          "STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_FILLTYPE",
-          "STYLEABLE_PROPERTY_ANIMATOR",
-          "STYLEABLE_PROPERTY_ANIMATOR_PROPERTY_X_NAME"
-        ]
-      },
-      "android/support/v7/app/ActionBar$LayoutParams": {
-        "androidx/app/ActionBar$LayoutParams": [
-          "gravity"
-        ]
-      },
-      "android/support/v7/widget/LinearLayoutCompat": {
-        "androidx/widget/LinearLayoutCompat": [
-          "VERTICAL_GRAVITY_COUNT",
-          "SHOW_DIVIDER_BEGINNING",
-          "HORIZONTAL",
-          "SHOW_DIVIDER_MIDDLE",
-          "SHOW_DIVIDER_NONE",
-          "INDEX_CENTER_VERTICAL",
-          "INDEX_TOP",
-          "INDEX_FILL",
-          "VERTICAL",
-          "INDEX_BOTTOM",
-          "SHOW_DIVIDER_END"
-        ]
-      },
-      "android/support/percent/PercentLayoutHelper$PercentMarginLayoutParams": {
-        "androidx/PercentLayoutHelper$PercentMarginLayoutParams": [
-          "topMargin",
-          "leftMargin",
-          "rightMargin",
-          "height",
-          "width",
-          "bottomMargin"
-        ]
-      },
-      "android/support/v17/leanback/widget/StreamingTextView": {
-        "androidx/leanback/widget/StreamingTextView": [
-          "STREAM_POSITION_PROPERTY",
-          "DOTS_FOR_STABLE",
-          "ANIMATE_DOTS_FOR_PENDING",
-          "STREAM_UPDATE_DELAY_MILLIS",
-          "DEBUG",
-          "TEXT_DOT_SCALE",
-          "DOTS_FOR_PENDING",
-          "SPLIT_PATTERN",
-          "TAG"
-        ]
-      },
-      "android/support/v7/view/SupportMenuInflater$MenuState": {
-        "androidx/view/SupportMenuInflater$MenuState": [
-          "itemListenerMethodName",
-          "itemActionViewClassName",
-          "itemContentDescription",
-          "itemEnabled",
-          "defaultItemChecked",
-          "itemCategoryOrder",
-          "itemTitle",
-          "groupCategory",
-          "itemIconTintMode",
-          "itemAdded",
-          "groupCheckable",
-          "itemNumericShortcut",
-          "groupVisible",
-          "itemNumericModifiers",
-          "itemTitleCondensed",
-          "defaultItemVisible",
-          "itemAlphabeticShortcut",
-          "itemShowAsAction",
-          "menu",
-          "defaultItemCheckable",
-          "itemActionProvider",
-          "itemCheckable",
-          "itemActionViewLayout",
-          "itemIconResId",
-          "itemVisible",
-          "itemTooltipText",
-          "defaultItemCategory",
-          "defaultGroupId",
-          "groupOrder",
-          "defaultItemId",
-          "itemActionProviderClassName",
-          "itemId",
-          "itemIconTintList",
-          "itemChecked",
-          "groupId",
-          "defaultItemEnabled",
-          "defaultItemOrder",
-          "itemAlphabeticModifiers",
-          "groupEnabled"
-        ]
-      },
-      "android/support/v4/view/InputDeviceCompat": {
-        "androidx/view/InputDeviceCompat": [
-          "SOURCE_CLASS_JOYSTICK",
-          "SOURCE_KEYBOARD",
-          "SOURCE_CLASS_MASK",
-          "SOURCE_CLASS_POINTER",
-          "SOURCE_ROTARY_ENCODER",
-          "SOURCE_TOUCHSCREEN",
-          "SOURCE_TOUCHPAD",
-          "SOURCE_STYLUS",
-          "SOURCE_CLASS_POSITION",
-          "SOURCE_UNKNOWN",
-          "SOURCE_DPAD",
-          "SOURCE_CLASS_BUTTON",
-          "SOURCE_JOYSTICK",
-          "SOURCE_ANY",
-          "SOURCE_TOUCH_NAVIGATION",
-          "SOURCE_TRACKBALL",
-          "SOURCE_MOUSE",
-          "SOURCE_HDMI",
-          "SOURCE_GAMEPAD",
-          "SOURCE_CLASS_TRACKBALL",
-          "SOURCE_CLASS_NONE"
-        ]
-      },
-      "android/support/v17/leanback/R$styleable": {
-        "androidx/leanback/R$styleable": [
-          "lbImageCardView_lbImageCardViewType",
-          "LeanbackTheme_browseRowsMarginTop",
-          "lbPlaybackControlsActionIcons_thumb_down_outline",
-          "lbSlide_android_interpolator",
-          "lbBaseCardView_cardType",
-          "lbResizingTextView_resizedPaddingAdjustmentBottom",
-          "lbBaseGridView_android_horizontalSpacing",
-          "lbResizingTextView_maintainLineSpacing",
-          "lbBaseGridView_verticalMargin",
-          "lbPlaybackControlsActionIcons_repeat_one",
-          "lbBaseGridView_horizontalMargin",
-          "lbHorizontalGridView_rowHeight",
-          "lbHorizontalGridView_numberOfRows",
-          "LeanbackTheme_browseRowsFadingEdgeLength",
-          "PagingIndicator_dotToDotGap",
-          "PagingIndicator_arrowColor",
-          "PagingIndicator",
-          "lbSearchOrbView_searchOrbColor",
-          "lbTimePicker_is24HourFormat",
-          "lbDatePicker",
-          "lbSearchOrbView_searchOrbBrightColor",
-          "lbDatePicker_android_maxDate",
-          "lbVerticalGridView_columnWidth",
-          "PagingIndicator_arrowRadius",
-          "lbTimePicker_useCurrentTime",
-          "LeanbackGuidedStepTheme",
-          "lbPlaybackControlsActionIcons_shuffle",
-          "lbBaseCardView_cardBackground",
-          "lbPlaybackControlsActionIcons",
-          "lbBaseCardView",
-          "lbPlaybackControlsActionIcons_play",
-          "lbSlide_lb_slideEdge",
-          "lbBaseCardView_extraVisibility",
-          "LeanbackTheme_overlayDimActiveLevel",
-          "lbResizingTextView_resizeTrigger",
-          "lbPlaybackControlsActionIcons_picture_in_picture",
-          "lbBaseGridView_android_gravity",
-          "lbBaseGridView_focusOutEnd",
-          "LeanbackTheme",
-          "lbPlaybackControlsActionIcons_thumb_up",
-          "PagingIndicator_dotBgColor",
-          "lbSearchOrbView_searchOrbIconColor",
-          "lbSearchOrbView",
-          "lbBaseGridView_focusOutFront",
-          "lbBaseCardView_infoVisibility",
-          "lbResizingTextView_resizedTextSize",
-          "lbPlaybackControlsActionIcons_skip_previous",
-          "PagingIndicator_dotToArrowGap",
-          "lbHorizontalGridView",
-          "lbDatePicker_datePickerFormat",
-          "lbVerticalGridView_numberOfColumns",
-          "lbSlide_android_duration",
-          "PagingIndicator_lbDotRadius",
-          "lbPlaybackControlsActionIcons_skip_next",
-          "lbSlide",
-          "lbSlide_android_startDelay",
-          "lbPlaybackControlsActionIcons_fast_forward",
-          "lbImageCardView",
-          "LeanbackTheme_browseRowsMarginStart",
-          "lbBaseCardView_Layout_layout_viewType",
-          "lbTimePicker",
-          "lbResizingTextView",
-          "lbImageCardView_infoAreaBackground",
-          "lbBaseCardView_Layout",
-          "lbPlaybackControlsActionIcons_repeat",
-          "lbPlaybackControlsActionIcons_rewind",
-          "lbBaseCardView_selectedAnimationDelay",
-          "lbBaseGridView_focusOutSideStart",
-          "lbBaseCardView_selectedAnimationDuration",
-          "lbBaseGridView_android_verticalSpacing",
-          "lbSearchOrbView_searchOrbIcon",
-          "lbPlaybackControlsActionIcons_pause",
-          "lbBaseGridView",
-          "PagingIndicator_arrowBgColor",
-          "lbVerticalGridView",
-          "lbDatePicker_android_minDate",
-          "lbPlaybackControlsActionIcons_thumb_up_outline",
-          "LeanbackTheme_overlayDimDimmedLevel",
-          "lbBaseGridView_focusOutSideEnd",
-          "lbPlaybackControlsActionIcons_high_quality",
-          "lbResizingTextView_resizedPaddingAdjustmentTop",
-          "lbBaseCardView_activatedAnimationDuration",
-          "lbPlaybackControlsActionIcons_closed_captioning",
-          "LeanbackTheme_overlayDimMaskColor",
-          "lbPlaybackControlsActionIcons_thumb_down",
-          "LeanbackGuidedStepTheme_guidedStepKeyline",
-          "lbBaseCardView_cardForeground"
-        ]
-      },
-      "android/support/v17/leanback/R$drawable": {
-        "androidx/leanback/R$drawable": [
-          "lb_ic_in_app_search",
-          "lb_text_dot_one",
-          "lb_ic_search_mic_out",
-          "lb_ic_search_mic",
-          "lb_background",
-          "lb_text_dot_two",
-          "lb_ic_nav_arrow",
-          "lb_ic_more"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$ViewHolder": {
-        "androidx/widget/RecyclerView$ViewHolder": [
-          "FLAG_NOT_RECYCLABLE",
-          "FLAG_INVALID",
-          "FULLUPDATE_PAYLOADS",
-          "FLAG_RETURNED_FROM_SCRAP",
-          "PENDING_ACCESSIBILITY_STATE_NOT_SET",
-          "FLAG_REMOVED",
-          "FLAG_TMP_DETACHED",
-          "FLAG_ADAPTER_POSITION_UNKNOWN",
-          "FLAG_SET_A11Y_ITEM_DELEGATE",
-          "itemView",
-          "FLAG_APPEARED_IN_PRE_LAYOUT",
-          "FLAG_ADAPTER_FULLUPDATE",
-          "FLAG_BOUNCED_FROM_HIDDEN_LIST",
-          "FLAG_IGNORE",
-          "FLAG_BOUND",
-          "FLAG_UPDATE",
-          "FLAG_MOVED"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$Token": {
-        "androidx/media/session/MediaSessionCompat$Token": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseFragment$ExpandPreLayout": {
-        "androidx/leanback/app/BrowseFragment$ExpandPreLayout": [
-          "STATE_SECOND_DRAW",
-          "STATE_INIT",
-          "mainFragmentAdapter",
-          "STATE_FIRST_DRAW"
-        ]
-      },
-      "android/support/v13/app/FragmentTabHost$TabInfo": {
-        "androidx/app/legacy/FragmentTabHost$TabInfo": [
-          "fragment",
-          "args",
-          "tag",
-          "clss"
-        ]
-      },
-      "android/support/media/tv/Channel": {
-        "androidx/media/tv/Channel": [
-          "IS_SEARCHABLE",
-          "IS_SYSTEM_APPROVED",
-          "INVALID_INT_VALUE",
-          "INVALID_CHANNEL_ID",
-          "PROJECTION",
-          "IS_TRANSIENT",
-          "IS_BROWSABLE",
-          "IS_LOCKED"
-        ]
-      },
-      "android/support/v4/text/BidiFormatter$DirectionalityEstimator": {
-        "androidx/text/BidiFormatter$DirectionalityEstimator": [
-          "lastChar",
-          "DIR_TYPE_CACHE_SIZE",
-          "DIR_TYPE_CACHE",
-          "charIndex",
-          "isHtml",
-          "text",
-          "length"
-        ]
-      },
-      "android/support/v7/widget/AppCompatDrawableManager": {
-        "androidx/widget/AppCompatDrawableManager": [
-          "COLOR_FILTER_CACHE",
-          "TINT_COLOR_CONTROL_NORMAL",
-          "TAG",
-          "COLORFILTER_TINT_COLOR_CONTROL_NORMAL",
-          "COLORFILTER_COLOR_CONTROL_ACTIVATED",
-          "TINT_CHECKABLE_BUTTON_LIST",
-          "INSTANCE",
-          "TINT_COLOR_CONTROL_STATE_LIST",
-          "DEFAULT_MODE",
-          "DEBUG",
-          "COLORFILTER_COLOR_BACKGROUND_MULTIPLY",
-          "PLATFORM_VD_CLAZZ",
-          "SKIP_DRAWABLE_TAG"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat": {
-        "androidx/media/tv/TvContractCompat": [
-          "PARAM_INPUT",
-          "PATH_CHANNEL",
-          "ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED",
-          "ACTION_REQUEST_CHANNEL_BROWSABLE",
-          "EXTRA_PREVIEW_PROGRAM_ID",
-          "PATH_RECORDED_PROGRAM",
-          "PATH_PASSTHROUGH",
-          "PARAM_CHANNEL",
-          "AUTHORITY",
-          "PARAM_START_TIME",
-          "PARAM_BROWSABLE_ONLY",
-          "EXTRA_DATA_TYPE",
-          "EXTRA_DEFAULT_VALUE",
-          "PARAM_END_TIME",
-          "EXTRA_WATCH_NEXT_PROGRAM_ID",
-          "PARAM_CANONICAL_GENRE",
-          "METHOD_GET_COLUMNS",
-          "PATH_PROGRAM",
-          "METHOD_ADD_COLUMN",
-          "PATH_PREVIEW_PROGRAM",
-          "PATH_WATCH_NEXT_PROGRAM",
-          "EXTRA_COLUMN_NAME",
-          "ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED",
-          "PERMISSION_READ_TV_LISTINGS",
-          "EXTRA_EXISTING_COLUMN_NAMES",
-          "ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT",
-          "EXTRA_PACKAGE_NAME",
-          "ACTION_CHANNEL_BROWSABLE_REQUESTED",
-          "EXTRA_CHANNEL_ID",
-          "ACTION_INITIALIZE_PROGRAMS"
-        ]
-      },
-      "android/support/v17/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller": {
-        "androidx/leanback/widget/GridLayoutManager$PendingMoveSmoothScroller": [
-          "TARGET_UNDEFINED"
-        ]
-      },
-      "android/support/v7/media/RemoteControlClientCompat$PlaybackInfo": {
-        "androidx/media/RemoteControlClientCompat$PlaybackInfo": [
-          "volumeMax",
-          "playbackType",
-          "volume",
-          "volumeHandling",
-          "playbackStream"
-        ]
-      },
-      "android/support/v4/util/ArraySet": {
-        "androidx/util/ArraySet": [
-          "OBJECT",
-          "TAG",
-          "sTwiceBaseCacheSize",
-          "CACHE_SIZE",
-          "sBaseCacheSize",
-          "sTwiceBaseCache",
-          "BASE_SIZE",
-          "INT",
-          "sBaseCache",
-          "DEBUG"
-        ]
-      },
-      "android/support/v17/leanback/app/OnboardingFragment": {
-        "androidx/leanback/app/OnboardingFragment": [
-          "DESCRIPTION_START_DELAY_MS",
-          "TAG",
-          "HEADER_ANIMATION_DURATION_MS",
-          "HEADER_APPEAR_DELAY_MS",
-          "KEY_LOGO_ANIMATION_FINISHED",
-          "HEADER_DISAPPEAR_INTERPOLATOR",
-          "DEBUG",
-          "HEADER_APPEAR_INTERPOLATOR",
-          "KEY_ENTER_ANIMATION_FINISHED",
-          "KEY_CURRENT_PAGE_INDEX",
-          "sSlideDistance",
-          "LOGO_SPLASH_PAUSE_DURATION_MS",
-          "SLIDE_DISTANCE"
-        ]
-      },
-      "android/support/v17/leanback/R$string": {
-        "androidx/leanback/R$string": [
-          "lb_control_display_fast_forward_multiplier",
-          "lb_playback_controls_repeat_one",
-          "lb_playback_controls_thumb_up_outline",
-          "lb_playback_controls_thumb_up",
-          "lb_playback_controls_repeat_none",
-          "lb_guidedaction_finish_title",
-          "lb_control_display_rewind_multiplier",
-          "lb_playback_controls_closed_captioning_disable",
-          "lb_playback_controls_repeat_all",
-          "lb_playback_controls_pause",
-          "lb_playback_controls_thumb_down",
-          "lb_playback_controls_shuffle_enable",
-          "lb_playback_controls_rewind_multiplier",
-          "lb_guidedaction_continue_title",
-          "lb_playback_controls_shuffle_disable",
-          "lb_media_player_error",
-          "lb_playback_controls_hidden",
-          "lb_playback_controls_play",
-          "lb_guidedactions_item_unselected_description_text_alpha",
-          "lb_playback_controls_skip_next",
-          "lb_playback_controls_fast_forward",
-          "lb_playback_controls_high_quality_enable",
-          "lb_search_bar_hint_speech",
-          "lb_search_bar_hint_with_title_speech",
-          "lb_playback_controls_closed_captioning_enable",
-          "lb_playback_controls_shown",
-          "lb_guidedactions_item_disabled_description_text_alpha",
-          "lb_search_bar_hint",
-          "lb_playback_controls_fast_forward_multiplier",
-          "lb_playback_controls_picture_in_picture",
-          "lb_playback_controls_thumb_down_outline",
-          "lb_playback_controls_high_quality_disable",
-          "lb_playback_controls_rewind",
-          "lb_playback_controls_more_actions",
-          "lb_guidedactions_item_unselected_text_alpha",
-          "lb_guidedactions_item_disabled_text_alpha",
-          "lb_playback_controls_skip_previous",
-          "lb_search_bar_hint_with_title"
-        ]
-      },
-      "android/support/v7/preference/PreferenceInflater": {
-        "androidx/preference/PreferenceInflater": [
-          "EXTRA_TAG_NAME",
-          "INTENT_TAG_NAME",
-          "CONSTRUCTOR_MAP",
-          "TAG",
-          "CONSTRUCTOR_SIGNATURE"
-        ]
-      },
-      "android/support/constraint/R$styleable": {
-        "androidx/constraint/R$styleable": [
-          "ConstraintLayout_Layout_layout_constraintWidth_max",
-          "ConstraintLayout_Layout_layout_constraintWidth_min",
-          "ConstraintSet_layout_constraintDimensionRatio",
-          "ConstraintSet_android_transformPivotY",
-          "ConstraintSet_android_transformPivotX",
-          "ConstraintSet_layout_goneMarginRight",
-          "ConstraintLayout_Layout_layout_constraintGuide_percent",
-          "ConstraintLayout_Layout_layout_constraintLeft_toLeftOf",
-          "ConstraintSet_layout_goneMarginStart",
-          "ConstraintSet_android_orientation",
-          "ConstraintLayout_Layout_layout_constraintRight_toLeftOf",
-          "ConstraintSet_android_layout_marginBottom",
-          "ConstraintSet_layout_constraintBaseline_toBaselineOf",
-          "ConstraintSet_android_layout_height",
-          "ConstraintSet_layout_constraintRight_creator",
-          "ConstraintSet_layout_constraintWidth_max",
-          "ConstraintSet_layout_constraintEnd_toStartOf",
-          "ConstraintLayout_Layout_layout_constraintBottom_creator",
-          "ConstraintSet_android_visibility",
-          "ConstraintLayout_Layout_layout_constraintTop_toBottomOf",
-          "ConstraintSet_layout_constraintGuide_begin",
-          "ConstraintSet_layout_constraintWidth_min",
-          "ConstraintLayout_Layout_android_maxHeight",
-          "ConstraintSet_android_id",
-          "ConstraintSet_layout_constraintBottom_creator",
-          "ConstraintLayout_Layout_layout_optimizationLevel",
-          "ConstraintLayout_Layout_layout_constraintVertical_bias",
-          "ConstraintSet_layout_constraintHorizontal_bias",
-          "ConstraintSet_layout_constraintHeight_default",
-          "ConstraintSet",
-          "ConstraintLayout_Layout_layout_constraintBottom_toBottomOf",
-          "ConstraintLayout_Layout",
-          "ConstraintLayout_Layout_layout_constraintBaseline_creator",
-          "ConstraintLayout_Layout_layout_constraintVertical_chainStyle",
-          "ConstraintSet_android_rotationY",
-          "ConstraintSet_android_rotationX",
-          "ConstraintSet_android_alpha",
-          "ConstraintLayout_Layout_layout_constraintDimensionRatio",
-          "ConstraintLayout_Layout_android_orientation",
-          "ConstraintSet_layout_constraintLeft_creator",
-          "ConstraintSet_layout_goneMarginLeft",
-          "ConstraintSet_layout_constraintLeft_toLeftOf",
-          "ConstraintLayout_Layout_layout_constraintVertical_weight",
-          "ConstraintSet_layout_constraintStart_toStartOf",
-          "ConstraintLayout_Layout_layout_constraintHorizontal_chainStyle",
-          "ConstraintLayout_Layout_layout_constraintEnd_toEndOf",
-          "ConstraintSet_layout_editor_absoluteY",
-          "ConstraintSet_layout_editor_absoluteX",
-          "ConstraintLayout_Layout_layout_constraintEnd_toStartOf",
-          "ConstraintLayout_Layout_layout_constraintTop_toTopOf",
-          "ConstraintSet_android_layout_marginEnd",
-          "ConstraintLayout_Layout_layout_goneMarginLeft",
-          "ConstraintLayout_Layout_layout_constraintGuide_begin",
-          "ConstraintSet_layout_constraintGuide_end",
-          "ConstraintSet_android_translationZ",
-          "ConstraintSet_android_translationY",
-          "ConstraintSet_android_translationX",
-          "ConstraintSet_layout_constraintStart_toEndOf",
-          "ConstraintSet_layout_constraintRight_toRightOf",
-          "ConstraintSet_layout_constraintHeight_max",
-          "ConstraintSet_android_layout_marginTop",
-          "ConstraintSet_layout_constraintHeight_min",
-          "ConstraintSet_layout_constraintTop_creator",
-          "ConstraintLayout_Layout_layout_editor_absoluteX",
-          "ConstraintLayout_Layout_layout_editor_absoluteY",
-          "ConstraintLayout_Layout_layout_goneMarginTop",
-          "ConstraintSet_layout_goneMarginEnd",
-          "ConstraintSet_layout_constraintLeft_toRightOf",
-          "ConstraintLayout_Layout_layout_goneMarginBottom",
-          "ConstraintLayout_Layout_android_minHeight",
-          "ConstraintLayout_Layout_layout_constraintBaseline_toBaselineOf",
-          "ConstraintSet_android_layout_marginLeft",
-          "ConstraintSet_layout_constraintHorizontal_weight",
-          "ConstraintLayout_Layout_layout_goneMarginEnd",
-          "ConstraintSet_layout_constraintVertical_weight",
-          "ConstraintSet_layout_constraintBaseline_creator",
-          "ConstraintSet_layout_constraintVertical_bias",
-          "ConstraintSet_layout_goneMarginTop",
-          "ConstraintLayout_Layout_layout_constraintRight_creator",
-          "ConstraintSet_layout_constraintBottom_toTopOf",
-          "ConstraintLayout_Layout_layout_constraintWidth_default",
-          "ConstraintSet_android_layout_marginStart",
-          "ConstraintSet_android_layout_width",
-          "ConstraintSet_layout_constraintWidth_default",
-          "ConstraintLayout_Layout_layout_constraintBottom_toTopOf",
-          "ConstraintLayout_Layout_layout_constraintStart_toEndOf",
-          "ConstraintLayout_Layout_layout_constraintHorizontal_weight",
-          "ConstraintSet_android_layout_marginRight",
-          "ConstraintSet_layout_constraintBottom_toBottomOf",
-          "ConstraintSet_android_scaleX",
-          "ConstraintSet_android_scaleY",
-          "ConstraintLayout_Layout_layout_constraintRight_toRightOf",
-          "ConstraintSet_layout_constraintGuide_percent",
-          "ConstraintLayout_Layout_layout_constraintLeft_creator",
-          "ConstraintLayout_Layout_layout_constraintTop_creator",
-          "ConstraintSet_layout_constraintTop_toTopOf",
-          "ConstraintLayout_Layout_layout_goneMarginRight",
-          "ConstraintSet_layout_constraintEnd_toEndOf",
-          "ConstraintLayout_Layout_layout_constraintHeight_max",
-          "ConstraintLayout_Layout_constraintSet",
-          "ConstraintLayout_Layout_layout_constraintHeight_min",
-          "ConstraintLayout_Layout_layout_goneMarginStart",
-          "ConstraintSet_android_elevation",
-          "ConstraintSet_layout_constraintTop_toBottomOf",
-          "ConstraintLayout_Layout_layout_constraintLeft_toRightOf",
-          "ConstraintLayout_Layout_layout_constraintStart_toStartOf",
-          "ConstraintSet_layout_constraintHorizontal_chainStyle",
-          "ConstraintLayout_Layout_android_maxWidth",
-          "ConstraintLayout_Layout_layout_constraintHorizontal_bias",
-          "ConstraintLayout_Layout_layout_constraintHeight_default",
-          "ConstraintSet_layout_constraintRight_toLeftOf",
-          "ConstraintLayout_Layout_android_minWidth",
-          "ConstraintSet_layout_constraintVertical_chainStyle",
-          "ConstraintLayout_Layout_layout_constraintGuide_end",
-          "ConstraintSet_layout_goneMarginBottom"
-        ]
-      },
-      "android/support/v4/view/ViewPager": {
-        "androidx/widget/ViewPager": [
-          "SCROLL_STATE_DRAGGING",
-          "MIN_FLING_VELOCITY",
-          "LAYOUT_ATTRS",
-          "DRAW_ORDER_DEFAULT",
-          "DEFAULT_OFFSCREEN_PAGES",
-          "USE_CACHE",
-          "INVALID_POINTER",
-          "sPositionComparator",
-          "SCROLL_STATE_IDLE",
-          "TAG",
-          "DEBUG",
-          "MAX_SETTLE_DURATION",
-          "SCROLL_STATE_SETTLING",
-          "DEFAULT_GUTTER_SIZE",
-          "sInterpolator",
-          "MIN_DISTANCE_FOR_FLING",
-          "DRAW_ORDER_REVERSE",
-          "CLOSE_ENOUGH",
-          "DRAW_ORDER_FORWARD",
-          "COMPARATOR"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler": {
-        "androidx/media/session/MediaSessionCompat$MediaSessionImplBase$MessageHandler": [
-          "MSG_CUSTOM_ACTION",
-          "MSG_SET_VOLUME",
-          "MSG_SET_SHUFFLE_MODE",
-          "MSG_PREPARE",
-          "MSG_COMMAND",
-          "MSG_REMOVE_QUEUE_ITEM",
-          "MSG_RATE_EXTRA",
-          "MSG_PREPARE_SEARCH",
-          "MSG_FAST_FORWARD",
-          "MSG_PREPARE_URI",
-          "MSG_PAUSE",
-          "MSG_PLAY_URI",
-          "MSG_STOP",
-          "MSG_SKIP_TO_ITEM",
-          "MSG_ADD_QUEUE_ITEM",
-          "MSG_RATE",
-          "MSG_PLAY",
-          "MSG_NEXT",
-          "MSG_REMOVE_QUEUE_ITEM_AT",
-          "MSG_SET_REPEAT_MODE",
-          "MSG_PREVIOUS",
-          "MSG_SEEK_TO",
-          "MSG_PLAY_SEARCH",
-          "MSG_PLAY_MEDIA_ID",
-          "MSG_MEDIA_BUTTON",
-          "KEYCODE_MEDIA_PAUSE",
-          "MSG_PREPARE_MEDIA_ID",
-          "KEYCODE_MEDIA_PLAY",
-          "MSG_ADD_QUEUE_ITEM_AT",
-          "MSG_SET_CAPTIONING_ENABLED",
-          "MSG_ADJUST_VOLUME",
-          "MSG_REWIND"
-        ]
-      },
-      "android/support/design/R$dimen": {
-        "androidx/design/R$dimen": [
-          "design_bottom_navigation_item_min_width",
-          "design_tab_scrollable_min_width",
-          "design_tab_text_size_2line",
-          "design_bottom_sheet_peek_height_min",
-          "design_fab_size_mini",
-          "design_snackbar_padding_vertical_2lines",
-          "design_snackbar_padding_vertical",
-          "design_bottom_navigation_item_max_width",
-          "design_bottom_navigation_active_text_size",
-          "design_navigation_separator_vertical_padding",
-          "design_navigation_icon_size",
-          "design_bottom_navigation_text_size",
-          "design_fab_image_size",
-          "design_bottom_navigation_height",
-          "design_bottom_navigation_margin",
-          "design_fab_size_normal",
-          "design_bottom_navigation_active_item_max_width",
-          "design_bottom_navigation_shadow_height"
-        ]
-      },
-      "android/support/multidex/MultiDex": {
-        "androidx/multidex/MultiDex": [
-          "installedApk",
-          "CODE_CACHE_SECONDARY_FOLDER_NAME",
-          "CODE_CACHE_NAME",
-          "VM_WITH_MULTIDEX_VERSION_MAJOR",
-          "TAG",
-          "NO_KEY_PREFIX",
-          "IS_VM_MULTIDEX_CAPABLE",
-          "VM_WITH_MULTIDEX_VERSION_MINOR",
-          "MIN_SDK_VERSION",
-          "MAX_SUPPORTED_SDK_VERSION",
-          "OLD_SECONDARY_FOLDER_NAME"
-        ]
-      },
-      "android/support/constraint/ConstraintSet$Constraint": {
-        "androidx/constraint/ConstraintSet$Constraint": [
-          "guidePercent",
-          "topToTop",
-          "guideEnd",
-          "heightDefault",
-          "topMargin",
-          "goneRightMargin",
-          "goneTopMargin",
-          "visibility",
-          "elevation",
-          "dimensionRatio",
-          "startToStart",
-          "widthMax",
-          "applyElevation",
-          "widthMin",
-          "verticalWeight",
-          "endToStart",
-          "bottomToTop",
-          "rotationY",
-          "rotationX",
-          "horizontalBias",
-          "translationY",
-          "translationZ",
-          "translationX",
-          "transformPivotX",
-          "transformPivotY",
-          "leftMargin",
-          "horizontalChainStyle",
-          "orientation",
-          "leftToRight",
-          "endMargin",
-          "verticalBias",
-          "heightMax",
-          "scaleX",
-          "scaleY",
-          "rightMargin",
-          "leftToLeft",
-          "heightMin",
-          "endToEnd",
-          "topToBottom",
-          "startMargin",
-          "goneLeftMargin",
-          "bottomToBottom",
-          "editorAbsoluteY",
-          "editorAbsoluteX",
-          "baselineToBaseline",
-          "horizontalWeight",
-          "guideBegin",
-          "bottomMargin",
-          "widthDefault",
-          "startToEnd",
-          "rightToRight",
-          "alpha",
-          "UNSET",
-          "goneStartMargin",
-          "rightToLeft",
-          "goneBottomMargin",
-          "verticalChainStyle",
-          "goneEndMargin"
-        ]
-      },
-      "android/support/compat/R$id": {
-        "androidx/compat/R$id": [
-          "right_icon",
-          "action_container",
-          "icon",
-          "notification_background",
-          "line1",
-          "line3",
-          "text",
-          "action_divider",
-          "time",
-          "action_text",
-          "right_side",
-          "notification_main_column",
-          "action_image",
-          "tag_transition_group",
-          "title",
-          "text2",
-          "actions",
-          "notification_main_column_container",
-          "info",
-          "chronometer"
-        ]
-      },
-      "android/support/v7/widget/helper/ItemTouchHelper": {
-        "androidx/widget/helper/ItemTouchHelper": [
-          "DOWN",
-          "DEBUG",
-          "PIXELS_PER_SECOND",
-          "ACTION_STATE_SWIPE",
-          "ANIMATION_TYPE_SWIPE_CANCEL",
-          "END",
-          "UP",
-          "START",
-          "ANIMATION_TYPE_SWIPE_SUCCESS",
-          "ANIMATION_TYPE_DRAG",
-          "LEFT",
-          "ACTIVE_POINTER_ID_NONE",
-          "RIGHT",
-          "TAG",
-          "ACTION_STATE_DRAG",
-          "ACTION_MODE_IDLE_MASK",
-          "ACTION_MODE_SWIPE_MASK",
-          "DIRECTION_FLAG_COUNT",
-          "ACTION_MODE_DRAG_MASK",
-          "ACTION_STATE_IDLE"
-        ]
-      },
-      "android/support/graphics/drawable/VectorDrawableCompat": {
-        "androidx/graphics/drawable/VectorDrawableCompat": [
-          "LINECAP_ROUND",
-          "SHAPE_VECTOR",
-          "LOGTAG",
-          "DEFAULT_TINT_MODE",
-          "SHAPE_CLIP_PATH",
-          "LINECAP_SQUARE",
-          "LINEJOIN_MITER",
-          "LINEJOIN_ROUND",
-          "LINEJOIN_BEVEL",
-          "LINECAP_BUTT",
-          "SHAPE_PATH",
-          "MAX_CACHED_BITMAP_SIZE",
-          "DBG_VECTOR_DRAWABLE",
-          "SHAPE_GROUP"
-        ]
-      },
-      "android/support/v14/preference/R$styleable": {
-        "androidx/preference/R$styleable": [
-          "SwitchPreference_switchTextOff",
-          "SwitchPreference_switchTextOn",
-          "SwitchPreference_disableDependentsState",
-          "PreferenceFragment",
-          "SwitchPreference_android_summaryOn",
-          "PreferenceFragment_android_dividerHeight",
-          "SwitchPreference_android_switchTextOff",
-          "SwitchPreference_android_summaryOff",
-          "PreferenceFragment_allowDividerAfterLastItem",
-          "SwitchPreference",
-          "SwitchPreference_summaryOff",
-          "SwitchPreference_summaryOn",
-          "SwitchPreference_android_switchTextOn",
-          "PreferenceFragment_android_divider",
-          "SwitchPreference_android_disableDependentsState",
-          "PreferenceFragment_android_layout"
-        ]
-      },
-      "android/support/v7/app/MediaRouteControllerDialog": {
-        "androidx/app/MediaRouteControllerDialog": [
-          "BUTTON_DISCONNECT_RES_ID",
-          "DEBUG",
-          "BUTTON_NEUTRAL_RES_ID",
-          "VOLUME_UPDATE_DELAY_MILLIS",
-          "CONNECTION_TIMEOUT_MILLIS",
-          "BUTTON_STOP_RES_ID",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/picker/PickerUtility": {
-        "androidx/leanback/widget/picker/PickerUtility": [
-          "SUPPORTS_BEST_DATE_TIME_PATTERN"
-        ]
-      },
-      "android/support/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder": {
-        "androidx/wear/widget/drawer/WearableActionDrawerView$TitleViewHolder": [
-          "textView",
-          "view"
-        ]
-      },
-      "android/support/customtabs/CustomTabsIntent": {
-        "androidx/browser/customtabs/CustomTabsIntent": [
-          "TOOLBAR_ACTION_BUTTON_ID",
-          "EXTRA_ACTION_BUTTON_BUNDLE",
-          "EXTRA_EXIT_ANIMATION_BUNDLE",
-          "EXTRA_MENU_ITEMS",
-          "EXTRA_CLOSE_BUTTON_ICON",
-          "startAnimationBundle",
-          "KEY_ICON",
-          "EXTRA_SESSION",
-          "EXTRA_DEFAULT_SHARE_MENU_ITEM",
-          "MAX_TOOLBAR_ITEMS",
-          "intent",
-          "EXTRA_SECONDARY_TOOLBAR_COLOR",
-          "KEY_ID",
-          "EXTRA_TOOLBAR_COLOR",
-          "SHOW_PAGE_TITLE",
-          "EXTRA_TITLE_VISIBILITY_STATE",
-          "EXTRA_TOOLBAR_ITEMS",
-          "EXTRA_TINT_ACTION_BUTTON",
-          "NO_TITLE",
-          "KEY_DESCRIPTION",
-          "EXTRA_ENABLE_INSTANT_APPS",
-          "EXTRA_REMOTEVIEWS_PENDINGINTENT",
-          "EXTRA_REMOTEVIEWS_CLICKED_ID",
-          "KEY_MENU_ITEM_TITLE",
-          "EXTRA_ENABLE_URLBAR_HIDING",
-          "KEY_PENDING_INTENT",
-          "EXTRA_REMOTEVIEWS",
-          "EXTRA_USER_OPT_OUT_FROM_CUSTOM_TABS",
-          "EXTRA_REMOTEVIEWS_VIEW_IDS"
-        ]
-      },
-      "android/support/wear/R$styleable": {
-        "androidx/wear/R$styleable": [
-          "PageIndicatorView_wsPageIndicatorDotFadeInDuration",
-          "CircularProgressLayout_strokeWidth",
-          "WearableActionDrawerView",
-          "WearableRecyclerView_circularScrollingGestureEnabled",
-          "PageIndicatorView_wsPageIndicatorDotColor",
-          "PageIndicatorView",
-          "WearableActionDrawerView_actionMenu",
-          "PageIndicatorView_wsPageIndicatorDotFadeOutDelay",
-          "PageIndicatorView_wsPageIndicatorDotRadius",
-          "PageIndicatorView_wsPageIndicatorDotRadiusSelected",
-          "RoundedDrawable",
-          "WearableNavigationDrawerView_navigationStyle",
-          "CircledImageView_img_horizontal_offset_percentage",
-          "CircularProgressLayout",
-          "CircledImageView_img_tint",
-          "WearableActionDrawerView_showOverflowInPeek",
-          "CircledImageView_background_border_cap",
-          "CircledImageView_img_circle_percentage",
-          "BoxInsetLayout_Layout",
-          "CircledImageView_background_radius_pressed_percent",
-          "WearableActionDrawerView_drawerTitle",
-          "WearableRecyclerView",
-          "PageIndicatorView_wsPageIndicatorDotColorSelected",
-          "CircledImageView_img_padding",
-          "WearableDrawerView_android_elevation",
-          "RoundedDrawable_backgroundColor",
-          "PageIndicatorView_wsPageIndicatorDotShadowDx",
-          "PageIndicatorView_wsPageIndicatorDotShadowDy",
-          "CircularProgressLayout_backgroundColor",
-          "CircledImageView_background_radius_pressed",
-          "WearableDrawerView",
-          "BoxInsetLayout_Layout_boxedEdges",
-          "RoundedDrawable_radius",
-          "CircularProgressLayout_indeterminate",
-          "WearableDrawerView_peekView",
-          "WearableDrawerView_android_background",
-          "WearableDrawerView_enableAutoPeek",
-          "CircledImageView",
-          "PageIndicatorView_wsPageIndicatorDotFadeOutDuration",
-          "CircledImageView_background_shadow_width",
-          "CircledImageView_android_src",
-          "CircledImageView_background_radius_percent",
-          "PageIndicatorView_wsPageIndicatorDotShadowRadius",
-          "WearableRecyclerView_scrollDegreesPerScreen",
-          "CircledImageView_background_color",
-          "CircledImageView_clip_dimen",
-          "CircledImageView_background_radius",
-          "PageIndicatorView_wsPageIndicatorDotShadowColor",
-          "RoundedDrawable_clipEnabled",
-          "RoundedDrawable_android_src",
-          "WearableRecyclerView_bezelWidth",
-          "CircularProgressLayout_colorSchemeColors",
-          "WearableDrawerView_drawerContent",
-          "CircledImageView_background_border_color",
-          "WearableNavigationDrawerView",
-          "PageIndicatorView_wsPageIndicatorDotSpacing",
-          "CircledImageView_background_border_width",
-          "PageIndicatorView_wsPageIndicatorDotFadeWhenIdle"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ShuffleAction": {
-        "androidx/leanback/widget/PlaybackControlsRow$ShuffleAction": [
-          "INDEX_ON",
-          "INDEX_OFF",
-          "ON",
-          "OFF"
-        ]
-      },
-      "android/support/v7/widget/TooltipCompatHandler": {
-        "androidx/widget/TooltipCompatHandler": [
-          "LONG_CLICK_HIDE_TIMEOUT_MS",
-          "sActiveHandler",
-          "HOVER_HIDE_TIMEOUT_MS",
-          "TAG",
-          "HOVER_HIDE_TIMEOUT_SHORT_MS"
-        ]
-      },
-      "android/support/v4/media/AudioAttributesCompat$AudioManagerHidden": {
-        "androidx/media/AudioAttributesCompat$AudioManagerHidden": [
-          "STREAM_TTS",
-          "STREAM_BLUETOOTH_SCO",
-          "STREAM_SYSTEM_ENFORCED",
-          "STREAM_ACCESSIBILITY"
-        ]
-      },
-      "android/support/v17/leanback/widget/CursorObjectAdapter": {
-        "androidx/leanback/widget/CursorObjectAdapter": [
-          "CACHE_SIZE"
-        ]
-      },
-      "android/support/v7/mediarouter/R$dimen": {
-        "androidx/mediarouter/R$dimen": [
-          "mr_controller_volume_group_list_padding_top",
-          "mr_controller_volume_group_list_max_height",
-          "mr_controller_volume_group_list_item_height",
-          "mr_controller_volume_group_list_item_icon_size",
-          "mr_dialog_fixed_width_major",
-          "mr_dialog_fixed_width_minor"
-        ]
-      },
-      "android/support/transition/Transition": {
-        "androidx/transition/Transition": [
-          "MATCH_INSTANCE",
-          "MATCH_LAST",
-          "MATCH_FIRST",
-          "sRunningAnimators",
-          "MATCH_ID_STR",
-          "DBG",
-          "MATCH_INSTANCE_STR",
-          "MATCH_ITEM_ID",
-          "DEFAULT_MATCH_ORDER",
-          "MATCH_NAME_STR",
-          "MATCH_NAME",
-          "STRAIGHT_PATH_MOTION",
-          "MATCH_ITEM_ID_STR",
-          "MATCH_ID",
-          "LOG_TAG"
-        ]
-      },
-      "android/support/design/widget/CoordinatorLayout": {
-        "androidx/widget/CoordinatorLayout": [
-          "EVENT_VIEW_REMOVED",
-          "sConstructors",
-          "TOP_SORTED_CHILDREN_COMPARATOR",
-          "TYPE_ON_TOUCH",
-          "sRectPool",
-          "CONSTRUCTOR_PARAMS",
-          "TAG",
-          "EVENT_NESTED_SCROLL",
-          "WIDGET_PACKAGE_NAME",
-          "EVENT_PRE_DRAW",
-          "TYPE_ON_INTERCEPT"
-        ]
-      },
-      "android/support/constraint/ConstraintSet": {
-        "androidx/constraint/ConstraintSet": [
-          "CHAIN_SPREAD_INSIDE",
-          "UNUSED",
-          "GONE_LEFT_MARGIN",
-          "WIDTH_MAX",
-          "DIMENSION_RATIO",
-          "WIDTH_MIN",
-          "GUIDE_BEGIN",
-          "START_TO_START",
-          "ORIENTATION",
-          "RIGHT_TO_LEFT",
-          "VERTICAL",
-          "GUIDE_PERCENT",
-          "GONE_END_MARGIN",
-          "CHAIN_SPREAD",
-          "LAYOUT_HEIGHT",
-          "HORIZONTAL_STYLE",
-          "TOP_MARGIN",
-          "TRANSLATION_X",
-          "TRANSLATION_Z",
-          "TRANSLATION_Y",
-          "ELEVATION",
-          "EDITOR_ABSOLUTE_Y",
-          "EDITOR_ABSOLUTE_X",
-          "END_TO_START",
-          "DEBUG",
-          "MATCH_CONSTRAINT",
-          "BOTTOM_TO_TOP",
-          "RIGHT_MARGIN",
-          "TRANSFORM_PIVOT_Y",
-          "TRANSFORM_PIVOT_X",
-          "WRAP_CONTENT",
-          "BASELINE",
-          "HORIZONTAL_BIAS",
-          "SCALE_Y",
-          "SCALE_X",
-          "VISIBILITY_FLAGS",
-          "CHAIN_PACKED",
-          "VERTICAL_STYLE",
-          "mapToConstant",
-          "HORIZONTAL_GUIDELINE",
-          "LEFT",
-          "START_MARGIN",
-          "PARENT_ID",
-          "GUIDE_END",
-          "END_TO_END",
-          "TOP",
-          "LAYOUT_VISIBILITY",
-          "GONE_BOTTOM_MARGIN",
-          "LEFT_MARGIN",
-          "RIGHT",
-          "GONE_TOP_MARGIN",
-          "VERTICAL_GUIDELINE",
-          "START",
-          "GONE_RIGHT_MARGIN",
-          "TAG",
-          "GONE_START_MARGIN",
-          "HEIGHT_MIN",
-          "MATCH_CONSTRAINT_WRAP",
-          "UNSET",
-          "HEIGHT_MAX",
-          "END",
-          "BASELINE_TO_BASELINE",
-          "LAYOUT_WIDTH",
-          "VERTICAL_BIAS",
-          "HORIZONTAL",
-          "MATCH_CONSTRAINT_SPREAD",
-          "ALPHA",
-          "TOP_TO_TOP",
-          "RIGHT_TO_RIGHT",
-          "TOP_TO_BOTTOM",
-          "BOTTOM",
-          "LEFT_TO_LEFT",
-          "VIEW_ID",
-          "INVISIBLE",
-          "VERTICAL_WEIGHT",
-          "VISIBLE",
-          "HEIGHT_DEFAULT",
-          "WIDTH_DEFAULT",
-          "LEFT_TO_RIGHT",
-          "END_MARGIN",
-          "BOTTOM_MARGIN",
-          "HORIZONTAL_WEIGHT",
-          "START_TO_END",
-          "BOTTOM_TO_BOTTOM",
-          "GONE",
-          "ROTATION_X",
-          "ROTATION_Y"
-        ]
-      },
-      "android/support/v4/app/FrameMetricsAggregator$FrameMetricsApi24Impl": {
-        "androidx/app/FrameMetricsAggregator$FrameMetricsApi24Impl": [
-          "NANOS_PER_MS",
-          "NANOS_ROUNDING_VALUE",
-          "sHandlerThread",
-          "sHandler"
-        ]
-      },
-      "android/support/v4/view/GestureDetectorCompat$GestureDetectorCompatImplBase": {
-        "androidx/view/GestureDetectorCompat$GestureDetectorCompatImplBase": [
-          "LONGPRESS_TIMEOUT",
-          "TAP_TIMEOUT",
-          "DOUBLE_TAP_TIMEOUT",
-          "LONG_PRESS",
-          "TAP",
-          "SHOW_PRESS"
-        ]
-      },
-      "android/support/multidex/MultiDexExtractor": {
-        "androidx/multidex/MultiDexExtractor": [
-          "KEY_DEX_TIME",
-          "MAX_EXTRACT_ATTEMPTS",
-          "TAG",
-          "DEX_PREFIX",
-          "DEX_SUFFIX",
-          "EXTRACTED_NAME_EXT",
-          "KEY_CRC",
-          "KEY_DEX_CRC",
-          "NO_VALUE",
-          "LOCK_FILENAME",
-          "KEY_TIME_STAMP",
-          "EXTRACTED_SUFFIX",
-          "BUFFER_SIZE",
-          "KEY_DEX_NUMBER",
-          "PREFS_FILE"
-        ]
-      },
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat": {
-        "androidx/view/accessibility/AccessibilityNodeInfoCompat$AccessibilityActionCompat": [
-          "ACTION_FOCUS",
-          "ACTION_SCROLL_BACKWARD",
-          "ACTION_SCROLL_DOWN",
-          "ACTION_CONTEXT_CLICK",
-          "ACTION_CLEAR_FOCUS",
-          "ACTION_ACCESSIBILITY_FOCUS",
-          "ACTION_PASTE",
-          "ACTION_SET_PROGRESS",
-          "ACTION_EXPAND",
-          "ACTION_NEXT_HTML_ELEMENT",
-          "ACTION_SCROLL_UP",
-          "ACTION_SCROLL_FORWARD",
-          "ACTION_CLEAR_SELECTION",
-          "ACTION_LONG_CLICK",
-          "ACTION_SET_TEXT",
-          "ACTION_NEXT_AT_MOVEMENT_GRANULARITY",
-          "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY",
-          "ACTION_SHOW_ON_SCREEN",
-          "ACTION_COLLAPSE",
-          "ACTION_COPY",
-          "ACTION_SCROLL_LEFT",
-          "ACTION_PREVIOUS_HTML_ELEMENT",
-          "ACTION_SET_SELECTION",
-          "ACTION_CLEAR_ACCESSIBILITY_FOCUS",
-          "ACTION_SCROLL_TO_POSITION",
-          "ACTION_DISMISS",
-          "ACTION_CLICK",
-          "ACTION_CUT",
-          "ACTION_SCROLL_RIGHT",
-          "ACTION_SELECT"
-        ]
-      },
-      "android/support/v4/graphics/drawable/DrawableWrapperApi21": {
-        "androidx/graphics/drawable/DrawableWrapperApi21": [
-          "sIsProjectedDrawableMethod",
-          "TAG"
-        ]
-      },
-      "android/support/v7/media/MediaRouter$RouteInfo": {
-        "androidx/media/MediaRouter$RouteInfo": [
-          "PRESENTATION_DISPLAY_ID_NONE",
-          "SYSTEM_MEDIA_ROUTE_PROVIDER_PACKAGE_NAME",
-          "PLAYBACK_TYPE_REMOTE",
-          "CHANGE_VOLUME",
-          "DEVICE_TYPE_BLUETOOTH",
-          "CHANGE_PRESENTATION_DISPLAY",
-          "CHANGE_GENERAL",
-          "CONNECTION_STATE_DISCONNECTED",
-          "DEVICE_TYPE_TV",
-          "PLAYBACK_VOLUME_VARIABLE",
-          "CONNECTION_STATE_CONNECTING",
-          "PLAYBACK_TYPE_LOCAL",
-          "DEVICE_TYPE_UNKNOWN",
-          "CONNECTION_STATE_CONNECTED",
-          "PLAYBACK_VOLUME_FIXED",
-          "DEVICE_TYPE_SPEAKER"
-        ]
-      },
-      "android/support/v17/leanback/widget/picker/TimePicker": {
-        "androidx/leanback/widget/picker/TimePicker": [
-          "TAG",
-          "HOURS_IN_HALF_DAY",
-          "AM_INDEX",
-          "PM_INDEX"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView": {
-        "androidx/widget/RecyclerView": [
-          "LAYOUT_MANAGER_CONSTRUCTOR_SIGNATURE",
-          "TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG",
-          "NO_ID",
-          "NO_POSITION",
-          "DISPATCH_TEMP_DETACH",
-          "TRACE_SCROLL_TAG",
-          "SCROLL_STATE_DRAGGING",
-          "TRACE_PREFETCH_TAG",
-          "INVALID_POINTER",
-          "MAX_SCROLL_DURATION",
-          "TOUCH_SLOP_PAGING",
-          "TOUCH_SLOP_DEFAULT",
-          "VERBOSE_TRACING",
-          "TRACE_CREATE_VIEW_TAG",
-          "ALLOW_SIZE_IN_UNSPECIFIED_SPEC",
-          "FORCE_ABS_FOCUS_SEARCH_DIRECTION",
-          "TRACE_BIND_VIEW_TAG",
-          "HORIZONTAL",
-          "ALLOW_THREAD_GAP_WORK",
-          "DEBUG",
-          "TRACE_NESTED_PREFETCH_TAG",
-          "SCROLL_STATE_SETTLING",
-          "POST_UPDATES_ON_ANIMATION",
-          "sQuinticInterpolator",
-          "VERTICAL",
-          "CLIP_TO_PADDING_ATTR",
-          "FOREVER_NS",
-          "IGNORE_DETACHED_FOCUSED_CHILD",
-          "INVALID_TYPE",
-          "SCROLL_STATE_IDLE",
-          "NESTED_SCROLLING_ATTRS",
-          "TAG",
-          "TRACE_ON_LAYOUT_TAG",
-          "FORCE_INVALIDATE_DISPLAY_LIST",
-          "TRACE_HANDLE_ADAPTER_UPDATES_TAG"
-        ]
-      },
-      "android/support/v4/view/PagerAdapter": {
-        "androidx/widget/PagerAdapter": [
-          "POSITION_NONE",
-          "POSITION_UNCHANGED"
-        ]
-      },
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat": {
-        "androidx/view/accessibility/AccessibilityNodeInfoCompat": [
-          "ACTION_PREVIOUS_HTML_ELEMENT",
-          "ACTION_ARGUMENT_SELECTION_END_INT",
-          "ACTION_SET_SELECTION",
-          "MOVEMENT_GRANULARITY_CHARACTER",
-          "MOVEMENT_GRANULARITY_LINE",
-          "ACTION_SET_TEXT",
-          "MOVEMENT_GRANULARITY_PARAGRAPH",
-          "ACTION_SELECT",
-          "FOCUS_ACCESSIBILITY",
-          "ACTION_DISMISS",
-          "ACTION_EXPAND",
-          "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE",
-          "ACTION_CLEAR_ACCESSIBILITY_FOCUS",
-          "ACTION_CUT",
-          "ACTION_PASTE",
-          "ACTION_ARGUMENT_ROW_INT",
-          "FOCUS_INPUT",
-          "ACTION_ARGUMENT_HTML_ELEMENT_STRING",
-          "MOVEMENT_GRANULARITY_PAGE",
-          "ACTION_ARGUMENT_PROGRESS_VALUE",
-          "ACTION_CLEAR_FOCUS",
-          "MOVEMENT_GRANULARITY_WORD",
-          "ACTION_SCROLL_BACKWARD",
-          "ROLE_DESCRIPTION_KEY",
-          "ACTION_FOCUS",
-          "ACTION_NEXT_HTML_ELEMENT",
-          "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN",
-          "ACTION_CLEAR_SELECTION",
-          "ACTION_ARGUMENT_COLUMN_INT",
-          "ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY",
-          "ACTION_NEXT_AT_MOVEMENT_GRANULARITY",
-          "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT",
-          "ACTION_ACCESSIBILITY_FOCUS",
-          "ACTION_CLICK",
-          "ACTION_ARGUMENT_SELECTION_START_INT",
-          "ACTION_SCROLL_FORWARD",
-          "ACTION_COPY",
-          "ACTION_COLLAPSE",
-          "ACTION_LONG_CLICK"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$RecordedPrograms": {
-        "androidx/media/tv/TvContractCompat$RecordedPrograms": [
-          "CONTENT_URI",
-          "COLUMN_RECORDING_DURATION_MILLIS",
-          "COLUMN_CHANNEL_ID",
-          "COLUMN_BROADCAST_GENRE",
-          "COLUMN_RECORDING_DATA_BYTES",
-          "COLUMN_END_TIME_UTC_MILLIS",
-          "CONTENT_TYPE",
-          "COLUMN_RECORDING_DATA_URI",
-          "COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS",
-          "COLUMN_INPUT_ID",
-          "COLUMN_START_TIME_UTC_MILLIS",
-          "CONTENT_ITEM_TYPE"
-        ]
-      },
-      "android/support/v17/leanback/app/PlaybackSupportFragment": {
-        "androidx/leanback/app/PlaybackSupportFragment": [
-          "IDLE",
-          "ANIMATION_MULTIPLIER",
-          "ANIMATING",
-          "BG_LIGHT",
-          "START_FADE_OUT",
-          "TAG",
-          "BG_DARK",
-          "BG_NONE",
-          "BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW",
-          "DEBUG"
-        ]
-      },
-      "android/support/v17/leanback/widget/ShadowOverlayHelper$Options": {
-        "androidx/leanback/widget/ShadowOverlayHelper$Options": [
-          "DEFAULT",
-          "roundedCornerRadius",
-          "dynamicShadowUnfocusedZ",
-          "dynamicShadowFocusedZ"
-        ]
-      },
-      "android/support/v17/leanback/widget/ShadowOverlayHelper": {
-        "androidx/leanback/widget/ShadowOverlayHelper": [
-          "SHADOW_NONE",
-          "SHADOW_STATIC",
-          "SHADOW_DYNAMIC"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserServiceCompat": {
-        "androidx/media/MediaBrowserServiceCompat": [
-          "EPSILON",
-          "RESULT_ERROR",
-          "DEBUG",
-          "RESULT_FLAG_ON_SEARCH_NOT_IMPLEMENTED",
-          "RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED",
-          "KEY_MEDIA_ITEM",
-          "TAG",
-          "SERVICE_INTERFACE",
-          "KEY_SEARCH_RESULTS",
-          "RESULT_OK",
-          "RESULT_PROGRESS_UPDATE",
-          "RESULT_FLAG_OPTION_NOT_HANDLED"
-        ]
-      },
-      "android/support/v13/app/FragmentPagerAdapter": {
-        "androidx/app/legacy/FragmentPagerAdapter": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/design/widget/BaseTransientBottomBar$BaseCallback": {
-        "androidx/design/widget/BaseTransientBottomBar$BaseCallback": [
-          "DISMISS_EVENT_MANUAL",
-          "DISMISS_EVENT_SWIPE",
-          "DISMISS_EVENT_TIMEOUT",
-          "DISMISS_EVENT_ACTION",
-          "DISMISS_EVENT_CONSECUTIVE"
-        ]
-      },
-      "android/support/v7/widget/GapWorker": {
-        "androidx/widget/GapWorker": [
-          "sGapWorker",
-          "sTaskComparator"
-        ]
-      },
-      "android/support/v7/preference/PreferenceManager": {
-        "androidx/preference/PreferenceManager": [
-          "STORAGE_DEFAULT",
-          "KEY_HAS_SET_DEFAULT_VALUES",
-          "STORAGE_DEVICE_PROTECTED"
-        ]
-      },
-      "android/support/v4/widget/SlidingPaneLayout$LayoutParams": {
-        "androidx/widget/SlidingPaneLayout$LayoutParams": [
-          "width",
-          "ATTRS",
-          "height",
-          "dimPaint",
-          "leftMargin",
-          "weight",
-          "slideable",
-          "rightMargin",
-          "dimWhenOffset"
-        ]
-      },
-      "android/support/v17/leanback/widget/GuidedAction": {
-        "androidx/leanback/widget/GuidedAction": [
-          "ACTION_ID_CONTINUE",
-          "PF_ENABLED",
-          "ACTION_ID_YES",
-          "ACTION_ID_OK",
-          "ACTION_ID_NO",
-          "PF_INFO_ONLY",
-          "ACTION_ID_FINISH",
-          "TAG",
-          "EDITING_TITLE",
-          "EDITING_DESCRIPTION",
-          "PF_MULTI_lINE_DESCRIPTION",
-          "PF_CHECKED",
-          "DEFAULT_CHECK_SET_ID",
-          "ACTION_ID_CURRENT",
-          "CHECKBOX_CHECK_SET_ID",
-          "EDITING_NONE",
-          "PF_AUTORESTORE",
-          "EDITING_ACTIVATOR_VIEW",
-          "PF_HAS_NEXT",
-          "ACTION_ID_NEXT",
-          "ACTION_ID_CANCEL",
-          "PF_FOCUSABLE",
-          "NO_CHECK_SET"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$PreviewPrograms": {
-        "androidx/media/tv/TvContractCompat$PreviewPrograms": [
-          "COLUMN_CHANNEL_ID",
-          "CONTENT_ITEM_TYPE",
-          "CONTENT_URI",
-          "CONTENT_TYPE",
-          "COLUMN_WEIGHT"
-        ]
-      },
-      "android/support/v17/leanback/widget/BaseCardView": {
-        "androidx/leanback/widget/BaseCardView": [
-          "CARD_TYPE_INFO_OVER",
-          "CARD_TYPE_INVALID",
-          "DEBUG",
-          "CARD_TYPE_INFO_UNDER",
-          "CARD_TYPE_MAIN_ONLY",
-          "LB_PRESSED_STATE_SET",
-          "CARD_REGION_VISIBLE_ALWAYS",
-          "CARD_REGION_VISIBLE_SELECTED",
-          "TAG",
-          "CARD_TYPE_INFO_UNDER_WITH_EXTRA",
-          "CARD_REGION_VISIBLE_ACTIVATED"
-        ]
-      },
-      "android/support/v7/mediarouter/R$string": {
-        "androidx/mediarouter/R$string": [
-          "mr_user_route_category_name",
-          "mr_controller_no_info_available",
-          "mr_system_route_name",
-          "mr_controller_disconnect",
-          "mr_cast_button_disconnected",
-          "mr_controller_casting_screen",
-          "mr_button_content_description",
-          "mr_controller_no_media_selected",
-          "mr_controller_expand_group",
-          "mr_controller_play",
-          "mr_controller_stop",
-          "mr_cast_button_connected",
-          "mr_controller_pause",
-          "mr_controller_collapse_group",
-          "mr_cast_button_connecting",
-          "mr_controller_stop_casting"
-        ]
-      },
-      "android/support/v4/text/util/LinkifyCompat$LinkSpec": {
-        "androidx/text/util/LinkifyCompat$LinkSpec": [
-          "end",
-          "url",
-          "frameworkAddedSpan",
-          "start"
-        ]
-      },
-      "android/support/transition/ArcMotion": {
-        "androidx/transition/ArcMotion": [
-          "DEFAULT_MIN_ANGLE_DEGREES",
-          "DEFAULT_MAX_ANGLE_DEGREES",
-          "DEFAULT_MAX_TANGENT"
-        ]
-      },
-      "android/support/v17/leanback/widget/TitleViewAdapter": {
-        "androidx/leanback/widget/TitleViewAdapter": [
-          "BRANDING_VIEW_VISIBLE",
-          "FULL_VIEW_VISIBLE",
-          "SEARCH_VIEW_VISIBLE"
-        ]
-      },
-      "android/support/v17/leanback/app/DetailsFragment": {
-        "androidx/leanback/app/DetailsFragment": [
-          "EVT_ON_CREATE",
-          "EVT_SWITCH_TO_VIDEO",
-          "STATE_ENTRANCE_INIT",
-          "STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
-          "STATE_START",
-          "EVT_DETAILS_ROW_LOADED",
-          "STATE_ENTER_TRANSITION_INIT",
-          "STATE_ENTER_TRANSITION_CANCEL",
-          "COND_TRANSITION_NOT_SUPPORTED",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "EVT_NO_ENTER_TRANSITION",
-          "EVT_ON_CREATEVIEW",
-          "STATE_ENTER_TRANSITION_PENDING",
-          "EVT_ONSTART",
-          "STATE_ON_SAFE_START",
-          "DEBUG",
-          "EVT_ENTER_TRANSIITON_DONE",
-          "STATE_SET_ENTRANCE_START_STATE",
-          "STATE_ENTRANCE_PERFORM",
-          "STATE_ENTRANCE_COMPLETE",
-          "STATE_ENTER_TRANSITION_COMPLETE",
-          "STATE_ENTER_TRANSITION_ADDLISTENER",
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/FastScroller": {
-        "androidx/widget/FastScroller": [
-          "ANIMATION_STATE_OUT",
-          "ANIMATION_STATE_IN",
-          "SHOW_DURATION_MS",
-          "STATE_VISIBLE",
-          "DRAG_NONE",
-          "STATE_HIDDEN",
-          "ANIMATION_STATE_FADING_IN",
-          "STATE_DRAGGING",
-          "HIDE_DELAY_AFTER_VISIBLE_MS",
-          "DRAG_X",
-          "DRAG_Y",
-          "HIDE_DELAY_AFTER_DRAGGING_MS",
-          "HIDE_DURATION_MS",
-          "SCROLLBAR_FULL_OPAQUE",
-          "ANIMATION_STATE_FADING_OUT",
-          "PRESSED_STATE_SET",
-          "EMPTY_STATE_SET"
-        ]
-      },
-      "android/support/v7/media/MediaRouteDescriptor": {
-        "androidx/media/MediaRouteDescriptor": [
-          "KEY_VOLUME",
-          "KEY_PLAYBACK_TYPE",
-          "KEY_SETTINGS_INTENT",
-          "KEY_ID",
-          "KEY_ENABLED",
-          "KEY_MAX_CLIENT_VERSION",
-          "KEY_ICON_URI",
-          "KEY_DESCRIPTION",
-          "KEY_PLAYBACK_STREAM",
-          "KEY_GROUP_MEMBER_IDS",
-          "KEY_CONNECTION_STATE",
-          "KEY_EXTRAS",
-          "KEY_VOLUME_HANDLING",
-          "KEY_PRESENTATION_DISPLAY_ID",
-          "KEY_MIN_CLIENT_VERSION",
-          "KEY_CONTROL_FILTERS",
-          "KEY_CAN_DISCONNECT",
-          "KEY_DEVICE_TYPE",
-          "KEY_NAME",
-          "KEY_VOLUME_MAX",
-          "KEY_CONNECTING"
-        ]
-      },
-      "android/support/design/widget/BottomNavigationView": {
-        "androidx/design/widget/BottomNavigationView": [
-          "DISABLED_STATE_SET",
-          "CHECKED_STATE_SET",
-          "EMPTY_STATE_SET",
-          "MENU_PRESENTER_ID"
-        ]
-      },
-      "android/support/wear/widget/drawer/WearableActionDrawerView": {
-        "androidx/wear/widget/drawer/WearableActionDrawerView": [
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/media/PlaybackBaseControlGlue": {
-        "androidx/leanback/media/PlaybackBaseControlGlue": [
-          "ACTION_FAST_FORWARD",
-          "DEBUG",
-          "ACTION_CUSTOM_LEFT_FIRST",
-          "ACTION_SKIP_TO_PREVIOUS",
-          "TAG",
-          "ACTION_SKIP_TO_NEXT",
-          "ACTION_CUSTOM_RIGHT_FIRST",
-          "ACTION_PLAY_PAUSE",
-          "ACTION_REPEAT",
-          "ACTION_REWIND",
-          "ACTION_SHUFFLE"
-        ]
-      },
-      "android/support/v4/app/AppLaunchChecker": {
-        "androidx/app/AppLaunchChecker": [
-          "KEY_STARTED_FROM_LAUNCHER",
-          "SHARED_PREFS_NAME"
-        ]
-      },
-      "android/support/transition/Styleable$ArcMotion": {
-        "androidx/transition/Styleable$ArcMotion": [
-          "MAXIMUM_ANGLE",
-          "MINIMUM_VERTICAL_ANGLE",
-          "MINIMUM_HORIZONTAL_ANGLE"
-        ]
-      },
-      "android/support/v7/cardview/R$color": {
-        "androidx/cardview/R$color": [
-          "cardview_shadow_end_color",
-          "cardview_light_background",
-          "cardview_dark_background",
-          "cardview_shadow_start_color"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseFragment": {
-        "androidx/leanback/app/BrowseFragment": [
-          "TAG",
-          "EVT_SCREEN_DATA_READY",
-          "LB_HEADERS_BACKSTACK",
-          "STATE_ENTRANCE_PERFORM",
-          "IS_PAGE_ROW",
-          "ARG_TITLE",
-          "HEADERS_HIDDEN",
-          "HEADER_SHOW",
-          "EVT_MAIN_FRAGMENT_VIEW_CREATED",
-          "CURRENT_SELECTED_POSITION",
-          "DEBUG",
-          "EVT_HEADER_VIEW_CREATED",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "HEADERS_ENABLED",
-          "ARG_HEADERS_STATE",
-          "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
-          "STATE_SET_ENTRANCE_START_STATE",
-          "HEADERS_DISABLED",
-          "HEADER_STACK_INDEX"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$ProgramColumns": {
-        "androidx/media/tv/TvContractCompat$ProgramColumns": [
-          "COLUMN_SHORT_DESCRIPTION",
-          "COLUMN_SEASON_DISPLAY_NUMBER",
-          "COLUMN_SEASON_TITLE",
-          "COLUMN_VIDEO_WIDTH",
-          "COLUMN_AUDIO_LANGUAGE",
-          "REVIEW_RATING_STYLE_STARS",
-          "COLUMN_EPISODE_TITLE",
-          "REVIEW_RATING_STYLE_THUMBS_UP_DOWN",
-          "COLUMN_INTERNAL_PROVIDER_FLAG2",
-          "COLUMN_INTERNAL_PROVIDER_FLAG3",
-          "COLUMN_INTERNAL_PROVIDER_FLAG4",
-          "COLUMN_INTERNAL_PROVIDER_FLAG1",
-          "COLUMN_TITLE",
-          "COLUMN_POSTER_ART_URI",
-          "COLUMN_VERSION_NUMBER",
-          "COLUMN_THUMBNAIL_URI",
-          "REVIEW_RATING_STYLE_PERCENTAGE",
-          "COLUMN_EPISODE_DISPLAY_NUMBER",
-          "COLUMN_SEARCHABLE",
-          "COLUMN_VIDEO_HEIGHT",
-          "COLUMN_CANONICAL_GENRE",
-          "COLUMN_CONTENT_RATING",
-          "COLUMN_REVIEW_RATING",
-          "COLUMN_REVIEW_RATING_STYLE",
-          "COLUMN_LONG_DESCRIPTION",
-          "COLUMN_INTERNAL_PROVIDER_DATA"
-        ]
-      },
-      "android/support/v4/graphics/PaintCompat": {
-        "androidx/graphics/PaintCompat": [
-          "TOFU_STRING",
-          "sRectThreadLocal",
-          "EM_STRING"
-        ]
-      },
-      "android/support/v4/view/accessibility/AccessibilityEventCompat": {
-        "androidx/view/accessibility/AccessibilityEventCompat": [
-          "CONTENT_CHANGE_TYPE_UNDEFINED",
-          "TYPE_ANNOUNCEMENT",
-          "TYPE_TOUCH_INTERACTION_END",
-          "CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION",
-          "TYPE_TOUCH_INTERACTION_START",
-          "TYPE_TOUCH_EXPLORATION_GESTURE_END",
-          "TYPE_VIEW_HOVER_ENTER",
-          "TYPE_VIEW_ACCESSIBILITY_FOCUSED",
-          "CONTENT_CHANGE_TYPE_TEXT",
-          "TYPE_WINDOW_CONTENT_CHANGED",
-          "TYPES_ALL_MASK",
-          "TYPE_TOUCH_EXPLORATION_GESTURE_START",
-          "TYPE_WINDOWS_CHANGED",
-          "TYPE_VIEW_CONTEXT_CLICKED",
-          "TYPE_VIEW_HOVER_EXIT",
-          "CONTENT_CHANGE_TYPE_SUBTREE",
-          "TYPE_ASSIST_READING_CONTEXT",
-          "TYPE_VIEW_TEXT_SELECTION_CHANGED",
-          "TYPE_GESTURE_DETECTION_START",
-          "TYPE_VIEW_SCROLLED",
-          "TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY",
-          "TYPE_GESTURE_DETECTION_END",
-          "TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED"
-        ]
-      },
-      "android/support/v17/leanback/R$attr": {
-        "androidx/leanback/R$attr": [
-          "guidedActionContentWidthWeightTwoPanels",
-          "onboardingTheme",
-          "playbackProgressPrimaryColor",
-          "guidedActionTitleMaxLines",
-          "guidedActionPressedAnimation",
-          "playbackMediaItemNumberViewFlipperLayout",
-          "imageCardViewStyle",
-          "playbackControlsActionIcons",
-          "browseTitleViewLayout",
-          "playbackControlsIconHighlightColor",
-          "guidedStepTheme",
-          "guidedActionTitleMinLines",
-          "defaultBrandColorDark",
-          "baseCardViewStyle",
-          "browseTitleViewStyle",
-          "guidedActionVerticalPadding",
-          "guidedActionDisabledChevronAlpha",
-          "searchOrbViewStyle",
-          "defaultBrandColor",
-          "guidedStepThemeFlag",
-          "rowHeaderStyle",
-          "guidedActionDescriptionMinLines",
-          "guidedActionUnpressedAnimation",
-          "guidedActionEnabledChevronAlpha"
-        ]
-      },
-      "android/support/media/ExifInterface$ExifTag": {
-        "androidx/media/ExifInterface$ExifTag": [
-          "number",
-          "primaryFormat",
-          "name",
-          "secondaryFormat"
-        ]
-      },
-      "android/support/v4/widget/ContentLoadingProgressBar": {
-        "androidx/widget/ContentLoadingProgressBar": [
-          "MIN_DELAY",
-          "MIN_SHOW_TIME"
-        ]
-      },
-      "android/support/transition/ViewGroupUtilsApi14": {
-        "androidx/transition/ViewGroupUtilsApi14": [
-          "TAG",
-          "LAYOUT_TRANSITION_CHANGING",
-          "sEmptyLayoutTransition",
-          "sCancelMethod",
-          "sLayoutSuppressedField",
-          "sCancelMethodFetched",
-          "sLayoutSuppressedFieldFetched"
-        ]
-      },
-      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuAdapter": {
-        "androidx/design/internal/NavigationMenuPresenter$NavigationMenuAdapter": [
-          "STATE_ACTION_VIEWS",
-          "VIEW_TYPE_SEPARATOR",
-          "VIEW_TYPE_HEADER",
-          "VIEW_TYPE_SUBHEADER",
-          "VIEW_TYPE_NORMAL",
-          "STATE_CHECKED_ITEM"
-        ]
-      },
-      "android/support/v4/os/LocaleListHelper": {
-        "androidx/os/LocaleListHelper": [
-          "EN_LATN",
-          "LOCALE_EN_XA",
-          "sDefaultAdjustedLocaleList",
-          "sLock",
-          "sLastExplicitlySetLocaleList",
-          "sEmptyLocaleList",
-          "sEmptyList",
-          "NUM_PSEUDO_LOCALES",
-          "STRING_AR_XB",
-          "sDefaultLocaleList",
-          "sLastDefaultLocale",
-          "STRING_EN_XA",
-          "LOCALE_AR_XB"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$CarExtender": {
-        "androidx/app/NotificationCompat$CarExtender": [
-          "KEY_TIMESTAMP",
-          "EXTRA_LARGE_ICON",
-          "KEY_ON_READ",
-          "KEY_PARTICIPANTS",
-          "KEY_ON_REPLY",
-          "KEY_AUTHOR",
-          "KEY_REMOTE_INPUT",
-          "KEY_TEXT",
-          "KEY_MESSAGES",
-          "EXTRA_CAR_EXTENDER",
-          "EXTRA_COLOR",
-          "EXTRA_CONVERSATION"
-        ]
-      },
-      "android/support/wear/R$layout": {
-        "androidx/wear/R$layout": [
-          "ws_navigation_drawer_item_view",
-          "ws_single_page_nav_drawer_7_item",
-          "ws_single_page_nav_drawer_4_item",
-          "ws_action_drawer_item_view",
-          "ws_single_page_nav_drawer_2_item",
-          "ws_navigation_drawer_view",
-          "ws_single_page_nav_drawer_5_item",
-          "ws_wearable_drawer_view",
-          "ws_single_page_nav_drawer_3_item",
-          "ws_single_page_nav_drawer_peek_view",
-          "ws_action_drawer_title_view",
-          "ws_action_drawer_peek_view",
-          "ws_single_page_nav_drawer_1_item",
-          "ws_single_page_nav_drawer_6_item"
-        ]
-      },
-      "android/support/v4/content/pm/ActivityInfoCompat": {
-        "androidx/content/pm/ActivityInfoCompat": [
-          "CONFIG_UI_MODE"
-        ]
-      },
-      "android/support/v7/mediarouter/R$layout": {
-        "androidx/mediarouter/R$layout": [
-          "mr_chooser_dialog",
-          "mr_controller_material_dialog_b",
-          "mr_chooser_list_item",
-          "mr_controller_volume_item"
-        ]
-      },
-      "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState": {
-        "androidx/app/AppCompatDelegateImplV9$PanelFeatureState": [
-          "x",
-          "y",
-          "frozenActionViewState",
-          "refreshDecorView",
-          "createdPanelView",
-          "frozenMenuState",
-          "qwertyMode",
-          "featureId",
-          "listPresenterContext",
-          "listMenuPresenter",
-          "decorView",
-          "isPrepared",
-          "wasLastOpen",
-          "isOpen",
-          "gravity",
-          "background",
-          "isHandled",
-          "windowAnimations",
-          "refreshMenuContent",
-          "shownPanelView",
-          "menu"
-        ]
-      },
-      "android/support/v4/graphics/TypefaceCompatBaseImpl": {
-        "androidx/graphics/TypefaceCompatBaseImpl": [
-          "TAG",
-          "CACHE_FILE_PREFIX"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$PreviewProgramColumns": {
-        "androidx/media/tv/TvContractCompat$PreviewProgramColumns": [
-          "COLUMN_DURATION_MILLIS",
-          "COLUMN_LIVE",
-          "COLUMN_OFFER_PRICE",
-          "AVAILABILITY_PURCHASED",
-          "COLUMN_INTERACTION_COUNT",
-          "INTERACTION_TYPE_FOLLOWERS",
-          "INTERACTION_TYPE_FANS",
-          "COLUMN_GENRE",
-          "INTERACTION_TYPE_LISTENS",
-          "AVAILABILITY_PAID_CONTENT",
-          "COLUMN_START_TIME_UTC_MILLIS",
-          "COLUMN_INTERACTION_TYPE",
-          "TYPE_MOVIE",
-          "TYPE_GAME",
-          "TYPE_ALBUM",
-          "TYPE_TRACK",
-          "COLUMN_POSTER_ART_ASPECT_RATIO",
-          "TYPE_EVENT",
-          "COLUMN_AVAILABILITY",
-          "COLUMN_BROWSABLE",
-          "COLUMN_INTENT_URI",
-          "COLUMN_LOGO_URI",
-          "TYPE_TV_SERIES",
-          "COLUMN_ITEM_COUNT",
-          "INTERACTION_TYPE_VIEWS",
-          "COLUMN_PREVIEW_AUDIO_URI",
-          "AVAILABILITY_FREE_WITH_SUBSCRIPTION",
-          "COLUMN_PREVIEW_VIDEO_URI",
-          "COLUMN_LAST_PLAYBACK_POSITION_MILLIS",
-          "COLUMN_END_TIME_UTC_MILLIS",
-          "ASPECT_RATIO_4_3",
-          "INTERACTION_TYPE_THUMBS",
-          "INTERACTION_TYPE_VIEWERS",
-          "COLUMN_TYPE",
-          "ASPECT_RATIO_3_2",
-          "COLUMN_AUTHOR",
-          "TYPE_TV_EPISODE",
-          "ASPECT_RATIO_1_1",
-          "ASPECT_RATIO_2_3",
-          "COLUMN_INTERNAL_PROVIDER_ID",
-          "ASPECT_RATIO_MOVIE_POSTER",
-          "TYPE_CHANNEL",
-          "COLUMN_LOGO_CONTENT_DESCRIPTION",
-          "AVAILABILITY_FREE",
-          "COLUMN_TRANSIENT",
-          "TYPE_STATION",
-          "INTERACTION_TYPE_LIKES",
-          "TYPE_TV_SEASON",
-          "AVAILABILITY_AVAILABLE",
-          "TYPE_PLAYLIST",
-          "ASPECT_RATIO_16_9",
-          "COLUMN_RELEASE_DATE",
-          "COLUMN_CONTENT_ID",
-          "TYPE_ARTIST",
-          "COLUMN_THUMBNAIL_ASPECT_RATIO",
-          "COLUMN_STARTING_PRICE",
-          "TYPE_CLIP"
-        ]
-      },
-      "android/support/wear/widget/BoxInsetLayout": {
-        "androidx/wear/widget/BoxInsetLayout": [
-          "FACTOR",
-          "DEFAULT_CHILD_GRAVITY"
-        ]
-      },
-      "android/support/v7/graphics/ColorCutQuantizer": {
-        "androidx/graphics/palette/ColorCutQuantizer": [
-          "LOG_TAG",
-          "COMPONENT_GREEN",
-          "VBOX_COMPARATOR_VOLUME",
-          "LOG_TIMINGS",
-          "COMPONENT_RED",
-          "COMPONENT_BLUE",
-          "QUANTIZE_WORD_WIDTH",
-          "QUANTIZE_WORD_MASK"
-        ]
-      },
-      "android/support/text/emoji/flatbuffer/Struct": {
-        "androidx/text/emoji/flatbuffer/Struct": [
-          "bb",
-          "bb_pos"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat": {
-        "androidx/media/session/MediaSessionCompat": [
-          "TAG",
-          "EXTRA_BINDER",
-          "ARGUMENT_MEDIA_ATTRIBUTE_VALUE",
-          "ACTION_PREPARE_FROM_MEDIA_ID",
-          "ACTION_FLAG_AS_INAPPROPRIATE",
-          "ACTION_SET_CAPTIONING_ENABLED",
-          "MEDIA_ATTRIBUTE_PLAYLIST",
-          "sMaxBitmapSize",
-          "MAX_BITMAP_SIZE_IN_DP",
-          "FLAG_HANDLES_MEDIA_BUTTONS",
-          "ACTION_ARGUMENT_CAPTIONING_ENABLED",
-          "ACTION_SET_SHUFFLE_MODE",
-          "ACTION_ARGUMENT_EXTRAS",
-          "ACTION_SKIP_AD",
-          "ACTION_ARGUMENT_REPEAT_MODE",
-          "FLAG_HANDLES_TRANSPORT_CONTROLS",
-          "ACTION_ARGUMENT_QUERY",
-          "ACTION_ARGUMENT_MEDIA_ID",
-          "ACTION_PREPARE_FROM_SEARCH",
-          "FLAG_HANDLES_QUEUE_COMMANDS",
-          "ACTION_UNFOLLOW",
-          "ACTION_ARGUMENT_RATING",
-          "ACTION_ARGUMENT_URI",
-          "ACTION_PLAY_FROM_URI",
-          "MEDIA_ATTRIBUTE_ALBUM",
-          "ACTION_SET_RATING",
-          "ACTION_SET_REPEAT_MODE",
-          "ACTION_ARGUMENT_SHUFFLE_MODE",
-          "ACTION_FOLLOW",
-          "ACTION_PREPARE_FROM_URI",
-          "ACTION_PREPARE",
-          "ARGUMENT_MEDIA_ATTRIBUTE",
-          "MEDIA_ATTRIBUTE_ARTIST"
-        ]
-      },
-      "android/support/v17/leanback/widget/GridLayoutManager": {
-        "androidx/leanback/widget/GridLayoutManager": [
-          "PREV_ROW",
-          "NEXT_ITEM",
-          "DEBUG",
-          "DEFAULT_MAX_PENDING_MOVES",
-          "TRACE",
-          "MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN",
-          "sTempRect",
-          "NEXT_ROW",
-          "TAG",
-          "PREV_ITEM",
-          "sTwoInts"
-        ]
-      },
-      "android/support/v4/util/TimeUtils": {
-        "androidx/util/TimeUtils": [
-          "HUNDRED_DAY_FIELD_LEN",
-          "SECONDS_PER_MINUTE",
-          "sFormatSync",
-          "sFormatStr",
-          "SECONDS_PER_DAY",
-          "SECONDS_PER_HOUR"
-        ]
-      },
-      "android/support/v4/view/accessibility/AccessibilityWindowInfoCompat": {
-        "androidx/view/accessibility/AccessibilityWindowInfoCompat": [
-          "TYPE_APPLICATION",
-          "TYPE_SYSTEM",
-          "TYPE_ACCESSIBILITY_OVERLAY",
-          "TYPE_INPUT_METHOD",
-          "UNDEFINED",
-          "TYPE_SPLIT_SCREEN_DIVIDER"
-        ]
-      },
-      "android/support/v17/leanback/app/VerticalGridFragment": {
-        "androidx/leanback/app/VerticalGridFragment": [
-          "STATE_SET_ENTRANCE_START_STATE",
-          "EVT_ON_CREATEVIEW",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v4/app/FrameMetricsAggregator": {
-        "androidx/app/FrameMetricsAggregator": [
-          "COMMAND_INDEX",
-          "SWAP_DURATION",
-          "SYNC_INDEX",
-          "ANIMATION_INDEX",
-          "LAYOUT_MEASURE_DURATION",
-          "INPUT_INDEX",
-          "TOTAL_INDEX",
-          "LAST_INDEX",
-          "LAYOUT_MEASURE_INDEX",
-          "DELAY_DURATION",
-          "COMMAND_DURATION",
-          "DBG",
-          "INPUT_DURATION",
-          "SWAP_INDEX",
-          "SYNC_DURATION",
-          "TOTAL_DURATION",
-          "TAG",
-          "ANIMATION_DURATION",
-          "DRAW_DURATION",
-          "DRAW_INDEX",
-          "EVERY_DURATION",
-          "DELAY_INDEX"
-        ]
-      },
-      "android/support/design/widget/FloatingActionButtonImpl": {
-        "androidx/design/widget/FloatingActionButtonImpl": [
-          "PRESSED_ENABLED_STATE_SET",
-          "PRESSED_ANIM_DURATION",
-          "PRESSED_ANIM_DELAY",
-          "FOCUSED_ENABLED_STATE_SET",
-          "ANIM_STATE_NONE",
-          "EMPTY_STATE_SET",
-          "ANIM_INTERPOLATOR",
-          "ENABLED_STATE_SET",
-          "ANIM_STATE_SHOWING",
-          "SHOW_HIDE_ANIM_DURATION",
-          "ANIM_STATE_HIDING"
-        ]
-      },
-      "android/support/transition/R$id": {
-        "androidx/transition/R$id": [
-          "transition_transform",
-          "ghost_view",
-          "transition_scene_layoutid_cache",
-          "save_image_matrix",
-          "save_scale_type",
-          "transition_current_scene",
-          "transition_layout_save",
-          "parent_matrix",
-          "transition_position",
-          "save_non_transition_alpha"
-        ]
-      },
-      "android/support/v7/app/ResourcesFlusher": {
-        "androidx/app/ResourcesFlusher": [
-          "sDrawableCacheField",
-          "sThemedResourceCacheClazz",
-          "sResourcesImplFieldFetched",
-          "sDrawableCacheFieldFetched",
-          "TAG",
-          "sThemedResourceCacheClazzFetched",
-          "sResourcesImplField",
-          "sThemedResourceCache_mUnthemedEntriesFieldFetched",
-          "sThemedResourceCache_mUnthemedEntriesField"
-        ]
-      },
-      "android/support/v4/app/RemoteInput": {
-        "androidx/app/RemoteInput": [
-          "EXTRA_RESULTS_DATA",
-          "TAG",
-          "RESULTS_CLIP_LABEL",
-          "EXTRA_DATA_TYPE_RESULTS_DATA"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$Programs$Genres": {
-        "androidx/media/tv/TvContractCompat$Programs$Genres": [
-          "EDUCATION",
-          "DELIMITER",
-          "LIFE_STYLE",
-          "SPORTS",
-          "GAMING",
-          "TECH_SCIENCE",
-          "DOUBLE_QUOTE",
-          "TRAVEL",
-          "CANONICAL_GENRES",
-          "MOVIES",
-          "FAMILY_KIDS",
-          "NEWS",
-          "ENTERTAINMENT",
-          "PREMIER",
-          "ARTS",
-          "EMPTY_STRING_ARRAY",
-          "DRAMA",
-          "MUSIC",
-          "COMMA",
-          "COMEDY",
-          "SHOPPING",
-          "ANIMAL_WILDLIFE"
-        ]
-      },
-      "android/support/v4/view/GravityCompat": {
-        "androidx/view/GravityCompat": [
-          "START",
-          "END",
-          "RELATIVE_LAYOUT_DIRECTION",
-          "RELATIVE_HORIZONTAL_GRAVITY_MASK"
-        ]
-      },
-      "android/support/design/R$color": {
-        "androidx/design/R$color": [
-          "design_fab_shadow_start_color",
-          "design_bottom_navigation_shadow_color",
-          "design_fab_stroke_end_outer_color",
-          "design_fab_shadow_mid_color",
-          "design_fab_stroke_end_inner_color",
-          "design_fab_shadow_end_color",
-          "design_fab_stroke_top_inner_color",
-          "design_fab_stroke_top_outer_color"
-        ]
-      },
-      "android/support/v4/view/LayoutInflaterCompat": {
-        "androidx/view/LayoutInflaterCompat": [
-          "sLayoutInflaterFactory2Field",
-          "TAG",
-          "sCheckedField",
-          "IMPL"
-        ]
-      },
-      "android/support/v13/view/inputmethod/EditorInfoCompat": {
-        "androidx/view/inputmethod/EditorInfoCompat": [
-          "IMPL",
-          "IME_FLAG_NO_PERSONALIZED_LEARNING",
-          "EMPTY_STRING_ARRAY",
-          "IME_FLAG_FORCE_ASCII"
-        ]
-      },
-      "android/support/v17/leanback/app/OnboardingSupportFragment": {
-        "androidx/leanback/app/OnboardingSupportFragment": [
-          "KEY_ENTER_ANIMATION_FINISHED",
-          "KEY_CURRENT_PAGE_INDEX",
-          "DEBUG",
-          "HEADER_DISAPPEAR_INTERPOLATOR",
-          "sSlideDistance",
-          "LOGO_SPLASH_PAUSE_DURATION_MS",
-          "HEADER_APPEAR_DELAY_MS",
-          "HEADER_ANIMATION_DURATION_MS",
-          "TAG",
-          "HEADER_APPEAR_INTERPOLATOR",
-          "DESCRIPTION_START_DELAY_MS",
-          "SLIDE_DISTANCE",
-          "KEY_LOGO_ANIMATION_FINISHED"
-        ]
-      },
-      "android/support/v4/app/BackStackRecord": {
-        "androidx/app/BackStackRecord": [
-          "TAG",
-          "OP_SET_PRIMARY_NAV",
-          "OP_DETACH",
-          "OP_NULL",
-          "OP_UNSET_PRIMARY_NAV",
-          "OP_REMOVE",
-          "OP_HIDE",
-          "OP_SHOW",
-          "OP_ADD",
-          "OP_REPLACE",
-          "OP_ATTACH"
-        ]
-      },
-      "android/support/v7/util/DiffUtil$DiffResult": {
-        "androidx/util/DiffUtil$DiffResult": [
-          "FLAG_MOVED_CHANGED",
-          "FLAG_IGNORE",
-          "FLAG_MASK",
-          "FLAG_OFFSET",
-          "FLAG_MOVED_NOT_CHANGED",
-          "FLAG_CHANGED",
-          "FLAG_NOT_CHANGED"
-        ]
-      },
-      "android/support/wear/widget/drawer/WearableDrawerView": {
-        "androidx/wear/widget/drawer/WearableDrawerView": [
-          "STATE_DRAGGING",
-          "STATE_SETTLING",
-          "STATE_IDLE"
-        ]
-      },
-      "android/support/wear/R$string": {
-        "androidx/wear/R$string": [
-          "ws_action_drawer_content_description",
-          "ws_navigation_drawer_content_description"
-        ]
-      },
-      "android/support/design/widget/SwipeDismissBehavior": {
-        "androidx/design/widget/SwipeDismissBehavior": [
-          "DEFAULT_ALPHA_START_DISTANCE",
-          "STATE_IDLE",
-          "STATE_DRAGGING",
-          "SWIPE_DIRECTION_START_TO_END",
-          "DEFAULT_ALPHA_END_DISTANCE",
-          "DEFAULT_DRAG_DISMISS_THRESHOLD",
-          "SWIPE_DIRECTION_ANY",
-          "STATE_SETTLING",
-          "SWIPE_DIRECTION_END_TO_START"
-        ]
-      },
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper": {
-        "androidx/leanback/widget/FullWidthDetailsOverviewSharedElementHelper": [
-          "DEFAULT_TIMEOUT",
-          "TAG",
-          "DEBUG"
-        ]
-      },
-      "android/support/transition/Styleable$TransitionTarget": {
-        "androidx/transition/Styleable$TransitionTarget": [
-          "EXCLUDE_CLASS",
-          "EXCLUDE_ID",
-          "TARGET_CLASS",
-          "EXCLUDE_NAME",
-          "TARGET_ID",
-          "TARGET_NAME"
-        ]
-      },
-      "android/support/v4/media/MediaDescriptionCompat": {
-        "androidx/media/MediaDescriptionCompat": [
-          "BT_FOLDER_TYPE_MIXED",
-          "CREATOR",
-          "STATUS_DOWNLOADED",
-          "STATUS_NOT_DOWNLOADED",
-          "EXTRA_BT_FOLDER_TYPE",
-          "BT_FOLDER_TYPE_GENRES",
-          "EXTRA_DOWNLOAD_STATUS",
-          "DESCRIPTION_KEY_MEDIA_URI",
-          "BT_FOLDER_TYPE_ARTISTS",
-          "DESCRIPTION_KEY_NULL_BUNDLE_FLAG",
-          "BT_FOLDER_TYPE_TITLES",
-          "STATUS_DOWNLOADING",
-          "BT_FOLDER_TYPE_YEARS",
-          "BT_FOLDER_TYPE_PLAYLISTS",
-          "BT_FOLDER_TYPE_ALBUMS"
-        ]
-      },
-      "android/support/v4/graphics/ColorUtils": {
-        "androidx/graphics/ColorUtils": [
-          "MIN_ALPHA_SEARCH_MAX_ITERATIONS",
-          "XYZ_KAPPA",
-          "MIN_ALPHA_SEARCH_PRECISION",
-          "TEMP_ARRAY",
-          "XYZ_WHITE_REFERENCE_Z",
-          "XYZ_WHITE_REFERENCE_Y",
-          "XYZ_WHITE_REFERENCE_X",
-          "XYZ_EPSILON"
-        ]
-      },
-      "android/support/v7/widget/AppCompatTextViewAutoSizeHelper": {
-        "androidx/widget/AppCompatTextViewAutoSizeHelper": [
-          "TAG",
-          "DEFAULT_AUTO_SIZE_GRANULARITY_IN_PX",
-          "UNSET_AUTO_SIZE_UNIFORM_CONFIGURATION_VALUE",
-          "DEFAULT_AUTO_SIZE_MIN_TEXT_SIZE_IN_SP",
-          "VERY_WIDE",
-          "sTextViewMethodByNameCache",
-          "DEFAULT_AUTO_SIZE_MAX_TEXT_SIZE_IN_SP",
-          "TEMP_RECTF"
-        ]
-      },
-      "android/support/design/R$style": {
-        "androidx/design/R$style": [
-          "Widget_Design_ScrimInsetsFrameLayout",
-          "Widget_Design_TextInputLayout",
-          "Widget_Design_TabLayout",
-          "Widget_Design_CollapsingToolbar",
-          "Widget_Design_NavigationView",
-          "TextAppearance_Design_Tab",
-          "Widget_Design_CoordinatorLayout",
-          "Theme_Design_Light_BottomSheetDialog",
-          "Widget_Design_FloatingActionButton",
-          "Widget_Design_AppBarLayout",
-          "Widget_Design_BottomNavigationView",
-          "TextAppearance_Design_CollapsingToolbar_Expanded"
-        ]
-      },
-      "android/support/v7/widget/GridLayoutManager": {
-        "androidx/widget/GridLayoutManager": [
-          "TAG",
-          "DEFAULT_SPAN_COUNT",
-          "DEBUG"
-        ]
-      },
-      "android/support/v7/appcompat/R$dimen": {
-        "androidx/appcompat/R$dimen": [
-          "tooltip_precise_anchor_extra_offset",
-          "abc_dropdownitem_icon_width",
-          "tooltip_precise_anchor_threshold",
-          "tooltip_y_offset_non_touch",
-          "abc_config_prefDialogWidth",
-          "abc_dropdownitem_text_padding_left",
-          "abc_action_bar_stacked_max_height",
-          "abc_search_view_preferred_height",
-          "abc_cascading_menus_min_smallest_width",
-          "abc_action_bar_stacked_tab_max_width",
-          "tooltip_y_offset_touch",
-          "abc_search_view_preferred_width"
-        ]
-      },
-      "android/support/wear/internal/widget/drawer/SinglePageUi": {
-        "androidx/wear/internal/widget/drawer/SinglePageUi": [
-          "SINGLE_PAGE_LAYOUT_RES",
-          "SINGLE_PAGE_BUTTON_IDS"
-        ]
-      },
-      "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": {
-        "androidx/accessibilityservice/AccessibilityServiceInfoCompat": [
-          "FLAG_REQUEST_TOUCH_EXPLORATION_MODE",
-          "CAPABILITY_CAN_FILTER_KEY_EVENTS",
-          "FLAG_INCLUDE_NOT_IMPORTANT_VIEWS",
-          "CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY",
-          "CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT",
-          "FEEDBACK_BRAILLE",
-          "FEEDBACK_ALL_MASK",
-          "FLAG_REPORT_VIEW_IDS",
-          "CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION",
-          "FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY",
-          "FLAG_REQUEST_FILTER_KEY_EVENTS"
-        ]
-      },
-      "android/support/graphics/drawable/AnimatorInflaterCompat": {
-        "androidx/graphics/drawable/AnimatorInflaterCompat": [
-          "MAX_NUM_POINTS",
-          "VALUE_TYPE_INT",
-          "VALUE_TYPE_FLOAT",
-          "VALUE_TYPE_COLOR",
-          "TAG",
-          "DBG_ANIMATOR_INFLATER",
-          "VALUE_TYPE_PATH",
-          "TOGETHER",
-          "VALUE_TYPE_UNDEFINED"
-        ]
-      },
-      "android/support/wear/R$id": {
-        "androidx/wear/R$id": [
-          "ws_navigation_drawer_item_icon",
-          "ws_drawer_view_peek_container",
-          "ws_navigation_drawer_item_text",
-          "ws_action_drawer_item_text",
-          "ws_drawer_view_peek_icon",
-          "ws_nav_drawer_icon_4",
-          "ws_nav_drawer_icon_5",
-          "ws_nav_drawer_icon_6",
-          "ws_nav_drawer_icon_0",
-          "ws_nav_drawer_icon_1",
-          "ws_nav_drawer_icon_2",
-          "ws_nav_drawer_icon_3",
-          "ws_navigation_drawer_page_indicator",
-          "ws_navigation_drawer_view_pager",
-          "ws_nav_drawer_text",
-          "ws_action_drawer_expand_icon",
-          "ws_action_drawer_item_icon",
-          "ws_action_drawer_title",
-          "ws_action_drawer_peek_action_icon"
-        ]
-      },
-      "android/support/v4/view/animation/LinearOutSlowInInterpolator": {
-        "androidx/view/animation/LinearOutSlowInInterpolator": [
-          "VALUES"
-        ]
-      },
-      "android/support/v4/graphics/TypefaceCompatApi24Impl": {
-        "androidx/graphics/TypefaceCompatApi24Impl": [
-          "FONT_FAMILY_CLASS",
-          "sFontFamily",
-          "TAG",
-          "sAddFontWeightStyle",
-          "sFontFamilyCtor",
-          "sCreateFromFamiliesWithDefault",
-          "ADD_FONT_WEIGHT_STYLE_METHOD",
-          "CREATE_FROM_FAMILIES_WITH_DEFAULT_METHOD"
-        ]
-      },
-      "android/support/v7/widget/AdapterHelper": {
-        "androidx/widget/AdapterHelper": [
-          "TAG",
-          "POSITION_TYPE_NEW_OR_LAID_OUT",
-          "DEBUG",
-          "POSITION_TYPE_INVISIBLE"
-        ]
-      },
-      "android/support/v4/media/session/ParcelableVolumeInfo": {
-        "androidx/media/session/ParcelableVolumeInfo": [
-          "audioStream",
-          "currentVolume",
-          "maxVolume",
-          "volumeType",
-          "CREATOR",
-          "controlType"
-        ]
-      },
-      "android/support/text/emoji/EmojiCompat": {
-        "androidx/text/emoji/EmojiCompat": [
-          "EDITOR_INFO_REPLACE_ALL_KEY",
-          "sInstanceLock",
-          "EMOJI_COUNT_UNLIMITED",
-          "LOAD_STATE_SUCCEEDED",
-          "EDITOR_INFO_METAVERSION_KEY",
-          "sInstance",
-          "REPLACE_STRATEGY_ALL",
-          "LOAD_STATE_FAILED",
-          "REPLACE_STRATEGY_NON_EXISTENT",
-          "LOAD_STATE_LOADING",
-          "REPLACE_STRATEGY_DEFAULT"
-        ]
-      },
-      "android/support/v7/graphics/Target": {
-        "androidx/graphics/palette/Target": [
-          "TARGET_MUTED_SATURATION",
-          "MUTED",
-          "MIN_NORMAL_LUMA",
-          "MAX_DARK_LUMA",
-          "VIBRANT",
-          "TARGET_LIGHT_LUMA",
-          "TARGET_NORMAL_LUMA",
-          "MAX_NORMAL_LUMA",
-          "WEIGHT_LUMA",
-          "INDEX_WEIGHT_LUMA",
-          "TARGET_VIBRANT_SATURATION",
-          "DARK_MUTED",
-          "DARK_VIBRANT",
-          "INDEX_MAX",
-          "INDEX_MIN",
-          "MAX_MUTED_SATURATION",
-          "MIN_LIGHT_LUMA",
-          "LIGHT_VIBRANT",
-          "LIGHT_MUTED",
-          "INDEX_TARGET",
-          "INDEX_WEIGHT_POP",
-          "TARGET_DARK_LUMA",
-          "WEIGHT_POPULATION",
-          "INDEX_WEIGHT_SAT",
-          "WEIGHT_SATURATION",
-          "MIN_VIBRANT_SATURATION"
-        ]
-      },
-      "android/support/v17/leanback/media/PlaybackControlGlue": {
-        "androidx/leanback/media/PlaybackControlGlue": [
-          "MSG_UPDATE_PLAYBACK_STATE",
-          "PLAYBACK_SPEED_INVALID",
-          "ACTION_REWIND",
-          "sHandler",
-          "ACTION_FAST_FORWARD",
-          "PLAYBACK_SPEED_FAST_L2",
-          "PLAYBACK_SPEED_FAST_L3",
-          "PLAYBACK_SPEED_FAST_L4",
-          "PLAYBACK_SPEED_FAST_L0",
-          "PLAYBACK_SPEED_FAST_L1",
-          "DEBUG",
-          "PLAYBACK_SPEED_PAUSED",
-          "UPDATE_PLAYBACK_STATE_DELAY_MS",
-          "PLAYBACK_SPEED_NORMAL",
-          "TAG",
-          "ACTION_SKIP_TO_NEXT",
-          "ACTION_SKIP_TO_PREVIOUS",
-          "ACTION_CUSTOM_LEFT_FIRST",
-          "ACTION_PLAY_PAUSE",
-          "NUMBER_OF_SEEK_SPEEDS",
-          "ACTION_CUSTOM_RIGHT_FIRST"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$LayoutParams": {
-        "androidx/widget/GridLayout$LayoutParams": [
-          "bottomMargin",
-          "DEFAULT_SPAN",
-          "COLUMN_WEIGHT",
-          "leftMargin",
-          "GRAVITY",
-          "ROW_SPAN",
-          "ROW",
-          "COLUMN",
-          "topMargin",
-          "RIGHT_MARGIN",
-          "height",
-          "COLUMN_SPAN",
-          "rightMargin",
-          "width",
-          "ROW_WEIGHT",
-          "BOTTOM_MARGIN",
-          "DEFAULT_SPAN_SIZE",
-          "columnSpec",
-          "DEFAULT_ROW",
-          "DEFAULT_WIDTH",
-          "MARGIN",
-          "rowSpec",
-          "TOP_MARGIN",
-          "DEFAULT_HEIGHT",
-          "LEFT_MARGIN",
-          "DEFAULT_COLUMN",
-          "DEFAULT_MARGIN"
-        ]
-      },
-      "android/support/v17/leanback/app/DetailsSupportFragment": {
-        "androidx/leanback/app/DetailsSupportFragment": [
-          "EVT_ONSTART",
-          "STATE_ENTER_TRANSITION_CANCEL",
-          "DEBUG",
-          "STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
-          "STATE_ENTRANCE_COMPLETE",
-          "STATE_ENTER_TRANSITION_COMPLETE",
-          "STATE_ENTER_TRANSITION_ADDLISTENER",
-          "STATE_ENTRANCE_INIT",
-          "EVT_SWITCH_TO_VIDEO",
-          "STATE_START",
-          "STATE_ON_SAFE_START",
-          "STATE_ENTRANCE_PERFORM",
-          "EVT_ON_CREATEVIEW",
-          "STATE_SET_ENTRANCE_START_STATE",
-          "COND_TRANSITION_NOT_SUPPORTED",
-          "TAG",
-          "STATE_ENTER_TRANSITION_PENDING",
-          "EVT_ENTER_TRANSIITON_DONE",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "EVT_ON_CREATE",
-          "EVT_DETAILS_ROW_LOADED",
-          "STATE_ENTER_TRANSITION_INIT",
-          "EVT_NO_ENTER_TRANSITION"
-        ]
-      },
-      "android/support/v17/leanback/app/ListRowDataAdapter": {
-        "androidx/leanback/app/ListRowDataAdapter": [
-          "ON_ITEM_RANGE_INSERTED",
-          "ON_ITEM_RANGE_CHANGED",
-          "ON_ITEM_RANGE_REMOVED",
-          "ON_CHANGED"
-        ]
-      },
-      "android/support/percent/PercentLayoutHelper$PercentLayoutInfo": {
-        "androidx/PercentLayoutHelper$PercentLayoutInfo": [
-          "topMarginPercent",
-          "endMarginPercent",
-          "aspectRatio",
-          "rightMarginPercent",
-          "heightPercent",
-          "leftMarginPercent",
-          "startMarginPercent",
-          "bottomMarginPercent",
-          "widthPercent"
-        ]
-      },
-      "android/support/v17/leanback/system/Settings": {
-        "androidx/leanback/system/Settings": [
-          "OUTLINE_CLIPPING_DISABLED",
-          "PREFER_STATIC_SHADOWS",
-          "DEBUG",
-          "sInstance",
-          "ACTION_PARTNER_CUSTOMIZATION",
-          "TAG"
-        ]
-      },
-      "android/support/v4/util/SimpleArrayMap": {
-        "androidx/util/SimpleArrayMap": [
-          "BASE_SIZE",
-          "CONCURRENT_MODIFICATION_EXCEPTIONS",
-          "DEBUG",
-          "TAG",
-          "CACHE_SIZE"
-        ]
-      },
-      "android/support/v4/widget/AutoScrollHelper": {
-        "androidx/widget/AutoScrollHelper": [
-          "EDGE_TYPE_OUTSIDE",
-          "NO_MIN",
-          "NO_MAX",
-          "HORIZONTAL",
-          "EDGE_TYPE_INSIDE_EXTEND",
-          "DEFAULT_MAXIMUM_EDGE",
-          "VERTICAL",
-          "EDGE_TYPE_INSIDE",
-          "RELATIVE_UNSPECIFIED",
-          "DEFAULT_MAXIMUM_VELOCITY_DIPS",
-          "DEFAULT_RAMP_DOWN_DURATION",
-          "DEFAULT_RELATIVE_VELOCITY",
-          "DEFAULT_ACTIVATION_DELAY",
-          "DEFAULT_MINIMUM_VELOCITY_DIPS",
-          "DEFAULT_RAMP_UP_DURATION",
-          "DEFAULT_EDGE_TYPE",
-          "DEFAULT_RELATIVE_EDGE"
-        ]
-      },
-      "android/support/v7/widget/ViewInfoStore$InfoRecord": {
-        "androidx/widget/ViewInfoStore$InfoRecord": [
-          "FLAG_PRE",
-          "postInfo",
-          "FLAG_APPEAR_AND_DISAPPEAR",
-          "FLAG_PRE_AND_POST",
-          "FLAG_DISAPPEARED",
-          "preInfo",
-          "flags",
-          "FLAG_APPEAR",
-          "FLAG_APPEAR_PRE_AND_POST",
-          "FLAG_POST",
-          "sPool"
-        ]
-      },
-      "android/support/design/widget/AnimationUtils": {
-        "androidx/design/widget/AnimationUtils": [
-          "LINEAR_OUT_SLOW_IN_INTERPOLATOR",
-          "LINEAR_INTERPOLATOR",
-          "FAST_OUT_LINEAR_IN_INTERPOLATOR",
-          "FAST_OUT_SLOW_IN_INTERPOLATOR",
-          "DECELERATE_INTERPOLATOR"
-        ]
-      },
-      "android/support/design/widget/SnackbarManager$SnackbarRecord": {
-        "androidx/design/widget/SnackbarManager$SnackbarRecord": [
-          "duration",
-          "callback",
-          "paused"
-        ]
-      },
-      "android/support/transition/ChangeScroll": {
-        "androidx/transition/ChangeScroll": [
-          "PROPNAME_SCROLL_X",
-          "PROPNAME_SCROLL_Y",
-          "PROPERTIES"
-        ]
-      },
-      "android/support/design/widget/FloatingActionButtonLollipop": {
-        "androidx/design/widget/FloatingActionButtonLollipop": [
-          "EMPTY_STATE_SET",
-          "ENABLED_STATE_SET",
-          "PRESSED_ENABLED_STATE_SET",
-          "ANIM_INTERPOLATOR",
-          "FOCUSED_ENABLED_STATE_SET"
-        ]
-      },
-      "android/support/v4/graphics/TypefaceCompat": {
-        "androidx/graphics/TypefaceCompat": [
-          "sTypefaceCompatImpl",
-          "TAG",
-          "sTypefaceCache"
-        ]
-      },
-      "android/support/v7/widget/LinearSmoothScroller": {
-        "androidx/widget/LinearSmoothScroller": [
-          "MILLISECONDS_PER_PX",
-          "SNAP_TO_ANY",
-          "SNAP_TO_END",
-          "DEBUG",
-          "TAG",
-          "MILLISECONDS_PER_INCH",
-          "TARGET_SEEK_SCROLL_DISTANCE_PX",
-          "TARGET_SEEK_EXTRA_SCROLL_RATIO",
-          "SNAP_TO_START"
-        ]
-      },
-      "android/support/transition/Styleable$ChangeTransform": {
-        "androidx/transition/Styleable$ChangeTransform": [
-          "REPARENT_WITH_OVERLAY",
-          "REPARENT"
-        ]
-      },
-      "android/support/animation/DynamicAnimation": {
-        "androidx/animation/DynamicAnimation": [
-          "MIN_VISIBLE_CHANGE_ALPHA",
-          "MIN_VISIBLE_CHANGE_ROTATION_DEGREES",
-          "UNSET",
-          "ROTATION_Y",
-          "ROTATION_X",
-          "ALPHA",
-          "Z",
-          "X",
-          "Y",
-          "SCROLL_Y",
-          "SCROLL_X",
-          "TRANSLATION_Z",
-          "TRANSLATION_X",
-          "TRANSLATION_Y",
-          "THRESHOLD_MULTIPLIER",
-          "ROTATION",
-          "MIN_VISIBLE_CHANGE_SCALE",
-          "SCALE_Y",
-          "SCALE_X",
-          "MIN_VISIBLE_CHANGE_PIXELS"
-        ]
-      },
-      "android/support/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour": {
-        "androidx/constraint/solver/widgets/ConstraintWidget$DimensionBehaviour": [
-          "FIXED",
-          "MATCH_PARENT",
-          "WRAP_CONTENT",
-          "MATCH_CONSTRAINT"
-        ]
-      },
-      "android/support/v17/leanback/media/PlaybackBannerControlGlue": {
-        "androidx/leanback/media/PlaybackBannerControlGlue": [
-          "PLAYBACK_SPEED_PAUSED",
-          "ACTION_SKIP_TO_PREVIOUS",
-          "ACTION_SKIP_TO_NEXT",
-          "ACTION_CUSTOM_LEFT_FIRST",
-          "TAG",
-          "ACTION_PLAY_PAUSE",
-          "PLAYBACK_SPEED_NORMAL",
-          "ACTION_CUSTOM_RIGHT_FIRST",
-          "NUMBER_OF_SEEK_SPEEDS",
-          "ACTION_REWIND",
-          "PLAYBACK_SPEED_INVALID",
-          "PLAYBACK_SPEED_FAST_L1",
-          "PLAYBACK_SPEED_FAST_L0",
-          "PLAYBACK_SPEED_FAST_L4",
-          "PLAYBACK_SPEED_FAST_L3",
-          "PLAYBACK_SPEED_FAST_L2",
-          "ACTION_FAST_FORWARD"
-        ]
-      },
-      "android/support/transition/ChangeTransform": {
-        "androidx/transition/ChangeTransform": [
-          "PROPNAME_PARENT",
-          "TRANSLATIONS_PROPERTY",
-          "PROPNAME_INTERMEDIATE_PARENT_MATRIX",
-          "PROPNAME_TRANSFORMS",
-          "PROPNAME_INTERMEDIATE_MATRIX",
-          "sTransitionProperties",
-          "PROPNAME_MATRIX",
-          "PROPNAME_PARENT_MATRIX",
-          "NON_TRANSLATIONS_PROPERTY",
-          "SUPPORTS_VIEW_REMOVAL_SUPPRESSION"
-        ]
-      },
-      "android/support/v17/leanback/R$fraction": {
-        "androidx/leanback/R$fraction": [
-          "lb_focus_zoom_factor_xsmall",
-          "lb_focus_zoom_factor_medium",
-          "lb_browse_rows_scale",
-          "lb_search_orb_focused_zoom",
-          "lb_view_active_level",
-          "lb_focus_zoom_factor_large",
-          "lb_focus_zoom_factor_small",
-          "lb_browse_header_unselect_alpha",
-          "lb_view_dimmed_level",
-          "lb_search_bar_speech_orb_max_level_zoom"
-        ]
-      },
-      "android/support/v7/widget/LinearLayoutCompat$LayoutParams": {
-        "androidx/widget/LinearLayoutCompat$LayoutParams": [
-          "height",
-          "gravity",
-          "rightMargin",
-          "width",
-          "bottomMargin",
-          "leftMargin",
-          "topMargin",
-          "weight"
-        ]
-      },
-      "android/support/v7/preference/PreferenceViewHolder": {
-        "androidx/preference/PreferenceViewHolder": [
-          "itemView"
-        ]
-      },
-      "android/support/v7/util/MessageThreadUtil$SyncQueueItem": {
-        "androidx/util/MessageThreadUtil$SyncQueueItem": [
-          "sPoolLock",
-          "what",
-          "sPool",
-          "arg2",
-          "arg1",
-          "arg4",
-          "arg3",
-          "arg5",
-          "next",
-          "data"
-        ]
-      },
-      "android/support/v14/preference/PreferenceFragment": {
-        "androidx/preference/PreferenceFragment": [
-          "PREFERENCES_TAG",
-          "DIALOG_FRAGMENT_TAG",
-          "ARG_PREFERENCE_ROOT",
-          "MSG_BIND_PREFERENCES"
-        ]
-      },
-      "android/support/v7/gridlayout/R$styleable": {
-        "androidx/gridlayout/R$styleable": [
-          "GridLayout_Layout_android_layout_margin",
-          "GridLayout_Layout_layout_gravity",
-          "GridLayout_Layout_layout_column",
-          "GridLayout_Layout_layout_columnSpan",
-          "GridLayout_Layout_layout_row",
-          "GridLayout_Layout_layout_columnWeight",
-          "GridLayout_Layout_layout_rowWeight",
-          "GridLayout_Layout",
-          "GridLayout_Layout_android_layout_marginBottom",
-          "GridLayout_rowCount",
-          "GridLayout_columnCount",
-          "GridLayout_Layout_android_layout_marginRight",
-          "GridLayout",
-          "GridLayout_useDefaultMargins",
-          "GridLayout_rowOrderPreserved",
-          "GridLayout_columnOrderPreserved",
-          "GridLayout_Layout_android_layout_marginLeft",
-          "GridLayout_alignmentMode",
-          "GridLayout_Layout_layout_rowSpan",
-          "GridLayout_orientation",
-          "GridLayout_Layout_android_layout_marginTop"
-        ]
-      },
-      "android/support/v17/leanback/app/BackgroundManager": {
-        "androidx/leanback/app/BackgroundManager": [
-          "FULL_ALPHA",
-          "DEBUG",
-          "FRAGMENT_TAG",
-          "FADE_DURATION",
-          "CHANGE_BG_DELAY_MS",
-          "TAG"
-        ]
-      },
-      "android/support/customtabs/ICustomTabsService$Stub": {
-        "androidx/browser/customtabs/ICustomTabsService$Stub": [
-          "TRANSACTION_extraCommand",
-          "TRANSACTION_requestPostMessageChannel",
-          "TRANSACTION_postMessage",
-          "TRANSACTION_validateRelationship",
-          "TRANSACTION_warmup",
-          "TRANSACTION_updateVisuals",
-          "TRANSACTION_mayLaunchUrl",
-          "TRANSACTION_newSession",
-          "DESCRIPTOR"
-        ]
-      },
-      "android/support/v7/widget/Toolbar$SavedState": {
-        "androidx/widget/Toolbar$SavedState": [
-          "isOverflowOpen",
-          "expandedMenuItemId",
-          "CREATOR"
-        ]
-      },
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter": {
-        "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter": [
-          "ALIGN_MODE_START",
-          "sTmpRect",
-          "STATE_HALF",
-          "TAG",
-          "STATE_SMALL",
-          "sHandler",
-          "ALIGN_MODE_MIDDLE",
-          "STATE_FULL",
-          "DEBUG"
-        ]
-      },
-      "android/support/v4/app/FragmentTabHost$SavedState": {
-        "androidx/app/FragmentTabHost$SavedState": [
-          "CREATOR",
-          "curTab"
-        ]
-      },
-      "android/support/v4/app/ActivityOptionsCompat": {
-        "androidx/app/ActivityOptionsCompat": [
-          "EXTRA_USAGE_TIME_REPORT",
-          "EXTRA_USAGE_TIME_REPORT_PACKAGES"
-        ]
-      },
-      "android/support/v4/widget/NestedScrollView": {
-        "androidx/widget/NestedScrollView": [
-          "MAX_SCROLL_FACTOR",
-          "SCROLLVIEW_STYLEABLE",
-          "TAG",
-          "ANIMATED_SCROLL_GAP",
-          "INVALID_POINTER",
-          "ACCESSIBILITY_DELEGATE"
-        ]
-      },
-      "android/support/v4/app/BackStackRecord$Op": {
-        "androidx/app/BackStackRecord$Op": [
-          "enterAnim",
-          "fragment",
-          "popEnterAnim",
-          "exitAnim",
-          "popExitAnim",
-          "cmd"
-        ]
-      },
-      "android/support/v17/leanback/graphics/BoundsRule": {
-        "androidx/leanback/graphics/BoundsRule": [
-          "bottom",
-          "right",
-          "left",
-          "top"
-        ]
-      },
-      "android/support/v17/leanback/app/SearchSupportFragment": {
-        "androidx/leanback/app/SearchSupportFragment": [
-          "SPEECH_RECOGNITION_DELAY_MS",
-          "TAG",
-          "AUDIO_PERMISSION_REQUEST_CODE",
-          "ARG_QUERY",
-          "RESULTS_CHANGED",
-          "ARG_TITLE",
-          "EXTRA_LEANBACK_BADGE_PRESENT",
-          "ARG_PREFIX",
-          "QUERY_COMPLETE",
-          "DEBUG"
-        ]
-      },
-      "android/support/v7/util/SortedList": {
-        "androidx/util/SortedList": [
-          "INSERTION",
-          "DELETION",
-          "MIN_CAPACITY",
-          "INVALID_POSITION",
-          "CAPACITY_GROWTH",
-          "LOOKUP"
-        ]
-      },
-      "android/support/v4/view/ViewCompat": {
-        "androidx/view/legacy/ViewCompat": [
-          "IMPL",
-          "SCROLL_AXIS_VERTICAL",
-          "SCROLL_INDICATOR_END",
-          "MEASURED_HEIGHT_STATE_SHIFT",
-          "OVER_SCROLL_ALWAYS",
-          "SCROLL_INDICATOR_RIGHT",
-          "IMPORTANT_FOR_ACCESSIBILITY_AUTO",
-          "SCROLL_INDICATOR_START",
-          "LAYOUT_DIRECTION_LOCALE",
-          "ACCESSIBILITY_LIVE_REGION_ASSERTIVE",
-          "IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS",
-          "SCROLL_INDICATOR_TOP",
-          "MEASURED_STATE_MASK",
-          "SCROLL_INDICATOR_BOTTOM",
-          "LAYOUT_DIRECTION_LTR",
-          "OVER_SCROLL_IF_CONTENT_SCROLLS",
-          "SCROLL_AXIS_NONE",
-          "OVER_SCROLL_NEVER",
-          "ACCESSIBILITY_LIVE_REGION_POLITE",
-          "TYPE_TOUCH",
-          "MEASURED_STATE_TOO_SMALL",
-          "ACCESSIBILITY_LIVE_REGION_NONE",
-          "LAYOUT_DIRECTION_INHERIT",
-          "IMPORTANT_FOR_ACCESSIBILITY_NO",
-          "LAYER_TYPE_NONE",
-          "MEASURED_SIZE_MASK",
-          "SCROLL_INDICATOR_LEFT",
-          "TAG",
-          "SCROLL_AXIS_HORIZONTAL",
-          "TYPE_NON_TOUCH",
-          "LAYER_TYPE_HARDWARE",
-          "LAYER_TYPE_SOFTWARE",
-          "IMPORTANT_FOR_ACCESSIBILITY_YES",
-          "LAYOUT_DIRECTION_RTL"
-        ]
-      },
-      "android/support/v7/media/MediaRouter": {
-        "androidx/media/MediaRouter": [
-          "AVAILABILITY_FLAG_REQUIRE_MATCH",
-          "CALLBACK_FLAG_PERFORM_ACTIVE_SCAN",
-          "CALLBACK_FLAG_FORCE_DISCOVERY",
-          "UNSELECT_REASON_DISCONNECTED",
-          "AVAILABILITY_FLAG_IGNORE_DEFAULT_ROUTE",
-          "UNSELECT_REASON_ROUTE_CHANGED",
-          "sGlobal",
-          "UNSELECT_REASON_UNKNOWN",
-          "TAG",
-          "CALLBACK_FLAG_REQUEST_DISCOVERY",
-          "DEBUG",
-          "UNSELECT_REASON_STOPPED",
-          "CALLBACK_FLAG_UNFILTERED_EVENTS"
-        ]
-      },
-      "android/support/v17/leanback/graphics/CompositeDrawable$ChildDrawable": {
-        "androidx/leanback/graphics/CompositeDrawable$ChildDrawable": [
-          "adjustedBounds",
-          "BOTTOM_FRACTION",
-          "RIGHT_FRACTION",
-          "BOTTOM_ABSOLUTE",
-          "RIGHT_ABSOLUTE",
-          "LEFT_ABSOLUTE",
-          "LEFT_FRACTION",
-          "TOP_FRACTION",
-          "TOP_ABSOLUTE"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRow$RepeatAction": {
-        "androidx/leanback/widget/PlaybackControlsRow$RepeatAction": [
-          "INDEX_NONE",
-          "INDEX_ALL",
-          "ALL",
-          "NONE",
-          "ONE",
-          "INDEX_ONE"
-        ]
-      },
-      "android/support/design/R$id": {
-        "androidx/design/R$id": [
-          "touch_outside",
-          "largeLabel",
-          "textinput_error",
-          "textinput_counter",
-          "snackbar_text",
-          "snackbar_action",
-          "icon",
-          "smallLabel",
-          "view_offset_helper",
-          "design_bottom_sheet",
-          "coordinator",
-          "design_menu_item_action_area_stub",
-          "design_menu_item_text"
-        ]
-      },
-      "android/support/v7/widget/ActivityChooserModel$HistoricalRecord": {
-        "androidx/widget/ActivityChooserModel$HistoricalRecord": [
-          "activity",
-          "weight",
-          "time"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$BaseTvColumns": {
-        "androidx/media/tv/TvContractCompat$BaseTvColumns": [
-          "COLUMN_PACKAGE_NAME"
-        ]
-      },
-      "android/support/v17/leanback/media/MediaPlayerGlue": {
-        "androidx/leanback/media/MediaPlayerGlue": [
-          "FAST_FORWARD_REWIND_STEP",
-          "TAG",
-          "REPEAT_ONE",
-          "FAST_FORWARD_REWIND_REPEAT_DELAY",
-          "NO_REPEAT",
-          "REPEAT_ALL"
-        ]
-      },
-      "android/support/text/emoji/EmojiProcessor$GlyphChecker": {
-        "androidx/text/emoji/EmojiProcessor$GlyphChecker": [
-          "PAINT_TEXT_SIZE",
-          "sStringBuilder"
-        ]
-      },
-      "android/support/v4/app/FragmentManager": {
-        "androidx/app/FragmentManager": [
-          "POP_BACK_STACK_INCLUSIVE"
-        ]
-      },
-      "android/support/v4/content/LocalBroadcastManager$ReceiverRecord": {
-        "androidx/content/LocalBroadcastManager$ReceiverRecord": [
-          "broadcasting",
-          "receiver",
-          "filter",
-          "dead"
-        ]
-      },
-      "android/support/percent/R$styleable": {
-        "androidx/R$styleable": [
-          "PercentLayout_Layout_layout_marginEndPercent",
-          "PercentLayout_Layout",
-          "PercentLayout_Layout_layout_marginBottomPercent",
-          "PercentLayout_Layout_layout_aspectRatio",
-          "PercentLayout_Layout_layout_widthPercent",
-          "PercentLayout_Layout_layout_heightPercent",
-          "PercentLayout_Layout_layout_marginLeftPercent",
-          "PercentLayout_Layout_layout_marginRightPercent",
-          "PercentLayout_Layout_layout_marginStartPercent",
-          "PercentLayout_Layout_layout_marginPercent",
-          "PercentLayout_Layout_layout_marginTopPercent"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseSupportFragment": {
-        "androidx/leanback/app/BrowseSupportFragment": [
-          "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
-          "STATE_SET_ENTRANCE_START_STATE",
-          "HEADERS_ENABLED",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "HEADERS_HIDDEN",
-          "ARG_HEADERS_STATE",
-          "TAG",
-          "STATE_ENTRANCE_PERFORM",
-          "HEADER_SHOW",
-          "IS_PAGE_ROW",
-          "ARG_TITLE",
-          "LB_HEADERS_BACKSTACK",
-          "DEBUG",
-          "EVT_SCREEN_DATA_READY",
-          "CURRENT_SELECTED_POSITION",
-          "EVT_HEADER_VIEW_CREATED",
-          "EVT_MAIN_FRAGMENT_VIEW_CREATED",
-          "HEADERS_DISABLED",
-          "HEADER_STACK_INDEX"
-        ]
-      },
-      "android/support/v17/leanback/app/SearchFragment": {
-        "androidx/leanback/app/SearchFragment": [
-          "TAG",
-          "QUERY_COMPLETE",
-          "ARG_QUERY",
-          "RESULTS_CHANGED",
-          "ARG_TITLE",
-          "SPEECH_RECOGNITION_DELAY_MS",
-          "EXTRA_LEANBACK_BADGE_PRESENT",
-          "AUDIO_PERMISSION_REQUEST_CODE",
-          "DEBUG",
-          "ARG_PREFIX"
-        ]
-      },
-      "android/support/v4/graphics/drawable/IconCompat": {
-        "androidx/graphics/drawable/IconCompat": [
-          "ADAPTIVE_ICON_INSET_FACTOR",
-          "TYPE_RESOURCE",
-          "TYPE_BITMAP",
-          "ICON_DIAMETER_FACTOR",
-          "KEY_SHADOW_ALPHA",
-          "DEFAULT_VIEW_PORT_SCALE",
-          "AMBIENT_SHADOW_ALPHA",
-          "TYPE_DATA",
-          "BLUR_FACTOR",
-          "TYPE_URI",
-          "KEY_SHADOW_OFFSET_FACTOR",
-          "TYPE_ADAPTIVE_BITMAP"
-        ]
-      },
-      "android/support/v4/internal/view/SupportMenuItem": {
-        "androidx/internal/view/SupportMenuItem": [
-          "SHOW_AS_ACTION_ALWAYS",
-          "SHOW_AS_ACTION_NEVER",
-          "SHOW_AS_ACTION_WITH_TEXT",
-          "SHOW_AS_ACTION_IF_ROOM",
-          "SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW"
-        ]
-      },
-      "android/support/v7/cardview/R$dimen": {
-        "androidx/cardview/R$dimen": [
-          "cardview_compat_inset_shadow"
-        ]
-      },
-      "android/support/v4/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl": {
-        "androidx/widget/CompoundButtonCompat$CompoundButtonCompatBaseImpl": [
-          "sButtonDrawableField",
-          "sButtonDrawableFieldFetched",
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/StaggeredGridLayoutManager$LayoutParams": {
-        "androidx/widget/StaggeredGridLayoutManager$LayoutParams": [
-          "width",
-          "leftMargin",
-          "INVALID_SPAN_ID",
-          "bottomMargin",
-          "height",
-          "topMargin",
-          "rightMargin"
-        ]
-      },
-      "android/support/v17/leanback/widget/ItemAlignmentFacetHelper": {
-        "androidx/leanback/widget/ItemAlignmentFacetHelper": [
-          "sRect"
-        ]
-      },
-      "android/support/media/ExifInterface$ExifAttribute": {
-        "androidx/media/ExifInterface$ExifAttribute": [
-          "format",
-          "numberOfComponents",
-          "bytes"
-        ]
-      },
-      "android/support/compat/R$styleable": {
-        "androidx/compat/R$styleable": [
-          "FontFamily_fontProviderCerts",
-          "FontFamily_fontProviderAuthority",
-          "FontFamilyFont_fontWeight",
-          "FontFamilyFont_android_font",
-          "FontFamilyFont_android_fontStyle",
-          "FontFamilyFont_android_fontWeight",
-          "FontFamilyFont_fontStyle",
-          "FontFamilyFont",
-          "FontFamily_fontProviderFetchTimeout",
-          "FontFamily_fontProviderFetchStrategy",
-          "FontFamilyFont_font",
-          "FontFamily_fontProviderQuery",
-          "FontFamily",
-          "FontFamily_fontProviderPackage"
-        ]
-      },
-      "android/support/v7/widget/ButtonBarLayout": {
-        "androidx/widget/ButtonBarLayout": [
-          "PEEK_BUTTON_DP",
-          "ALLOW_STACKING_MIN_HEIGHT_DP"
-        ]
-      },
-      "android/support/v7/app/ActionBarDrawerToggleHoneycomb": {
-        "androidx/app/ActionBarDrawerToggleHoneycomb": [
-          "THEME_ATTRS",
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$LayoutParams": {
-        "androidx/widget/RecyclerView$LayoutParams": [
-          "topMargin",
-          "bottomMargin",
-          "width",
-          "height",
-          "rightMargin",
-          "leftMargin"
-        ]
-      },
-      "android/support/v7/util/DiffUtil$Snake": {
-        "androidx/util/DiffUtil$Snake": [
-          "size",
-          "x",
-          "y",
-          "reverse",
-          "removal"
-        ]
-      },
-      "android/support/v4/print/PrintHelper": {
-        "androidx/print/PrintHelper": [
-          "COLOR_MODE_MONOCHROME",
-          "SCALE_MODE_FILL",
-          "ORIENTATION_PORTRAIT",
-          "SCALE_MODE_FIT",
-          "COLOR_MODE_COLOR",
-          "ORIENTATION_LANDSCAPE"
-        ]
-      },
-      "android/support/v4/widget/CompoundButtonCompat": {
-        "androidx/widget/CompoundButtonCompat": [
-          "IMPL"
-        ]
-      },
-      "android/support/v7/widget/DefaultItemAnimator$MoveInfo": {
-        "androidx/widget/DefaultItemAnimator$MoveInfo": [
-          "toY",
-          "toX",
-          "fromY",
-          "fromX",
-          "holder"
-        ]
-      },
-      "android/support/v7/widget/ActionMenuView": {
-        "androidx/widget/ActionMenuView": [
-          "MIN_CELL_SIZE",
-          "TAG",
-          "GENERATED_ITEM_PADDING"
-        ]
-      },
-      "android/support/v7/widget/GapWorker$Task": {
-        "androidx/widget/GapWorker$Task": [
-          "viewVelocity",
-          "position",
-          "view",
-          "immediate",
-          "distanceToItem"
-        ]
-      },
-      "android/support/v7/util/DiffUtil": {
-        "androidx/util/DiffUtil": [
-          "SNAKE_COMPARATOR"
-        ]
-      },
-      "android/support/v4/content/res/ResourcesCompat": {
-        "androidx/content/res/ResourcesCompat": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/ActionMenuView$LayoutParams": {
-        "androidx/widget/ActionMenuView$LayoutParams": [
-          "expandable",
-          "extraPixels",
-          "isOverflowButton",
-          "gravity",
-          "rightMargin",
-          "cellsUsed",
-          "expanded",
-          "leftMargin",
-          "preventEdgeOffset"
-        ]
-      },
-      "android/support/transition/Visibility": {
-        "androidx/transition/Visibility": [
-          "PROPNAME_PARENT",
-          "PROPNAME_VISIBILITY",
-          "MODE_OUT",
-          "PROPNAME_SCREEN_LOCATION",
-          "sTransitionProperties",
-          "MODE_IN"
-        ]
-      },
-      "android/support/v4/view/ViewPager$LayoutParams": {
-        "androidx/view/ViewPager$LayoutParams": [
-          "needsMeasure",
-          "height",
-          "width",
-          "childIndex",
-          "position",
-          "widthFactor",
-          "gravity",
-          "isDecor"
-        ]
-      },
-      "android/support/v17/preference/R$layout": {
-        "androidx/leanback/preference/R$layout": [
-          "leanback_list_preference_item_multi",
-          "leanback_list_preference_fragment",
-          "leanback_settings_fragment",
-          "leanback_list_preference_item_single",
-          "leanback_preferences_list",
-          "leanback_preference_fragment"
-        ]
-      },
-      "android/support/v4/widget/CircularProgressDrawable": {
-        "androidx/widget/CircularProgressDrawable": [
-          "ANIMATION_DURATION",
-          "CENTER_RADIUS",
-          "COLOR_CHANGE_OFFSET",
-          "ARROW_WIDTH",
-          "STROKE_WIDTH",
-          "MAX_PROGRESS_ARC",
-          "GROUP_FULL_ROTATION",
-          "MIN_PROGRESS_ARC",
-          "RING_ROTATION",
-          "DEFAULT",
-          "ARROW_WIDTH_LARGE",
-          "ARROW_HEIGHT_LARGE",
-          "CENTER_RADIUS_LARGE",
-          "COLORS",
-          "STROKE_WIDTH_LARGE",
-          "MATERIAL_INTERPOLATOR",
-          "ARROW_HEIGHT",
-          "SHRINK_OFFSET",
-          "LARGE",
-          "LINEAR_INTERPOLATOR"
-        ]
-      },
-      "android/support/v7/mediarouter/R$integer": {
-        "androidx/mediarouter/R$integer": [
-          "mr_controller_volume_group_list_animation_duration_ms",
-          "mr_controller_volume_group_list_fade_in_duration_ms",
-          "mr_controller_volume_group_list_fade_out_duration_ms"
-        ]
-      },
-      "android/support/v17/leanback/widget/ShadowOverlayContainer": {
-        "androidx/leanback/widget/ShadowOverlayContainer": [
-          "SHADOW_DYNAMIC",
-          "sTempRect",
-          "SHADOW_NONE",
-          "SHADOW_STATIC"
-        ]
-      },
-      "android/support/v4/widget/SwipeRefreshLayout": {
-        "androidx/widget/SwipeRefreshLayout": [
-          "LAYOUT_ATTRS",
-          "CIRCLE_DIAMETER_LARGE",
-          "ALPHA_ANIMATION_DURATION",
-          "MAX_ALPHA",
-          "ANIMATE_TO_START_DURATION",
-          "LOG_TAG",
-          "MAX_PROGRESS_ANGLE",
-          "ANIMATE_TO_TRIGGER_DURATION",
-          "DEFAULT",
-          "SCALE_DOWN_DURATION",
-          "CIRCLE_DIAMETER",
-          "INVALID_POINTER",
-          "DRAG_RATE",
-          "CIRCLE_BG_LIGHT",
-          "DECELERATE_INTERPOLATION_FACTOR",
-          "LARGE",
-          "DEFAULT_CIRCLE_TARGET",
-          "STARTING_PROGRESS_ALPHA"
-        ]
-      },
-      "android/support/annotation/Dimension": {
-        "androidx/annotation/Dimension": [
-          "DP",
-          "SP",
-          "PX"
-        ]
-      },
-      "android/support/v7/widget/AppCompatSpinner": {
-        "androidx/widget/AppCompatSpinner": [
-          "MAX_ITEMS_MEASURED",
-          "MODE_DIALOG",
-          "ATTRS_ANDROID_SPINNERMODE",
-          "TAG",
-          "MODE_THEME",
-          "MODE_DROPDOWN"
-        ]
-      },
-      "android/support/v13/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl": {
-        "androidx/view/inputmethod/InputConnectionCompat$InputContentInfoCompatBaseImpl": [
-          "COMMIT_CONTENT_RESULT_RECEIVER",
-          "COMMIT_CONTENT_OPTS_KEY",
-          "COMMIT_CONTENT_FLAGS_KEY",
-          "COMMIT_CONTENT_LINK_URI_KEY",
-          "COMMIT_CONTENT_DESCRIPTION_KEY",
-          "COMMIT_CONTENT_ACTION",
-          "COMMIT_CONTENT_CONTENT_URI_KEY"
-        ]
-      },
-      "android/support/v7/app/TwilightCalculator": {
-        "androidx/app/TwilightCalculator": [
-          "OBLIQUITY",
-          "ALTIDUTE_CORRECTION_CIVIL_TWILIGHT",
-          "UTC_2000",
-          "DEGREES_TO_RADIANS",
-          "NIGHT",
-          "sunrise",
-          "state",
-          "DAY",
-          "J0",
-          "C1",
-          "C2",
-          "C3",
-          "sunset",
-          "sInstance"
-        ]
-      },
-      "android/support/v7/widget/LinearLayoutManager$LayoutState": {
-        "androidx/widget/LinearLayoutManager$LayoutState": [
-          "TAG",
-          "SCROLLING_OFFSET_NaN",
-          "LAYOUT_START",
-          "ITEM_DIRECTION_TAIL",
-          "INVALID_LAYOUT",
-          "LAYOUT_END",
-          "ITEM_DIRECTION_HEAD"
-        ]
-      },
-      "android/support/wear/R$drawable": {
-        "androidx/wear/R$drawable": [
-          "ws_ic_more_horiz_24dp_wht",
-          "ws_ic_more_vert_24dp_wht"
-        ]
-      },
-      "android/support/v17/leanback/widget/ControlBarPresenter$BoundData": {
-        "androidx/leanback/widget/ControlBarPresenter$BoundData": [
-          "adapter",
-          "presenter"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserServiceCompat$ConnectionRecord": {
-        "androidx/media/MediaBrowserServiceCompat$ConnectionRecord": [
-          "callbacks",
-          "pkg",
-          "subscriptions",
-          "rootHints",
-          "root"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplApi18": {
-        "androidx/media/session/MediaSessionCompat$MediaSessionImplApi18": [
-          "sIsMbrPendingIntentSupported"
-        ]
-      },
-      "android/support/v4/util/PatternsCompat": {
-        "androidx/util/PatternsCompat": [
-          "TLD_CHAR",
-          "USER_INFO",
-          "WEB_URL",
-          "AUTOLINK_WEB_URL",
-          "LABEL_CHAR",
-          "PATH_AND_QUERY",
-          "PUNYCODE_TLD",
-          "EMAIL_CHAR",
-          "STRICT_DOMAIN_NAME",
-          "STRICT_HOST_NAME",
-          "IP_ADDRESS",
-          "STRICT_TLD",
-          "WEB_URL_WITHOUT_PROTOCOL",
-          "PROTOCOL",
-          "EMAIL_ADDRESS",
-          "EMAIL_ADDRESS_LOCAL_PART",
-          "UCS_CHAR",
-          "TLD",
-          "IRI_LABEL",
-          "WEB_URL_WITH_PROTOCOL",
-          "AUTOLINK_EMAIL_ADDRESS",
-          "PORT_NUMBER",
-          "EMAIL_ADDRESS_DOMAIN",
-          "DOMAIN_NAME",
-          "HOST_NAME",
-          "IANA_TOP_LEVEL_DOMAINS",
-          "RELAXED_DOMAIN_NAME",
-          "WORD_BOUNDARY"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction": {
-        "androidx/leanback/widget/PlaybackControlsRow$ClosedCaptioningAction": [
-          "INDEX_OFF",
-          "INDEX_ON",
-          "OFF",
-          "ON"
-        ]
-      },
-      "android/support/v4/widget/ExploreByTouchHelper": {
-        "androidx/widget/ExploreByTouchHelper": [
-          "INVALID_ID",
-          "NODE_ADAPTER",
-          "DEFAULT_CLASS_NAME",
-          "INVALID_PARENT_BOUNDS",
-          "HOST_ID",
-          "SPARSE_VALUES_ADAPTER"
-        ]
-      },
-      "android/support/v7/widget/OrientationHelper": {
-        "androidx/widget/OrientationHelper": [
-          "INVALID_SIZE",
-          "HORIZONTAL",
-          "VERTICAL"
-        ]
-      },
-      "android/support/animation/SpringForce": {
-        "androidx/animation/SpringForce": [
-          "DAMPING_RATIO_NO_BOUNCY",
-          "UNSET",
-          "DAMPING_RATIO_HIGH_BOUNCY",
-          "VELOCITY_THRESHOLD_MULTIPLIER",
-          "STIFFNESS_LOW",
-          "DAMPING_RATIO_LOW_BOUNCY",
-          "STIFFNESS_HIGH",
-          "STIFFNESS_MEDIUM",
-          "DAMPING_RATIO_MEDIUM_BOUNCY",
-          "STIFFNESS_VERY_LOW"
-        ]
-      },
-      "android/support/v7/view/menu/MenuAdapter": {
-        "androidx/view/menu/MenuAdapter": [
-          "ITEM_LAYOUT"
-        ]
-      },
-      "android/support/design/widget/ViewGroupUtils": {
-        "androidx/widget/ViewGroupUtils": [
-          "sMatrix",
-          "sRectF"
-        ]
-      },
-      "android/support/multidex/ZipUtil": {
-        "androidx/multidex/ZipUtil": [
-          "ENDSIG",
-          "ENDHDR",
-          "BUFFER_SIZE"
-        ]
-      },
-      "android/support/v7/media/MediaItemStatus": {
-        "androidx/media/MediaItemStatus": [
-          "KEY_EXTRAS",
-          "PLAYBACK_STATE_PLAYING",
-          "KEY_TIMESTAMP",
-          "KEY_CONTENT_POSITION",
-          "PLAYBACK_STATE_PENDING",
-          "PLAYBACK_STATE_FINISHED",
-          "PLAYBACK_STATE_BUFFERING",
-          "PLAYBACK_STATE_PAUSED",
-          "PLAYBACK_STATE_INVALIDATED",
-          "KEY_CONTENT_DURATION",
-          "PLAYBACK_STATE_ERROR",
-          "PLAYBACK_STATE_CANCELED",
-          "EXTRA_HTTP_RESPONSE_HEADERS",
-          "KEY_PLAYBACK_STATE",
-          "EXTRA_HTTP_STATUS_CODE"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$Recycler": {
-        "androidx/widget/RecyclerView$Recycler": [
-          "DEFAULT_CACHE_SIZE"
-        ]
-      },
-      "android/support/transition/ViewUtilsApi19": {
-        "androidx/transition/ViewUtilsApi19": [
-          "sSetTransitionAlphaMethod",
-          "sSetTransitionAlphaMethodFetched",
-          "TAG",
-          "sGetTransitionAlphaMethod",
-          "sGetTransitionAlphaMethodFetched"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserCompat": {
-        "androidx/media/MediaBrowserCompat": [
-          "EXTRA_PAGE",
-          "DEBUG",
-          "EXTRA_MEDIA_ID",
-          "EXTRA_PAGE_SIZE",
-          "CUSTOM_ACTION_DOWNLOAD",
-          "CUSTOM_ACTION_REMOVE_DOWNLOADED_FILE",
-          "TAG",
-          "EXTRA_DOWNLOAD_PROGRESS"
-        ]
-      },
-      "android/support/v4/app/FragmentTransition$FragmentContainerTransition": {
-        "androidx/app/FragmentTransition$FragmentContainerTransition": [
-          "lastInTransaction",
-          "lastIn",
-          "lastInIsPop",
-          "firstOut",
-          "firstOutIsPop",
-          "firstOutTransaction"
-        ]
-      },
-      "android/support/v4/text/util/LinkifyCompat": {
-        "androidx/text/util/LinkifyCompat": [
-          "COMPARATOR",
-          "EMPTY_STRING"
-        ]
-      },
-      "android/support/v7/app/TwilightManager$TwilightState": {
-        "androidx/app/TwilightManager$TwilightState": [
-          "todaySunrise",
-          "todaySunset",
-          "yesterdaySunset",
-          "nextUpdate",
-          "tomorrowSunrise",
-          "isNight"
-        ]
-      },
-      "android/support/v4/content/res/FontResourcesParserCompat": {
-        "androidx/content/res/FontResourcesParserCompat": [
-          "NORMAL_WEIGHT",
-          "FETCH_STRATEGY_ASYNC",
-          "INFINITE_TIMEOUT_VALUE",
-          "DEFAULT_TIMEOUT_MILLIS",
-          "FETCH_STRATEGY_BLOCKING",
-          "ITALIC"
-        ]
-      },
-      "android/support/v7/widget/ListPopupWindow": {
-        "androidx/widget/ListPopupWindow": [
-          "sSetEpicenterBoundsMethod",
-          "WRAP_CONTENT",
-          "MATCH_PARENT",
-          "POSITION_PROMPT_BELOW",
-          "DEBUG",
-          "sGetMaxAvailableHeightMethod",
-          "INPUT_METHOD_FROM_FOCUSABLE",
-          "INPUT_METHOD_NEEDED",
-          "EXPAND_LIST_TIMEOUT",
-          "sClipToWindowEnabledMethod",
-          "POSITION_PROMPT_ABOVE",
-          "TAG",
-          "INPUT_METHOD_NOT_NEEDED"
-        ]
-      },
-      "android/support/v7/media/MediaRouteProviderProtocol": {
-        "androidx/media/MediaRouteProviderProtocol": [
-          "SERVICE_INTERFACE",
-          "CLIENT_MSG_RELEASE_ROUTE_CONTROLLER",
-          "CLIENT_DATA_ROUTE_ID",
-          "CLIENT_VERSION_CURRENT",
-          "CLIENT_VERSION_START",
-          "CLIENT_DATA_ROUTE_LIBRARY_GROUP",
-          "CLIENT_VERSION_1",
-          "CLIENT_VERSION_2",
-          "SERVICE_VERSION_CURRENT",
-          "SERVICE_MSG_CONTROL_REQUEST_SUCCEEDED",
-          "CLIENT_MSG_SELECT_ROUTE",
-          "CLIENT_MSG_UNREGISTER",
-          "CLIENT_MSG_UPDATE_ROUTE_VOLUME",
-          "SERVICE_MSG_REGISTERED",
-          "CLIENT_MSG_CREATE_ROUTE_CONTROLLER",
-          "CLIENT_MSG_ROUTE_CONTROL_REQUEST",
-          "CLIENT_DATA_UNSELECT_REASON",
-          "CLIENT_MSG_SET_DISCOVERY_REQUEST",
-          "SERVICE_MSG_CONTROL_REQUEST_FAILED",
-          "CLIENT_MSG_REGISTER",
-          "CLIENT_MSG_UNSELECT_ROUTE",
-          "SERVICE_MSG_GENERIC_FAILURE",
-          "SERVICE_MSG_GENERIC_SUCCESS",
-          "SERVICE_VERSION_1",
-          "CLIENT_DATA_VOLUME",
-          "SERVICE_DATA_ERROR",
-          "SERVICE_MSG_DESCRIPTOR_CHANGED",
-          "CLIENT_MSG_SET_ROUTE_VOLUME"
-        ]
-      },
-      "android/support/v4/app/Fragment": {
-        "androidx/app/Fragment": [
-          "CREATED",
-          "STARTED",
-          "ACTIVITY_CREATED",
-          "USE_DEFAULT_TRANSITION",
-          "RESUMED",
-          "sClassMap",
-          "INITIALIZING",
-          "STOPPED"
-        ]
-      },
-      "android/support/v7/app/AlertController$ButtonHandler": {
-        "androidx/app/AlertController$ButtonHandler": [
-          "MSG_DISMISS_DIALOG"
-        ]
-      },
-      "android/support/v4/text/BidiFormatter": {
-        "androidx/text/BidiFormatter": [
-          "DIR_LTR",
-          "DIR_UNKNOWN",
-          "DEFAULT_FLAGS",
-          "DEFAULT_LTR_INSTANCE",
-          "PDF",
-          "FLAG_STEREO_RESET",
-          "LRM_STRING",
-          "LRE",
-          "LRM",
-          "DEFAULT_TEXT_DIRECTION_HEURISTIC",
-          "DIR_RTL",
-          "DEFAULT_RTL_INSTANCE",
-          "RLM",
-          "RLE",
-          "EMPTY_STRING",
-          "RLM_STRING"
-        ]
-      },
-      "android/support/v17/leanback/widget/BaseGridView": {
-        "androidx/leanback/widget/BaseGridView": [
-          "WINDOW_ALIGN_NO_EDGE",
-          "SAVE_ALL_CHILD",
-          "WINDOW_ALIGN_BOTH_EDGE",
-          "FOCUS_SCROLL_PAGE",
-          "WINDOW_ALIGN_HIGH_EDGE",
-          "ITEM_ALIGN_OFFSET_PERCENT_DISABLED",
-          "WINDOW_ALIGN_LOW_EDGE",
-          "SAVE_ON_SCREEN_CHILD",
-          "SAVE_NO_CHILD",
-          "FOCUS_SCROLL_ALIGNED",
-          "WINDOW_ALIGN_OFFSET_PERCENT_DISABLED",
-          "FOCUS_SCROLL_ITEM",
-          "SAVE_LIMITED_CHILD"
-        ]
-      },
-      "android/support/v4/app/FragmentActivity": {
-        "androidx/app/FragmentActivity": [
-          "MSG_REALLY_STOPPED",
-          "NEXT_CANDIDATE_REQUEST_INDEX_TAG",
-          "MAX_NUM_PENDING_FRAGMENT_ACTIVITY_RESULTS",
-          "FRAGMENTS_TAG",
-          "TAG",
-          "ALLOCATED_REQUEST_INDICIES_TAG",
-          "MSG_RESUME_PENDING",
-          "REQUEST_FRAGMENT_WHO_TAG"
-        ]
-      },
-      "android/support/v7/gridlayout/R$dimen": {
-        "androidx/gridlayout/R$dimen": [
-          "default_gap"
-        ]
-      },
-      "android/support/content/ContentPager$Stats": {
-        "androidx/content/ContentPager$Stats": [
-          "EXTRA_COMPAT_PAGED",
-          "EXTRA_PROVIDER_PAGED",
-          "EXTRA_RESOLVED_QUERIES",
-          "EXTRA_TOTAL_QUERIES"
-        ]
-      },
-      "android/support/design/widget/BaseTransientBottomBar": {
-        "androidx/design/widget/BaseTransientBottomBar": [
-          "ANIMATION_DURATION",
-          "USE_OFFSET_API",
-          "LENGTH_SHORT",
-          "MSG_SHOW",
-          "MSG_DISMISS",
-          "LENGTH_LONG",
-          "sHandler",
-          "ANIMATION_FADE_DURATION",
-          "LENGTH_INDEFINITE"
-        ]
-      },
-      "android/support/v17/leanback/widget/ArrayObjectAdapter": {
-        "androidx/leanback/widget/ArrayObjectAdapter": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v4/view/AsyncLayoutInflater$InflateRequest": {
-        "androidx/view/AsyncLayoutInflater$InflateRequest": [
-          "inflater",
-          "callback",
-          "view",
-          "parent",
-          "resid"
-        ]
-      },
-      "android/support/transition/Styleable": {
-        "androidx/transition/Styleable": [
-          "TRANSITION",
-          "VISIBILITY_TRANSITION",
-          "CHANGE_TRANSFORM",
-          "SLIDE",
-          "TRANSITION_MANAGER",
-          "CHANGE_BOUNDS",
-          "TRANSITION_SET",
-          "FADE",
-          "TRANSITION_TARGET",
-          "ARC_MOTION",
-          "PATTERN_PATH_MOTION"
-        ]
-      },
-      "android/support/design/widget/Snackbar$Callback": {
-        "androidx/design/widget/Snackbar$Callback": [
-          "DISMISS_EVENT_ACTION",
-          "DISMISS_EVENT_TIMEOUT",
-          "DISMISS_EVENT_SWIPE",
-          "DISMISS_EVENT_CONSECUTIVE",
-          "DISMISS_EVENT_MANUAL"
-        ]
-      },
-      "android/support/v4/content/ModernAsyncTask$Status": {
-        "androidx/content/ModernAsyncTask$Status": [
-          "PENDING",
-          "FINISHED",
-          "RUNNING"
-        ]
-      },
-      "android/support/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter": {
-        "androidx/wear/widget/drawer/WearableActionDrawerView$ActionListAdapter": [
-          "TYPE_TITLE",
-          "TYPE_ACTION"
-        ]
-      },
-      "android/support/design/widget/AppBarLayout$Behavior": {
-        "androidx/design/widget/AppBarLayout$Behavior": [
-          "INVALID_POSITION",
-          "MAX_OFFSET_ANIMATION_DURATION"
-        ]
-      },
-      "android/support/v17/leanback/app/BaseSupportFragment": {
-        "androidx/leanback/app/BaseSupportFragment": [
-          "STATE_ENTRANCE_INIT",
-          "EVT_PREPARE_ENTRANCE",
-          "EVT_ON_CREATE",
-          "COND_TRANSITION_NOT_SUPPORTED",
-          "STATE_ENTRANCE_PERFORM",
-          "EVT_ENTRANCE_END",
-          "EVT_ON_CREATEVIEW",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
-          "EVT_START_ENTRANCE",
-          "STATE_ENTRANCE_ON_ENDED",
-          "STATE_START",
-          "STATE_ENTRANCE_COMPLETE"
-        ]
-      },
-      "android/support/annotation/VisibleForTesting": {
-        "androidx/annotation/VisibleForTesting": [
-          "PROTECTED",
-          "PACKAGE_PRIVATE",
-          "NONE",
-          "PRIVATE"
-        ]
-      },
-      "android/support/v17/leanback/widget/Parallax$IntProperty": {
-        "androidx/leanback/widget/Parallax$IntProperty": [
-          "UNKNOWN_AFTER",
-          "UNKNOWN_BEFORE"
-        ]
-      },
-      "android/support/v7/media/SystemMediaRouteProvider$JellybeanImpl": {
-        "androidx/media/SystemMediaRouteProvider$JellybeanImpl": [
-          "LIVE_AUDIO_CONTROL_FILTERS",
-          "LIVE_VIDEO_CONTROL_FILTERS"
-        ]
-      },
-      "android/support/constraint/ConstraintLayout": {
-        "androidx/constraint/ConstraintLayout": [
-          "VERSION",
-          "ALLOWS_EMBEDDED",
-          "SIMPLE_LAYOUT",
-          "TAG"
-        ]
-      },
-      "android/support/v4/widget/TextViewCompat": {
-        "androidx/widget/TextViewCompat": [
-          "AUTO_SIZE_TEXT_TYPE_UNIFORM",
-          "IMPL",
-          "AUTO_SIZE_TEXT_TYPE_NONE"
-        ]
-      },
-      "android/support/content/ContentPager": {
-        "androidx/content/ContentPager": [
-          "DEBUG",
-          "CURSOR_DISPOSITION",
-          "EXTRA_TOTAL_COUNT",
-          "EXTRA_HONORED_ARGS",
-          "CURSOR_DISPOSITION_REPAGED",
-          "QUERY_ARG_LIMIT",
-          "QUERY_ARG_OFFSET",
-          "EXTRA_SUGGESTED_LIMIT",
-          "EXTRA_REQUESTED_LIMIT",
-          "CURSOR_DISPOSITION_PAGED",
-          "TAG",
-          "CURSOR_DISPOSITION_WRAPPED",
-          "DEFAULT_CURSOR_CACHE_SIZE",
-          "CURSOR_DISPOSITION_COPIED"
-        ]
-      },
-      "android/support/v13/app/FragmentTabHost$SavedState": {
-        "androidx/app/legacy/FragmentTabHost$SavedState": [
-          "curTab",
-          "CREATOR"
-        ]
-      },
-      "android/support/design/widget/CollapsingToolbarLayout$LayoutParams": {
-        "androidx/design/widget/CollapsingToolbarLayout$LayoutParams": [
-          "DEFAULT_PARALLAX_MULTIPLIER",
-          "bottomMargin",
-          "COLLAPSE_MODE_PARALLAX",
-          "COLLAPSE_MODE_PIN",
-          "COLLAPSE_MODE_OFF"
-        ]
-      },
-      "android/support/v7/app/WindowDecorActionBar": {
-        "androidx/app/WindowDecorActionBar": [
-          "FADE_OUT_DURATION_MS",
-          "FADE_IN_DURATION_MS",
-          "sShowInterpolator",
-          "INVALID_POSITION",
-          "sHideInterpolator",
-          "TAG"
-        ]
-      },
-      "android/support/v4/view/PointerIconCompat": {
-        "androidx/view/PointerIconCompat": [
-          "TYPE_ZOOM_IN",
-          "TYPE_HELP",
-          "TYPE_WAIT",
-          "TYPE_VERTICAL_TEXT",
-          "TYPE_GRAB",
-          "TYPE_NULL",
-          "TYPE_CELL",
-          "TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW",
-          "TYPE_ARROW",
-          "TYPE_TEXT",
-          "TYPE_HORIZONTAL_DOUBLE_ARROW",
-          "TYPE_HAND",
-          "TYPE_DEFAULT",
-          "TYPE_VERTICAL_DOUBLE_ARROW",
-          "TYPE_NO_DROP",
-          "TYPE_COPY",
-          "TYPE_ALL_SCROLL",
-          "TYPE_GRABBING",
-          "TYPE_ALIAS",
-          "TYPE_CROSSHAIR",
-          "TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW",
-          "TYPE_ZOOM_OUT",
-          "TYPE_CONTEXT_MENU"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$Bounds": {
-        "androidx/widget/GridLayout$Bounds": [
-          "after",
-          "flexibility",
-          "before"
-        ]
-      },
-      "android/support/v4/internal/view/SupportMenu": {
-        "androidx/internal/view/SupportMenu": [
-          "USER_SHIFT",
-          "SUPPORTED_MODIFIERS_MASK",
-          "USER_MASK",
-          "CATEGORY_SHIFT",
-          "FLAG_KEEP_OPEN_ON_SUBMENU_OPENED",
-          "CATEGORY_MASK"
-        ]
-      },
-      "android/support/multidex/ZipUtil$CentralDirectory": {
-        "androidx/multidex/ZipUtil$CentralDirectory": [
-          "offset",
-          "size"
-        ]
-      },
-      "android/support/app/recommendation/ContentRecommendation": {
-        "androidx/app/recommendation/ContentRecommendation": [
-          "CONTENT_TYPE_SERIAL",
-          "CONTENT_TYPE_SPORTS",
-          "CONTENT_TYPE_APP",
-          "CONTENT_MATURITY_LOW",
-          "CONTENT_MATURITY_ALL",
-          "CONTENT_PRICING_PREORDER",
-          "INTENT_TYPE_BROADCAST",
-          "CONTENT_STATUS_AVAILABLE",
-          "CONTENT_PRICING_SUBSCRIPTION",
-          "CONTENT_TYPE_MAGAZINE",
-          "CONTENT_TYPE_VIDEO",
-          "CONTENT_MATURITY_MEDIUM",
-          "CONTENT_PRICING_PURCHASE",
-          "CONTENT_TYPE_RADIO",
-          "CONTENT_TYPE_WEBSITE",
-          "CONTENT_TYPE_MUSIC",
-          "INTENT_TYPE_ACTIVITY",
-          "CONTENT_STATUS_UNAVAILABLE",
-          "CONTENT_PRICING_FREE",
-          "CONTENT_TYPE_TRAILER",
-          "CONTENT_TYPE_GAME",
-          "CONTENT_MATURITY_HIGH",
-          "CONTENT_TYPE_NEWS",
-          "CONTENT_STATUS_READY",
-          "CONTENT_TYPE_MOVIE",
-          "CONTENT_STATUS_PENDING",
-          "INTENT_TYPE_SERVICE",
-          "CONTENT_TYPE_PODCAST",
-          "CONTENT_PRICING_RENTAL",
-          "CONTENT_TYPE_COMIC",
-          "CONTENT_TYPE_BOOK"
-        ]
-      },
-      "android/support/v4/media/app/NotificationCompat$MediaStyle": {
-        "androidx/media/app/NotificationCompat$MediaStyle": [
-          "MAX_MEDIA_BUTTONS",
-          "MAX_MEDIA_BUTTONS_IN_COMPACT"
-        ]
-      },
-      "android/support/v4/media/session/MediaControllerCompat$Callback$MessageHandler": {
-        "androidx/media/session/MediaControllerCompat$Callback$MessageHandler": [
-          "MSG_EVENT",
-          "MSG_UPDATE_QUEUE_TITLE",
-          "MSG_UPDATE_EXTRAS",
-          "MSG_UPDATE_METADATA",
-          "MSG_UPDATE_VOLUME",
-          "MSG_UPDATE_SHUFFLE_MODE",
-          "MSG_DESTROYED",
-          "MSG_SESSION_READY",
-          "MSG_UPDATE_REPEAT_MODE",
-          "MSG_UPDATE_CAPTIONING_ENABLED",
-          "MSG_UPDATE_QUEUE",
-          "MSG_UPDATE_PLAYBACK_STATE"
-        ]
-      },
-      "android/support/v7/widget/LinearLayoutManager": {
-        "androidx/widget/LinearLayoutManager": [
-          "TAG",
-          "MAX_SCROLL_FACTOR",
-          "VERTICAL",
-          "INVALID_OFFSET",
-          "DEBUG",
-          "HORIZONTAL"
-        ]
-      },
-      "android/support/v4/view/ViewParentCompat": {
-        "androidx/view/ViewParentCompat": [
-          "IMPL",
-          "TAG"
-        ]
-      },
-      "android/support/v4/widget/DrawerLayout$LayoutParams": {
-        "androidx/widget/DrawerLayout$LayoutParams": [
-          "gravity",
-          "width",
-          "FLAG_IS_OPENED",
-          "openState",
-          "onScreen",
-          "isPeeking",
-          "leftMargin",
-          "bottomMargin",
-          "FLAG_IS_OPENING",
-          "topMargin",
-          "FLAG_IS_CLOSING",
-          "height",
-          "rightMargin"
-        ]
-      },
-      "android/support/v4/graphics/drawable/DrawableWrapperApi14": {
-        "androidx/graphics/drawable/DrawableWrapperApi14": [
-          "DEFAULT_TINT_MODE"
-        ]
-      },
-      "android/support/v7/widget/GridLayoutManager$LayoutParams": {
-        "androidx/widget/GridLayoutManager$LayoutParams": [
-          "bottomMargin",
-          "rightMargin",
-          "height",
-          "topMargin",
-          "width",
-          "INVALID_SPAN_ID",
-          "leftMargin"
-        ]
-      },
-      "android/support/v4/app/NotificationManagerCompat$SideChannelManager$ListenerRecord": {
-        "androidx/app/NotificationManagerCompat$SideChannelManager$ListenerRecord": [
-          "taskQueue",
-          "service",
-          "componentName",
-          "retryCount",
-          "bound"
-        ]
-      },
-      "android/support/v17/leanback/widget/picker/DatePicker": {
-        "androidx/leanback/widget/picker/DatePicker": [
-          "DATE_FORMAT",
-          "LOG_TAG",
-          "DATE_FIELDS"
-        ]
-      },
-      "android/support/v7/widget/DrawableUtils": {
-        "androidx/widget/DrawableUtils": [
-          "INSETS_NONE",
-          "VECTOR_DRAWABLE_CLAZZ_NAME",
-          "TAG",
-          "sInsetsClazz"
-        ]
-      },
-      "android/support/v4/media/session/MediaControllerCompat$PlaybackInfo": {
-        "androidx/media/session/MediaControllerCompat$PlaybackInfo": [
-          "PLAYBACK_TYPE_LOCAL",
-          "PLAYBACK_TYPE_REMOTE"
-        ]
-      },
-      "android/support/v17/leanback/widget/SearchOrbView$Colors": {
-        "androidx/leanback/widget/SearchOrbView$Colors": [
-          "sBrightnessAlpha",
-          "brightColor",
-          "iconColor",
-          "color"
-        ]
-      },
-      "android/support/v7/widget/LayoutState": {
-        "androidx/widget/LayoutState": [
-          "TAG",
-          "LAYOUT_END",
-          "INVALID_LAYOUT",
-          "ITEM_DIRECTION_HEAD",
-          "ITEM_DIRECTION_TAIL",
-          "LAYOUT_START"
-        ]
-      },
-      "android/support/v17/leanback/app/BaseFragment": {
-        "androidx/leanback/app/BaseFragment": [
-          "STATE_ENTRANCE_COMPLETE",
-          "EVT_ON_CREATEVIEW",
-          "COND_TRANSITION_NOT_SUPPORTED",
-          "STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW",
-          "STATE_ENTRANCE_ON_ENDED",
-          "EVT_START_ENTRANCE",
-          "EVT_PREPARE_ENTRANCE",
-          "STATE_ENTRANCE_INIT",
-          "STATE_START",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "EVT_ENTRANCE_END",
-          "STATE_ENTRANCE_PERFORM",
-          "EVT_ON_CREATE"
-        ]
-      },
-      "android/support/v7/widget/ActivityChooserView": {
-        "androidx/widget/ActivityChooserView": [
-          "LOG_TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/picker/PickerUtility$TimeConstant": {
-        "androidx/leanback/widget/picker/PickerUtility$TimeConstant": [
-          "ampm",
-          "minutes",
-          "locale",
-          "hours12",
-          "hours24"
-        ]
-      },
-      "android/support/design/widget/DrawableUtils": {
-        "androidx/design/widget/DrawableUtils": [
-          "LOG_TAG",
-          "sSetConstantStateMethod",
-          "sSetConstantStateMethodFetched"
-        ]
-      },
-      "android/support/v7/util/AsyncListUtil": {
-        "androidx/util/AsyncListUtil": [
-          "TAG",
-          "DEBUG"
-        ]
-      },
-      "android/support/v7/widget/ActivityChooserView$ActivityChooserViewAdapter": {
-        "androidx/widget/ActivityChooserView$ActivityChooserViewAdapter": [
-          "ITEM_VIEW_TYPE_COUNT",
-          "MAX_ACTIVITY_COUNT_DEFAULT",
-          "ITEM_VIEW_TYPE_ACTIVITY",
-          "ITEM_VIEW_TYPE_FOOTER",
-          "MAX_ACTIVITY_COUNT_UNLIMITED"
-        ]
-      },
-      "android/support/v17/leanback/widget/ControlBarPresenter": {
-        "androidx/leanback/widget/ControlBarPresenter": [
-          "sChildMarginDefault",
-          "MAX_CONTROLS",
-          "sControlIconWidth"
-        ]
-      },
-      "android/support/v4/app/FragmentTransaction": {
-        "androidx/app/FragmentTransaction": [
-          "TRANSIT_FRAGMENT_CLOSE",
-          "TRANSIT_EXIT_MASK",
-          "TRANSIT_FRAGMENT_OPEN",
-          "TRANSIT_UNSET",
-          "TRANSIT_FRAGMENT_FADE",
-          "TRANSIT_NONE",
-          "TRANSIT_ENTER_MASK"
-        ]
-      },
-      "android/support/design/widget/BottomSheetBehavior": {
-        "androidx/design/widget/BottomSheetBehavior": [
-          "STATE_COLLAPSED",
-          "HIDE_THRESHOLD",
-          "STATE_SETTLING",
-          "STATE_HIDDEN",
-          "STATE_DRAGGING",
-          "HIDE_FRICTION",
-          "STATE_EXPANDED",
-          "PEEK_HEIGHT_AUTO"
-        ]
-      },
-      "android/support/v17/leanback/app/VerticalGridSupportFragment": {
-        "androidx/leanback/app/VerticalGridSupportFragment": [
-          "DEBUG",
-          "STATE_ENTRANCE_ON_PREPARED",
-          "EVT_ON_CREATEVIEW",
-          "STATE_SET_ENTRANCE_START_STATE",
-          "TAG"
-        ]
-      },
-      "android/support/v7/media/MediaItemMetadata": {
-        "androidx/media/MediaItemMetadata": [
-          "KEY_ALBUM_TITLE",
-          "KEY_DURATION",
-          "KEY_YEAR",
-          "KEY_TRACK_NUMBER",
-          "KEY_AUTHOR",
-          "KEY_DISC_NUMBER",
-          "KEY_ALBUM_ARTIST",
-          "KEY_COMPOSER",
-          "KEY_ARTIST",
-          "KEY_ARTWORK_URI",
-          "KEY_TITLE"
-        ]
-      },
-      "android/support/v7/appcompat/R$bool": {
-        "androidx/appcompat/R$bool": [
-          "abc_config_showMenuShortcutsWhenKeyboardPresent",
-          "abc_action_bar_embed_tabs"
-        ]
-      },
-      "android/support/transition/ViewUtilsApi21": {
-        "androidx/transition/ViewUtilsApi21": [
-          "sTransformMatrixToGlobalMethodFetched",
-          "sTransformMatrixToLocalMethodFetched",
-          "TAG",
-          "sSetAnimationMatrixMethod",
-          "sTransformMatrixToGlobalMethod",
-          "sTransformMatrixToLocalMethod",
-          "sSetAnimationMatrixMethodFetched"
-        ]
-      },
-      "android/support/v4/util/Pair": {
-        "androidx/util/Pair": [
-          "first",
-          "second"
-        ]
-      },
-      "android/support/v7/preference/SeekBarPreference$SavedState": {
-        "androidx/preference/SeekBarPreference$SavedState": [
-          "min",
-          "max",
-          "CREATOR",
-          "seekBarValue"
-        ]
-      },
-      "android/support/v7/mediarouter/R$attr": {
-        "androidx/mediarouter/R$attr": [
-          "mediaRouteTheme",
-          "mediaRouteTvIconDrawable",
-          "mediaRouteButtonStyle",
-          "mediaRouteStopDrawable",
-          "mediaRoutePauseDrawable",
-          "mediaRouteSpeakerGroupIconDrawable",
-          "mediaRouteSpeakerIconDrawable",
-          "mediaRouteDefaultIconDrawable",
-          "mediaRoutePlayDrawable"
-        ]
-      },
-      "android/support/v7/view/SupportMenuInflater": {
-        "androidx/view/SupportMenuInflater": [
-          "XML_ITEM",
-          "XML_GROUP",
-          "LOG_TAG",
-          "ACTION_VIEW_CONSTRUCTOR_SIGNATURE",
-          "XML_MENU",
-          "ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE",
-          "NO_ID"
-        ]
-      },
-      "android/support/v4/view/AsyncLayoutInflater$InflateThread": {
-        "androidx/view/AsyncLayoutInflater$InflateThread": [
-          "sInstance"
-        ]
-      },
-      "android/support/design/widget/CollapsingTextHelper": {
-        "androidx/design/widget/CollapsingTextHelper": [
-          "DEBUG_DRAW",
-          "USE_SCALING_TEXTURE",
-          "DEBUG_DRAW_PAINT"
-        ]
-      },
-      "android/support/v4/app/FragmentTabHost$TabInfo": {
-        "androidx/app/FragmentTabHost$TabInfo": [
-          "tag",
-          "fragment",
-          "args",
-          "clss"
-        ]
-      },
-      "android/support/v17/leanback/app/VideoFragment": {
-        "androidx/leanback/app/VideoFragment": [
-          "SURFACE_NOT_CREATED",
-          "SURFACE_CREATED"
-        ]
-      },
-      "android/support/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable": {
-        "androidx/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable": [
-          "FONT_NAME"
-        ]
-      },
-      "android/support/mediacompat/R$layout": {
-        "androidx/mediacompat/R$layout": [
-          "notification_template_big_media_custom",
-          "notification_template_media",
-          "notification_media_action",
-          "notification_template_big_media_narrow_custom",
-          "notification_template_media_custom",
-          "notification_template_big_media",
-          "notification_template_big_media_narrow"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$MessagingStyle$Message": {
-        "androidx/app/NotificationCompat$MessagingStyle$Message": [
-          "KEY_DATA_URI",
-          "KEY_EXTRAS_BUNDLE",
-          "KEY_DATA_MIME_TYPE",
-          "KEY_TIMESTAMP",
-          "KEY_SENDER",
-          "KEY_TEXT"
-        ]
-      },
-      "android/support/v4/media/session/MediaControllerCompat": {
-        "androidx/media/session/MediaControllerCompat": [
-          "COMMAND_GET_EXTRA_BINDER",
-          "COMMAND_REMOVE_QUEUE_ITEM_AT",
-          "COMMAND_ARGUMENT_INDEX",
-          "COMMAND_ARGUMENT_MEDIA_DESCRIPTION",
-          "COMMAND_ADD_QUEUE_ITEM_AT",
-          "COMMAND_ADD_QUEUE_ITEM",
-          "COMMAND_REMOVE_QUEUE_ITEM",
-          "TAG"
-        ]
-      },
-      "android/support/v4/text/TextDirectionHeuristicsCompat$AnyStrong": {
-        "androidx/text/TextDirectionHeuristicsCompat$AnyStrong": [
-          "INSTANCE_RTL",
-          "INSTANCE_LTR"
-        ]
-      },
-      "android/support/wear/widget/ProgressDrawable": {
-        "androidx/wear/widget/ProgressDrawable": [
-          "FULL_CIRCLE",
-          "LEVEL",
-          "CORRECTION_ANGLE",
-          "GROW_SHRINK_RATIO",
-          "MAX_LEVEL",
-          "sInterpolator",
-          "NUMBER_OF_SEGMENTS",
-          "STARTING_ANGLE",
-          "MAX_SWEEP",
-          "ANIMATION_DURATION",
-          "LEVELS_PER_SEGMENT"
-        ]
-      },
-      "android/support/v7/app/MediaRouteControllerDialog$FetchArtTask": {
-        "androidx/app/MediaRouteControllerDialog$FetchArtTask": [
-          "SHOW_ANIM_TIME_THRESHOLD_MILLIS"
-        ]
-      },
-      "android/support/v17/leanback/transition/SlideKitkat": {
-        "androidx/leanback/transition/SlideKitkat": [
-          "sCalculateRight",
-          "sCalculateStart",
-          "sAccelerate",
-          "sDecelerate",
-          "sCalculateTop",
-          "sCalculateEnd",
-          "sCalculateLeft",
-          "sCalculateBottom",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/ImageCardView": {
-        "androidx/leanback/widget/ImageCardView": [
-          "CARD_TYPE_FLAG_CONTENT",
-          "ALPHA",
-          "CARD_TYPE_FLAG_ICON_RIGHT",
-          "CARD_TYPE_FLAG_TITLE",
-          "CARD_TYPE_FLAG_IMAGE_ONLY",
-          "CARD_TYPE_FLAG_ICON_LEFT"
-        ]
-      },
-      "android/support/v17/leanback/app/VideoSupportFragment": {
-        "androidx/leanback/app/VideoSupportFragment": [
-          "SURFACE_NOT_CREATED",
-          "SURFACE_CREATED"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRow$PlayPauseAction": {
-        "androidx/leanback/widget/PlaybackControlsRow$PlayPauseAction": [
-          "INDEX_PAUSE",
-          "PLAY",
-          "INDEX_PLAY",
-          "PAUSE"
-        ]
-      },
-      "android/support/v7/widget/SearchView$AutoCompleteTextViewReflector": {
-        "androidx/widget/SearchView$AutoCompleteTextViewReflector": [
-          "showSoftInputUnchecked",
-          "doAfterTextChanged",
-          "ensureImeVisible",
-          "doBeforeTextChanged"
-        ]
-      },
-      "android/support/text/emoji/R$styleable": {
-        "androidx/text/emoji/R$styleable": [
-          "EmojiExtractTextLayout",
-          "EmojiEditText_maxEmojiCount",
-          "EmojiExtractTextLayout_emojiReplaceStrategy",
-          "EmojiEditText"
-        ]
-      },
-      "android/support/v4/view/animation/PathInterpolatorApi14": {
-        "androidx/view/animation/PathInterpolatorApi14": [
-          "PRECISION"
-        ]
-      },
-      "android/support/v4/app/FragmentTransition": {
-        "androidx/app/FragmentTransition": [
-          "PLATFORM_IMPL",
-          "INVERSE_OPS",
-          "SUPPORT_IMPL"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$Spec": {
-        "androidx/widget/GridLayout$Spec": [
-          "weight",
-          "alignment",
-          "UNDEFINED",
-          "startDefined",
-          "span",
-          "DEFAULT_WEIGHT"
-        ]
-      },
-      "android/support/v4/app/INotificationSideChannel$Stub": {
-        "androidx/app/INotificationSideChannel$Stub": [
-          "TRANSACTION_notify",
-          "TRANSACTION_cancel",
-          "TRANSACTION_cancelAll",
-          "DESCRIPTOR"
-        ]
-      },
-      "android/support/v4/app/FragmentManagerImpl": {
-        "androidx/app/FragmentManagerImpl": [
-          "sAnimationListenerField",
-          "TAG",
-          "ANIM_DUR",
-          "ANIM_STYLE_FADE_EXIT",
-          "DEBUG",
-          "ACCELERATE_QUINT",
-          "TARGET_REQUEST_CODE_STATE_TAG",
-          "ANIM_STYLE_OPEN_EXIT",
-          "ANIM_STYLE_OPEN_ENTER",
-          "TARGET_STATE_TAG",
-          "USER_VISIBLE_HINT_TAG",
-          "ANIM_STYLE_FADE_ENTER",
-          "VIEW_STATE_TAG",
-          "DECELERATE_QUINT",
-          "DECELERATE_CUBIC",
-          "ANIM_STYLE_CLOSE_ENTER",
-          "ACCELERATE_CUBIC",
-          "ANIM_STYLE_CLOSE_EXIT"
-        ]
-      },
-      "android/support/v7/app/MediaRouteButton": {
-        "androidx/app/MediaRouteButton": [
-          "TAG",
-          "sRemoteIndicatorCache",
-          "CHECKED_STATE_SET",
-          "CHECKABLE_STATE_SET",
-          "CONTROLLER_FRAGMENT_TAG",
-          "CHOOSER_FRAGMENT_TAG"
-        ]
-      },
-      "android/support/v7/widget/VectorEnabledTintResources": {
-        "androidx/widget/VectorEnabledTintResources": [
-          "MAX_SDK_WHERE_REQUIRED"
-        ]
-      },
-      "android/support/v7/view/menu/MenuItemImpl": {
-        "androidx/view/menu/MenuItemImpl": [
-          "NO_ICON",
-          "HIDDEN",
-          "sEnterShortcutLabel",
-          "CHECKABLE",
-          "SHOW_AS_ACTION_MASK",
-          "sSpaceShortcutLabel",
-          "EXCLUSIVE",
-          "CHECKED",
-          "TAG",
-          "sDeleteShortcutLabel",
-          "IS_ACTION",
-          "ENABLED",
-          "sPrependShortcutLabel"
-        ]
-      },
-      "android/support/content/InMemoryCursor": {
-        "androidx/content/InMemoryCursor": [
-          "NUM_TYPES"
-        ]
-      },
-      "android/support/v4/app/FragmentPagerAdapter": {
-        "androidx/app/FragmentPagerAdapter": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v4/text/ICUCompat": {
-        "androidx/text/ICUCompat": [
-          "TAG",
-          "sAddLikelySubtagsMethod",
-          "sGetScriptMethod"
-        ]
-      },
-      "android/support/v4/media/session/MediaControllerCompatApi21$PlaybackInfo": {
-        "androidx/media/session/MediaControllerCompatApi21$PlaybackInfo": [
-          "FLAG_SCO",
-          "STREAM_BLUETOOTH_SCO",
-          "STREAM_SYSTEM_ENFORCED"
-        ]
-      },
-      "android/support/text/emoji/R$id": {
-        "androidx/text/emoji/R$id": [
-          "inputExtractAccessories",
-          "inputExtractAction"
-        ]
-      },
-      "android/support/v17/leanback/R$animator": {
-        "androidx/leanback/R$animator": [
-          "lb_onboarding_page_indicator_fade_in",
-          "lb_onboarding_page_indicator_fade_out",
-          "lb_onboarding_start_button_fade_in",
-          "lb_playback_controls_fade_in",
-          "lb_playback_controls_fade_out",
-          "lb_onboarding_logo_enter",
-          "lb_onboarding_start_button_fade_out",
-          "lb_onboarding_page_indicator_enter",
-          "lb_playback_bg_fade_out",
-          "lb_onboarding_title_enter",
-          "lb_onboarding_description_enter",
-          "lb_playback_bg_fade_in",
-          "lb_onboarding_logo_exit"
-        ]
-      },
-      "android/support/transition/TransitionInflater": {
-        "androidx/transition/TransitionInflater": [
-          "CONSTRUCTOR_SIGNATURE",
-          "CONSTRUCTORS"
-        ]
-      },
-      "android/support/v4/media/RatingCompat": {
-        "androidx/media/RatingCompat": [
-          "RATING_THUMB_UP_DOWN",
-          "RATING_5_STARS",
-          "RATING_HEART",
-          "RATING_PERCENTAGE",
-          "CREATOR",
-          "RATING_4_STARS",
-          "RATING_NONE",
-          "RATING_NOT_RATED",
-          "TAG",
-          "RATING_3_STARS"
-        ]
-      },
-      "android/support/v17/leanback/transition/FadeAndShortSlide": {
-        "androidx/leanback/transition/FadeAndShortSlide": [
-          "sCalculateTopBottom",
-          "sCalculateStartEnd",
-          "sCalculateEnd",
-          "sCalculateBottom",
-          "PROPNAME_SCREEN_POSITION",
-          "sDecelerate",
-          "sCalculateStart",
-          "sCalculateTop"
-        ]
-      },
-      "android/support/design/R$attr": {
-        "androidx/design/R$attr": [
-          "state_collapsible",
-          "state_collapsed",
-          "bottomSheetDialogTheme"
-        ]
-      },
-      "android/support/graphics/drawable/PathInterpolatorCompat": {
-        "androidx/graphics/drawable/PathInterpolatorCompat": [
-          "EPSILON",
-          "PRECISION",
-          "MAX_NUM_POINTS"
-        ]
-      },
-      "android/support/animation/SpringAnimation": {
-        "androidx/animation/SpringAnimation": [
-          "UNSET"
-        ]
-      },
-      "android/support/v7/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState": {
-        "androidx/app/AppCompatDelegateImplV9$PanelFeatureState$SavedState": [
-          "featureId",
-          "menuState",
-          "CREATOR",
-          "isOpen"
-        ]
-      },
-      "android/support/v7/view/menu/MenuBuilder": {
-        "androidx/view/menu/MenuBuilder": [
-          "EXPANDED_ACTION_VIEW_ID",
-          "TAG",
-          "PRESENTER_KEY",
-          "ACTION_VIEW_STATES_KEY",
-          "sCategoryToOrder"
-        ]
-      },
-      "android/support/v4/view/ViewGroupCompat": {
-        "androidx/view/ViewGroupCompat": [
-          "LAYOUT_MODE_OPTICAL_BOUNDS",
-          "LAYOUT_MODE_CLIP_BOUNDS",
-          "IMPL"
-        ]
-      },
-      "android/support/v14/preference/MultiSelectListPreferenceDialogFragment": {
-        "androidx/preference/MultiSelectListPreferenceDialogFragment": [
-          "SAVE_STATE_ENTRY_VALUES",
-          "SAVE_STATE_VALUES",
-          "SAVE_STATE_ENTRIES",
-          "SAVE_STATE_CHANGED"
-        ]
-      },
-      "android/support/v4/print/PrintHelper$PrintHelperApi19": {
-        "androidx/print/PrintHelper$PrintHelperApi19": [
-          "MAX_PRINT_SIZE",
-          "LOG_TAG"
-        ]
-      },
-      "android/support/v7/widget/AdapterHelper$UpdateOp": {
-        "androidx/widget/AdapterHelper$UpdateOp": [
-          "positionStart",
-          "payload",
-          "MOVE",
-          "REMOVE",
-          "ADD",
-          "UPDATE",
-          "cmd",
-          "POOL_SIZE",
-          "itemCount"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseFragment$SetSelectionRunnable": {
-        "androidx/leanback/app/BrowseFragment$SetSelectionRunnable": [
-          "TYPE_INTERNAL_SYNC",
-          "TYPE_USER_REQUEST",
-          "TYPE_INVALID"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseSupportFragment$ExpandPreLayout": {
-        "androidx/leanback/app/BrowseSupportFragment$ExpandPreLayout": [
-          "STATE_SECOND_DRAW",
-          "STATE_INIT",
-          "STATE_FIRST_DRAW",
-          "mainFragmentAdapter"
-        ]
-      },
-      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatBaseImpl": {
-        "androidx/widget/PopupWindowCompat$PopupWindowCompatBaseImpl": [
-          "sGetWindowLayoutTypeMethodAttempted",
-          "sGetWindowLayoutTypeMethod",
-          "sSetWindowLayoutTypeMethod",
-          "sSetWindowLayoutTypeMethodAttempted"
-        ]
-      },
-      "android/support/v7/widget/SwitchCompat": {
-        "androidx/widget/SwitchCompat": [
-          "MONOSPACE",
-          "CHECKED_STATE_SET",
-          "TOUCH_MODE_DRAGGING",
-          "TOUCH_MODE_DOWN",
-          "THUMB_POS",
-          "TOUCH_MODE_IDLE",
-          "SERIF",
-          "THUMB_ANIMATION_DURATION",
-          "ACCESSIBILITY_EVENT_CLASS_NAME",
-          "SANS"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$LayoutManager$Properties": {
-        "androidx/widget/RecyclerView$LayoutManager$Properties": [
-          "reverseLayout",
-          "stackFromEnd",
-          "spanCount",
-          "orientation"
-        ]
-      },
-      "android/support/v4/app/NotificationManagerCompat$SideChannelManager": {
-        "androidx/app/NotificationManagerCompat$SideChannelManager": [
-          "MSG_QUEUE_TASK",
-          "MSG_RETRY_LISTENER_QUEUE",
-          "MSG_SERVICE_CONNECTED",
-          "MSG_SERVICE_DISCONNECTED"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry": {
-        "androidx/leanback/app/BrowseSupportFragment$MainFragmentAdapterRegistry": [
-          "sDefaultFragmentFactory"
-        ]
-      },
-      "android/support/v7/preference/PreferenceFragmentCompat": {
-        "androidx/preference/PreferenceFragmentCompat": [
-          "MSG_BIND_PREFERENCES",
-          "PREFERENCES_TAG",
-          "ARG_PREFERENCE_ROOT",
-          "DIALOG_FRAGMENT_TAG"
-        ]
-      },
-      "android/support/v7/widget/SearchView": {
-        "androidx/widget/SearchView": [
-          "ENABLED_STATE_SET",
-          "EMPTY_STATE_SET",
-          "FOCUSED_STATE_SET",
-          "DBG",
-          "IME_OPTION_NO_MICROPHONE",
-          "LOG_TAG",
-          "HIDDEN_METHOD_INVOKER"
-        ]
-      },
-      "android/support/v4/view/AsyncLayoutInflater$BasicInflater": {
-        "androidx/view/AsyncLayoutInflater$BasicInflater": [
-          "sClassPrefixList"
-        ]
-      },
-      "android/support/v7/widget/DividerItemDecoration": {
-        "androidx/widget/DividerItemDecoration": [
-          "VERTICAL",
-          "HORIZONTAL",
-          "ATTRS",
-          "TAG"
-        ]
-      },
-      "android/support/wear/widget/SwipeDismissFrameLayout": {
-        "androidx/wear/widget/SwipeDismissFrameLayout": [
-          "DEFAULT_INTERPOLATION_FACTOR",
-          "TRANSLATION_MIN_ALPHA",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/app/HeadersFragment": {
-        "androidx/leanback/app/HeadersFragment": [
-          "sHeaderPresenter",
-          "sLayoutChangeListener"
-        ]
-      },
-      "android/support/customtabs/CustomTabsService": {
-        "androidx/browser/customtabs/CustomTabsService": [
-          "RESULT_FAILURE_MESSAGING_ERROR",
-          "RESULT_SUCCESS",
-          "RESULT_FAILURE_REMOTE_ERROR",
-          "ACTION_CUSTOM_TABS_CONNECTION",
-          "KEY_URL",
-          "RESULT_FAILURE_DISALLOWED",
-          "RELATION_HANDLE_ALL_URLS",
-          "RELATION_USE_AS_ORIGIN"
-        ]
-      },
-      "android/support/v17/leanback/app/GuidedStepFragment": {
-        "androidx/leanback/app/GuidedStepFragment": [
-          "IS_FRAMEWORK_FRAGMENT",
-          "entranceTransitionType",
-          "ENTRY_NAME_ENTRANCE",
-          "TAG_LEAN_BACK_ACTIONS_FRAGMENT",
-          "UI_STYLE_REPLACE",
-          "EXTRA_BUTTON_ACTION_PREFIX",
-          "UI_STYLE_DEFAULT",
-          "DEBUG",
-          "SLIDE_FROM_BOTTOM",
-          "UI_STYLE_ENTRANCE",
-          "SLIDE_FROM_SIDE",
-          "TAG",
-          "EXTRA_UI_STYLE",
-          "EXTRA_ACTION_PREFIX",
-          "ENTRY_NAME_REPLACE",
-          "UI_STYLE_ACTIVITY_ROOT"
-        ]
-      },
-      "android/support/v17/leanback/util/StateMachine": {
-        "androidx/leanback/util/StateMachine": [
-          "STATUS_ZERO",
-          "STATUS_INVOKED",
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/compat/R$drawable": {
-        "androidx/compat/R$drawable": [
-          "notification_template_icon_bg",
-          "notification_bg",
-          "notification_icon_background",
-          "notification_template_icon_low_bg",
-          "notification_bg_low"
-        ]
-      },
-      "android/support/v4/provider/DocumentsContractApi19": {
-        "androidx/provider/DocumentsContractApi19": [
-          "TAG",
-          "FLAG_VIRTUAL_DOCUMENT"
-        ]
-      },
-      "android/support/v4/app/JobIntentService": {
-        "androidx/app/JobIntentService": [
-          "TAG",
-          "sClassWorkEnqueuer",
-          "DEBUG",
-          "sLock"
-        ]
-      },
-      "android/support/v4/graphics/TypefaceCompatUtil": {
-        "androidx/graphics/TypefaceCompatUtil": [
-          "CACHE_FILE_PREFIX",
-          "TAG"
-        ]
-      },
-      "android/support/transition/Explode": {
-        "androidx/transition/Explode": [
-          "PROPNAME_SCREEN_BOUNDS",
-          "sDecelerate",
-          "sAccelerate"
-        ]
-      },
-      "android/support/v4/view/AccessibilityDelegateCompat": {
-        "androidx/view/AccessibilityDelegateCompat": [
-          "DEFAULT_DELEGATE",
-          "IMPL"
-        ]
-      },
-      "android/support/v4/view/MenuItemCompat": {
-        "androidx/view/MenuItemCompat": [
-          "IMPL",
-          "SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW",
-          "SHOW_AS_ACTION_WITH_TEXT",
-          "SHOW_AS_ACTION_NEVER",
-          "SHOW_AS_ACTION_ALWAYS",
-          "SHOW_AS_ACTION_IF_ROOM",
-          "TAG"
-        ]
-      },
-      "android/support/v4/widget/CircleImageView": {
-        "androidx/widget/CircleImageView": [
-          "SHADOW_RADIUS",
-          "Y_OFFSET",
-          "X_OFFSET",
-          "KEY_SHADOW_COLOR",
-          "SHADOW_ELEVATION",
-          "FILL_SHADOW_COLOR"
-        ]
-      },
-      "android/support/v7/widget/SuggestionsAdapter": {
-        "androidx/widget/SuggestionsAdapter": [
-          "REFINE_NONE",
-          "LOG_TAG",
-          "REFINE_ALL",
-          "INVALID_INDEX",
-          "DBG",
-          "QUERY_LIMIT",
-          "REFINE_BY_ENTRY"
-        ]
-      },
-      "android/support/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder": {
-        "androidx/wear/widget/drawer/WearableActionDrawerView$ActionItemViewHolder": [
-          "view",
-          "iconView",
-          "textView"
-        ]
-      },
-      "android/support/v14/preference/PreferenceDialogFragment": {
-        "androidx/preference/PreferenceDialogFragment": [
-          "SAVE_STATE_POSITIVE_TEXT",
-          "SAVE_STATE_TITLE",
-          "SAVE_STATE_ICON",
-          "ARG_KEY",
-          "SAVE_STATE_MESSAGE",
-          "SAVE_STATE_NEGATIVE_TEXT",
-          "SAVE_STATE_LAYOUT"
-        ]
-      },
-      "android/support/v4/media/session/IMediaControllerCallback$Stub": {
-        "androidx/media/session/IMediaControllerCallback$Stub": [
-          "TRANSACTION_onSessionDestroyed",
-          "TRANSACTION_onMetadataChanged",
-          "TRANSACTION_onEvent",
-          "TRANSACTION_onQueueChanged",
-          "TRANSACTION_onSessionReady",
-          "TRANSACTION_onCaptioningEnabledChanged",
-          "TRANSACTION_onVolumeInfoChanged",
-          "TRANSACTION_onShuffleModeChangedRemoved",
-          "TRANSACTION_onRepeatModeChanged",
-          "TRANSACTION_onPlaybackStateChanged",
-          "TRANSACTION_onQueueTitleChanged",
-          "TRANSACTION_onShuffleModeChanged",
-          "DESCRIPTOR",
-          "TRANSACTION_onExtrasChanged"
-        ]
-      },
-      "android/support/v7/preference/EditTextPreference$SavedState": {
-        "androidx/preference/EditTextPreference$SavedState": [
-          "text",
-          "CREATOR"
-        ]
-      },
-      "android/support/v17/leanback/widget/PagingIndicator$Dot": {
-        "androidx/leanback/widget/PagingIndicator$Dot": [
-          "LEFT",
-          "LTR",
-          "RIGHT",
-          "RTL"
-        ]
-      },
-      "android/support/v7/widget/ScrollingTabContainerView$TabView": {
-        "androidx/widget/ScrollingTabContainerView$TabView": [
-          "BG_ATTRS"
-        ]
-      },
-      "android/support/wear/ambient/SharedLibraryVersion$PresenceHolder": {
-        "androidx/wear/ambient/SharedLibraryVersion$PresenceHolder": [
-          "PRESENT"
-        ]
-      },
-      "android/support/v4/graphics/BitmapCompat": {
-        "androidx/graphics/BitmapCompat": [
-          "IMPL"
-        ]
-      },
-      "android/support/wear/R$fraction": {
-        "androidx/wear/R$fraction": [
-          "ws_action_drawer_item_right_padding",
-          "ws_action_drawer_item_last_item_bottom_padding",
-          "ws_action_drawer_item_left_padding",
-          "ws_action_drawer_item_first_item_top_padding"
-        ]
-      },
-      "android/support/v7/media/MediaSessionStatus": {
-        "androidx/media/MediaSessionStatus": [
-          "KEY_TIMESTAMP",
-          "SESSION_STATE_INVALIDATED",
-          "KEY_EXTRAS",
-          "KEY_QUEUE_PAUSED",
-          "KEY_SESSION_STATE",
-          "SESSION_STATE_ENDED",
-          "SESSION_STATE_ACTIVE"
-        ]
-      },
-      "android/support/v4/app/NotificationManagerCompat$CancelTask": {
-        "androidx/app/NotificationManagerCompat$CancelTask": [
-          "tag",
-          "all",
-          "id",
-          "packageName"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserCompat$MediaBrowserImplBase": {
-        "androidx/media/MediaBrowserCompat$MediaBrowserImplBase": [
-          "CONNECT_STATE_DISCONNECTED",
-          "CONNECT_STATE_CONNECTED",
-          "CONNECT_STATE_CONNECTING",
-          "CONNECT_STATE_SUSPENDED",
-          "CONNECT_STATE_DISCONNECTING"
-        ]
-      },
-      "android/support/wear/widget/WearableRecyclerView": {
-        "androidx/wear/widget/WearableRecyclerView": [
-          "TAG",
-          "NO_VALUE"
-        ]
-      },
-      "android/support/app/recommendation/RecommendationExtender": {
-        "androidx/app/recommendation/RecommendationExtender": [
-          "KEY_CONTENT_RUN_LENGTH",
-          "KEY_CONTENT_GENRES",
-          "KEY_CONTENT_TYPE",
-          "TAG",
-          "EXTRA_CONTENT_INFO_EXTENDER",
-          "KEY_CONTENT_MATURITY_RATING",
-          "KEY_CONTENT_STATUS",
-          "KEY_CONTENT_PRICING_VALUE",
-          "KEY_CONTENT_PRICING_TYPE"
-        ]
-      },
-      "android/support/v7/widget/ThemeUtils": {
-        "androidx/widget/ThemeUtils": [
-          "TEMP_ARRAY",
-          "DISABLED_STATE_SET",
-          "ACTIVATED_STATE_SET",
-          "NOT_PRESSED_OR_FOCUSED_STATE_SET",
-          "FOCUSED_STATE_SET",
-          "SELECTED_STATE_SET",
-          "CHECKED_STATE_SET",
-          "PRESSED_STATE_SET",
-          "EMPTY_STATE_SET",
-          "TL_TYPED_VALUE"
-        ]
-      },
-      "android/support/media/ExifInterface$ByteOrderedDataInputStream": {
-        "androidx/media/ExifInterface$ByteOrderedDataInputStream": [
-          "BIG_ENDIAN",
-          "LITTLE_ENDIAN"
-        ]
-      },
-      "android/support/v7/widget/helper/ItemTouchHelper$Callback": {
-        "androidx/widget/helper/ItemTouchHelper$Callback": [
-          "ABS_HORIZONTAL_DIR_FLAGS",
-          "sDragScrollInterpolator",
-          "DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS",
-          "DEFAULT_DRAG_ANIMATION_DURATION",
-          "RELATIVE_DIR_FLAGS",
-          "DEFAULT_SWIPE_ANIMATION_DURATION",
-          "sDragViewScrollCapInterpolator",
-          "sUICallback"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserServiceCompat$BrowserRoot": {
-        "androidx/media/MediaBrowserServiceCompat$BrowserRoot": [
-          "EXTRA_SUGGESTION_KEYWORDS",
-          "EXTRA_SUGGESTED",
-          "EXTRA_OFFLINE",
-          "EXTRA_RECENT"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsPresenter": {
-        "androidx/leanback/widget/PlaybackControlsPresenter": [
-          "sChildMarginBigger",
-          "sChildMarginBiggest"
-        ]
-      },
-      "android/support/v7/preference/PreferenceDialogFragmentCompat": {
-        "androidx/preference/PreferenceDialogFragmentCompat": [
-          "SAVE_STATE_LAYOUT",
-          "ARG_KEY",
-          "SAVE_STATE_ICON",
-          "SAVE_STATE_MESSAGE",
-          "SAVE_STATE_TITLE",
-          "SAVE_STATE_NEGATIVE_TEXT",
-          "SAVE_STATE_POSITIVE_TEXT"
-        ]
-      },
-      "android/support/v7/app/TwilightManager": {
-        "androidx/app/TwilightManager": [
-          "SUNRISE",
-          "SUNSET",
-          "TAG",
-          "sInstance"
-        ]
-      },
-      "android/support/v4/graphics/drawable/DrawableCompat": {
-        "androidx/graphics/drawable/DrawableCompat": [
-          "sSetLayoutDirectionMethod",
-          "sGetLayoutDirectionMethodFetched",
-          "sGetLayoutDirectionMethod",
-          "TAG",
-          "sSetLayoutDirectionMethodFetched"
-        ]
-      },
-      "android/support/v4/graphics/drawable/RoundedBitmapDrawableFactory": {
-        "androidx/graphics/drawable/RoundedBitmapDrawableFactory": [
-          "TAG"
-        ]
-      },
-      "android/support/transition/GhostViewApi21": {
-        "androidx/transition/GhostViewApi21": [
-          "sAddGhostMethod",
-          "TAG",
-          "sRemoveGhostMethod",
-          "sAddGhostMethodFetched",
-          "sRemoveGhostMethodFetched",
-          "sGhostViewClassFetched",
-          "sGhostViewClass"
-        ]
-      },
-      "android/support/v7/app/ActionBar": {
-        "androidx/app/ActionBar": [
-          "NAVIGATION_MODE_TABS",
-          "NAVIGATION_MODE_LIST",
-          "DISPLAY_SHOW_TITLE",
-          "DISPLAY_SHOW_CUSTOM",
-          "DISPLAY_USE_LOGO",
-          "NAVIGATION_MODE_STANDARD",
-          "DISPLAY_HOME_AS_UP",
-          "DISPLAY_SHOW_HOME"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$WatchNextPrograms": {
-        "androidx/media/tv/TvContractCompat$WatchNextPrograms": [
-          "WATCH_NEXT_TYPE_WATCHLIST",
-          "WATCH_NEXT_TYPE_CONTINUE",
-          "WATCH_NEXT_TYPE_NEXT",
-          "COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS",
-          "CONTENT_URI",
-          "WATCH_NEXT_TYPE_NEW",
-          "CONTENT_TYPE",
-          "COLUMN_WATCH_NEXT_TYPE",
-          "CONTENT_ITEM_TYPE"
-        ]
-      },
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat": {
-        "androidx/view/accessibility/AccessibilityNodeInfoCompat$CollectionInfoCompat": [
-          "SELECTION_MODE_MULTIPLE",
-          "SELECTION_MODE_SINGLE",
-          "SELECTION_MODE_NONE"
-        ]
-      },
-      "android/support/v17/preference/R$id": {
-        "androidx/leanback/preference/R$id": [
-          "button",
-          "settings_preference_fragment_container",
-          "main_frame",
-          "container",
-          "decor_title",
-          "settings_dialog_container"
-        ]
-      },
-      "android/support/wear/R$style": {
-        "androidx/wear/R$style": [
-          "Widget_Wear_WearableDrawerView",
-          "WsPageIndicatorViewStyle"
-        ]
-      },
-      "android/support/v17/leanback/widget/GuidedActionAdapterGroup": {
-        "androidx/leanback/widget/GuidedActionAdapterGroup": [
-          "TAG_EDIT",
-          "DEBUG_EDIT"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$PackedMap": {
-        "androidx/widget/GridLayout$PackedMap": [
-          "values",
-          "index",
-          "keys"
-        ]
-      },
-      "android/support/v7/widget/ActionBarOverlayLayout": {
-        "androidx/widget/ActionBarOverlayLayout": [
-          "TAG",
-          "ATTRS",
-          "ACTION_BAR_ANIMATE_DELAY"
-        ]
-      },
-      "android/support/v4/app/NavUtils": {
-        "androidx/app/NavUtils": [
-          "TAG",
-          "PARENT_ACTIVITY"
-        ]
-      },
-      "android/support/v7/media/RemotePlaybackClient$ActionReceiver": {
-        "androidx/media/RemotePlaybackClient$ActionReceiver": [
-          "ACTION_ITEM_STATUS_CHANGED",
-          "ACTION_MESSAGE_RECEIVED",
-          "ACTION_SESSION_STATUS_CHANGED"
-        ]
-      },
-      "android/support/v4/app/JobIntentService$JobServiceEngineImpl": {
-        "androidx/app/JobIntentService$JobServiceEngineImpl": [
-          "TAG",
-          "DEBUG"
-        ]
-      },
-      "android/support/v4/app/FragmentActivity$NonConfigurationInstances": {
-        "androidx/app/FragmentActivity$NonConfigurationInstances": [
-          "custom",
-          "fragments",
-          "loaders"
-        ]
-      },
-      "android/support/text/emoji/flatbuffer/FlatBufferBuilder": {
-        "androidx/text/emoji/flatbuffer/FlatBufferBuilder": [
-          "encoder",
-          "vtable_in_use",
-          "minalign",
-          "vtables",
-          "num_vtables",
-          "force_defaults",
-          "space",
-          "bb",
-          "object_start",
-          "vtable",
-          "dst",
-          "vector_num_elems",
-          "nested",
-          "finished",
-          "utf8charset"
-        ]
-      },
-      "android/support/v7/mediarouter/R$interpolator": {
-        "androidx/mediarouter/R$interpolator": [
-          "mr_fast_out_slow_in",
-          "mr_linear_out_slow_in"
-        ]
-      },
-      "android/support/v7/recyclerview/R$dimen": {
-        "androidx/recyclerview/R$dimen": [
-          "item_touch_helper_max_drag_scroll_per_frame",
-          "fastscroll_minimum_range",
-          "item_touch_helper_swipe_escape_max_velocity",
-          "fastscroll_default_thickness",
-          "item_touch_helper_swipe_escape_velocity",
-          "fastscroll_margin"
-        ]
-      },
-      "android/support/v4/app/ShareCompat": {
-        "androidx/app/ShareCompat": [
-          "EXTRA_CALLING_PACKAGE",
-          "HISTORY_FILENAME_PREFIX",
-          "EXTRA_CALLING_ACTIVITY"
-        ]
-      },
-      "android/support/v4/media/AudioAttributesCompatApi21": {
-        "androidx/media/AudioAttributesCompatApi21": [
-          "TAG",
-          "sAudioAttributesToLegacyStreamType"
-        ]
-      },
-      "android/support/customtabs/CustomTabsCallback": {
-        "androidx/browser/customtabs/CustomTabsCallback": [
-          "NAVIGATION_FINISHED",
-          "NAVIGATION_ABORTED",
-          "NAVIGATION_FAILED",
-          "NAVIGATION_STARTED",
-          "TAB_HIDDEN",
-          "TAB_SHOWN"
-        ]
-      },
-      "android/support/wear/widget/CircularProgressLayout": {
-        "androidx/wear/widget/CircularProgressLayout": [
-          "DEFAULT_ROTATION",
-          "DEFAULT_UPDATE_INTERVAL"
-        ]
-      },
-      "android/support/v17/leanback/widget/ListRowPresenter": {
-        "androidx/leanback/widget/ListRowPresenter": [
-          "DEBUG",
-          "TAG",
-          "sExpandedSelectedRowTopPadding",
-          "DEFAULT_RECYCLED_POOL_SIZE",
-          "sExpandedRowNoHovercardBottomPadding",
-          "sSelectedRowTopPadding"
-        ]
-      },
-      "android/support/v7/preference/PreferenceGroupAdapter$PreferenceLayout": {
-        "androidx/preference/PreferenceGroupAdapter$PreferenceLayout": [
-          "widgetResId",
-          "resId",
-          "name"
-        ]
-      },
-      "android/support/transition/Styleable$Transition": {
-        "androidx/transition/Styleable$Transition": [
-          "MATCH_ORDER",
-          "START_DELAY",
-          "DURATION",
-          "INTERPOLATOR"
-        ]
-      },
-      "android/support/v4/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat": {
-        "androidx/view/accessibility/AccessibilityNodeInfoCompat$RangeInfoCompat": [
-          "RANGE_TYPE_PERCENT",
-          "RANGE_TYPE_INT",
-          "RANGE_TYPE_FLOAT"
-        ]
-      },
-      "android/support/transition/Styleable$Fade": {
-        "androidx/transition/Styleable$Fade": [
-          "FADING_MODE"
-        ]
-      },
-      "android/support/v4/app/SharedElementCallback": {
-        "androidx/app/SharedElementCallback": [
-          "BUNDLE_SNAPSHOT_BITMAP",
-          "BUNDLE_SNAPSHOT_IMAGE_MATRIX",
-          "BUNDLE_SNAPSHOT_IMAGE_SCALETYPE",
-          "MAX_IMAGE_SIZE"
-        ]
-      },
-      "android/support/design/widget/ThemeUtils": {
-        "androidx/design/widget/ThemeUtils": [
-          "APPCOMPAT_CHECK_ATTRS"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$Programs": {
-        "androidx/media/tv/TvContractCompat$Programs": [
-          "COLUMN_BROADCAST_GENRE",
-          "COLUMN_CHANNEL_ID",
-          "COLUMN_START_TIME_UTC_MILLIS",
-          "CONTENT_ITEM_TYPE",
-          "CONTENT_TYPE",
-          "COLUMN_EPISODE_NUMBER",
-          "COLUMN_END_TIME_UTC_MILLIS",
-          "COLUMN_RECORDING_PROHIBITED",
-          "CONTENT_URI",
-          "COLUMN_SEASON_NUMBER"
-        ]
-      },
-      "android/support/v17/leanback/R$integer": {
-        "androidx/leanback/R$integer": [
-          "lb_details_description_body_min_lines",
-          "lb_search_orb_pulse_duration_ms",
-          "lb_search_bar_speech_mode_background_alpha",
-          "lb_search_bar_text_mode_background_alpha",
-          "lb_details_description_body_max_lines",
-          "lb_card_activated_animation_duration",
-          "lb_card_selected_animation_duration",
-          "lb_search_orb_scale_duration_ms",
-          "lb_browse_rows_anim_duration",
-          "lb_playback_controls_show_time_ms",
-          "lb_card_selected_animation_delay"
-        ]
-      },
-      "android/support/mediacompat/R$id": {
-        "androidx/mediacompat/R$id": [
-          "action0",
-          "media_actions",
-          "cancel_action",
-          "status_bar_latest_event_content",
-          "end_padder"
-        ]
-      },
-      "android/support/v17/leanback/widget/Row": {
-        "androidx/leanback/widget/Row": [
-          "FLAG_ID_USE_HEADER",
-          "FLAG_ID_USE_ID",
-          "FLAG_ID_USE_MASK"
-        ]
-      },
-      "android/support/compat/R$layout": {
-        "androidx/compat/R$layout": [
-          "notification_action_tombstone",
-          "notification_template_custom_big",
-          "notification_action"
-        ]
-      },
-      "android/support/v4/app/FragmentManagerImpl$AnimationOrAnimator": {
-        "androidx/app/FragmentManagerImpl$AnimationOrAnimator": [
-          "animator",
-          "animation"
-        ]
-      },
-      "android/support/transition/VisibilityPropagation": {
-        "androidx/transition/VisibilityPropagation": [
-          "PROPNAME_VISIBILITY",
-          "PROPNAME_VIEW_CENTER",
-          "VISIBILITY_PROPAGATION_VALUES"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$Action$WearableExtender": {
-        "androidx/app/NotificationCompat$Action$WearableExtender": [
-          "KEY_FLAGS",
-          "KEY_CONFIRM_LABEL",
-          "KEY_CANCEL_LABEL",
-          "FLAG_HINT_LAUNCHES_ACTIVITY",
-          "KEY_IN_PROGRESS_LABEL",
-          "EXTRA_WEARABLE_EXTENSIONS",
-          "FLAG_AVAILABLE_OFFLINE",
-          "FLAG_HINT_DISPLAY_INLINE",
-          "DEFAULT_FLAGS"
-        ]
-      },
-      "android/support/v4/view/ViewPager$ItemInfo": {
-        "androidx/view/ViewPager$ItemInfo": [
-          "offset",
-          "object",
-          "position",
-          "widthFactor",
-          "scrolling"
-        ]
-      },
-      "android/support/v17/leanback/transition/TransitionHelper": {
-        "androidx/leanback/transition/TransitionHelper": [
-          "SLIDE_RIGHT",
-          "sImpl",
-          "SLIDE_BOTTOM",
-          "FADE_OUT",
-          "SLIDE_TOP",
-          "FADE_IN",
-          "SLIDE_LEFT"
-        ]
-      },
-      "android/support/v4/widget/AutoSizeableTextView": {
-        "androidx/widget/AutoSizeableTextView": [
-          "PLATFORM_SUPPORTS_AUTOSIZE"
-        ]
-      },
-      "android/support/v7/widget/SimpleItemAnimator": {
-        "androidx/widget/SimpleItemAnimator": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/transition/TransitionManager": {
-        "androidx/transition/TransitionManager": [
-          "sPendingTransitions",
-          "sRunningTransitions",
-          "sDefaultTransition",
-          "LOG_TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/WindowAlignment$Axis": {
-        "androidx/leanback/widget/WindowAlignment$Axis": [
-          "PF_KEYLINE_OVER_HIGH_EDGE",
-          "PF_KEYLINE_OVER_LOW_EDGE"
-        ]
-      },
-      "android/support/v7/widget/AppCompatPopupWindow": {
-        "androidx/widget/AppCompatPopupWindow": [
-          "COMPAT_OVERLAP_ANCHOR"
-        ]
-      },
-      "android/support/constraint/solver/widgets/ConstraintAnchor$Type": {
-        "androidx/constraint/solver/widgets/ConstraintAnchor$Type": [
-          "RIGHT",
-          "TOP",
-          "BOTTOM",
-          "LEFT",
-          "BASELINE"
-        ]
-      },
-      "android/support/wear/widget/drawer/WearableDrawerLayout": {
-        "androidx/wear/widget/drawer/WearableDrawerLayout": [
-          "TAG",
-          "UP",
-          "OPENED_PERCENT_THRESHOLD",
-          "NESTED_SCROLL_SLOP_DP",
-          "GRAVITY_UNDEFINED",
-          "DOWN",
-          "PEEK_FADE_DURATION_MS",
-          "PEEK_AUTO_CLOSE_DELAY_MS"
-        ]
-      },
-      "android/support/v17/leanback/widget/ShadowOverlayHelper$Builder": {
-        "androidx/leanback/widget/ShadowOverlayHelper$Builder": [
-          "options",
-          "needsRoundedCorner",
-          "keepForegroundDrawable",
-          "preferZOrder",
-          "needsOverlay",
-          "needsShadow"
-        ]
-      },
-      "android/support/v7/media/MediaRouteProvider": {
-        "androidx/media/MediaRouteProvider": [
-          "MSG_DELIVER_DESCRIPTOR_CHANGED",
-          "MSG_DELIVER_DISCOVERY_REQUEST_CHANGED"
-        ]
-      },
-      "android/support/design/widget/AppBarLayout$LayoutParams": {
-        "androidx/design/widget/AppBarLayout$LayoutParams": [
-          "SCROLL_FLAG_ENTER_ALWAYS_COLLAPSED",
-          "bottomMargin",
-          "topMargin",
-          "SCROLL_FLAG_EXIT_UNTIL_COLLAPSED",
-          "SCROLL_FLAG_SCROLL",
-          "COLLAPSIBLE_FLAGS",
-          "FLAG_SNAP",
-          "SCROLL_FLAG_SNAP",
-          "FLAG_QUICK_RETURN",
-          "SCROLL_FLAG_ENTER_ALWAYS"
-        ]
-      },
-      "android/support/v7/media/MediaRouterJellybean": {
-        "androidx/media/MediaRouterJellybean": [
-          "TAG",
-          "DEVICE_OUT_BLUETOOTH",
-          "ROUTE_TYPE_LIVE_AUDIO",
-          "ROUTE_TYPE_USER",
-          "ROUTE_TYPE_LIVE_VIDEO",
-          "ALL_ROUTE_TYPES"
-        ]
-      },
-      "android/support/content/LoaderQueryRunner": {
-        "androidx/content/LoaderQueryRunner": [
-          "TAG",
-          "CONTENT_URI_KEY",
-          "DEBUG"
-        ]
-      },
-      "android/support/v17/leanback/app/BackgroundManager$BackgroundContinuityService": {
-        "androidx/leanback/app/BackgroundManager$BackgroundContinuityService": [
-          "DEBUG",
-          "TAG",
-          "sService"
-        ]
-      },
-      "android/support/design/internal/NavigationMenuPresenter": {
-        "androidx/design/internal/NavigationMenuPresenter": [
-          "STATE_HEADER",
-          "STATE_ADAPTER",
-          "STATE_HIERARCHY"
-        ]
-      },
-      "android/support/v17/leanback/widget/RowPresenter$ViewHolder": {
-        "androidx/leanback/widget/RowPresenter$ViewHolder": [
-          "ACTIVATED_NOT_ASSIGNED",
-          "NOT_ACTIVATED",
-          "ACTIVATED",
-          "view"
-        ]
-      },
-      "android/support/v7/widget/AppCompatCheckedTextView": {
-        "androidx/widget/AppCompatCheckedTextView": [
-          "TINT_ATTRS"
-        ]
-      },
-      "android/support/transition/ChangeImageTransform": {
-        "androidx/transition/ChangeImageTransform": [
-          "PROPNAME_BOUNDS",
-          "NULL_MATRIX_EVALUATOR",
-          "ANIMATED_TRANSFORM_PROPERTY",
-          "sTransitionProperties",
-          "PROPNAME_MATRIX"
-        ]
-      },
-      "android/support/design/widget/AppBarLayout$Behavior$SavedState": {
-        "androidx/design/widget/AppBarLayout$Behavior$SavedState": [
-          "firstVisibleChildIndex",
-          "firstVisibleChildPercentageShown",
-          "firstVisibleChildAtMinimumHeight",
-          "CREATOR"
-        ]
-      },
-      "android/support/design/widget/Snackbar": {
-        "androidx/design/widget/Snackbar": [
-          "LENGTH_SHORT",
-          "LENGTH_INDEFINITE",
-          "LENGTH_LONG"
-        ]
-      },
-      "android/support/v7/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo": {
-        "androidx/app/ActionBarDrawerToggleHoneycomb$SetIndicatorInfo": [
-          "setHomeActionContentDescription",
-          "setHomeAsUpIndicator",
-          "upIndicatorView"
-        ]
-      },
-      "android/support/v17/leanback/widget/Grid": {
-        "androidx/leanback/widget/Grid": [
-          "START_DEFAULT"
-        ]
-      },
-      "android/support/media/tv/WatchNextProgram": {
-        "androidx/media/tv/WatchNextProgram": [
-          "PROJECTION",
-          "INVALID_INT_VALUE",
-          "INVALID_LONG_VALUE"
-        ]
-      },
-      "android/support/v7/widget/TintContextWrapper": {
-        "androidx/widget/TintContextWrapper": [
-          "CACHE_LOCK",
-          "sCache"
-        ]
-      },
-      "android/support/text/emoji/flatbuffer/Constants": {
-        "androidx/text/emoji/flatbuffer/Constants": [
-          "SIZEOF_INT",
-          "SIZEOF_FLOAT",
-          "SIZEOF_LONG",
-          "FILE_IDENTIFIER_LENGTH",
-          "SIZEOF_SHORT",
-          "SIZEOF_BYTE",
-          "SIZEOF_DOUBLE"
-        ]
-      },
-      "android/support/wear/widget/CurvingLayoutCallback": {
-        "androidx/wear/widget/CurvingLayoutCallback": [
-          "EPSILON"
-        ]
-      },
-      "android/support/v4/app/AppOpsManagerCompat": {
-        "androidx/app/AppOpsManagerCompat": [
-          "MODE_IGNORED",
-          "MODE_DEFAULT",
-          "MODE_ALLOWED"
-        ]
-      },
-      "android/support/v4/widget/CursorAdapter": {
-        "androidx/widget/CursorAdapter": [
-          "FLAG_AUTO_REQUERY",
-          "FLAG_REGISTER_CONTENT_OBSERVER"
-        ]
-      },
-      "android/support/v17/leanback/app/DetailsBackgroundVideoHelper": {
-        "androidx/leanback/app/DetailsBackgroundVideoHelper": [
-          "NO_VIDEO",
-          "CROSSFADE_DELAY",
-          "INITIAL",
-          "BACKGROUND_CROSS_FADE_DURATION",
-          "PLAY_VIDEO"
-        ]
-      },
-      "android/support/transition/ChangeBounds": {
-        "androidx/transition/ChangeBounds": [
-          "PROPNAME_BOUNDS",
-          "POSITION_PROPERTY",
-          "sRectEvaluator",
-          "BOTTOM_RIGHT_PROPERTY",
-          "BOTTOM_RIGHT_ONLY_PROPERTY",
-          "DRAWABLE_ORIGIN_PROPERTY",
-          "sTransitionProperties",
-          "TOP_LEFT_ONLY_PROPERTY",
-          "PROPNAME_PARENT",
-          "TOP_LEFT_PROPERTY",
-          "PROPNAME_CLIP",
-          "PROPNAME_WINDOW_X",
-          "PROPNAME_WINDOW_Y"
-        ]
-      },
-      "android/support/v4/widget/SwipeProgressBar": {
-        "androidx/widget/SwipeProgressBar": [
-          "INTERPOLATOR",
-          "ANIMATION_DURATION_MS",
-          "FINISH_ANIMATION_DURATION_MS",
-          "COLOR2",
-          "COLOR1",
-          "COLOR4",
-          "COLOR3"
-        ]
-      },
-      "android/support/v17/leanback/media/PlaybackTransportControlGlue": {
-        "androidx/leanback/media/PlaybackTransportControlGlue": [
-          "UPDATE_PLAYBACK_STATE_DELAY_MS",
-          "sHandler",
-          "TAG",
-          "DEBUG",
-          "MSG_UPDATE_PLAYBACK_STATE"
-        ]
-      },
-      "android/support/media/tv/BasePreviewProgram": {
-        "androidx/media/tv/BasePreviewProgram": [
-          "IS_LIVE",
-          "IS_TRANSIENT",
-          "PROJECTION",
-          "INVALID_LONG_VALUE",
-          "INVALID_INT_VALUE",
-          "IS_BROWSABLE"
-        ]
-      },
-      "android/support/v4/widget/TextViewCompat$TextViewCompatBaseImpl": {
-        "androidx/widget/TextViewCompat$TextViewCompatBaseImpl": [
-          "sMaxModeFieldFetched",
-          "sMinimumFieldFetched",
-          "sMinModeField",
-          "sMaximumField",
-          "sMinModeFieldFetched",
-          "sMaxModeField",
-          "sMinimumField",
-          "LOG_TAG",
-          "sMaximumFieldFetched",
-          "LINES"
-        ]
-      },
-      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver": {
-        "androidx/media/SystemMediaRouteProvider$LegacyImpl$VolumeChangeReceiver": [
-          "EXTRA_VOLUME_STREAM_TYPE",
-          "VOLUME_CHANGED_ACTION",
-          "EXTRA_VOLUME_STREAM_VALUE"
-        ]
-      },
-      "android/support/transition/Styleable$ChangeBounds": {
-        "androidx/transition/Styleable$ChangeBounds": [
-          "RESIZE_CLIP"
-        ]
-      },
-      "android/support/v7/widget/ActivityChooserModel": {
-        "androidx/widget/ActivityChooserModel": [
-          "DEFAULT_ACTIVITY_INFLATION",
-          "ATTRIBUTE_TIME",
-          "TAG_HISTORICAL_RECORD",
-          "DEFAULT_HISTORY_FILE_NAME",
-          "HISTORY_FILE_EXTENSION",
-          "TAG_HISTORICAL_RECORDS",
-          "ATTRIBUTE_ACTIVITY",
-          "ATTRIBUTE_WEIGHT",
-          "DEBUG",
-          "INVALID_INDEX",
-          "DEFAULT_HISTORICAL_RECORD_WEIGHT",
-          "sDataModelRegistry",
-          "sRegistryLock",
-          "DEFAULT_HISTORY_MAX_LENGTH",
-          "LOG_TAG"
-        ]
-      },
-      "android/support/v7/widget/ViewUtils": {
-        "androidx/widget/ViewUtils": [
-          "TAG",
-          "sComputeFitSystemWindowsMethod"
-        ]
-      },
-      "android/support/v14/preference/ListPreferenceDialogFragment": {
-        "androidx/preference/ListPreferenceDialogFragment": [
-          "SAVE_STATE_ENTRIES",
-          "SAVE_STATE_INDEX",
-          "SAVE_STATE_ENTRY_VALUES"
-        ]
-      },
-      "android/support/v17/leanback/widget/RoundedRectHelper": {
-        "androidx/leanback/widget/RoundedRectHelper": [
-          "sInstance"
-        ]
-      },
-      "android/support/transition/Styleable$TransitionManager": {
-        "androidx/transition/Styleable$TransitionManager": [
-          "FROM_SCENE",
-          "TRANSITION",
-          "TO_SCENE"
-        ]
-      },
-      "android/support/v17/leanback/R$style": {
-        "androidx/leanback/R$style": [
-          "TextAppearance_Leanback_SearchTextEdit",
-          "Widget_Leanback_ImageCardView"
-        ]
-      },
-      "android/support/v7/widget/ShareActionProvider": {
-        "androidx/widget/ShareActionProvider": [
-          "DEFAULT_SHARE_HISTORY_FILE_NAME",
-          "DEFAULT_INITIAL_ACTIVITY_COUNT"
-        ]
-      },
-      "android/support/v4/app/ListFragment": {
-        "androidx/app/ListFragment": [
-          "INTERNAL_EMPTY_ID",
-          "INTERNAL_PROGRESS_CONTAINER_ID",
-          "INTERNAL_LIST_CONTAINER_ID"
-        ]
-      },
-      "android/support/design/widget/BottomSheetBehavior$SavedState": {
-        "androidx/design/widget/BottomSheetBehavior$SavedState": [
-          "state",
-          "CREATOR"
-        ]
-      },
-      "android/support/v7/appcompat/R$color": {
-        "androidx/appcompat/R$color": [
-          "abc_tint_switch_track",
-          "abc_tint_edittext",
-          "abc_tint_btn_checkable",
-          "abc_tint_default",
-          "abc_tint_spinner",
-          "abc_tint_seek_thumb",
-          "error_color_material",
-          "abc_input_method_navigation_guard"
-        ]
-      },
-      "android/support/v17/leanback/R$raw": {
-        "androidx/leanback/R$raw": [
-          "lb_voice_no_input",
-          "lb_voice_failure",
-          "lb_voice_success",
-          "lb_voice_open"
-        ]
-      },
-      "android/support/v7/util/DiffUtil$PostponedUpdate": {
-        "androidx/util/DiffUtil$PostponedUpdate": [
-          "posInOwnerList",
-          "removal",
-          "currentPos"
-        ]
-      },
-      "android/support/v7/graphics/drawable/DrawerArrowDrawable": {
-        "androidx/graphics/drawable/DrawerArrowDrawable": [
-          "ARROW_DIRECTION_LEFT",
-          "ARROW_HEAD_ANGLE",
-          "ARROW_DIRECTION_RIGHT",
-          "ARROW_DIRECTION_END",
-          "ARROW_DIRECTION_START"
-        ]
-      },
-      "android/support/v4/os/IResultReceiver$Stub": {
-        "androidx/os/IResultReceiver$Stub": [
-          "TRANSACTION_send",
-          "DESCRIPTOR"
-        ]
-      },
-      "android/support/v7/util/DiffUtil$Range": {
-        "androidx/util/DiffUtil$Range": [
-          "newListEnd",
-          "oldListEnd",
-          "newListStart",
-          "oldListStart"
-        ]
-      },
-      "android/support/v7/widget/ActionMenuPresenter$SavedState": {
-        "androidx/widget/ActionMenuPresenter$SavedState": [
-          "CREATOR",
-          "openSubMenuId"
-        ]
-      },
-      "android/support/v17/leanback/widget/GuidedActionAdapter": {
-        "androidx/leanback/widget/GuidedActionAdapter": [
-          "DEBUG",
-          "DEBUG_EDIT",
-          "TAG_EDIT",
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/AppCompatMultiAutoCompleteTextView": {
-        "androidx/widget/AppCompatMultiAutoCompleteTextView": [
-          "TINT_ATTRS"
-        ]
-      },
-      "android/support/compat/R$dimen": {
-        "androidx/compat/R$dimen": [
-          "notification_small_icon_background_padding",
-          "notification_top_pad_large_text",
-          "notification_large_icon_width",
-          "notification_small_icon_size_as_large",
-          "notification_big_circle_margin",
-          "notification_subtext_size",
-          "notification_top_pad",
-          "notification_right_icon_size"
-        ]
-      },
-      "android/support/customtabs/CustomTabsSessionToken": {
-        "androidx/browser/customtabs/CustomTabsSessionToken": [
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/StaggeredGrid$Location": {
-        "androidx/leanback/widget/StaggeredGrid$Location": [
-          "row",
-          "offset",
-          "size"
-        ]
-      },
-      "android/support/compat/R$color": {
-        "androidx/compat/R$color": [
-          "notification_action_color_filter"
-        ]
-      },
-      "android/support/v7/widget/DefaultItemAnimator$ChangeInfo": {
-        "androidx/widget/DefaultItemAnimator$ChangeInfo": [
-          "toY",
-          "toX",
-          "oldHolder",
-          "newHolder",
-          "fromY",
-          "fromX"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsPresenter$ViewHolder": {
-        "androidx/leanback/widget/PlaybackControlsPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v4/app/DialogFragment": {
-        "androidx/app/DialogFragment": [
-          "SAVED_SHOWS_DIALOG",
-          "STYLE_NORMAL",
-          "STYLE_NO_INPUT",
-          "SAVED_CANCELABLE",
-          "SAVED_THEME",
-          "SAVED_DIALOG_STATE_TAG",
-          "STYLE_NO_TITLE",
-          "SAVED_BACK_STACK_ID",
-          "STYLE_NO_FRAME",
-          "SAVED_STYLE"
-        ]
-      },
-      "android/support/v17/leanback/widget/BaseCardView$LayoutParams": {
-        "androidx/leanback/widget/BaseCardView$LayoutParams": [
-          "VIEW_TYPE_INFO",
-          "VIEW_TYPE_MAIN",
-          "VIEW_TYPE_EXTRA",
-          "viewType"
-        ]
-      },
-      "android/support/wear/ambient/WearableControllerProvider": {
-        "androidx/wear/ambient/WearableControllerProvider": [
-          "TAG",
-          "sAmbientCallbacksVerifiedPresent"
-        ]
-      },
-      "android/support/design/R$anim": {
-        "androidx/design/R$anim": [
-          "design_snackbar_out",
-          "design_snackbar_in"
-        ]
-      },
-      "android/support/wear/ambient/AmbientMode": {
-        "androidx/wear/ambient/AmbientMode": [
-          "FRAGMENT_TAG",
-          "EXTRA_BURN_IN_PROTECTION",
-          "EXTRA_LOWBIT_AMBIENT"
-        ]
-      },
-      "android/support/text/emoji/flatbuffer/MetadataItem": {
-        "androidx/text/emoji/flatbuffer/MetadataItem": [
-          "bb_pos",
-          "bb"
-        ]
-      },
-      "android/support/v13/app/FragmentStatePagerAdapter": {
-        "androidx/app/legacy/FragmentStatePagerAdapter": [
-          "TAG",
-          "DEBUG"
-        ]
-      },
-      "android/support/v17/leanback/transition/LeanbackTransitionHelper": {
-        "androidx/leanback/transition/LeanbackTransitionHelper": [
-          "sImpl"
-        ]
-      },
-      "android/support/v7/view/menu/MenuItemWrapperICS": {
-        "androidx/view/menu/MenuItemWrapperICS": [
-          "LOG_TAG"
-        ]
-      },
-      "android/support/v4/content/IntentCompat": {
-        "androidx/content/IntentCompat": [
-          "EXTRA_HTML_TEXT",
-          "CATEGORY_LEANBACK_LAUNCHER",
-          "EXTRA_START_PLAYBACK"
-        ]
-      },
-      "android/support/graphics/drawable/AnimatedVectorDrawableCompat": {
-        "androidx/graphics/drawable/AnimatedVectorDrawableCompat": [
-          "LOGTAG",
-          "TARGET",
-          "ANIMATED_VECTOR",
-          "DBG_ANIMATION_VECTOR_DRAWABLE"
-        ]
-      },
-      "android/support/v7/appcompat/R$style": {
-        "androidx/appcompat/R$style": [
-          "Base_Widget_AppCompat_DrawerArrowToggle",
-          "Theme_AppCompat_Light",
-          "TextAppearance_AppCompat_Caption",
-          "Theme_AppCompat_CompactMenu",
-          "TextAppearance_AppCompat_Widget_ActionBar_Title",
-          "Animation_AppCompat_Tooltip"
-        ]
-      },
-      "android/support/media/instantvideo/widget/InstantVideoView": {
-        "androidx/media/instantvideo/widget/InstantVideoView": [
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/transition/Scale": {
-        "androidx/leanback/transition/Scale": [
-          "PROPNAME_SCALE"
-        ]
-      },
-      "android/support/v4/content/WakefulBroadcastReceiver": {
-        "androidx/content/WakefulBroadcastReceiver": [
-          "EXTRA_WAKE_LOCK_ID",
-          "sActiveWakeLocks"
-        ]
-      },
-      "android/support/v17/leanback/widget/VerticalGridPresenter": {
-        "androidx/leanback/widget/VerticalGridPresenter": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/PersistentFocusWrapper": {
-        "androidx/leanback/widget/PersistentFocusWrapper": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v4/provider/SelfDestructiveThread": {
-        "androidx/provider/SelfDestructiveThread": [
-          "MSG_DESTRUCTION",
-          "MSG_INVOKE_RUNNABLE"
-        ]
-      },
-      "android/support/customtabs/TrustedWebUtils": {
-        "androidx/browser/customtabs/TrustedWebUtils": [
-          "EXTRA_LAUNCH_AS_TRUSTED_WEB_ACTIVITY"
-        ]
-      },
-      "android/support/v17/leanback/app/RowsSupportFragment": {
-        "androidx/leanback/app/RowsSupportFragment": [
-          "TAG",
-          "ALIGN_TOP_NOT_SET",
-          "DEBUG"
-        ]
-      },
-      "android/support/v17/leanback/widget/ScaleFrameLayout": {
-        "androidx/leanback/widget/ScaleFrameLayout": [
-          "DEFAULT_CHILD_GRAVITY"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserCompat$MediaItem": {
-        "androidx/media/MediaBrowserCompat$MediaItem": [
-          "CREATOR",
-          "FLAG_PLAYABLE",
-          "FLAG_BROWSABLE"
-        ]
-      },
-      "android/support/v4/provider/FontsContractCompat$FontRequestCallback": {
-        "androidx/provider/FontsContractCompat$FontRequestCallback": [
-          "FAIL_REASON_WRONG_CERTIFICATES",
-          "FAIL_REASON_FONT_UNAVAILABLE",
-          "FAIL_REASON_MALFORMED_QUERY",
-          "FAIL_REASON_SECURITY_VIOLATION",
-          "FAIL_REASON_FONT_LOAD_ERROR",
-          "RESULT_OK",
-          "FAIL_REASON_FONT_NOT_FOUND",
-          "FAIL_REASON_PROVIDER_NOT_FOUND"
-        ]
-      },
-      "android/support/v4/widget/NestedScrollView$SavedState": {
-        "androidx/widget/NestedScrollView$SavedState": [
-          "CREATOR",
-          "scrollPosition"
-        ]
-      },
-      "android/support/text/emoji/R$layout": {
-        "androidx/text/emoji/R$layout": [
-          "input_method_extract_view"
-        ]
-      },
-      "android/support/v4/app/FragmentManagerImpl$FragmentTag": {
-        "androidx/app/FragmentManagerImpl$FragmentTag": [
-          "Fragment",
-          "Fragment_tag",
-          "Fragment_name",
-          "Fragment_id"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$Assoc": {
-        "androidx/widget/GridLayout$Assoc": [
-          "keyType",
-          "valueType"
-        ]
-      },
-      "android/support/v4/app/LoaderManagerImpl": {
-        "androidx/app/LoaderManagerImpl": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v7/appcompat/R$string": {
-        "androidx/appcompat/R$string": [
-          "abc_action_bar_up_description",
-          "abc_searchview_description_search",
-          "abc_activity_chooser_view_see_all",
-          "abc_shareactionprovider_share_with",
-          "abc_shareactionprovider_share_with_application",
-          "abc_activitychooserview_choose_application"
-        ]
-      },
-      "android/support/v7/widget/AppCompatAutoCompleteTextView": {
-        "androidx/widget/AppCompatAutoCompleteTextView": [
-          "TINT_ATTRS"
-        ]
-      },
-      "android/support/v7/widget/ChildHelper": {
-        "androidx/widget/ChildHelper": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/wear/ambient/SharedLibraryVersion$VersionHolder": {
-        "androidx/wear/ambient/SharedLibraryVersion$VersionHolder": [
-          "VERSION"
-        ]
-      },
-      "android/support/media/tv/BaseProgram": {
-        "androidx/media/tv/BaseProgram": [
-          "INVALID_LONG_VALUE",
-          "PROJECTION",
-          "IS_SEARCHABLE",
-          "INVALID_INT_VALUE"
-        ]
-      },
-      "android/support/transition/TransitionUtils": {
-        "androidx/transition/TransitionUtils": [
-          "MAX_IMAGE_SIZE"
-        ]
-      },
-      "android/support/v17/leanback/widget/ItemAlignment": {
-        "androidx/leanback/widget/ItemAlignment": [
-          "horizontal",
-          "vertical"
-        ]
-      },
-      "android/support/design/widget/NavigationView$SavedState": {
-        "androidx/design/widget/NavigationView$SavedState": [
-          "CREATOR",
-          "menuState"
-        ]
-      },
-      "android/support/v17/leanback/widget/WindowAlignment": {
-        "androidx/leanback/widget/WindowAlignment": [
-          "horizontal",
-          "vertical"
-        ]
-      },
-      "android/support/design/internal/BottomNavigationMenuView": {
-        "androidx/design/internal/BottomNavigationMenuView": [
-          "ACTIVE_ANIMATION_DURATION_MS"
-        ]
-      },
-      "android/support/transition/Slide": {
-        "androidx/transition/Slide": [
-          "sDecelerate",
-          "PROPNAME_SCREEN_POSITION",
-          "sCalculateTop",
-          "sCalculateBottom",
-          "sCalculateRight",
-          "sAccelerate",
-          "sCalculateStart",
-          "sCalculateEnd",
-          "sCalculateLeft"
-        ]
-      },
-      "android/support/text/emoji/MetadataRepo": {
-        "androidx/text/emoji/MetadataRepo": [
-          "DEFAULT_ROOT_SIZE"
-        ]
-      },
-      "android/support/v7/app/AppCompatDelegateImplBase": {
-        "androidx/app/AppCompatDelegateImplBase": [
-          "EXCEPTION_HANDLER_MESSAGE_SUFFIX",
-          "sInstalledExceptionHandler",
-          "sWindowBackgroundStyleable",
-          "DEBUG",
-          "SHOULD_INSTALL_EXCEPTION_HANDLER"
-        ]
-      },
-      "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem": {
-        "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup$FullSpanItem": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v17/leanback/R$anim": {
-        "androidx/leanback/R$anim": [
-          "lb_decelerator_4"
-        ]
-      },
-      "android/support/v17/leanback/widget/PagingIndicator": {
-        "androidx/leanback/widget/PagingIndicator": [
-          "DURATION_DIAMETER",
-          "DURATION_TRANSLATION_X",
-          "DECELERATE_INTERPOLATOR",
-          "DOT_DIAMETER",
-          "DURATION_ALPHA",
-          "DOT_TRANSLATION_X",
-          "DOT_ALPHA"
-        ]
-      },
-      "android/support/v7/widget/ScrollingTabContainerView": {
-        "androidx/widget/ScrollingTabContainerView": [
-          "sAlphaInterpolator",
-          "TAG",
-          "FADE_DURATION"
-        ]
-      },
-      "android/support/v4/text/TextDirectionHeuristicsCompat$FirstStrong": {
-        "androidx/text/TextDirectionHeuristicsCompat$FirstStrong": [
-          "INSTANCE"
-        ]
-      },
-      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuTextItem": {
-        "androidx/design/internal/NavigationMenuPresenter$NavigationMenuTextItem": [
-          "needsEmptyIcon"
-        ]
-      },
-      "android/support/v17/leanback/widget/Presenter$ViewHolder": {
-        "androidx/leanback/widget/Presenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/customtabs/IPostMessageService$Stub": {
-        "androidx/browser/customtabs/IPostMessageService$Stub": [
-          "TRANSACTION_onPostMessage",
-          "DESCRIPTOR",
-          "TRANSACTION_onMessageChannelReady"
-        ]
-      },
-      "android/support/v4/view/ViewPropertyAnimatorCompat": {
-        "androidx/view/ViewPropertyAnimatorCompat": [
-          "LISTENER_TAG_ID",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/AbstractMediaItemPresenter": {
-        "androidx/leanback/widget/AbstractMediaItemPresenter": [
-          "PLAY_STATE_PLAYING",
-          "PLAY_STATE_PAUSED",
-          "sTempRect",
-          "PLAY_STATE_INITIAL"
-        ]
-      },
-      "android/support/v4/media/session/MediaControllerCompat$TransportControls": {
-        "androidx/media/session/MediaControllerCompat$TransportControls": [
-          "EXTRA_LEGACY_STREAM_TYPE"
-        ]
-      },
-      "android/support/v4/view/WindowCompat": {
-        "androidx/view/WindowCompat": [
-          "FEATURE_ACTION_MODE_OVERLAY",
-          "FEATURE_ACTION_BAR",
-          "FEATURE_ACTION_BAR_OVERLAY"
-        ]
-      },
-      "android/support/v4/content/PermissionChecker": {
-        "androidx/content/PermissionChecker": [
-          "PERMISSION_GRANTED",
-          "PERMISSION_DENIED",
-          "PERMISSION_DENIED_APP_OP"
-        ]
-      },
-      "android/support/v4/text/TextUtilsCompat": {
-        "androidx/text/TextUtilsCompat": [
-          "ROOT",
-          "ARAB_SCRIPT_SUBTAG",
-          "HEBR_SCRIPT_SUBTAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter": {
-        "androidx/leanback/widget/DetailsOverviewRowPresenter": [
-          "MORE_ACTIONS_FADE_MS",
-          "DEBUG",
-          "TAG",
-          "DEFAULT_TIMEOUT"
-        ]
-      },
-      "android/support/design/widget/TextInputLayout": {
-        "androidx/design/widget/TextInputLayout": [
-          "LOG_TAG",
-          "INVALID_MAX_LENGTH",
-          "ANIMATION_DURATION"
-        ]
-      },
-      "android/support/v7/media/RemotePlaybackClient": {
-        "androidx/media/RemotePlaybackClient": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/ListRowPresenter$ViewHolder": {
-        "androidx/leanback/widget/ListRowPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v7/content/res/AppCompatColorStateListInflater": {
-        "androidx/content/res/AppCompatColorStateListInflater": [
-          "DEFAULT_COLOR"
-        ]
-      },
-      "android/support/v7/view/menu/ExpandedMenuView": {
-        "androidx/view/menu/ExpandedMenuView": [
-          "TINT_ATTRS"
-        ]
-      },
-      "android/support/v7/widget/PositionMap$ContainerHelpers": {
-        "androidx/widget/PositionMap$ContainerHelpers": [
-          "EMPTY_BOOLEANS",
-          "EMPTY_INTS",
-          "EMPTY_OBJECTS",
-          "EMPTY_LONGS"
-        ]
-      },
-      "android/support/design/widget/TextInputLayout$SavedState": {
-        "androidx/design/widget/TextInputLayout$SavedState": [
-          "error",
-          "isPasswordToggledVisible",
-          "CREATOR"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$MutableInt": {
-        "androidx/widget/GridLayout$MutableInt": [
-          "value"
-        ]
-      },
-      "android/support/wear/R$dimen": {
-        "androidx/wear/R$dimen": [
-          "ws_action_drawer_item_icon_right_margin",
-          "ws_action_drawer_item_bottom_padding",
-          "ws_wearable_drawer_view_elevation",
-          "circular_progress_layout_stroke_width",
-          "ws_wrv_curve_default_x_offset",
-          "ws_action_drawer_item_top_padding"
-        ]
-      },
-      "android/support/wear/widget/drawer/WearableNavigationDrawerView": {
-        "androidx/wear/widget/drawer/WearableNavigationDrawerView": [
-          "MULTI_PAGE",
-          "SINGLE_PAGE",
-          "AUTO_CLOSE_DRAWER_DELAY_MS",
-          "TAG",
-          "DEFAULT_STYLE"
-        ]
-      },
-      "android/support/v7/graphics/Palette": {
-        "androidx/graphics/palette/Palette": [
-          "DEFAULT_CALCULATE_NUMBER_COLORS",
-          "MIN_CONTRAST_BODY_TEXT",
-          "LOG_TIMINGS",
-          "DEFAULT_FILTER",
-          "LOG_TAG",
-          "MIN_CONTRAST_TITLE_TEXT",
-          "DEFAULT_RESIZE_BITMAP_AREA"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$State": {
-        "androidx/widget/RecyclerView$State": [
-          "STEP_ANIMATIONS",
-          "STEP_LAYOUT",
-          "STEP_START"
-        ]
-      },
-      "android/support/design/widget/AppBarLayout": {
-        "androidx/design/widget/AppBarLayout": [
-          "PENDING_ACTION_FORCE",
-          "PENDING_ACTION_NONE",
-          "PENDING_ACTION_COLLAPSED",
-          "INVALID_SCROLL_RANGE",
-          "PENDING_ACTION_EXPANDED",
-          "PENDING_ACTION_ANIMATE_ENABLED"
-        ]
-      },
-      "android/support/design/widget/ViewUtilsLollipop": {
-        "androidx/design/widget/ViewUtilsLollipop": [
-          "STATE_LIST_ANIM_ATTRS"
-        ]
-      },
-      "android/support/v4/provider/FontsContractCompat": {
-        "androidx/provider/FontsContractCompat": [
-          "sByteArrayComparator",
-          "sBackgroundThread",
-          "BACKGROUND_THREAD_KEEP_ALIVE_DURATION_MS",
-          "sTypefaceCache",
-          "RESULT_CODE_WRONG_CERTIFICATES",
-          "RESULT_CODE_PROVIDER_NOT_FOUND",
-          "PARCEL_FONT_RESULTS",
-          "sPendingReplies",
-          "TAG",
-          "sLock"
-        ]
-      },
-      "android/support/media/tv/TvContractUtils": {
-        "androidx/media/tv/TvContractUtils": [
-          "DEBUG",
-          "EMPTY",
-          "TAG",
-          "DELIMITER"
-        ]
-      },
-      "android/support/v17/leanback/widget/RoundedRectHelperApi21": {
-        "androidx/leanback/widget/RoundedRectHelperApi21": [
-          "sRoundedRectProvider",
-          "MAX_CACHED_PROVIDER"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseFragment$MainFragmentAdapterRegistry": {
-        "androidx/leanback/app/BrowseFragment$MainFragmentAdapterRegistry": [
-          "sDefaultFragmentFactory"
-        ]
-      },
-      "android/support/v7/util/BatchingListUpdateCallback": {
-        "androidx/util/BatchingListUpdateCallback": [
-          "TYPE_CHANGE",
-          "TYPE_REMOVE",
-          "TYPE_NONE",
-          "TYPE_ADD"
-        ]
-      },
-      "android/support/v4/widget/DrawerLayout$SavedState": {
-        "androidx/widget/DrawerLayout$SavedState": [
-          "lockModeLeft",
-          "lockModeEnd",
-          "CREATOR",
-          "lockModeStart",
-          "openDrawerGravity",
-          "lockModeRight"
-        ]
-      },
-      "android/support/design/internal/NavigationMenuItemView": {
-        "androidx/design/internal/NavigationMenuItemView": [
-          "CHECKED_STATE_SET",
-          "EMPTY_STATE_SET"
-        ]
-      },
-      "android/support/text/emoji/EmojiProcessor$ProcessorSm": {
-        "androidx/text/emoji/EmojiProcessor$ProcessorSm": [
-          "STATE_DEFAULT",
-          "STATE_WALKING"
-        ]
-      },
-      "android/support/v7/widget/ActivityChooserModel$DefaultSorter": {
-        "androidx/widget/ActivityChooserModel$DefaultSorter": [
-          "WEIGHT_DECAY_COEFFICIENT"
-        ]
-      },
-      "android/support/v4/content/pm/ShortcutManagerCompat": {
-        "androidx/content/pm/ShortcutManagerCompat": [
-          "ACTION_INSTALL_SHORTCUT",
-          "INSTALL_SHORTCUT_PERMISSION"
-        ]
-      },
-      "android/support/media/tv/TvContractCompat$Channels$Logo": {
-        "androidx/media/tv/TvContractCompat$Channels$Logo": [
-          "CONTENT_DIRECTORY"
-        ]
-      },
-      "android/support/v4/view/ViewCompat$ViewCompatBaseImpl": {
-        "androidx/view/legacy/ViewCompat$ViewCompatBaseImpl": [
-          "sChildrenDrawingOrderMethod",
-          "sMinHeightField",
-          "sMinHeightFieldFetched",
-          "sTransitionNameMap",
-          "sAccessibilityDelegateCheckFailed",
-          "sMinWidthField",
-          "sMinWidthFieldFetched",
-          "sAccessibilityDelegateField"
-        ]
-      },
-      "android/support/v4/content/res/TypedArrayUtils": {
-        "androidx/content/res/TypedArrayUtils": [
-          "NAMESPACE"
-        ]
-      },
-      "android/support/annotation/RestrictTo$Scope": {
-        "androidx/annotation/RestrictTo$Scope": [
-          "GROUP_ID",
-          "TESTS",
-          "LIBRARY",
-          "SUBCLASSES",
-          "LIBRARY_GROUP"
-        ]
-      },
-      "android/support/media/tv/ChannelLogoUtils": {
-        "androidx/media/tv/ChannelLogoUtils": [
-          "TAG",
-          "CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION",
-          "READ_TIMEOUT_MS_FOR_URLCONNECTION"
-        ]
-      },
-      "android/support/text/emoji/EmojiProcessor": {
-        "androidx/text/emoji/EmojiProcessor": [
-          "ACTION_FLUSH",
-          "ACTION_ADVANCE_BOTH",
-          "ACTION_ADVANCE_END"
-        ]
-      },
-      "android/support/design/R$layout": {
-        "androidx/design/R$layout": [
-          "design_navigation_item",
-          "design_navigation_menu_item",
-          "design_navigation_item_separator",
-          "design_navigation_item_subheader",
-          "design_navigation_item_header",
-          "design_bottom_navigation_item",
-          "design_text_input_password_icon",
-          "design_layout_snackbar_include",
-          "design_layout_tab_text",
-          "design_layout_snackbar",
-          "design_bottom_sheet_dialog",
-          "design_layout_tab_icon",
-          "design_navigation_menu"
-        ]
-      },
-      "android/support/v4/app/NotificationCompatExtras": {
-        "androidx/app/NotificationCompatExtras": [
-          "EXTRA_ACTION_EXTRAS",
-          "EXTRA_GROUP_KEY",
-          "EXTRA_SORT_KEY",
-          "EXTRA_REMOTE_INPUTS",
-          "EXTRA_LOCAL_ONLY",
-          "EXTRA_GROUP_SUMMARY"
-        ]
-      },
-      "android/support/v17/leanback/widget/GridLayoutManager$SavedState": {
-        "androidx/leanback/widget/GridLayoutManager$SavedState": [
-          "CREATOR",
-          "index",
-          "childStates"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$ItemAnimator": {
-        "androidx/widget/RecyclerView$ItemAnimator": [
-          "FLAG_CHANGED",
-          "FLAG_REMOVED",
-          "FLAG_APPEARED_IN_PRE_LAYOUT",
-          "FLAG_INVALIDATED",
-          "FLAG_MOVED"
-        ]
-      },
-      "android/support/v17/leanback/widget/Grid$Location": {
-        "androidx/leanback/widget/Grid$Location": [
-          "row"
-        ]
-      },
-      "android/support/v17/leanback/media/MediaControllerGlue": {
-        "androidx/leanback/media/MediaControllerGlue": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v17/preference/LeanbackListPreferenceDialogFragment": {
-        "androidx/leanback/preference/LeanbackListPreferenceDialogFragment": [
-          "SAVE_STATE_ENTRY_VALUES",
-          "SAVE_STATE_TITLE",
-          "SAVE_STATE_INITIAL_SELECTIONS",
-          "SAVE_STATE_IS_MULTI",
-          "SAVE_STATE_ENTRIES",
-          "SAVE_STATE_INITIAL_SELECTION",
-          "SAVE_STATE_MESSAGE"
-        ]
-      },
-      "android/support/v4/app/ServiceCompat": {
-        "androidx/app/ServiceCompat": [
-          "STOP_FOREGROUND_DETACH",
-          "START_STICKY",
-          "STOP_FOREGROUND_REMOVE"
-        ]
-      },
-      "android/support/wear/widget/SwipeDismissLayout": {
-        "androidx/wear/widget/SwipeDismissLayout": [
-          "TAG",
-          "DEFAULT_DISMISS_DRAG_WIDTH_RATIO",
-          "EDGE_SWIPE_THRESHOLD"
-        ]
-      },
-      "android/support/v4/os/LocaleListCompat": {
-        "androidx/os/LocaleListCompat": [
-          "sEmptyLocaleList",
-          "IMPL"
-        ]
-      },
-      "android/support/v7/preference/Preference$BaseSavedState": {
-        "androidx/preference/Preference$BaseSavedState": [
-          "CREATOR",
-          "EMPTY_STATE"
-        ]
-      },
-      "android/support/v7/media/MediaRouteProviderService": {
-        "androidx/media/MediaRouteProviderService": [
-          "TAG",
-          "SERVICE_INTERFACE",
-          "DEBUG",
-          "PRIVATE_MSG_CLIENT_DIED"
-        ]
-      },
-      "android/support/v7/view/menu/CascadingMenuPopup$CascadingMenuInfo": {
-        "androidx/view/menu/CascadingMenuPopup$CascadingMenuInfo": [
-          "position",
-          "menu",
-          "window"
-        ]
-      },
-      "android/support/v7/widget/ToolbarWidgetWrapper": {
-        "androidx/widget/ToolbarWidgetWrapper": [
-          "DEFAULT_FADE_DURATION_MS",
-          "AFFECTS_LOGO_MASK",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$ViewHolder": {
-        "androidx/leanback/widget/PlaybackTransportRowPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v7/widget/DefaultItemAnimator": {
-        "androidx/widget/DefaultItemAnimator": [
-          "DEBUG",
-          "sDefaultInterpolator"
-        ]
-      },
-      "android/support/v4/widget/PopupWindowCompat$PopupWindowCompatApi21Impl": {
-        "androidx/widget/PopupWindowCompat$PopupWindowCompatApi21Impl": [
-          "sOverlapAnchorField",
-          "TAG"
-        ]
-      },
-      "android/support/v17/preference/LeanbackSettingsFragment": {
-        "androidx/leanback/preference/LeanbackSettingsFragment": [
-          "PREFERENCE_FRAGMENT_TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget": {
-        "androidx/leanback/widget/ParallaxTarget$PropertyValuesHolderTarget": [
-          "PSEUDO_DURATION"
-        ]
-      },
-      "android/support/design/widget/SnackbarManager": {
-        "androidx/design/widget/SnackbarManager": [
-          "MSG_TIMEOUT",
-          "sSnackbarManager",
-          "LONG_DURATION_MS",
-          "SHORT_DURATION_MS"
-        ]
-      },
-      "android/support/v17/leanback/app/BaseRowSupportFragment": {
-        "androidx/leanback/app/BaseRowSupportFragment": [
-          "CURRENT_SELECTED_POSITION"
-        ]
-      },
-      "android/support/v7/app/MediaRouteVolumeSlider": {
-        "androidx/app/MediaRouteVolumeSlider": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/util/AsyncListUtil$ViewCallback": {
-        "androidx/util/AsyncListUtil$ViewCallback": [
-          "HINT_SCROLL_DESC",
-          "HINT_SCROLL_NONE",
-          "HINT_SCROLL_ASC"
-        ]
-      },
-      "android/support/multidex/MultiDexExtractor$ExtractedDex": {
-        "androidx/multidex/MultiDexExtractor$ExtractedDex": [
-          "crc"
-        ]
-      },
-      "android/support/transition/AnimatorUtils": {
-        "androidx/transition/AnimatorUtils": [
-          "IMPL"
-        ]
-      },
-      "android/support/v7/app/AppCompatDelegateImplV14": {
-        "androidx/app/AppCompatDelegateImplV14": [
-          "KEY_LOCAL_NIGHT_MODE"
-        ]
-      },
-      "android/support/transition/Styleable$PatternPathMotion": {
-        "androidx/transition/Styleable$PatternPathMotion": [
-          "PATTERN_PATH_DATA"
-        ]
-      },
-      "android/support/v7/media/SystemMediaRouteProvider": {
-        "androidx/media/SystemMediaRouteProvider": [
-          "TAG",
-          "DEFAULT_ROUTE_ID",
-          "PACKAGE_NAME"
-        ]
-      },
-      "android/support/design/internal/BottomNavigationItemView": {
-        "androidx/design/internal/BottomNavigationItemView": [
-          "CHECKED_STATE_SET",
-          "INVALID_ITEM_POSITION"
-        ]
-      },
-      "android/support/wear/widget/ScrollManager": {
-        "androidx/wear/widget/ScrollManager": [
-          "ONE_SEC_IN_MS",
-          "FLING_EDGE_RATIO",
-          "VELOCITY_MULTIPLIER"
-        ]
-      },
-      "android/support/v7/widget/AppCompatTextHelper": {
-        "androidx/widget/AppCompatTextHelper": [
-          "MONOSPACE",
-          "SANS",
-          "SERIF"
-        ]
-      },
-      "android/support/v17/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout": {
-        "androidx/leanback/app/DetailsSupportFragment$WaitEnterTransitionTimeout": [
-          "WAIT_ENTERTRANSITION_START"
-        ]
-      },
-      "android/support/v7/media/MediaRouteProviderDescriptor": {
-        "androidx/media/MediaRouteProviderDescriptor": [
-          "KEY_ROUTES"
-        ]
-      },
-      "android/support/v17/leanback/widget/TitleView": {
-        "androidx/leanback/widget/TitleView": [
-          "flags"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$QueueItem": {
-        "androidx/media/session/MediaSessionCompat$QueueItem": [
-          "CREATOR",
-          "UNKNOWN_ID"
-        ]
-      },
-      "android/support/v7/mediarouter/R$styleable": {
-        "androidx/mediarouter/R$styleable": [
-          "MediaRouteButton_android_minHeight",
-          "MediaRouteButton_mediaRouteButtonTint",
-          "MediaRouteButton_android_minWidth",
-          "MediaRouteButton_externalRouteEnabledDrawable",
-          "MediaRouteButton"
-        ]
-      },
-      "android/support/v7/view/menu/ActionMenuItemView": {
-        "androidx/view/menu/ActionMenuItemView": [
-          "TAG",
-          "MAX_ICON_SIZE"
-        ]
-      },
-      "android/support/v4/app/FragmentStatePagerAdapter": {
-        "androidx/app/FragmentStatePagerAdapter": [
-          "TAG",
-          "DEBUG"
-        ]
-      },
-      "android/support/wear/widget/drawer/ScrollViewFlingWatcher": {
-        "androidx/wear/widget/drawer/ScrollViewFlingWatcher": [
-          "MAX_WAIT_TIME_MS"
-        ]
-      },
-      "android/support/transition/MatrixUtils": {
-        "androidx/transition/MatrixUtils": [
-          "IDENTITY_MATRIX"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$Action": {
-        "androidx/app/NotificationCompat$Action": [
-          "icon",
-          "title",
-          "actionIntent"
-        ]
-      },
-      "android/support/v4/os/ResultReceiver": {
-        "androidx/os/ResultReceiver": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v7/widget/AppCompatTextView": {
-        "androidx/widget/AppCompatTextView": [
-          "PLATFORM_SUPPORTS_AUTOSIZE"
-        ]
-      },
-      "android/support/v7/widget/StaggeredGridLayoutManager": {
-        "androidx/widget/StaggeredGridLayoutManager": [
-          "GAP_HANDLING_LAZY",
-          "GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS",
-          "TAG",
-          "VERTICAL",
-          "INVALID_OFFSET",
-          "MAX_SCROLL_FACTOR",
-          "GAP_HANDLING_NONE",
-          "DEBUG",
-          "HORIZONTAL"
-        ]
-      },
-      "android/support/design/widget/BottomNavigationView$SavedState": {
-        "androidx/design/widget/BottomNavigationView$SavedState": [
-          "CREATOR",
-          "menuPresenterState"
-        ]
-      },
-      "android/support/v7/widget/RoundRectDrawableWithShadow": {
-        "androidx/widget/RoundRectDrawableWithShadow": [
-          "sRoundRectHelper",
-          "COS_45",
-          "SHADOW_MULTIPLIER"
-        ]
-      },
-      "android/support/v7/preference/PreferenceCategory": {
-        "androidx/preference/PreferenceCategory": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$ItemAnimator$ItemHolderInfo": {
-        "androidx/widget/RecyclerView$ItemAnimator$ItemHolderInfo": [
-          "left",
-          "changeFlags",
-          "top",
-          "right",
-          "bottom"
-        ]
-      },
-      "android/support/v7/preference/ListPreference$SavedState": {
-        "androidx/preference/ListPreference$SavedState": [
-          "CREATOR",
-          "value"
-        ]
-      },
-      "android/support/v7/widget/TooltipPopup": {
-        "androidx/widget/TooltipPopup": [
-          "TAG"
-        ]
-      },
-      "android/support/v4/net/ConnectivityManagerCompat": {
-        "androidx/net/ConnectivityManagerCompat": [
-          "RESTRICT_BACKGROUND_STATUS_ENABLED",
-          "RESTRICT_BACKGROUND_STATUS_WHITELISTED",
-          "RESTRICT_BACKGROUND_STATUS_DISABLED"
-        ]
-      },
-      "android/support/v7/widget/MenuPopupWindow": {
-        "androidx/widget/MenuPopupWindow": [
-          "sSetTouchModalMethod",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/app/RowsFragment": {
-        "androidx/leanback/app/RowsFragment": [
-          "TAG",
-          "ALIGN_TOP_NOT_SET",
-          "DEBUG"
-        ]
-      },
-      "android/support/v17/leanback/app/ProgressBarManager": {
-        "androidx/leanback/app/ProgressBarManager": [
-          "runnable",
-          "rootView",
-          "DEFAULT_PROGRESS_BAR_DELAY"
-        ]
-      },
-      "android/support/v7/media/RegisteredMediaRouteProvider": {
-        "androidx/media/RegisteredMediaRouteProvider": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/design/widget/CheckableImageButton": {
-        "androidx/design/widget/CheckableImageButton": [
-          "DRAWABLE_STATE_CHECKED"
-        ]
-      },
-      "android/support/transition/ImageViewUtils": {
-        "androidx/transition/ImageViewUtils": [
-          "IMPL"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRow$HighQualityAction": {
-        "androidx/leanback/widget/PlaybackControlsRow$HighQualityAction": [
-          "INDEX_OFF",
-          "INDEX_ON",
-          "OFF",
-          "ON"
-        ]
-      },
-      "android/support/wear/widget/drawer/PageIndicatorView": {
-        "androidx/wear/widget/drawer/PageIndicatorView": [
-          "TAG"
-        ]
-      },
-      "android/support/transition/TransitionValues": {
-        "androidx/transition/TransitionValues": [
-          "view",
-          "values"
-        ]
-      },
-      "android/support/v17/leanback/app/BaseRowFragment": {
-        "androidx/leanback/app/BaseRowFragment": [
-          "CURRENT_SELECTED_POSITION"
-        ]
-      },
-      "android/support/v7/mediarouter/R$drawable": {
-        "androidx/mediarouter/R$drawable": [
-          "mr_group_collapse",
-          "mr_group_expand"
-        ]
-      },
-      "android/support/transition/ViewUtils": {
-        "androidx/transition/ViewUtils": [
-          "sViewFlagsField",
-          "TRANSITION_ALPHA",
-          "IMPL",
-          "sViewFlagsFieldFetched",
-          "TAG",
-          "CLIP_BOUNDS",
-          "VISIBILITY_MASK"
-        ]
-      },
-      "android/support/v7/preference/AndroidResources": {
-        "androidx/preference/AndroidResources": [
-          "ANDROID_R_ICON_FRAME",
-          "ANDROID_R_SWITCH_WIDGET",
-          "ANDROID_R_PREFERENCE_FRAGMENT_STYLE",
-          "ANDROID_R_LIST_CONTAINER",
-          "ANDROID_R_EDITTEXT_PREFERENCE_STYLE"
-        ]
-      },
-      "android/support/v4/net/DatagramSocketWrapper$DatagramSocketImplWrapper": {
-        "androidx/net/DatagramSocketWrapper$DatagramSocketImplWrapper": [
-          "localport",
-          "fd"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$BoundData": {
-        "androidx/leanback/widget/PlaybackControlsRowPresenter$BoundData": [
-          "secondaryActionsAdapter",
-          "presenter",
-          "adapter"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter$ViewHolder": {
-        "androidx/leanback/widget/PlaybackControlsRowPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v17/leanback/widget/Parallax$FloatProperty": {
-        "androidx/leanback/widget/Parallax$FloatProperty": [
-          "UNKNOWN_AFTER",
-          "UNKNOWN_BEFORE"
-        ]
-      },
-      "android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder": {
-        "androidx/leanback/widget/AbstractDetailsDescriptionPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/design/R$string": {
-        "androidx/design/R$string": [
-          "character_counter_pattern"
-        ]
-      },
-      "android/support/wear/ambient/AmbientDelegate": {
-        "androidx/wear/ambient/AmbientDelegate": [
-          "TAG",
-          "sInitAutoResumeEnabledMethod",
-          "sHasAutoResumeEnabledMethod"
-        ]
-      },
-      "android/support/v17/leanback/app/PlaybackFragment": {
-        "androidx/leanback/app/PlaybackFragment": [
-          "ANIMATION_MULTIPLIER",
-          "BG_DARK",
-          "BG_NONE",
-          "DEBUG",
-          "BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW",
-          "BG_LIGHT",
-          "TAG",
-          "ANIMATING",
-          "IDLE",
-          "START_FADE_OUT"
-        ]
-      },
-      "android/support/v7/widget/ActionBarOverlayLayout$LayoutParams": {
-        "androidx/widget/ActionBarOverlayLayout$LayoutParams": [
-          "topMargin",
-          "rightMargin",
-          "bottomMargin",
-          "leftMargin"
-        ]
-      },
-      "android/support/v4/os/EnvironmentCompat": {
-        "androidx/os/EnvironmentCompat": [
-          "MEDIA_UNKNOWN",
-          "TAG"
-        ]
-      },
-      "android/support/compat/R$string": {
-        "androidx/compat/R$string": [
-          "status_bar_notification_info_overflow"
-        ]
-      },
-      "android/support/v7/widget/PositionMap": {
-        "androidx/widget/PositionMap": [
-          "DELETED"
-        ]
-      },
-      "android/support/media/tv/Program": {
-        "androidx/media/tv/Program": [
-          "INVALID_LONG_VALUE",
-          "PROJECTION",
-          "IS_RECORDING_PROHIBITED"
-        ]
-      },
-      "android/support/v7/widget/ActionBarContextView": {
-        "androidx/widget/ActionBarContextView": [
-          "TAG"
-        ]
-      },
-      "android/support/v4/media/VolumeProviderCompat": {
-        "androidx/media/VolumeProviderCompat": [
-          "VOLUME_CONTROL_RELATIVE",
-          "VOLUME_CONTROL_FIXED",
-          "VOLUME_CONTROL_ABSOLUTE"
-        ]
-      },
-      "android/support/v7/view/menu/CascadingMenuPopup": {
-        "androidx/view/menu/CascadingMenuPopup": [
-          "SUBMENU_TIMEOUT_MS",
-          "HORIZ_POSITION_LEFT",
-          "HORIZ_POSITION_RIGHT"
-        ]
-      },
-      "android/support/v4/app/NotificationManagerCompat$ServiceConnectedEvent": {
-        "androidx/app/NotificationManagerCompat$ServiceConnectedEvent": [
-          "componentName",
-          "iBinder"
-        ]
-      },
-      "android/support/v7/app/AlertDialog": {
-        "androidx/app/AlertDialog": [
-          "LAYOUT_HINT_NONE",
-          "LAYOUT_HINT_SIDE"
-        ]
-      },
-      "android/support/v17/leanback/widget/picker/PickerUtility$DateConstant": {
-        "androidx/leanback/widget/picker/PickerUtility$DateConstant": [
-          "months",
-          "days",
-          "locale"
-        ]
-      },
-      "android/support/v7/app/MediaRouteChooserDialogFragment": {
-        "androidx/app/MediaRouteChooserDialogFragment": [
-          "ARGUMENT_SELECTOR"
-        ]
-      },
-      "android/support/design/widget/CoordinatorLayout$SavedState": {
-        "androidx/design/widget/CoordinatorLayout$SavedState": [
-          "behaviorStates",
-          "CREATOR"
-        ]
-      },
-      "android/support/v7/media/MediaRouteDiscoveryRequest": {
-        "androidx/media/MediaRouteDiscoveryRequest": [
-          "KEY_ACTIVE_SCAN",
-          "KEY_SELECTOR"
-        ]
-      },
-      "android/support/v17/leanback/widget/StaticShadowHelper": {
-        "androidx/leanback/widget/StaticShadowHelper": [
-          "sInstance"
-        ]
-      },
-      "android/support/design/widget/ShadowDrawableWrapper": {
-        "androidx/design/widget/ShadowDrawableWrapper": [
-          "SHADOW_MULTIPLIER",
-          "SHADOW_TOP_SCALE",
-          "COS_45",
-          "SHADOW_HORIZ_SCALE",
-          "SHADOW_BOTTOM_SCALE"
-        ]
-      },
-      "android/support/v13/app/FragmentCompat": {
-        "androidx/app/FragmentCompat": [
-          "sDelegate",
-          "IMPL"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$Arc": {
-        "androidx/widget/GridLayout$Arc": [
-          "span",
-          "valid",
-          "value"
-        ]
-      },
-      "android/support/v4/content/AsyncTaskLoader": {
-        "androidx/content/AsyncTaskLoader": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/text/emoji/flatbuffer/MetadataList": {
-        "androidx/text/emoji/flatbuffer/MetadataList": [
-          "bb_pos",
-          "bb"
-        ]
-      },
-      "android/support/text/emoji/widget/EditTextAttributeHelper": {
-        "androidx/text/emoji/widget/EditTextAttributeHelper": [
-          "MAX_EMOJI_COUNT"
-        ]
-      },
-      "android/support/v7/widget/ChildHelper$Bucket": {
-        "androidx/widget/ChildHelper$Bucket": [
-          "LAST_BIT",
-          "BITS_PER_WORD"
-        ]
-      },
-      "android/support/v4/content/LocalBroadcastManager": {
-        "androidx/content/LocalBroadcastManager": [
-          "DEBUG",
-          "MSG_EXEC_PENDING_BROADCASTS",
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/TooltipCompat": {
-        "androidx/widget/TooltipCompat": [
-          "IMPL"
-        ]
-      },
-      "android/support/media/tv/PreviewProgram": {
-        "androidx/media/tv/PreviewProgram": [
-          "INVALID_INT_VALUE",
-          "PROJECTION",
-          "INVALID_LONG_VALUE"
-        ]
-      },
-      "android/support/v7/preference/ListPreferenceDialogFragmentCompat": {
-        "androidx/preference/ListPreferenceDialogFragmentCompat": [
-          "SAVE_STATE_INDEX",
-          "SAVE_STATE_ENTRIES",
-          "SAVE_STATE_ENTRY_VALUES"
-        ]
-      },
-      "android/support/v7/widget/ViewInfoStore": {
-        "androidx/widget/ViewInfoStore": [
-          "DEBUG"
-        ]
-      },
-      "android/support/v7/widget/ActivityChooserModel$ActivityResolveInfo": {
-        "androidx/widget/ActivityChooserModel$ActivityResolveInfo": [
-          "weight",
-          "resolveInfo"
-        ]
-      },
-      "android/support/v7/preference/SeekBarPreference": {
-        "androidx/preference/SeekBarPreference": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/ActivityChooserView$InnerLayout": {
-        "androidx/widget/ActivityChooserView$InnerLayout": [
-          "TINT_ATTRS"
-        ]
-      },
-      "android/support/v7/app/AppCompatDelegateImplV9": {
-        "androidx/app/AppCompatDelegateImplV9": [
-          "IS_PRE_LOLLIPOP"
-        ]
-      },
-      "android/support/v7/media/SystemMediaRouteProvider$LegacyImpl": {
-        "androidx/media/SystemMediaRouteProvider$LegacyImpl": [
-          "PLAYBACK_STREAM",
-          "CONTROL_FILTERS"
-        ]
-      },
-      "android/support/transition/ViewUtilsApi22": {
-        "androidx/transition/ViewUtilsApi22": [
-          "sSetLeftTopRightBottomMethod",
-          "TAG",
-          "sSetLeftTopRightBottomMethodFetched"
-        ]
-      },
-      "android/support/v17/leanback/widget/ObjectAdapter": {
-        "androidx/leanback/widget/ObjectAdapter": [
-          "NO_ID"
-        ]
-      },
-      "android/support/content/Query": {
-        "androidx/content/Query": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/media/MediaControllerAdapter": {
-        "androidx/leanback/media/MediaControllerAdapter": [
-          "TAG",
-          "DEBUG"
-        ]
-      },
-      "android/support/v7/recyclerview/R$id": {
-        "androidx/recyclerview/R$id": [
-          "item_touch_helper_previous_elevation"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$Callback$CallbackHandler": {
-        "androidx/media/session/MediaSessionCompat$Callback$CallbackHandler": [
-          "MSG_MEDIA_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT"
-        ]
-      },
-      "android/support/design/widget/FloatingActionButton": {
-        "androidx/design/widget/FloatingActionButton": [
-          "LOG_TAG",
-          "AUTO_MINI_LARGEST_SCREEN_WIDTH",
-          "SIZE_AUTO",
-          "SIZE_NORMAL",
-          "SIZE_MINI"
-        ]
-      },
-      "android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper": {
-        "androidx/leanback/widget/DetailsOverviewSharedElementHelper": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v7/app/AlertDialog$Builder": {
-        "androidx/app/AlertDialog$Builder": [
-          "P"
-        ]
-      },
-      "android/support/wear/internal/widget/drawer/SinglePagePresenter": {
-        "androidx/wear/internal/widget/drawer/SinglePagePresenter": [
-          "DRAWER_CLOSE_DELAY_MS"
-        ]
-      },
-      "android/support/v17/leanback/app/BrowseSupportFragment$SetSelectionRunnable": {
-        "androidx/leanback/app/BrowseSupportFragment$SetSelectionRunnable": [
-          "TYPE_INTERNAL_SYNC",
-          "TYPE_USER_REQUEST",
-          "TYPE_INVALID"
-        ]
-      },
-      "android/support/media/tv/BasePreviewProgram$Builder": {
-        "androidx/media/tv/BasePreviewProgram$Builder": [
-          "sFormat"
-        ]
-      },
-      "android/support/v4/widget/SlidingPaneLayout": {
-        "androidx/widget/SlidingPaneLayout": [
-          "DEFAULT_OVERHANG_SIZE",
-          "IMPL",
-          "DEFAULT_FADE_COLOR",
-          "TAG",
-          "MIN_FLING_VELOCITY"
-        ]
-      },
-      "android/support/v7/app/MediaRouteChooserDialog": {
-        "androidx/app/MediaRouteChooserDialog": [
-          "UPDATE_ROUTES_DELAY_MS",
-          "TAG",
-          "MSG_UPDATE_ROUTES"
-        ]
-      },
-      "android/support/v4/app/ShareCompat$IntentReader": {
-        "androidx/app/ShareCompat$IntentReader": [
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/ItemBridgeAdapter$ViewHolder": {
-        "androidx/leanback/widget/ItemBridgeAdapter$ViewHolder": [
-          "itemView"
-        ]
-      },
-      "android/support/v17/leanback/app/BrandedFragment": {
-        "androidx/leanback/app/BrandedFragment": [
-          "TITLE_SHOW"
-        ]
-      },
-      "android/support/v17/leanback/widget/SearchEditText": {
-        "androidx/leanback/widget/SearchEditText": [
-          "DEBUG",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/PersistentFocusWrapper$SavedState": {
-        "androidx/leanback/widget/PersistentFocusWrapper$SavedState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/percent/PercentFrameLayout$LayoutParams": {
-        "androidx/PercentFrameLayout$LayoutParams": [
-          "gravity"
-        ]
-      },
-      "android/support/text/emoji/widget/EmojiEditableFactory": {
-        "androidx/text/emoji/widget/EmojiEditableFactory": [
-          "sWatcherClass",
-          "sInstanceLock",
-          "sInstance"
-        ]
-      },
-      "android/support/v4/view/ViewPager$SavedState": {
-        "androidx/view/ViewPager$SavedState": [
-          "position",
-          "adapterState",
-          "CREATOR",
-          "loader"
-        ]
-      },
-      "android/support/v17/leanback/widget/RowPresenter": {
-        "androidx/leanback/widget/RowPresenter": [
-          "SYNC_ACTIVATED_TO_SELECTED",
-          "SYNC_ACTIVATED_TO_EXPANDED_AND_SELECTED",
-          "SYNC_ACTIVATED_CUSTOM",
-          "SYNC_ACTIVATED_TO_EXPANDED"
-        ]
-      },
-      "android/support/v7/preference/EditTextPreferenceDialogFragmentCompat": {
-        "androidx/preference/EditTextPreferenceDialogFragmentCompat": [
-          "SAVE_STATE_TEXT"
-        ]
-      },
-      "android/support/v17/leanback/graphics/ColorFilterCache": {
-        "androidx/leanback/graphics/ColorFilterCache": [
-          "sColorToFiltersMap"
-        ]
-      },
-      "android/support/v7/view/menu/ListMenuPresenter": {
-        "androidx/view/menu/ListMenuPresenter": [
-          "VIEWS_TAG",
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/VerticalGridPresenter$ViewHolder": {
-        "androidx/leanback/widget/VerticalGridPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v4/app/TaskStackBuilder": {
-        "androidx/app/TaskStackBuilder": [
-          "TAG",
-          "IMPL"
-        ]
-      },
-      "android/support/v7/content/res/AppCompatResources": {
-        "androidx/content/res/AppCompatResources": [
-          "LOG_TAG",
-          "sColorStateCaches",
-          "TL_TYPED_VALUE",
-          "sColorStateCacheLock"
-        ]
-      },
-      "android/support/v4/hardware/display/DisplayManagerCompat": {
-        "androidx/hardware/display/DisplayManagerCompat": [
-          "DISPLAY_CATEGORY_PRESENTATION",
-          "sInstances"
-        ]
-      },
-      "android/support/v7/widget/ActionMenuPresenter": {
-        "androidx/widget/ActionMenuPresenter": [
-          "TAG"
-        ]
-      },
-      "android/support/v4/app/NotificationManagerCompat$NotifyTask": {
-        "androidx/app/NotificationManagerCompat$NotifyTask": [
-          "notif",
-          "id",
-          "tag",
-          "packageName"
-        ]
-      },
-      "android/support/text/emoji/FontRequestEmojiCompatConfig": {
-        "androidx/text/emoji/FontRequestEmojiCompatConfig": [
-          "DEFAULT_FONTS_CONTRACT"
-        ]
-      },
-      "android/support/v17/leanback/widget/ShadowHelperApi21": {
-        "androidx/leanback/widget/ShadowHelperApi21": [
-          "sOutlineProvider"
-        ]
-      },
-      "android/support/v17/leanback/widget/ItemBridgeAdapter": {
-        "androidx/leanback/widget/ItemBridgeAdapter": [
-          "TAG",
-          "DEBUG"
-        ]
-      },
-      "android/support/wear/utils/MetadataConstants": {
-        "androidx/wear/utils/MetadataConstants": [
-          "STANDALONE_METADATA_NAME",
-          "WATCH_FACE_PREVIEW_CIRCULAR_METADATA_NAME",
-          "NOTIFICATION_BRIDGE_MODE_NO_BRIDGING",
-          "NOTIFICATION_BRIDGE_MODE_BRIDGING",
-          "WATCH_FACE_PREVIEW_METADATA_NAME",
-          "NOTIFICATION_BRIDGE_MODE_METADATA_NAME"
-        ]
-      },
-      "android/support/transition/GhostViewUtils": {
-        "androidx/transition/GhostViewUtils": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder": {
-        "androidx/leanback/widget/AbstractMediaListHeaderPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsRowPresenter": {
-        "androidx/leanback/widget/PlaybackControlsRowPresenter": [
-          "sShadowZ"
-        ]
-      },
-      "android/support/v7/widget/CardView": {
-        "androidx/widget/CardView": [
-          "COLOR_BACKGROUND_ATTR",
-          "IMPL"
-        ]
-      },
-      "android/support/v7/app/ActionBar$Tab": {
-        "androidx/app/ActionBar$Tab": [
-          "INVALID_POSITION"
-        ]
-      },
-      "android/support/v7/app/MediaRouterThemeHelper": {
-        "androidx/app/MediaRouterThemeHelper": [
-          "MIN_CONTRAST",
-          "COLOR_WHITE_ON_DARK_BACKGROUND",
-          "COLOR_DARK_ON_LIGHT_BACKGROUND"
-        ]
-      },
-      "android/support/transition/ChangeClipBounds": {
-        "androidx/transition/ChangeClipBounds": [
-          "PROPNAME_CLIP",
-          "PROPNAME_BOUNDS",
-          "sTransitionProperties"
-        ]
-      },
-      "android/support/transition/Styleable$Slide": {
-        "androidx/transition/Styleable$Slide": [
-          "SLIDE_EDGE"
-        ]
-      },
-      "android/support/transition/TransitionSet": {
-        "androidx/transition/TransitionSet": [
-          "ORDERING_TOGETHER",
-          "ORDERING_SEQUENTIAL"
-        ]
-      },
-      "android/support/v7/widget/SearchView$SavedState": {
-        "androidx/widget/SearchView$SavedState": [
-          "CREATOR",
-          "isIconified"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackControlsPresenter$BoundData": {
-        "androidx/leanback/widget/PlaybackControlsPresenter$BoundData": [
-          "secondaryActionsAdapter"
-        ]
-      },
-      "android/support/v4/content/LocalBroadcastManager$BroadcastRecord": {
-        "androidx/content/LocalBroadcastManager$BroadcastRecord": [
-          "intent",
-          "receivers"
-        ]
-      },
-      "android/support/v7/preference/MultiSelectListPreferenceDialogFragmentCompat": {
-        "androidx/preference/MultiSelectListPreferenceDialogFragmentCompat": [
-          "SAVE_STATE_ENTRIES",
-          "SAVE_STATE_CHANGED",
-          "SAVE_STATE_ENTRY_VALUES",
-          "SAVE_STATE_VALUES"
-        ]
-      },
-      "android/support/transition/ViewGroupUtils": {
-        "androidx/transition/ViewGroupUtils": [
-          "IMPL"
-        ]
-      },
-      "android/support/v17/leanback/widget/ControlBarPresenter$ViewHolder": {
-        "androidx/leanback/widget/ControlBarPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v17/leanback/R$transition": {
-        "androidx/leanback/R$transition": [
-          "lb_title_in",
-          "lb_browse_headers_out",
-          "lb_title_out",
-          "lb_browse_entrance_transition",
-          "lb_details_enter_transition",
-          "lb_vertical_grid_entrance_transition",
-          "lb_browse_headers_in"
-        ]
-      },
-      "android/support/design/R$drawable": {
-        "androidx/design/R$drawable": [
-          "navigation_empty_icon",
-          "design_bottom_navigation_item_background"
-        ]
-      },
-      "android/support/wear/widget/drawer/NestedScrollViewFlingWatcher": {
-        "androidx/wear/widget/drawer/NestedScrollViewFlingWatcher": [
-          "MAX_WAIT_TIME_MS"
-        ]
-      },
-      "android/support/v17/leanback/app/HeadersSupportFragment": {
-        "androidx/leanback/app/HeadersSupportFragment": [
-          "sHeaderPresenter",
-          "sLayoutChangeListener"
-        ]
-      },
-      "android/support/v17/leanback/widget/ShadowHelper": {
-        "androidx/leanback/widget/ShadowHelper": [
-          "sInstance"
-        ]
-      },
-      "android/support/percent/PercentLayoutHelper": {
-        "androidx/PercentLayoutHelper": [
-          "TAG",
-          "VERBOSE",
-          "DEBUG"
-        ]
-      },
-      "android/support/design/internal/BottomNavigationMenu": {
-        "androidx/design/internal/BottomNavigationMenu": [
-          "MAX_ITEM_COUNT"
-        ]
-      },
-      "android/support/design/internal/TextScale": {
-        "androidx/design/internal/TextScale": [
-          "PROPNAME_SCALE"
-        ]
-      },
-      "android/support/v17/leanback/widget/PlaybackTransportRowPresenter$BoundData": {
-        "androidx/leanback/widget/PlaybackTransportRowPresenter$BoundData": [
-          "adapter",
-          "presenter"
-        ]
-      },
-      "android/support/v13/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl": {
-        "androidx/view/inputmethod/EditorInfoCompat$EditorInfoCompatBaseImpl": [
-          "CONTENT_MIME_TYPES_KEY"
-        ]
-      },
-      "android/support/v17/leanback/widget/ViewsStateBundle": {
-        "androidx/leanback/widget/ViewsStateBundle": [
-          "UNLIMITED",
-          "LIMIT_DEFAULT"
-        ]
-      },
-      "android/support/v4/content/ContextCompat": {
-        "androidx/content/ContextCompat": [
-          "sLock",
-          "TAG",
-          "sTempValue"
-        ]
-      },
-      "android/support/v4/util/SparseArrayCompat": {
-        "androidx/util/SparseArrayCompat": [
-          "DELETED"
-        ]
-      },
-      "android/support/transition/Styleable$VisibilityTransition": {
-        "androidx/transition/Styleable$VisibilityTransition": [
-          "TRANSITION_VISIBILITY_MODE"
-        ]
-      },
-      "android/support/v14/preference/MultiSelectListPreference$SavedState": {
-        "androidx/preference/MultiSelectListPreference$SavedState": [
-          "CREATOR",
-          "values"
-        ]
-      },
-      "android/support/v17/leanback/app/DetailsFragment$WaitEnterTransitionTimeout": {
-        "androidx/leanback/app/DetailsFragment$WaitEnterTransitionTimeout": [
-          "WAIT_ENTERTRANSITION_START"
-        ]
-      },
-      "android/support/text/emoji/MetadataListReader$OpenTypeReader": {
-        "androidx/text/emoji/MetadataListReader$OpenTypeReader": [
-          "UINT16_BYTE_COUNT",
-          "UINT32_BYTE_COUNT"
-        ]
-      },
-      "android/support/v7/preference/TwoStatePreference$SavedState": {
-        "androidx/preference/TwoStatePreference$SavedState": [
-          "checked",
-          "CREATOR"
-        ]
-      },
-      "android/support/v17/leanback/widget/Action": {
-        "androidx/leanback/widget/Action": [
-          "NO_ID"
-        ]
-      },
-      "android/support/v7/widget/Toolbar": {
-        "androidx/widget/Toolbar": [
-          "TAG"
-        ]
-      },
-      "android/support/v17/preference/LeanbackPreferenceDialogFragment": {
-        "androidx/leanback/preference/LeanbackPreferenceDialogFragment": [
-          "ARG_KEY"
-        ]
-      },
-      "android/support/v4/content/SharedPreferencesCompat$EditorCompat": {
-        "androidx/content/SharedPreferencesCompat$EditorCompat": [
-          "sInstance"
-        ]
-      },
-      "android/support/v17/leanback/widget/RowPresenter$ContainerViewHolder": {
-        "androidx/leanback/widget/RowPresenter$ContainerViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v7/app/MediaRouteChooserDialog$RouteComparator": {
-        "androidx/app/MediaRouteChooserDialog$RouteComparator": [
-          "sInstance"
-        ]
-      },
-      "android/support/v4/widget/PopupWindowCompat": {
-        "androidx/widget/PopupWindowCompat": [
-          "IMPL"
-        ]
-      },
-      "android/support/v4/widget/ImageViewCompat": {
-        "androidx/widget/ImageViewCompat": [
-          "IMPL"
-        ]
-      },
-      "android/support/v17/leanback/widget/GuidedActionsStylist$ViewHolder": {
-        "androidx/leanback/widget/GuidedActionsStylist$ViewHolder": [
-          "itemView"
-        ]
-      },
-      "android/support/v4/view/ActionProvider": {
-        "androidx/view/ActionProvider": [
-          "TAG"
-        ]
-      },
-      "android/support/v4/view/ViewConfigurationCompat": {
-        "androidx/view/ViewConfigurationCompat": [
-          "TAG",
-          "sGetScaledScrollFactorMethod"
-        ]
-      },
-      "android/support/customtabs/CustomTabsSession": {
-        "androidx/browser/customtabs/CustomTabsSession": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/mediarouter/R$style": {
-        "androidx/mediarouter/R$style": [
-          "Theme_MediaRouter_LightControlPanel",
-          "Theme_MediaRouter_Light",
-          "Theme_MediaRouter_Light_DarkControlPanel",
-          "Theme_MediaRouter"
-        ]
-      },
-      "android/support/text/emoji/EmojiProcessor$CodepointIndexFinder": {
-        "androidx/text/emoji/EmojiProcessor$CodepointIndexFinder": [
-          "INVALID_INDEX"
-        ]
-      },
-      "android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground": {
-        "androidx/leanback/widget/NonOverlappingLinearLayoutWithForeground": [
-          "VERSION_M"
-        ]
-      },
-      "android/support/v4/view/ViewCompat$ViewCompatApi21Impl": {
-        "androidx/view/legacy/ViewCompat$ViewCompatApi21Impl": [
-          "sThreadLocalRect"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$DecoratedCustomViewStyle": {
-        "androidx/app/NotificationCompat$DecoratedCustomViewStyle": [
-          "MAX_ACTION_BUTTONS"
-        ]
-      },
-      "android/support/v7/widget/PagerSnapHelper": {
-        "androidx/widget/PagerSnapHelper": [
-          "MAX_SCROLL_ON_FLING_DURATION"
-        ]
-      },
-      "android/support/wear/widget/CircledImageView": {
-        "androidx/wear/widget/CircledImageView": [
-          "SQUARE_DIMEN_WIDTH",
-          "SQUARE_DIMEN_NONE",
-          "SQUARE_DIMEN_HEIGHT",
-          "ARGB_EVALUATOR"
-        ]
-      },
-      "android/support/v7/widget/RtlSpacingHelper": {
-        "androidx/widget/RtlSpacingHelper": [
-          "UNDEFINED"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserServiceCompatApi26": {
-        "androidx/media/MediaBrowserServiceCompatApi26": [
-          "sResultFlags",
-          "TAG"
-        ]
-      },
-      "android/support/text/emoji/EmojiMetadata": {
-        "androidx/text/emoji/EmojiMetadata": [
-          "HAS_GLYPH_EXISTS",
-          "HAS_GLYPH_ABSENT",
-          "HAS_GLYPH_UNKNOWN",
-          "sMetadataItem"
-        ]
-      },
-      "android/support/mediacompat/R$integer": {
-        "androidx/mediacompat/R$integer": [
-          "cancel_button_image_alpha"
-        ]
-      },
-      "android/support/v7/content/res/AppCompatResources$ColorStateListCacheEntry": {
-        "androidx/content/res/AppCompatResources$ColorStateListCacheEntry": [
-          "value",
-          "configuration"
-        ]
-      },
-      "android/support/v17/leanback/widget/DetailsOverviewRowPresenter$ViewHolder": {
-        "androidx/leanback/widget/DetailsOverviewRowPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/wear/R$color": {
-        "androidx/wear/R$color": [
-          "circular_progress_layout_background_color"
-        ]
-      },
-      "android/support/v17/leanback/widget/ItemAlignmentFacet": {
-        "androidx/leanback/widget/ItemAlignmentFacet": [
-          "ITEM_ALIGN_OFFSET_PERCENT_DISABLED"
-        ]
-      },
-      "android/support/wear/ambient/AmbientMode$AmbientController": {
-        "androidx/wear/ambient/AmbientMode$AmbientController": [
-          "TAG"
-        ]
-      },
-      "android/support/v13/view/inputmethod/InputConnectionCompat": {
-        "androidx/view/inputmethod/InputConnectionCompat": [
-          "INPUT_CONTENT_GRANT_READ_URI_PERMISSION",
-          "IMPL"
-        ]
-      },
-      "android/support/wear/widget/BezierSCurveInterpolator": {
-        "androidx/wear/widget/BezierSCurveInterpolator": [
-          "STEP_SIZE",
-          "VALUES",
-          "INSTANCE"
-        ]
-      },
-      "android/support/v4/graphics/PathParser": {
-        "androidx/graphics/PathParser": [
-          "LOGTAG"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$RecycledViewPool": {
-        "androidx/widget/RecyclerView$RecycledViewPool": [
-          "DEFAULT_MAX_SCRAP"
-        ]
-      },
-      "android/support/v7/media/MediaRouteSelector": {
-        "androidx/media/MediaRouteSelector": [
-          "KEY_CONTROL_CATEGORIES",
-          "EMPTY"
-        ]
-      },
-      "android/support/transition/PropertyValuesHolderUtils": {
-        "androidx/transition/PropertyValuesHolderUtils": [
-          "IMPL"
-        ]
-      },
-      "android/support/graphics/drawable/VectorDrawableCompat$VFullPath": {
-        "androidx/graphics/drawable/VectorDrawableCompat$VFullPath": [
-          "FILL_TYPE_WINDING"
-        ]
-      },
-      "android/support/mediacompat/R$color": {
-        "androidx/mediacompat/R$color": [
-          "notification_material_background_media_default_color"
-        ]
-      },
-      "android/support/v17/leanback/widget/RowHeaderPresenter$ViewHolder": {
-        "androidx/leanback/widget/RowHeaderPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/design/widget/CollapsingToolbarLayout": {
-        "androidx/design/widget/CollapsingToolbarLayout": [
-          "DEFAULT_SCRIM_ANIMATION_DURATION"
-        ]
-      },
-      "android/support/v17/leanback/app/BrandedSupportFragment": {
-        "androidx/leanback/app/BrandedSupportFragment": [
-          "TITLE_SHOW"
-        ]
-      },
-      "android/support/design/internal/BottomNavigationPresenter$SavedState": {
-        "androidx/design/internal/BottomNavigationPresenter$SavedState": [
-          "CREATOR",
-          "selectedItemId"
-        ]
-      },
-      "android/support/v4/app/BackStackState": {
-        "androidx/app/BackStackState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v4/provider/FontsContractCompat$FontFamilyResult": {
-        "androidx/provider/FontsContractCompat$FontFamilyResult": [
-          "STATUS_WRONG_CERTIFICATES",
-          "STATUS_OK",
-          "STATUS_UNEXPECTED_DATA_PROVIDED"
-        ]
-      },
-      "android/support/v4/app/FragmentManagerState": {
-        "androidx/app/FragmentManagerState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/media/ExifInterface$Rational": {
-        "androidx/media/ExifInterface$Rational": [
-          "denominator",
-          "numerator"
-        ]
-      },
-      "android/support/text/emoji/TypefaceEmojiSpan": {
-        "androidx/text/emoji/TypefaceEmojiSpan": [
-          "sDebugPaint"
-        ]
-      },
-      "android/support/design/widget/FloatingActionButton$Behavior": {
-        "androidx/design/widget/FloatingActionButton$Behavior": [
-          "AUTO_HIDE_DEFAULT"
-        ]
-      },
-      "android/support/graphics/drawable/ArgbEvaluator": {
-        "androidx/graphics/drawable/ArgbEvaluator": [
-          "sInstance"
-        ]
-      },
-      "android/support/v4/util/ContainerHelpers": {
-        "androidx/util/ContainerHelpers": [
-          "EMPTY_INTS",
-          "EMPTY_LONGS",
-          "EMPTY_OBJECTS"
-        ]
-      },
-      "android/support/v7/media/MediaRouterJellybeanMr1": {
-        "androidx/media/MediaRouterJellybeanMr1": [
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/ActionPresenterSelector$ActionViewHolder": {
-        "androidx/leanback/widget/ActionPresenterSelector$ActionViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v4/app/FragmentState": {
-        "androidx/app/FragmentState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v7/widget/LinearSnapHelper": {
-        "androidx/widget/LinearSnapHelper": [
-          "INVALID_DISTANCE"
-        ]
-      },
-      "android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder": {
-        "androidx/leanback/widget/FullWidthDetailsOverviewRowPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/constraint/solver/widgets/ConstraintAnchor$Strength": {
-        "androidx/constraint/solver/widgets/ConstraintAnchor$Strength": [
-          "STRONG"
-        ]
-      },
-      "android/support/design/widget/HeaderBehavior": {
-        "androidx/design/widget/HeaderBehavior": [
-          "INVALID_POINTER"
-        ]
-      },
-      "android/support/v7/widget/LinearLayoutManager$SavedState": {
-        "androidx/widget/LinearLayoutManager$SavedState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v7/widget/GridLayout$Interval": {
-        "androidx/widget/GridLayout$Interval": [
-          "min",
-          "max"
-        ]
-      },
-      "android/support/v4/widget/SlidingPaneLayout$SavedState": {
-        "androidx/widget/SlidingPaneLayout$SavedState": [
-          "CREATOR",
-          "isOpen"
-        ]
-      },
-      "android/support/v17/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder": {
-        "androidx/leanback/widget/DetailsOverviewLogoPresenter$ViewHolder": [
-          "view"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompatApi24": {
-        "androidx/media/session/MediaSessionCompatApi24": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/app/MediaRouteActionProvider": {
-        "androidx/app/MediaRouteActionProvider": [
-          "TAG"
-        ]
-      },
-      "android/support/v4/media/session/MediaButtonReceiver": {
-        "androidx/media/session/MediaButtonReceiver": [
-          "TAG"
-        ]
-      },
-      "android/support/v4/content/AsyncTaskLoader$LoadTask": {
-        "androidx/content/AsyncTaskLoader$LoadTask": [
-          "waiting"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompatApi21": {
-        "androidx/media/session/MediaSessionCompatApi21": [
-          "TAG"
-        ]
-      },
-      "android/support/design/internal/NavigationMenuPresenter$ViewHolder": {
-        "androidx/design/internal/NavigationMenuPresenter$ViewHolder": [
-          "itemView"
-        ]
-      },
-      "android/support/v7/widget/AppCompatButton": {
-        "androidx/widget/AppCompatButton": [
-          "PLATFORM_SUPPORTS_AUTOSIZE"
-        ]
-      },
-      "android/support/v17/leanback/widget/CheckableImageView": {
-        "androidx/leanback/widget/CheckableImageView": [
-          "CHECKED_STATE_SET"
-        ]
-      },
-      "android/support/v4/view/animation/FastOutLinearInInterpolator": {
-        "androidx/view/animation/FastOutLinearInInterpolator": [
-          "VALUES"
-        ]
-      },
-      "android/support/v7/app/MediaRouteDiscoveryFragment": {
-        "androidx/app/MediaRouteDiscoveryFragment": [
-          "ARGUMENT_SELECTOR"
-        ]
-      },
-      "android/support/v4/graphics/TypefaceCompatApi21Impl": {
-        "androidx/graphics/TypefaceCompatApi21Impl": [
-          "TAG"
-        ]
-      },
-      "android/support/v17/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight": {
-        "androidx/leanback/widget/FocusHighlightHelper$BrowseItemFocusHighlight": [
-          "DURATION_MS"
-        ]
-      },
-      "android/support/transition/ImageViewUtilsApi21": {
-        "androidx/transition/ImageViewUtilsApi21": [
-          "TAG",
-          "sAnimateTransformMethodFetched",
-          "sAnimateTransformMethod"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$SmoothScroller$Action": {
-        "androidx/widget/RecyclerView$SmoothScroller$Action": [
-          "UNDEFINED_DURATION"
-        ]
-      },
-      "android/support/v4/media/session/PlaybackStateCompat$CustomAction": {
-        "androidx/media/session/PlaybackStateCompat$CustomAction": [
-          "CREATOR"
-        ]
-      },
-      "android/support/design/R$integer": {
-        "androidx/design/R$integer": [
-          "app_bar_elevation_anim_duration"
-        ]
-      },
-      "android/support/v4/provider/DocumentFile": {
-        "androidx/provider/DocumentFile": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/widget/StaggeredGridLayoutManager$SavedState": {
-        "androidx/widget/StaggeredGridLayoutManager$SavedState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/animation/FlingAnimation$DragForce": {
-        "androidx/animation/FlingAnimation$DragForce": [
-          "VELOCITY_THRESHOLD_MULTIPLIER",
-          "DEFAULT_FRICTION"
-        ]
-      },
-      "android/support/v17/leanback/transition/ParallaxTransition": {
-        "androidx/leanback/transition/ParallaxTransition": [
-          "sInterpolator"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$MessagingStyle": {
-        "androidx/app/NotificationCompat$MessagingStyle": [
-          "MAXIMUM_RETAINED_MESSAGES"
-        ]
-      },
-      "android/support/v7/widget/RecyclerView$SavedState": {
-        "androidx/widget/RecyclerView$SavedState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v17/leanback/widget/ResizingTextView": {
-        "androidx/leanback/widget/ResizingTextView": [
-          "TRIGGER_MAX_LINES"
-        ]
-      },
-      "android/support/v7/widget/StaggeredGridLayoutManager$LazySpanLookup": {
-        "androidx/widget/StaggeredGridLayoutManager$LazySpanLookup": [
-          "MIN_SIZE"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$MediaSessionImplBase": {
-        "androidx/media/session/MediaSessionCompat$MediaSessionImplBase": [
-          "RCC_PLAYSTATE_NONE"
-        ]
-      },
-      "android/support/v4/util/LongSparseArray": {
-        "androidx/util/LongSparseArray": [
-          "DELETED"
-        ]
-      },
-      "android/support/v4/view/accessibility/AccessibilityNodeProviderCompat": {
-        "androidx/view/accessibility/AccessibilityNodeProviderCompat": [
-          "HOST_VIEW_ID"
-        ]
-      },
-      "android/support/v4/view/AsyncLayoutInflater": {
-        "androidx/view/AsyncLayoutInflater": [
-          "TAG"
-        ]
-      },
-      "android/support/graphics/drawable/VectorDrawableCompat$VPathRenderer": {
-        "androidx/graphics/drawable/VectorDrawableCompat$VPathRenderer": [
-          "IDENTITY_MATRIX"
-        ]
-      },
-      "android/support/v13/view/DragAndDropPermissionsCompat": {
-        "androidx/view/DragAndDropPermissionsCompat": [
-          "IMPL"
-        ]
-      },
-      "android/support/v4/media/MediaBrowserCompatApi21": {
-        "androidx/media/MediaBrowserCompatApi21": [
-          "NULL_MEDIA_ITEM_ID"
-        ]
-      },
-      "android/support/v4/view/animation/FastOutSlowInInterpolator": {
-        "androidx/view/animation/FastOutSlowInInterpolator": [
-          "VALUES"
-        ]
-      },
-      "android/support/v7/widget/AppCompatProgressBarHelper": {
-        "androidx/widget/AppCompatProgressBarHelper": [
-          "TINT_ATTRS"
-        ]
-      },
-      "android/support/v4/media/ParceledListSliceAdapterApi21": {
-        "androidx/media/ParceledListSliceAdapterApi21": [
-          "sConstructor"
-        ]
-      },
-      "android/support/compat/R$integer": {
-        "androidx/compat/R$integer": [
-          "status_bar_notification_info_maxnum"
-        ]
-      },
-      "android/support/v14/preference/EditTextPreferenceDialogFragment": {
-        "androidx/preference/EditTextPreferenceDialogFragment": [
-          "SAVE_STATE_TEXT"
-        ]
-      },
-      "android/support/wear/R$array": {
-        "androidx/wear/R$array": [
-          "circular_progress_layout_color_scheme_colors"
-        ]
-      },
-      "android/support/v7/cardview/R$style": {
-        "androidx/cardview/R$style": [
-          "CardView"
-        ]
-      },
-      "android/support/design/internal/ParcelableSparseArray": {
-        "androidx/design/internal/ParcelableSparseArray": [
-          "CREATOR"
-        ]
-      },
-      "android/support/design/widget/CircularBorderDrawable": {
-        "androidx/design/widget/CircularBorderDrawable": [
-          "DRAW_STROKE_WIDTH_MULTIPLE"
-        ]
-      },
-      "android/support/transition/ObjectAnimatorUtils": {
-        "androidx/transition/ObjectAnimatorUtils": [
-          "IMPL"
-        ]
-      },
-      "android/support/v4/app/ActivityCompat": {
-        "androidx/app/legacy/ActivityCompat": [
-          "sDelegate"
-        ]
-      },
-      "android/support/wear/internal/widget/drawer/MultiPageUi": {
-        "androidx/wear/internal/widget/drawer/MultiPageUi": [
-          "TAG"
-        ]
-      },
-      "android/support/transition/ViewOverlayApi14$OverlayViewGroup": {
-        "androidx/transition/ViewOverlayApi14$OverlayViewGroup": [
-          "sInvalidateChildInParentFastMethod"
-        ]
-      },
-      "android/support/v4/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale": {
-        "androidx/text/TextDirectionHeuristicsCompat$TextDirectionHeuristicLocale": [
-          "INSTANCE"
-        ]
-      },
-      "android/support/v7/preference/Preference": {
-        "androidx/preference/Preference": [
-          "DEFAULT_ORDER"
-        ]
-      },
-      "android/support/v4/graphics/drawable/RoundedBitmapDrawable": {
-        "androidx/graphics/drawable/RoundedBitmapDrawable": [
-          "DEFAULT_PAINT_FLAGS"
-        ]
-      },
-      "android/support/design/widget/TabLayout$Tab": {
-        "androidx/design/widget/TabLayout$Tab": [
-          "INVALID_POSITION"
-        ]
-      },
-      "android/support/v7/widget/SnapHelper": {
-        "androidx/widget/SnapHelper": [
-          "MILLISECONDS_PER_INCH"
-        ]
-      },
-      "android/support/v7/widget/AbsActionBarView": {
-        "androidx/widget/AbsActionBarView": [
-          "FADE_DURATION"
-        ]
-      },
-      "android/support/v17/leanback/graphics/FitWidthBitmapDrawable": {
-        "androidx/leanback/graphics/FitWidthBitmapDrawable": [
-          "PROPERTY_VERTICAL_OFFSET"
-        ]
-      },
-      "android/support/v4/media/session/MediaSessionCompat$ResultReceiverWrapper": {
-        "androidx/media/session/MediaSessionCompat$ResultReceiverWrapper": [
-          "CREATOR"
-        ]
-      },
-      "android/support/v7/view/SupportMenuInflater$InflatedOnMenuItemClickListener": {
-        "androidx/view/SupportMenuInflater$InflatedOnMenuItemClickListener": [
-          "PARAM_TYPES"
-        ]
-      },
-      "android/support/v4/widget/EdgeEffectCompat": {
-        "androidx/widget/EdgeEffectCompat": [
-          "IMPL"
-        ]
-      },
-      "android/support/v7/app/MediaRouteDialogFactory": {
-        "androidx/app/MediaRouteDialogFactory": [
-          "sDefault"
-        ]
-      },
-      "android/support/v4/app/Fragment$SavedState": {
-        "androidx/app/Fragment$SavedState": [
-          "CREATOR"
-        ]
-      },
-      "android/support/transition/Styleable$TransitionSet": {
-        "androidx/transition/Styleable$TransitionSet": [
-          "TRANSITION_ORDERING"
-        ]
-      },
-      "android/support/v7/preference/PreferenceGroupAdapter": {
-        "androidx/preference/PreferenceGroupAdapter": [
-          "TAG"
-        ]
-      },
-      "android/support/v7/view/menu/MenuPopupHelper": {
-        "androidx/view/menu/MenuPopupHelper": [
-          "TOUCH_EPICENTER_SIZE_DP"
-        ]
-      },
-      "android/support/v4/app/NotificationCompat$Builder": {
-        "androidx/app/NotificationCompat$Builder": [
-          "MAX_CHARSEQUENCE_LENGTH"
-        ]
-      }
+      "android/support/text/emoji/R$id": "androidx/text/emoji/R$id",
+      "android/support/text/emoji/widget/ExtractButtonCompat": "androidx/text/emoji/widget/ExtractButtonCompat",
+      "android/support/text/emoji/widget/EmojiInputFilter$InitCallbackImpl": "androidx/text/emoji/widget/EmojiInputFilter$InitCallbackImpl",
+      "android/support/text/emoji/widget/EmojiInputFilter": "androidx/text/emoji/widget/EmojiInputFilter",
+      "android/support/text/emoji/widget/EmojiTextView": "androidx/text/emoji/widget/EmojiTextView",
+      "android/support/text/emoji/widget/EmojiTextViewHelper$1": "androidx/text/emoji/widget/EmojiTextViewHelper$1",
+      "android/support/text/emoji/widget/EmojiTextViewHelper$HelperInternal": "androidx/text/emoji/widget/EmojiTextViewHelper$HelperInternal",
+      "android/support/text/emoji/widget/EmojiTextViewHelper$HelperInternal19": "androidx/text/emoji/widget/EmojiTextViewHelper$HelperInternal19",
+      "android/support/text/emoji/widget/EmojiTransformationMethod": "androidx/text/emoji/widget/EmojiTransformationMethod",
+      "android/support/text/emoji/widget/EmojiTextWatcher$InitCallbackImpl": "androidx/text/emoji/widget/EmojiTextWatcher$InitCallbackImpl",
+      "android/support/text/emoji/widget/SpannableBuilder$WatcherWrapper": "androidx/text/emoji/widget/SpannableBuilder$WatcherWrapper",
+      "android/support/customtabs/CustomTabsCallback": "androidx/browser/customtabs/CustomTabsCallback",
+      "android/support/customtabs/CustomTabsClient$1": "androidx/browser/customtabs/CustomTabsClient$1",
+      "android/support/customtabs/CustomTabsServiceConnection": "androidx/browser/customtabs/CustomTabsServiceConnection",
+      "android/support/customtabs/CustomTabsClient": "androidx/browser/customtabs/CustomTabsClient",
+      "android/support/customtabs/CustomTabsClient$2$1": "androidx/browser/customtabs/CustomTabsClient$2$1",
+      "android/support/customtabs/CustomTabsClient$2": "androidx/browser/customtabs/CustomTabsClient$2",
+      "android/support/customtabs/CustomTabsClient$2$2": "androidx/browser/customtabs/CustomTabsClient$2$2",
+      "android/support/customtabs/CustomTabsClient$2$3": "androidx/browser/customtabs/CustomTabsClient$2$3",
+      "android/support/customtabs/CustomTabsClient$2$4": "androidx/browser/customtabs/CustomTabsClient$2$4",
+      "android/support/customtabs/CustomTabsClient$2$5": "androidx/browser/customtabs/CustomTabsClient$2$5",
+      "android/support/customtabs/ICustomTabsCallback$Stub": "androidx/browser/customtabs/ICustomTabsCallback$Stub",
+      "android/support/customtabs/CustomTabsSession": "androidx/browser/customtabs/CustomTabsSession",
+      "android/support/customtabs/ICustomTabsCallback": "androidx/browser/customtabs/ICustomTabsCallback",
+      "android/support/customtabs/ICustomTabsService": "androidx/browser/customtabs/ICustomTabsService",
+      "android/support/customtabs/CustomTabsIntent$1": "androidx/browser/customtabs/CustomTabsIntent$1",
+      "android/support/customtabs/CustomTabsIntent": "androidx/browser/customtabs/CustomTabsIntent",
+      "android/support/customtabs/CustomTabsIntent$Builder": "androidx/browser/customtabs/CustomTabsIntent$Builder",
+      "android/support/customtabs/CustomTabsService$1$1": "androidx/browser/customtabs/CustomTabsService$1$1",
+      "android/support/customtabs/CustomTabsService$1": "androidx/browser/customtabs/CustomTabsService$1",
+      "android/support/customtabs/CustomTabsSessionToken": "androidx/browser/customtabs/CustomTabsSessionToken",
+      "android/support/customtabs/CustomTabsService": "androidx/browser/customtabs/CustomTabsService",
+      "android/support/customtabs/ICustomTabsService$Stub": "androidx/browser/customtabs/ICustomTabsService$Stub",
+      "android/support/customtabs/CustomTabsService$Relation": "androidx/browser/customtabs/CustomTabsService$Relation",
+      "android/support/customtabs/CustomTabsService$Result": "androidx/browser/customtabs/CustomTabsService$Result",
+      "android/support/customtabs/CustomTabsServiceConnection$1": "androidx/browser/customtabs/CustomTabsServiceConnection$1",
+      "android/support/customtabs/CustomTabsSessionToken$MockCallback": "androidx/browser/customtabs/CustomTabsSessionToken$MockCallback",
+      "android/support/customtabs/CustomTabsSessionToken$1": "androidx/browser/customtabs/CustomTabsSessionToken$1",
+      "android/support/customtabs/ICustomTabsCallback$Stub$Proxy": "androidx/browser/customtabs/ICustomTabsCallback$Stub$Proxy",
+      "android/support/customtabs/ICustomTabsService$Stub$Proxy": "androidx/browser/customtabs/ICustomTabsService$Stub$Proxy",
+      "android/support/customtabs/IPostMessageService$Stub$Proxy": "androidx/browser/customtabs/IPostMessageService$Stub$Proxy",
+      "android/support/customtabs/IPostMessageService": "androidx/browser/customtabs/IPostMessageService",
+      "android/support/customtabs/IPostMessageService$Stub": "androidx/browser/customtabs/IPostMessageService$Stub",
+      "android/support/customtabs/PostMessageService$1": "androidx/browser/customtabs/PostMessageService$1",
+      "android/support/customtabs/PostMessageService": "androidx/browser/customtabs/PostMessageService",
+      "android/support/customtabs/PostMessageServiceConnection": "androidx/browser/customtabs/PostMessageServiceConnection",
+      "android/support/customtabs/TrustedWebUtils": "androidx/browser/customtabs/TrustedWebUtils",
+      "android/support/media/ExifInterface$1": "androidx/media/ExifInterface$1",
+      "android/support/media/ExifInterface": "androidx/media/ExifInterface",
+      "android/support/media/ExifInterface$ByteOrderedDataInputStream": "androidx/media/ExifInterface$ByteOrderedDataInputStream",
+      "android/support/media/ExifInterface$ByteOrderedDataOutputStream": "androidx/media/ExifInterface$ByteOrderedDataOutputStream",
+      "android/support/media/ExifInterface$ExifAttribute": "androidx/media/ExifInterface$ExifAttribute",
+      "android/support/media/ExifInterface$Rational": "androidx/media/ExifInterface$Rational",
+      "android/support/media/ExifInterface$ExifTag": "androidx/media/ExifInterface$ExifTag",
+      "android/support/media/ExifInterface$IfdType": "androidx/media/ExifInterface$IfdType",
+      "android/arch/persistence/room/RoomDatabase$Callback": "androidx/persistence/room/RoomDatabase$Callback",
+      "android/arch/persistence/room/EntityDeletionOrUpdateAdapter": "androidx/persistence/room/EntityDeletionOrUpdateAdapter",
+      "android/arch/persistence/room/SharedSQLiteStatement": "androidx/persistence/room/SharedSQLiteStatement",
+      "android/arch/persistence/room/EntityInsertionAdapter": "androidx/persistence/room/EntityInsertionAdapter",
+      "android/arch/persistence/room/InvalidationTracker$1": "androidx/persistence/room/InvalidationTracker$1",
+      "android/arch/persistence/room/InvalidationTracker$ObservedTableTracker": "androidx/persistence/room/InvalidationTracker$ObservedTableTracker",
+      "android/arch/persistence/room/InvalidationTracker$2": "androidx/persistence/room/InvalidationTracker$2",
+      "android/arch/persistence/room/InvalidationTracker$ObserverWrapper": "androidx/persistence/room/InvalidationTracker$ObserverWrapper",
+      "android/arch/persistence/room/InvalidationTracker$WeakObserver": "androidx/persistence/room/InvalidationTracker$WeakObserver",
+      "android/arch/persistence/room/Room": "androidx/persistence/room/Room",
+      "android/arch/persistence/room/RoomDatabase$Builder": "androidx/persistence/room/RoomDatabase$Builder",
+      "android/arch/persistence/room/RoomSQLiteQuery": "androidx/persistence/room/RoomSQLiteQuery",
+      "android/arch/persistence/room/paging/LimitOffsetDataSource$1": "androidx/persistence/room/paging/LimitOffsetDataSource$1",
+      "android/arch/persistence/room/paging/LimitOffsetDataSource": "androidx/persistence/room/paging/LimitOffsetDataSource",
+      "android/arch/persistence/room/util/StringUtil": "androidx/persistence/room/util/StringUtil",
+      "android/arch/persistence/room/ColumnInfo$SQLiteTypeAffinity": "androidx/persistence/room/ColumnInfo$SQLiteTypeAffinity",
+      "android/arch/persistence/room/util/TableInfo$ForeignKeyWithSequence": "androidx/persistence/room/util/TableInfo$ForeignKeyWithSequence",
+      "android/support/design/internal/BaselineLayout": "androidx/design/internal/BaselineLayout",
+      "android/support/design/internal/BottomNavigationItemView": "androidx/design/internal/BottomNavigationItemView",
+      "android/support/design/R$dimen": "androidx/design/R$dimen",
+      "android/support/design/R": "androidx/design/R",
+      "android/support/design/R$layout": "androidx/design/R$layout",
+      "android/support/design/R$drawable": "androidx/design/R$drawable",
+      "android/support/design/R$id": "androidx/design/R$id",
+      "android/support/design/internal/BottomNavigationMenu": "androidx/design/internal/BottomNavigationMenu",
+      "android/support/design/internal/BottomNavigationMenuView$1": "androidx/design/internal/BottomNavigationMenuView$1",
+      "android/support/design/internal/BottomNavigationMenuView": "androidx/design/internal/BottomNavigationMenuView",
+      "android/support/design/internal/BottomNavigationPresenter": "androidx/design/internal/BottomNavigationPresenter",
+      "android/support/design/internal/TextScale": "androidx/design/internal/TextScale",
+      "android/support/design/internal/BottomNavigationPresenter$SavedState$1": "androidx/design/internal/BottomNavigationPresenter$SavedState$1",
+      "android/support/design/internal/BottomNavigationPresenter$SavedState": "androidx/design/internal/BottomNavigationPresenter$SavedState",
+      "android/support/design/internal/ForegroundLinearLayout": "androidx/design/internal/ForegroundLinearLayout",
+      "android/support/design/R$styleable": "androidx/design/R$styleable",
+      "android/support/design/internal/NavigationMenu": "androidx/design/internal/NavigationMenu",
+      "android/support/design/internal/NavigationSubMenu": "androidx/design/internal/NavigationSubMenu",
+      "android/support/design/internal/NavigationMenuItemView$1": "androidx/design/internal/NavigationMenuItemView$1",
+      "android/support/design/internal/NavigationMenuItemView": "androidx/design/internal/NavigationMenuItemView",
+      "android/support/design/internal/NavigationMenuPresenter$1": "androidx/design/internal/NavigationMenuPresenter$1",
+      "android/support/design/internal/NavigationMenuPresenter": "androidx/design/internal/NavigationMenuPresenter",
+      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuAdapter": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuAdapter",
+      "android/support/design/internal/NavigationMenuPresenter$HeaderViewHolder": "androidx/design/internal/NavigationMenuPresenter$HeaderViewHolder",
+      "android/support/design/internal/NavigationMenuPresenter$ViewHolder": "androidx/design/internal/NavigationMenuPresenter$ViewHolder",
+      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuItem",
+      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuTextItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuTextItem",
+      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuSeparatorItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuSeparatorItem",
+      "android/support/design/internal/NavigationMenuPresenter$NavigationMenuHeaderItem": "androidx/design/internal/NavigationMenuPresenter$NavigationMenuHeaderItem",
+      "android/support/design/internal/NavigationMenuPresenter$NormalViewHolder": "androidx/design/internal/NavigationMenuPresenter$NormalViewHolder",
+      "android/support/design/internal/NavigationMenuPresenter$SubheaderViewHolder": "androidx/design/internal/NavigationMenuPresenter$SubheaderViewHolder",
+      "android/support/design/internal/NavigationMenuPresenter$SeparatorViewHolder": "androidx/design/internal/NavigationMenuPresenter$SeparatorViewHolder",
+      "android/support/design/internal/ParcelableSparseArray": "androidx/design/internal/ParcelableSparseArray",
+      "android/support/design/internal/NavigationMenuView": "androidx/design/internal/NavigationMenuView",
+      "android/support/design/internal/ParcelableSparseArray$1": "androidx/design/internal/ParcelableSparseArray$1",
+      "android/support/design/internal/ScrimInsetsFrameLayout$1": "androidx/design/internal/ScrimInsetsFrameLayout$1",
+      "android/support/design/internal/ScrimInsetsFrameLayout": "androidx/design/internal/ScrimInsetsFrameLayout",
+      "android/support/design/R$style": "androidx/design/R$style",
+      "android/support/design/internal/SnackbarContentLayout": "androidx/design/internal/SnackbarContentLayout",
+      "android/support/design/widget/BaseTransientBottomBar$ContentViewCallback": "androidx/design/widget/BaseTransientBottomBar$ContentViewCallback",
+      "android/support/design/widget/BaseTransientBottomBar": "androidx/design/widget/BaseTransientBottomBar",
+      "android/support/design/internal/TextScale$1": "androidx/design/internal/TextScale$1",
+      "android/support/design/widget/AnimationUtils": "androidx/design/widget/AnimationUtils",
+      "android/support/design/widget/AppBarLayout$1": "androidx/design/widget/AppBarLayout$1",
+      "android/support/design/widget/AppBarLayout": "androidx/design/widget/AppBarLayout",
+      "android/support/design/widget/AppBarLayout$Behavior$1": "androidx/design/widget/AppBarLayout$Behavior$1",
+      "android/support/design/widget/AppBarLayout$Behavior": "androidx/design/widget/AppBarLayout$Behavior",
+      "android/support/design/widget/AppBarLayout$Behavior$DragCallback": "androidx/design/widget/AppBarLayout$Behavior$DragCallback",
+      "android/support/design/widget/AppBarLayout$Behavior$SavedState$1": "androidx/design/widget/AppBarLayout$Behavior$SavedState$1",
+      "android/support/design/widget/AppBarLayout$Behavior$SavedState": "androidx/design/widget/AppBarLayout$Behavior$SavedState",
+      "android/support/design/widget/HeaderBehavior": "androidx/design/widget/HeaderBehavior",
+      "android/support/design/widget/AppBarLayout$LayoutParams": "androidx/design/widget/AppBarLayout$LayoutParams",
+      "android/support/design/widget/AppBarLayout$ScrollingViewBehavior": "androidx/design/widget/AppBarLayout$ScrollingViewBehavior",
+      "android/support/design/widget/AppBarLayout$LayoutParams$ScrollFlags": "androidx/design/widget/AppBarLayout$LayoutParams$ScrollFlags",
+      "android/support/design/widget/AppBarLayout$OnOffsetChangedListener": "androidx/design/widget/AppBarLayout$OnOffsetChangedListener",
+      "android/support/design/widget/HeaderScrollingViewBehavior": "androidx/design/widget/HeaderScrollingViewBehavior",
+      "android/support/design/R$attr": "androidx/design/R$attr",
+      "android/support/design/widget/ThemeUtils": "androidx/design/widget/ThemeUtils",
+      "android/support/design/widget/ViewUtilsLollipop": "androidx/design/widget/ViewUtilsLollipop",
+      "android/support/design/widget/BaseTransientBottomBar$1": "androidx/design/widget/BaseTransientBottomBar$1",
+      "android/support/design/widget/BaseTransientBottomBar$10": "androidx/design/widget/BaseTransientBottomBar$10",
+      "android/support/design/widget/BaseTransientBottomBar$11": "androidx/design/widget/BaseTransientBottomBar$11",
+      "android/support/design/widget/BaseTransientBottomBar$SnackbarBaseLayout": "androidx/design/widget/BaseTransientBottomBar$SnackbarBaseLayout",
+      "android/support/design/widget/BaseTransientBottomBar$12": "androidx/design/widget/BaseTransientBottomBar$12",
+      "android/support/design/widget/BaseTransientBottomBar$2": "androidx/design/widget/BaseTransientBottomBar$2",
+      "android/support/design/widget/BaseTransientBottomBar$3": "androidx/design/widget/BaseTransientBottomBar$3",
+      "android/support/design/widget/SnackbarManager$Callback": "androidx/design/widget/SnackbarManager$Callback",
+      "android/support/design/widget/SnackbarManager": "androidx/design/widget/SnackbarManager",
+      "android/support/design/widget/BaseTransientBottomBar$4": "androidx/design/widget/BaseTransientBottomBar$4",
+      "android/support/design/widget/SwipeDismissBehavior$OnDismissListener": "androidx/design/widget/SwipeDismissBehavior$OnDismissListener",
+      "android/support/design/widget/BaseTransientBottomBar$BaseCallback": "androidx/design/widget/BaseTransientBottomBar$BaseCallback",
+      "android/support/design/widget/SwipeDismissBehavior": "androidx/design/widget/SwipeDismissBehavior",
+      "android/support/design/widget/BaseTransientBottomBar$5$1": "androidx/design/widget/BaseTransientBottomBar$5$1",
+      "android/support/design/widget/BaseTransientBottomBar$5": "androidx/design/widget/BaseTransientBottomBar$5",
+      "android/support/design/widget/BaseTransientBottomBar$OnAttachStateChangeListener": "androidx/design/widget/BaseTransientBottomBar$OnAttachStateChangeListener",
+      "android/support/design/widget/BaseTransientBottomBar$6": "androidx/design/widget/BaseTransientBottomBar$6",
+      "android/support/design/widget/BaseTransientBottomBar$OnLayoutChangeListener": "androidx/design/widget/BaseTransientBottomBar$OnLayoutChangeListener",
+      "android/support/design/widget/BaseTransientBottomBar$7": "androidx/design/widget/BaseTransientBottomBar$7",
+      "android/support/design/widget/BaseTransientBottomBar$8": "androidx/design/widget/BaseTransientBottomBar$8",
+      "android/support/design/widget/BaseTransientBottomBar$9": "androidx/design/widget/BaseTransientBottomBar$9",
+      "android/support/design/widget/BaseTransientBottomBar$BaseCallback$DismissEvent": "androidx/design/widget/BaseTransientBottomBar$BaseCallback$DismissEvent",
+      "android/support/design/widget/BaseTransientBottomBar$Behavior": "androidx/design/widget/BaseTransientBottomBar$Behavior",
+      "android/support/design/widget/BaseTransientBottomBar$Duration": "androidx/design/widget/BaseTransientBottomBar$Duration",
+      "android/support/design/R$anim": "androidx/design/R$anim",
+      "android/support/design/widget/BottomNavigationView$1": "androidx/design/widget/BottomNavigationView$1",
+      "android/support/design/widget/BottomNavigationView": "androidx/design/widget/BottomNavigationView",
+      "android/support/design/widget/BottomNavigationView$OnNavigationItemReselectedListener": "androidx/design/widget/BottomNavigationView$OnNavigationItemReselectedListener",
+      "android/support/design/widget/BottomNavigationView$OnNavigationItemSelectedListener": "androidx/design/widget/BottomNavigationView$OnNavigationItemSelectedListener",
+      "android/support/design/widget/BottomNavigationView$SavedState$1": "androidx/design/widget/BottomNavigationView$SavedState$1",
+      "android/support/design/widget/BottomNavigationView$SavedState": "androidx/design/widget/BottomNavigationView$SavedState",
+      "android/support/design/R$color": "androidx/design/R$color",
+      "android/support/design/widget/BottomSheetBehavior$1": "androidx/design/widget/BottomSheetBehavior$1",
+      "android/support/design/widget/BottomSheetBehavior": "androidx/design/widget/BottomSheetBehavior",
+      "android/support/design/widget/BottomSheetBehavior$2": "androidx/design/widget/BottomSheetBehavior$2",
+      "android/support/design/widget/BottomSheetBehavior$SettleRunnable": "androidx/design/widget/BottomSheetBehavior$SettleRunnable",
+      "android/support/design/widget/BottomSheetBehavior$BottomSheetCallback": "androidx/design/widget/BottomSheetBehavior$BottomSheetCallback",
+      "android/support/design/widget/BottomSheetBehavior$SavedState$1": "androidx/design/widget/BottomSheetBehavior$SavedState$1",
+      "android/support/design/widget/BottomSheetBehavior$SavedState": "androidx/design/widget/BottomSheetBehavior$SavedState",
+      "android/support/design/widget/BottomSheetBehavior$State": "androidx/design/widget/BottomSheetBehavior$State",
+      "android/support/design/widget/BottomSheetDialog$1": "androidx/design/widget/BottomSheetDialog$1",
+      "android/support/design/widget/BottomSheetDialog": "androidx/design/widget/BottomSheetDialog",
+      "android/support/design/widget/BottomSheetDialog$2": "androidx/design/widget/BottomSheetDialog$2",
+      "android/support/design/widget/BottomSheetDialog$3": "androidx/design/widget/BottomSheetDialog$3",
+      "android/support/design/widget/BottomSheetDialog$4": "androidx/design/widget/BottomSheetDialog$4",
+      "android/support/design/widget/BottomSheetDialogFragment": "androidx/design/widget/BottomSheetDialogFragment",
+      "android/support/design/widget/CheckableImageButton$1": "androidx/design/widget/CheckableImageButton$1",
+      "android/support/design/widget/CheckableImageButton": "androidx/design/widget/CheckableImageButton",
+      "android/support/design/widget/CircularBorderDrawable": "androidx/design/widget/CircularBorderDrawable",
+      "android/support/design/widget/CircularBorderDrawableLollipop": "androidx/design/widget/CircularBorderDrawableLollipop",
+      "android/support/design/widget/CollapsingTextHelper": "androidx/design/widget/CollapsingTextHelper",
+      "android/support/design/widget/CollapsingToolbarLayout$1": "androidx/design/widget/CollapsingToolbarLayout$1",
+      "android/support/design/widget/CollapsingToolbarLayout": "androidx/design/widget/CollapsingToolbarLayout",
+      "android/support/design/widget/CollapsingToolbarLayout$2": "androidx/design/widget/CollapsingToolbarLayout$2",
+      "android/support/design/widget/CollapsingToolbarLayout$LayoutParams$CollapseMode": "androidx/design/widget/CollapsingToolbarLayout$LayoutParams$CollapseMode",
+      "android/support/design/widget/CollapsingToolbarLayout$LayoutParams": "androidx/design/widget/CollapsingToolbarLayout$LayoutParams",
+      "android/support/design/widget/CollapsingToolbarLayout$OffsetUpdateListener": "androidx/design/widget/CollapsingToolbarLayout$OffsetUpdateListener",
+      "android/support/design/widget/ViewOffsetHelper": "androidx/design/widget/ViewOffsetHelper",
+      "android/support/design/widget/DrawableUtils": "androidx/design/widget/DrawableUtils",
+      "android/support/design/widget/FloatingActionButton$1": "androidx/design/widget/FloatingActionButton$1",
+      "android/support/design/widget/FloatingActionButtonImpl$InternalVisibilityChangedListener": "androidx/design/widget/FloatingActionButtonImpl$InternalVisibilityChangedListener",
+      "android/support/design/widget/FloatingActionButton": "androidx/design/widget/FloatingActionButton",
+      "android/support/design/widget/FloatingActionButton$OnVisibilityChangedListener": "androidx/design/widget/FloatingActionButton$OnVisibilityChangedListener",
+      "android/support/design/widget/FloatingActionButtonImpl": "androidx/design/widget/FloatingActionButtonImpl",
+      "android/support/design/widget/FloatingActionButton$Behavior": "androidx/design/widget/FloatingActionButton$Behavior",
+      "android/support/design/widget/FloatingActionButton$ShadowDelegateImpl": "androidx/design/widget/FloatingActionButton$ShadowDelegateImpl",
+      "android/support/design/widget/ShadowViewDelegate": "androidx/design/widget/ShadowViewDelegate",
+      "android/support/design/widget/FloatingActionButton$Size": "androidx/design/widget/FloatingActionButton$Size",
+      "android/support/design/widget/VisibilityAwareImageButton": "androidx/design/widget/VisibilityAwareImageButton",
+      "android/support/design/widget/ViewUtils": "androidx/design/widget/ViewUtils",
+      "android/support/design/widget/FloatingActionButtonLollipop": "androidx/design/widget/FloatingActionButtonLollipop",
+      "android/support/design/widget/FloatingActionButtonImpl$1": "androidx/design/widget/FloatingActionButtonImpl$1",
+      "android/support/design/widget/FloatingActionButtonImpl$2": "androidx/design/widget/FloatingActionButtonImpl$2",
+      "android/support/design/widget/FloatingActionButtonImpl$3": "androidx/design/widget/FloatingActionButtonImpl$3",
+      "android/support/design/widget/FloatingActionButtonImpl$DisabledElevationAnimation": "androidx/design/widget/FloatingActionButtonImpl$DisabledElevationAnimation",
+      "android/support/design/widget/FloatingActionButtonImpl$ShadowAnimatorImpl": "androidx/design/widget/FloatingActionButtonImpl$ShadowAnimatorImpl",
+      "android/support/design/widget/FloatingActionButtonImpl$ElevateToTranslationZAnimation": "androidx/design/widget/FloatingActionButtonImpl$ElevateToTranslationZAnimation",
+      "android/support/design/widget/FloatingActionButtonImpl$ResetElevationAnimation": "androidx/design/widget/FloatingActionButtonImpl$ResetElevationAnimation",
+      "android/support/design/widget/ShadowDrawableWrapper": "androidx/design/widget/ShadowDrawableWrapper",
+      "android/support/design/widget/StateListAnimator": "androidx/design/widget/StateListAnimator",
+      "android/support/design/widget/FloatingActionButtonLollipop$AlwaysStatefulGradientDrawable": "androidx/design/widget/FloatingActionButtonLollipop$AlwaysStatefulGradientDrawable",
+      "android/support/design/widget/HeaderBehavior$FlingRunnable": "androidx/design/widget/HeaderBehavior$FlingRunnable",
+      "android/support/design/widget/ViewOffsetBehavior": "androidx/design/widget/ViewOffsetBehavior",
+      "android/support/design/widget/NavigationView$1": "androidx/design/widget/NavigationView$1",
+      "android/support/design/widget/NavigationView": "androidx/design/widget/NavigationView",
+      "android/support/design/widget/NavigationView$OnNavigationItemSelectedListener": "androidx/design/widget/NavigationView$OnNavigationItemSelectedListener",
+      "android/support/design/widget/NavigationView$SavedState$1": "androidx/design/widget/NavigationView$SavedState$1",
+      "android/support/design/widget/NavigationView$SavedState": "androidx/design/widget/NavigationView$SavedState",
+      "android/support/design/widget/Snackbar$1": "androidx/design/widget/Snackbar$1",
+      "android/support/design/widget/Snackbar": "androidx/design/widget/Snackbar",
+      "android/support/design/widget/Snackbar$Callback": "androidx/design/widget/Snackbar$Callback",
+      "android/support/design/widget/Snackbar$SnackbarLayout": "androidx/design/widget/Snackbar$SnackbarLayout",
+      "android/support/design/widget/SnackbarManager$1": "androidx/design/widget/SnackbarManager$1",
+      "android/support/design/widget/SnackbarManager$SnackbarRecord": "androidx/design/widget/SnackbarManager$SnackbarRecord",
+      "android/support/design/widget/StateListAnimator$1": "androidx/design/widget/StateListAnimator$1",
+      "android/support/design/widget/StateListAnimator$Tuple": "androidx/design/widget/StateListAnimator$Tuple",
+      "android/support/design/widget/SwipeDismissBehavior$1": "androidx/design/widget/SwipeDismissBehavior$1",
+      "android/support/design/widget/SwipeDismissBehavior$SettleRunnable": "androidx/design/widget/SwipeDismissBehavior$SettleRunnable",
+      "android/support/design/widget/SwipeDismissBehavior$SwipeDirection": "androidx/design/widget/SwipeDismissBehavior$SwipeDirection",
+      "android/support/design/widget/TabItem": "androidx/design/widget/TabItem",
+      "android/support/design/widget/TabLayout$1": "androidx/design/widget/TabLayout$1",
+      "android/support/design/widget/TabLayout": "androidx/design/widget/TabLayout",
+      "android/support/design/widget/TabLayout$AdapterChangeListener": "androidx/design/widget/TabLayout$AdapterChangeListener",
+      "android/support/design/widget/TabLayout$Mode": "androidx/design/widget/TabLayout$Mode",
+      "android/support/design/widget/TabLayout$OnTabSelectedListener": "androidx/design/widget/TabLayout$OnTabSelectedListener",
+      "android/support/design/widget/TabLayout$Tab": "androidx/design/widget/TabLayout$Tab",
+      "android/support/design/widget/TabLayout$PagerAdapterObserver": "androidx/design/widget/TabLayout$PagerAdapterObserver",
+      "android/support/design/widget/TabLayout$SlidingTabStrip$1": "androidx/design/widget/TabLayout$SlidingTabStrip$1",
+      "android/support/design/widget/TabLayout$SlidingTabStrip": "androidx/design/widget/TabLayout$SlidingTabStrip",
+      "android/support/design/widget/TabLayout$SlidingTabStrip$2": "androidx/design/widget/TabLayout$SlidingTabStrip$2",
+      "android/support/design/widget/TabLayout$TabView": "androidx/design/widget/TabLayout$TabView",
+      "android/support/design/widget/TabLayout$TabGravity": "androidx/design/widget/TabLayout$TabGravity",
+      "android/support/design/widget/TabLayout$TabLayoutOnPageChangeListener": "androidx/design/widget/TabLayout$TabLayoutOnPageChangeListener",
+      "android/support/design/widget/TabLayout$ViewPagerOnTabSelectedListener": "androidx/design/widget/TabLayout$ViewPagerOnTabSelectedListener",
+      "android/support/design/widget/TextInputEditText": "androidx/design/widget/TextInputEditText",
+      "android/support/design/widget/TextInputLayout$1": "androidx/design/widget/TextInputLayout$1",
+      "android/support/design/widget/TextInputLayout": "androidx/design/widget/TextInputLayout",
+      "android/support/design/widget/TextInputLayout$2": "androidx/design/widget/TextInputLayout$2",
+      "android/support/design/widget/TextInputLayout$3": "androidx/design/widget/TextInputLayout$3",
+      "android/support/design/widget/TextInputLayout$4": "androidx/design/widget/TextInputLayout$4",
+      "android/support/design/widget/TextInputLayout$5": "androidx/design/widget/TextInputLayout$5",
+      "android/support/design/widget/TextInputLayout$SavedState$1": "androidx/design/widget/TextInputLayout$SavedState$1",
+      "android/support/design/widget/TextInputLayout$SavedState": "androidx/design/widget/TextInputLayout$SavedState",
+      "android/support/design/widget/TextInputLayout$TextInputAccessibilityDelegate": "androidx/design/widget/TextInputLayout$TextInputAccessibilityDelegate",
+      "android/support/design/R$string": "androidx/design/R$string",
+      "android/support/design/R$integer": "androidx/design/R$integer",
+      "android/support/text/emoji/bundled/BundledEmojiCompatConfig$1": "androidx/text/emoji/bundled/BundledEmojiCompatConfig$1",
+      "android/support/text/emoji/bundled/BundledEmojiCompatConfig": "androidx/text/emoji/bundled/BundledEmojiCompatConfig",
+      "android/support/text/emoji/bundled/BundledEmojiCompatConfig$BundledMetadataLoader": "androidx/text/emoji/bundled/BundledEmojiCompatConfig$BundledMetadataLoader",
+      "android/support/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable": "androidx/text/emoji/bundled/BundledEmojiCompatConfig$InitRunnable",
+      "android/arch/lifecycle/AndroidViewModel": "androidx/lifecycle/AndroidViewModel",
+      "android/arch/lifecycle/ViewModel": "androidx/lifecycle/ViewModel",
+      "android/arch/lifecycle/ViewModelProvider$NewInstanceFactory": "androidx/lifecycle/ViewModelProvider$NewInstanceFactory",
+      "android/arch/persistence/room/ForeignKey": "androidx/persistence/room/ForeignKey",
+      "android/arch/persistence/room/ForeignKey$Action": "androidx/persistence/room/ForeignKey$Action",
+      "android/arch/persistence/room/OnConflictStrategy": "androidx/persistence/room/OnConflictStrategy",
+      "android/arch/persistence/room/Index": "androidx/persistence/room/Index",
+      "android/arch/persistence/room/ColumnInfo$Collate": "androidx/persistence/room/ColumnInfo$Collate",
+      "android/arch/persistence/room/RoomWarnings": "androidx/persistence/room/RoomWarnings",
+      "android/support/v4/app/NotificationCompat$Action$SemanticAction": "androidx/app/NotificationCompat$Action$SemanticAction",
+      "android/support/v4/graphics/TypefaceCompatApi28Impl": "androidx/graphics/TypefaceCompatApi28Impl",
+      "android/support/v7/util/AdapterListUpdateCallback": "androidx/widget/recyclerview/AdapterListUpdateCallback",
+      "android/support/v7/recyclerview/extensions/ListAdapterConfig$Builder$MainThreadExecutor": "androidx/widget/recyclerview/ListAdapterConfig$Builder$MainThreadExecutor"
     }
   },
   "proGuardMap": {
-    "rules": {}
+    "rules": {
+      "android/support/transition/ChangeBounds$*": "androidx/transition/ChangeBounds$*",
+      "android/support/graphics/drawable/VectorDrawableCompat$*": "androidx/graphics/drawable/VectorDrawableCompat$*"
+    }
   }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/ChangeDetectionTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/ChangeDetectionTest.kt
new file mode 100644
index 0000000..1eeabdc
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/ChangeDetectionTest.kt
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.tools.jetifier.core
+
+import android.support.tools.jetifier.core.archive.Archive
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.RewriteRule
+import android.support.tools.jetifier.core.transform.PackageMap
+import android.support.tools.jetifier.core.transform.pom.PomDependency
+import android.support.tools.jetifier.core.transform.pom.PomRewriteRule
+import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
+import com.google.common.truth.Truth
+import org.junit.Test
+import java.io.File
+import java.nio.file.Files
+import java.nio.file.Paths
+
+/**
+ * Tests that transformed artifacts are properly marked as changed / unchanged base on whether there
+ * was something to rewrite or not.
+ */
+class ChangeDetectionTest {
+    private val emptyConfig = Config(
+        restrictToPackagePrefixes = emptyList(),
+        rewriteRules = emptyList(),
+        slRules = emptyList(),
+        pomRewriteRules = emptyList(),
+        typesMap = TypesMap.EMPTY,
+        proGuardMap = ProGuardTypesMap.EMPTY,
+        packageMap = PackageMap.EMPTY
+    )
+
+    private val prefRewriteConfig = Config(
+        restrictToPackagePrefixes = listOf("android/support/v7/preference"),
+        rewriteRules =
+        listOf(
+            RewriteRule(from = "android/support/v7/preference/Preference(.+)", to = "ignore"),
+            RewriteRule(from = "(.*)/R(.*)", to = "ignore")
+        ),
+        slRules = emptyList(),
+        pomRewriteRules = listOf(
+            PomRewriteRule(
+                PomDependency(
+                    groupId = "supportGroup", artifactId = "supportArtifact", version = "4.0"),
+                listOf(
+                    PomDependency(
+                        groupId = "testGroup", artifactId = "testArtifact", version = "1.0")
+                )
+        )),
+        typesMap = TypesMap(mapOf(
+            JavaType("android/support/v7/preference/Preference")
+                to JavaType("android/test/pref/Preference")
+        )),
+        proGuardMap = ProGuardTypesMap.EMPTY,
+        packageMap = PackageMap.EMPTY
+    )
+
+    @Test
+    fun xmlRewrite_archiveChanged() {
+        testChange(
+            config = prefRewriteConfig,
+            fileContent =
+                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+                "<android.support.v7.preference.Preference/>",
+            fileName = "test.xml",
+            areChangesExpected = true
+        )
+    }
+
+    @Test
+    fun xmlRewrite_archiveNotChanged() {
+        testChange(
+            config = emptyConfig,
+            fileContent =
+                "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+                "<android.support.v7.preference.Preference/>",
+            fileName = "test.xml",
+            areChangesExpected = false
+        )
+    }
+
+    @Test
+    fun proGuard_archiveChanged() {
+        testChange(
+            config = prefRewriteConfig,
+            fileContent =
+                "-keep public class * extends android.support.v7.preference.Preference { \n" +
+                "  <fields>; \n" +
+                "}",
+            fileName = "proguard.txt",
+            areChangesExpected = true
+        )
+    }
+
+    @Test
+    fun proGuard_archiveNotChanged() {
+        testChange(
+            config = emptyConfig,
+            fileContent =
+                "-keep public class * extends android.support.v7.preference.Preference { \n" +
+                "  <fields>; \n" +
+                "}",
+            fileName = "test.xml",
+            areChangesExpected = false
+        )
+    }
+
+    @Test
+    fun pom_archiveChanged() {
+        testChange(
+            config = prefRewriteConfig,
+            fileContent =
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" " +
+                "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
+                "  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0" +
+                "  http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+                "  <dependencies>\n" +
+                "    <dependency>\n" +
+                "      <groupId>supportGroup</groupId>\n" +
+                "      <artifactId>supportArtifact</artifactId>\n" +
+                "      <version>4.0</version>\n" +
+                "    </dependency>\n" +
+                "  </dependencies>" +
+                "</project>\n",
+            fileName = "pom.xml",
+            areChangesExpected = true
+        )
+    }
+
+    @Test
+    fun pom_archiveNotChanged() {
+        testChange(
+            config = emptyConfig,
+            fileContent =
+                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+                "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" " +
+                "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
+                "  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0" +
+                "  http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
+                "  <dependencies>\n" +
+                "    <dependency>\n" +
+                "      <groupId>supportGroup</groupId>\n" +
+                "      <artifactId>supportArtifact</artifactId>\n" +
+                "      <version>4.0</version>\n" +
+                "    </dependency>\n" +
+                "  </dependencies>" +
+                "</project>\n",
+            fileName = "pom.xml",
+            areChangesExpected = true
+        )
+    }
+
+    @Test
+    fun javaClass_archiveChanged() {
+        val inputClassPath = "/changeDetectionTest/testPreference.class"
+        val inputFile = File(javaClass.getResource(inputClassPath).file)
+
+        testChange(
+            config = prefRewriteConfig,
+            file = ArchiveFile(Paths.get("/", "preference.class"), inputFile.readBytes()),
+            areChangesExpected = true
+        )
+    }
+
+    @Test
+    fun javaClass_archiveNotChanged() {
+        val inputClassPath = "/changeDetectionTest/testPreference.class"
+        val inputFile = File(javaClass.getResource(inputClassPath).file)
+
+        testChange(
+            config = emptyConfig,
+            file = ArchiveFile(Paths.get("/", "preference.class"), inputFile.readBytes()),
+            areChangesExpected = false
+        )
+    }
+
+    private fun testChange(
+        config: Config,
+        fileContent: String,
+        fileName: String,
+        areChangesExpected: Boolean
+    ) {
+        testChange(
+            config = config,
+            file = ArchiveFile(Paths.get("/", fileName), fileContent.toByteArray()),
+            areChangesExpected = areChangesExpected)
+    }
+
+    /**
+     * Runs the whole transformation process over the given file and verifies if the parent
+     * artifacts was properly marked as changed / unchanged base on [areChangesExpected] param.
+     */
+    private fun testChange(
+        config: Config,
+        file: ArchiveFile,
+        areChangesExpected: Boolean
+    ) {
+        val archive = Archive(Paths.get("some/path"), listOf(file))
+        val sourceArchive = archive.writeSelfToFile(Files.createTempFile("test", ".zip"))
+
+        val expectedFileIfRefactored = Files.createTempFile("testRefactored", ".zip")
+        val processor = Processor.createProcessor(config)
+        val resultFiles = processor.transform(
+            setOf(sourceArchive),
+            outputPath = expectedFileIfRefactored,
+            outputIsDir = false,
+            copyUnmodifiedLibsAlso = false)
+
+        if (areChangesExpected) {
+            Truth.assertThat(resultFiles).containsExactly(expectedFileIfRefactored.toFile())
+        } else {
+            Truth.assertThat(resultFiles).containsExactly(sourceArchive)
+        }
+    }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/config/ConfigParserTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/config/ConfigParserTest.kt
index 4a03ef3..97cfc2f 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/config/ConfigParserTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/config/ConfigParserTest.kt
@@ -44,7 +44,12 @@
                 "                {groupId: \"g\", artifactId: \"a\", version: \"2.0\"} \n" +
                 "            ]\n" +
                 "        }\n" +
-                "    ]\n" +
+                "    ],\n" +
+                "   proGuardMap: {\n" +
+                "       rules: {\n" +
+                "           \"android/support/**\": \"androidx/**\"\n" +
+                "       }\n" +
+                "    }" +
                 "}"
 
         val config = ConfigParser.parseFromString(confStr)
@@ -52,6 +57,7 @@
         Truth.assertThat(config).isNotNull()
         Truth.assertThat(config!!.restrictToPackagePrefixes[0]).isEqualTo("android/support/")
         Truth.assertThat(config.rewriteRules.size).isEqualTo(2)
+        Truth.assertThat(config.proGuardMap.rules.size).isEqualTo(1)
     }
 }
 
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/map/MapGenerationTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/map/MapGenerationTest.kt
index ecf9ccf..6f4eb59 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/map/MapGenerationTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/map/MapGenerationTest.kt
@@ -17,7 +17,6 @@
 package android.support.tools.jetifier.core.map
 
 import android.support.tools.jetifier.core.config.Config
-import android.support.tools.jetifier.core.rules.JavaField
 import android.support.tools.jetifier.core.rules.JavaType
 import android.support.tools.jetifier.core.rules.RewriteRule
 import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
@@ -40,8 +39,6 @@
             .mapInto(
                 types = mapOf(
                     "android/support/v7/pref/Preference" to "android/test/pref/Preference"
-                ),
-                fields = mapOf(
                 )
             )
             .andIsComplete()
@@ -63,8 +60,6 @@
             .mapInto(
                 types = mapOf(
                     "android/support/v7/pref/Preference" to "android/test/pref/Preference"
-                ),
-                fields = mapOf(
                 )
             )
             .andIsComplete()
@@ -89,8 +84,6 @@
                     "android/support/v7/pref/Preference" to "android/test/pref/Preference",
                     "android/support/v14/pref/PreferenceDialog"
                         to "android/test/pref/PreferenceDialog"
-                ),
-                fields = mapOf(
                 )
             )
             .andIsComplete()
@@ -114,166 +107,16 @@
                     "android/support/v7/pref/Preference" to "android/fallback/v7/pref/Preference",
                     "android/support/v14/pref/PreferenceDialog"
                         to "android/test/pref/PreferenceDialog"
-                ),
-                fields = mapOf(
                 )
             )
             .andIsComplete()
     }
 
-    @Test fun mapTwoFields_usingOneTypeRule() {
-        ScanTester
-            .testThatRules(
-                RewriteRule("android/support/v7/(.*)", "android/test/{0}")
-            )
-            .withAllowedPrefixes(
-                "android/support/"
-            )
-            .forGivenFields(
-                JavaField("android/support/v7/pref/Preference", "count"),
-                JavaField("android/support/v7/pref/Preference", "min")
-            )
-            .mapInto(
-                types = mapOf(
-                ),
-                fields = mapOf(
-                    "android/support/v7/pref/Preference" to mapOf(
-                        "android/test/pref/Preference" to listOf(
-                            "count",
-                            "min"
-                        )
-                    )
-                )
-            )
-            .andIsComplete()
-    }
-
-    @Test fun mapFieldInInnerClass_usingOneTypeRule() {
-        ScanTester
-            .testThatRules(
-                RewriteRule("android/support/v7/(.*)", "android/test/{0}")
-            )
-            .withAllowedPrefixes(
-                "android/support/"
-            )
-            .forGivenFields(
-                JavaField("android/support/v7/pref/R\$attr", "border")
-            )
-            .mapInto(
-                types = mapOf(
-                ),
-                fields = mapOf(
-                    "android/support/v7/pref/R\$attr" to mapOf(
-                        "android/test/pref/R\$attr" to listOf(
-                            "border"
-                        )
-                    )
-                )
-            )
-            .andIsComplete()
-    }
-
-    @Test fun mapPrivateFields_shouldIgnore() {
-        ScanTester
-            .testThatRules(
-                RewriteRule("android/support/v7/(.*)", "android/test/{0}")
-            )
-            .withAllowedPrefixes(
-                "android/support/"
-            )
-            .forGivenFields(
-                JavaField("android/support/v7/pref/Preference", "mCount"),
-                JavaField("android/support/v7/pref/Preference", "this$0")
-            )
-            .mapInto(
-                types = mapOf(
-                ),
-                fields = mapOf(
-                )
-            )
-            .andIsComplete()
-    }
-
-    @Test fun mapType_usingFieldSelector_shouldNotApply() {
-        ScanTester
-            .testThatRules(
-                RewriteRule("android/support/v7/(.*)", "android/test/{0}", listOf("count"))
-            )
-            .withAllowedPrefixes(
-                "android/support/"
-            )
-            .forGivenTypes(
-                JavaType("android/support/v7/pref/Preference")
-            )
-            .mapInto(
-                types = mapOf(
-                    "android/support/v7/pref/Preference" to "android/support/v7/pref/Preference"
-                ),
-                fields = mapOf(
-                )
-            )
-            .andIsNotComplete()
-    }
-
-    @Test fun mapField_noApplicableRule() {
-        ScanTester
-            .testThatRules(
-                RewriteRule("android/support/v7/(.*)", "android/test/{0}", listOf("count2"))
-            )
-            .withAllowedPrefixes(
-                "android/support/"
-            )
-            .forGivenFields(
-                JavaField("android/support/v7/pref/Preference", "count")
-            )
-            .mapInto(
-                types = mapOf(
-                ),
-                fields = mapOf(
-                    "android/support/v7/pref/Preference" to mapOf(
-                        "android/support/v7/pref/Preference" to listOf(
-                            "count"
-                        )
-                    )
-                )
-            )
-            .andIsNotComplete()
-    }
-
-    @Test fun mapTwoFields_usingTwoFieldsSelectors() {
-        ScanTester
-            .testThatRules(
-                RewriteRule("android/support/v7/(.*)", "android/test/{0}", listOf("count")),
-                RewriteRule("android/support/v7/(.*)", "android/test2/{0}", listOf("size"))
-            )
-            .withAllowedPrefixes(
-                "android/support/"
-            )
-            .forGivenFields(
-                JavaField("android/support/v7/pref/Preference", "count"),
-                JavaField("android/support/v7/pref/Preference", "size")
-            )
-            .mapInto(
-                types = mapOf(
-                ),
-                fields = mapOf(
-                    "android/support/v7/pref/Preference" to mapOf(
-                        "android/test/pref/Preference" to listOf(
-                            "count"
-                        ),
-                        "android/test2/pref/Preference" to listOf(
-                            "size"
-                        )
-                    )
-                )
-            )
-            .andIsComplete()
-    }
-
-    @Test fun mapTwoTypes_shouldIgnoreOne() {
+    @Test fun mapTwoTypes_shouldIgnoreFirstTwo() {
         ScanTester
             .testThatRules(
                 RewriteRule("android/support/v7/(.*)", "ignore"),
+                RewriteRule("android/support/v8/(.*)", "ignoreInPreprocessorOnly"),
                 RewriteRule("android/support/v14/(.*)", "android/test/{0}")
             )
             .withAllowedPrefixes(
@@ -281,40 +124,12 @@
             )
             .forGivenTypes(
                 JavaType("android/support/v7/pref/Preference"),
+                JavaType("android/support/v8/pref/Preference"),
                 JavaType("android/support/v14/pref/Preference")
             )
             .mapInto(
                 types = mapOf(
                     "android/support/v14/pref/Preference" to "android/test/pref/Preference"
-                ),
-                fields = mapOf(
-                )
-            )
-            .andIsComplete()
-    }
-
-    @Test fun mapTwoFields_shouldIgnoreOne() {
-        ScanTester
-            .testThatRules(
-                RewriteRule("android/support/v7/(.*)", "ignore"),
-                RewriteRule("android/support/v14/(.*)", "android/test/{0}")
-            )
-            .withAllowedPrefixes(
-                "android/support/"
-            )
-            .forGivenFields(
-                JavaField("android/support/v7/pref/Preference", "count"),
-                JavaField("android/support/v14/pref/Preference", "size")
-            )
-            .mapInto(
-                types = mapOf(
-                ),
-                fields = mapOf(
-                    "android/support/v14/pref/Preference" to mapOf(
-                        "android/test/pref/Preference" to listOf(
-                            "size"
-                        )
-                    )
                 )
             )
             .andIsComplete()
@@ -333,7 +148,6 @@
             class Step2(private val rules: List<RewriteRule>, private val prefixes: List<String>) {
 
                 private val allTypes: MutableList<JavaType> = mutableListOf()
-                private val allFields: MutableList<JavaField> = mutableListOf()
                 private var wasMapIncomplete = false
 
 
@@ -342,29 +156,23 @@
                     return this
                 }
 
-                fun forGivenFields(vararg fields: JavaField): Step2 {
-                    allFields.addAll(fields)
-                    return this
-                }
 
-                fun mapInto(types: Map<String, String>,
-                            fields: Map<String, Map<String, List<String>>>): Step2 {
+                fun mapInto(types: Map<String, String>): Step2 {
                     val config = Config(
                         restrictToPackagePrefixes = prefixes,
                         rewriteRules = rules,
+                        slRules = emptyList(),
                         pomRewriteRules = emptyList(),
                         typesMap = TypesMap.EMPTY,
                         proGuardMap = ProGuardTypesMap.EMPTY)
                     val scanner = MapGeneratorRemapper(config)
 
                     allTypes.forEach { scanner.rewriteType(it) }
-                    allFields.forEach { scanner.rewriteField(it) }
 
                     val typesMap = scanner.createTypesMap().toJson()
                     wasMapIncomplete = scanner.isMapNotComplete
 
                     Truth.assertThat(typesMap.types).containsExactlyEntriesIn(types)
-                    Truth.assertThat(typesMap.fields).containsExactlyEntriesIn(fields)
                     return this
                 }
 
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/RewriteRuleTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/RewriteRuleTest.kt
index 298d46c..ebb48dd 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/RewriteRuleTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/RewriteRuleTest.kt
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2017 The Android Open Source Project
  *
@@ -16,13 +17,11 @@
 
 package android.support.tools.jetifier.core.transform
 
-import android.support.tools.jetifier.core.rules.JavaField
 import android.support.tools.jetifier.core.rules.JavaType
 import android.support.tools.jetifier.core.rules.RewriteRule
 import com.google.common.truth.Truth
 import org.junit.Test
 
-
 class RewriteRuleTest {
 
     @Test fun noRegEx_shouldRewrite() {
@@ -53,14 +52,6 @@
             .into("A/C\$D")
     }
 
-    @Test fun fieldRule_noRegEx_shouldRewrite() {
-        RuleTester
-            .testThatRule("A/B", "A/C")
-            .withFieldSelector("MyField")
-            .rewritesField("A/B", "MyField")
-            .into("A/C", "MyField")
-    }
-
     @Test fun fieldRule_innerClass_groupRegEx_shouldRewrite() {
         RuleTester
             .testThatRule("A/B$(.*)", "A/C\${0}")
@@ -68,13 +59,19 @@
             .into("A/C\$D")
     }
 
-    @Test fun noFieldRule_shouldRewriteEvenWithField() {
+    @Test fun typeRewrite_ignore() {
         RuleTester
-            .testThatRule("A/B", "A/C")
-            .rewritesField("A/B", "test")
-            .into("A/C", "test")
+            .testThatRule("A/B", "ignore")
+            .rewritesType("A/B")
+            .isIgnored()
     }
 
+    @Test fun typeRewrite_ignoreInPreprocessor() {
+        RuleTester
+            .testThatRule("A/B", "ignoreInPreprocessorOnly")
+            .rewritesType("A/B")
+            .isIgnored()
+    }
 
     object RuleTester {
 
@@ -82,53 +79,31 @@
 
         class RuleTesterStep1(val from: String, val to: String) {
 
-            val fieldSelectors: MutableList<String> = mutableListOf()
-
-            fun withFieldSelector(input: String): RuleTesterStep1 {
-                fieldSelectors.add(input)
-                return this
-            }
-
-            fun rewritesField(inputType: String, inputField: String)
-                    = RuleTesterFinalFieldStep(from, to, inputType, inputField, fieldSelectors)
-
             fun rewritesType(inputType: String)
-                    = RuleTesterFinalTypeStep(from, to, inputType, fieldSelectors)
-        }
-
-        class RuleTesterFinalFieldStep(val fromType: String,
-                                       val toType: String,
-                                       val inputType: String,
-                                       val inputField: String,
-                                       val fieldSelectors: List<String>) {
-
-            fun into(expectedTypeName: String, expectedFieldName: String) {
-                val fieldRule = RewriteRule(fromType, toType, fieldSelectors)
-                val result = fieldRule.apply(JavaField(inputType, inputField))
-                Truth.assertThat(result).isNotNull()
-
-                Truth.assertThat(result.result!!.owner.fullName).isEqualTo(expectedTypeName)
-                Truth.assertThat(result.result!!.name).isEqualTo(expectedFieldName)
-            }
-
+                    = RuleTesterFinalTypeStep(from, to, inputType)
         }
 
         class RuleTesterFinalTypeStep(val fromType: String,
                                       val toType: String,
-                                      val inputType: String,
-                                      val fieldSelectors: List<String>) {
+                                      val inputType: String) {
 
             fun into(expectedResult: String) {
-                val fieldRule = RewriteRule(fromType, toType, fieldSelectors)
+                val fieldRule = RewriteRule(fromType, toType)
                 val result = fieldRule.apply(JavaType(inputType))
-                Truth.assertThat(result).isNotNull()
 
                 Truth.assertThat(result).isNotNull()
                 Truth.assertThat(result.result!!.fullName).isEqualTo(expectedResult)
             }
 
-        }
-    }
+            fun isIgnored() {
+                val fieldRule = RewriteRule(fromType, toType)
+                val result = fieldRule.apply(JavaType(inputType))
 
+                Truth.assertThat(result).isNotNull()
+                Truth.assertThat(result.isIgnored).isTrue()
+            }
+        }
+
+    }
 }
 
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/bytecode/ClassFilesMoveTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/bytecode/ClassFilesMoveTest.kt
new file mode 100644
index 0000000..6876976
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/bytecode/ClassFilesMoveTest.kt
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.tools.jetifier.core.transform.bytecode
+
+import android.support.tools.jetifier.core.Processor
+import android.support.tools.jetifier.core.archive.Archive
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.archive.ArchiveItemVisitor
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.RewriteRule
+import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
+import com.google.common.truth.Truth
+import org.junit.Test
+import java.io.File
+
+/**
+ * Tests that individual files were moved properly due to their owner types rewrites.
+ */
+class ClassFilesMoveTest {
+
+    companion object {
+        private val TEST_CONFIG = Config(
+            restrictToPackagePrefixes = listOf("android/support"),
+            rewriteRules = listOf(
+                RewriteRule("android/support/annotation/(.*)", "ignore"),
+                RewriteRule("android/support/v7/preference/R(.*)", "ignore"),
+                RewriteRule("android/support/v4/(.*)", "ignore")
+            ),
+            slRules = listOf(
+                RewriteRule("android/support/annotation/(.*)", "ignore"),
+                RewriteRule("android/support/v7/preference/R(.*)", "ignore"),
+                RewriteRule("android/support/v4/(.*)", "ignore")
+            ),
+            pomRewriteRules = emptyList(),
+            typesMap = TypesMap(mapOf(
+                "android/support/v7/preference/Preference"
+                    to "androidx/support/preference/Preference",
+                "android/support/v7/preference/Preference\$1"
+                    to "androidx/support/preference/Preference\$1",
+                "android/support/v7/preference/TwoStatePreference"
+                    to "androidx/support/preference/TwoStatePreference",
+                "android/support/v7/preference/PreferenceGroup"
+                    to "androidx/support/preference/PreferenceGroup",
+                "android/support/v7/preference/Preference\$OnPreferenceChangeListener"
+                    to "androidx/support/preference/Preference\$OnPreferenceChangeListener",
+                "android/support/v7/preference/Preference\$OnPreferenceClickListener"
+                    to "androidx/support/preference/Preference\$OnPreferenceClickListener",
+                "android/support/v7/preference/Preference\$OnPreferenceChangeInternalListener"
+                    to "androidx/support/preference/Preference\$OnPreferenceChangeInternalListener",
+                "android/support/v7/preference/PreferenceManager\$OnPreferenceTreeClickListener"
+                    to "androidx/support/preference/PreferenceManager\$OnPreferenceTreeClickLisnr",
+                "android/support/v7/preference/PreferenceViewHolder"
+                    to "androidx/support/preference/PreferenceViewHolder",
+                "android/support/v7/preference/PreferenceManager"
+                    to "androidx/support/preference/PreferenceManager",
+                "android/support/v14/preference/SwitchPreference"
+                    to "androidx/support/preference/SwitchPreference",
+                "android/support/v14/preference/SwitchPreference\$1"
+                    to "androidx/support/preference/SwitchPreference\$1",
+                "android/support/v14/preference/SwitchPreference\$Listener"
+                    to "androidx/support/preference/SwitchPreference\$Listener",
+                "android/support/v7/preference/PreferenceDataStore"
+                    to "androidx/support/preference/PreferenceDataStore",
+                "android/support/v7/preference/Preference\$BaseSavedState"
+                    to "androidx/support/preference/Preference\$BaseSavedState"
+            ).map { JavaType(it.key) to JavaType(it.value) }.toMap()),
+            proGuardMap = ProGuardTypesMap.EMPTY
+        )
+    }
+
+    /**
+     * Tests that after rewrite of a input archive the internal classes are properly moved to new
+     * locations (based on the rewrite rules) which is compared with the expected archive.
+     *
+     * Note: The expected archive does not contain rewritten classes - they were only manually
+     * moved. Which is fine because this test validates only files locations.
+     *
+     * Note: This runs in support library rewrite mode which allows to move classes around.
+     */
+    @Test fun fileMove_forwardRewrite_shouldMoveFilesProperly() {
+        val inputZipPath = "/fileRenameTest/inputTestLib.zip"
+        val expectedZipPath = "/fileRenameTest/expectedTestLib.zip"
+
+        val processor = Processor.createProcessor(TEST_CONFIG, rewritingSupportLib = true)
+        val inputFile = File(javaClass.getResource(inputZipPath).file)
+
+        val tempDir = createTempDir()
+        val resultFiles = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+
+        Truth.assertThat(resultFiles).hasSize(1)
+        testArchivesAreSame(resultFiles.first(),
+            File(javaClass.getResource(expectedZipPath).file))
+
+        tempDir.delete()
+    }
+
+    /**
+     * Does exactly the same as [fileMove_forwardRewrite_nestedArchive_shouldMoveFilesProperly] but
+     * the files are in a nested archive e.g. archive.zip/classes.jar/some files.
+     */
+    @Test fun fileMove_forwardRewrite_nestedArchive_shouldMoveFilesProperly() {
+        val inputZipPath = "/fileRenameTest/inputTestLibNested.zip"
+        val expectedZipPath = "/fileRenameTest/expectedTestLibNested.zip"
+
+        val processor = Processor.createProcessor(TEST_CONFIG, rewritingSupportLib = true)
+        val inputFile = File(javaClass.getResource(inputZipPath).file)
+
+        val tempDir = createTempDir()
+        val resultFiles = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+
+        Truth.assertThat(resultFiles).hasSize(1)
+        testArchivesAreSame(resultFiles.first(),
+            File(javaClass.getResource(expectedZipPath).file))
+
+        tempDir.delete()
+    }
+
+    /**
+     * Rewrites the input archive and then applies reversed mode to rewrite it back. The final
+     * produced archive has to have the same directory structure as the input one.
+     *
+     * Note: This runs in support library rewrite mode which allows to move classes around.
+     */
+    @Test fun fileMove_forwardRewrite_backwardsRewrite_shouldKeepFilesProperly() {
+        val inputZipPath = "/fileRenameTest/inputTestLib.zip"
+
+        // Transform forward
+        val processor = Processor.createProcessor(TEST_CONFIG,
+            rewritingSupportLib = true)
+        val inputFile = File(javaClass.getResource(inputZipPath).file)
+        val tempDir = createTempDir()
+        val resultFiles = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+
+        // Take previous result & reverse it
+        val processor2 = Processor.createProcessor(TEST_CONFIG,
+            rewritingSupportLib = true,
+            reversedMode = true)
+        val resultFiles2 = processor2.transform(setOf(resultFiles.first()), tempDir.toPath(), true)
+
+        testArchivesAreSame(resultFiles2.first(),
+            File(javaClass.getResource(inputZipPath).file))
+
+        tempDir.delete()
+    }
+
+    /**
+     * Runs the rewrite but with support library rewrite mode off which means that none of the files
+     * should be moved.
+     */
+    @Test fun fileMove_forwardRewrite_noSupportLibMode_noFilesMove() {
+        val inputZipPath = "/fileRenameTest/inputTestLib.zip"
+
+        val processor = Processor.createProcessor(TEST_CONFIG, rewritingSupportLib = false)
+        val inputFile = File(javaClass.getResource(inputZipPath).file)
+
+        val tempDir = createTempDir()
+        val resultFiles = processor.transform(setOf(inputFile), tempDir.toPath(), true)
+
+        Truth.assertThat(resultFiles).hasSize(1)
+        testArchivesAreSame(resultFiles.first(),
+            File(javaClass.getResource(inputZipPath).file))
+
+        tempDir.delete()
+    }
+
+    fun testArchivesAreSame(givenZip: File, expectedZip: File) {
+        testArchivesAreSame(Archive.Builder.extract(givenZip), Archive.Builder.extract(expectedZip))
+    }
+
+    fun testArchivesAreSame(givenZip: Archive, expectedZip: Archive) {
+        val givenFiles = ArchiveBrowser.grabAllPathsIn(givenZip)
+        val expectedFiles = ArchiveBrowser.grabAllPathsIn(expectedZip)
+        Truth.assertThat(givenFiles).containsExactlyElementsIn(expectedFiles)
+    }
+
+    /**
+     * Just a helper utility to get all file paths in the archive.
+     */
+    class ArchiveBrowser : ArchiveItemVisitor {
+
+        companion object {
+            fun grabAllPathsIn(archive: Archive): MutableSet<String> {
+                val grabber = ArchiveBrowser()
+                archive.accept(grabber)
+                return grabber.allPaths
+            }
+        }
+
+        val allPaths = mutableSetOf<String>()
+
+        override fun visit(archiveFile: ArchiveFile) {
+            allPaths.add(archiveFile.relativePath.toString())
+            println("Visited ${archiveFile.relativePath}")
+        }
+
+        override fun visit(archive: Archive) {
+            archive.files.forEach { it.accept(this) }
+        }
+    }
+}
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/metainf/MetaInfTransformerTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/metainf/MetaInfTransformerTest.kt
new file mode 100644
index 0000000..db6cd21
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/metainf/MetaInfTransformerTest.kt
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.support.tools.jetifier.core.transform.metainf
+
+import android.support.tools.jetifier.core.archive.ArchiveFile
+import android.support.tools.jetifier.core.config.Config
+import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.transform.PackageMap
+import android.support.tools.jetifier.core.transform.TransformationContext
+import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
+import com.google.common.truth.Truth
+import org.junit.Test
+import java.nio.charset.Charset
+import java.nio.file.Path
+import java.nio.file.Paths
+
+class MetaInfTransformerTest {
+
+    @Test
+    fun rewriteVersion_forward() {
+        testRewrite(
+            given = "28.0.0-SNAPSHOT",
+            expected = "1.0.0-SNAPSHOT",
+            filePath = Paths.get("something/META-INF", "support_preference-v7.version"),
+            reverseMode = false
+        )
+    }
+
+    @Test
+    fun rewriteVersion_reversed() {
+        testRewrite(
+            given = "1.0.0-SNAPSHOT",
+            expected = "28.0.0-SNAPSHOT",
+            filePath = Paths.get("something/META-INF", "support_preference-v7.version"),
+            reverseMode = true
+        )
+    }
+
+    @Test
+    fun rewriteVersion_notSLRewrite_shouldSkip() {
+        testRewrite(
+            given = "28.0.0-SNAPSHOT",
+            expected = "28.0.0-SNAPSHOT",
+            filePath = Paths.get("something/META-INF", "support_preference-v7.version"),
+            reverseMode = false,
+            rewritingSupportLib = false,
+            expectedCanTransform = false
+        )
+    }
+
+    @Test
+    fun rewriteVersion_notMatchingVersion_shouldNoOp() {
+        testRewrite(
+            given = "test",
+            expected = "test",
+            filePath = Paths.get("something/META-INF", "support_preference-v7.version")
+        )
+    }
+
+    @Test
+    fun rewriteVersion_notValidSuffix_shouldSkip() {
+        testRewrite(
+            given = "28.0.0-SNAPSHOT",
+            expected = "28.0.0-SNAPSHOT",
+            filePath = Paths.get("something/META-INF", "support_preference-v7.none"),
+            expectedCanTransform = false
+        )
+    }
+
+    @Test
+    fun rewriteVersion_notInMetaInfDir_shouldSkip() {
+        testRewrite(
+            given = "28.0.0-SNAPSHOT",
+            expected = "28.0.0-SNAPSHOT",
+            filePath = Paths.get("something/else", "support_preference-v7.version"),
+            expectedCanTransform = false
+        )
+    }
+
+    private fun testRewrite(
+        given: String,
+        expected: String,
+        filePath: Path,
+        reverseMode: Boolean = false,
+        expectedCanTransform: Boolean = true,
+        rewritingSupportLib: Boolean = true
+    ) {
+        val config = Config(
+            restrictToPackagePrefixes = emptyList(),
+            rewriteRules = emptyList(),
+            slRules = emptyList(),
+            pomRewriteRules = emptyList(),
+            packageMap = PackageMap.EMPTY,
+            typesMap = TypesMap.EMPTY,
+            proGuardMap = ProGuardTypesMap.EMPTY
+        )
+        val context = TransformationContext(config,
+            rewritingSupportLib = rewritingSupportLib,
+            isInReversedMode = reverseMode)
+        val transformer = MetaInfTransformer(context)
+
+        val file = ArchiveFile(filePath, given.toByteArray())
+
+        val canTransform = transformer.canTransform(file)
+        if (canTransform) {
+            transformer.runTransform(file)
+        }
+
+        val strResult = file.data.toString(Charset.defaultCharset())
+
+        Truth.assertThat(canTransform).isEqualTo(expectedCanTransform)
+        Truth.assertThat(strResult).isEqualTo(expected)
+    }
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassFilterTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassFilterTest.kt
index 2c7d7e2..86b1599 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassFilterTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassFilterTest.kt
@@ -21,7 +21,7 @@
 class ClassFilterTest {
 
     @Test fun proGuard_classFilter() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -38,7 +38,7 @@
     }
 
     @Test fun proGuard_classFilter_newLineIgnored() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -57,7 +57,7 @@
     }
 
     @Test fun proGuard_classFilter_spacesRespected() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -74,7 +74,7 @@
     }
 
     @Test fun proGuard_classFilter_negation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest.kt
index e64590f..dc3e470 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest.kt
@@ -21,7 +21,7 @@
 class ClassSpecTest {
 
     @Test fun proGuard_classSpec_simple() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -39,7 +39,7 @@
     }
 
     @Test fun proGuard_classSpec_allExistingRules() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -71,7 +71,7 @@
     }
 
     @Test fun proGuard_classSpec_rulesModifiers() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -99,7 +99,7 @@
     }
 
     @Test fun proGuard_classSpec_extends() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -119,7 +119,7 @@
     }
 
     @Test fun proGuard_classSpec_modifiers_extends() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -137,7 +137,7 @@
     }
 
     @Test fun proGuard_classSpec_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -157,7 +157,7 @@
     }
 
     @Test fun proGuard_classSpec_annotation_extends() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -177,7 +177,7 @@
     }
 
     @Test fun proGuard_classSpec_annotation_extends_spaces() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -193,5 +193,4 @@
                 "-keep \t @test.Annotation \t public  class  *  extends test.Activity"
             )
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldTypeSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldTypeSelector.kt
index 2832385..d08bbbe 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldTypeSelector.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldTypeSelector.kt
@@ -21,7 +21,7 @@
 class ClassSpecTest_FieldTypeSelector {
 
     @Test fun proGuard_fieldTypeSelector() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -46,7 +46,7 @@
     }
 
     @Test fun proGuard_fieldTypeSelector_modifiers() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -71,7 +71,7 @@
     }
 
     @Test fun proGuard_fieldTypeSelector_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -95,7 +95,7 @@
     }
 
     @Test fun proGuard_fieldTypeSelector_modifiers_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -121,7 +121,7 @@
     }
 
     @Test fun proGuard_fieldTypeSelector_modifiers_annotation_spaces() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -141,5 +141,4 @@
                 "}"
             )
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldsSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldsSelector.kt
index 6f6a1f9..2a0f752 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldsSelector.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_FieldsSelector.kt
@@ -21,7 +21,7 @@
 class ClassSpecTest_FieldsSelector {
 
     @Test fun proGuard_fieldsSelector_minimal() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -41,7 +41,7 @@
     }
 
     @Test fun proGuard_fieldsSelector_modifiers() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
             )
             .forGivenTypesMap(
@@ -63,7 +63,7 @@
     }
 
     @Test fun proGuard_fieldsSelector_modifiers_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -87,7 +87,7 @@
     }
 
     @Test fun proGuard_fieldsSelector_modifiers_annotation_spaces() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodInitSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodInitSelector.kt
index 9a792cf..d681bda 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodInitSelector.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodInitSelector.kt
@@ -21,7 +21,7 @@
 class ClassSpecTest_MethodInitSelector {
 
     @Test fun proGuard_methodsInitSelector() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
             )
             .forGivenTypesMap(
@@ -39,7 +39,7 @@
     }
 
     @Test fun proGuard_methodsInitSelector_modifiers() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
             )
             .forGivenTypesMap(
@@ -63,7 +63,7 @@
     }
 
     @Test fun proGuard_methodsInitSelector_modifiers_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -89,7 +89,7 @@
     }
 
     @Test fun proGuard_methodInitSelector() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -118,7 +118,7 @@
     }
 
     @Test fun proGuard_methodInitSelector_modifiers() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -147,7 +147,7 @@
     }
 
     @Test fun proGuard_methodInitSelector_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -162,7 +162,8 @@
                 "  @support.Annotation <init>(*); \n" +
                 "  @support.Annotation <init>(...); \n" +
                 "  @keep.Me <init>(support.Activity); \n" +
-                "  @support.Annotation <init>(support.Activity, support.Fragment, keep.Please); \n" +
+                "  @support.Annotation <init>(support.Activity, support.Fragment, keep.Please);" +
+                " \n" +
                 "}"
             )
             .rewritesTo(
@@ -177,7 +178,7 @@
     }
 
     @Test fun proGuard_methodInitSelector_modifiers_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -192,7 +193,8 @@
                 "  @support.Annotation public static <init>(*); \n" +
                 "  @support.Annotation !public !static <init>(...); \n" +
                 "  @support.Annotation !private static <init>(support.Activity); \n" +
-                "  @support.Annotation public !abstract <init>(support.Activity, support.Fragment, keep.Please); \n" +
+                "  @support.Annotation public !abstract <init>(support.Activity, support.Fragment" +
+                ", keep.Please); \n" +
                 "}"
             )
             .rewritesTo(
@@ -201,13 +203,14 @@
                 "  @test.Annotation public static <init>(*); \n" +
                 "  @test.Annotation !public !static <init>(...); \n" +
                 "  @test.Annotation !private static <init>(test.Activity); \n" +
-                "  @test.Annotation public !abstract <init>(test.Activity, test.Fragment, keep.Please); \n" +
+                "  @test.Annotation public !abstract <init>(test.Activity, test.Fragment, " +
+                "keep.Please); \n" +
                 "}"
             )
     }
 
     @Test fun proGuard_methodInitSelector_modifiers_annotation_test() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -218,12 +221,14 @@
             )
             .testThatGivenProGuard(
                 "-keep public class * { \n" +
-                "  @support.Annotation  public  !abstract \t <init> ( support.Activity , support.Fragment, keep.Please); \n" +
+                "  @support.Annotation  public  !abstract \t <init> ( support.Activity , " +
+                "support.Fragment, keep.Please); \n" +
                 "}"
             )
             .rewritesTo(
                 "-keep public class * { \n" +
-                "  @test.Annotation  public  !abstract \t <init> (test.Activity, test.Fragment, keep.Please); \n" +
+                "  @test.Annotation  public  !abstract \t <init> (test.Activity, test.Fragment, " +
+                "keep.Please); \n" +
                 "}"
             )
     }
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodSelectorWithReturnType.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodSelectorWithReturnType.kt
index d9960b4..1cee765 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodSelectorWithReturnType.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_MethodSelectorWithReturnType.kt
@@ -21,7 +21,7 @@
 class ClassSpecTest_MethodSelectorWithReturnType {
 
     @Test fun proGuard_methodReturnTypeSelector() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -54,7 +54,7 @@
     }
 
     @Test fun proGuard_methodReturnTypeSelector_voidResult() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -83,7 +83,7 @@
     }
 
     @Test fun proGuard_methodReturnTypeSelector_starResult() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -112,7 +112,7 @@
     }
 
     @Test fun proGuard_methodReturnTypeSelector_typeResult() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -141,7 +141,7 @@
     }
 
     @Test fun proGuard_methodReturnTypeSelector_typeResult_wildcards() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -170,7 +170,7 @@
     }
 
     @Test fun proGuard_methodReturnTypeSelector_typeResult_modifiers() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -184,7 +184,8 @@
                 "  public static support.Fragment get(...); \n" +
                 "  !public !static support.Fragment get(*); \n" +
                 "  private support.Fragment get(support.Activity); \n" +
-                "  public abstract support.Fragment get(support.Activity, support.Fragment, keep.Please); \n" +
+                "  public abstract support.Fragment get(support.Activity, support.Fragment, " +
+                "keep.Please); \n" +
                 "}"
             )
             .rewritesTo(
@@ -193,13 +194,14 @@
                 "  public static test.Fragment get(...); \n" +
                 "  !public !static test.Fragment get(*); \n" +
                 "  private test.Fragment get(test.Activity); \n" +
-                "  public abstract test.Fragment get(test.Activity, test.Fragment, keep.Please); \n" +
+                "  public abstract test.Fragment get(test.Activity, test.Fragment, keep.Please); " +
+                "\n" +
                 "}"
             )
     }
 
     @Test fun proGuard_methodReturnTypeSelector_typeResult_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -214,7 +216,8 @@
                 "  @support.Annotation support.Fragment get(...); \n" +
                 "  @support.Annotation support.Fragment get(*); \n" +
                 "  @keep.Me support.Fragment get(support.Activity); \n" +
-                "  @support.Annotation support.Fragment get(support.Activity, support.Fragment, keep.Please); \n" +
+                "  @support.Annotation support.Fragment get(support.Activity, support.Fragment, " +
+                "keep.Please); \n" +
                 "}"
             )
             .rewritesTo(
@@ -223,13 +226,14 @@
                 "  @test.Annotation test.Fragment get(...); \n" +
                 "  @test.Annotation test.Fragment get(*); \n" +
                 "  @keep.Me test.Fragment get(test.Activity); \n" +
-                "  @test.Annotation test.Fragment get(test.Activity, test.Fragment, keep.Please); \n" +
+                "  @test.Annotation test.Fragment get(test.Activity, test.Fragment, keep.Please" +
+                "); \n" +
                 "}"
             )
     }
 
     @Test fun proGuard_methodReturnTypeSelector_typeResult_modifiers_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -244,7 +248,8 @@
                 "  @support.Annotation public static support.Fragment get(...); \n" +
                 "  @support.Annotation !public !static support.Fragment get(*); \n" +
                 "  @support.Annotation private support.Fragment get(support.Activity); \n" +
-                "  @support.Annotation public abstract support.Fragment get(support.Activity, support.Fragment,  keep.Please); \n" +
+                "  @support.Annotation public abstract support.Fragment get(support.Activity, " +
+                "support.Fragment,  keep.Please); \n" +
                 "}"
             )
             .rewritesTo(
@@ -253,13 +258,14 @@
                 "  @test.Annotation public static test.Fragment get(...); \n" +
                 "  @test.Annotation !public !static test.Fragment get(*); \n" +
                 "  @test.Annotation private test.Fragment get(test.Activity); \n" +
-                "  @test.Annotation public abstract test.Fragment get(test.Activity, test.Fragment, keep.Please); \n" +
+                "  @test.Annotation public abstract test.Fragment get(test.Activity, " +
+                "test.Fragment, keep.Please); \n" +
                 "}"
             )
     }
 
     @Test fun proGuard_methodReturnTypeSelector_typeResult_modifiers_annotation_spaces() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -270,12 +276,14 @@
             )
             .testThatGivenProGuard(
                 "-keep public class * { \n" +
-                "  @support.Annotation  support.Fragment \t get(support.Activity ,  support.Fragment ,  keep.Please) ; \n" +
+                "  @support.Annotation  support.Fragment \t get(support.Activity ,  " +
+                "support.Fragment ,  keep.Please) ; \n" +
                 "}"
             )
             .rewritesTo(
                 "-keep public class * { \n" +
-                "  @test.Annotation  test.Fragment \t get(test.Activity, test.Fragment, keep.Please) ; \n" +
+                "  @test.Annotation  test.Fragment \t get(test.Activity, test.Fragment, " +
+                "keep.Please) ; \n" +
                 "}"
             )
     }
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_NamedCtorSelector.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_NamedCtorSelector.kt
index 21b8b8c..671be61 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_NamedCtorSelector.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ClassSpecTest_NamedCtorSelector.kt
@@ -21,7 +21,7 @@
 class ClassSpecTest_NamedCtorSelector {
 
     @Test fun proGuard_ctorSelector() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -50,7 +50,7 @@
     }
 
     @Test fun proGuard_ctorSelector_modifiers() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -64,7 +64,8 @@
                 "  public static support.Activity(...); \n" +
                 "  !private support.Activity(*); \n" +
                 "  !public !static support.Activity(support.Activity); \n" +
-                "  !protected support.Activity(support.Activity, support.Fragment, keep.Please); \n" +
+                "  !protected support.Activity(support.Activity, support.Fragment, keep.Please);" +
+                " \n" +
                 "}"
             )
             .rewritesTo(
@@ -79,7 +80,7 @@
     }
 
     @Test fun proGuard_ctorSelector_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -94,7 +95,8 @@
                 "  @support.Annotation support.Activity(...); \n" +
                 "  @support.Annotation support.Activity(*); \n" +
                 "  @support.Annotation support.Activity(support.Activity); \n" +
-                "  @support.Annotation support.Activity(support.Activity, support.Fragment, keep.Please); \n" +
+                "  @support.Annotation support.Activity(support.Activity, support.Fragment, " +
+                "keep.Please); \n" +
                 "}"
             )
             .rewritesTo(
@@ -109,7 +111,7 @@
     }
 
     @Test fun proGuard_ctorSelector_modifiers_annotation() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -124,7 +126,8 @@
                 "  @support.Annotation public static support.Activity(...); \n" +
                 "  @support.Annotation !private support.Activity(*); \n" +
                 "  @support.Annotation !public !static support.Activity(support.Activity); \n" +
-                "  @support.Annotation !protected support.Activity(support.Activity, support.Fragment, keep.Please); \n" +
+                "  @support.Annotation !protected support.Activity(support.Activity, " +
+                "support.Fragment, keep.Please); \n" +
                 "}"
             )
             .rewritesTo(
@@ -133,13 +136,14 @@
                 "  @test.Annotation public static test.Activity(...); \n" +
                 "  @test.Annotation !private test.Activity(*); \n" +
                 "  @test.Annotation !public !static test.Activity(test.Activity); \n" +
-                "  @test.Annotation !protected test.Activity(test.Activity, test.Fragment, keep.Please); \n" +
+                "  @test.Annotation !protected test.Activity(test.Activity, test.Fragment, " +
+                "keep.Please); \n" +
                 "}"
             )
     }
 
     @Test fun proGuard_ctorSelector_modifiers_annotation_spaces() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTester.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTester.kt
index cae21d0..37075d3 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTester.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTester.kt
@@ -20,62 +20,68 @@
 import android.support.tools.jetifier.core.config.Config
 import android.support.tools.jetifier.core.map.TypesMap
 import android.support.tools.jetifier.core.rules.JavaType
+import android.support.tools.jetifier.core.rules.RewriteRule
 import android.support.tools.jetifier.core.transform.TransformationContext
 import com.google.common.truth.Truth
 import java.nio.charset.StandardCharsets
 import java.nio.file.Paths
 
-
 /**
  * Helper to test ProGuard rewriting logic using lightweight syntax.
  */
-object ProGuardTester {
+class ProGuardTester {
 
     private var javaTypes = emptyList<Pair<String, String>>()
+    private var rewriteRules = emptyList<Pair<String, String>>()
     private var proGuardTypes = emptyList<Pair<ProGuardType, ProGuardType>>()
     private var prefixes = emptyList<String>()
 
-    fun forGivenPrefixes(vararg prefixes: String) : ProGuardTester {
+    fun forGivenPrefixes(vararg prefixes: String): ProGuardTester {
         this.prefixes = prefixes.toList()
         return this
     }
 
-    fun forGivenTypesMap(vararg rules: Pair<String, String>) : ProGuardTester {
-        this.javaTypes = rules.toList()
+    fun forGivenTypesMap(vararg types: Pair<String, String>): ProGuardTester {
+        this.javaTypes = types.toList()
         return this
     }
 
-    fun forGivenProGuardMap(vararg rules: Pair<String, String>) : ProGuardTester {
+    fun forGivenRules(vararg rules: Pair<String, String>): ProGuardTester {
+        this.rewriteRules = rules.toList()
+        return this
+    }
+
+    fun forGivenProGuardMap(vararg rules: Pair<String, String>): ProGuardTester {
         this.proGuardTypes = rules.map {
             ProGuardType.fromDotNotation(it.first) to ProGuardType.fromDotNotation(it.second) }
             .toList()
         return this
     }
 
-    fun testThatGivenType(givenType: String) : ProGuardTesterForType {
+    fun testThatGivenType(givenType: String): ProGuardTesterForType {
         return ProGuardTesterForType(createConfig(), givenType)
     }
 
-    fun testThatGivenArguments(givenArgs: String) : ProGuardTesterForArgs {
+    fun testThatGivenArguments(givenArgs: String): ProGuardTesterForArgs {
         return ProGuardTesterForArgs(createConfig(), givenArgs)
     }
 
-    fun testThatGivenProGuard(given: String) : ProGuardTesterForFile {
+    fun testThatGivenProGuard(given: String): ProGuardTesterForFile {
         return ProGuardTesterForFile(createConfig(), given)
     }
 
-    private fun createConfig() : Config {
+    private fun createConfig(): Config {
         return Config(
             restrictToPackagePrefixes = prefixes,
-            rewriteRules = emptyList(),
-            pomRewriteRules =  emptyList(),
+            rewriteRules = rewriteRules.map { RewriteRule(it.first, it.second) },
+            slRules = emptyList(),
+            pomRewriteRules = emptyList(),
             typesMap = TypesMap(
-                types = javaTypes.map { JavaType(it.first) to JavaType(it.second) }.toMap(),
-                fields = emptyMap()),
+                types = javaTypes.map { JavaType(it.first) to JavaType(it.second) }.toMap()
+            ),
             proGuardMap = ProGuardTypesMap(proGuardTypes.toMap()))
     }
 
-
     class ProGuardTesterForFile(private val config: Config, private val given: String) {
 
         fun rewritesTo(expected: String) {
@@ -87,8 +93,8 @@
             val result = file.data.toString(StandardCharsets.UTF_8)
 
             Truth.assertThat(result).isEqualTo(expected)
+            Truth.assertThat(context.errorsTotal()).isEqualTo(0)
         }
-
     }
 
     class ProGuardTesterForType(private val config: Config, private val given: String) {
@@ -99,8 +105,8 @@
             val result = mapper.replaceType(given)
 
             Truth.assertThat(result).isEqualTo(expectedType)
+            Truth.assertThat(context.errorsTotal()).isEqualTo(0)
         }
-
     }
 
     class ProGuardTesterForArgs(private val config: Config, private val given: String) {
@@ -111,8 +117,7 @@
             val result = mapper.replaceMethodArgs(given)
 
             Truth.assertThat(result).isEqualTo(expectedArguments)
+            Truth.assertThat(context.errorsTotal()).isEqualTo(0)
         }
     }
-
-}
-
+}
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapperTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapperTest.kt
index 5e12aff..b1da4e2 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapperTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProGuardTypesMapperTest.kt
@@ -21,25 +21,25 @@
 class ProGuardTypesMapperTest {
 
     @Test fun proGuard_typeMapper_wildcard_simple() {
-        ProGuardTester
+        ProGuardTester()
             .testThatGivenType("*")
             .getsRewrittenTo("*")
     }
 
     @Test fun proGuard_typeMapper_wildcard_double() {
-        ProGuardTester
+        ProGuardTester()
             .testThatGivenType("**")
             .getsRewrittenTo("**")
     }
 
     @Test fun proGuard_typeMapper_wildcard_composed() {
-        ProGuardTester
+        ProGuardTester()
             .testThatGivenType("**/*")
             .getsRewrittenTo("**/*")
     }
 
     @Test fun proGuard_typeMapper_wildcard_viaMap() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -51,7 +51,7 @@
     }
 
     @Test fun proGuard_typeMapper_wildcard_viaMap2() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -63,7 +63,7 @@
     }
 
     @Test fun proGuard_typeMapper_wildcard_viaTypesMap() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -75,7 +75,7 @@
     }
 
     @Test fun proGuard_typeMapper_wildcard_notFoundInMap() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -87,7 +87,7 @@
     }
 
     @Test fun proGuard_typeMapper_differentPrefix_notRewritten() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -99,7 +99,7 @@
     }
 
     @Test fun proGuard_typeMapper_differentPrefix_wildcard_getsRewritten() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -111,7 +111,7 @@
     }
 
     @Test fun proGuard_typeMapper_innerClass() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -123,7 +123,7 @@
     }
 
     @Test fun proGuard_typeMapper_innerClass_wildcard() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -135,25 +135,25 @@
     }
 
     @Test fun proGuard_argsMapper_tripleDots() {
-        ProGuardTester
+        ProGuardTester()
             .testThatGivenArguments("...")
             .getRewrittenTo("...")
     }
 
     @Test fun proGuard_argsMapper_wildcard() {
-        ProGuardTester
+        ProGuardTester()
             .testThatGivenArguments("*")
             .getRewrittenTo("*")
     }
 
     @Test fun proGuard_argsMapper_wildcards() {
-        ProGuardTester
+        ProGuardTester()
             .testThatGivenArguments("**, **")
             .getRewrittenTo("**, **")
     }
 
     @Test fun proGuard_argsMapper_viaMaps() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -168,7 +168,7 @@
     }
 
     @Test fun proGuard_argsMapper_viaMaps_spaces() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -182,4 +182,41 @@
             .getRewrittenTo("test.Activity, test.v7.**, keep.Me")
     }
 
+    @Test fun proGuard_shouldIgnore() {
+        ProGuardTester()
+            .forGivenPrefixes(
+                "support/"
+            )
+            .forGivenRules(
+                "support/v7/Activity" to "ignore"
+            )
+            .testThatGivenType("support.v7.Activity")
+            .getsRewrittenTo("support.v7.Activity")
+    }
+
+    @Test fun proGuard_shouldIgnore_withWildcard() {
+        ProGuardTester()
+            .forGivenPrefixes(
+                "support/"
+            )
+            .forGivenRules(
+                "support/v7/(.*)" to "ignore"
+            )
+            .testThatGivenType("support.v7.**")
+            .getsRewrittenTo("support.v7.**")
+    }
+
+
+    @Test(expected = AssertionError::class)
+    fun proGuard_shouldNotIgnore() {
+        ProGuardTester()
+            .forGivenPrefixes(
+                "support/"
+            )
+            .forGivenRules(
+                "support/v7/Activity" to "ignoreInPreprocessor"
+            )
+            .testThatGivenType("support.v7.Activity")
+            .getsRewrittenTo("support.v7.Activity")
+    }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProguardSamplesTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProguardSamplesTest.kt
index 0542e7d..f9554f1 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProguardSamplesTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/proguard/ProguardSamplesTest.kt
@@ -21,7 +21,7 @@
 class ProguardSamplesTest {
 
     @Test fun proGuard_sample() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "android/app/",
                 "android/view/",
@@ -39,51 +39,51 @@
                 "android/webkit/JavascriptInterface" to "test/webkit/JavascriptInterface"
             )
             .testThatGivenProGuard(
-               "-injars      bin/classes \n" +
-               "-injars      libs \n" +
-               "-outjars     bin/classes-processed.jar \n" +
-               "-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar \n" +
-               "\n" +
-               "-dontpreverify \n" +
-               "-repackageclasses '' \n" +
-               "-allowaccessmodification \n" +
-               "-optimizations !code/simplification/arithmetic \n" +
-               "-keepattributes *Annotation* \n" +
-               "\n" +
-               "-keep public class * extends android.app.Activity \n" +
-               "-keep public class * extends android.app.Application \n" +
-               " \n" +
-               "-keep public class * extends android.view.View { \n" +
-               "      public <init>(android.content.Context); \n" +
-               "      public <init>(android.content.Context, android.util.AttributeSet); \n" +
-               "      public <init>(android.content.Context, android.util.AttributeSet, int); \n" +
-               "      public void set*(...); \n" +
-               "} \n" +
-               "\n" +
-               "-keepclasseswithmembers class * { \n" +
-               "    public <init>(android.content.Context, android.util.AttributeSet); \n" +
-               "} \n" +
-               "\n" +
-               "-keepclasseswithmembers class * { \n" +
-               "    public <init>(android.content.Context, android.util.AttributeSet, int); \n" +
-               "} \n" +
-               "\n" +
-               "-keepclassmembers class * extends android.content.Context { \n" +
-               "    public void *(android.view.View); \n" +
-               "    public void *(android.view.MenuItem); \n" +
-               "} \n" +
-               "\n" +
-               "-keepclassmembers class * implements android.os.Parcelable { \n" +
-               "    static ** CREATOR; \n" +
-               "} \n" +
-               "\n" +
-               "-keepclassmembers class **.R\$* { \n" +
-               "    public static <fields>; \n" +
-               "} \n" +
-               "\n" +
-               "-keepclassmembers class * { \n" +
-               "    @android.webkit.JavascriptInterface <methods>; \n" +
-               "} "
+                "-injars      bin/classes \n" +
+                "-injars      libs \n" +
+                "-outjars     bin/classes-processed.jar \n" +
+                "-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar \n" +
+                "\n" +
+                "-dontpreverify \n" +
+                "-repackageclasses '' \n" +
+                "-allowaccessmodification \n" +
+                "-optimizations !code/simplification/arithmetic \n" +
+                "-keepattributes *Annotation* \n" +
+                "\n" +
+                "-keep public class * extends android.app.Activity \n" +
+                "-keep public class * extends android.app.Application \n" +
+                " \n" +
+                "-keep public class * extends android.view.View { \n" +
+                "      public <init>(android.content.Context); \n" +
+                "      public <init>(android.content.Context, android.util.AttributeSet); \n" +
+                "      public <init>(android.content.Context, android.util.AttributeSet, int); \n" +
+                "      public void set*(...); \n" +
+                "} \n" +
+                "\n" +
+                "-keepclasseswithmembers class * { \n" +
+                "    public <init>(android.content.Context, android.util.AttributeSet); \n" +
+                "} \n" +
+                "\n" +
+                "-keepclasseswithmembers class * { \n" +
+                "    public <init>(android.content.Context, android.util.AttributeSet, int); \n" +
+                "} \n" +
+                "\n" +
+                "-keepclassmembers class * extends android.content.Context { \n" +
+                "    public void *(android.view.View); \n" +
+                "    public void *(android.view.MenuItem); \n" +
+                "} \n" +
+                "\n" +
+                "-keepclassmembers class * implements android.os.Parcelable { \n" +
+                "    static ** CREATOR; \n" +
+                "} \n" +
+                "\n" +
+                "-keepclassmembers class **.R\$* { \n" +
+                "    public static <fields>; \n" +
+                "} \n" +
+                "\n" +
+                "-keepclassmembers class * { \n" +
+                "    @android.webkit.JavascriptInterface <methods>; \n" +
+                "} "
             )
             .rewritesTo(
                 "-injars      bin/classes \n" +
@@ -135,7 +135,7 @@
     }
 
     @Test fun proGuard_sample2() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "android/support/v7/"
             )
@@ -161,7 +161,7 @@
     }
 
     @Test fun proGuard_sample3() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "android/support/design/",
                 "android/support/v7/"
@@ -191,7 +191,7 @@
     }
 
     @Test fun proGuard_sample4() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "android/support/design/",
                 "android/support/v7/",
@@ -238,7 +238,7 @@
     }
 
     @Test fun proGuard_sample5() {
-        ProGuardTester
+        ProGuardTester()
             .forGivenPrefixes(
                 "support/"
             )
@@ -270,5 +270,4 @@
                 "}"
             )
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformerTest.kt b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformerTest.kt
index 5788b40..4aaaae0 100644
--- a/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformerTest.kt
+++ b/jetifier/jetifier/core/src/test/kotlin/android/support/tools/jetifier/core/transform/resource/XmlResourcesTransformerTest.kt
@@ -16,14 +16,17 @@
 
 package android.support.tools.jetifier.core.transform.resource
 
+import android.support.tools.jetifier.core.archive.ArchiveFile
 import android.support.tools.jetifier.core.config.Config
 import android.support.tools.jetifier.core.rules.JavaType
 import android.support.tools.jetifier.core.map.TypesMap
+import android.support.tools.jetifier.core.transform.PackageMap
 import android.support.tools.jetifier.core.transform.TransformationContext
 import android.support.tools.jetifier.core.transform.proguard.ProGuardTypesMap
 import com.google.common.truth.Truth
 import org.junit.Test
 import java.nio.charset.Charset
+import java.nio.file.Paths
 
 class XmlResourcesTransformerTest {
 
@@ -45,7 +48,8 @@
                 "<android.support.v7.preference.Preference>\n" +
                 "</android.support.v7.preference.Preference>",
             prefixes = listOf("android/support/v7/"),
-            map = mapOf()
+            map = mapOf(),
+            errorsExpected = true
         )
     }
 
@@ -81,7 +85,8 @@
             prefixes = listOf("android/support/"),
             map = mapOf(
                 "android/support2/v7/preference/Preference" to "android/test/pref/Preference"
-            )
+            ),
+            errorsExpected = true
         )
     }
 
@@ -92,7 +97,7 @@
             expectedXml =
                 "<android.test.pref.Preference/>",
             prefixes = listOf("android/support/"),
-            map = mapOf(
+            typesMap = mapOf(
                 "android/support/v7/preference/Preference" to "android/test/pref/Preference"
             )
         )
@@ -107,7 +112,7 @@
                 "<android.test.pref.Preference \n" +
                 "    someAttribute=\"android.support.v7.preference.Preference\"/>",
             prefixes = listOf("android/support/"),
-            map =  mapOf(
+            typesMap = mapOf(
                 "android/support/v7/preference/Preference" to "android/test/pref/Preference"
             )
         )
@@ -122,7 +127,7 @@
                 "<android.test.pref.Preference>\n" +
                 "</android.test.pref.Preference>",
             prefixes = listOf("android/support/"),
-            map = mapOf(
+            typesMap = mapOf(
                 "android/support/v7/preference/Preference" to "android/test/pref/Preference"
             )
         )
@@ -135,7 +140,7 @@
             expectedXml =
                 "<view class=\"android.test.pref.Preference\">",
             prefixes = listOf("android/support/"),
-            map = mapOf(
+            typesMap = mapOf(
                 "android/support/v7/preference/Preference" to "android/test/pref/Preference"
             )
         )
@@ -152,7 +157,7 @@
                 "      class=\"android.test.pref.Preference\"" +
                 "      ignoreMe=\"android.support.v7.preference.Preference\">",
             prefixes = listOf("android/support/"),
-            map = mapOf(
+            typesMap = mapOf(
                 "android/support/v7/preference/Preference" to "android/test/pref/Preference"
             )
         )
@@ -178,8 +183,9 @@
                 "<android.support.v7.preference.Preference>\n" +
                 "</android.support.v7.preference.Preference>",
             prefixes = listOf("android/support/"),
-            map = mapOf(
-                "android/support/v7/preference/Preference" to "android/support/v7/preference/Preference"
+            typesMap = mapOf(
+                "android/support/v7/preference/Preference"
+                    to "android/support/v7/preference/Preference"
             )
         )
     }
@@ -214,25 +220,98 @@
                 "android/support/v7/",
                 "android/support/v14/"
             ),
-            map = mapOf(
-                "android/support/v7/preference/ListPreference" to "android/test/pref/ListPref",
-                "android/support/v7/preference/Preference" to "android/test/pref/Preference",
-                "android/support/v14/preference/DialogPreference" to "android/test14/pref/DialogPreference",
-                "android/support/v21/preference/DialogPreference" to "android/test21/pref/DialogPreference"
+            typesMap = mapOf(
+                "android/support/v7/preference/ListPreference"
+                    to "android/test/pref/ListPref",
+                "android/support/v7/preference/Preference"
+                    to "android/test/pref/Preference",
+                "android/support/v14/preference/DialogPreference"
+                    to "android/test14/pref/DialogPreference",
+                "android/support/v21/preference/DialogPreference"
+                    to "android/test21/pref/DialogPreference"
             )
         )
     }
 
-    private fun testRewriteToTheSame(givenAndExpectedXml: String,
-                                     prefixes: List<String>,
-                                     map: Map<String, String>) {
-        testRewrite(givenAndExpectedXml, givenAndExpectedXml, prefixes, map)
+    @Test fun manifestFile_packageRewrite() {
+        testRewrite(
+            givenXml =
+                "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                "          package=\"android.support.v7.preference\">\n" +
+                "    <uses-sdk android:minSdkVersion=\"14\"/>\n" +
+                "</manifest>",
+            expectedXml =
+                "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                "          package=\"androidx.preference\">\n" +
+                "    <uses-sdk android:minSdkVersion=\"14\"/>\n" +
+                "</manifest>",
+            prefixes = listOf(
+            ),
+            typesMap = mapOf(
+            ),
+            packageMap = PackageMap(listOf(
+                PackageMap.PackageRule(
+                    from = "android/support/v7/preference",
+                    to = "androidx/preference")
+            )),
+            rewritingSupportLib = true,
+            isManifestFile = true
+        )
     }
 
-    private fun testRewrite(givenXml : String,
-                            expectedXml : String,
-                            prefixes: List<String>,
-                            map: Map<String, String>) {
+    @Test fun manifestFile_packageRewrite_chooseBasedOnArtifactName() {
+        testRewrite(
+            givenXml =
+            "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                "          package=\"androidx.preference\">\n" +
+                "    <uses-sdk android:minSdkVersion=\"14\"/>\n" +
+                "</manifest>",
+            expectedXml =
+            "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                "          package=\"android.support.v14.preference\">\n" +
+                "    <uses-sdk android:minSdkVersion=\"14\"/>\n" +
+                "</manifest>",
+            prefixes = listOf(
+            ),
+            typesMap = mapOf(
+            ),
+            packageMap = PackageMap(listOf(
+                PackageMap.PackageRule(
+                    from = "androidx/preference",
+                    to = "android/support/v7/preference",
+                    filePrefix = "preference-7"),
+                PackageMap.PackageRule(
+                    from = "androidx/preference",
+                    to = "android/support/v14/preference",
+                    filePrefix = "preference-v14")
+            )),
+            rewritingSupportLib = true,
+            isManifestFile = true,
+            libraryName = "preference-v14-28.0.0-123.aar"
+        )
+    }
+
+    private fun testRewriteToTheSame(
+        givenAndExpectedXml: String,
+        prefixes: List<String>,
+        map: Map<String, String>,
+        errorsExpected: Boolean = false
+    ) {
+        testRewrite(givenAndExpectedXml, givenAndExpectedXml, prefixes, map,
+            errorsExpected = errorsExpected)
+    }
+
+    private fun testRewrite(
+        givenXml: String,
+        expectedXml: String,
+        prefixes: List<String>,
+        typesMap: Map<String, String>,
+        packageMap: PackageMap = PackageMap.EMPTY,
+        rewritingSupportLib: Boolean = false,
+        isManifestFile: Boolean = false,
+        libraryName: String = "",
+        errorsExpected: Boolean = false
+    ) {
         val given =
             "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
             "$givenXml\n"
@@ -241,15 +320,35 @@
             "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
             "$expectedXml\n"
 
-        val typesMap = TypesMap(map.map{ JavaType(it.key) to JavaType(it.value) }.toMap(),
-            emptyMap())
-        val config = Config(prefixes, emptyList(), emptyList(), typesMap, ProGuardTypesMap.EMPTY)
-        val context = TransformationContext(config)
+        val typeMap = TypesMap(typesMap.map { JavaType(it.key) to JavaType(it.value) }.toMap())
+        val config = Config(
+            restrictToPackagePrefixes = prefixes,
+            rewriteRules = emptyList(),
+            slRules = emptyList(),
+            pomRewriteRules = emptyList(),
+            typesMap = typeMap,
+            proGuardMap = ProGuardTypesMap.EMPTY,
+            packageMap = packageMap
+        )
+        val context = TransformationContext(config, rewritingSupportLib = rewritingSupportLib)
+        context.libraryName = libraryName
         val processor = XmlResourcesTransformer(context)
-        val result = processor.transform(given.toByteArray())
-        val strResult = result.toString(Charset.defaultCharset())
+        val fileName = if (isManifestFile) {
+            Paths.get("AndroidManifest.xml")
+        } else {
+            Paths.get("random.xml")
+        }
+        val file = ArchiveFile(fileName, given.toByteArray())
+        processor.runTransform(file)
+        val strResult = file.data.toString(Charset.defaultCharset())
 
         Truth.assertThat(strResult).isEqualTo(expected)
+
+        if (errorsExpected) {
+            Truth.assertThat(context.errorsTotal()).isAtLeast(1)
+        } else {
+            Truth.assertThat(context.errorsTotal()).isEqualTo(0)
+        }
     }
 }
 
diff --git a/jetifier/jetifier/core/src/test/resources/changeDetectionTest/testPreference.class b/jetifier/jetifier/core/src/test/resources/changeDetectionTest/testPreference.class
new file mode 100644
index 0000000..50d7d11
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/resources/changeDetectionTest/testPreference.class
Binary files differ
diff --git a/jetifier/jetifier/core/src/test/resources/fileRenameTest/expectedTestLib.zip b/jetifier/jetifier/core/src/test/resources/fileRenameTest/expectedTestLib.zip
new file mode 100644
index 0000000..7ee64b7
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/resources/fileRenameTest/expectedTestLib.zip
Binary files differ
diff --git a/jetifier/jetifier/core/src/test/resources/fileRenameTest/expectedTestLibNested.zip b/jetifier/jetifier/core/src/test/resources/fileRenameTest/expectedTestLibNested.zip
new file mode 100644
index 0000000..11c328d
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/resources/fileRenameTest/expectedTestLibNested.zip
Binary files differ
diff --git a/jetifier/jetifier/core/src/test/resources/fileRenameTest/inputTestLib.zip b/jetifier/jetifier/core/src/test/resources/fileRenameTest/inputTestLib.zip
new file mode 100644
index 0000000..239baa1
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/resources/fileRenameTest/inputTestLib.zip
Binary files differ
diff --git a/jetifier/jetifier/core/src/test/resources/fileRenameTest/inputTestLibNested.zip b/jetifier/jetifier/core/src/test/resources/fileRenameTest/inputTestLibNested.zip
new file mode 100644
index 0000000..e722db1
--- /dev/null
+++ b/jetifier/jetifier/core/src/test/resources/fileRenameTest/inputTestLibNested.zip
Binary files differ
diff --git a/jetifier/jetifier/gradle b/jetifier/jetifier/gradle
deleted file mode 120000
index 1ce6c4c..0000000
--- a/jetifier/jetifier/gradle
+++ /dev/null
@@ -1 +0,0 @@
-../../gradle
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/build.gradle b/jetifier/jetifier/gradle-plugin/build.gradle
index 3b001f8..4a8d0fb 100644
--- a/jetifier/jetifier/gradle-plugin/build.gradle
+++ b/jetifier/jetifier/gradle-plugin/build.gradle
@@ -14,30 +14,29 @@
  * limitations under the License
  */
 
-apply plugin: 'maven'
+import static android.support.dependencies.DependenciesKt.KOTLIN_STDLIB
 
-version '0.2'
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+  id("SupportKotlinLibraryPlugin")
+}
 
 dependencies {
-    compile project(':core')
+    compile project(':jetifier-core')
+    compile(KOTLIN_STDLIB)
     compileOnly gradleApi()
 }
 
-// Task to create a jar with all the required dependencies bundled inside
-task fatJar(type: Jar) {
-    baseName = project.name + '-all'
-    destinationDir = rootProject.ext.distDir
-    from { configurations.runtime.collect { it.isDirectory() ? it : zipTree(it) } }
-    with jar
+
+supportLibrary {
+    name = "Android Jetifier Gradle Plugin"
+    publish = true
+    mavenVersion = LibraryVersions.JETIFIER
+    mavenGroup = LibraryGroups.JETIFIER
+    generateDocs = false
+    inceptionYear = "2017"
+    description = "Android Jetifier Gradle Plugin"
 }
 
-uploadArchives {
-    repositories {
-        mavenDeployer {
-            repository(url: rootProject.ext.repoDir)
-        }
-    }
-}
-
-rootProject.mainUpload.dependsOn tasks["uploadArchives"]
-tasks["uploadArchives"].dependsOn rootProject.prepareRepo
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierExtension.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierExtension.kt
index 7b516ec..e0eb60c 100644
--- a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierExtension.kt
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifierExtension.kt
@@ -16,6 +16,7 @@
 
 package android.support.tools.jetifier.plugin.gradle
 
+import groovy.lang.Closure
 import org.gradle.api.Project
 import org.gradle.api.artifacts.Configuration
 import org.gradle.api.artifacts.Dependency
@@ -31,7 +32,6 @@
     /**
      * Adds dependency defined via string notation to be processed by jetifyLibs task.
      *
-     *
      * Example usage in Gradle:
      * dependencies {
      *   compile jetifier.process('groupId:artifactId:1.0')
@@ -42,21 +42,20 @@
     }
 
     /**
-     * Adds dependency defined via string notation to be processed by jetifyLibs task while also
-     * applying the given exclude rules.
-     *
+     * Adds dependency defined via string notation to be processed by jetifyLibs task. This version
+     * supports Gradle's configuration closure that is passed to the Gradle's DependencyHandler.
      *
      * Example usage in Gradle:
      * dependencies {
-     *   compile jetifier.processAndExclude('groupId:artifactId:1.0',
-     *     [group: 'some.package', module: 'moduleName'])
+     *   compile jetifier.process('groupId:artifactId:1.0') {
+     *     exclude group: 'groupId'
+     *
+     *     transitive = false
+     *   }
      * }
      */
-    fun processAndExclude(
-        dependencyNotation: String,
-        vararg excludes: Map<String, String>
-    ): FileCollection {
-        return processAndExclude(project.dependencies.create(dependencyNotation), *excludes)
+    fun process(dependencyNotation: String, closure: Closure<Any>): FileCollection {
+        return process(project.dependencies.create(dependencyNotation, closure))
     }
 
     /**
@@ -69,20 +68,6 @@
     }
 
     /**
-     * Adds dependency to be processed by jetifyLibs task while also applying the given excludes
-     * rules.
-     */
-    fun processAndExclude(
-        dependency: Dependency,
-        vararg excludes: Map<String, String>
-    ): FileCollection {
-        val configuration = project.configurations.detachedConfiguration()
-        configuration.dependencies.add(dependency)
-        excludes.forEach { configuration.exclude(it) }
-        return process(configuration)
-    }
-
-    /**
      * Adds dependencies defined via file collection to be processed by jetifyLibs task.
      *
      * Example usage in Gradle for a single file:
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyGlobalTask.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyGlobalTask.kt
index 4d35625..22f4308 100644
--- a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyGlobalTask.kt
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/JetifyGlobalTask.kt
@@ -48,7 +48,7 @@
 
         const val OUTPUT_DIR_APPENDIX = "jetifier"
 
-        fun resolveTask(project: Project) : JetifyGlobalTask {
+        fun resolveTask(project: Project): JetifyGlobalTask {
             val task = project.tasks.findByName(TASK_NAME) as? JetifyGlobalTask
             if (task != null) {
                 return task
@@ -61,7 +61,6 @@
 
     private val outputDir = File(project.buildDir, OUTPUT_DIR_APPENDIX)
 
-
     override fun getGroup() = GROUP_ID
 
     override fun getDescription() = DESCRIPTION
@@ -93,7 +92,7 @@
                 if (fileDep != null) {
                     fileDep.files.forEach {
                         dependenciesMap
-                            .getOrPut(it, { mutableSetOf<Dependency>() } )
+                            .getOrPut(it, { mutableSetOf<Dependency>() })
                             .add(fileDep)
                     }
                 } else {
@@ -108,7 +107,7 @@
                     detached.dependencies.add(dep)
                     detached.resolvedConfiguration.resolvedArtifacts.forEach {
                         dependenciesMap
-                            .getOrPut(it.file, { mutableSetOf<Dependency>() } )
+                            .getOrPut(it.file, { mutableSetOf<Dependency>() })
                             .add(dep)
                     }
                 }
@@ -116,21 +115,27 @@
         }
 
         // Process the files using Jetifier
-        val result = TasksCommon.processFiles(config, dependenciesMap.keys, project.logger, outputDir)
+        val result = TasksCommon.processFiles(config, dependenciesMap.keys, project.logger,
+            outputDir)
 
-        // Apply changes
         configurationsToProcess.forEach { conf ->
-            // Apply that on our set
-            result.filesToRemove.forEach { file ->
-                dependenciesMap[file]!!.forEach {
-                    conf.dependencies.remove(it)
+            // Remove files that we don't need anymore
+            dependenciesMap.keys
+                .toTypedArray()
+                .forEach { file ->
+                    if (!result.contains(file)) {
+                        dependenciesMap[file]!!.forEach {
+                            conf.dependencies.remove(it)
+                        }
+                    }
                 }
-            }
 
-            result.filesToAdd.forEach {
-                project.dependencies.add(conf.name, project.files(it))
+            // Add new generated files
+            result.forEach { file ->
+                if (!dependenciesMap.contains(file)) {
+                    project.dependencies.add(conf.name, project.files(file))
+                }
             }
         }
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/TasksCommon.kt b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/TasksCommon.kt
index dcc6375..88b5cc1 100644
--- a/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/TasksCommon.kt
+++ b/jetifier/jetifier/gradle-plugin/src/main/kotlin/android/support/tools/jetifier/plugin/gradle/TasksCommon.kt
@@ -17,7 +17,6 @@
 package android.support.tools.jetifier.plugin.gradle
 
 import android.support.tools.jetifier.core.Processor
-import android.support.tools.jetifier.core.TransformationResult
 import android.support.tools.jetifier.core.config.Config
 import android.support.tools.jetifier.core.utils.Log
 import org.gradle.api.logging.LogLevel
@@ -31,8 +30,12 @@
 
         var configFilePath: Path? = null
 
-
-        fun processFiles(config: Config, filesToProcess: Set<File>, logger: Logger, outputDir: File) : TransformationResult {
+        fun processFiles(
+            config: Config,
+            filesToProcess: Set<File>,
+            logger: Logger,
+            outputDir: File
+        ): Set<File> {
             outputDir.mkdirs()
 
             logger.log(LogLevel.DEBUG, "Jetifier will now process the following files:")
@@ -43,15 +46,18 @@
             // Hook to the gradle logger
             Log.logConsumer = JetifierLoggerAdapter(logger)
 
-            val processor = Processor(config)
-            return processor.transform(filesToProcess, outputDir.toPath())
+            val processor = Processor.createProcessor(config)
+            return processor.transform(
+                filesToProcess,
+                outputDir.toPath(),
+                outputIsDir = true,
+                copyUnmodifiedLibsAlso = false)
         }
 
-        fun shouldSkipArtifact(artifactId: String, groupId: String?, config: Config) : Boolean {
+        fun shouldSkipArtifact(artifactId: String, groupId: String?, config: Config): Boolean {
             return config.pomRewriteRules.any {
                 it.from.artifactId == artifactId && it.from.groupId == groupId
             }
         }
     }
-
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/gradlew b/jetifier/jetifier/gradlew
deleted file mode 120000
index 343e0d2..0000000
--- a/jetifier/jetifier/gradlew
+++ /dev/null
@@ -1 +0,0 @@
-../../gradlew
\ No newline at end of file
diff --git a/jetifier/jetifier/preprocessor/build.gradle b/jetifier/jetifier/preprocessor/build.gradle
index b688a9d..893b763 100644
--- a/jetifier/jetifier/preprocessor/build.gradle
+++ b/jetifier/jetifier/preprocessor/build.gradle
@@ -14,13 +14,14 @@
  * limitations under the License
  */
 
-version '1.0'
-
-apply plugin: "application"
+plugins {
+    id("SupportKotlinLibraryPlugin")
+    id("application")
+}
 
 mainClassName = "android.support.tools.jetifier.preprocessor.MainKt"
 
 dependencies {
-    compile project(':core')
+    compile project(':jetifier-core')
     compile group: 'commons-cli', name: 'commons-cli', version: '1.3.1'
-}
\ No newline at end of file
+}
diff --git a/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
old mode 100644
new mode 100755
index 2b61811..5ddc2df
--- a/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
+++ b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
@@ -18,6 +18,8 @@
 # Grabs all the support libraries and runs them through a preprocessor
 # using the default Jetifier config to generate the final mappings.
 
+set -e
+
 ROOT_DIR=$(dirname $(readlink -f $0))
 OUT_DIR="$ROOT_DIR/out"
 TEMP_LOG="$OUT_DIR/tempLog"
@@ -28,15 +30,16 @@
 GENERATED_CONFIG="$JETIFIER_DIR/core/src/main/resources/default.generated.config"
 PREPROCESSOR_DISTRO_PATH="$BUILD_DIR/preprocessor/build/distributions/preprocessor-1.0.zip"
 PREPROCESSOR_BIN_PATH="$OUT_DIR/preprocessor-1.0/bin/preprocessor"
-SUPPORT_LIBS_DOWNLOADED="$OUT_DIR/supportLibs"
+SUPPORT_LIBS_BUILD_NUMBER="4560478"
+SUPPORT_LIBS_DOWNLOADED="$OUT_DIR/supportLibs/downloaded"
+SUPPORT_LIBS_UNPACKED="$OUT_DIR/supportLibs/unpacked"
 
 GREEN='\033[0;32m'
 RED='\033[0;31m'
 NC='\033[0m' # No Color
 
-function exitAndFail() {
-	cat $TEMP_LOG
-	echo -e "${RED}FAILED${NC}"
+function die() {
+	echo "$@"
 	exit 1
 }
 
@@ -53,16 +56,38 @@
 
 function buildProjectUsingGradle() {
 	cd $1
-	sh gradlew clean build $2 > $TEMP_LOG --stacktrace || exitAndFail 2>&1
+	sh gradlew clean build $2 > $TEMP_LOG --stacktrace
 }
 
 
-rm -r $OUT_DIR
+rm -rf $OUT_DIR
 mkdir $OUT_DIR
 echo "OUT dir is at '$OUT_DIR'"
 
-printSectionStart "Downloading all affected support libraries"
-wget -nd -i $ROOT_DIR/repo-links -P $SUPPORT_LIBS_DOWNLOADED
+function getPreRenamedSupportLib() {
+	INPUT_FILENAME="top-of-tree-m2repository-$SUPPORT_LIBS_BUILD_NUMBER.zip"
+	printSectionStart "Downloading all affected support libraries"
+	mkdir -p "$SUPPORT_LIBS_DOWNLOADED"
+
+	if [ "$FETCH_ARTIFACT" == "" ]; then
+		if which fetch_artifact; then
+			FETCH_ARTIFACT="$(which fetch_artifact)"
+		fi
+	fi
+	if [ ! -f "$FETCH_ARTIFACT" ]; then
+		die "fetch_artifact not found. Please set the environment variable FETCH_ARTIFACT equal to the path of fetch_artifact and try again"
+	fi
+
+	cd "$SUPPORT_LIBS_DOWNLOADED"
+	"$FETCH_ARTIFACT" --bid "$SUPPORT_LIBS_BUILD_NUMBER" --target support_library "$INPUT_FILENAME" "$SUPPORT_LIBS_DOWNLOADED/support-lib-${SUPPORT_LIBS_BUILD_NUMBER}.zip"
+	"$FETCH_ARTIFACT" --bid "$SUPPORT_LIBS_BUILD_NUMBER" --target support_library_app_toolkit "$INPUT_FILENAME" "$SUPPORT_LIBS_DOWNLOADED/arch-${SUPPORT_LIBS_BUILD_NUMBER}.zip"
+	cd -
+
+
+	unzip -oj "$SUPPORT_LIBS_DOWNLOADED/support-lib-${SUPPORT_LIBS_BUILD_NUMBER}.zip" -d "$SUPPORT_LIBS_UNPACKED"
+	unzip -oj "$SUPPORT_LIBS_DOWNLOADED/arch-${SUPPORT_LIBS_BUILD_NUMBER}.zip" -d "$SUPPORT_LIBS_UNPACKED"
+}
+getPreRenamedSupportLib
 
 printSectionStart "Preparing Jetifier"
 buildProjectUsingGradle $JETIFIER_DIR
@@ -72,7 +97,7 @@
 echo "[OK] Copied & unziped jetifier preprocessor"
 
 printSectionStart "Preprocessing mappings on support libraries"
-sh $PREPROCESSOR_BIN_PATH -i "$SUPPORT_LIBS_DOWNLOADED" -o "$GENERATED_CONFIG" -c "$DEFAULT_CONFIG" -l verbose || exitAndFail
+sh $PREPROCESSOR_BIN_PATH -i "$SUPPORT_LIBS_UNPACKED" -o "$GENERATED_CONFIG" -c "$DEFAULT_CONFIG" -l verbose || exitAndFail
 echo "[OK] Done, config generated into $GENERATED_CONFIG"
 
 printSuccess
diff --git a/jetifier/jetifier/preprocessor/scripts/repo-links b/jetifier/jetifier/preprocessor/scripts/repo-links
deleted file mode 100644
index 961c149..0000000
--- a/jetifier/jetifier/preprocessor/scripts/repo-links
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License
-
-https://maven.google.com/com/android/support/animated-vector-drawable/27.0.1/animated-vector-drawable-27.0.1.aar
-https://maven.google.com/com/android/support/appcompat-v7/27.0.1/appcompat-v7-27.0.1.aar
-https://maven.google.com/com/android/support/cardview-v7/27.0.1/cardview-v7-27.0.1.aar
-https://maven.google.com/com/android/support/customtabs/27.0.1/customtabs-27.0.1.aar
-https://maven.google.com/com/android/support/design/27.0.1/design-27.0.1.aar
-https://maven.google.com/com/android/support/exifinterface/27.0.1/exifinterface-27.0.1.aar
-https://maven.google.com/com/android/support/gridlayout-v7/27.0.1/gridlayout-v7-27.0.1.aar
-https://maven.google.com/com/android/support/instantvideo/26.0.0-alpha1/instantvideo-26.0.0-alpha1.aar
-https://maven.google.com/com/android/support/leanback-v17/27.0.1/leanback-v17-27.0.1.aar
-https://maven.google.com/com/android/support/mediarouter-v7/27.0.1/mediarouter-v7-27.0.1.aar
-https://maven.google.com/com/android/support/multidex/1.0.2/multidex-1.0.2.aar
-https://maven.google.com/com/android/support/multidex-instrumentation/1.0.2/multidex-instrumentation-1.0.2.aar
-https://maven.google.com/com/android/support/palette-v7/27.0.1/palette-v7-27.0.1.aar
-https://maven.google.com/com/android/support/percent/27.0.1/percent-27.0.1.aar
-https://maven.google.com/com/android/support/preference-leanback-v17/27.0.1/preference-leanback-v17-27.0.1.aar
-https://maven.google.com/com/android/support/preference-v14/27.0.1/preference-v14-27.0.1.aar
-https://maven.google.com/com/android/support/preference-v7/27.0.1/preference-v7-27.0.1.aar
-https://maven.google.com/com/android/support/recommendation/27.0.1/recommendation-27.0.1.aar
-https://maven.google.com/com/android/support/recyclerview-v7/27.0.1/recyclerview-v7-27.0.1.aar
-https://maven.google.com/com/android/support/support-annotations/27.0.1/support-annotations-27.0.1.jar
-https://maven.google.com/com/android/support/support-compat/27.0.1/support-compat-27.0.1.aar
-https://maven.google.com/com/android/support/support-content/27.0.1/support-content-27.0.1.aar
-https://maven.google.com/com/android/support/support-core-ui/27.0.1/support-core-ui-27.0.1.aar
-https://maven.google.com/com/android/support/support-core-utils/27.0.1/support-core-utils-27.0.1.aar
-https://maven.google.com/com/android/support/support-dynamic-animation/27.0.1/support-dynamic-animation-27.0.1.aar
-https://maven.google.com/com/android/support/support-emoji/27.0.1/support-emoji-27.0.1.aar
-https://maven.google.com/com/android/support/support-emoji-appcompat/27.0.1/support-emoji-appcompat-27.0.1.aar
-https://maven.google.com/com/android/support/support-emoji-bundled/27.0.1/support-emoji-bundled-27.0.1.aar
-https://maven.google.com/com/android/support/support-fragment/27.0.1/support-fragment-27.0.1.aar
-https://maven.google.com/com/android/support/support-media-compat/27.0.1/support-media-compat-27.0.1.aar
-https://maven.google.com/com/android/support/support-tv-provider/27.0.1/support-tv-provider-27.0.1.aar
-https://maven.google.com/com/android/support/support-v13/27.0.1/support-v13-27.0.1.aar
-https://maven.google.com/com/android/support/support-v4/27.0.1/support-v4-27.0.1.aar
-https://maven.google.com/com/android/support/support-vector-drawable/27.0.1/support-vector-drawable-27.0.1.aar
-https://maven.google.com/com/android/support/transition/27.0.1/transition-27.0.1.aar
-https://maven.google.com/com/android/support/wear/27.0.1/wear-27.0.1.aar
-https://maven.google.com/com/android/support/wearable/27.0.1/wearable-27.0.1.aar
-https://maven.google.com/com/android/support/constraint/constraint-layout/1.0.2/constraint-layout-1.0.2.aar
diff --git a/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/ConfigGenerator.kt b/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/ConfigGenerator.kt
index ec12ac8..3f79553 100644
--- a/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/ConfigGenerator.kt
+++ b/jetifier/jetifier/preprocessor/src/main/kotlin/android/support/tools/jetifier/preprocessor/ConfigGenerator.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
 package android.support.tools.jetifier.preprocessor
 
 import android.support.tools.jetifier.core.archive.Archive
@@ -11,7 +27,7 @@
 
     companion object {
         private const val LEGAL_NOTICE =
-            "# Copyright (C) 2017 The Android Open Source Project\n" +
+            "# Copyright (C) 2018 The Android Open Source Project\n" +
             "#\n" +
             "# Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
             "# you may not use this file except in compliance with the License.\n" +
@@ -49,13 +65,14 @@
             }
         }
 
-        val map = mapper.generateMap()
+        val map = mapper.generateMap().mergetWith(config.typesMap)
+        map.reverseMapOrDie() // Check that map can be reversed
         val newConfig = config.setNewMap(map)
 
         saveConfigToFile(newConfig, outputConfigPath.toFile())
     }
 
-    private fun saveConfigToFile(configToSave: Config, outputFile : File) {
+    private fun saveConfigToFile(configToSave: Config, outputFile: File) {
         val sb = StringBuilder()
         sb.append(LEGAL_NOTICE)
         sb.append("\n")
diff --git a/jetifier/jetifier/settings.gradle b/jetifier/jetifier/settings.gradle
deleted file mode 100644
index 7d13b73..0000000
--- a/jetifier/jetifier/settings.gradle
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *       http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-rootProject.name = 'jetifier'
-include 'core'
-include 'gradle-plugin'
-include 'standalone'
-include 'preprocessor'
-
diff --git a/jetifier/jetifier/standalone/build.gradle b/jetifier/jetifier/standalone/build.gradle
index 8814d50..3caa366 100644
--- a/jetifier/jetifier/standalone/build.gradle
+++ b/jetifier/jetifier/standalone/build.gradle
@@ -14,14 +14,22 @@
  * limitations under the License
  */
 
-version '1.0'
-
-apply plugin: "application"
+plugins {
+    id("SupportKotlinLibraryPlugin")
+    id("application")
+}
 
 mainClassName = "android.support.tools.jetifier.standalone.MainKt"
 
 dependencies {
-    compile project(':core')
+    compile project(':jetifier-core')
     compile group: 'commons-cli', name: 'commons-cli', version: '1.3.1'
 }
 
+task dist(type: Copy) {
+  from project.tasks.findByPath("distZip") // defined by application plugin
+
+  destinationDir rootProject.distDir // defined by support library plugin
+}
+rootProject.tasks["buildOnServer"].dependsOn(dist)
+
diff --git a/jetifier/jetifier/standalone/src/main/kotlin/android/support/tools/jetifier/standalone/Main.kt b/jetifier/jetifier/standalone/src/main/kotlin/android/support/tools/jetifier/standalone/Main.kt
index de310e4..8fdb78e 100644
--- a/jetifier/jetifier/standalone/src/main/kotlin/android/support/tools/jetifier/standalone/Main.kt
+++ b/jetifier/jetifier/standalone/src/main/kotlin/android/support/tools/jetifier/standalone/Main.kt
@@ -27,6 +27,7 @@
 import org.apache.commons.cli.Options
 import org.apache.commons.cli.ParseException
 import java.io.File
+import java.nio.file.Path
 import java.nio.file.Paths
 
 class Main {
@@ -37,16 +38,27 @@
 
         val OPTIONS = Options()
         val OPTION_INPUT = createOption("i", "Input libraries paths", multiple = true)
-        val OPTION_OUTPUT = createOption("o", "Output config path")
+        val OPTION_OUTPUT_DIR = createOption("outputdir", "Output directory path",
+                isRequired = false)
+        val OPTION_OUTPUT_FILE = createOption("outputfile", "Output file", isRequired = false)
         val OPTION_CONFIG = createOption("c", "Input config path", isRequired = false)
-        val OPTION_LOG_LEVEL = createOption("l", "Logging level. debug, verbose, default",
+        val OPTION_LOG_LEVEL = createOption("l", "Logging level. debug, verbose, error, info " +
+            "(default)", isRequired = false)
+        val OPTION_REVERSED = createOption("r", "Run reversed process", hasArgs = false,
             isRequired = false)
+        val OPTION_REWRITE_SUPPORT_LIB = createOption("s", "If set, all libraries being rewritten" +
+            " are assumed to be part of Support Library. Otherwise only general dependencies are" +
+            " expected.",
+            hasArgs = false, isRequired = false)
 
-        private fun createOption(argName: String,
-                                 desc: String,
-                                 isRequired: Boolean = true,
-                                 multiple: Boolean = false) : Option {
-            val op = Option(argName, true, desc)
+        private fun createOption(
+            argName: String,
+            desc: String,
+            hasArgs: Boolean = true,
+            isRequired: Boolean = true,
+            multiple: Boolean = false
+        ): Option {
+            val op = Option(argName, hasArgs, desc)
             op.isRequired = isRequired
             if (multiple) {
                 op.args = Option.UNLIMITED_VALUES
@@ -56,7 +68,7 @@
         }
     }
 
-    fun run(args : Array<String>) {
+    fun run(args: Array<String>) {
         val cmd = parseCmdLine(args)
         if (cmd == null) {
             System.exit(1)
@@ -66,9 +78,31 @@
         Log.setLevel(cmd.getOptionValue(OPTION_LOG_LEVEL.opt))
 
         val inputLibraries = cmd.getOptionValues(OPTION_INPUT.opt).map { File(it) }.toSet()
-        val outputPath = Paths.get(cmd.getOptionValue(OPTION_OUTPUT.opt))
+        val outputDir = cmd.getOptionValue(OPTION_OUTPUT_DIR.opt)
+        val outputFile = cmd.getOptionValue(OPTION_OUTPUT_FILE.opt)
+        if (outputDir == null && outputFile == null) {
+            throw IllegalArgumentException("Must specify -outputdir or -outputfile")
+        }
+        if (outputDir != null && outputFile != null) {
+            throw IllegalArgumentException("Cannot specify both -outputdir and -outputfile")
+        }
+        if (inputLibraries.size > 1 && outputFile != null) {
+            throw IllegalArgumentException(
+                    "Cannot specify -outputfile when multiple input libraries are given")
+        }
 
-        val config : Config?
+        var outputIsDir = false
+        fun chooseOutputPath(): Path {
+            if (outputFile == null) {
+                outputIsDir = true
+                return Paths.get(outputDir)
+            } else {
+                return Paths.get(outputFile)
+            }
+        }
+        val outputPath = chooseOutputPath()
+
+        val config: Config?
         if (cmd.hasOption(OPTION_CONFIG.opt)) {
             val configPath = Paths.get(cmd.getOptionValue(OPTION_CONFIG.opt))
             config = ConfigParser.loadFromFile(configPath)
@@ -82,11 +116,16 @@
             return
         }
 
-        val processor = Processor(config)
-        processor.transform(inputLibraries, outputPath)
+        val isReversed = cmd.hasOption(OPTION_REVERSED.opt)
+        val rewriteSupportLib = cmd.hasOption(OPTION_REWRITE_SUPPORT_LIB.opt)
+        val processor = Processor.createProcessor(
+            config = config,
+            reversedMode = isReversed,
+            rewritingSupportLib = rewriteSupportLib)
+        processor.transform(inputLibraries, outputPath, outputIsDir)
     }
 
-    private fun parseCmdLine(args : Array<String>) : CommandLine? {
+    private fun parseCmdLine(args: Array<String>): CommandLine? {
         try {
             return DefaultParser().parse(OPTIONS, args)
         } catch (e: ParseException) {
@@ -95,10 +134,8 @@
         }
         return null
     }
-
 }
 
-
-fun main(args : Array<String>) {
+fun main(args: Array<String>) {
     Main().run(args)
 }
\ No newline at end of file
diff --git a/leanback/Android.mk b/leanback/Android.mk
deleted file mode 100644
index e39261f..0000000
--- a/leanback/Android.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v17-leanback \
-#       android-support-v7-recyclerview \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE := android-support-v17-leanback
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, common) \
-    $(call all-java-files-under, jbmr2) \
-    $(call all-java-files-under, kitkat) \
-    $(call all-java-files-under, api21) \
-    $(call all-java-files-under, src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v7-recyclerview \
-    android-support-compat \
-    android-support-core-ui \
-    android-support-media-compat \
-    android-support-fragment
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/leanback/AndroidManifest.xml b/leanback/AndroidManifest.xml
deleted file mode 100644
index 59ec5c0..0000000
--- a/leanback/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v17.leanback">
-    <uses-sdk android:minSdkVersion="17"/>
-</manifest>
diff --git a/leanback/api/27.1.0.ignore b/leanback/api/27.1.0.ignore
new file mode 100644
index 0000000..ab7d797
--- /dev/null
+++ b/leanback/api/27.1.0.ignore
@@ -0,0 +1,26 @@
+8ce8f86
+b6b0c56
+58f32b9
+4b6dd02
+ea5f43d
+a0b0ae1
+61c6f5a
+077595e
+68eee39
+1788dd5
+b346683
+ad9b56e
+d472c9a
+a7ab9bd
+cd00c06
+a30ba0c
+536faee
+18d0545
+d1f97bd
+1a8fcc1
+b12407d
+88e0d29
+be0db9a
+c547c4e
+666fa9b
+397d4c0
diff --git a/leanback/api/current.txt b/leanback/api/current.txt
index 3a5a22b..ebb5137 100644
--- a/leanback/api/current.txt
+++ b/leanback/api/current.txt
@@ -2430,8 +2430,8 @@
     ctor public PlaybackControlsRow.ClosedCaptioningAction(android.content.Context, int);
     field public static final int INDEX_OFF = 0; // 0x0
     field public static final int INDEX_ON = 1; // 0x1
-    field public static deprecated int OFF;
-    field public static deprecated int ON;
+    field public static final deprecated int OFF = 0; // 0x0
+    field public static final deprecated int ON = 1; // 0x1
   }
 
   public static class PlaybackControlsRow.FastForwardAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
@@ -2444,8 +2444,8 @@
     ctor public PlaybackControlsRow.HighQualityAction(android.content.Context, int);
     field public static final int INDEX_OFF = 0; // 0x0
     field public static final int INDEX_ON = 1; // 0x1
-    field public static deprecated int OFF;
-    field public static deprecated int ON;
+    field public static final deprecated int OFF = 0; // 0x0
+    field public static final deprecated int ON = 1; // 0x1
   }
 
   public static class PlaybackControlsRow.MoreActions extends android.support.v17.leanback.widget.Action {
@@ -2481,20 +2481,20 @@
     ctor public PlaybackControlsRow.PlayPauseAction(android.content.Context);
     field public static final int INDEX_PAUSE = 1; // 0x1
     field public static final int INDEX_PLAY = 0; // 0x0
-    field public static deprecated int PAUSE;
-    field public static deprecated int PLAY;
+    field public static final deprecated int PAUSE = 1; // 0x1
+    field public static final deprecated int PLAY = 0; // 0x0
   }
 
   public static class PlaybackControlsRow.RepeatAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
     ctor public PlaybackControlsRow.RepeatAction(android.content.Context);
     ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int);
     ctor public PlaybackControlsRow.RepeatAction(android.content.Context, int, int);
-    field public static deprecated int ALL;
+    field public static final deprecated int ALL = 1; // 0x1
     field public static final int INDEX_ALL = 1; // 0x1
     field public static final int INDEX_NONE = 0; // 0x0
     field public static final int INDEX_ONE = 2; // 0x2
-    field public static deprecated int NONE;
-    field public static deprecated int ONE;
+    field public static final deprecated int NONE = 0; // 0x0
+    field public static final deprecated int ONE = 2; // 0x2
   }
 
   public static class PlaybackControlsRow.RewindAction extends android.support.v17.leanback.widget.PlaybackControlsRow.MultiAction {
@@ -2507,8 +2507,8 @@
     ctor public PlaybackControlsRow.ShuffleAction(android.content.Context, int);
     field public static final int INDEX_OFF = 0; // 0x0
     field public static final int INDEX_ON = 1; // 0x1
-    field public static deprecated int OFF;
-    field public static deprecated int ON;
+    field public static final deprecated int OFF = 0; // 0x0
+    field public static final deprecated int ON = 1; // 0x1
   }
 
   public static class PlaybackControlsRow.SkipNextAction extends android.support.v17.leanback.widget.Action {
@@ -2523,8 +2523,8 @@
     ctor public PlaybackControlsRow.ThumbsAction(int, android.content.Context, int, int);
     field public static final int INDEX_OUTLINE = 1; // 0x1
     field public static final int INDEX_SOLID = 0; // 0x0
-    field public static deprecated int OUTLINE;
-    field public static deprecated int SOLID;
+    field public static final deprecated int OUTLINE = 1; // 0x1
+    field public static final deprecated int SOLID = 0; // 0x0
   }
 
   public static class PlaybackControlsRow.ThumbsDownAction extends android.support.v17.leanback.widget.PlaybackControlsRow.ThumbsAction {
diff --git a/leanback/build.gradle b/leanback/build.gradle
index 05a91df..36ba9e2 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -21,14 +21,12 @@
 
 android {
     sourceSets {
-        main.java.srcDirs = [
+        main.java.srcDirs += [
                 'common',
                 'jbmr2',
                 'kitkat',
                 'api21',
-                'src'
         ]
-        main.res.srcDir 'res'
     }
 }
 
@@ -39,6 +37,5 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2014"
     description = "Android Support Leanback v17"
-    legacySourceLocation = true
     minSdkVersion = 17
 }
diff --git a/leanback/res/values-mr/strings.xml b/leanback/res/values-mr/strings.xml
deleted file mode 100644
index 8629ef1..0000000
--- a/leanback/res/values-mr/strings.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-Copyright (C) 2014 The Android Open Source Project
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="lb_navigation_menu_contentDescription" msgid="6215811486591629025">"नेव्हिगेशन मेनू"</string>
-    <string name="orb_search_action" msgid="5651268540267663887">"शोध क्रिया"</string>
-    <string name="lb_search_bar_hint" msgid="8325490927970116252">"शोधा"</string>
-    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"शोधण्यासाठी बोला"</string>
-    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधा"</string>
-    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधण्यासाठी बोला"</string>
-    <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
-    <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
-    <string name="lb_playback_controls_play" msgid="731953341987346903">"प्ले करा"</string>
-    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"विराम द्या"</string>
-    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"फास्ट फॉरवर्ड करा"</string>
-    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"फास्ट फॉरवर्ड %1$dX"</string>
-    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"रिवाईँड करा"</string>
-    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"रीवाईंड %1$dX"</string>
-    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"पुढील वगळा"</string>
-    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"मागील वगळा"</string>
-    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"अधिक क्रिया"</string>
-    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"वर अंगठा निवड रद्द करा"</string>
-    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"वर अंगठा निवडा"</string>
-    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"खाली अंगठा निवड रद्द करा"</string>
-    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"खाली अंगठा निवडा"</string>
-    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"काहीही पुनरावृत्ती करू नका"</string>
-    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"सर्व पुनरावृत्ती करा"</string>
-    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"एक पुनरावृत्ती करा"</string>
-    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"शफल करा सक्षम करा"</string>
-    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"शफल करा अक्षम करा"</string>
-    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"उच्च गुणवत्ता सक्षम करा"</string>
-    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करा"</string>
-    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षके सक्षम करा"</string>
-    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"सबटायटल अक्षम करा"</string>
-    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"चित्र मोडमध्ये चित्र प्रविष्ट करा"</string>
-    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
-    <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_media_player_error" msgid="3650250994187305396">"मीडियाप्लेअर एरर कोड %1$d अतिरिक्त %2$d"</string>
-    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"सुरू करा"</string>
-    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"पुढील"</string>
-</resources>
diff --git a/leanback/src/android/support/v17/leanback/app/BackgroundManager.java b/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
deleted file mode 100644
index 262a5a6..0000000
--- a/leanback/src/android/support/v17/leanback/app/BackgroundManager.java
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.animation.Animator;
-import android.animation.ValueAnimator;
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.os.Build;
-import android.os.Handler;
-import android.support.annotation.ColorInt;
-import android.support.annotation.NonNull;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.widget.BackgroundHelper;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.graphics.drawable.DrawableCompat;
-import android.support.v4.view.animation.FastOutLinearInInterpolator;
-import android.util.Log;
-import android.view.View;
-import android.view.Window;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Supports background image continuity between multiple Activities.
- *
- * <p>An Activity should instantiate a BackgroundManager and {@link #attach}
- * to the Activity's window.  When the Activity is started, the background is
- * initialized to the current background values stored in a continuity service.
- * The background continuity service is updated as the background is updated.
- *
- * <p>At some point, for example when it is stopped, the Activity may release
- * its background state.
- *
- * <p>When an Activity is resumed, if the BackgroundManager has not been
- * released, the continuity service is updated from the BackgroundManager state.
- * If the BackgroundManager was released, the BackgroundManager inherits the
- * current state from the continuity service.
- *
- * <p>When the last Activity is destroyed, the background state is reset.
- *
- * <p>Backgrounds consist of several layers, from back to front:
- * <ul>
- *   <li>the background Drawable of the theme</li>
- *   <li>a solid color (set via {@link #setColor})</li>
- *   <li>two Drawables, previous and current (set via {@link #setBitmap} or
- *   {@link #setDrawable}), which may be in transition</li>
- * </ul>
- *
- * <p>BackgroundManager holds references to potentially large bitmap Drawables.
- * Call {@link #release} to release these references when the Activity is not
- * visible.
- */
-// TODO: support for multiple app processes requires a proper android service
-// instead of the shared memory "service" implemented here. Such a service could
-// support continuity between fragments of different applications if desired.
-public final class BackgroundManager {
-
-    static final String TAG = "BackgroundManager";
-    static final boolean DEBUG = false;
-
-    static final int FULL_ALPHA = 255;
-    private static final int CHANGE_BG_DELAY_MS = 500;
-    private static final int FADE_DURATION = 500;
-
-    private static final String FRAGMENT_TAG = BackgroundManager.class.getCanonicalName();
-
-    Activity mContext;
-    Handler mHandler;
-    private View mBgView;
-    private BackgroundContinuityService mService;
-    private int mThemeDrawableResourceId;
-    private BackgroundFragment mFragmentState;
-    private boolean mAutoReleaseOnStop = true;
-
-    private int mHeightPx;
-    private int mWidthPx;
-    int mBackgroundColor;
-    Drawable mBackgroundDrawable;
-    private boolean mAttached;
-    private long mLastSetTime;
-
-    private final Interpolator mAccelerateInterpolator;
-    private final Interpolator mDecelerateInterpolator;
-    final ValueAnimator mAnimator;
-
-    static class BitmapDrawable extends Drawable {
-
-        static final class ConstantState extends Drawable.ConstantState {
-            final Bitmap mBitmap;
-            final Matrix mMatrix;
-            final Paint mPaint = new Paint();
-
-            ConstantState(Bitmap bitmap, Matrix matrix) {
-                mBitmap = bitmap;
-                mMatrix = matrix != null ? matrix : new Matrix();
-                mPaint.setFilterBitmap(true);
-            }
-
-            ConstantState(ConstantState copyFrom) {
-                mBitmap = copyFrom.mBitmap;
-                mMatrix = copyFrom.mMatrix != null ? new Matrix(copyFrom.mMatrix) : new Matrix();
-                if (copyFrom.mPaint.getAlpha() != FULL_ALPHA) {
-                    mPaint.setAlpha(copyFrom.mPaint.getAlpha());
-                }
-                if (copyFrom.mPaint.getColorFilter() != null) {
-                    mPaint.setColorFilter(copyFrom.mPaint.getColorFilter());
-                }
-                mPaint.setFilterBitmap(true);
-            }
-
-            @Override
-            public Drawable newDrawable() {
-                return new BitmapDrawable(this);
-            }
-
-            @Override
-            public int getChangingConfigurations() {
-                return 0;
-            }
-        }
-
-        ConstantState mState;
-        boolean mMutated;
-
-        BitmapDrawable(Resources resources, Bitmap bitmap) {
-            this(resources, bitmap, null);
-        }
-
-        BitmapDrawable(Resources resources, Bitmap bitmap, Matrix matrix) {
-            mState = new ConstantState(bitmap, matrix);
-        }
-
-        BitmapDrawable(ConstantState state) {
-            mState = state;
-        }
-
-        Bitmap getBitmap() {
-            return mState.mBitmap;
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            if (mState.mBitmap == null) {
-                return;
-            }
-            if (mState.mPaint.getAlpha() < FULL_ALPHA && mState.mPaint.getColorFilter() != null) {
-                throw new IllegalStateException("Can't draw with translucent alpha and color filter");
-            }
-            canvas.drawBitmap(mState.mBitmap, mState.mMatrix, mState.mPaint);
-        }
-
-        @Override
-        public int getOpacity() {
-            return android.graphics.PixelFormat.TRANSLUCENT;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-            mutate();
-            if (mState.mPaint.getAlpha() != alpha) {
-                mState.mPaint.setAlpha(alpha);
-                invalidateSelf();
-            }
-        }
-
-        /**
-         * Does not invalidateSelf to avoid recursion issues.
-         * Caller must ensure appropriate invalidation.
-         */
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-            mutate();
-            mState.mPaint.setColorFilter(cf);
-            invalidateSelf();
-        }
-
-        @Override
-        public ColorFilter getColorFilter() {
-            return mState.mPaint.getColorFilter();
-        }
-
-        @Override
-        public ConstantState getConstantState() {
-            return mState;
-        }
-
-        @NonNull
-        @Override
-        public Drawable mutate() {
-            if (!mMutated) {
-                mMutated = true;
-                mState = new ConstantState(mState);
-            }
-            return this;
-        }
-    }
-
-    static final class DrawableWrapper {
-        int mAlpha = FULL_ALPHA;
-        final Drawable mDrawable;
-
-        public DrawableWrapper(Drawable drawable) {
-            mDrawable = drawable;
-        }
-        public DrawableWrapper(DrawableWrapper wrapper, Drawable drawable) {
-            mDrawable = drawable;
-            mAlpha = wrapper.mAlpha;
-        }
-
-        public Drawable getDrawable() {
-            return mDrawable;
-        }
-
-        public void setColor(int color) {
-            ((ColorDrawable) mDrawable).setColor(color);
-        }
-    }
-
-    static final class TranslucentLayerDrawable extends LayerDrawable {
-        DrawableWrapper[] mWrapper;
-        int mAlpha = FULL_ALPHA;
-        boolean mSuspendInvalidation;
-        WeakReference<BackgroundManager> mManagerWeakReference;
-
-        TranslucentLayerDrawable(BackgroundManager manager, Drawable[] drawables) {
-            super(drawables);
-            mManagerWeakReference = new WeakReference(manager);
-            int count = drawables.length;
-            mWrapper = new DrawableWrapper[count];
-            for (int i = 0; i < count; i++) {
-                mWrapper[i] = new DrawableWrapper(drawables[i]);
-            }
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-            if (mAlpha != alpha) {
-                mAlpha = alpha;
-                invalidateSelf();
-                BackgroundManager manager = mManagerWeakReference.get();
-                if (manager != null) {
-                    manager.postChangeRunnable();
-                }
-            }
-        }
-
-        void setWrapperAlpha(int wrapperIndex, int alpha) {
-            if (mWrapper[wrapperIndex] != null) {
-                mWrapper[wrapperIndex].mAlpha = alpha;
-                invalidateSelf();
-            }
-        }
-
-        // Queried by system transitions
-        @Override
-        public int getAlpha() {
-            return mAlpha;
-        }
-
-        @Override
-        public Drawable mutate() {
-            Drawable drawable = super.mutate();
-            int count = getNumberOfLayers();
-            for (int i = 0; i < count; i++) {
-                if (mWrapper[i] != null) {
-                    mWrapper[i] = new DrawableWrapper(mWrapper[i], getDrawable(i));
-                }
-            }
-            return drawable;
-        }
-
-        @Override
-        public int getOpacity() {
-            return PixelFormat.TRANSLUCENT;
-        }
-
-        @Override
-        public boolean setDrawableByLayerId(int id, Drawable drawable) {
-            return updateDrawable(id, drawable) != null;
-        }
-
-        public DrawableWrapper updateDrawable(int id, Drawable drawable) {
-            super.setDrawableByLayerId(id, drawable);
-            for (int i = 0; i < getNumberOfLayers(); i++) {
-                if (getId(i) == id) {
-                    mWrapper[i] = new DrawableWrapper(drawable);
-                    // Must come after mWrapper was updated so it can be seen by updateColorFilter
-                    invalidateSelf();
-                    return mWrapper[i];
-                }
-            }
-            return null;
-        }
-
-        public void clearDrawable(int id, Context context) {
-            for (int i = 0; i < getNumberOfLayers(); i++) {
-                if (getId(i) == id) {
-                    mWrapper[i] = null;
-                    if (!(getDrawable(i) instanceof EmptyDrawable)) {
-                        super.setDrawableByLayerId(id, createEmptyDrawable(context));
-                    }
-                    break;
-                }
-            }
-        }
-
-        public int findWrapperIndexById(int id) {
-            for (int i = 0; i < getNumberOfLayers(); i++) {
-                if (getId(i) == id) {
-                    return i;
-                }
-            }
-            return -1;
-        }
-
-        @Override
-        public void invalidateDrawable(Drawable who) {
-            // Prevent invalidate when temporarily change child drawable's alpha in draw()
-            if (!mSuspendInvalidation) {
-                super.invalidateDrawable(who);
-            }
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            for (int i = 0; i < mWrapper.length; i++) {
-                final Drawable d;
-                // For each child drawable, we multiple Wrapper's alpha and LayerDrawable's alpha
-                // temporarily using mSuspendInvalidation to suppress invalidate event.
-                if (mWrapper[i] != null && (d = mWrapper[i].getDrawable()) != null) {
-                    int alpha = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
-                            ? DrawableCompat.getAlpha(d) : FULL_ALPHA;
-                    final int savedAlpha = alpha;
-                    int multiple = 0;
-                    if (mAlpha < FULL_ALPHA) {
-                        alpha = alpha * mAlpha;
-                        multiple++;
-                    }
-                    if (mWrapper[i].mAlpha < FULL_ALPHA) {
-                        alpha = alpha * mWrapper[i].mAlpha;
-                        multiple++;
-                    }
-                    if (multiple == 0) {
-                        d.draw(canvas);
-                    } else {
-                        if (multiple == 1) {
-                            alpha = alpha / FULL_ALPHA;
-                        } else if (multiple == 2) {
-                            alpha = alpha / (FULL_ALPHA * FULL_ALPHA);
-                        }
-                        try {
-                            mSuspendInvalidation = true;
-                            d.setAlpha(alpha);
-                            d.draw(canvas);
-                            d.setAlpha(savedAlpha);
-                        } finally {
-                            mSuspendInvalidation = false;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    TranslucentLayerDrawable createTranslucentLayerDrawable(
-            LayerDrawable layerDrawable) {
-        int numChildren = layerDrawable.getNumberOfLayers();
-        Drawable[] drawables = new Drawable[numChildren];
-        for (int i = 0; i < numChildren; i++) {
-            drawables[i] = layerDrawable.getDrawable(i);
-        }
-        TranslucentLayerDrawable result = new TranslucentLayerDrawable(this, drawables);
-        for (int i = 0; i < numChildren; i++) {
-            result.setId(i, layerDrawable.getId(i));
-        }
-        return result;
-    }
-
-    TranslucentLayerDrawable mLayerDrawable;
-    int mImageInWrapperIndex;
-    int mImageOutWrapperIndex;
-    ChangeBackgroundRunnable mChangeRunnable;
-    private boolean mChangeRunnablePending;
-
-    private final Animator.AnimatorListener mAnimationListener = new Animator.AnimatorListener() {
-        final Runnable mRunnable = new Runnable() {
-            @Override
-            public void run() {
-                postChangeRunnable();
-            }
-        };
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-        }
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            if (mLayerDrawable != null) {
-                mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
-            }
-            mHandler.post(mRunnable);
-        }
-        @Override
-        public void onAnimationCancel(Animator animation) {
-        }
-    };
-
-    private final ValueAnimator.AnimatorUpdateListener mAnimationUpdateListener =
-            new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            int fadeInAlpha = (Integer) animation.getAnimatedValue();
-            if (mImageInWrapperIndex != -1) {
-                mLayerDrawable.setWrapperAlpha(mImageInWrapperIndex, fadeInAlpha);
-            }
-        }
-    };
-
-    /**
-     * Shared memory continuity service.
-     */
-    private static class BackgroundContinuityService {
-        private static final String TAG = "BackgroundContinuity";
-        private static boolean DEBUG = BackgroundManager.DEBUG;
-
-        private static BackgroundContinuityService sService = new BackgroundContinuityService();
-
-        private int mColor;
-        private Drawable mDrawable;
-        private int mCount;
-
-        /** Single cache of theme drawable */
-        private int mLastThemeDrawableId;
-        private WeakReference<Drawable.ConstantState> mLastThemeDrawableState;
-
-        private BackgroundContinuityService() {
-            reset();
-        }
-
-        private void reset() {
-            mColor = Color.TRANSPARENT;
-            mDrawable = null;
-        }
-
-        public static BackgroundContinuityService getInstance() {
-            final int count = sService.mCount++;
-            if (DEBUG) Log.v(TAG, "Returning instance with new count " + count);
-            return sService;
-        }
-
-        public void unref() {
-            if (mCount <= 0) throw new IllegalStateException("Can't unref, count " + mCount);
-            if (--mCount == 0) {
-                if (DEBUG) Log.v(TAG, "mCount is zero, resetting");
-                reset();
-            }
-        }
-        public int getColor() {
-            return mColor;
-        }
-        public Drawable getDrawable() {
-            return mDrawable;
-        }
-        public void setColor(int color) {
-            mColor = color;
-            mDrawable = null;
-        }
-        public void setDrawable(Drawable drawable) {
-            mDrawable = drawable;
-        }
-        public Drawable getThemeDrawable(Context context, int themeDrawableId) {
-            Drawable drawable = null;
-            if (mLastThemeDrawableState != null && mLastThemeDrawableId == themeDrawableId) {
-                Drawable.ConstantState drawableState = mLastThemeDrawableState.get();
-                if (DEBUG) Log.v(TAG, "got cached theme drawable state " + drawableState);
-                if (drawableState != null) {
-                    drawable = drawableState.newDrawable();
-                }
-            }
-            if (drawable == null) {
-                drawable = ContextCompat.getDrawable(context, themeDrawableId);
-                if (DEBUG) Log.v(TAG, "loaded theme drawable " + drawable);
-                mLastThemeDrawableState = new WeakReference<Drawable.ConstantState>(
-                        drawable.getConstantState());
-                mLastThemeDrawableId = themeDrawableId;
-            }
-            // No mutate required because this drawable is never manipulated.
-            return drawable;
-        }
-    }
-
-    Drawable getDefaultDrawable() {
-        if (mBackgroundColor != Color.TRANSPARENT) {
-            return new ColorDrawable(mBackgroundColor);
-        } else {
-            return getThemeDrawable();
-        }
-    }
-
-    private Drawable getThemeDrawable() {
-        Drawable drawable = null;
-        if (mThemeDrawableResourceId != -1) {
-            drawable = mService.getThemeDrawable(mContext, mThemeDrawableResourceId);
-        }
-        if (drawable == null) {
-            drawable = createEmptyDrawable(mContext);
-        }
-        return drawable;
-    }
-
-    /**
-     * Returns the BackgroundManager associated with the given Activity.
-     * <p>
-     * The BackgroundManager will be created on-demand for each individual
-     * Activity. Subsequent calls will return the same BackgroundManager created
-     * for this Activity.
-     */
-    public static BackgroundManager getInstance(Activity activity) {
-        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
-                .findFragmentByTag(FRAGMENT_TAG);
-        if (fragment != null) {
-            BackgroundManager manager = fragment.getBackgroundManager();
-            if (manager != null) {
-                return manager;
-            }
-            // manager is null: this is a fragment restored by FragmentManager,
-            // fall through to create a BackgroundManager attach to it.
-        }
-        return new BackgroundManager(activity);
-    }
-
-    private BackgroundManager(Activity activity) {
-        mContext = activity;
-        mService = BackgroundContinuityService.getInstance();
-        mHeightPx = mContext.getResources().getDisplayMetrics().heightPixels;
-        mWidthPx = mContext.getResources().getDisplayMetrics().widthPixels;
-        mHandler = new Handler();
-
-        Interpolator defaultInterpolator = new FastOutLinearInInterpolator();
-        mAccelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.anim.accelerate_interpolator);
-        mDecelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.anim.decelerate_interpolator);
-
-        mAnimator = ValueAnimator.ofInt(0, FULL_ALPHA);
-        mAnimator.addListener(mAnimationListener);
-        mAnimator.addUpdateListener(mAnimationUpdateListener);
-        mAnimator.setInterpolator(defaultInterpolator);
-
-        TypedArray ta = activity.getTheme().obtainStyledAttributes(new int[] {
-                android.R.attr.windowBackground });
-        mThemeDrawableResourceId = ta.getResourceId(0, -1);
-        if (mThemeDrawableResourceId < 0) {
-            if (DEBUG) Log.v(TAG, "BackgroundManager no window background resource!");
-        }
-        ta.recycle();
-
-        createFragment(activity);
-    }
-
-    private void createFragment(Activity activity) {
-        // Use a fragment to ensure the background manager gets detached properly.
-        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
-                .findFragmentByTag(FRAGMENT_TAG);
-        if (fragment == null) {
-            fragment = new BackgroundFragment();
-            activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
-        } else {
-            if (fragment.getBackgroundManager() != null) {
-                throw new IllegalStateException("Created duplicated BackgroundManager for same "
-                        + "activity, please use getInstance() instead");
-            }
-        }
-        fragment.setBackgroundManager(this);
-        mFragmentState = fragment;
-    }
-
-    DrawableWrapper getImageInWrapper() {
-        return mLayerDrawable == null
-                ? null : mLayerDrawable.mWrapper[mImageInWrapperIndex];
-    }
-
-    DrawableWrapper getImageOutWrapper() {
-        return mLayerDrawable == null
-                ? null : mLayerDrawable.mWrapper[mImageOutWrapperIndex];
-    }
-
-    /**
-     * Synchronizes state when the owning Activity is started.
-     * At that point the view becomes visible.
-     */
-    void onActivityStart() {
-        updateImmediate();
-    }
-
-    void onStop() {
-        if (isAutoReleaseOnStop()) {
-            release();
-        }
-    }
-
-    void onResume() {
-        if (DEBUG) Log.v(TAG, "onResume " + this);
-        postChangeRunnable();
-    }
-
-    private void syncWithService() {
-        int color = mService.getColor();
-        Drawable drawable = mService.getDrawable();
-
-        if (DEBUG) Log.v(TAG, "syncWithService color " + Integer.toHexString(color)
-                + " drawable " + drawable);
-
-        mBackgroundColor = color;
-        mBackgroundDrawable = drawable == null ? null :
-            drawable.getConstantState().newDrawable().mutate();
-
-        updateImmediate();
-    }
-
-    /**
-     * Makes the background visible on the given Window. The background manager must be attached
-     * when the background is set.
-     */
-    public void attach(Window window) {
-        attachToViewInternal(window.getDecorView());
-    }
-
-    /**
-     * Sets the resource id for the drawable to be shown when there is no background set.
-     * Overrides the window background drawable from the theme. This should
-     * be called before attaching.
-     */
-    public void setThemeDrawableResourceId(int resourceId) {
-        mThemeDrawableResourceId = resourceId;
-    }
-
-    /**
-     * Adds the composite drawable to the given view.
-     */
-    public void attachToView(View sceneRoot) {
-        attachToViewInternal(sceneRoot);
-        // clear background to reduce overdraw since the View will act as background.
-        // Activity transition below O has ghost effect for null window background where we
-        // need set a transparent background to force redraw the whole window.
-        mContext.getWindow().getDecorView().setBackground(
-                Build.VERSION.SDK_INT >= 26 ? null : new ColorDrawable(Color.TRANSPARENT));
-    }
-
-    void attachToViewInternal(View sceneRoot) {
-        if (mAttached) {
-            throw new IllegalStateException("Already attached to " + mBgView);
-        }
-        mBgView = sceneRoot;
-        mAttached = true;
-        syncWithService();
-    }
-
-    /**
-     * Returns true if the background manager is currently attached; false otherwise.
-     */
-    public boolean isAttached() {
-        return mAttached;
-    }
-
-    /**
-     * Release references to Drawables and put the BackgroundManager into the
-     * detached state. Called when the associated Activity is destroyed.
-     */
-    void detach() {
-        if (DEBUG) Log.v(TAG, "detach " + this);
-        release();
-
-        mBgView = null;
-        mAttached = false;
-
-        if (mService != null) {
-            mService.unref();
-            mService = null;
-        }
-    }
-
-    /**
-     * Release references to Drawable/Bitmap. Typically called in Activity onStop() to reduce memory
-     * overhead when not visible. It's app's responsibility to restore the drawable/bitmap in
-     * Activity onStart(). The method is automatically called in onStop() when
-     * {@link #isAutoReleaseOnStop()} is true.
-     * @see #setAutoReleaseOnStop(boolean)
-     */
-    public void release() {
-        if (DEBUG) Log.v(TAG, "release " + this);
-        if (mChangeRunnable != null) {
-            mHandler.removeCallbacks(mChangeRunnable);
-            mChangeRunnable = null;
-        }
-        if (mAnimator.isStarted()) {
-            mAnimator.cancel();
-        }
-        if (mLayerDrawable != null) {
-            mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
-            mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
-            mLayerDrawable = null;
-        }
-        mBackgroundDrawable = null;
-    }
-
-    /**
-     * Sets the drawable used as a dim layer.
-     * @deprecated No longer support dim layer.
-     */
-    @Deprecated
-    public void setDimLayer(Drawable drawable) {
-    }
-
-    /**
-     * Returns the drawable used as a dim layer.
-     * @deprecated No longer support dim layer.
-     */
-    @Deprecated
-    public Drawable getDimLayer() {
-        return null;
-    }
-
-    /**
-     * Returns the default drawable used as a dim layer.
-     * @deprecated No longer support dim layer.
-     */
-    @Deprecated
-    public Drawable getDefaultDimLayer() {
-        return ContextCompat.getDrawable(mContext, R.color.lb_background_protection);
-    }
-
-    void postChangeRunnable() {
-        if (mChangeRunnable == null || !mChangeRunnablePending) {
-            return;
-        }
-
-        // Postpone a pending change runnable until: no existing change animation in progress &&
-        // activity is resumed (in the foreground) && layerdrawable fully opaque.
-        // If the layerdrawable is translucent then an activity transition is in progress
-        // and we want to use the optimized drawing path for performance reasons (see
-        // OptimizedTranslucentLayerDrawable).
-        if (mAnimator.isStarted()) {
-            if (DEBUG) Log.v(TAG, "animation in progress");
-        } else if (!mFragmentState.isResumed()) {
-            if (DEBUG) Log.v(TAG, "not resumed");
-        } else if (mLayerDrawable.getAlpha() < FULL_ALPHA) {
-            if (DEBUG) Log.v(TAG, "in transition, alpha " + mLayerDrawable.getAlpha());
-        } else {
-            long delayMs = getRunnableDelay();
-            if (DEBUG) Log.v(TAG, "posting runnable delayMs " + delayMs);
-            mLastSetTime = System.currentTimeMillis();
-            mHandler.postDelayed(mChangeRunnable, delayMs);
-            mChangeRunnablePending = false;
-        }
-    }
-
-    private void lazyInit() {
-        if (mLayerDrawable != null) {
-            return;
-        }
-
-        LayerDrawable layerDrawable = (LayerDrawable)
-                ContextCompat.getDrawable(mContext, R.drawable.lb_background).mutate();
-        mLayerDrawable = createTranslucentLayerDrawable(layerDrawable);
-        mImageInWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imagein);
-        mImageOutWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imageout);
-        BackgroundHelper.setBackgroundPreservingAlpha(mBgView, mLayerDrawable);
-    }
-
-    private void updateImmediate() {
-        if (!mAttached) {
-            return;
-        }
-        lazyInit();
-
-        if (mBackgroundDrawable == null) {
-            if (DEBUG) Log.v(TAG, "Use defefault background");
-            mLayerDrawable.updateDrawable(R.id.background_imagein, getDefaultDrawable());
-        } else {
-            if (DEBUG) Log.v(TAG, "Background drawable is available " + mBackgroundDrawable);
-            mLayerDrawable.updateDrawable(R.id.background_imagein, mBackgroundDrawable);
-        }
-        mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
-    }
-
-    /**
-     * Sets the background to the given color. The timing for when this becomes
-     * visible in the app is undefined and may take place after a small delay.
-     */
-    public void setColor(@ColorInt int color) {
-        if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
-
-        mService.setColor(color);
-        mBackgroundColor = color;
-        mBackgroundDrawable = null;
-        if (mLayerDrawable == null) {
-            return;
-        }
-        setDrawableInternal(getDefaultDrawable());
-    }
-
-    /**
-     * Sets the given drawable into the background. The provided Drawable will be
-     * used unmodified as the background, without any scaling or cropping
-     * applied to it. The timing for when this becomes visible in the app is
-     * undefined and may take place after a small delay.
-     */
-    public void setDrawable(Drawable drawable) {
-        if (DEBUG) Log.v(TAG, "setBackgroundDrawable " + drawable);
-
-        mService.setDrawable(drawable);
-        mBackgroundDrawable = drawable;
-        if (mLayerDrawable == null) {
-            return;
-        }
-        if (drawable == null) {
-            setDrawableInternal(getDefaultDrawable());
-        } else {
-            setDrawableInternal(drawable);
-        }
-    }
-
-    /**
-     * Clears the Drawable set by {@link #setDrawable(Drawable)} or {@link #setBitmap(Bitmap)}.
-     * BackgroundManager will show a solid color set by {@link #setColor(int)} or theme drawable
-     * if color is not provided.
-     */
-    public void clearDrawable() {
-        setDrawable(null);
-    }
-
-    private void setDrawableInternal(Drawable drawable) {
-        if (!mAttached) {
-            throw new IllegalStateException("Must attach before setting background drawable");
-        }
-
-        if (mChangeRunnable != null) {
-            if (sameDrawable(drawable, mChangeRunnable.mDrawable)) {
-                if (DEBUG) Log.v(TAG, "new drawable same as pending");
-                return;
-            }
-            mHandler.removeCallbacks(mChangeRunnable);
-            mChangeRunnable = null;
-        }
-
-        mChangeRunnable = new ChangeBackgroundRunnable(drawable);
-        mChangeRunnablePending = true;
-
-        postChangeRunnable();
-    }
-
-    private long getRunnableDelay() {
-        return Math.max(0, mLastSetTime + CHANGE_BG_DELAY_MS - System.currentTimeMillis());
-    }
-
-    /**
-     * Sets the given bitmap into the background. When using setCoverImageBitmap to set the
-     * background, the provided bitmap will be scaled and cropped to correctly
-     * fit within the dimensions of the view. The timing for when this becomes
-     * visible in the app is undefined and may take place after a small delay.
-     */
-    public void setBitmap(Bitmap bitmap) {
-        if (DEBUG) {
-            Log.v(TAG, "setCoverImageBitmap " + bitmap);
-        }
-
-        if (bitmap == null) {
-            setDrawable(null);
-            return;
-        }
-
-        if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
-            if (DEBUG) {
-                Log.v(TAG, "invalid bitmap width or height");
-            }
-            return;
-        }
-
-        Matrix matrix = null;
-
-        if ((bitmap.getWidth() != mWidthPx || bitmap.getHeight() != mHeightPx)) {
-            int dwidth = bitmap.getWidth();
-            int dheight = bitmap.getHeight();
-            float scale;
-
-            // Scale proportionately to fit width and height.
-            if (dwidth * mHeightPx > mWidthPx * dheight) {
-                scale = (float) mHeightPx / (float) dheight;
-            } else {
-                scale = (float) mWidthPx / (float) dwidth;
-            }
-
-            int subX = Math.min((int) (mWidthPx / scale), dwidth);
-            int dx = Math.max(0, (dwidth - subX) / 2);
-
-            matrix = new Matrix();
-            matrix.setScale(scale, scale);
-            matrix.preTranslate(-dx, 0);
-
-            if (DEBUG) {
-                Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight()
-                        + " scale " + scale + " dx " + dx);
-            }
-        }
-
-        BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
-
-        setDrawable(bitmapDrawable);
-    }
-
-    /**
-     * Enable or disable call release() in Activity onStop(). Default is true.
-     * @param autoReleaseOnStop True to call release() in Activity onStop(), false otherwise.
-     */
-    public void setAutoReleaseOnStop(boolean autoReleaseOnStop) {
-        mAutoReleaseOnStop = autoReleaseOnStop;
-    }
-
-    /**
-     * @return True if release() in Activity.onStop(), false otherwise.
-     */
-    public boolean isAutoReleaseOnStop() {
-        return mAutoReleaseOnStop;
-    }
-
-    /**
-     * Returns the current background color.
-     */
-    @ColorInt
-    public final int getColor() {
-        return mBackgroundColor;
-    }
-
-    /**
-     * Returns the current background {@link Drawable}.
-     */
-    public Drawable getDrawable() {
-        return mBackgroundDrawable;
-    }
-
-    boolean sameDrawable(Drawable first, Drawable second) {
-        if (first == null || second == null) {
-            return false;
-        }
-        if (first == second) {
-            return true;
-        }
-        if (first instanceof BitmapDrawable && second instanceof BitmapDrawable) {
-            if (((BitmapDrawable) first).getBitmap().sameAs(((BitmapDrawable) second).getBitmap())) {
-                return true;
-            }
-        }
-        if (first instanceof ColorDrawable && second instanceof ColorDrawable) {
-            if (((ColorDrawable) first).getColor() == ((ColorDrawable) second).getColor()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Task which changes the background.
-     */
-    final class ChangeBackgroundRunnable implements Runnable {
-        final Drawable mDrawable;
-
-        ChangeBackgroundRunnable(Drawable drawable) {
-            mDrawable = drawable;
-        }
-
-        @Override
-        public void run() {
-            runTask();
-            mChangeRunnable = null;
-        }
-
-        private void runTask() {
-            if (mLayerDrawable == null) {
-                if (DEBUG) Log.v(TAG, "runTask while released - should not happen");
-                return;
-            }
-
-            DrawableWrapper imageInWrapper = getImageInWrapper();
-            if (imageInWrapper != null) {
-                if (sameDrawable(mDrawable, imageInWrapper.getDrawable())) {
-                    if (DEBUG) Log.v(TAG, "new drawable same as current");
-                    return;
-                }
-
-                if (DEBUG) Log.v(TAG, "moving image in to image out");
-                // Order is important! Setting a drawable "removes" the
-                // previous one from the view
-                mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
-                mLayerDrawable.updateDrawable(R.id.background_imageout,
-                        imageInWrapper.getDrawable());
-            }
-
-            applyBackgroundChanges();
-        }
-
-        void applyBackgroundChanges() {
-            if (!mAttached) {
-                return;
-            }
-
-            if (DEBUG) Log.v(TAG, "applyBackgroundChanges drawable " + mDrawable);
-
-            DrawableWrapper imageInWrapper = getImageInWrapper();
-            if (imageInWrapper == null && mDrawable != null) {
-                if (DEBUG) Log.v(TAG, "creating new imagein drawable");
-                imageInWrapper = mLayerDrawable.updateDrawable(
-                        R.id.background_imagein, mDrawable);
-                if (DEBUG) Log.v(TAG, "imageInWrapper animation starting");
-                mLayerDrawable.setWrapperAlpha(mImageInWrapperIndex, 0);
-            }
-
-            mAnimator.setDuration(FADE_DURATION);
-            mAnimator.start();
-
-        }
-
-    }
-
-    static class EmptyDrawable extends BitmapDrawable {
-        EmptyDrawable(Resources res) {
-            super(res, (Bitmap) null);
-        }
-    }
-
-    static Drawable createEmptyDrawable(Context context) {
-        return new EmptyDrawable(context.getResources());
-    }
-
-}
diff --git a/leanback/src/android/support/v17/leanback/app/BrowseFragment.java b/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
deleted file mode 100644
index a2439e4..0000000
--- a/leanback/src/android/support/v17/leanback/app/BrowseFragment.java
+++ /dev/null
@@ -1,1871 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from BrowseSupportFragment.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import static android.support.v7.widget.RecyclerView.NO_POSITION;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.support.annotation.ColorInt;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.transition.TransitionListener;
-import android.support.v17.leanback.util.StateMachine.Event;
-import android.support.v17.leanback.util.StateMachine.State;
-import android.support.v17.leanback.widget.BrowseFrameLayout;
-import android.support.v17.leanback.widget.InvisibleRowPresenter;
-import android.support.v17.leanback.widget.ListRow;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.PageRow;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowHeaderPresenter;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.ScaleFrameLayout;
-import android.support.v17.leanback.widget.TitleViewAdapter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentManager.BackStackEntry;
-import android.app.FragmentTransaction;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.view.ViewTreeObserver;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A fragment for creating Leanback browse screens. It is composed of a
- * RowsFragment and a HeadersFragment.
- * <p>
- * A BrowseFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list. The elements in this adapter must be subclasses
- * of {@link Row}.
- * <p>
- * The HeadersFragment can be set to be either shown or hidden by default, or
- * may be disabled entirely. See {@link #setHeadersState} for details.
- * <p>
- * By default the BrowseFragment includes support for returning to the headers
- * when the user presses Back. For Activities that customize {@link
- * android.app.Activity#onBackPressed()}, you must disable this default Back key support by
- * calling {@link #setHeadersTransitionOnBackEnabled(boolean)} with false and
- * use {@link BrowseFragment.BrowseTransitionListener} and
- * {@link #startHeadersTransition(boolean)}.
- * <p>
- * The recommended theme to use with a BrowseFragment is
- * {@link android.support.v17.leanback.R.style#Theme_Leanback_Browse}.
- * </p>
- * @deprecated use {@link BrowseSupportFragment}
- */
-@Deprecated
-public class BrowseFragment extends BaseFragment {
-
-    // BUNDLE attribute for saving header show/hide status when backstack is used:
-    static final String HEADER_STACK_INDEX = "headerStackIndex";
-    // BUNDLE attribute for saving header show/hide status when backstack is not used:
-    static final String HEADER_SHOW = "headerShow";
-    private static final String IS_PAGE_ROW = "isPageRow";
-    private static final String CURRENT_SELECTED_POSITION = "currentSelectedPosition";
-
-    /**
-     * State to hide headers fragment.
-     */
-    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
-        @Override
-        public void run() {
-            setEntranceTransitionStartState();
-        }
-    };
-
-    /**
-     * Event for Header fragment view is created, we could perform
-     * {@link #setEntranceTransitionStartState()} to hide headers fragment initially.
-     */
-    final Event EVT_HEADER_VIEW_CREATED = new Event("headerFragmentViewCreated");
-
-    /**
-     * Event for {@link #getMainFragment()} view is created, it's additional requirement to execute
-     * {@link #onEntranceTransitionPrepare()}.
-     */
-    final Event EVT_MAIN_FRAGMENT_VIEW_CREATED = new Event("mainFragmentViewCreated");
-
-    /**
-     * Event that data for the screen is ready, this is additional requirement to launch entrance
-     * transition.
-     */
-    final Event EVT_SCREEN_DATA_READY = new Event("screenDataReady");
-
-    @Override
-    void createStateMachineStates() {
-        super.createStateMachineStates();
-        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
-    }
-
-    @Override
-    void createStateMachineTransitions() {
-        super.createStateMachineTransitions();
-        // when headers fragment view is created we could setEntranceTransitionStartState()
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED, STATE_SET_ENTRANCE_START_STATE,
-                EVT_HEADER_VIEW_CREATED);
-
-        // add additional requirement for onEntranceTransitionPrepare()
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
-                STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
-                EVT_MAIN_FRAGMENT_VIEW_CREATED);
-        // add additional requirement to launch entrance transition.
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,  STATE_ENTRANCE_PERFORM,
-                EVT_SCREEN_DATA_READY);
-    }
-
-    final class BackStackListener implements FragmentManager.OnBackStackChangedListener {
-        int mLastEntryCount;
-        int mIndexOfHeadersBackStack;
-
-        BackStackListener() {
-            mLastEntryCount = getFragmentManager().getBackStackEntryCount();
-            mIndexOfHeadersBackStack = -1;
-        }
-
-        void load(Bundle savedInstanceState) {
-            if (savedInstanceState != null) {
-                mIndexOfHeadersBackStack = savedInstanceState.getInt(HEADER_STACK_INDEX, -1);
-                mShowingHeaders = mIndexOfHeadersBackStack == -1;
-            } else {
-                if (!mShowingHeaders) {
-                    getFragmentManager().beginTransaction()
-                            .addToBackStack(mWithHeadersBackStackName).commit();
-                }
-            }
-        }
-
-        void save(Bundle outState) {
-            outState.putInt(HEADER_STACK_INDEX, mIndexOfHeadersBackStack);
-        }
-
-
-        @Override
-        public void onBackStackChanged() {
-            if (getFragmentManager() == null) {
-                Log.w(TAG, "getFragmentManager() is null, stack:", new Exception());
-                return;
-            }
-            int count = getFragmentManager().getBackStackEntryCount();
-            // if backstack is growing and last pushed entry is "headers" backstack,
-            // remember the index of the entry.
-            if (count > mLastEntryCount) {
-                BackStackEntry entry = getFragmentManager().getBackStackEntryAt(count - 1);
-                if (mWithHeadersBackStackName.equals(entry.getName())) {
-                    mIndexOfHeadersBackStack = count - 1;
-                }
-            } else if (count < mLastEntryCount) {
-                // if popped "headers" backstack, initiate the show header transition if needed
-                if (mIndexOfHeadersBackStack >= count) {
-                    if (!isHeadersDataReady()) {
-                        // if main fragment was restored first before BrowseFragment's adapter gets
-                        // restored: don't start header transition, but add the entry back.
-                        getFragmentManager().beginTransaction()
-                                .addToBackStack(mWithHeadersBackStackName).commit();
-                        return;
-                    }
-                    mIndexOfHeadersBackStack = -1;
-                    if (!mShowingHeaders) {
-                        startHeadersTransitionInternal(true);
-                    }
-                }
-            }
-            mLastEntryCount = count;
-        }
-    }
-
-    /**
-     * Listener for transitions between browse headers and rows.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public static class BrowseTransitionListener {
-        /**
-         * Callback when headers transition starts.
-         *
-         * @param withHeaders True if the transition will result in headers
-         *        being shown, false otherwise.
-         */
-        public void onHeadersTransitionStart(boolean withHeaders) {
-        }
-        /**
-         * Callback when headers transition stops.
-         *
-         * @param withHeaders True if the transition will result in headers
-         *        being shown, false otherwise.
-         */
-        public void onHeadersTransitionStop(boolean withHeaders) {
-        }
-    }
-
-    private class SetSelectionRunnable implements Runnable {
-        static final int TYPE_INVALID = -1;
-        static final int TYPE_INTERNAL_SYNC = 0;
-        static final int TYPE_USER_REQUEST = 1;
-
-        private int mPosition;
-        private int mType;
-        private boolean mSmooth;
-
-        SetSelectionRunnable() {
-            reset();
-        }
-
-        void post(int position, int type, boolean smooth) {
-            // Posting the set selection, rather than calling it immediately, prevents an issue
-            // with adapter changes.  Example: a row is added before the current selected row;
-            // first the fast lane view updates its selection, then the rows fragment has that
-            // new selection propagated immediately; THEN the rows view processes the same adapter
-            // change and moves the selection again.
-            if (type >= mType) {
-                mPosition = position;
-                mType = type;
-                mSmooth = smooth;
-                mBrowseFrame.removeCallbacks(this);
-                mBrowseFrame.post(this);
-            }
-        }
-
-        @Override
-        public void run() {
-            setSelection(mPosition, mSmooth);
-            reset();
-        }
-
-        private void reset() {
-            mPosition = -1;
-            mType = TYPE_INVALID;
-            mSmooth = false;
-        }
-    }
-
-    /**
-     * Possible set of actions that {@link BrowseFragment} exposes to clients. Custom
-     * fragments can interact with {@link BrowseFragment} using this interface.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public interface FragmentHost {
-        /**
-         * Fragments are required to invoke this callback once their view is created
-         * inside {@link Fragment#onViewCreated} method. {@link BrowseFragment} starts the entrance
-         * animation only after receiving this callback. Failure to invoke this method
-         * will lead to fragment not showing up.
-         *
-         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
-         */
-        void notifyViewCreated(MainFragmentAdapter fragmentAdapter);
-
-        /**
-         * Fragments mapped to {@link PageRow} are required to invoke this callback once their data
-         * is created for transition, the entrance animation only after receiving this callback.
-         * Failure to invoke this method will lead to fragment not showing up.
-         *
-         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
-         */
-        void notifyDataReady(MainFragmentAdapter fragmentAdapter);
-
-        /**
-         * Show or hide title view in {@link BrowseFragment} for fragments mapped to
-         * {@link PageRow}.  Otherwise the request is ignored, in that case BrowseFragment is fully
-         * in control of showing/hiding title view.
-         * <p>
-         * When HeadersFragment is visible, BrowseFragment will hide search affordance view if
-         * there are other focusable rows above currently focused row.
-         *
-         * @param show Boolean indicating whether or not to show the title view.
-         */
-        void showTitleView(boolean show);
-    }
-
-    /**
-     * Default implementation of {@link FragmentHost} that is used only by
-     * {@link BrowseFragment}.
-     */
-    private final class FragmentHostImpl implements FragmentHost {
-        boolean mShowTitleView = true;
-
-        FragmentHostImpl() {
-        }
-
-        @Override
-        public void notifyViewCreated(MainFragmentAdapter fragmentAdapter) {
-            mStateMachine.fireEvent(EVT_MAIN_FRAGMENT_VIEW_CREATED);
-            if (!mIsPageRow) {
-                // If it's not a PageRow: it's a ListRow, so we already have data ready.
-                mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
-            }
-        }
-
-        @Override
-        public void notifyDataReady(MainFragmentAdapter fragmentAdapter) {
-            // If fragment host is not the currently active fragment (in BrowseFragment), then
-            // ignore the request.
-            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
-                return;
-            }
-
-            // We only honor showTitle request for PageRows.
-            if (!mIsPageRow) {
-                return;
-            }
-
-            mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
-        }
-
-        @Override
-        public void showTitleView(boolean show) {
-            mShowTitleView = show;
-
-            // If fragment host is not the currently active fragment (in BrowseFragment), then
-            // ignore the request.
-            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
-                return;
-            }
-
-            // We only honor showTitle request for PageRows.
-            if (!mIsPageRow) {
-                return;
-            }
-
-            updateTitleViewVisibility();
-        }
-    }
-
-    /**
-     * Interface that defines the interaction between {@link BrowseFragment} and its main
-     * content fragment. The key method is {@link MainFragmentAdapter#getFragment()},
-     * it will be used to get the fragment to be shown in the content section. Clients can
-     * provide any implementation of fragment and customize its interaction with
-     * {@link BrowseFragment} by overriding the necessary methods.
-     *
-     * <p>
-     * Clients are expected to provide
-     * an instance of {@link MainFragmentAdapterRegistry} which will be responsible for providing
-     * implementations of {@link MainFragmentAdapter} for given content types. Currently
-     * we support different types of content - {@link ListRow}, {@link PageRow} or any subtype
-     * of {@link Row}. We provide an out of the box adapter implementation for any rows other than
-     * {@link PageRow} - {@link android.support.v17.leanback.app.RowsFragment.MainFragmentAdapter}.
-     *
-     * <p>
-     * {@link PageRow} is intended to give full flexibility to developers in terms of Fragment
-     * design. Users will have to provide an implementation of {@link MainFragmentAdapter}
-     * and provide that through {@link MainFragmentAdapterRegistry}.
-     * {@link MainFragmentAdapter} implementation can supply any fragment and override
-     * just those interactions that makes sense.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public static class MainFragmentAdapter<T extends Fragment> {
-        private boolean mScalingEnabled;
-        private final T mFragment;
-        FragmentHostImpl mFragmentHost;
-
-        public MainFragmentAdapter(T fragment) {
-            this.mFragment = fragment;
-        }
-
-        public final T getFragment() {
-            return mFragment;
-        }
-
-        /**
-         * Returns whether its scrolling.
-         */
-        public boolean isScrolling() {
-            return false;
-        }
-
-        /**
-         * Set the visibility of titles/hover card of browse rows.
-         */
-        public void setExpand(boolean expand) {
-        }
-
-        /**
-         * For rows that willing to participate entrance transition,  this function
-         * hide views if afterTransition is true,  show views if afterTransition is false.
-         */
-        public void setEntranceTransitionState(boolean state) {
-        }
-
-        /**
-         * Sets the window alignment and also the pivots for scale operation.
-         */
-        public void setAlignment(int windowAlignOffsetFromTop) {
-        }
-
-        /**
-         * Callback indicating transition prepare start.
-         */
-        public boolean onTransitionPrepare() {
-            return false;
-        }
-
-        /**
-         * Callback indicating transition start.
-         */
-        public void onTransitionStart() {
-        }
-
-        /**
-         * Callback indicating transition end.
-         */
-        public void onTransitionEnd() {
-        }
-
-        /**
-         * Returns whether row scaling is enabled.
-         */
-        public boolean isScalingEnabled() {
-            return mScalingEnabled;
-        }
-
-        /**
-         * Sets the row scaling property.
-         */
-        public void setScalingEnabled(boolean scalingEnabled) {
-            this.mScalingEnabled = scalingEnabled;
-        }
-
-        /**
-         * Returns the current host interface so that main fragment can interact with
-         * {@link BrowseFragment}.
-         */
-        public final FragmentHost getFragmentHost() {
-            return mFragmentHost;
-        }
-
-        void setFragmentHost(FragmentHostImpl fragmentHost) {
-            this.mFragmentHost = fragmentHost;
-        }
-    }
-
-    /**
-     * Interface to be implemented by all fragments for providing an instance of
-     * {@link MainFragmentAdapter}. Both {@link RowsFragment} and custom fragment provided
-     * against {@link PageRow} will need to implement this interface.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public interface MainFragmentAdapterProvider {
-        /**
-         * Returns an instance of {@link MainFragmentAdapter} that {@link BrowseFragment}
-         * would use to communicate with the target fragment.
-         */
-        MainFragmentAdapter getMainFragmentAdapter();
-    }
-
-    /**
-     * Interface to be implemented by {@link RowsFragment} and its subclasses for providing
-     * an instance of {@link MainFragmentRowsAdapter}.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public interface MainFragmentRowsAdapterProvider {
-        /**
-         * Returns an instance of {@link MainFragmentRowsAdapter} that {@link BrowseFragment}
-         * would use to communicate with the target fragment.
-         */
-        MainFragmentRowsAdapter getMainFragmentRowsAdapter();
-    }
-
-    /**
-     * This is used to pass information to {@link RowsFragment} or its subclasses.
-     * {@link BrowseFragment} uses this interface to pass row based interaction events to
-     * the target fragment.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public static class MainFragmentRowsAdapter<T extends Fragment> {
-        private final T mFragment;
-
-        public MainFragmentRowsAdapter(T fragment) {
-            if (fragment == null) {
-                throw new IllegalArgumentException("Fragment can't be null");
-            }
-            this.mFragment = fragment;
-        }
-
-        public final T getFragment() {
-            return mFragment;
-        }
-        /**
-         * Set the visibility titles/hover of browse rows.
-         */
-        public void setAdapter(ObjectAdapter adapter) {
-        }
-
-        /**
-         * Sets an item clicked listener on the fragment.
-         */
-        public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        }
-
-        /**
-         * Sets an item selection listener.
-         */
-        public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
-        }
-
-        /**
-         * Selects a Row and perform an optional task on the Row.
-         */
-        public void setSelectedPosition(int rowPosition,
-                                        boolean smooth,
-                                        final Presenter.ViewHolderTask rowHolderTask) {
-        }
-
-        /**
-         * Selects a Row.
-         */
-        public void setSelectedPosition(int rowPosition, boolean smooth) {
-        }
-
-        /**
-         * @return The position of selected row.
-         */
-        public int getSelectedPosition() {
-            return 0;
-        }
-
-        /**
-         * @param position Position of Row.
-         * @return Row ViewHolder.
-         */
-        public RowPresenter.ViewHolder findRowViewHolderByPosition(int position) {
-            return null;
-        }
-    }
-
-    private boolean createMainFragment(ObjectAdapter adapter, int position) {
-        Object item = null;
-        if (!mCanShowHeaders) {
-            // when header is disabled, we can decide to use RowsFragment even no data.
-        } else if (adapter == null || adapter.size() == 0) {
-            return false;
-        } else {
-            if (position < 0) {
-                position = 0;
-            } else if (position >= adapter.size()) {
-                throw new IllegalArgumentException(
-                        String.format("Invalid position %d requested", position));
-            }
-            item = adapter.get(position);
-        }
-
-        boolean oldIsPageRow = mIsPageRow;
-        Object oldPageRow = mPageRow;
-        mIsPageRow = mCanShowHeaders && item instanceof PageRow;
-        mPageRow = mIsPageRow ? item : null;
-        boolean swap;
-
-        if (mMainFragment == null) {
-            swap = true;
-        } else {
-            if (oldIsPageRow) {
-                if (mIsPageRow) {
-                    if (oldPageRow == null) {
-                        // fragment is restored, page row object not yet set, so just set the
-                        // mPageRow object and there is no need to replace the fragment
-                        swap = false;
-                    } else {
-                        // swap if page row object changes
-                        swap = oldPageRow != mPageRow;
-                    }
-                } else {
-                    swap = true;
-                }
-            } else {
-                swap = mIsPageRow;
-            }
-        }
-
-        if (swap) {
-            mMainFragment = mMainFragmentAdapterRegistry.createFragment(item);
-            if (!(mMainFragment instanceof MainFragmentAdapterProvider)) {
-                throw new IllegalArgumentException(
-                        "Fragment must implement MainFragmentAdapterProvider");
-            }
-
-            setMainFragmentAdapter();
-        }
-
-        return swap;
-    }
-
-    void setMainFragmentAdapter() {
-        mMainFragmentAdapter = ((MainFragmentAdapterProvider) mMainFragment)
-                .getMainFragmentAdapter();
-        mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
-        if (!mIsPageRow) {
-            if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
-                setMainFragmentRowsAdapter(((MainFragmentRowsAdapterProvider) mMainFragment)
-                        .getMainFragmentRowsAdapter());
-            } else {
-                setMainFragmentRowsAdapter(null);
-            }
-            mIsPageRow = mMainFragmentRowsAdapter == null;
-        } else {
-            setMainFragmentRowsAdapter(null);
-        }
-    }
-
-    /**
-     * Factory class responsible for creating fragment given the current item. {@link ListRow}
-     * should return {@link RowsFragment} or its subclass whereas {@link PageRow}
-     * can return any fragment class.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public abstract static class FragmentFactory<T extends Fragment> {
-        public abstract T createFragment(Object row);
-    }
-
-    /**
-     * FragmentFactory implementation for {@link ListRow}.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public static class ListRowFragmentFactory extends FragmentFactory<RowsFragment> {
-        @Override
-        public RowsFragment createFragment(Object row) {
-            return new RowsFragment();
-        }
-    }
-
-    /**
-     * Registry class maintaining the mapping of {@link Row} subclasses to {@link FragmentFactory}.
-     * BrowseRowFragment automatically registers {@link ListRowFragmentFactory} for
-     * handling {@link ListRow}. Developers can override that and also if they want to
-     * use custom fragment, they can register a custom {@link FragmentFactory}
-     * against {@link PageRow}.
-     * @deprecated use {@link BrowseSupportFragment}
-     */
-    @Deprecated
-    public final static class MainFragmentAdapterRegistry {
-        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
-        private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
-
-        public MainFragmentAdapterRegistry() {
-            registerFragment(ListRow.class, sDefaultFragmentFactory);
-        }
-
-        public void registerFragment(Class rowClass, FragmentFactory factory) {
-            mItemToFragmentFactoryMapping.put(rowClass, factory);
-        }
-
-        public Fragment createFragment(Object item) {
-            FragmentFactory fragmentFactory = item == null ? sDefaultFragmentFactory :
-                    mItemToFragmentFactoryMapping.get(item.getClass());
-            if (fragmentFactory == null && !(item instanceof PageRow)) {
-                fragmentFactory = sDefaultFragmentFactory;
-            }
-
-            return fragmentFactory.createFragment(item);
-        }
-    }
-
-    static final String TAG = "BrowseFragment";
-
-    private static final String LB_HEADERS_BACKSTACK = "lbHeadersBackStack_";
-
-    static boolean DEBUG = false;
-
-    /** The headers fragment is enabled and shown by default. */
-    public static final int HEADERS_ENABLED = 1;
-
-    /** The headers fragment is enabled and hidden by default. */
-    public static final int HEADERS_HIDDEN = 2;
-
-    /** The headers fragment is disabled and will never be shown. */
-    public static final int HEADERS_DISABLED = 3;
-
-    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry =
-            new MainFragmentAdapterRegistry();
-    MainFragmentAdapter mMainFragmentAdapter;
-    Fragment mMainFragment;
-    HeadersFragment mHeadersFragment;
-    MainFragmentRowsAdapter mMainFragmentRowsAdapter;
-    ListRowDataAdapter mMainFragmentListRowDataAdapter;
-
-    private ObjectAdapter mAdapter;
-    private PresenterSelector mAdapterPresenter;
-
-    private int mHeadersState = HEADERS_ENABLED;
-    private int mBrandColor = Color.TRANSPARENT;
-    private boolean mBrandColorSet;
-
-    BrowseFrameLayout mBrowseFrame;
-    private ScaleFrameLayout mScaleFrameLayout;
-    boolean mHeadersBackStackEnabled = true;
-    String mWithHeadersBackStackName;
-    boolean mShowingHeaders = true;
-    boolean mCanShowHeaders = true;
-    private int mContainerListMarginStart;
-    private int mContainerListAlignTop;
-    private boolean mMainFragmentScaleEnabled = true;
-    OnItemViewSelectedListener mExternalOnItemViewSelectedListener;
-    private OnItemViewClickedListener mOnItemViewClickedListener;
-    private int mSelectedPosition = -1;
-    private float mScaleFactor;
-    boolean mIsPageRow;
-    Object mPageRow;
-
-    private PresenterSelector mHeaderPresenterSelector;
-    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
-
-    // transition related:
-    Object mSceneWithHeaders;
-    Object mSceneWithoutHeaders;
-    private Object mSceneAfterEntranceTransition;
-    Object mHeadersTransition;
-    BackStackListener mBackStackChangedListener;
-    BrowseTransitionListener mBrowseTransitionListener;
-
-    private static final String ARG_TITLE = BrowseFragment.class.getCanonicalName() + ".title";
-    private static final String ARG_HEADERS_STATE =
-        BrowseFragment.class.getCanonicalName() + ".headersState";
-
-    /**
-     * Creates arguments for a browse fragment.
-     *
-     * @param args The Bundle to place arguments into, or null if the method
-     *        should return a new Bundle.
-     * @param title The title of the BrowseFragment.
-     * @param headersState The initial state of the headers of the
-     *        BrowseFragment. Must be one of {@link #HEADERS_ENABLED}, {@link
-     *        #HEADERS_HIDDEN}, or {@link #HEADERS_DISABLED}.
-     * @return A Bundle with the given arguments for creating a BrowseFragment.
-     */
-    public static Bundle createArgs(Bundle args, String title, int headersState) {
-        if (args == null) {
-            args = new Bundle();
-        }
-        args.putString(ARG_TITLE, title);
-        args.putInt(ARG_HEADERS_STATE, headersState);
-        return args;
-    }
-
-    /**
-     * Sets the brand color for the browse fragment. The brand color is used as
-     * the primary color for UI elements in the browse fragment. For example,
-     * the background color of the headers fragment uses the brand color.
-     *
-     * @param color The color to use as the brand color of the fragment.
-     */
-    public void setBrandColor(@ColorInt int color) {
-        mBrandColor = color;
-        mBrandColorSet = true;
-
-        if (mHeadersFragment != null) {
-            mHeadersFragment.setBackgroundColor(mBrandColor);
-        }
-    }
-
-    /**
-     * Returns the brand color for the browse fragment.
-     * The default is transparent.
-     */
-    @ColorInt
-    public int getBrandColor() {
-        return mBrandColor;
-    }
-
-    /**
-     * Wrapping app provided PresenterSelector to support InvisibleRowPresenter for SectionRow
-     * DividerRow and PageRow.
-     */
-    private void updateWrapperPresenter() {
-        if (mAdapter == null) {
-            mAdapterPresenter = null;
-            return;
-        }
-        final PresenterSelector adapterPresenter = mAdapter.getPresenterSelector();
-        if (adapterPresenter == null) {
-            throw new IllegalArgumentException("Adapter.getPresenterSelector() is null");
-        }
-        if (adapterPresenter == mAdapterPresenter) {
-            return;
-        }
-        mAdapterPresenter = adapterPresenter;
-
-        Presenter[] presenters = adapterPresenter.getPresenters();
-        final Presenter invisibleRowPresenter = new InvisibleRowPresenter();
-        final Presenter[] allPresenters = new Presenter[presenters.length + 1];
-        System.arraycopy(allPresenters, 0, presenters, 0, presenters.length);
-        allPresenters[allPresenters.length - 1] = invisibleRowPresenter;
-        mAdapter.setPresenterSelector(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object item) {
-                Row row = (Row) item;
-                if (row.isRenderedAsRowView()) {
-                    return adapterPresenter.getPresenter(item);
-                } else {
-                    return invisibleRowPresenter;
-                }
-            }
-
-            @Override
-            public Presenter[] getPresenters() {
-                return allPresenters;
-            }
-        });
-    }
-
-    /**
-     * Sets the adapter containing the rows for the fragment.
-     *
-     * <p>The items referenced by the adapter must be be derived from
-     * {@link Row}. These rows will be used by the rows fragment and the headers
-     * fragment (if not disabled) to render the browse rows.
-     *
-     * @param adapter An ObjectAdapter for the browse rows. All items must
-     *        derive from {@link Row}.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        updateWrapperPresenter();
-        if (getView() == null) {
-            return;
-        }
-
-        updateMainFragmentRowsAdapter();
-        mHeadersFragment.setAdapter(mAdapter);
-    }
-
-    void setMainFragmentRowsAdapter(MainFragmentRowsAdapter mainFragmentRowsAdapter) {
-        if (mainFragmentRowsAdapter == mMainFragmentRowsAdapter) {
-            return;
-        }
-        // first clear previous mMainFragmentRowsAdapter and set a new mMainFragmentRowsAdapter
-        if (mMainFragmentRowsAdapter != null) {
-            // RowsFragment cannot change click/select listeners after view created.
-            // The main fragment and adapter should be GCed as long as there is no reference from
-            // BrowseFragment to it.
-            mMainFragmentRowsAdapter.setAdapter(null);
-        }
-        mMainFragmentRowsAdapter = mainFragmentRowsAdapter;
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setOnItemViewSelectedListener(
-                    new MainFragmentItemViewSelectedListener(mMainFragmentRowsAdapter));
-            mMainFragmentRowsAdapter.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
-        // second update mMainFragmentListRowDataAdapter set on mMainFragmentRowsAdapter
-        updateMainFragmentRowsAdapter();
-    }
-
-    /**
-     * Update mMainFragmentListRowDataAdapter and set it on mMainFragmentRowsAdapter.
-     * It also clears old mMainFragmentListRowDataAdapter.
-     */
-    void updateMainFragmentRowsAdapter() {
-        if (mMainFragmentListRowDataAdapter != null) {
-            mMainFragmentListRowDataAdapter.detach();
-            mMainFragmentListRowDataAdapter = null;
-        }
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentListRowDataAdapter = mAdapter == null
-                    ? null : new ListRowDataAdapter(mAdapter);
-            mMainFragmentRowsAdapter.setAdapter(mMainFragmentListRowDataAdapter);
-        }
-    }
-
-    public final MainFragmentAdapterRegistry getMainFragmentRegistry() {
-        return mMainFragmentAdapterRegistry;
-    }
-
-    /**
-     * Returns the adapter containing the rows for the fragment.
-     */
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    /**
-     * Sets an item selection listener.
-     */
-    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
-        mExternalOnItemViewSelectedListener = listener;
-    }
-
-    /**
-     * Returns an item selection listener.
-     */
-    public OnItemViewSelectedListener getOnItemViewSelectedListener() {
-        return mExternalOnItemViewSelectedListener;
-    }
-
-    /**
-     * Get RowsFragment if it's bound to BrowseFragment or null if either BrowseFragment has
-     * not been created yet or a different fragment is bound to it.
-     *
-     * @return RowsFragment if it's bound to BrowseFragment or null otherwise.
-     */
-    public RowsFragment getRowsFragment() {
-        if (mMainFragment instanceof RowsFragment) {
-            return (RowsFragment) mMainFragment;
-        }
-
-        return null;
-    }
-
-    /**
-     * @return Current main fragment or null if not created.
-     */
-    public Fragment getMainFragment() {
-        return mMainFragment;
-    }
-
-    /**
-     * Get currently bound HeadersFragment or null if HeadersFragment has not been created yet.
-     * @return Currently bound HeadersFragment or null if HeadersFragment has not been created yet.
-     */
-    public HeadersFragment getHeadersFragment() {
-        return mHeadersFragment;
-    }
-
-    /**
-     * Sets an item clicked listener on the fragment.
-     * OnItemViewClickedListener will override {@link View.OnClickListener} that
-     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
-     * So in general, developer should choose one of the listeners but not both.
-     */
-    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        mOnItemViewClickedListener = listener;
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setOnItemViewClickedListener(listener);
-        }
-    }
-
-    /**
-     * Returns the item Clicked listener.
-     */
-    public OnItemViewClickedListener getOnItemViewClickedListener() {
-        return mOnItemViewClickedListener;
-    }
-
-    /**
-     * Starts a headers transition.
-     *
-     * <p>This method will begin a transition to either show or hide the
-     * headers, depending on the value of withHeaders. If headers are disabled
-     * for this browse fragment, this method will throw an exception.
-     *
-     * @param withHeaders True if the headers should transition to being shown,
-     *        false if the transition should result in headers being hidden.
-     */
-    public void startHeadersTransition(boolean withHeaders) {
-        if (!mCanShowHeaders) {
-            throw new IllegalStateException("Cannot start headers transition");
-        }
-        if (isInHeadersTransition() || mShowingHeaders == withHeaders) {
-            return;
-        }
-        startHeadersTransitionInternal(withHeaders);
-    }
-
-    /**
-     * Returns true if the headers transition is currently running.
-     */
-    public boolean isInHeadersTransition() {
-        return mHeadersTransition != null;
-    }
-
-    /**
-     * Returns true if headers are shown.
-     */
-    public boolean isShowingHeaders() {
-        return mShowingHeaders;
-    }
-
-    /**
-     * Sets a listener for browse fragment transitions.
-     *
-     * @param listener The listener to call when a browse headers transition
-     *        begins or ends.
-     */
-    public void setBrowseTransitionListener(BrowseTransitionListener listener) {
-        mBrowseTransitionListener = listener;
-    }
-
-    /**
-     * @deprecated use {@link BrowseFragment#enableMainFragmentScaling(boolean)} instead.
-     *
-     * @param enable true to enable row scaling
-     */
-    @Deprecated
-    public void enableRowScaling(boolean enable) {
-        enableMainFragmentScaling(enable);
-    }
-
-    /**
-     * Enables scaling of main fragment when headers are present. For the page/row fragment,
-     * scaling is enabled only when both this method and
-     * {@link MainFragmentAdapter#isScalingEnabled()} are enabled.
-     *
-     * @param enable true to enable row scaling
-     */
-    public void enableMainFragmentScaling(boolean enable) {
-        mMainFragmentScaleEnabled = enable;
-    }
-
-    void startHeadersTransitionInternal(final boolean withHeaders) {
-        if (getFragmentManager().isDestroyed()) {
-            return;
-        }
-        if (!isHeadersDataReady()) {
-            return;
-        }
-        mShowingHeaders = withHeaders;
-        mMainFragmentAdapter.onTransitionPrepare();
-        mMainFragmentAdapter.onTransitionStart();
-        onExpandTransitionStart(!withHeaders, new Runnable() {
-            @Override
-            public void run() {
-                mHeadersFragment.onTransitionPrepare();
-                mHeadersFragment.onTransitionStart();
-                createHeadersTransition();
-                if (mBrowseTransitionListener != null) {
-                    mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
-                }
-                TransitionHelper.runTransition(
-                        withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders, mHeadersTransition);
-                if (mHeadersBackStackEnabled) {
-                    if (!withHeaders) {
-                        getFragmentManager().beginTransaction()
-                                .addToBackStack(mWithHeadersBackStackName).commit();
-                    } else {
-                        int index = mBackStackChangedListener.mIndexOfHeadersBackStack;
-                        if (index >= 0) {
-                            BackStackEntry entry = getFragmentManager().getBackStackEntryAt(index);
-                            getFragmentManager().popBackStackImmediate(entry.getId(),
-                                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    boolean isVerticalScrolling() {
-        // don't run transition
-        return mHeadersFragment.isScrolling() || mMainFragmentAdapter.isScrolling();
-    }
-
-
-    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
-            new BrowseFrameLayout.OnFocusSearchListener() {
-        @Override
-        public View onFocusSearch(View focused, int direction) {
-            // if headers is running transition,  focus stays
-            if (mCanShowHeaders && isInHeadersTransition()) {
-                return focused;
-            }
-            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
-
-            if (getTitleView() != null && focused != getTitleView()
-                    && direction == View.FOCUS_UP) {
-                return getTitleView();
-            }
-            if (getTitleView() != null && getTitleView().hasFocus()
-                    && direction == View.FOCUS_DOWN) {
-                return mCanShowHeaders && mShowingHeaders
-                        ? mHeadersFragment.getVerticalGridView() : mMainFragment.getView();
-            }
-
-            boolean isRtl = ViewCompat.getLayoutDirection(focused)
-                    == ViewCompat.LAYOUT_DIRECTION_RTL;
-            int towardStart = isRtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
-            int towardEnd = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
-            if (mCanShowHeaders && direction == towardStart) {
-                if (isVerticalScrolling() || mShowingHeaders || !isHeadersDataReady()) {
-                    return focused;
-                }
-                return mHeadersFragment.getVerticalGridView();
-            } else if (direction == towardEnd) {
-                if (isVerticalScrolling()) {
-                    return focused;
-                } else if (mMainFragment != null && mMainFragment.getView() != null) {
-                    return mMainFragment.getView();
-                }
-                return focused;
-            } else if (direction == View.FOCUS_DOWN && mShowingHeaders) {
-                // disable focus_down moving into PageFragment.
-                return focused;
-            } else {
-                return null;
-            }
-        }
-    };
-
-    final boolean isHeadersDataReady() {
-        return mAdapter != null && mAdapter.size() != 0;
-    }
-
-    private final BrowseFrameLayout.OnChildFocusListener mOnChildFocusListener =
-            new BrowseFrameLayout.OnChildFocusListener() {
-
-        @Override
-        public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-            if (getChildFragmentManager().isDestroyed()) {
-                return true;
-            }
-            // Make sure not changing focus when requestFocus() is called.
-            if (mCanShowHeaders && mShowingHeaders) {
-                if (mHeadersFragment != null && mHeadersFragment.getView() != null
-                        && mHeadersFragment.getView().requestFocus(
-                                direction, previouslyFocusedRect)) {
-                    return true;
-                }
-            }
-            if (mMainFragment != null && mMainFragment.getView() != null
-                    && mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
-                return true;
-            }
-            return getTitleView() != null
-                    && getTitleView().requestFocus(direction, previouslyFocusedRect);
-        }
-
-        @Override
-        public void onRequestChildFocus(View child, View focused) {
-            if (getChildFragmentManager().isDestroyed()) {
-                return;
-            }
-            if (!mCanShowHeaders || isInHeadersTransition()) return;
-            int childId = child.getId();
-            if (childId == R.id.browse_container_dock && mShowingHeaders) {
-                startHeadersTransitionInternal(false);
-            } else if (childId == R.id.browse_headers_dock && !mShowingHeaders) {
-                startHeadersTransitionInternal(true);
-            }
-        }
-    };
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putInt(CURRENT_SELECTED_POSITION, mSelectedPosition);
-        outState.putBoolean(IS_PAGE_ROW, mIsPageRow);
-
-        if (mBackStackChangedListener != null) {
-            mBackStackChangedListener.save(outState);
-        } else {
-            outState.putBoolean(HEADER_SHOW, mShowingHeaders);
-        }
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        final Context context = FragmentUtil.getContext(BrowseFragment.this);
-        TypedArray ta = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
-        mContainerListMarginStart = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginStart, context.getResources()
-                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
-        mContainerListAlignTop = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginTop, context.getResources()
-                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
-        ta.recycle();
-
-        readArguments(getArguments());
-
-        if (mCanShowHeaders) {
-            if (mHeadersBackStackEnabled) {
-                mWithHeadersBackStackName = LB_HEADERS_BACKSTACK + this;
-                mBackStackChangedListener = new BackStackListener();
-                getFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
-                mBackStackChangedListener.load(savedInstanceState);
-            } else {
-                if (savedInstanceState != null) {
-                    mShowingHeaders = savedInstanceState.getBoolean(HEADER_SHOW);
-                }
-            }
-        }
-
-        mScaleFactor = getResources().getFraction(R.fraction.lb_browse_rows_scale, 1, 1);
-    }
-
-    @Override
-    public void onDestroyView() {
-        setMainFragmentRowsAdapter(null);
-        mPageRow = null;
-        mMainFragmentAdapter = null;
-        mMainFragment = null;
-        mHeadersFragment = null;
-        super.onDestroyView();
-    }
-
-    @Override
-    public void onDestroy() {
-        if (mBackStackChangedListener != null) {
-            getFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
-        }
-        super.onDestroy();
-    }
-
-    /**
-     * Creates a new {@link HeadersFragment} instance. Subclass of BrowseFragment may override and
-     * return an instance of subclass of HeadersFragment, e.g. when app wants to replace presenter
-     * to render HeaderItem.
-     *
-     * @return A new instance of {@link HeadersFragment} or its subclass.
-     */
-    public HeadersFragment onCreateHeadersFragment() {
-        return new HeadersFragment();
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-
-        if (getChildFragmentManager().findFragmentById(R.id.scale_frame) == null) {
-            mHeadersFragment = onCreateHeadersFragment();
-
-            createMainFragment(mAdapter, mSelectedPosition);
-            FragmentTransaction ft = getChildFragmentManager().beginTransaction()
-                    .replace(R.id.browse_headers_dock, mHeadersFragment);
-
-            if (mMainFragment != null) {
-                ft.replace(R.id.scale_frame, mMainFragment);
-            } else {
-                // Empty adapter used to guard against lazy adapter loading. When this
-                // fragment is instantiated, mAdapter might not have the data or might not
-                // have been set. In either of those cases mFragmentAdapter will be null.
-                // This way we can maintain the invariant that mMainFragmentAdapter is never
-                // null and it avoids doing null checks all over the code.
-                mMainFragmentAdapter = new MainFragmentAdapter(null);
-                mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
-            }
-
-            ft.commit();
-        } else {
-            mHeadersFragment = (HeadersFragment) getChildFragmentManager()
-                    .findFragmentById(R.id.browse_headers_dock);
-            mMainFragment = getChildFragmentManager().findFragmentById(R.id.scale_frame);
-
-            mIsPageRow = savedInstanceState != null
-                    && savedInstanceState.getBoolean(IS_PAGE_ROW, false);
-            // mPageRow object is unable to restore, if its null and mIsPageRow is true, this is
-            // the case for restoring, later if setSelection() triggers a createMainFragment(),
-            // should not create fragment.
-
-            mSelectedPosition = savedInstanceState != null
-                    ? savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
-
-            setMainFragmentAdapter();
-        }
-
-        mHeadersFragment.setHeadersGone(!mCanShowHeaders);
-        if (mHeaderPresenterSelector != null) {
-            mHeadersFragment.setPresenterSelector(mHeaderPresenterSelector);
-        }
-        mHeadersFragment.setAdapter(mAdapter);
-        mHeadersFragment.setOnHeaderViewSelectedListener(mHeaderViewSelectedListener);
-        mHeadersFragment.setOnHeaderClickedListener(mHeaderClickedListener);
-
-        View root = inflater.inflate(R.layout.lb_browse_fragment, container, false);
-
-        getProgressBarManager().setRootView((ViewGroup)root);
-
-        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
-        mBrowseFrame.setOnChildFocusListener(mOnChildFocusListener);
-        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
-
-        installTitleView(inflater, mBrowseFrame, savedInstanceState);
-
-        mScaleFrameLayout = (ScaleFrameLayout) root.findViewById(R.id.scale_frame);
-        mScaleFrameLayout.setPivotX(0);
-        mScaleFrameLayout.setPivotY(mContainerListAlignTop);
-
-        if (mBrandColorSet) {
-            mHeadersFragment.setBackgroundColor(mBrandColor);
-        }
-
-        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
-            @Override
-            public void run() {
-                showHeaders(true);
-            }
-        });
-        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
-            @Override
-            public void run() {
-                showHeaders(false);
-            }
-        });
-        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
-            @Override
-            public void run() {
-                setEntranceTransitionEndState();
-            }
-        });
-
-        return root;
-    }
-
-    void createHeadersTransition() {
-        mHeadersTransition = TransitionHelper.loadTransition(FragmentUtil.getContext(BrowseFragment.this),
-                mShowingHeaders
-                        ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
-
-        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
-            @Override
-            public void onTransitionStart(Object transition) {
-            }
-            @Override
-            public void onTransitionEnd(Object transition) {
-                mHeadersTransition = null;
-                if (mMainFragmentAdapter != null) {
-                    mMainFragmentAdapter.onTransitionEnd();
-                    if (!mShowingHeaders && mMainFragment != null) {
-                        View mainFragmentView = mMainFragment.getView();
-                        if (mainFragmentView != null && !mainFragmentView.hasFocus()) {
-                            mainFragmentView.requestFocus();
-                        }
-                    }
-                }
-                if (mHeadersFragment != null) {
-                    mHeadersFragment.onTransitionEnd();
-                    if (mShowingHeaders) {
-                        VerticalGridView headerGridView = mHeadersFragment.getVerticalGridView();
-                        if (headerGridView != null && !headerGridView.hasFocus()) {
-                            headerGridView.requestFocus();
-                        }
-                    }
-                }
-
-                // Animate TitleView once header animation is complete.
-                updateTitleViewVisibility();
-
-                if (mBrowseTransitionListener != null) {
-                    mBrowseTransitionListener.onHeadersTransitionStop(mShowingHeaders);
-                }
-            }
-        });
-    }
-
-    void updateTitleViewVisibility() {
-        if (!mShowingHeaders) {
-            boolean showTitleView;
-            if (mIsPageRow && mMainFragmentAdapter != null) {
-                // page fragment case:
-                showTitleView = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
-            } else {
-                // regular row view case:
-                showTitleView = isFirstRowWithContent(mSelectedPosition);
-            }
-            if (showTitleView) {
-                showTitle(TitleViewAdapter.FULL_VIEW_VISIBLE);
-            } else {
-                showTitle(false);
-            }
-        } else {
-            // when HeaderFragment is showing,  showBranding and showSearch are slightly different
-            boolean showBranding;
-            boolean showSearch;
-            if (mIsPageRow && mMainFragmentAdapter != null) {
-                showBranding = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
-            } else {
-                showBranding = isFirstRowWithContent(mSelectedPosition);
-            }
-            showSearch = isFirstRowWithContentOrPageRow(mSelectedPosition);
-            int flags = 0;
-            if (showBranding) flags |= TitleViewAdapter.BRANDING_VIEW_VISIBLE;
-            if (showSearch) flags |= TitleViewAdapter.SEARCH_VIEW_VISIBLE;
-            if (flags != 0) {
-                showTitle(flags);
-            } else {
-                showTitle(false);
-            }
-        }
-    }
-
-    boolean isFirstRowWithContentOrPageRow(int rowPosition) {
-        if (mAdapter == null || mAdapter.size() == 0) {
-            return true;
-        }
-        for (int i = 0; i < mAdapter.size(); i++) {
-            final Row row = (Row) mAdapter.get(i);
-            if (row.isRenderedAsRowView() || row instanceof PageRow) {
-                return rowPosition == i;
-            }
-        }
-        return true;
-    }
-
-    boolean isFirstRowWithContent(int rowPosition) {
-        if (mAdapter == null || mAdapter.size() == 0) {
-            return true;
-        }
-        for (int i = 0; i < mAdapter.size(); i++) {
-            final Row row = (Row) mAdapter.get(i);
-            if (row.isRenderedAsRowView()) {
-                return rowPosition == i;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Sets the {@link PresenterSelector} used to render the row headers.
-     *
-     * @param headerPresenterSelector The PresenterSelector that will determine
-     *        the Presenter for each row header.
-     */
-    public void setHeaderPresenterSelector(PresenterSelector headerPresenterSelector) {
-        mHeaderPresenterSelector = headerPresenterSelector;
-        if (mHeadersFragment != null) {
-            mHeadersFragment.setPresenterSelector(mHeaderPresenterSelector);
-        }
-    }
-
-    private void setHeadersOnScreen(boolean onScreen) {
-        MarginLayoutParams lp;
-        View containerList;
-        containerList = mHeadersFragment.getView();
-        lp = (MarginLayoutParams) containerList.getLayoutParams();
-        lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
-        containerList.setLayoutParams(lp);
-    }
-
-    void showHeaders(boolean show) {
-        if (DEBUG) Log.v(TAG, "showHeaders " + show);
-        mHeadersFragment.setHeadersEnabled(show);
-        setHeadersOnScreen(show);
-        expandMainFragment(!show);
-    }
-
-    private void expandMainFragment(boolean expand) {
-        MarginLayoutParams params = (MarginLayoutParams) mScaleFrameLayout.getLayoutParams();
-        params.setMarginStart(!expand ? mContainerListMarginStart : 0);
-        mScaleFrameLayout.setLayoutParams(params);
-        mMainFragmentAdapter.setExpand(expand);
-
-        setMainFragmentAlignment();
-        final float scaleFactor = !expand
-                && mMainFragmentScaleEnabled
-                && mMainFragmentAdapter.isScalingEnabled() ? mScaleFactor : 1;
-        mScaleFrameLayout.setLayoutScaleY(scaleFactor);
-        mScaleFrameLayout.setChildScale(scaleFactor);
-    }
-
-    private HeadersFragment.OnHeaderClickedListener mHeaderClickedListener =
-        new HeadersFragment.OnHeaderClickedListener() {
-            @Override
-            public void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
-                if (!mCanShowHeaders || !mShowingHeaders || isInHeadersTransition()) {
-                    return;
-                }
-                if (mMainFragment == null || mMainFragment.getView() == null) {
-                    return;
-                }
-                startHeadersTransitionInternal(false);
-                mMainFragment.getView().requestFocus();
-            }
-        };
-
-    class MainFragmentItemViewSelectedListener implements OnItemViewSelectedListener {
-        MainFragmentRowsAdapter mMainFragmentRowsAdapter;
-
-        public MainFragmentItemViewSelectedListener(MainFragmentRowsAdapter fragmentRowsAdapter) {
-            mMainFragmentRowsAdapter = fragmentRowsAdapter;
-        }
-
-        @Override
-        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                RowPresenter.ViewHolder rowViewHolder, Row row) {
-            int position = mMainFragmentRowsAdapter.getSelectedPosition();
-            if (DEBUG) Log.v(TAG, "row selected position " + position);
-            onRowSelected(position);
-            if (mExternalOnItemViewSelectedListener != null) {
-                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
-                        rowViewHolder, row);
-            }
-        }
-    };
-
-    private HeadersFragment.OnHeaderViewSelectedListener mHeaderViewSelectedListener =
-            new HeadersFragment.OnHeaderViewSelectedListener() {
-        @Override
-        public void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
-            int position = mHeadersFragment.getSelectedPosition();
-            if (DEBUG) Log.v(TAG, "header selected position " + position);
-            onRowSelected(position);
-        }
-    };
-
-    void onRowSelected(int position) {
-        // even position is same, it could be data changed, always post selection runnable
-        // to possibly swap main fragment.
-        mSetSelectionRunnable.post(
-                position, SetSelectionRunnable.TYPE_INTERNAL_SYNC, true);
-    }
-
-    void setSelection(int position, boolean smooth) {
-        if (position == NO_POSITION) {
-            return;
-        }
-
-        mSelectedPosition = position;
-        if (mHeadersFragment == null || mMainFragmentAdapter == null) {
-            // onDestroyView() called
-            return;
-        }
-        mHeadersFragment.setSelectedPosition(position, smooth);
-        replaceMainFragment(position);
-
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setSelectedPosition(position, smooth);
-        }
-
-        updateTitleViewVisibility();
-    }
-
-    private void replaceMainFragment(int position) {
-        if (createMainFragment(mAdapter, position)) {
-            swapToMainFragment();
-            expandMainFragment(!(mCanShowHeaders && mShowingHeaders));
-        }
-    }
-
-    private void swapToMainFragment() {
-        final VerticalGridView gridView = mHeadersFragment.getVerticalGridView();
-        if (isShowingHeaders() && gridView != null
-                && gridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
-            // if user is scrolling HeadersFragment,  swap to empty fragment and wait scrolling
-            // finishes.
-            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) {
-                        gridView.removeOnScrollListener(this);
-                        FragmentManager fm = getChildFragmentManager();
-                        Fragment currentFragment = fm.findFragmentById(R.id.scale_frame);
-                        if (currentFragment != mMainFragment) {
-                            fm.beginTransaction().replace(R.id.scale_frame, mMainFragment).commit();
-                        }
-                    }
-                }
-            });
-        } else {
-            // Otherwise swap immediately
-            getChildFragmentManager().beginTransaction()
-                    .replace(R.id.scale_frame, mMainFragment).commit();
-        }
-    }
-
-    /**
-     * Sets the selected row position with smooth animation.
-     */
-    public void setSelectedPosition(int position) {
-        setSelectedPosition(position, true);
-    }
-
-    /**
-     * Gets position of currently selected row.
-     * @return Position of currently selected row.
-     */
-    public int getSelectedPosition() {
-        return mSelectedPosition;
-    }
-
-    /**
-     * @return selected row ViewHolder inside fragment created by {@link MainFragmentRowsAdapter}.
-     */
-    public RowPresenter.ViewHolder getSelectedRowViewHolder() {
-        if (mMainFragmentRowsAdapter != null) {
-            int rowPos = mMainFragmentRowsAdapter.getSelectedPosition();
-            return mMainFragmentRowsAdapter.findRowViewHolderByPosition(rowPos);
-        }
-        return null;
-    }
-
-    /**
-     * Sets the selected row position.
-     */
-    public void setSelectedPosition(int position, boolean smooth) {
-        mSetSelectionRunnable.post(
-                position, SetSelectionRunnable.TYPE_USER_REQUEST, smooth);
-    }
-
-    /**
-     * Selects a Row and perform an optional task on the Row. For example
-     * <code>setSelectedPosition(10, true, new ListRowPresenterSelectItemViewHolderTask(5))</code>
-     * scrolls to 11th row and selects 6th item on that row.  The method will be ignored if
-     * RowsFragment has not been created (i.e. before {@link #onCreateView(LayoutInflater,
-     * ViewGroup, Bundle)}).
-     *
-     * @param rowPosition Which row to select.
-     * @param smooth True to scroll to the row, false for no animation.
-     * @param rowHolderTask Optional task to perform on the Row.  When the task is not null, headers
-     * fragment will be collapsed.
-     */
-    public void setSelectedPosition(int rowPosition, boolean smooth,
-            final Presenter.ViewHolderTask rowHolderTask) {
-        if (mMainFragmentAdapterRegistry == null) {
-            return;
-        }
-        if (rowHolderTask != null) {
-            startHeadersTransition(false);
-        }
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setSelectedPosition(rowPosition, smooth, rowHolderTask);
-        }
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        mHeadersFragment.setAlignment(mContainerListAlignTop);
-        setMainFragmentAlignment();
-
-        if (mCanShowHeaders && mShowingHeaders && mHeadersFragment != null
-                && mHeadersFragment.getView() != null) {
-            mHeadersFragment.getView().requestFocus();
-        } else if ((!mCanShowHeaders || !mShowingHeaders) && mMainFragment != null
-                && mMainFragment.getView() != null) {
-            mMainFragment.getView().requestFocus();
-        }
-
-        if (mCanShowHeaders) {
-            showHeaders(mShowingHeaders);
-        }
-
-        mStateMachine.fireEvent(EVT_HEADER_VIEW_CREATED);
-    }
-
-    private void onExpandTransitionStart(boolean expand, final Runnable callback) {
-        if (expand) {
-            callback.run();
-            return;
-        }
-        // Run a "pre" layout when we go non-expand, in order to get the initial
-        // positions of added rows.
-        new ExpandPreLayout(callback, mMainFragmentAdapter, getView()).execute();
-    }
-
-    private void setMainFragmentAlignment() {
-        int alignOffset = mContainerListAlignTop;
-        if (mMainFragmentScaleEnabled
-                && mMainFragmentAdapter.isScalingEnabled()
-                && mShowingHeaders) {
-            alignOffset = (int) (alignOffset / mScaleFactor + 0.5f);
-        }
-        mMainFragmentAdapter.setAlignment(alignOffset);
-    }
-
-    /**
-     * Enables/disables headers transition on back key support. This is enabled by
-     * default. The BrowseFragment will add a back stack entry when headers are
-     * showing. Running a headers transition when the back key is pressed only
-     * works when the headers state is {@link #HEADERS_ENABLED} or
-     * {@link #HEADERS_HIDDEN}.
-     * <p>
-     * NOTE: If an Activity has its own onBackPressed() handling, you must
-     * disable this feature. You may use {@link #startHeadersTransition(boolean)}
-     * and {@link BrowseTransitionListener} in your own back stack handling.
-     */
-    public final void setHeadersTransitionOnBackEnabled(boolean headersBackStackEnabled) {
-        mHeadersBackStackEnabled = headersBackStackEnabled;
-    }
-
-    /**
-     * Returns true if headers transition on back key support is enabled.
-     */
-    public final boolean isHeadersTransitionOnBackEnabled() {
-        return mHeadersBackStackEnabled;
-    }
-
-    private void readArguments(Bundle args) {
-        if (args == null) {
-            return;
-        }
-        if (args.containsKey(ARG_TITLE)) {
-            setTitle(args.getString(ARG_TITLE));
-        }
-        if (args.containsKey(ARG_HEADERS_STATE)) {
-            setHeadersState(args.getInt(ARG_HEADERS_STATE));
-        }
-    }
-
-    /**
-     * Sets the state for the headers column in the browse fragment. Must be one
-     * of {@link #HEADERS_ENABLED}, {@link #HEADERS_HIDDEN}, or
-     * {@link #HEADERS_DISABLED}.
-     *
-     * @param headersState The state of the headers for the browse fragment.
-     */
-    public void setHeadersState(int headersState) {
-        if (headersState < HEADERS_ENABLED || headersState > HEADERS_DISABLED) {
-            throw new IllegalArgumentException("Invalid headers state: " + headersState);
-        }
-        if (DEBUG) Log.v(TAG, "setHeadersState " + headersState);
-
-        if (headersState != mHeadersState) {
-            mHeadersState = headersState;
-            switch (headersState) {
-                case HEADERS_ENABLED:
-                    mCanShowHeaders = true;
-                    mShowingHeaders = true;
-                    break;
-                case HEADERS_HIDDEN:
-                    mCanShowHeaders = true;
-                    mShowingHeaders = false;
-                    break;
-                case HEADERS_DISABLED:
-                    mCanShowHeaders = false;
-                    mShowingHeaders = false;
-                    break;
-                default:
-                    Log.w(TAG, "Unknown headers state: " + headersState);
-                    break;
-            }
-            if (mHeadersFragment != null) {
-                mHeadersFragment.setHeadersGone(!mCanShowHeaders);
-            }
-        }
-    }
-
-    /**
-     * Returns the state of the headers column in the browse fragment.
-     */
-    public int getHeadersState() {
-        return mHeadersState;
-    }
-
-    @Override
-    protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(FragmentUtil.getContext(BrowseFragment.this),
-                R.transition.lb_browse_entrance_transition);
-    }
-
-    @Override
-    protected void runEntranceTransition(Object entranceTransition) {
-        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
-    }
-
-    @Override
-    protected void onEntranceTransitionPrepare() {
-        mHeadersFragment.onTransitionPrepare();
-        mMainFragmentAdapter.setEntranceTransitionState(false);
-        mMainFragmentAdapter.onTransitionPrepare();
-    }
-
-    @Override
-    protected void onEntranceTransitionStart() {
-        mHeadersFragment.onTransitionStart();
-        mMainFragmentAdapter.onTransitionStart();
-    }
-
-    @Override
-    protected void onEntranceTransitionEnd() {
-        if (mMainFragmentAdapter != null) {
-            mMainFragmentAdapter.onTransitionEnd();
-        }
-
-        if (mHeadersFragment != null) {
-            mHeadersFragment.onTransitionEnd();
-        }
-    }
-
-    void setSearchOrbViewOnScreen(boolean onScreen) {
-        View searchOrbView = getTitleViewAdapter().getSearchAffordanceView();
-        if (searchOrbView != null) {
-            MarginLayoutParams lp = (MarginLayoutParams) searchOrbView.getLayoutParams();
-            lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
-            searchOrbView.setLayoutParams(lp);
-        }
-    }
-
-    void setEntranceTransitionStartState() {
-        setHeadersOnScreen(false);
-        setSearchOrbViewOnScreen(false);
-        // NOTE that mMainFragmentAdapter.setEntranceTransitionState(false) will be called
-        // in onEntranceTransitionPrepare() because mMainFragmentAdapter is still the dummy
-        // one when setEntranceTransitionStartState() is called.
-    }
-
-    void setEntranceTransitionEndState() {
-        setHeadersOnScreen(mShowingHeaders);
-        setSearchOrbViewOnScreen(true);
-        mMainFragmentAdapter.setEntranceTransitionState(true);
-    }
-
-    private class ExpandPreLayout implements ViewTreeObserver.OnPreDrawListener {
-
-        private final View mView;
-        private final Runnable mCallback;
-        private int mState;
-        private MainFragmentAdapter mainFragmentAdapter;
-
-        final static int STATE_INIT = 0;
-        final static int STATE_FIRST_DRAW = 1;
-        final static int STATE_SECOND_DRAW = 2;
-
-        ExpandPreLayout(Runnable callback, MainFragmentAdapter adapter, View view) {
-            mView = view;
-            mCallback = callback;
-            mainFragmentAdapter = adapter;
-        }
-
-        void execute() {
-            mView.getViewTreeObserver().addOnPreDrawListener(this);
-            mainFragmentAdapter.setExpand(false);
-            // always trigger onPreDraw even adapter setExpand() does nothing.
-            mView.invalidate();
-            mState = STATE_INIT;
-        }
-
-        @Override
-        public boolean onPreDraw() {
-            if (getView() == null || FragmentUtil.getContext(BrowseFragment.this) == null) {
-                mView.getViewTreeObserver().removeOnPreDrawListener(this);
-                return true;
-            }
-            if (mState == STATE_INIT) {
-                mainFragmentAdapter.setExpand(true);
-                // always trigger onPreDraw even adapter setExpand() does nothing.
-                mView.invalidate();
-                mState = STATE_FIRST_DRAW;
-            } else if (mState == STATE_FIRST_DRAW) {
-                mCallback.run();
-                mView.getViewTreeObserver().removeOnPreDrawListener(this);
-                mState = STATE_SECOND_DRAW;
-            }
-            return false;
-        }
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java b/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
deleted file mode 100644
index 114e0a7..0000000
--- a/leanback/src/android/support/v17/leanback/app/BrowseSupportFragment.java
+++ /dev/null
@@ -1,1848 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import static android.support.v7.widget.RecyclerView.NO_POSITION;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.support.annotation.ColorInt;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.transition.TransitionListener;
-import android.support.v17.leanback.util.StateMachine.Event;
-import android.support.v17.leanback.util.StateMachine.State;
-import android.support.v17.leanback.widget.BrowseFrameLayout;
-import android.support.v17.leanback.widget.InvisibleRowPresenter;
-import android.support.v17.leanback.widget.ListRow;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.PageRow;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowHeaderPresenter;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.ScaleFrameLayout;
-import android.support.v17.leanback.widget.TitleViewAdapter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentManager.BackStackEntry;
-import android.support.v4.app.FragmentTransaction;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.view.ViewTreeObserver;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A fragment for creating Leanback browse screens. It is composed of a
- * RowsSupportFragment and a HeadersSupportFragment.
- * <p>
- * A BrowseSupportFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list. The elements in this adapter must be subclasses
- * of {@link Row}.
- * <p>
- * The HeadersSupportFragment can be set to be either shown or hidden by default, or
- * may be disabled entirely. See {@link #setHeadersState} for details.
- * <p>
- * By default the BrowseSupportFragment includes support for returning to the headers
- * when the user presses Back. For Activities that customize {@link
- * android.support.v4.app.FragmentActivity#onBackPressed()}, you must disable this default Back key support by
- * calling {@link #setHeadersTransitionOnBackEnabled(boolean)} with false and
- * use {@link BrowseSupportFragment.BrowseTransitionListener} and
- * {@link #startHeadersTransition(boolean)}.
- * <p>
- * The recommended theme to use with a BrowseSupportFragment is
- * {@link android.support.v17.leanback.R.style#Theme_Leanback_Browse}.
- * </p>
- */
-public class BrowseSupportFragment extends BaseSupportFragment {
-
-    // BUNDLE attribute for saving header show/hide status when backstack is used:
-    static final String HEADER_STACK_INDEX = "headerStackIndex";
-    // BUNDLE attribute for saving header show/hide status when backstack is not used:
-    static final String HEADER_SHOW = "headerShow";
-    private static final String IS_PAGE_ROW = "isPageRow";
-    private static final String CURRENT_SELECTED_POSITION = "currentSelectedPosition";
-
-    /**
-     * State to hide headers fragment.
-     */
-    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
-        @Override
-        public void run() {
-            setEntranceTransitionStartState();
-        }
-    };
-
-    /**
-     * Event for Header fragment view is created, we could perform
-     * {@link #setEntranceTransitionStartState()} to hide headers fragment initially.
-     */
-    final Event EVT_HEADER_VIEW_CREATED = new Event("headerFragmentViewCreated");
-
-    /**
-     * Event for {@link #getMainFragment()} view is created, it's additional requirement to execute
-     * {@link #onEntranceTransitionPrepare()}.
-     */
-    final Event EVT_MAIN_FRAGMENT_VIEW_CREATED = new Event("mainFragmentViewCreated");
-
-    /**
-     * Event that data for the screen is ready, this is additional requirement to launch entrance
-     * transition.
-     */
-    final Event EVT_SCREEN_DATA_READY = new Event("screenDataReady");
-
-    @Override
-    void createStateMachineStates() {
-        super.createStateMachineStates();
-        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
-    }
-
-    @Override
-    void createStateMachineTransitions() {
-        super.createStateMachineTransitions();
-        // when headers fragment view is created we could setEntranceTransitionStartState()
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED, STATE_SET_ENTRANCE_START_STATE,
-                EVT_HEADER_VIEW_CREATED);
-
-        // add additional requirement for onEntranceTransitionPrepare()
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
-                STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
-                EVT_MAIN_FRAGMENT_VIEW_CREATED);
-        // add additional requirement to launch entrance transition.
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,  STATE_ENTRANCE_PERFORM,
-                EVT_SCREEN_DATA_READY);
-    }
-
-    final class BackStackListener implements FragmentManager.OnBackStackChangedListener {
-        int mLastEntryCount;
-        int mIndexOfHeadersBackStack;
-
-        BackStackListener() {
-            mLastEntryCount = getFragmentManager().getBackStackEntryCount();
-            mIndexOfHeadersBackStack = -1;
-        }
-
-        void load(Bundle savedInstanceState) {
-            if (savedInstanceState != null) {
-                mIndexOfHeadersBackStack = savedInstanceState.getInt(HEADER_STACK_INDEX, -1);
-                mShowingHeaders = mIndexOfHeadersBackStack == -1;
-            } else {
-                if (!mShowingHeaders) {
-                    getFragmentManager().beginTransaction()
-                            .addToBackStack(mWithHeadersBackStackName).commit();
-                }
-            }
-        }
-
-        void save(Bundle outState) {
-            outState.putInt(HEADER_STACK_INDEX, mIndexOfHeadersBackStack);
-        }
-
-
-        @Override
-        public void onBackStackChanged() {
-            if (getFragmentManager() == null) {
-                Log.w(TAG, "getFragmentManager() is null, stack:", new Exception());
-                return;
-            }
-            int count = getFragmentManager().getBackStackEntryCount();
-            // if backstack is growing and last pushed entry is "headers" backstack,
-            // remember the index of the entry.
-            if (count > mLastEntryCount) {
-                BackStackEntry entry = getFragmentManager().getBackStackEntryAt(count - 1);
-                if (mWithHeadersBackStackName.equals(entry.getName())) {
-                    mIndexOfHeadersBackStack = count - 1;
-                }
-            } else if (count < mLastEntryCount) {
-                // if popped "headers" backstack, initiate the show header transition if needed
-                if (mIndexOfHeadersBackStack >= count) {
-                    if (!isHeadersDataReady()) {
-                        // if main fragment was restored first before BrowseSupportFragment's adapter gets
-                        // restored: don't start header transition, but add the entry back.
-                        getFragmentManager().beginTransaction()
-                                .addToBackStack(mWithHeadersBackStackName).commit();
-                        return;
-                    }
-                    mIndexOfHeadersBackStack = -1;
-                    if (!mShowingHeaders) {
-                        startHeadersTransitionInternal(true);
-                    }
-                }
-            }
-            mLastEntryCount = count;
-        }
-    }
-
-    /**
-     * Listener for transitions between browse headers and rows.
-     */
-    public static class BrowseTransitionListener {
-        /**
-         * Callback when headers transition starts.
-         *
-         * @param withHeaders True if the transition will result in headers
-         *        being shown, false otherwise.
-         */
-        public void onHeadersTransitionStart(boolean withHeaders) {
-        }
-        /**
-         * Callback when headers transition stops.
-         *
-         * @param withHeaders True if the transition will result in headers
-         *        being shown, false otherwise.
-         */
-        public void onHeadersTransitionStop(boolean withHeaders) {
-        }
-    }
-
-    private class SetSelectionRunnable implements Runnable {
-        static final int TYPE_INVALID = -1;
-        static final int TYPE_INTERNAL_SYNC = 0;
-        static final int TYPE_USER_REQUEST = 1;
-
-        private int mPosition;
-        private int mType;
-        private boolean mSmooth;
-
-        SetSelectionRunnable() {
-            reset();
-        }
-
-        void post(int position, int type, boolean smooth) {
-            // Posting the set selection, rather than calling it immediately, prevents an issue
-            // with adapter changes.  Example: a row is added before the current selected row;
-            // first the fast lane view updates its selection, then the rows fragment has that
-            // new selection propagated immediately; THEN the rows view processes the same adapter
-            // change and moves the selection again.
-            if (type >= mType) {
-                mPosition = position;
-                mType = type;
-                mSmooth = smooth;
-                mBrowseFrame.removeCallbacks(this);
-                mBrowseFrame.post(this);
-            }
-        }
-
-        @Override
-        public void run() {
-            setSelection(mPosition, mSmooth);
-            reset();
-        }
-
-        private void reset() {
-            mPosition = -1;
-            mType = TYPE_INVALID;
-            mSmooth = false;
-        }
-    }
-
-    /**
-     * Possible set of actions that {@link BrowseSupportFragment} exposes to clients. Custom
-     * fragments can interact with {@link BrowseSupportFragment} using this interface.
-     */
-    public interface FragmentHost {
-        /**
-         * Fragments are required to invoke this callback once their view is created
-         * inside {@link Fragment#onViewCreated} method. {@link BrowseSupportFragment} starts the entrance
-         * animation only after receiving this callback. Failure to invoke this method
-         * will lead to fragment not showing up.
-         *
-         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
-         */
-        void notifyViewCreated(MainFragmentAdapter fragmentAdapter);
-
-        /**
-         * Fragments mapped to {@link PageRow} are required to invoke this callback once their data
-         * is created for transition, the entrance animation only after receiving this callback.
-         * Failure to invoke this method will lead to fragment not showing up.
-         *
-         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
-         */
-        void notifyDataReady(MainFragmentAdapter fragmentAdapter);
-
-        /**
-         * Show or hide title view in {@link BrowseSupportFragment} for fragments mapped to
-         * {@link PageRow}.  Otherwise the request is ignored, in that case BrowseSupportFragment is fully
-         * in control of showing/hiding title view.
-         * <p>
-         * When HeadersSupportFragment is visible, BrowseSupportFragment will hide search affordance view if
-         * there are other focusable rows above currently focused row.
-         *
-         * @param show Boolean indicating whether or not to show the title view.
-         */
-        void showTitleView(boolean show);
-    }
-
-    /**
-     * Default implementation of {@link FragmentHost} that is used only by
-     * {@link BrowseSupportFragment}.
-     */
-    private final class FragmentHostImpl implements FragmentHost {
-        boolean mShowTitleView = true;
-
-        FragmentHostImpl() {
-        }
-
-        @Override
-        public void notifyViewCreated(MainFragmentAdapter fragmentAdapter) {
-            mStateMachine.fireEvent(EVT_MAIN_FRAGMENT_VIEW_CREATED);
-            if (!mIsPageRow) {
-                // If it's not a PageRow: it's a ListRow, so we already have data ready.
-                mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
-            }
-        }
-
-        @Override
-        public void notifyDataReady(MainFragmentAdapter fragmentAdapter) {
-            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
-            // ignore the request.
-            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
-                return;
-            }
-
-            // We only honor showTitle request for PageRows.
-            if (!mIsPageRow) {
-                return;
-            }
-
-            mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
-        }
-
-        @Override
-        public void showTitleView(boolean show) {
-            mShowTitleView = show;
-
-            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
-            // ignore the request.
-            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
-                return;
-            }
-
-            // We only honor showTitle request for PageRows.
-            if (!mIsPageRow) {
-                return;
-            }
-
-            updateTitleViewVisibility();
-        }
-    }
-
-    /**
-     * Interface that defines the interaction between {@link BrowseSupportFragment} and its main
-     * content fragment. The key method is {@link MainFragmentAdapter#getFragment()},
-     * it will be used to get the fragment to be shown in the content section. Clients can
-     * provide any implementation of fragment and customize its interaction with
-     * {@link BrowseSupportFragment} by overriding the necessary methods.
-     *
-     * <p>
-     * Clients are expected to provide
-     * an instance of {@link MainFragmentAdapterRegistry} which will be responsible for providing
-     * implementations of {@link MainFragmentAdapter} for given content types. Currently
-     * we support different types of content - {@link ListRow}, {@link PageRow} or any subtype
-     * of {@link Row}. We provide an out of the box adapter implementation for any rows other than
-     * {@link PageRow} - {@link android.support.v17.leanback.app.RowsSupportFragment.MainFragmentAdapter}.
-     *
-     * <p>
-     * {@link PageRow} is intended to give full flexibility to developers in terms of Fragment
-     * design. Users will have to provide an implementation of {@link MainFragmentAdapter}
-     * and provide that through {@link MainFragmentAdapterRegistry}.
-     * {@link MainFragmentAdapter} implementation can supply any fragment and override
-     * just those interactions that makes sense.
-     */
-    public static class MainFragmentAdapter<T extends Fragment> {
-        private boolean mScalingEnabled;
-        private final T mFragment;
-        FragmentHostImpl mFragmentHost;
-
-        public MainFragmentAdapter(T fragment) {
-            this.mFragment = fragment;
-        }
-
-        public final T getFragment() {
-            return mFragment;
-        }
-
-        /**
-         * Returns whether its scrolling.
-         */
-        public boolean isScrolling() {
-            return false;
-        }
-
-        /**
-         * Set the visibility of titles/hover card of browse rows.
-         */
-        public void setExpand(boolean expand) {
-        }
-
-        /**
-         * For rows that willing to participate entrance transition,  this function
-         * hide views if afterTransition is true,  show views if afterTransition is false.
-         */
-        public void setEntranceTransitionState(boolean state) {
-        }
-
-        /**
-         * Sets the window alignment and also the pivots for scale operation.
-         */
-        public void setAlignment(int windowAlignOffsetFromTop) {
-        }
-
-        /**
-         * Callback indicating transition prepare start.
-         */
-        public boolean onTransitionPrepare() {
-            return false;
-        }
-
-        /**
-         * Callback indicating transition start.
-         */
-        public void onTransitionStart() {
-        }
-
-        /**
-         * Callback indicating transition end.
-         */
-        public void onTransitionEnd() {
-        }
-
-        /**
-         * Returns whether row scaling is enabled.
-         */
-        public boolean isScalingEnabled() {
-            return mScalingEnabled;
-        }
-
-        /**
-         * Sets the row scaling property.
-         */
-        public void setScalingEnabled(boolean scalingEnabled) {
-            this.mScalingEnabled = scalingEnabled;
-        }
-
-        /**
-         * Returns the current host interface so that main fragment can interact with
-         * {@link BrowseSupportFragment}.
-         */
-        public final FragmentHost getFragmentHost() {
-            return mFragmentHost;
-        }
-
-        void setFragmentHost(FragmentHostImpl fragmentHost) {
-            this.mFragmentHost = fragmentHost;
-        }
-    }
-
-    /**
-     * Interface to be implemented by all fragments for providing an instance of
-     * {@link MainFragmentAdapter}. Both {@link RowsSupportFragment} and custom fragment provided
-     * against {@link PageRow} will need to implement this interface.
-     */
-    public interface MainFragmentAdapterProvider {
-        /**
-         * Returns an instance of {@link MainFragmentAdapter} that {@link BrowseSupportFragment}
-         * would use to communicate with the target fragment.
-         */
-        MainFragmentAdapter getMainFragmentAdapter();
-    }
-
-    /**
-     * Interface to be implemented by {@link RowsSupportFragment} and its subclasses for providing
-     * an instance of {@link MainFragmentRowsAdapter}.
-     */
-    public interface MainFragmentRowsAdapterProvider {
-        /**
-         * Returns an instance of {@link MainFragmentRowsAdapter} that {@link BrowseSupportFragment}
-         * would use to communicate with the target fragment.
-         */
-        MainFragmentRowsAdapter getMainFragmentRowsAdapter();
-    }
-
-    /**
-     * This is used to pass information to {@link RowsSupportFragment} or its subclasses.
-     * {@link BrowseSupportFragment} uses this interface to pass row based interaction events to
-     * the target fragment.
-     */
-    public static class MainFragmentRowsAdapter<T extends Fragment> {
-        private final T mFragment;
-
-        public MainFragmentRowsAdapter(T fragment) {
-            if (fragment == null) {
-                throw new IllegalArgumentException("Fragment can't be null");
-            }
-            this.mFragment = fragment;
-        }
-
-        public final T getFragment() {
-            return mFragment;
-        }
-        /**
-         * Set the visibility titles/hover of browse rows.
-         */
-        public void setAdapter(ObjectAdapter adapter) {
-        }
-
-        /**
-         * Sets an item clicked listener on the fragment.
-         */
-        public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        }
-
-        /**
-         * Sets an item selection listener.
-         */
-        public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
-        }
-
-        /**
-         * Selects a Row and perform an optional task on the Row.
-         */
-        public void setSelectedPosition(int rowPosition,
-                                        boolean smooth,
-                                        final Presenter.ViewHolderTask rowHolderTask) {
-        }
-
-        /**
-         * Selects a Row.
-         */
-        public void setSelectedPosition(int rowPosition, boolean smooth) {
-        }
-
-        /**
-         * @return The position of selected row.
-         */
-        public int getSelectedPosition() {
-            return 0;
-        }
-
-        /**
-         * @param position Position of Row.
-         * @return Row ViewHolder.
-         */
-        public RowPresenter.ViewHolder findRowViewHolderByPosition(int position) {
-            return null;
-        }
-    }
-
-    private boolean createMainFragment(ObjectAdapter adapter, int position) {
-        Object item = null;
-        if (!mCanShowHeaders) {
-            // when header is disabled, we can decide to use RowsSupportFragment even no data.
-        } else if (adapter == null || adapter.size() == 0) {
-            return false;
-        } else {
-            if (position < 0) {
-                position = 0;
-            } else if (position >= adapter.size()) {
-                throw new IllegalArgumentException(
-                        String.format("Invalid position %d requested", position));
-            }
-            item = adapter.get(position);
-        }
-
-        boolean oldIsPageRow = mIsPageRow;
-        Object oldPageRow = mPageRow;
-        mIsPageRow = mCanShowHeaders && item instanceof PageRow;
-        mPageRow = mIsPageRow ? item : null;
-        boolean swap;
-
-        if (mMainFragment == null) {
-            swap = true;
-        } else {
-            if (oldIsPageRow) {
-                if (mIsPageRow) {
-                    if (oldPageRow == null) {
-                        // fragment is restored, page row object not yet set, so just set the
-                        // mPageRow object and there is no need to replace the fragment
-                        swap = false;
-                    } else {
-                        // swap if page row object changes
-                        swap = oldPageRow != mPageRow;
-                    }
-                } else {
-                    swap = true;
-                }
-            } else {
-                swap = mIsPageRow;
-            }
-        }
-
-        if (swap) {
-            mMainFragment = mMainFragmentAdapterRegistry.createFragment(item);
-            if (!(mMainFragment instanceof MainFragmentAdapterProvider)) {
-                throw new IllegalArgumentException(
-                        "Fragment must implement MainFragmentAdapterProvider");
-            }
-
-            setMainFragmentAdapter();
-        }
-
-        return swap;
-    }
-
-    void setMainFragmentAdapter() {
-        mMainFragmentAdapter = ((MainFragmentAdapterProvider) mMainFragment)
-                .getMainFragmentAdapter();
-        mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
-        if (!mIsPageRow) {
-            if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
-                setMainFragmentRowsAdapter(((MainFragmentRowsAdapterProvider) mMainFragment)
-                        .getMainFragmentRowsAdapter());
-            } else {
-                setMainFragmentRowsAdapter(null);
-            }
-            mIsPageRow = mMainFragmentRowsAdapter == null;
-        } else {
-            setMainFragmentRowsAdapter(null);
-        }
-    }
-
-    /**
-     * Factory class responsible for creating fragment given the current item. {@link ListRow}
-     * should return {@link RowsSupportFragment} or its subclass whereas {@link PageRow}
-     * can return any fragment class.
-     */
-    public abstract static class FragmentFactory<T extends Fragment> {
-        public abstract T createFragment(Object row);
-    }
-
-    /**
-     * FragmentFactory implementation for {@link ListRow}.
-     */
-    public static class ListRowFragmentFactory extends FragmentFactory<RowsSupportFragment> {
-        @Override
-        public RowsSupportFragment createFragment(Object row) {
-            return new RowsSupportFragment();
-        }
-    }
-
-    /**
-     * Registry class maintaining the mapping of {@link Row} subclasses to {@link FragmentFactory}.
-     * BrowseRowFragment automatically registers {@link ListRowFragmentFactory} for
-     * handling {@link ListRow}. Developers can override that and also if they want to
-     * use custom fragment, they can register a custom {@link FragmentFactory}
-     * against {@link PageRow}.
-     */
-    public final static class MainFragmentAdapterRegistry {
-        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
-        private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
-
-        public MainFragmentAdapterRegistry() {
-            registerFragment(ListRow.class, sDefaultFragmentFactory);
-        }
-
-        public void registerFragment(Class rowClass, FragmentFactory factory) {
-            mItemToFragmentFactoryMapping.put(rowClass, factory);
-        }
-
-        public Fragment createFragment(Object item) {
-            FragmentFactory fragmentFactory = item == null ? sDefaultFragmentFactory :
-                    mItemToFragmentFactoryMapping.get(item.getClass());
-            if (fragmentFactory == null && !(item instanceof PageRow)) {
-                fragmentFactory = sDefaultFragmentFactory;
-            }
-
-            return fragmentFactory.createFragment(item);
-        }
-    }
-
-    static final String TAG = "BrowseSupportFragment";
-
-    private static final String LB_HEADERS_BACKSTACK = "lbHeadersBackStack_";
-
-    static boolean DEBUG = false;
-
-    /** The headers fragment is enabled and shown by default. */
-    public static final int HEADERS_ENABLED = 1;
-
-    /** The headers fragment is enabled and hidden by default. */
-    public static final int HEADERS_HIDDEN = 2;
-
-    /** The headers fragment is disabled and will never be shown. */
-    public static final int HEADERS_DISABLED = 3;
-
-    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry =
-            new MainFragmentAdapterRegistry();
-    MainFragmentAdapter mMainFragmentAdapter;
-    Fragment mMainFragment;
-    HeadersSupportFragment mHeadersSupportFragment;
-    MainFragmentRowsAdapter mMainFragmentRowsAdapter;
-    ListRowDataAdapter mMainFragmentListRowDataAdapter;
-
-    private ObjectAdapter mAdapter;
-    private PresenterSelector mAdapterPresenter;
-
-    private int mHeadersState = HEADERS_ENABLED;
-    private int mBrandColor = Color.TRANSPARENT;
-    private boolean mBrandColorSet;
-
-    BrowseFrameLayout mBrowseFrame;
-    private ScaleFrameLayout mScaleFrameLayout;
-    boolean mHeadersBackStackEnabled = true;
-    String mWithHeadersBackStackName;
-    boolean mShowingHeaders = true;
-    boolean mCanShowHeaders = true;
-    private int mContainerListMarginStart;
-    private int mContainerListAlignTop;
-    private boolean mMainFragmentScaleEnabled = true;
-    OnItemViewSelectedListener mExternalOnItemViewSelectedListener;
-    private OnItemViewClickedListener mOnItemViewClickedListener;
-    private int mSelectedPosition = -1;
-    private float mScaleFactor;
-    boolean mIsPageRow;
-    Object mPageRow;
-
-    private PresenterSelector mHeaderPresenterSelector;
-    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
-
-    // transition related:
-    Object mSceneWithHeaders;
-    Object mSceneWithoutHeaders;
-    private Object mSceneAfterEntranceTransition;
-    Object mHeadersTransition;
-    BackStackListener mBackStackChangedListener;
-    BrowseTransitionListener mBrowseTransitionListener;
-
-    private static final String ARG_TITLE = BrowseSupportFragment.class.getCanonicalName() + ".title";
-    private static final String ARG_HEADERS_STATE =
-        BrowseSupportFragment.class.getCanonicalName() + ".headersState";
-
-    /**
-     * Creates arguments for a browse fragment.
-     *
-     * @param args The Bundle to place arguments into, or null if the method
-     *        should return a new Bundle.
-     * @param title The title of the BrowseSupportFragment.
-     * @param headersState The initial state of the headers of the
-     *        BrowseSupportFragment. Must be one of {@link #HEADERS_ENABLED}, {@link
-     *        #HEADERS_HIDDEN}, or {@link #HEADERS_DISABLED}.
-     * @return A Bundle with the given arguments for creating a BrowseSupportFragment.
-     */
-    public static Bundle createArgs(Bundle args, String title, int headersState) {
-        if (args == null) {
-            args = new Bundle();
-        }
-        args.putString(ARG_TITLE, title);
-        args.putInt(ARG_HEADERS_STATE, headersState);
-        return args;
-    }
-
-    /**
-     * Sets the brand color for the browse fragment. The brand color is used as
-     * the primary color for UI elements in the browse fragment. For example,
-     * the background color of the headers fragment uses the brand color.
-     *
-     * @param color The color to use as the brand color of the fragment.
-     */
-    public void setBrandColor(@ColorInt int color) {
-        mBrandColor = color;
-        mBrandColorSet = true;
-
-        if (mHeadersSupportFragment != null) {
-            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
-        }
-    }
-
-    /**
-     * Returns the brand color for the browse fragment.
-     * The default is transparent.
-     */
-    @ColorInt
-    public int getBrandColor() {
-        return mBrandColor;
-    }
-
-    /**
-     * Wrapping app provided PresenterSelector to support InvisibleRowPresenter for SectionRow
-     * DividerRow and PageRow.
-     */
-    private void updateWrapperPresenter() {
-        if (mAdapter == null) {
-            mAdapterPresenter = null;
-            return;
-        }
-        final PresenterSelector adapterPresenter = mAdapter.getPresenterSelector();
-        if (adapterPresenter == null) {
-            throw new IllegalArgumentException("Adapter.getPresenterSelector() is null");
-        }
-        if (adapterPresenter == mAdapterPresenter) {
-            return;
-        }
-        mAdapterPresenter = adapterPresenter;
-
-        Presenter[] presenters = adapterPresenter.getPresenters();
-        final Presenter invisibleRowPresenter = new InvisibleRowPresenter();
-        final Presenter[] allPresenters = new Presenter[presenters.length + 1];
-        System.arraycopy(allPresenters, 0, presenters, 0, presenters.length);
-        allPresenters[allPresenters.length - 1] = invisibleRowPresenter;
-        mAdapter.setPresenterSelector(new PresenterSelector() {
-            @Override
-            public Presenter getPresenter(Object item) {
-                Row row = (Row) item;
-                if (row.isRenderedAsRowView()) {
-                    return adapterPresenter.getPresenter(item);
-                } else {
-                    return invisibleRowPresenter;
-                }
-            }
-
-            @Override
-            public Presenter[] getPresenters() {
-                return allPresenters;
-            }
-        });
-    }
-
-    /**
-     * Sets the adapter containing the rows for the fragment.
-     *
-     * <p>The items referenced by the adapter must be be derived from
-     * {@link Row}. These rows will be used by the rows fragment and the headers
-     * fragment (if not disabled) to render the browse rows.
-     *
-     * @param adapter An ObjectAdapter for the browse rows. All items must
-     *        derive from {@link Row}.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        updateWrapperPresenter();
-        if (getView() == null) {
-            return;
-        }
-
-        updateMainFragmentRowsAdapter();
-        mHeadersSupportFragment.setAdapter(mAdapter);
-    }
-
-    void setMainFragmentRowsAdapter(MainFragmentRowsAdapter mainFragmentRowsAdapter) {
-        if (mainFragmentRowsAdapter == mMainFragmentRowsAdapter) {
-            return;
-        }
-        // first clear previous mMainFragmentRowsAdapter and set a new mMainFragmentRowsAdapter
-        if (mMainFragmentRowsAdapter != null) {
-            // RowsFragment cannot change click/select listeners after view created.
-            // The main fragment and adapter should be GCed as long as there is no reference from
-            // BrowseSupportFragment to it.
-            mMainFragmentRowsAdapter.setAdapter(null);
-        }
-        mMainFragmentRowsAdapter = mainFragmentRowsAdapter;
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setOnItemViewSelectedListener(
-                    new MainFragmentItemViewSelectedListener(mMainFragmentRowsAdapter));
-            mMainFragmentRowsAdapter.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
-        // second update mMainFragmentListRowDataAdapter set on mMainFragmentRowsAdapter
-        updateMainFragmentRowsAdapter();
-    }
-
-    /**
-     * Update mMainFragmentListRowDataAdapter and set it on mMainFragmentRowsAdapter.
-     * It also clears old mMainFragmentListRowDataAdapter.
-     */
-    void updateMainFragmentRowsAdapter() {
-        if (mMainFragmentListRowDataAdapter != null) {
-            mMainFragmentListRowDataAdapter.detach();
-            mMainFragmentListRowDataAdapter = null;
-        }
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentListRowDataAdapter = mAdapter == null
-                    ? null : new ListRowDataAdapter(mAdapter);
-            mMainFragmentRowsAdapter.setAdapter(mMainFragmentListRowDataAdapter);
-        }
-    }
-
-    public final MainFragmentAdapterRegistry getMainFragmentRegistry() {
-        return mMainFragmentAdapterRegistry;
-    }
-
-    /**
-     * Returns the adapter containing the rows for the fragment.
-     */
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    /**
-     * Sets an item selection listener.
-     */
-    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
-        mExternalOnItemViewSelectedListener = listener;
-    }
-
-    /**
-     * Returns an item selection listener.
-     */
-    public OnItemViewSelectedListener getOnItemViewSelectedListener() {
-        return mExternalOnItemViewSelectedListener;
-    }
-
-    /**
-     * Get RowsSupportFragment if it's bound to BrowseSupportFragment or null if either BrowseSupportFragment has
-     * not been created yet or a different fragment is bound to it.
-     *
-     * @return RowsSupportFragment if it's bound to BrowseSupportFragment or null otherwise.
-     */
-    public RowsSupportFragment getRowsSupportFragment() {
-        if (mMainFragment instanceof RowsSupportFragment) {
-            return (RowsSupportFragment) mMainFragment;
-        }
-
-        return null;
-    }
-
-    /**
-     * @return Current main fragment or null if not created.
-     */
-    public Fragment getMainFragment() {
-        return mMainFragment;
-    }
-
-    /**
-     * Get currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
-     * @return Currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
-     */
-    public HeadersSupportFragment getHeadersSupportFragment() {
-        return mHeadersSupportFragment;
-    }
-
-    /**
-     * Sets an item clicked listener on the fragment.
-     * OnItemViewClickedListener will override {@link View.OnClickListener} that
-     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
-     * So in general, developer should choose one of the listeners but not both.
-     */
-    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        mOnItemViewClickedListener = listener;
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setOnItemViewClickedListener(listener);
-        }
-    }
-
-    /**
-     * Returns the item Clicked listener.
-     */
-    public OnItemViewClickedListener getOnItemViewClickedListener() {
-        return mOnItemViewClickedListener;
-    }
-
-    /**
-     * Starts a headers transition.
-     *
-     * <p>This method will begin a transition to either show or hide the
-     * headers, depending on the value of withHeaders. If headers are disabled
-     * for this browse fragment, this method will throw an exception.
-     *
-     * @param withHeaders True if the headers should transition to being shown,
-     *        false if the transition should result in headers being hidden.
-     */
-    public void startHeadersTransition(boolean withHeaders) {
-        if (!mCanShowHeaders) {
-            throw new IllegalStateException("Cannot start headers transition");
-        }
-        if (isInHeadersTransition() || mShowingHeaders == withHeaders) {
-            return;
-        }
-        startHeadersTransitionInternal(withHeaders);
-    }
-
-    /**
-     * Returns true if the headers transition is currently running.
-     */
-    public boolean isInHeadersTransition() {
-        return mHeadersTransition != null;
-    }
-
-    /**
-     * Returns true if headers are shown.
-     */
-    public boolean isShowingHeaders() {
-        return mShowingHeaders;
-    }
-
-    /**
-     * Sets a listener for browse fragment transitions.
-     *
-     * @param listener The listener to call when a browse headers transition
-     *        begins or ends.
-     */
-    public void setBrowseTransitionListener(BrowseTransitionListener listener) {
-        mBrowseTransitionListener = listener;
-    }
-
-    /**
-     * @deprecated use {@link BrowseSupportFragment#enableMainFragmentScaling(boolean)} instead.
-     *
-     * @param enable true to enable row scaling
-     */
-    @Deprecated
-    public void enableRowScaling(boolean enable) {
-        enableMainFragmentScaling(enable);
-    }
-
-    /**
-     * Enables scaling of main fragment when headers are present. For the page/row fragment,
-     * scaling is enabled only when both this method and
-     * {@link MainFragmentAdapter#isScalingEnabled()} are enabled.
-     *
-     * @param enable true to enable row scaling
-     */
-    public void enableMainFragmentScaling(boolean enable) {
-        mMainFragmentScaleEnabled = enable;
-    }
-
-    void startHeadersTransitionInternal(final boolean withHeaders) {
-        if (getFragmentManager().isDestroyed()) {
-            return;
-        }
-        if (!isHeadersDataReady()) {
-            return;
-        }
-        mShowingHeaders = withHeaders;
-        mMainFragmentAdapter.onTransitionPrepare();
-        mMainFragmentAdapter.onTransitionStart();
-        onExpandTransitionStart(!withHeaders, new Runnable() {
-            @Override
-            public void run() {
-                mHeadersSupportFragment.onTransitionPrepare();
-                mHeadersSupportFragment.onTransitionStart();
-                createHeadersTransition();
-                if (mBrowseTransitionListener != null) {
-                    mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
-                }
-                TransitionHelper.runTransition(
-                        withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders, mHeadersTransition);
-                if (mHeadersBackStackEnabled) {
-                    if (!withHeaders) {
-                        getFragmentManager().beginTransaction()
-                                .addToBackStack(mWithHeadersBackStackName).commit();
-                    } else {
-                        int index = mBackStackChangedListener.mIndexOfHeadersBackStack;
-                        if (index >= 0) {
-                            BackStackEntry entry = getFragmentManager().getBackStackEntryAt(index);
-                            getFragmentManager().popBackStackImmediate(entry.getId(),
-                                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    boolean isVerticalScrolling() {
-        // don't run transition
-        return mHeadersSupportFragment.isScrolling() || mMainFragmentAdapter.isScrolling();
-    }
-
-
-    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
-            new BrowseFrameLayout.OnFocusSearchListener() {
-        @Override
-        public View onFocusSearch(View focused, int direction) {
-            // if headers is running transition,  focus stays
-            if (mCanShowHeaders && isInHeadersTransition()) {
-                return focused;
-            }
-            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
-
-            if (getTitleView() != null && focused != getTitleView()
-                    && direction == View.FOCUS_UP) {
-                return getTitleView();
-            }
-            if (getTitleView() != null && getTitleView().hasFocus()
-                    && direction == View.FOCUS_DOWN) {
-                return mCanShowHeaders && mShowingHeaders
-                        ? mHeadersSupportFragment.getVerticalGridView() : mMainFragment.getView();
-            }
-
-            boolean isRtl = ViewCompat.getLayoutDirection(focused)
-                    == ViewCompat.LAYOUT_DIRECTION_RTL;
-            int towardStart = isRtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
-            int towardEnd = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
-            if (mCanShowHeaders && direction == towardStart) {
-                if (isVerticalScrolling() || mShowingHeaders || !isHeadersDataReady()) {
-                    return focused;
-                }
-                return mHeadersSupportFragment.getVerticalGridView();
-            } else if (direction == towardEnd) {
-                if (isVerticalScrolling()) {
-                    return focused;
-                } else if (mMainFragment != null && mMainFragment.getView() != null) {
-                    return mMainFragment.getView();
-                }
-                return focused;
-            } else if (direction == View.FOCUS_DOWN && mShowingHeaders) {
-                // disable focus_down moving into PageFragment.
-                return focused;
-            } else {
-                return null;
-            }
-        }
-    };
-
-    final boolean isHeadersDataReady() {
-        return mAdapter != null && mAdapter.size() != 0;
-    }
-
-    private final BrowseFrameLayout.OnChildFocusListener mOnChildFocusListener =
-            new BrowseFrameLayout.OnChildFocusListener() {
-
-        @Override
-        public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-            if (getChildFragmentManager().isDestroyed()) {
-                return true;
-            }
-            // Make sure not changing focus when requestFocus() is called.
-            if (mCanShowHeaders && mShowingHeaders) {
-                if (mHeadersSupportFragment != null && mHeadersSupportFragment.getView() != null
-                        && mHeadersSupportFragment.getView().requestFocus(
-                                direction, previouslyFocusedRect)) {
-                    return true;
-                }
-            }
-            if (mMainFragment != null && mMainFragment.getView() != null
-                    && mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
-                return true;
-            }
-            return getTitleView() != null
-                    && getTitleView().requestFocus(direction, previouslyFocusedRect);
-        }
-
-        @Override
-        public void onRequestChildFocus(View child, View focused) {
-            if (getChildFragmentManager().isDestroyed()) {
-                return;
-            }
-            if (!mCanShowHeaders || isInHeadersTransition()) return;
-            int childId = child.getId();
-            if (childId == R.id.browse_container_dock && mShowingHeaders) {
-                startHeadersTransitionInternal(false);
-            } else if (childId == R.id.browse_headers_dock && !mShowingHeaders) {
-                startHeadersTransitionInternal(true);
-            }
-        }
-    };
-
-    @Override
-    public void onSaveInstanceState(Bundle outState) {
-        super.onSaveInstanceState(outState);
-        outState.putInt(CURRENT_SELECTED_POSITION, mSelectedPosition);
-        outState.putBoolean(IS_PAGE_ROW, mIsPageRow);
-
-        if (mBackStackChangedListener != null) {
-            mBackStackChangedListener.save(outState);
-        } else {
-            outState.putBoolean(HEADER_SHOW, mShowingHeaders);
-        }
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        final Context context = getContext();
-        TypedArray ta = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
-        mContainerListMarginStart = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginStart, context.getResources()
-                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
-        mContainerListAlignTop = (int) ta.getDimension(
-                R.styleable.LeanbackTheme_browseRowsMarginTop, context.getResources()
-                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
-        ta.recycle();
-
-        readArguments(getArguments());
-
-        if (mCanShowHeaders) {
-            if (mHeadersBackStackEnabled) {
-                mWithHeadersBackStackName = LB_HEADERS_BACKSTACK + this;
-                mBackStackChangedListener = new BackStackListener();
-                getFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
-                mBackStackChangedListener.load(savedInstanceState);
-            } else {
-                if (savedInstanceState != null) {
-                    mShowingHeaders = savedInstanceState.getBoolean(HEADER_SHOW);
-                }
-            }
-        }
-
-        mScaleFactor = getResources().getFraction(R.fraction.lb_browse_rows_scale, 1, 1);
-    }
-
-    @Override
-    public void onDestroyView() {
-        setMainFragmentRowsAdapter(null);
-        mPageRow = null;
-        mMainFragmentAdapter = null;
-        mMainFragment = null;
-        mHeadersSupportFragment = null;
-        super.onDestroyView();
-    }
-
-    @Override
-    public void onDestroy() {
-        if (mBackStackChangedListener != null) {
-            getFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
-        }
-        super.onDestroy();
-    }
-
-    /**
-     * Creates a new {@link HeadersSupportFragment} instance. Subclass of BrowseSupportFragment may override and
-     * return an instance of subclass of HeadersSupportFragment, e.g. when app wants to replace presenter
-     * to render HeaderItem.
-     *
-     * @return A new instance of {@link HeadersSupportFragment} or its subclass.
-     */
-    public HeadersSupportFragment onCreateHeadersSupportFragment() {
-        return new HeadersSupportFragment();
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-
-        if (getChildFragmentManager().findFragmentById(R.id.scale_frame) == null) {
-            mHeadersSupportFragment = onCreateHeadersSupportFragment();
-
-            createMainFragment(mAdapter, mSelectedPosition);
-            FragmentTransaction ft = getChildFragmentManager().beginTransaction()
-                    .replace(R.id.browse_headers_dock, mHeadersSupportFragment);
-
-            if (mMainFragment != null) {
-                ft.replace(R.id.scale_frame, mMainFragment);
-            } else {
-                // Empty adapter used to guard against lazy adapter loading. When this
-                // fragment is instantiated, mAdapter might not have the data or might not
-                // have been set. In either of those cases mFragmentAdapter will be null.
-                // This way we can maintain the invariant that mMainFragmentAdapter is never
-                // null and it avoids doing null checks all over the code.
-                mMainFragmentAdapter = new MainFragmentAdapter(null);
-                mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
-            }
-
-            ft.commit();
-        } else {
-            mHeadersSupportFragment = (HeadersSupportFragment) getChildFragmentManager()
-                    .findFragmentById(R.id.browse_headers_dock);
-            mMainFragment = getChildFragmentManager().findFragmentById(R.id.scale_frame);
-
-            mIsPageRow = savedInstanceState != null
-                    && savedInstanceState.getBoolean(IS_PAGE_ROW, false);
-            // mPageRow object is unable to restore, if its null and mIsPageRow is true, this is
-            // the case for restoring, later if setSelection() triggers a createMainFragment(),
-            // should not create fragment.
-
-            mSelectedPosition = savedInstanceState != null
-                    ? savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
-
-            setMainFragmentAdapter();
-        }
-
-        mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
-        if (mHeaderPresenterSelector != null) {
-            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
-        }
-        mHeadersSupportFragment.setAdapter(mAdapter);
-        mHeadersSupportFragment.setOnHeaderViewSelectedListener(mHeaderViewSelectedListener);
-        mHeadersSupportFragment.setOnHeaderClickedListener(mHeaderClickedListener);
-
-        View root = inflater.inflate(R.layout.lb_browse_fragment, container, false);
-
-        getProgressBarManager().setRootView((ViewGroup)root);
-
-        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
-        mBrowseFrame.setOnChildFocusListener(mOnChildFocusListener);
-        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
-
-        installTitleView(inflater, mBrowseFrame, savedInstanceState);
-
-        mScaleFrameLayout = (ScaleFrameLayout) root.findViewById(R.id.scale_frame);
-        mScaleFrameLayout.setPivotX(0);
-        mScaleFrameLayout.setPivotY(mContainerListAlignTop);
-
-        if (mBrandColorSet) {
-            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
-        }
-
-        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
-            @Override
-            public void run() {
-                showHeaders(true);
-            }
-        });
-        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
-            @Override
-            public void run() {
-                showHeaders(false);
-            }
-        });
-        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
-            @Override
-            public void run() {
-                setEntranceTransitionEndState();
-            }
-        });
-
-        return root;
-    }
-
-    void createHeadersTransition() {
-        mHeadersTransition = TransitionHelper.loadTransition(getContext(),
-                mShowingHeaders
-                        ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
-
-        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
-            @Override
-            public void onTransitionStart(Object transition) {
-            }
-            @Override
-            public void onTransitionEnd(Object transition) {
-                mHeadersTransition = null;
-                if (mMainFragmentAdapter != null) {
-                    mMainFragmentAdapter.onTransitionEnd();
-                    if (!mShowingHeaders && mMainFragment != null) {
-                        View mainFragmentView = mMainFragment.getView();
-                        if (mainFragmentView != null && !mainFragmentView.hasFocus()) {
-                            mainFragmentView.requestFocus();
-                        }
-                    }
-                }
-                if (mHeadersSupportFragment != null) {
-                    mHeadersSupportFragment.onTransitionEnd();
-                    if (mShowingHeaders) {
-                        VerticalGridView headerGridView = mHeadersSupportFragment.getVerticalGridView();
-                        if (headerGridView != null && !headerGridView.hasFocus()) {
-                            headerGridView.requestFocus();
-                        }
-                    }
-                }
-
-                // Animate TitleView once header animation is complete.
-                updateTitleViewVisibility();
-
-                if (mBrowseTransitionListener != null) {
-                    mBrowseTransitionListener.onHeadersTransitionStop(mShowingHeaders);
-                }
-            }
-        });
-    }
-
-    void updateTitleViewVisibility() {
-        if (!mShowingHeaders) {
-            boolean showTitleView;
-            if (mIsPageRow && mMainFragmentAdapter != null) {
-                // page fragment case:
-                showTitleView = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
-            } else {
-                // regular row view case:
-                showTitleView = isFirstRowWithContent(mSelectedPosition);
-            }
-            if (showTitleView) {
-                showTitle(TitleViewAdapter.FULL_VIEW_VISIBLE);
-            } else {
-                showTitle(false);
-            }
-        } else {
-            // when HeaderFragment is showing,  showBranding and showSearch are slightly different
-            boolean showBranding;
-            boolean showSearch;
-            if (mIsPageRow && mMainFragmentAdapter != null) {
-                showBranding = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
-            } else {
-                showBranding = isFirstRowWithContent(mSelectedPosition);
-            }
-            showSearch = isFirstRowWithContentOrPageRow(mSelectedPosition);
-            int flags = 0;
-            if (showBranding) flags |= TitleViewAdapter.BRANDING_VIEW_VISIBLE;
-            if (showSearch) flags |= TitleViewAdapter.SEARCH_VIEW_VISIBLE;
-            if (flags != 0) {
-                showTitle(flags);
-            } else {
-                showTitle(false);
-            }
-        }
-    }
-
-    boolean isFirstRowWithContentOrPageRow(int rowPosition) {
-        if (mAdapter == null || mAdapter.size() == 0) {
-            return true;
-        }
-        for (int i = 0; i < mAdapter.size(); i++) {
-            final Row row = (Row) mAdapter.get(i);
-            if (row.isRenderedAsRowView() || row instanceof PageRow) {
-                return rowPosition == i;
-            }
-        }
-        return true;
-    }
-
-    boolean isFirstRowWithContent(int rowPosition) {
-        if (mAdapter == null || mAdapter.size() == 0) {
-            return true;
-        }
-        for (int i = 0; i < mAdapter.size(); i++) {
-            final Row row = (Row) mAdapter.get(i);
-            if (row.isRenderedAsRowView()) {
-                return rowPosition == i;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Sets the {@link PresenterSelector} used to render the row headers.
-     *
-     * @param headerPresenterSelector The PresenterSelector that will determine
-     *        the Presenter for each row header.
-     */
-    public void setHeaderPresenterSelector(PresenterSelector headerPresenterSelector) {
-        mHeaderPresenterSelector = headerPresenterSelector;
-        if (mHeadersSupportFragment != null) {
-            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
-        }
-    }
-
-    private void setHeadersOnScreen(boolean onScreen) {
-        MarginLayoutParams lp;
-        View containerList;
-        containerList = mHeadersSupportFragment.getView();
-        lp = (MarginLayoutParams) containerList.getLayoutParams();
-        lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
-        containerList.setLayoutParams(lp);
-    }
-
-    void showHeaders(boolean show) {
-        if (DEBUG) Log.v(TAG, "showHeaders " + show);
-        mHeadersSupportFragment.setHeadersEnabled(show);
-        setHeadersOnScreen(show);
-        expandMainFragment(!show);
-    }
-
-    private void expandMainFragment(boolean expand) {
-        MarginLayoutParams params = (MarginLayoutParams) mScaleFrameLayout.getLayoutParams();
-        params.setMarginStart(!expand ? mContainerListMarginStart : 0);
-        mScaleFrameLayout.setLayoutParams(params);
-        mMainFragmentAdapter.setExpand(expand);
-
-        setMainFragmentAlignment();
-        final float scaleFactor = !expand
-                && mMainFragmentScaleEnabled
-                && mMainFragmentAdapter.isScalingEnabled() ? mScaleFactor : 1;
-        mScaleFrameLayout.setLayoutScaleY(scaleFactor);
-        mScaleFrameLayout.setChildScale(scaleFactor);
-    }
-
-    private HeadersSupportFragment.OnHeaderClickedListener mHeaderClickedListener =
-        new HeadersSupportFragment.OnHeaderClickedListener() {
-            @Override
-            public void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
-                if (!mCanShowHeaders || !mShowingHeaders || isInHeadersTransition()) {
-                    return;
-                }
-                if (mMainFragment == null || mMainFragment.getView() == null) {
-                    return;
-                }
-                startHeadersTransitionInternal(false);
-                mMainFragment.getView().requestFocus();
-            }
-        };
-
-    class MainFragmentItemViewSelectedListener implements OnItemViewSelectedListener {
-        MainFragmentRowsAdapter mMainFragmentRowsAdapter;
-
-        public MainFragmentItemViewSelectedListener(MainFragmentRowsAdapter fragmentRowsAdapter) {
-            mMainFragmentRowsAdapter = fragmentRowsAdapter;
-        }
-
-        @Override
-        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                RowPresenter.ViewHolder rowViewHolder, Row row) {
-            int position = mMainFragmentRowsAdapter.getSelectedPosition();
-            if (DEBUG) Log.v(TAG, "row selected position " + position);
-            onRowSelected(position);
-            if (mExternalOnItemViewSelectedListener != null) {
-                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
-                        rowViewHolder, row);
-            }
-        }
-    };
-
-    private HeadersSupportFragment.OnHeaderViewSelectedListener mHeaderViewSelectedListener =
-            new HeadersSupportFragment.OnHeaderViewSelectedListener() {
-        @Override
-        public void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
-            int position = mHeadersSupportFragment.getSelectedPosition();
-            if (DEBUG) Log.v(TAG, "header selected position " + position);
-            onRowSelected(position);
-        }
-    };
-
-    void onRowSelected(int position) {
-        // even position is same, it could be data changed, always post selection runnable
-        // to possibly swap main fragment.
-        mSetSelectionRunnable.post(
-                position, SetSelectionRunnable.TYPE_INTERNAL_SYNC, true);
-    }
-
-    void setSelection(int position, boolean smooth) {
-        if (position == NO_POSITION) {
-            return;
-        }
-
-        mSelectedPosition = position;
-        if (mHeadersSupportFragment == null || mMainFragmentAdapter == null) {
-            // onDestroyView() called
-            return;
-        }
-        mHeadersSupportFragment.setSelectedPosition(position, smooth);
-        replaceMainFragment(position);
-
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setSelectedPosition(position, smooth);
-        }
-
-        updateTitleViewVisibility();
-    }
-
-    private void replaceMainFragment(int position) {
-        if (createMainFragment(mAdapter, position)) {
-            swapToMainFragment();
-            expandMainFragment(!(mCanShowHeaders && mShowingHeaders));
-        }
-    }
-
-    private void swapToMainFragment() {
-        final VerticalGridView gridView = mHeadersSupportFragment.getVerticalGridView();
-        if (isShowingHeaders() && gridView != null
-                && gridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
-            // if user is scrolling HeadersSupportFragment,  swap to empty fragment and wait scrolling
-            // finishes.
-            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) {
-                        gridView.removeOnScrollListener(this);
-                        FragmentManager fm = getChildFragmentManager();
-                        Fragment currentFragment = fm.findFragmentById(R.id.scale_frame);
-                        if (currentFragment != mMainFragment) {
-                            fm.beginTransaction().replace(R.id.scale_frame, mMainFragment).commit();
-                        }
-                    }
-                }
-            });
-        } else {
-            // Otherwise swap immediately
-            getChildFragmentManager().beginTransaction()
-                    .replace(R.id.scale_frame, mMainFragment).commit();
-        }
-    }
-
-    /**
-     * Sets the selected row position with smooth animation.
-     */
-    public void setSelectedPosition(int position) {
-        setSelectedPosition(position, true);
-    }
-
-    /**
-     * Gets position of currently selected row.
-     * @return Position of currently selected row.
-     */
-    public int getSelectedPosition() {
-        return mSelectedPosition;
-    }
-
-    /**
-     * @return selected row ViewHolder inside fragment created by {@link MainFragmentRowsAdapter}.
-     */
-    public RowPresenter.ViewHolder getSelectedRowViewHolder() {
-        if (mMainFragmentRowsAdapter != null) {
-            int rowPos = mMainFragmentRowsAdapter.getSelectedPosition();
-            return mMainFragmentRowsAdapter.findRowViewHolderByPosition(rowPos);
-        }
-        return null;
-    }
-
-    /**
-     * Sets the selected row position.
-     */
-    public void setSelectedPosition(int position, boolean smooth) {
-        mSetSelectionRunnable.post(
-                position, SetSelectionRunnable.TYPE_USER_REQUEST, smooth);
-    }
-
-    /**
-     * Selects a Row and perform an optional task on the Row. For example
-     * <code>setSelectedPosition(10, true, new ListRowPresenterSelectItemViewHolderTask(5))</code>
-     * scrolls to 11th row and selects 6th item on that row.  The method will be ignored if
-     * RowsSupportFragment has not been created (i.e. before {@link #onCreateView(LayoutInflater,
-     * ViewGroup, Bundle)}).
-     *
-     * @param rowPosition Which row to select.
-     * @param smooth True to scroll to the row, false for no animation.
-     * @param rowHolderTask Optional task to perform on the Row.  When the task is not null, headers
-     * fragment will be collapsed.
-     */
-    public void setSelectedPosition(int rowPosition, boolean smooth,
-            final Presenter.ViewHolderTask rowHolderTask) {
-        if (mMainFragmentAdapterRegistry == null) {
-            return;
-        }
-        if (rowHolderTask != null) {
-            startHeadersTransition(false);
-        }
-        if (mMainFragmentRowsAdapter != null) {
-            mMainFragmentRowsAdapter.setSelectedPosition(rowPosition, smooth, rowHolderTask);
-        }
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        mHeadersSupportFragment.setAlignment(mContainerListAlignTop);
-        setMainFragmentAlignment();
-
-        if (mCanShowHeaders && mShowingHeaders && mHeadersSupportFragment != null
-                && mHeadersSupportFragment.getView() != null) {
-            mHeadersSupportFragment.getView().requestFocus();
-        } else if ((!mCanShowHeaders || !mShowingHeaders) && mMainFragment != null
-                && mMainFragment.getView() != null) {
-            mMainFragment.getView().requestFocus();
-        }
-
-        if (mCanShowHeaders) {
-            showHeaders(mShowingHeaders);
-        }
-
-        mStateMachine.fireEvent(EVT_HEADER_VIEW_CREATED);
-    }
-
-    private void onExpandTransitionStart(boolean expand, final Runnable callback) {
-        if (expand) {
-            callback.run();
-            return;
-        }
-        // Run a "pre" layout when we go non-expand, in order to get the initial
-        // positions of added rows.
-        new ExpandPreLayout(callback, mMainFragmentAdapter, getView()).execute();
-    }
-
-    private void setMainFragmentAlignment() {
-        int alignOffset = mContainerListAlignTop;
-        if (mMainFragmentScaleEnabled
-                && mMainFragmentAdapter.isScalingEnabled()
-                && mShowingHeaders) {
-            alignOffset = (int) (alignOffset / mScaleFactor + 0.5f);
-        }
-        mMainFragmentAdapter.setAlignment(alignOffset);
-    }
-
-    /**
-     * Enables/disables headers transition on back key support. This is enabled by
-     * default. The BrowseSupportFragment will add a back stack entry when headers are
-     * showing. Running a headers transition when the back key is pressed only
-     * works when the headers state is {@link #HEADERS_ENABLED} or
-     * {@link #HEADERS_HIDDEN}.
-     * <p>
-     * NOTE: If an Activity has its own onBackPressed() handling, you must
-     * disable this feature. You may use {@link #startHeadersTransition(boolean)}
-     * and {@link BrowseTransitionListener} in your own back stack handling.
-     */
-    public final void setHeadersTransitionOnBackEnabled(boolean headersBackStackEnabled) {
-        mHeadersBackStackEnabled = headersBackStackEnabled;
-    }
-
-    /**
-     * Returns true if headers transition on back key support is enabled.
-     */
-    public final boolean isHeadersTransitionOnBackEnabled() {
-        return mHeadersBackStackEnabled;
-    }
-
-    private void readArguments(Bundle args) {
-        if (args == null) {
-            return;
-        }
-        if (args.containsKey(ARG_TITLE)) {
-            setTitle(args.getString(ARG_TITLE));
-        }
-        if (args.containsKey(ARG_HEADERS_STATE)) {
-            setHeadersState(args.getInt(ARG_HEADERS_STATE));
-        }
-    }
-
-    /**
-     * Sets the state for the headers column in the browse fragment. Must be one
-     * of {@link #HEADERS_ENABLED}, {@link #HEADERS_HIDDEN}, or
-     * {@link #HEADERS_DISABLED}.
-     *
-     * @param headersState The state of the headers for the browse fragment.
-     */
-    public void setHeadersState(int headersState) {
-        if (headersState < HEADERS_ENABLED || headersState > HEADERS_DISABLED) {
-            throw new IllegalArgumentException("Invalid headers state: " + headersState);
-        }
-        if (DEBUG) Log.v(TAG, "setHeadersState " + headersState);
-
-        if (headersState != mHeadersState) {
-            mHeadersState = headersState;
-            switch (headersState) {
-                case HEADERS_ENABLED:
-                    mCanShowHeaders = true;
-                    mShowingHeaders = true;
-                    break;
-                case HEADERS_HIDDEN:
-                    mCanShowHeaders = true;
-                    mShowingHeaders = false;
-                    break;
-                case HEADERS_DISABLED:
-                    mCanShowHeaders = false;
-                    mShowingHeaders = false;
-                    break;
-                default:
-                    Log.w(TAG, "Unknown headers state: " + headersState);
-                    break;
-            }
-            if (mHeadersSupportFragment != null) {
-                mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
-            }
-        }
-    }
-
-    /**
-     * Returns the state of the headers column in the browse fragment.
-     */
-    public int getHeadersState() {
-        return mHeadersState;
-    }
-
-    @Override
-    protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getContext(),
-                R.transition.lb_browse_entrance_transition);
-    }
-
-    @Override
-    protected void runEntranceTransition(Object entranceTransition) {
-        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
-    }
-
-    @Override
-    protected void onEntranceTransitionPrepare() {
-        mHeadersSupportFragment.onTransitionPrepare();
-        mMainFragmentAdapter.setEntranceTransitionState(false);
-        mMainFragmentAdapter.onTransitionPrepare();
-    }
-
-    @Override
-    protected void onEntranceTransitionStart() {
-        mHeadersSupportFragment.onTransitionStart();
-        mMainFragmentAdapter.onTransitionStart();
-    }
-
-    @Override
-    protected void onEntranceTransitionEnd() {
-        if (mMainFragmentAdapter != null) {
-            mMainFragmentAdapter.onTransitionEnd();
-        }
-
-        if (mHeadersSupportFragment != null) {
-            mHeadersSupportFragment.onTransitionEnd();
-        }
-    }
-
-    void setSearchOrbViewOnScreen(boolean onScreen) {
-        View searchOrbView = getTitleViewAdapter().getSearchAffordanceView();
-        if (searchOrbView != null) {
-            MarginLayoutParams lp = (MarginLayoutParams) searchOrbView.getLayoutParams();
-            lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
-            searchOrbView.setLayoutParams(lp);
-        }
-    }
-
-    void setEntranceTransitionStartState() {
-        setHeadersOnScreen(false);
-        setSearchOrbViewOnScreen(false);
-        // NOTE that mMainFragmentAdapter.setEntranceTransitionState(false) will be called
-        // in onEntranceTransitionPrepare() because mMainFragmentAdapter is still the dummy
-        // one when setEntranceTransitionStartState() is called.
-    }
-
-    void setEntranceTransitionEndState() {
-        setHeadersOnScreen(mShowingHeaders);
-        setSearchOrbViewOnScreen(true);
-        mMainFragmentAdapter.setEntranceTransitionState(true);
-    }
-
-    private class ExpandPreLayout implements ViewTreeObserver.OnPreDrawListener {
-
-        private final View mView;
-        private final Runnable mCallback;
-        private int mState;
-        private MainFragmentAdapter mainFragmentAdapter;
-
-        final static int STATE_INIT = 0;
-        final static int STATE_FIRST_DRAW = 1;
-        final static int STATE_SECOND_DRAW = 2;
-
-        ExpandPreLayout(Runnable callback, MainFragmentAdapter adapter, View view) {
-            mView = view;
-            mCallback = callback;
-            mainFragmentAdapter = adapter;
-        }
-
-        void execute() {
-            mView.getViewTreeObserver().addOnPreDrawListener(this);
-            mainFragmentAdapter.setExpand(false);
-            // always trigger onPreDraw even adapter setExpand() does nothing.
-            mView.invalidate();
-            mState = STATE_INIT;
-        }
-
-        @Override
-        public boolean onPreDraw() {
-            if (getView() == null || getContext() == null) {
-                mView.getViewTreeObserver().removeOnPreDrawListener(this);
-                return true;
-            }
-            if (mState == STATE_INIT) {
-                mainFragmentAdapter.setExpand(true);
-                // always trigger onPreDraw even adapter setExpand() does nothing.
-                mView.invalidate();
-                mState = STATE_FIRST_DRAW;
-            } else if (mState == STATE_FIRST_DRAW) {
-                mCallback.run();
-                mView.getViewTreeObserver().removeOnPreDrawListener(this);
-                mState = STATE_SECOND_DRAW;
-            }
-            return false;
-        }
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/app/DetailsFragment.java b/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
deleted file mode 100644
index 18934f4..0000000
--- a/leanback/src/android/support/v17/leanback/app/DetailsFragment.java
+++ /dev/null
@@ -1,934 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from DetailsSupportFragment.java.  DO NOT MODIFY. */
-
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from DetailsFragment.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentTransaction;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.annotation.CallSuper;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.transition.TransitionListener;
-import android.support.v17.leanback.util.StateMachine.Event;
-import android.support.v17.leanback.util.StateMachine.State;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
-import android.support.v17.leanback.widget.BrowseFrameLayout;
-import android.support.v17.leanback.widget.DetailsParallax;
-import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
-import android.support.v17.leanback.widget.ItemAlignmentFacet;
-import android.support.v17.leanback.widget.ItemBridgeAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-
-import java.lang.ref.WeakReference;
-
-/**
- * A fragment for creating Leanback details screens.
- *
- * <p>
- * A DetailsFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list.The Adapter's {@link PresenterSelector} must maintain subclasses
- * of {@link RowPresenter}.
- * </p>
- *
- * When {@link FullWidthDetailsOverviewRowPresenter} is found in adapter,  DetailsFragment will
- * setup default behavior of the DetailsOverviewRow:
- * <li>
- * The alignment of FullWidthDetailsOverviewRowPresenter is setup in
- * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}.
- * </li>
- * <li>
- * The view status switching of FullWidthDetailsOverviewRowPresenter is done in
- * {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
- * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)}.
- * </li>
- *
- * <p>
- * The recommended activity themes to use with a DetailsFragment are
- * <li>
- * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details} with activity
- * shared element transition for {@link FullWidthDetailsOverviewRowPresenter}.
- * </li>
- * <li>
- * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details_NoSharedElementTransition}
- * if shared element transition is not needed, for example if first row is not rendered by
- * {@link FullWidthDetailsOverviewRowPresenter}.
- * </li>
- * </p>
- *
- * <p>
- * DetailsFragment can use {@link DetailsFragmentBackgroundController} to add a parallax drawable
- * background and embedded video playing fragment.
- * </p>
- * @deprecated use {@link DetailsSupportFragment}
- */
-@Deprecated
-public class DetailsFragment extends BaseFragment {
-    static final String TAG = "DetailsFragment";
-    static boolean DEBUG = false;
-
-    final State STATE_SET_ENTRANCE_START_STATE = new State("STATE_SET_ENTRANCE_START_STATE") {
-        @Override
-        public void run() {
-            mRowsFragment.setEntranceTransitionState(false);
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_INIT = new State("STATE_ENTER_TRANSIITON_INIT");
-
-    void switchToVideoBeforeVideoFragmentCreated() {
-        // if the video fragment is not ready: immediately fade out covering drawable,
-        // hide title and mark mPendingFocusOnVideo and set focus on it later.
-        mDetailsBackgroundController.switchToVideoBeforeCreate();
-        showTitle(false);
-        mPendingFocusOnVideo = true;
-        slideOutGridView();
-    }
-
-    final State STATE_SWITCH_TO_VIDEO_IN_ON_CREATE = new State("STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
-            false, false) {
-        @Override
-        public void run() {
-            switchToVideoBeforeVideoFragmentCreated();
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_CANCEL = new State("STATE_ENTER_TRANSITION_CANCEL",
-            false, false) {
-        @Override
-        public void run() {
-            if (mWaitEnterTransitionTimeout != null) {
-                mWaitEnterTransitionTimeout.mRef.clear();
-            }
-            // clear the activity enter/sharedElement transition, return transitions are kept.
-            // keep the return transitions and clear enter transition
-            if (getActivity() != null) {
-                Window window = getActivity().getWindow();
-                Object returnTransition = TransitionHelper.getReturnTransition(window);
-                Object sharedReturnTransition = TransitionHelper
-                        .getSharedElementReturnTransition(window);
-                TransitionHelper.setEnterTransition(window, null);
-                TransitionHelper.setSharedElementEnterTransition(window, null);
-                TransitionHelper.setReturnTransition(window, returnTransition);
-                TransitionHelper.setSharedElementReturnTransition(window, sharedReturnTransition);
-            }
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_COMPLETE = new State("STATE_ENTER_TRANSIITON_COMPLETE",
-            true, false);
-
-    final State STATE_ENTER_TRANSITION_ADDLISTENER = new State("STATE_ENTER_TRANSITION_PENDING") {
-        @Override
-        public void run() {
-            Object transition = TransitionHelper.getEnterTransition(getActivity().getWindow());
-            TransitionHelper.addTransitionListener(transition, mEnterTransitionListener);
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_PENDING = new State("STATE_ENTER_TRANSITION_PENDING") {
-        @Override
-        public void run() {
-            if (mWaitEnterTransitionTimeout == null) {
-                new WaitEnterTransitionTimeout(DetailsFragment.this);
-            }
-        }
-    };
-
-    /**
-     * Start this task when first DetailsOverviewRow is created, if there is no entrance transition
-     * started, it will clear PF_ENTRANCE_TRANSITION_PENDING.
-     */
-    static class WaitEnterTransitionTimeout implements Runnable {
-        static final long WAIT_ENTERTRANSITION_START = 200;
-
-        final WeakReference<DetailsFragment> mRef;
-
-        WaitEnterTransitionTimeout(DetailsFragment f) {
-            mRef = new WeakReference<>(f);
-            f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
-        }
-
-        @Override
-        public void run() {
-            DetailsFragment f = mRef.get();
-            if (f != null) {
-                f.mStateMachine.fireEvent(f.EVT_ENTER_TRANSIITON_DONE);
-            }
-        }
-    }
-
-    final State STATE_ON_SAFE_START = new State("STATE_ON_SAFE_START") {
-        @Override
-        public void run() {
-            onSafeStart();
-        }
-    };
-
-    final Event EVT_ONSTART = new Event("onStart");
-
-    final Event EVT_NO_ENTER_TRANSITION = new Event("EVT_NO_ENTER_TRANSITION");
-
-    final Event EVT_DETAILS_ROW_LOADED = new Event("onFirstRowLoaded");
-
-    final Event EVT_ENTER_TRANSIITON_DONE = new Event("onEnterTransitionDone");
-
-    final Event EVT_SWITCH_TO_VIDEO = new Event("switchToVideo");
-
-    @Override
-    void createStateMachineStates() {
-        super.createStateMachineStates();
-        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
-        mStateMachine.addState(STATE_ON_SAFE_START);
-        mStateMachine.addState(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_INIT);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_ADDLISTENER);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_CANCEL);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_PENDING);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_COMPLETE);
-    }
-
-    @Override
-    void createStateMachineTransitions() {
-        super.createStateMachineTransitions();
-        /**
-         * Part 1: Processing enter transitions after fragment.onCreate
-         */
-        mStateMachine.addTransition(STATE_START, STATE_ENTER_TRANSITION_INIT, EVT_ON_CREATE);
-        // if transition is not supported, skip to complete
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
-                COND_TRANSITION_NOT_SUPPORTED);
-        // if transition is not set on Activity, skip to complete
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
-                EVT_NO_ENTER_TRANSITION);
-        // if switchToVideo is called before EVT_ON_CREATEVIEW, clear enter transition and skip to
-        // complete.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_CANCEL,
-                EVT_SWITCH_TO_VIDEO);
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_CANCEL, STATE_ENTER_TRANSITION_COMPLETE);
-        // once after onCreateView, we cannot skip the enter transition, add a listener and wait
-        // it to finish
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_ADDLISTENER,
-                EVT_ON_CREATEVIEW);
-        // when enter transition finishes, go to complete, however this might never happen if
-        // the activity is not giving transition options in startActivity, there is no API to query
-        // if this activity is started in a enter transition mode. So we rely on a timer below:
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
-                STATE_ENTER_TRANSITION_COMPLETE, EVT_ENTER_TRANSIITON_DONE);
-        // we are expecting app to start delayed enter transition shortly after details row is
-        // loaded, so create a timer and wait for enter transition start.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
-                STATE_ENTER_TRANSITION_PENDING, EVT_DETAILS_ROW_LOADED);
-        // if enter transition not started in the timer, skip to DONE, this can be also true when
-        // startActivity is not giving transition option.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_PENDING, STATE_ENTER_TRANSITION_COMPLETE,
-                EVT_ENTER_TRANSIITON_DONE);
-
-        /**
-         * Part 2: modification to the entrance transition defined in BaseFragment
-         */
-        // Must finish enter transition before perform entrance transition.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ENTRANCE_PERFORM);
-        // Calling switch to video would hide immediately and skip entrance transition
-        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
-                EVT_SWITCH_TO_VIDEO);
-        mStateMachine.addTransition(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE, STATE_ENTRANCE_COMPLETE);
-        // if the entrance transition is skipped to complete by COND_TRANSITION_NOT_SUPPORTED, we
-        // still need to do the switchToVideo.
-        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
-                EVT_SWITCH_TO_VIDEO);
-
-        // for once the view is created in onStart and prepareEntranceTransition was called, we
-        // could setEntranceStartState:
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
-                STATE_SET_ENTRANCE_START_STATE, EVT_ONSTART);
-
-        /**
-         * Part 3: onSafeStart()
-         */
-        // for onSafeStart: the condition is onStart called, entrance transition complete
-        mStateMachine.addTransition(STATE_START, STATE_ON_SAFE_START, EVT_ONSTART);
-        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_ON_SAFE_START);
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ON_SAFE_START);
-    }
-
-    private class SetSelectionRunnable implements Runnable {
-        int mPosition;
-        boolean mSmooth = true;
-
-        SetSelectionRunnable() {
-        }
-
-        @Override
-        public void run() {
-            if (mRowsFragment == null) {
-                return;
-            }
-            mRowsFragment.setSelectedPosition(mPosition, mSmooth);
-        }
-    }
-
-    TransitionListener mEnterTransitionListener = new TransitionListener() {
-        @Override
-        public void onTransitionStart(Object transition) {
-            if (mWaitEnterTransitionTimeout != null) {
-                // cancel task of WaitEnterTransitionTimeout, we will clearPendingEnterTransition
-                // when transition finishes.
-                mWaitEnterTransitionTimeout.mRef.clear();
-            }
-        }
-
-        @Override
-        public void onTransitionCancel(Object transition) {
-            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
-        }
-
-        @Override
-        public void onTransitionEnd(Object transition) {
-            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
-        }
-    };
-
-    TransitionListener mReturnTransitionListener = new TransitionListener() {
-        @Override
-        public void onTransitionStart(Object transition) {
-            onReturnTransitionStart();
-        }
-    };
-
-    BrowseFrameLayout mRootView;
-    View mBackgroundView;
-    Drawable mBackgroundDrawable;
-    Fragment mVideoFragment;
-    DetailsParallax mDetailsParallax;
-    RowsFragment mRowsFragment;
-    ObjectAdapter mAdapter;
-    int mContainerListAlignTop;
-    BaseOnItemViewSelectedListener mExternalOnItemViewSelectedListener;
-    BaseOnItemViewClickedListener mOnItemViewClickedListener;
-    DetailsFragmentBackgroundController mDetailsBackgroundController;
-
-    // A temporarily flag when switchToVideo() is called in onCreate(), if mPendingFocusOnVideo is
-    // true, we will focus to VideoFragment immediately after video fragment's view is created.
-    boolean mPendingFocusOnVideo = false;
-
-    WaitEnterTransitionTimeout mWaitEnterTransitionTimeout;
-
-    Object mSceneAfterEntranceTransition;
-
-    final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
-
-    final BaseOnItemViewSelectedListener<Object> mOnItemViewSelectedListener =
-            new BaseOnItemViewSelectedListener<Object>() {
-        @Override
-        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                                   RowPresenter.ViewHolder rowViewHolder, Object row) {
-            int position = mRowsFragment.getVerticalGridView().getSelectedPosition();
-            int subposition = mRowsFragment.getVerticalGridView().getSelectedSubPosition();
-            if (DEBUG) Log.v(TAG, "row selected position " + position
-                    + " subposition " + subposition);
-            onRowSelected(position, subposition);
-            if (mExternalOnItemViewSelectedListener != null) {
-                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
-                        rowViewHolder, row);
-            }
-        }
-    };
-
-    /**
-     * Sets the list of rows for the fragment.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        Presenter[] presenters = adapter.getPresenterSelector().getPresenters();
-        if (presenters != null) {
-            for (int i = 0; i < presenters.length; i++) {
-                setupPresenter(presenters[i]);
-            }
-        } else {
-            Log.e(TAG, "PresenterSelector.getPresenters() not implemented");
-        }
-        if (mRowsFragment != null) {
-            mRowsFragment.setAdapter(adapter);
-        }
-    }
-
-    /**
-     * Returns the list of rows.
-     */
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    /**
-     * Sets an item selection listener.
-     */
-    public void setOnItemViewSelectedListener(BaseOnItemViewSelectedListener listener) {
-        mExternalOnItemViewSelectedListener = listener;
-    }
-
-    /**
-     * Sets an item clicked listener.
-     */
-    public void setOnItemViewClickedListener(BaseOnItemViewClickedListener listener) {
-        if (mOnItemViewClickedListener != listener) {
-            mOnItemViewClickedListener = listener;
-            if (mRowsFragment != null) {
-                mRowsFragment.setOnItemViewClickedListener(listener);
-            }
-        }
-    }
-
-    /**
-     * Returns the item clicked listener.
-     */
-    public BaseOnItemViewClickedListener getOnItemViewClickedListener() {
-        return mOnItemViewClickedListener;
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mContainerListAlignTop =
-            getResources().getDimensionPixelSize(R.dimen.lb_details_rows_align_top);
-
-        Activity activity = getActivity();
-        if (activity != null) {
-            Object transition = TransitionHelper.getEnterTransition(activity.getWindow());
-            if (transition == null) {
-                mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
-            }
-            transition = TransitionHelper.getReturnTransition(activity.getWindow());
-            if (transition != null) {
-                TransitionHelper.addTransitionListener(transition, mReturnTransitionListener);
-            }
-        } else {
-            mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
-        }
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        mRootView = (BrowseFrameLayout) inflater.inflate(
-                R.layout.lb_details_fragment, container, false);
-        mBackgroundView = mRootView.findViewById(R.id.details_background_view);
-        if (mBackgroundView != null) {
-            mBackgroundView.setBackground(mBackgroundDrawable);
-        }
-        mRowsFragment = (RowsFragment) getChildFragmentManager().findFragmentById(
-                R.id.details_rows_dock);
-        if (mRowsFragment == null) {
-            mRowsFragment = new RowsFragment();
-            getChildFragmentManager().beginTransaction()
-                    .replace(R.id.details_rows_dock, mRowsFragment).commit();
-        }
-        installTitleView(inflater, mRootView, savedInstanceState);
-        mRowsFragment.setAdapter(mAdapter);
-        mRowsFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
-        mRowsFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
-
-        mSceneAfterEntranceTransition = TransitionHelper.createScene(mRootView, new Runnable() {
-            @Override
-            public void run() {
-                mRowsFragment.setEntranceTransitionState(true);
-            }
-        });
-
-        setupDpadNavigation();
-
-        if (Build.VERSION.SDK_INT >= 21) {
-            // Setup adapter listener to work with ParallaxTransition (>= API 21).
-            mRowsFragment.setExternalAdapterListener(new ItemBridgeAdapter.AdapterListener() {
-                @Override
-                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
-                    if (mDetailsParallax != null && vh.getViewHolder()
-                            instanceof FullWidthDetailsOverviewRowPresenter.ViewHolder) {
-                        FullWidthDetailsOverviewRowPresenter.ViewHolder rowVh =
-                                (FullWidthDetailsOverviewRowPresenter.ViewHolder)
-                                        vh.getViewHolder();
-                        rowVh.getOverviewView().setTag(R.id.lb_parallax_source,
-                                mDetailsParallax);
-                    }
-                }
-            });
-        }
-        return mRootView;
-    }
-
-    /**
-     * @deprecated override {@link #onInflateTitleView(LayoutInflater,ViewGroup,Bundle)} instead.
-     */
-    @Deprecated
-    protected View inflateTitle(LayoutInflater inflater, ViewGroup parent,
-            Bundle savedInstanceState) {
-        return super.onInflateTitleView(inflater, parent, savedInstanceState);
-    }
-
-    @Override
-    public View onInflateTitleView(LayoutInflater inflater, ViewGroup parent,
-                                   Bundle savedInstanceState) {
-        return inflateTitle(inflater, parent, savedInstanceState);
-    }
-
-    void setVerticalGridViewLayout(VerticalGridView listview) {
-        // align the top edge of item to a fixed position
-        listview.setItemAlignmentOffset(-mContainerListAlignTop);
-        listview.setItemAlignmentOffsetPercent(VerticalGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
-        listview.setWindowAlignmentOffset(0);
-        listview.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
-    }
-
-    /**
-     * Called to setup each Presenter of Adapter passed in {@link #setAdapter(ObjectAdapter)}.Note
-     * that setup should only change the Presenter behavior that is meaningful in DetailsFragment.
-     * For example how a row is aligned in details Fragment.   The default implementation invokes
-     * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}
-     *
-     */
-    protected void setupPresenter(Presenter rowPresenter) {
-        if (rowPresenter instanceof FullWidthDetailsOverviewRowPresenter) {
-            setupDetailsOverviewRowPresenter((FullWidthDetailsOverviewRowPresenter) rowPresenter);
-        }
-    }
-
-    /**
-     * Called to setup {@link FullWidthDetailsOverviewRowPresenter}.  The default implementation
-     * adds two alignment positions({@link ItemAlignmentFacet}) for ViewHolder of
-     * FullWidthDetailsOverviewRowPresenter to align in fragment.
-     */
-    protected void setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter presenter) {
-        ItemAlignmentFacet facet = new ItemAlignmentFacet();
-        // by default align details_frame to half window height
-        ItemAlignmentFacet.ItemAlignmentDef alignDef1 = new ItemAlignmentFacet.ItemAlignmentDef();
-        alignDef1.setItemAlignmentViewId(R.id.details_frame);
-        alignDef1.setItemAlignmentOffset(- getResources()
-                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions));
-        alignDef1.setItemAlignmentOffsetPercent(0);
-        // when description is selected, align details_frame to top edge
-        ItemAlignmentFacet.ItemAlignmentDef alignDef2 = new ItemAlignmentFacet.ItemAlignmentDef();
-        alignDef2.setItemAlignmentViewId(R.id.details_frame);
-        alignDef2.setItemAlignmentFocusViewId(R.id.details_overview_description);
-        alignDef2.setItemAlignmentOffset(- getResources()
-                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description));
-        alignDef2.setItemAlignmentOffsetPercent(0);
-        ItemAlignmentFacet.ItemAlignmentDef[] defs =
-                new ItemAlignmentFacet.ItemAlignmentDef[] {alignDef1, alignDef2};
-        facet.setAlignmentDefs(defs);
-        presenter.setFacet(ItemAlignmentFacet.class, facet);
-    }
-
-    VerticalGridView getVerticalGridView() {
-        return mRowsFragment == null ? null : mRowsFragment.getVerticalGridView();
-    }
-
-    /**
-     * Gets embedded RowsFragment showing multiple rows for DetailsFragment.  If view of
-     * DetailsFragment is not created, the method returns null.
-     * @return Embedded RowsFragment showing multiple rows for DetailsFragment.
-     */
-    public RowsFragment getRowsFragment() {
-        return mRowsFragment;
-    }
-
-    /**
-     * Setup dimensions that are only meaningful when the child Fragments are inside
-     * DetailsFragment.
-     */
-    private void setupChildFragmentLayout() {
-        setVerticalGridViewLayout(mRowsFragment.getVerticalGridView());
-    }
-
-    /**
-     * Sets the selected row position with smooth animation.
-     */
-    public void setSelectedPosition(int position) {
-        setSelectedPosition(position, true);
-    }
-
-    /**
-     * Sets the selected row position.
-     */
-    public void setSelectedPosition(int position, boolean smooth) {
-        mSetSelectionRunnable.mPosition = position;
-        mSetSelectionRunnable.mSmooth = smooth;
-        if (getView() != null && getView().getHandler() != null) {
-            getView().getHandler().post(mSetSelectionRunnable);
-        }
-    }
-
-    void switchToVideo() {
-        if (mVideoFragment != null && mVideoFragment.getView() != null) {
-            mVideoFragment.getView().requestFocus();
-        } else {
-            mStateMachine.fireEvent(EVT_SWITCH_TO_VIDEO);
-        }
-    }
-
-    void switchToRows() {
-        mPendingFocusOnVideo = false;
-        VerticalGridView verticalGridView = getVerticalGridView();
-        if (verticalGridView != null && verticalGridView.getChildCount() > 0) {
-            verticalGridView.requestFocus();
-        }
-    }
-
-    /**
-     * This method asks DetailsFragmentBackgroundController to add a fragment for rendering video.
-     * In case the fragment is already there, it will return the existing one. The method must be
-     * called after calling super.onCreate(). App usually does not call this method directly.
-     *
-     * @return Fragment the added or restored fragment responsible for rendering video.
-     * @see DetailsFragmentBackgroundController#onCreateVideoFragment()
-     */
-    final Fragment findOrCreateVideoFragment() {
-        if (mVideoFragment != null) {
-            return mVideoFragment;
-        }
-        Fragment fragment = getChildFragmentManager()
-                .findFragmentById(R.id.video_surface_container);
-        if (fragment == null && mDetailsBackgroundController != null) {
-            FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
-            ft2.add(android.support.v17.leanback.R.id.video_surface_container,
-                    fragment = mDetailsBackgroundController.onCreateVideoFragment());
-            ft2.commit();
-            if (mPendingFocusOnVideo) {
-                // wait next cycle for Fragment view created so we can focus on it.
-                // This is a bit hack eventually we will do commitNow() which get view immediately.
-                getView().post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (getView() != null) {
-                            switchToVideo();
-                        }
-                        mPendingFocusOnVideo = false;
-                    }
-                });
-            }
-        }
-        mVideoFragment = fragment;
-        return mVideoFragment;
-    }
-
-    void onRowSelected(int selectedPosition, int selectedSubPosition) {
-        ObjectAdapter adapter = getAdapter();
-        if (( mRowsFragment != null && mRowsFragment.getView() != null
-                && mRowsFragment.getView().hasFocus() && !mPendingFocusOnVideo)
-                && (adapter == null || adapter.size() == 0
-                || (getVerticalGridView().getSelectedPosition() == 0
-                && getVerticalGridView().getSelectedSubPosition() == 0))) {
-            showTitle(true);
-        } else {
-            showTitle(false);
-        }
-        if (adapter != null && adapter.size() > selectedPosition) {
-            final VerticalGridView gridView = getVerticalGridView();
-            final int count = gridView.getChildCount();
-            if (count > 0) {
-                mStateMachine.fireEvent(EVT_DETAILS_ROW_LOADED);
-            }
-            for (int i = 0; i < count; i++) {
-                ItemBridgeAdapter.ViewHolder bridgeViewHolder = (ItemBridgeAdapter.ViewHolder)
-                        gridView.getChildViewHolder(gridView.getChildAt(i));
-                RowPresenter rowPresenter = (RowPresenter) bridgeViewHolder.getPresenter();
-                onSetRowStatus(rowPresenter,
-                        rowPresenter.getRowViewHolder(bridgeViewHolder.getViewHolder()),
-                        bridgeViewHolder.getAdapterPosition(),
-                        selectedPosition, selectedSubPosition);
-            }
-        }
-    }
-
-    /**
-     * Called when onStart and enter transition (postponed/none postponed) and entrance transition
-     * are all finished.
-     */
-    @CallSuper
-    void onSafeStart() {
-        if (mDetailsBackgroundController != null) {
-            mDetailsBackgroundController.onStart();
-        }
-    }
-
-    @CallSuper
-    void onReturnTransitionStart() {
-        if (mDetailsBackgroundController != null) {
-            // first disable parallax effect that auto-start PlaybackGlue.
-            boolean isVideoVisible = mDetailsBackgroundController.disableVideoParallax();
-            // if video is not visible we can safely remove VideoFragment,
-            // otherwise let video playing during return transition.
-            if (!isVideoVisible && mVideoFragment != null) {
-                FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
-                ft2.remove(mVideoFragment);
-                ft2.commit();
-                mVideoFragment = null;
-            }
-        }
-    }
-
-    @Override
-    public void onStop() {
-        if (mDetailsBackgroundController != null) {
-            mDetailsBackgroundController.onStop();
-        }
-        super.onStop();
-    }
-
-    /**
-     * Called on every visible row to change view status when current selected row position
-     * or selected sub position changed.  Subclass may override.   The default
-     * implementation calls {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
-     * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)} if presenter is
-     * instance of {@link FullWidthDetailsOverviewRowPresenter}.
-     *
-     * @param presenter   The presenter used to create row ViewHolder.
-     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
-     *                    be selected.
-     * @param adapterPosition  The adapter position of viewHolder inside adapter.
-     * @param selectedPosition The adapter position of currently selected row.
-     * @param selectedSubPosition The sub position within currently selected row.  This is used
-     *                            When a row has multiple alignment positions.
-     */
-    protected void onSetRowStatus(RowPresenter presenter, RowPresenter.ViewHolder viewHolder, int
-            adapterPosition, int selectedPosition, int selectedSubPosition) {
-        if (presenter instanceof FullWidthDetailsOverviewRowPresenter) {
-            onSetDetailsOverviewRowStatus((FullWidthDetailsOverviewRowPresenter) presenter,
-                    (FullWidthDetailsOverviewRowPresenter.ViewHolder) viewHolder,
-                    adapterPosition, selectedPosition, selectedSubPosition);
-        }
-    }
-
-    /**
-     * Called to change DetailsOverviewRow view status when current selected row position
-     * or selected sub position changed.  Subclass may override.   The default
-     * implementation switches between three states based on the positions:
-     * {@link FullWidthDetailsOverviewRowPresenter#STATE_HALF},
-     * {@link FullWidthDetailsOverviewRowPresenter#STATE_FULL} and
-     * {@link FullWidthDetailsOverviewRowPresenter#STATE_SMALL}.
-     *
-     * @param presenter   The presenter used to create row ViewHolder.
-     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
-     *                    be selected.
-     * @param adapterPosition  The adapter position of viewHolder inside adapter.
-     * @param selectedPosition The adapter position of currently selected row.
-     * @param selectedSubPosition The sub position within currently selected row.  This is used
-     *                            When a row has multiple alignment positions.
-     */
-    protected void onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter presenter,
-            FullWidthDetailsOverviewRowPresenter.ViewHolder viewHolder, int adapterPosition,
-            int selectedPosition, int selectedSubPosition) {
-        if (selectedPosition > adapterPosition) {
-            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
-        } else if (selectedPosition == adapterPosition && selectedSubPosition == 1) {
-            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
-        } else if (selectedPosition == adapterPosition && selectedSubPosition == 0){
-            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_FULL);
-        } else {
-            presenter.setState(viewHolder,
-                    FullWidthDetailsOverviewRowPresenter.STATE_SMALL);
-        }
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        setupChildFragmentLayout();
-        mStateMachine.fireEvent(EVT_ONSTART);
-        if (mDetailsParallax != null) {
-            mDetailsParallax.setRecyclerView(mRowsFragment.getVerticalGridView());
-        }
-        if (mPendingFocusOnVideo) {
-            slideOutGridView();
-        } else if (!getView().hasFocus()) {
-            mRowsFragment.getVerticalGridView().requestFocus();
-        }
-    }
-
-    @Override
-    protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(FragmentUtil.getContext(DetailsFragment.this),
-                R.transition.lb_details_enter_transition);
-    }
-
-    @Override
-    protected void runEntranceTransition(Object entranceTransition) {
-        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
-    }
-
-    @Override
-    protected void onEntranceTransitionEnd() {
-        mRowsFragment.onTransitionEnd();
-    }
-
-    @Override
-    protected void onEntranceTransitionPrepare() {
-        mRowsFragment.onTransitionPrepare();
-    }
-
-    @Override
-    protected void onEntranceTransitionStart() {
-        mRowsFragment.onTransitionStart();
-    }
-
-    /**
-     * Returns the {@link DetailsParallax} instance used by
-     * {@link DetailsFragmentBackgroundController} to configure parallax effect of background and
-     * control embedded video playback. App usually does not use this method directly.
-     * App may use this method for other custom parallax tasks.
-     *
-     * @return The DetailsParallax instance attached to the DetailsFragment.
-     */
-    public DetailsParallax getParallax() {
-        if (mDetailsParallax == null) {
-            mDetailsParallax = new DetailsParallax();
-            if (mRowsFragment != null && mRowsFragment.getView() != null) {
-                mDetailsParallax.setRecyclerView(mRowsFragment.getVerticalGridView());
-            }
-        }
-        return mDetailsParallax;
-    }
-
-    /**
-     * Set background drawable shown below foreground rows UI and above
-     * {@link #findOrCreateVideoFragment()}.
-     *
-     * @see DetailsFragmentBackgroundController
-     */
-    void setBackgroundDrawable(Drawable drawable) {
-        if (mBackgroundView != null) {
-            mBackgroundView.setBackground(drawable);
-        }
-        mBackgroundDrawable = drawable;
-    }
-
-    /**
-     * This method does the following
-     * <ul>
-     * <li>sets up focus search handling logic in the root view to enable transitioning between
-     * half screen/full screen/no video mode.</li>
-     *
-     * <li>Sets up the key listener in the root view to intercept events like UP/DOWN and
-     * transition to appropriate mode like half/full screen video.</li>
-     * </ul>
-     */
-    void setupDpadNavigation() {
-        mRootView.setOnChildFocusListener(new BrowseFrameLayout.OnChildFocusListener() {
-
-            @Override
-            public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-                return false;
-            }
-
-            @Override
-            public void onRequestChildFocus(View child, View focused) {
-                if (child != mRootView.getFocusedChild()) {
-                    if (child.getId() == R.id.details_fragment_root) {
-                        if (!mPendingFocusOnVideo) {
-                            slideInGridView();
-                            showTitle(true);
-                        }
-                    } else if (child.getId() == R.id.video_surface_container) {
-                        slideOutGridView();
-                        showTitle(false);
-                    } else {
-                        showTitle(true);
-                    }
-                }
-            }
-        });
-        mRootView.setOnFocusSearchListener(new BrowseFrameLayout.OnFocusSearchListener() {
-            @Override
-            public View onFocusSearch(View focused, int direction) {
-                if (mRowsFragment.getVerticalGridView() != null
-                        && mRowsFragment.getVerticalGridView().hasFocus()) {
-                    if (direction == View.FOCUS_UP) {
-                        if (mDetailsBackgroundController != null
-                                && mDetailsBackgroundController.canNavigateToVideoFragment()
-                                && mVideoFragment != null && mVideoFragment.getView() != null) {
-                            return mVideoFragment.getView();
-                        } else if (getTitleView() != null && getTitleView().hasFocusable()) {
-                            return getTitleView();
-                        }
-                    }
-                } else if (getTitleView() != null && getTitleView().hasFocus()) {
-                    if (direction == View.FOCUS_DOWN) {
-                        if (mRowsFragment.getVerticalGridView() != null) {
-                            return mRowsFragment.getVerticalGridView();
-                        }
-                    }
-                }
-                return focused;
-            }
-        });
-
-        // If we press BACK on remote while in full screen video mode, we should
-        // transition back to half screen video playback mode.
-        mRootView.setOnDispatchKeyListener(new View.OnKeyListener() {
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                // This is used to check if we are in full screen video mode. This is somewhat
-                // hacky and relies on the behavior of the video helper class to update the
-                // focusability of the video surface view.
-                if (mVideoFragment != null && mVideoFragment.getView() != null
-                        && mVideoFragment.getView().hasFocus()) {
-                    if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
-                        if (getVerticalGridView().getChildCount() > 0) {
-                            getVerticalGridView().requestFocus();
-                            return true;
-                        }
-                    }
-                }
-
-                return false;
-            }
-        });
-    }
-
-    /**
-     * Slides vertical grid view (displaying media item details) out of the screen from below.
-     */
-    void slideOutGridView() {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().animateOut();
-        }
-    }
-
-    void slideInGridView() {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().animateIn();
-        }
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java b/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
deleted file mode 100644
index 1f0c259..0000000
--- a/leanback/src/android/support/v17/leanback/app/DetailsSupportFragment.java
+++ /dev/null
@@ -1,929 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from DetailsFragment.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.support.v4.app.FragmentActivity;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.annotation.CallSuper;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.transition.TransitionListener;
-import android.support.v17.leanback.util.StateMachine.Event;
-import android.support.v17.leanback.util.StateMachine.State;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
-import android.support.v17.leanback.widget.BrowseFrameLayout;
-import android.support.v17.leanback.widget.DetailsParallax;
-import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
-import android.support.v17.leanback.widget.ItemAlignmentFacet;
-import android.support.v17.leanback.widget.ItemBridgeAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-
-import java.lang.ref.WeakReference;
-
-/**
- * A fragment for creating Leanback details screens.
- *
- * <p>
- * A DetailsSupportFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list.The Adapter's {@link PresenterSelector} must maintain subclasses
- * of {@link RowPresenter}.
- * </p>
- *
- * When {@link FullWidthDetailsOverviewRowPresenter} is found in adapter,  DetailsSupportFragment will
- * setup default behavior of the DetailsOverviewRow:
- * <li>
- * The alignment of FullWidthDetailsOverviewRowPresenter is setup in
- * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}.
- * </li>
- * <li>
- * The view status switching of FullWidthDetailsOverviewRowPresenter is done in
- * {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
- * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)}.
- * </li>
- *
- * <p>
- * The recommended activity themes to use with a DetailsSupportFragment are
- * <li>
- * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details} with activity
- * shared element transition for {@link FullWidthDetailsOverviewRowPresenter}.
- * </li>
- * <li>
- * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details_NoSharedElementTransition}
- * if shared element transition is not needed, for example if first row is not rendered by
- * {@link FullWidthDetailsOverviewRowPresenter}.
- * </li>
- * </p>
- *
- * <p>
- * DetailsSupportFragment can use {@link DetailsSupportFragmentBackgroundController} to add a parallax drawable
- * background and embedded video playing fragment.
- * </p>
- */
-public class DetailsSupportFragment extends BaseSupportFragment {
-    static final String TAG = "DetailsSupportFragment";
-    static boolean DEBUG = false;
-
-    final State STATE_SET_ENTRANCE_START_STATE = new State("STATE_SET_ENTRANCE_START_STATE") {
-        @Override
-        public void run() {
-            mRowsSupportFragment.setEntranceTransitionState(false);
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_INIT = new State("STATE_ENTER_TRANSIITON_INIT");
-
-    void switchToVideoBeforeVideoSupportFragmentCreated() {
-        // if the video fragment is not ready: immediately fade out covering drawable,
-        // hide title and mark mPendingFocusOnVideo and set focus on it later.
-        mDetailsBackgroundController.switchToVideoBeforeCreate();
-        showTitle(false);
-        mPendingFocusOnVideo = true;
-        slideOutGridView();
-    }
-
-    final State STATE_SWITCH_TO_VIDEO_IN_ON_CREATE = new State("STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
-            false, false) {
-        @Override
-        public void run() {
-            switchToVideoBeforeVideoSupportFragmentCreated();
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_CANCEL = new State("STATE_ENTER_TRANSITION_CANCEL",
-            false, false) {
-        @Override
-        public void run() {
-            if (mWaitEnterTransitionTimeout != null) {
-                mWaitEnterTransitionTimeout.mRef.clear();
-            }
-            // clear the activity enter/sharedElement transition, return transitions are kept.
-            // keep the return transitions and clear enter transition
-            if (getActivity() != null) {
-                Window window = getActivity().getWindow();
-                Object returnTransition = TransitionHelper.getReturnTransition(window);
-                Object sharedReturnTransition = TransitionHelper
-                        .getSharedElementReturnTransition(window);
-                TransitionHelper.setEnterTransition(window, null);
-                TransitionHelper.setSharedElementEnterTransition(window, null);
-                TransitionHelper.setReturnTransition(window, returnTransition);
-                TransitionHelper.setSharedElementReturnTransition(window, sharedReturnTransition);
-            }
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_COMPLETE = new State("STATE_ENTER_TRANSIITON_COMPLETE",
-            true, false);
-
-    final State STATE_ENTER_TRANSITION_ADDLISTENER = new State("STATE_ENTER_TRANSITION_PENDING") {
-        @Override
-        public void run() {
-            Object transition = TransitionHelper.getEnterTransition(getActivity().getWindow());
-            TransitionHelper.addTransitionListener(transition, mEnterTransitionListener);
-        }
-    };
-
-    final State STATE_ENTER_TRANSITION_PENDING = new State("STATE_ENTER_TRANSITION_PENDING") {
-        @Override
-        public void run() {
-            if (mWaitEnterTransitionTimeout == null) {
-                new WaitEnterTransitionTimeout(DetailsSupportFragment.this);
-            }
-        }
-    };
-
-    /**
-     * Start this task when first DetailsOverviewRow is created, if there is no entrance transition
-     * started, it will clear PF_ENTRANCE_TRANSITION_PENDING.
-     */
-    static class WaitEnterTransitionTimeout implements Runnable {
-        static final long WAIT_ENTERTRANSITION_START = 200;
-
-        final WeakReference<DetailsSupportFragment> mRef;
-
-        WaitEnterTransitionTimeout(DetailsSupportFragment f) {
-            mRef = new WeakReference<>(f);
-            f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
-        }
-
-        @Override
-        public void run() {
-            DetailsSupportFragment f = mRef.get();
-            if (f != null) {
-                f.mStateMachine.fireEvent(f.EVT_ENTER_TRANSIITON_DONE);
-            }
-        }
-    }
-
-    final State STATE_ON_SAFE_START = new State("STATE_ON_SAFE_START") {
-        @Override
-        public void run() {
-            onSafeStart();
-        }
-    };
-
-    final Event EVT_ONSTART = new Event("onStart");
-
-    final Event EVT_NO_ENTER_TRANSITION = new Event("EVT_NO_ENTER_TRANSITION");
-
-    final Event EVT_DETAILS_ROW_LOADED = new Event("onFirstRowLoaded");
-
-    final Event EVT_ENTER_TRANSIITON_DONE = new Event("onEnterTransitionDone");
-
-    final Event EVT_SWITCH_TO_VIDEO = new Event("switchToVideo");
-
-    @Override
-    void createStateMachineStates() {
-        super.createStateMachineStates();
-        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
-        mStateMachine.addState(STATE_ON_SAFE_START);
-        mStateMachine.addState(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_INIT);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_ADDLISTENER);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_CANCEL);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_PENDING);
-        mStateMachine.addState(STATE_ENTER_TRANSITION_COMPLETE);
-    }
-
-    @Override
-    void createStateMachineTransitions() {
-        super.createStateMachineTransitions();
-        /**
-         * Part 1: Processing enter transitions after fragment.onCreate
-         */
-        mStateMachine.addTransition(STATE_START, STATE_ENTER_TRANSITION_INIT, EVT_ON_CREATE);
-        // if transition is not supported, skip to complete
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
-                COND_TRANSITION_NOT_SUPPORTED);
-        // if transition is not set on Activity, skip to complete
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
-                EVT_NO_ENTER_TRANSITION);
-        // if switchToVideo is called before EVT_ON_CREATEVIEW, clear enter transition and skip to
-        // complete.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_CANCEL,
-                EVT_SWITCH_TO_VIDEO);
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_CANCEL, STATE_ENTER_TRANSITION_COMPLETE);
-        // once after onCreateView, we cannot skip the enter transition, add a listener and wait
-        // it to finish
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_ADDLISTENER,
-                EVT_ON_CREATEVIEW);
-        // when enter transition finishes, go to complete, however this might never happen if
-        // the activity is not giving transition options in startActivity, there is no API to query
-        // if this activity is started in a enter transition mode. So we rely on a timer below:
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
-                STATE_ENTER_TRANSITION_COMPLETE, EVT_ENTER_TRANSIITON_DONE);
-        // we are expecting app to start delayed enter transition shortly after details row is
-        // loaded, so create a timer and wait for enter transition start.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
-                STATE_ENTER_TRANSITION_PENDING, EVT_DETAILS_ROW_LOADED);
-        // if enter transition not started in the timer, skip to DONE, this can be also true when
-        // startActivity is not giving transition option.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_PENDING, STATE_ENTER_TRANSITION_COMPLETE,
-                EVT_ENTER_TRANSIITON_DONE);
-
-        /**
-         * Part 2: modification to the entrance transition defined in BaseSupportFragment
-         */
-        // Must finish enter transition before perform entrance transition.
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ENTRANCE_PERFORM);
-        // Calling switch to video would hide immediately and skip entrance transition
-        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
-                EVT_SWITCH_TO_VIDEO);
-        mStateMachine.addTransition(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE, STATE_ENTRANCE_COMPLETE);
-        // if the entrance transition is skipped to complete by COND_TRANSITION_NOT_SUPPORTED, we
-        // still need to do the switchToVideo.
-        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
-                EVT_SWITCH_TO_VIDEO);
-
-        // for once the view is created in onStart and prepareEntranceTransition was called, we
-        // could setEntranceStartState:
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
-                STATE_SET_ENTRANCE_START_STATE, EVT_ONSTART);
-
-        /**
-         * Part 3: onSafeStart()
-         */
-        // for onSafeStart: the condition is onStart called, entrance transition complete
-        mStateMachine.addTransition(STATE_START, STATE_ON_SAFE_START, EVT_ONSTART);
-        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_ON_SAFE_START);
-        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ON_SAFE_START);
-    }
-
-    private class SetSelectionRunnable implements Runnable {
-        int mPosition;
-        boolean mSmooth = true;
-
-        SetSelectionRunnable() {
-        }
-
-        @Override
-        public void run() {
-            if (mRowsSupportFragment == null) {
-                return;
-            }
-            mRowsSupportFragment.setSelectedPosition(mPosition, mSmooth);
-        }
-    }
-
-    TransitionListener mEnterTransitionListener = new TransitionListener() {
-        @Override
-        public void onTransitionStart(Object transition) {
-            if (mWaitEnterTransitionTimeout != null) {
-                // cancel task of WaitEnterTransitionTimeout, we will clearPendingEnterTransition
-                // when transition finishes.
-                mWaitEnterTransitionTimeout.mRef.clear();
-            }
-        }
-
-        @Override
-        public void onTransitionCancel(Object transition) {
-            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
-        }
-
-        @Override
-        public void onTransitionEnd(Object transition) {
-            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
-        }
-    };
-
-    TransitionListener mReturnTransitionListener = new TransitionListener() {
-        @Override
-        public void onTransitionStart(Object transition) {
-            onReturnTransitionStart();
-        }
-    };
-
-    BrowseFrameLayout mRootView;
-    View mBackgroundView;
-    Drawable mBackgroundDrawable;
-    Fragment mVideoSupportFragment;
-    DetailsParallax mDetailsParallax;
-    RowsSupportFragment mRowsSupportFragment;
-    ObjectAdapter mAdapter;
-    int mContainerListAlignTop;
-    BaseOnItemViewSelectedListener mExternalOnItemViewSelectedListener;
-    BaseOnItemViewClickedListener mOnItemViewClickedListener;
-    DetailsSupportFragmentBackgroundController mDetailsBackgroundController;
-
-    // A temporarily flag when switchToVideo() is called in onCreate(), if mPendingFocusOnVideo is
-    // true, we will focus to VideoSupportFragment immediately after video fragment's view is created.
-    boolean mPendingFocusOnVideo = false;
-
-    WaitEnterTransitionTimeout mWaitEnterTransitionTimeout;
-
-    Object mSceneAfterEntranceTransition;
-
-    final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
-
-    final BaseOnItemViewSelectedListener<Object> mOnItemViewSelectedListener =
-            new BaseOnItemViewSelectedListener<Object>() {
-        @Override
-        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                                   RowPresenter.ViewHolder rowViewHolder, Object row) {
-            int position = mRowsSupportFragment.getVerticalGridView().getSelectedPosition();
-            int subposition = mRowsSupportFragment.getVerticalGridView().getSelectedSubPosition();
-            if (DEBUG) Log.v(TAG, "row selected position " + position
-                    + " subposition " + subposition);
-            onRowSelected(position, subposition);
-            if (mExternalOnItemViewSelectedListener != null) {
-                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
-                        rowViewHolder, row);
-            }
-        }
-    };
-
-    /**
-     * Sets the list of rows for the fragment.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        Presenter[] presenters = adapter.getPresenterSelector().getPresenters();
-        if (presenters != null) {
-            for (int i = 0; i < presenters.length; i++) {
-                setupPresenter(presenters[i]);
-            }
-        } else {
-            Log.e(TAG, "PresenterSelector.getPresenters() not implemented");
-        }
-        if (mRowsSupportFragment != null) {
-            mRowsSupportFragment.setAdapter(adapter);
-        }
-    }
-
-    /**
-     * Returns the list of rows.
-     */
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    /**
-     * Sets an item selection listener.
-     */
-    public void setOnItemViewSelectedListener(BaseOnItemViewSelectedListener listener) {
-        mExternalOnItemViewSelectedListener = listener;
-    }
-
-    /**
-     * Sets an item clicked listener.
-     */
-    public void setOnItemViewClickedListener(BaseOnItemViewClickedListener listener) {
-        if (mOnItemViewClickedListener != listener) {
-            mOnItemViewClickedListener = listener;
-            if (mRowsSupportFragment != null) {
-                mRowsSupportFragment.setOnItemViewClickedListener(listener);
-            }
-        }
-    }
-
-    /**
-     * Returns the item clicked listener.
-     */
-    public BaseOnItemViewClickedListener getOnItemViewClickedListener() {
-        return mOnItemViewClickedListener;
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mContainerListAlignTop =
-            getResources().getDimensionPixelSize(R.dimen.lb_details_rows_align_top);
-
-        FragmentActivity activity = getActivity();
-        if (activity != null) {
-            Object transition = TransitionHelper.getEnterTransition(activity.getWindow());
-            if (transition == null) {
-                mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
-            }
-            transition = TransitionHelper.getReturnTransition(activity.getWindow());
-            if (transition != null) {
-                TransitionHelper.addTransitionListener(transition, mReturnTransitionListener);
-            }
-        } else {
-            mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
-        }
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        mRootView = (BrowseFrameLayout) inflater.inflate(
-                R.layout.lb_details_fragment, container, false);
-        mBackgroundView = mRootView.findViewById(R.id.details_background_view);
-        if (mBackgroundView != null) {
-            mBackgroundView.setBackground(mBackgroundDrawable);
-        }
-        mRowsSupportFragment = (RowsSupportFragment) getChildFragmentManager().findFragmentById(
-                R.id.details_rows_dock);
-        if (mRowsSupportFragment == null) {
-            mRowsSupportFragment = new RowsSupportFragment();
-            getChildFragmentManager().beginTransaction()
-                    .replace(R.id.details_rows_dock, mRowsSupportFragment).commit();
-        }
-        installTitleView(inflater, mRootView, savedInstanceState);
-        mRowsSupportFragment.setAdapter(mAdapter);
-        mRowsSupportFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
-        mRowsSupportFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
-
-        mSceneAfterEntranceTransition = TransitionHelper.createScene(mRootView, new Runnable() {
-            @Override
-            public void run() {
-                mRowsSupportFragment.setEntranceTransitionState(true);
-            }
-        });
-
-        setupDpadNavigation();
-
-        if (Build.VERSION.SDK_INT >= 21) {
-            // Setup adapter listener to work with ParallaxTransition (>= API 21).
-            mRowsSupportFragment.setExternalAdapterListener(new ItemBridgeAdapter.AdapterListener() {
-                @Override
-                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
-                    if (mDetailsParallax != null && vh.getViewHolder()
-                            instanceof FullWidthDetailsOverviewRowPresenter.ViewHolder) {
-                        FullWidthDetailsOverviewRowPresenter.ViewHolder rowVh =
-                                (FullWidthDetailsOverviewRowPresenter.ViewHolder)
-                                        vh.getViewHolder();
-                        rowVh.getOverviewView().setTag(R.id.lb_parallax_source,
-                                mDetailsParallax);
-                    }
-                }
-            });
-        }
-        return mRootView;
-    }
-
-    /**
-     * @deprecated override {@link #onInflateTitleView(LayoutInflater,ViewGroup,Bundle)} instead.
-     */
-    @Deprecated
-    protected View inflateTitle(LayoutInflater inflater, ViewGroup parent,
-            Bundle savedInstanceState) {
-        return super.onInflateTitleView(inflater, parent, savedInstanceState);
-    }
-
-    @Override
-    public View onInflateTitleView(LayoutInflater inflater, ViewGroup parent,
-                                   Bundle savedInstanceState) {
-        return inflateTitle(inflater, parent, savedInstanceState);
-    }
-
-    void setVerticalGridViewLayout(VerticalGridView listview) {
-        // align the top edge of item to a fixed position
-        listview.setItemAlignmentOffset(-mContainerListAlignTop);
-        listview.setItemAlignmentOffsetPercent(VerticalGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
-        listview.setWindowAlignmentOffset(0);
-        listview.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
-    }
-
-    /**
-     * Called to setup each Presenter of Adapter passed in {@link #setAdapter(ObjectAdapter)}.Note
-     * that setup should only change the Presenter behavior that is meaningful in DetailsSupportFragment.
-     * For example how a row is aligned in details Fragment.   The default implementation invokes
-     * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}
-     *
-     */
-    protected void setupPresenter(Presenter rowPresenter) {
-        if (rowPresenter instanceof FullWidthDetailsOverviewRowPresenter) {
-            setupDetailsOverviewRowPresenter((FullWidthDetailsOverviewRowPresenter) rowPresenter);
-        }
-    }
-
-    /**
-     * Called to setup {@link FullWidthDetailsOverviewRowPresenter}.  The default implementation
-     * adds two alignment positions({@link ItemAlignmentFacet}) for ViewHolder of
-     * FullWidthDetailsOverviewRowPresenter to align in fragment.
-     */
-    protected void setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter presenter) {
-        ItemAlignmentFacet facet = new ItemAlignmentFacet();
-        // by default align details_frame to half window height
-        ItemAlignmentFacet.ItemAlignmentDef alignDef1 = new ItemAlignmentFacet.ItemAlignmentDef();
-        alignDef1.setItemAlignmentViewId(R.id.details_frame);
-        alignDef1.setItemAlignmentOffset(- getResources()
-                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions));
-        alignDef1.setItemAlignmentOffsetPercent(0);
-        // when description is selected, align details_frame to top edge
-        ItemAlignmentFacet.ItemAlignmentDef alignDef2 = new ItemAlignmentFacet.ItemAlignmentDef();
-        alignDef2.setItemAlignmentViewId(R.id.details_frame);
-        alignDef2.setItemAlignmentFocusViewId(R.id.details_overview_description);
-        alignDef2.setItemAlignmentOffset(- getResources()
-                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description));
-        alignDef2.setItemAlignmentOffsetPercent(0);
-        ItemAlignmentFacet.ItemAlignmentDef[] defs =
-                new ItemAlignmentFacet.ItemAlignmentDef[] {alignDef1, alignDef2};
-        facet.setAlignmentDefs(defs);
-        presenter.setFacet(ItemAlignmentFacet.class, facet);
-    }
-
-    VerticalGridView getVerticalGridView() {
-        return mRowsSupportFragment == null ? null : mRowsSupportFragment.getVerticalGridView();
-    }
-
-    /**
-     * Gets embedded RowsSupportFragment showing multiple rows for DetailsSupportFragment.  If view of
-     * DetailsSupportFragment is not created, the method returns null.
-     * @return Embedded RowsSupportFragment showing multiple rows for DetailsSupportFragment.
-     */
-    public RowsSupportFragment getRowsSupportFragment() {
-        return mRowsSupportFragment;
-    }
-
-    /**
-     * Setup dimensions that are only meaningful when the child Fragments are inside
-     * DetailsSupportFragment.
-     */
-    private void setupChildFragmentLayout() {
-        setVerticalGridViewLayout(mRowsSupportFragment.getVerticalGridView());
-    }
-
-    /**
-     * Sets the selected row position with smooth animation.
-     */
-    public void setSelectedPosition(int position) {
-        setSelectedPosition(position, true);
-    }
-
-    /**
-     * Sets the selected row position.
-     */
-    public void setSelectedPosition(int position, boolean smooth) {
-        mSetSelectionRunnable.mPosition = position;
-        mSetSelectionRunnable.mSmooth = smooth;
-        if (getView() != null && getView().getHandler() != null) {
-            getView().getHandler().post(mSetSelectionRunnable);
-        }
-    }
-
-    void switchToVideo() {
-        if (mVideoSupportFragment != null && mVideoSupportFragment.getView() != null) {
-            mVideoSupportFragment.getView().requestFocus();
-        } else {
-            mStateMachine.fireEvent(EVT_SWITCH_TO_VIDEO);
-        }
-    }
-
-    void switchToRows() {
-        mPendingFocusOnVideo = false;
-        VerticalGridView verticalGridView = getVerticalGridView();
-        if (verticalGridView != null && verticalGridView.getChildCount() > 0) {
-            verticalGridView.requestFocus();
-        }
-    }
-
-    /**
-     * This method asks DetailsSupportFragmentBackgroundController to add a fragment for rendering video.
-     * In case the fragment is already there, it will return the existing one. The method must be
-     * called after calling super.onCreate(). App usually does not call this method directly.
-     *
-     * @return Fragment the added or restored fragment responsible for rendering video.
-     * @see DetailsSupportFragmentBackgroundController#onCreateVideoSupportFragment()
-     */
-    final Fragment findOrCreateVideoSupportFragment() {
-        if (mVideoSupportFragment != null) {
-            return mVideoSupportFragment;
-        }
-        Fragment fragment = getChildFragmentManager()
-                .findFragmentById(R.id.video_surface_container);
-        if (fragment == null && mDetailsBackgroundController != null) {
-            FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
-            ft2.add(android.support.v17.leanback.R.id.video_surface_container,
-                    fragment = mDetailsBackgroundController.onCreateVideoSupportFragment());
-            ft2.commit();
-            if (mPendingFocusOnVideo) {
-                // wait next cycle for Fragment view created so we can focus on it.
-                // This is a bit hack eventually we will do commitNow() which get view immediately.
-                getView().post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (getView() != null) {
-                            switchToVideo();
-                        }
-                        mPendingFocusOnVideo = false;
-                    }
-                });
-            }
-        }
-        mVideoSupportFragment = fragment;
-        return mVideoSupportFragment;
-    }
-
-    void onRowSelected(int selectedPosition, int selectedSubPosition) {
-        ObjectAdapter adapter = getAdapter();
-        if (( mRowsSupportFragment != null && mRowsSupportFragment.getView() != null
-                && mRowsSupportFragment.getView().hasFocus() && !mPendingFocusOnVideo)
-                && (adapter == null || adapter.size() == 0
-                || (getVerticalGridView().getSelectedPosition() == 0
-                && getVerticalGridView().getSelectedSubPosition() == 0))) {
-            showTitle(true);
-        } else {
-            showTitle(false);
-        }
-        if (adapter != null && adapter.size() > selectedPosition) {
-            final VerticalGridView gridView = getVerticalGridView();
-            final int count = gridView.getChildCount();
-            if (count > 0) {
-                mStateMachine.fireEvent(EVT_DETAILS_ROW_LOADED);
-            }
-            for (int i = 0; i < count; i++) {
-                ItemBridgeAdapter.ViewHolder bridgeViewHolder = (ItemBridgeAdapter.ViewHolder)
-                        gridView.getChildViewHolder(gridView.getChildAt(i));
-                RowPresenter rowPresenter = (RowPresenter) bridgeViewHolder.getPresenter();
-                onSetRowStatus(rowPresenter,
-                        rowPresenter.getRowViewHolder(bridgeViewHolder.getViewHolder()),
-                        bridgeViewHolder.getAdapterPosition(),
-                        selectedPosition, selectedSubPosition);
-            }
-        }
-    }
-
-    /**
-     * Called when onStart and enter transition (postponed/none postponed) and entrance transition
-     * are all finished.
-     */
-    @CallSuper
-    void onSafeStart() {
-        if (mDetailsBackgroundController != null) {
-            mDetailsBackgroundController.onStart();
-        }
-    }
-
-    @CallSuper
-    void onReturnTransitionStart() {
-        if (mDetailsBackgroundController != null) {
-            // first disable parallax effect that auto-start PlaybackGlue.
-            boolean isVideoVisible = mDetailsBackgroundController.disableVideoParallax();
-            // if video is not visible we can safely remove VideoSupportFragment,
-            // otherwise let video playing during return transition.
-            if (!isVideoVisible && mVideoSupportFragment != null) {
-                FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
-                ft2.remove(mVideoSupportFragment);
-                ft2.commit();
-                mVideoSupportFragment = null;
-            }
-        }
-    }
-
-    @Override
-    public void onStop() {
-        if (mDetailsBackgroundController != null) {
-            mDetailsBackgroundController.onStop();
-        }
-        super.onStop();
-    }
-
-    /**
-     * Called on every visible row to change view status when current selected row position
-     * or selected sub position changed.  Subclass may override.   The default
-     * implementation calls {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
-     * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)} if presenter is
-     * instance of {@link FullWidthDetailsOverviewRowPresenter}.
-     *
-     * @param presenter   The presenter used to create row ViewHolder.
-     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
-     *                    be selected.
-     * @param adapterPosition  The adapter position of viewHolder inside adapter.
-     * @param selectedPosition The adapter position of currently selected row.
-     * @param selectedSubPosition The sub position within currently selected row.  This is used
-     *                            When a row has multiple alignment positions.
-     */
-    protected void onSetRowStatus(RowPresenter presenter, RowPresenter.ViewHolder viewHolder, int
-            adapterPosition, int selectedPosition, int selectedSubPosition) {
-        if (presenter instanceof FullWidthDetailsOverviewRowPresenter) {
-            onSetDetailsOverviewRowStatus((FullWidthDetailsOverviewRowPresenter) presenter,
-                    (FullWidthDetailsOverviewRowPresenter.ViewHolder) viewHolder,
-                    adapterPosition, selectedPosition, selectedSubPosition);
-        }
-    }
-
-    /**
-     * Called to change DetailsOverviewRow view status when current selected row position
-     * or selected sub position changed.  Subclass may override.   The default
-     * implementation switches between three states based on the positions:
-     * {@link FullWidthDetailsOverviewRowPresenter#STATE_HALF},
-     * {@link FullWidthDetailsOverviewRowPresenter#STATE_FULL} and
-     * {@link FullWidthDetailsOverviewRowPresenter#STATE_SMALL}.
-     *
-     * @param presenter   The presenter used to create row ViewHolder.
-     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
-     *                    be selected.
-     * @param adapterPosition  The adapter position of viewHolder inside adapter.
-     * @param selectedPosition The adapter position of currently selected row.
-     * @param selectedSubPosition The sub position within currently selected row.  This is used
-     *                            When a row has multiple alignment positions.
-     */
-    protected void onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter presenter,
-            FullWidthDetailsOverviewRowPresenter.ViewHolder viewHolder, int adapterPosition,
-            int selectedPosition, int selectedSubPosition) {
-        if (selectedPosition > adapterPosition) {
-            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
-        } else if (selectedPosition == adapterPosition && selectedSubPosition == 1) {
-            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
-        } else if (selectedPosition == adapterPosition && selectedSubPosition == 0){
-            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_FULL);
-        } else {
-            presenter.setState(viewHolder,
-                    FullWidthDetailsOverviewRowPresenter.STATE_SMALL);
-        }
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        setupChildFragmentLayout();
-        mStateMachine.fireEvent(EVT_ONSTART);
-        if (mDetailsParallax != null) {
-            mDetailsParallax.setRecyclerView(mRowsSupportFragment.getVerticalGridView());
-        }
-        if (mPendingFocusOnVideo) {
-            slideOutGridView();
-        } else if (!getView().hasFocus()) {
-            mRowsSupportFragment.getVerticalGridView().requestFocus();
-        }
-    }
-
-    @Override
-    protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getContext(),
-                R.transition.lb_details_enter_transition);
-    }
-
-    @Override
-    protected void runEntranceTransition(Object entranceTransition) {
-        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
-    }
-
-    @Override
-    protected void onEntranceTransitionEnd() {
-        mRowsSupportFragment.onTransitionEnd();
-    }
-
-    @Override
-    protected void onEntranceTransitionPrepare() {
-        mRowsSupportFragment.onTransitionPrepare();
-    }
-
-    @Override
-    protected void onEntranceTransitionStart() {
-        mRowsSupportFragment.onTransitionStart();
-    }
-
-    /**
-     * Returns the {@link DetailsParallax} instance used by
-     * {@link DetailsSupportFragmentBackgroundController} to configure parallax effect of background and
-     * control embedded video playback. App usually does not use this method directly.
-     * App may use this method for other custom parallax tasks.
-     *
-     * @return The DetailsParallax instance attached to the DetailsSupportFragment.
-     */
-    public DetailsParallax getParallax() {
-        if (mDetailsParallax == null) {
-            mDetailsParallax = new DetailsParallax();
-            if (mRowsSupportFragment != null && mRowsSupportFragment.getView() != null) {
-                mDetailsParallax.setRecyclerView(mRowsSupportFragment.getVerticalGridView());
-            }
-        }
-        return mDetailsParallax;
-    }
-
-    /**
-     * Set background drawable shown below foreground rows UI and above
-     * {@link #findOrCreateVideoSupportFragment()}.
-     *
-     * @see DetailsSupportFragmentBackgroundController
-     */
-    void setBackgroundDrawable(Drawable drawable) {
-        if (mBackgroundView != null) {
-            mBackgroundView.setBackground(drawable);
-        }
-        mBackgroundDrawable = drawable;
-    }
-
-    /**
-     * This method does the following
-     * <ul>
-     * <li>sets up focus search handling logic in the root view to enable transitioning between
-     * half screen/full screen/no video mode.</li>
-     *
-     * <li>Sets up the key listener in the root view to intercept events like UP/DOWN and
-     * transition to appropriate mode like half/full screen video.</li>
-     * </ul>
-     */
-    void setupDpadNavigation() {
-        mRootView.setOnChildFocusListener(new BrowseFrameLayout.OnChildFocusListener() {
-
-            @Override
-            public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
-                return false;
-            }
-
-            @Override
-            public void onRequestChildFocus(View child, View focused) {
-                if (child != mRootView.getFocusedChild()) {
-                    if (child.getId() == R.id.details_fragment_root) {
-                        if (!mPendingFocusOnVideo) {
-                            slideInGridView();
-                            showTitle(true);
-                        }
-                    } else if (child.getId() == R.id.video_surface_container) {
-                        slideOutGridView();
-                        showTitle(false);
-                    } else {
-                        showTitle(true);
-                    }
-                }
-            }
-        });
-        mRootView.setOnFocusSearchListener(new BrowseFrameLayout.OnFocusSearchListener() {
-            @Override
-            public View onFocusSearch(View focused, int direction) {
-                if (mRowsSupportFragment.getVerticalGridView() != null
-                        && mRowsSupportFragment.getVerticalGridView().hasFocus()) {
-                    if (direction == View.FOCUS_UP) {
-                        if (mDetailsBackgroundController != null
-                                && mDetailsBackgroundController.canNavigateToVideoSupportFragment()
-                                && mVideoSupportFragment != null && mVideoSupportFragment.getView() != null) {
-                            return mVideoSupportFragment.getView();
-                        } else if (getTitleView() != null && getTitleView().hasFocusable()) {
-                            return getTitleView();
-                        }
-                    }
-                } else if (getTitleView() != null && getTitleView().hasFocus()) {
-                    if (direction == View.FOCUS_DOWN) {
-                        if (mRowsSupportFragment.getVerticalGridView() != null) {
-                            return mRowsSupportFragment.getVerticalGridView();
-                        }
-                    }
-                }
-                return focused;
-            }
-        });
-
-        // If we press BACK on remote while in full screen video mode, we should
-        // transition back to half screen video playback mode.
-        mRootView.setOnDispatchKeyListener(new View.OnKeyListener() {
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                // This is used to check if we are in full screen video mode. This is somewhat
-                // hacky and relies on the behavior of the video helper class to update the
-                // focusability of the video surface view.
-                if (mVideoSupportFragment != null && mVideoSupportFragment.getView() != null
-                        && mVideoSupportFragment.getView().hasFocus()) {
-                    if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
-                        if (getVerticalGridView().getChildCount() > 0) {
-                            getVerticalGridView().requestFocus();
-                            return true;
-                        }
-                    }
-                }
-
-                return false;
-            }
-        });
-    }
-
-    /**
-     * Slides vertical grid view (displaying media item details) out of the screen from below.
-     */
-    void slideOutGridView() {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().animateOut();
-        }
-    }
-
-    void slideInGridView() {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().animateIn();
-        }
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java b/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
deleted file mode 100644
index dc59e0e..0000000
--- a/leanback/src/android/support/v17/leanback/app/PlaybackFragment.java
+++ /dev/null
@@ -1,1183 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from PlaybackSupportFragment.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.animation.LogAccelerateInterpolator;
-import android.support.v17.leanback.animation.LogDecelerateInterpolator;
-import android.support.v17.leanback.media.PlaybackGlueHost;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
-import android.support.v17.leanback.widget.ClassPresenterSelector;
-import android.support.v17.leanback.widget.ItemAlignmentFacet;
-import android.support.v17.leanback.widget.ItemBridgeAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.PlaybackSeekDataProvider;
-import android.support.v17.leanback.widget.PlaybackSeekUi;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.app.Fragment;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.InputEvent;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-
-/**
- * A fragment for displaying playback controls and related content.
- *
- * <p>
- * A PlaybackFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
- * of {@link RowPresenter}.
- * </p>
- * <p>
- * A playback row is a row rendered by {@link PlaybackRowPresenter}.
- * App can call {@link #setPlaybackRow(Row)} to set playback row for the first element of adapter.
- * App can call {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} to set presenter for it.
- * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} are
- * optional, app can pass playback row and PlaybackRowPresenter in the adapter using
- * {@link #setAdapter(ObjectAdapter)}.
- * </p>
- * <p>
- * Auto hide controls upon playing: best practice is calling
- * {@link #setControlsOverlayAutoHideEnabled(boolean)} upon play/pause. The auto hiding timer will
- * be cancelled upon {@link #tickle()} triggered by input event.
- * </p>
- * @deprecated use {@link PlaybackSupportFragment}
- */
-@Deprecated
-public class PlaybackFragment extends Fragment {
-    static final String BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW = "controlvisible_oncreateview";
-
-    /**
-     * No background.
-     */
-    public static final int BG_NONE = 0;
-
-    /**
-     * A dark translucent background.
-     */
-    public static final int BG_DARK = 1;
-    PlaybackGlueHost.HostCallback mHostCallback;
-
-    PlaybackSeekUi.Client mSeekUiClient;
-    boolean mInSeek;
-    ProgressBarManager mProgressBarManager = new ProgressBarManager();
-
-    /**
-     * Resets the focus on the button in the middle of control row.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public void resetFocus() {
-        ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView()
-                .findViewHolderForAdapterPosition(0);
-        if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
-            ((PlaybackRowPresenter) vh.getPresenter()).onReappear(
-                    (RowPresenter.ViewHolder) vh.getViewHolder());
-        }
-    }
-
-    private class SetSelectionRunnable implements Runnable {
-        int mPosition;
-        boolean mSmooth = true;
-
-        @Override
-        public void run() {
-            if (mRowsFragment == null) {
-                return;
-            }
-            mRowsFragment.setSelectedPosition(mPosition, mSmooth);
-        }
-    }
-
-    /**
-     * A light translucent background.
-     */
-    public static final int BG_LIGHT = 2;
-    RowsFragment mRowsFragment;
-    ObjectAdapter mAdapter;
-    PlaybackRowPresenter mPresenter;
-    Row mRow;
-    BaseOnItemViewSelectedListener mExternalItemSelectedListener;
-    BaseOnItemViewClickedListener mExternalItemClickedListener;
-    BaseOnItemViewClickedListener mPlaybackItemClickedListener;
-
-    private final BaseOnItemViewClickedListener mOnItemViewClickedListener =
-            new BaseOnItemViewClickedListener() {
-                @Override
-                public void onItemClicked(Presenter.ViewHolder itemViewHolder,
-                                          Object item,
-                                          RowPresenter.ViewHolder rowViewHolder,
-                                          Object row) {
-                    if (mPlaybackItemClickedListener != null
-                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder) {
-                        mPlaybackItemClickedListener.onItemClicked(
-                                itemViewHolder, item, rowViewHolder, row);
-                    }
-                    if (mExternalItemClickedListener != null) {
-                        mExternalItemClickedListener.onItemClicked(
-                                itemViewHolder, item, rowViewHolder, row);
-                    }
-                }
-            };
-
-    private final BaseOnItemViewSelectedListener mOnItemViewSelectedListener =
-            new BaseOnItemViewSelectedListener() {
-                @Override
-                public void onItemSelected(Presenter.ViewHolder itemViewHolder,
-                                           Object item,
-                                           RowPresenter.ViewHolder rowViewHolder,
-                                           Object row) {
-                    if (mExternalItemSelectedListener != null) {
-                        mExternalItemSelectedListener.onItemSelected(
-                                itemViewHolder, item, rowViewHolder, row);
-                    }
-                }
-            };
-
-    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
-
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    /**
-     * Listener allowing the application to receive notification of fade in and/or fade out
-     * completion events.
-     * @hide
-     * @deprecated use {@link PlaybackSupportFragment}
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    @Deprecated
-    public static class OnFadeCompleteListener {
-        public void onFadeInComplete() {
-        }
-
-        public void onFadeOutComplete() {
-        }
-    }
-
-    private static final String TAG = "PlaybackFragment";
-    private static final boolean DEBUG = false;
-    private static final int ANIMATION_MULTIPLIER = 1;
-
-    private static int START_FADE_OUT = 1;
-
-    // Fading status
-    private static final int IDLE = 0;
-    private static final int ANIMATING = 1;
-
-    int mPaddingBottom;
-    int mOtherRowsCenterToBottom;
-    View mRootView;
-    View mBackgroundView;
-    int mBackgroundType = BG_DARK;
-    int mBgDarkColor;
-    int mBgLightColor;
-    int mShowTimeMs;
-    int mMajorFadeTranslateY, mMinorFadeTranslateY;
-    int mAnimationTranslateY;
-    OnFadeCompleteListener mFadeCompleteListener;
-    View.OnKeyListener mInputEventHandler;
-    boolean mFadingEnabled = true;
-    boolean mControlVisibleBeforeOnCreateView = true;
-    boolean mControlVisible = true;
-    int mBgAlpha;
-    ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
-    ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
-    ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
-
-    private final Animator.AnimatorListener mFadeListener =
-            new Animator.AnimatorListener() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    enableVerticalGridAnimations(false);
-                }
-
-                @Override
-                public void onAnimationRepeat(Animator animation) {
-                }
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
-                    if (mBgAlpha > 0) {
-                        enableVerticalGridAnimations(true);
-                        if (mFadeCompleteListener != null) {
-                            mFadeCompleteListener.onFadeInComplete();
-                        }
-                    } else {
-                        VerticalGridView verticalView = getVerticalGridView();
-                        // reset focus to the primary actions only if the selected row was the controls row
-                        if (verticalView != null && verticalView.getSelectedPosition() == 0) {
-                            ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder)
-                                    verticalView.findViewHolderForAdapterPosition(0);
-                            if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
-                                ((PlaybackRowPresenter)vh.getPresenter()).onReappear(
-                                        (RowPresenter.ViewHolder) vh.getViewHolder());
-                            }
-                        }
-                        if (mFadeCompleteListener != null) {
-                            mFadeCompleteListener.onFadeOutComplete();
-                        }
-                    }
-                }
-            };
-
-    public PlaybackFragment() {
-        mProgressBarManager.setInitialDelay(500);
-    }
-
-    VerticalGridView getVerticalGridView() {
-        if (mRowsFragment == null) {
-            return null;
-        }
-        return mRowsFragment.getVerticalGridView();
-    }
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message message) {
-            if (message.what == START_FADE_OUT && mFadingEnabled) {
-                hideControlsOverlay(true);
-            }
-        }
-    };
-
-    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
-            new VerticalGridView.OnTouchInterceptListener() {
-                @Override
-                public boolean onInterceptTouchEvent(MotionEvent event) {
-                    return onInterceptInputEvent(event);
-                }
-            };
-
-    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
-            new VerticalGridView.OnKeyInterceptListener() {
-                @Override
-                public boolean onInterceptKeyEvent(KeyEvent event) {
-                    return onInterceptInputEvent(event);
-                }
-            };
-
-    private void setBgAlpha(int alpha) {
-        mBgAlpha = alpha;
-        if (mBackgroundView != null) {
-            mBackgroundView.getBackground().setAlpha(alpha);
-        }
-    }
-
-    private void enableVerticalGridAnimations(boolean enable) {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().setAnimateChildLayout(enable);
-        }
-    }
-
-    /**
-     * Enables or disables auto hiding controls overlay after a short delay fragment is resumed.
-     * If enabled and fragment is resumed, the view will fade out after a time period.
-     * {@link #tickle()} will kill the timer, next time fragment is resumed,
-     * the timer will be started again if {@link #isControlsOverlayAutoHideEnabled()} is true.
-     */
-    public void setControlsOverlayAutoHideEnabled(boolean enabled) {
-        if (DEBUG) Log.v(TAG, "setControlsOverlayAutoHideEnabled " + enabled);
-        if (enabled != mFadingEnabled) {
-            mFadingEnabled = enabled;
-            if (isResumed() && getView().hasFocus()) {
-                showControlsOverlay(true);
-                if (enabled) {
-                    // StateGraph 7->2 5->2
-                    startFadeTimer();
-                } else {
-                    // StateGraph 4->5 2->5
-                    stopFadeTimer();
-                }
-            } else {
-                // StateGraph 6->1 1->6
-            }
-        }
-    }
-
-    /**
-     * Returns true if controls will be auto hidden after a delay when fragment is resumed.
-     */
-    public boolean isControlsOverlayAutoHideEnabled() {
-        return mFadingEnabled;
-    }
-
-    /**
-     * @deprecated Uses {@link #setControlsOverlayAutoHideEnabled(boolean)}
-     */
-    @Deprecated
-    public void setFadingEnabled(boolean enabled) {
-        setControlsOverlayAutoHideEnabled(enabled);
-    }
-
-    /**
-     * @deprecated Uses {@link #isControlsOverlayAutoHideEnabled()}
-     */
-    @Deprecated
-    public boolean isFadingEnabled() {
-        return isControlsOverlayAutoHideEnabled();
-    }
-
-    /**
-     * Sets the listener to be called when fade in or out has completed.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
-        mFadeCompleteListener = listener;
-    }
-
-    /**
-     * Returns the listener to be called when fade in or out has completed.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public OnFadeCompleteListener getFadeCompleteListener() {
-        return mFadeCompleteListener;
-    }
-
-    /**
-     * Sets the input event handler.
-     */
-    public final void setOnKeyInterceptListener(View.OnKeyListener handler) {
-        mInputEventHandler = handler;
-    }
-
-    /**
-     * Tickles the playback controls. Fades in the view if it was faded out. {@link #tickle()} will
-     * also kill the timer created by {@link #setControlsOverlayAutoHideEnabled(boolean)}. When
-     * next time fragment is resumed, the timer will be started again if
-     * {@link #isControlsOverlayAutoHideEnabled()} is true. In most cases app does not need call
-     * this method, tickling on input events is handled by the fragment.
-     */
-    public void tickle() {
-        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
-        //StateGraph 2->4
-        stopFadeTimer();
-        showControlsOverlay(true);
-    }
-
-    private boolean onInterceptInputEvent(InputEvent event) {
-        final boolean controlsHidden = !mControlVisible;
-        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
-        boolean consumeEvent = false;
-        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
-        int keyAction = 0;
-
-        if (event instanceof KeyEvent) {
-            keyCode = ((KeyEvent) event).getKeyCode();
-            keyAction = ((KeyEvent) event).getAction();
-            if (mInputEventHandler != null) {
-                consumeEvent = mInputEventHandler.onKey(getView(), keyCode, (KeyEvent) event);
-            }
-        }
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                // Event may be consumed; regardless, if controls are hidden then these keys will
-                // bring up the controls.
-                if (controlsHidden) {
-                    consumeEvent = true;
-                }
-                if (keyAction == KeyEvent.ACTION_DOWN) {
-                    tickle();
-                }
-                break;
-            case KeyEvent.KEYCODE_BACK:
-            case KeyEvent.KEYCODE_ESCAPE:
-                if (mInSeek) {
-                    // when in seek, the SeekUi will handle the BACK.
-                    return false;
-                }
-                // If controls are not hidden, back will be consumed to fade
-                // them out (even if the key was consumed by the handler).
-                if (!controlsHidden) {
-                    consumeEvent = true;
-
-                    if (((KeyEvent) event).getAction() == KeyEvent.ACTION_UP) {
-                        hideControlsOverlay(true);
-                    }
-                }
-                break;
-            default:
-                if (consumeEvent) {
-                    if (keyAction == KeyEvent.ACTION_DOWN) {
-                        tickle();
-                    }
-                }
-        }
-        return consumeEvent;
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-        // controls view are initially visible, make it invisible
-        // if app has called hideControlsOverlay() before view created.
-        mControlVisible = true;
-        if (!mControlVisibleBeforeOnCreateView) {
-            showControlsOverlay(false, false);
-            mControlVisibleBeforeOnCreateView = true;
-        }
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        if (mControlVisible) {
-            //StateGraph: 6->5 1->2
-            if (mFadingEnabled) {
-                // StateGraph 1->2
-                startFadeTimer();
-            }
-        } else {
-            //StateGraph: 6->7 1->3
-        }
-        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
-        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
-        if (mHostCallback != null) {
-            mHostCallback.onHostResume();
-        }
-    }
-
-    private void stopFadeTimer() {
-        if (mHandler != null) {
-            mHandler.removeMessages(START_FADE_OUT);
-        }
-    }
-
-    private void startFadeTimer() {
-        if (mHandler != null) {
-            mHandler.removeMessages(START_FADE_OUT);
-            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
-        }
-    }
-
-    private static ValueAnimator loadAnimator(Context context, int resId) {
-        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
-        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
-        return animator;
-    }
-
-    private void loadBgAnimator() {
-        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                setBgAlpha((Integer) arg0.getAnimatedValue());
-            }
-        };
-
-        Context context = FragmentUtil.getContext(PlaybackFragment.this);
-        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
-        mBgFadeInAnimator.addUpdateListener(listener);
-        mBgFadeInAnimator.addListener(mFadeListener);
-
-        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
-        mBgFadeOutAnimator.addUpdateListener(listener);
-        mBgFadeOutAnimator.addListener(mFadeListener);
-    }
-
-    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100, 0);
-    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100, 0);
-
-    private void loadControlRowAnimator() {
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                RecyclerView.ViewHolder vh = getVerticalGridView()
-                        .findViewHolderForAdapterPosition(0);
-                if (vh == null) {
-                    return;
-                }
-                View view = vh.itemView;
-                if (view != null) {
-                    final float fraction = (Float) arg0.getAnimatedValue();
-                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
-                    view.setAlpha(fraction);
-                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                }
-            }
-        };
-
-        Context context = FragmentUtil.getContext(PlaybackFragment.this);
-        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mControlRowFadeInAnimator.addUpdateListener(updateListener);
-        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mControlRowFadeOutAnimator = loadAnimator(context,
-                R.animator.lb_playback_controls_fade_out);
-        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
-        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
-    }
-
-    private void loadOtherRowAnimator() {
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                final float fraction = (Float) arg0.getAnimatedValue();
-                final int count = getVerticalGridView().getChildCount();
-                for (int i = 0; i < count; i++) {
-                    View view = getVerticalGridView().getChildAt(i);
-                    if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
-                        view.setAlpha(fraction);
-                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                    }
-                }
-            }
-        };
-
-        Context context = FragmentUtil.getContext(PlaybackFragment.this);
-        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
-        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
-    }
-
-    /**
-     * Fades out the playback overlay immediately.
-     * @deprecated Call {@link #hideControlsOverlay(boolean)}
-     */
-    @Deprecated
-    public void fadeOut() {
-        showControlsOverlay(false, false);
-    }
-
-    /**
-     * Show controls overlay.
-     *
-     * @param runAnimation True to run animation, false otherwise.
-     */
-    public void showControlsOverlay(boolean runAnimation) {
-        showControlsOverlay(true, runAnimation);
-    }
-
-    /**
-     * Returns true if controls overlay is visible, false otherwise.
-     *
-     * @return True if controls overlay is visible, false otherwise.
-     * @see #showControlsOverlay(boolean)
-     * @see #hideControlsOverlay(boolean)
-     */
-    public boolean isControlsOverlayVisible() {
-        return mControlVisible;
-    }
-
-    /**
-     * Hide controls overlay.
-     *
-     * @param runAnimation True to run animation, false otherwise.
-     */
-    public void hideControlsOverlay(boolean runAnimation) {
-        showControlsOverlay(false, runAnimation);
-    }
-
-    /**
-     * if first animator is still running, reverse it; otherwise start second animator.
-     */
-    static void reverseFirstOrStartSecond(ValueAnimator first, ValueAnimator second,
-            boolean runAnimation) {
-        if (first.isStarted()) {
-            first.reverse();
-            if (!runAnimation) {
-                first.end();
-            }
-        } else {
-            second.start();
-            if (!runAnimation) {
-                second.end();
-            }
-        }
-    }
-
-    /**
-     * End first or second animator if they are still running.
-     */
-    static void endAll(ValueAnimator first, ValueAnimator second) {
-        if (first.isStarted()) {
-            first.end();
-        } else if (second.isStarted()) {
-            second.end();
-        }
-    }
-
-    /**
-     * Fade in or fade out rows and background.
-     *
-     * @param show True to fade in, false to fade out.
-     * @param animation True to run animation.
-     */
-    void showControlsOverlay(boolean show, boolean animation) {
-        if (DEBUG) Log.v(TAG, "showControlsOverlay " + show);
-        if (getView() == null) {
-            mControlVisibleBeforeOnCreateView = show;
-            return;
-        }
-        // force no animation when fragment is not resumed
-        if (!isResumed()) {
-            animation = false;
-        }
-        if (show == mControlVisible) {
-            if (!animation) {
-                // End animation if needed
-                endAll(mBgFadeInAnimator, mBgFadeOutAnimator);
-                endAll(mControlRowFadeInAnimator, mControlRowFadeOutAnimator);
-                endAll(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator);
-            }
-            return;
-        }
-        // StateGraph: 7<->5 4<->3 2->3
-        mControlVisible = show;
-        if (!mControlVisible) {
-            // StateGraph 2->3
-            stopFadeTimer();
-        }
-
-        mAnimationTranslateY = (getVerticalGridView() == null
-                || getVerticalGridView().getSelectedPosition() == 0)
-                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
-
-        if (show) {
-            reverseFirstOrStartSecond(mBgFadeOutAnimator, mBgFadeInAnimator, animation);
-            reverseFirstOrStartSecond(mControlRowFadeOutAnimator, mControlRowFadeInAnimator,
-                    animation);
-            reverseFirstOrStartSecond(mOtherRowFadeOutAnimator, mOtherRowFadeInAnimator, animation);
-        } else {
-            reverseFirstOrStartSecond(mBgFadeInAnimator, mBgFadeOutAnimator, animation);
-            reverseFirstOrStartSecond(mControlRowFadeInAnimator, mControlRowFadeOutAnimator,
-                    animation);
-            reverseFirstOrStartSecond(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator, animation);
-        }
-        if (animation) {
-            getView().announceForAccessibility(getString(show
-                    ? R.string.lb_playback_controls_shown
-                    : R.string.lb_playback_controls_hidden));
-        }
-    }
-
-    /**
-     * Sets the selected row position with smooth animation.
-     */
-    public void setSelectedPosition(int position) {
-        setSelectedPosition(position, true);
-    }
-
-    /**
-     * Sets the selected row position.
-     */
-    public void setSelectedPosition(int position, boolean smooth) {
-        mSetSelectionRunnable.mPosition = position;
-        mSetSelectionRunnable.mSmooth = smooth;
-        if (getView() != null && getView().getHandler() != null) {
-            getView().getHandler().post(mSetSelectionRunnable);
-        }
-    }
-
-    private void setupChildFragmentLayout() {
-        setVerticalGridViewLayout(mRowsFragment.getVerticalGridView());
-    }
-
-    void setVerticalGridViewLayout(VerticalGridView listview) {
-        if (listview == null) {
-            return;
-        }
-
-        // we set the base line of alignment to -paddingBottom
-        listview.setWindowAlignmentOffset(-mPaddingBottom);
-        listview.setWindowAlignmentOffsetPercent(
-                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-
-        // align other rows that arent the last to center of screen, since our baseline is
-        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
-        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
-        listview.setItemAlignmentOffsetPercent(50);
-
-        // Push last row to the bottom padding
-        // Padding affects alignment when last row is focused
-        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
-                listview.getPaddingRight(), mPaddingBottom);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mOtherRowsCenterToBottom = getResources()
-                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
-        mPaddingBottom =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
-        mBgDarkColor =
-                getResources().getColor(R.color.lb_playback_controls_background_dark);
-        mBgLightColor =
-                getResources().getColor(R.color.lb_playback_controls_background_light);
-        mShowTimeMs =
-                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
-        mMajorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
-        mMinorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
-
-        loadBgAnimator();
-        loadControlRowAnimator();
-        loadOtherRowAnimator();
-    }
-
-    /**
-     * Sets the background type.
-     *
-     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
-     */
-    public void setBackgroundType(int type) {
-        switch (type) {
-            case BG_LIGHT:
-            case BG_DARK:
-            case BG_NONE:
-                if (type != mBackgroundType) {
-                    mBackgroundType = type;
-                    updateBackground();
-                }
-                break;
-            default:
-                throw new IllegalArgumentException("Invalid background type");
-        }
-    }
-
-    /**
-     * Returns the background type.
-     */
-    public int getBackgroundType() {
-        return mBackgroundType;
-    }
-
-    private void updateBackground() {
-        if (mBackgroundView != null) {
-            int color = mBgDarkColor;
-            switch (mBackgroundType) {
-                case BG_DARK:
-                    break;
-                case BG_LIGHT:
-                    color = mBgLightColor;
-                    break;
-                case BG_NONE:
-                    color = Color.TRANSPARENT;
-                    break;
-            }
-            mBackgroundView.setBackground(new ColorDrawable(color));
-            setBgAlpha(mBgAlpha);
-        }
-    }
-
-    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
-            new ItemBridgeAdapter.AdapterListener() {
-                @Override
-                public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
-                    if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
-                    if (!mControlVisible) {
-                        if (DEBUG) Log.v(TAG, "setting alpha to 0");
-                        vh.getViewHolder().view.setAlpha(0);
-                    }
-                }
-
-                @Override
-                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
-                    Presenter.ViewHolder viewHolder = vh.getViewHolder();
-                    if (viewHolder instanceof PlaybackSeekUi) {
-                        ((PlaybackSeekUi) viewHolder).setPlaybackSeekUiClient(mChainedClient);
-                    }
-                }
-
-                @Override
-                public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
-                    if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
-                    // Reset animation state
-                    vh.getViewHolder().view.setAlpha(1f);
-                    vh.getViewHolder().view.setTranslationY(0);
-                    vh.getViewHolder().view.setAlpha(1f);
-                }
-
-                @Override
-                public void onBind(ItemBridgeAdapter.ViewHolder vh) {
-                }
-            };
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
-        mRootView = inflater.inflate(R.layout.lb_playback_fragment, container, false);
-        mBackgroundView = mRootView.findViewById(R.id.playback_fragment_background);
-        mRowsFragment = (RowsFragment) getChildFragmentManager().findFragmentById(
-                R.id.playback_controls_dock);
-        if (mRowsFragment == null) {
-            mRowsFragment = new RowsFragment();
-            getChildFragmentManager().beginTransaction()
-                    .replace(R.id.playback_controls_dock, mRowsFragment)
-                    .commit();
-        }
-        if (mAdapter == null) {
-            setAdapter(new ArrayObjectAdapter(new ClassPresenterSelector()));
-        } else {
-            mRowsFragment.setAdapter(mAdapter);
-        }
-        mRowsFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
-        mRowsFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
-
-        mBgAlpha = 255;
-        updateBackground();
-        mRowsFragment.setExternalAdapterListener(mAdapterListener);
-        ProgressBarManager progressBarManager = getProgressBarManager();
-        if (progressBarManager != null) {
-            progressBarManager.setRootView((ViewGroup) mRootView);
-        }
-        return mRootView;
-    }
-
-    /**
-     * Sets the {@link PlaybackGlueHost.HostCallback}. Implementor of this interface will
-     * take appropriate actions to take action when the hosting fragment starts/stops processing.
-     */
-    public void setHostCallback(PlaybackGlueHost.HostCallback hostCallback) {
-        this.mHostCallback = hostCallback;
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        setupChildFragmentLayout();
-        mRowsFragment.setAdapter(mAdapter);
-        if (mHostCallback != null) {
-            mHostCallback.onHostStart();
-        }
-    }
-
-    @Override
-    public void onStop() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostStop();
-        }
-        super.onStop();
-    }
-
-    @Override
-    public void onPause() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostPause();
-        }
-        if (mHandler.hasMessages(START_FADE_OUT)) {
-            // StateGraph: 2->1
-            mHandler.removeMessages(START_FADE_OUT);
-        } else {
-            // StateGraph: 5->6, 7->6, 4->1, 3->1
-        }
-        super.onPause();
-    }
-
-    /**
-     * This listener is called every time there is a selection in {@link RowsFragment}. This can
-     * be used by users to take additional actions such as animations.
-     */
-    public void setOnItemViewSelectedListener(final BaseOnItemViewSelectedListener listener) {
-        mExternalItemSelectedListener = listener;
-    }
-
-    /**
-     * This listener is called every time there is a click in {@link RowsFragment}. This can
-     * be used by users to take additional actions such as animations.
-     */
-    public void setOnItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
-        mExternalItemClickedListener = listener;
-    }
-
-    /**
-     * Sets the {@link BaseOnItemViewClickedListener} that would be invoked for clicks
-     * only on {@link android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder}.
-     */
-    public void setOnPlaybackItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
-        mPlaybackItemClickedListener = listener;
-    }
-
-    @Override
-    public void onDestroyView() {
-        mRootView = null;
-        mBackgroundView = null;
-        super.onDestroyView();
-    }
-
-    @Override
-    public void onDestroy() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostDestroy();
-        }
-        super.onDestroy();
-    }
-
-    /**
-     * Sets the playback row for the playback controls. The row will be set as first element
-     * of adapter if the adapter is {@link ArrayObjectAdapter} or {@link SparseArrayObjectAdapter}.
-     * @param row The row that represents the playback.
-     */
-    public void setPlaybackRow(Row row) {
-        this.mRow = row;
-        setupRow();
-        setupPresenter();
-    }
-
-    /**
-     * Sets the presenter for rendering the playback row set by {@link #setPlaybackRow(Row)}. If
-     * adapter does not set a {@link PresenterSelector}, {@link #setAdapter(ObjectAdapter)} will
-     * create a {@link ClassPresenterSelector} by default and map from the row object class to this
-     * {@link PlaybackRowPresenter}.
-     *
-     * @param  presenter Presenter used to render {@link #setPlaybackRow(Row)}.
-     */
-    public void setPlaybackRowPresenter(PlaybackRowPresenter presenter) {
-        this.mPresenter = presenter;
-        setupPresenter();
-        setPlaybackRowPresenterAlignment();
-    }
-
-    void setPlaybackRowPresenterAlignment() {
-        if (mAdapter != null && mAdapter.getPresenterSelector() != null) {
-            Presenter[] presenters = mAdapter.getPresenterSelector().getPresenters();
-            if (presenters != null) {
-                for (int i = 0; i < presenters.length; i++) {
-                    if (presenters[i] instanceof PlaybackRowPresenter
-                            && presenters[i].getFacet(ItemAlignmentFacet.class) == null) {
-                        ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
-                        ItemAlignmentFacet.ItemAlignmentDef def =
-                                new ItemAlignmentFacet.ItemAlignmentDef();
-                        def.setItemAlignmentOffset(0);
-                        def.setItemAlignmentOffsetPercent(100);
-                        itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
-                                {def});
-                        presenters[i].setFacet(ItemAlignmentFacet.class, itemAlignment);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Updates the ui when the row data changes.
-     */
-    public void notifyPlaybackRowChanged() {
-        if (mAdapter == null) {
-            return;
-        }
-        mAdapter.notifyItemRangeChanged(0, 1);
-    }
-
-    /**
-     * Sets the list of rows for the fragment. A default {@link ClassPresenterSelector} will be
-     * created if {@link ObjectAdapter#getPresenterSelector()} is null. if user provides
-     * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)},
-     * the row and presenter will be set onto the adapter.
-     *
-     * @param adapter The adapter that contains related rows and optional playback row.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        setupRow();
-        setupPresenter();
-        setPlaybackRowPresenterAlignment();
-
-        if (mRowsFragment != null) {
-            mRowsFragment.setAdapter(adapter);
-        }
-    }
-
-    private void setupRow() {
-        if (mAdapter instanceof ArrayObjectAdapter && mRow != null) {
-            ArrayObjectAdapter adapter = ((ArrayObjectAdapter) mAdapter);
-            if (adapter.size() == 0) {
-                adapter.add(mRow);
-            } else {
-                adapter.replace(0, mRow);
-            }
-        } else if (mAdapter instanceof SparseArrayObjectAdapter && mRow != null) {
-            SparseArrayObjectAdapter adapter = ((SparseArrayObjectAdapter) mAdapter);
-            adapter.set(0, mRow);
-        }
-    }
-
-    private void setupPresenter() {
-        if (mAdapter != null && mRow != null && mPresenter != null) {
-            PresenterSelector selector = mAdapter.getPresenterSelector();
-            if (selector == null) {
-                selector = new ClassPresenterSelector();
-                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
-                mAdapter.setPresenterSelector(selector);
-            } else if (selector instanceof ClassPresenterSelector) {
-                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
-            }
-        }
-    }
-
-    final PlaybackSeekUi.Client mChainedClient = new PlaybackSeekUi.Client() {
-        @Override
-        public boolean isSeekEnabled() {
-            return mSeekUiClient == null ? false : mSeekUiClient.isSeekEnabled();
-        }
-
-        @Override
-        public void onSeekStarted() {
-            if (mSeekUiClient != null) {
-                mSeekUiClient.onSeekStarted();
-            }
-            setSeekMode(true);
-        }
-
-        @Override
-        public PlaybackSeekDataProvider getPlaybackSeekDataProvider() {
-            return mSeekUiClient == null ? null : mSeekUiClient.getPlaybackSeekDataProvider();
-        }
-
-        @Override
-        public void onSeekPositionChanged(long pos) {
-            if (mSeekUiClient != null) {
-                mSeekUiClient.onSeekPositionChanged(pos);
-            }
-        }
-
-        @Override
-        public void onSeekFinished(boolean cancelled) {
-            if (mSeekUiClient != null) {
-                mSeekUiClient.onSeekFinished(cancelled);
-            }
-            setSeekMode(false);
-        }
-    };
-
-    /**
-     * Interface to be implemented by UI widget to support PlaybackSeekUi.
-     */
-    public void setPlaybackSeekUiClient(PlaybackSeekUi.Client client) {
-        mSeekUiClient = client;
-    }
-
-    /**
-     * Show or hide other rows other than PlaybackRow.
-     * @param inSeek True to make other rows visible, false to make other rows invisible.
-     */
-    void setSeekMode(boolean inSeek) {
-        if (mInSeek == inSeek) {
-            return;
-        }
-        mInSeek = inSeek;
-        getVerticalGridView().setSelectedPosition(0);
-        if (mInSeek) {
-            stopFadeTimer();
-        }
-        // immediately fade in control row.
-        showControlsOverlay(true);
-        final int count = getVerticalGridView().getChildCount();
-        for (int i = 0; i < count; i++) {
-            View view = getVerticalGridView().getChildAt(i);
-            if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
-                view.setVisibility(mInSeek ? View.INVISIBLE : View.VISIBLE);
-            }
-        }
-    }
-
-    /**
-     * Called when size of the video changes. App may override.
-     * @param videoWidth Intrinsic width of video
-     * @param videoHeight Intrinsic height of video
-     */
-    protected void onVideoSizeChanged(int videoWidth, int videoHeight) {
-    }
-
-    /**
-     * Called when media has start or stop buffering. App may override. The default initial state
-     * is not buffering.
-     * @param start True for buffering start, false otherwise.
-     */
-    protected void onBufferingStateChanged(boolean start) {
-        ProgressBarManager progressBarManager = getProgressBarManager();
-        if (progressBarManager != null) {
-            if (start) {
-                progressBarManager.show();
-            } else {
-                progressBarManager.hide();
-            }
-        }
-    }
-
-    /**
-     * Called when media has error. App may override.
-     * @param errorCode Optional error code for specific implementation.
-     * @param errorMessage Optional error message for specific implementation.
-     */
-    protected void onError(int errorCode, CharSequence errorMessage) {
-    }
-
-    /**
-     * Returns the ProgressBarManager that will show or hide progress bar in
-     * {@link #onBufferingStateChanged(boolean)}.
-     * @return The ProgressBarManager that will show or hide progress bar in
-     * {@link #onBufferingStateChanged(boolean)}.
-     */
-    public ProgressBarManager getProgressBarManager() {
-        return mProgressBarManager;
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java b/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
deleted file mode 100644
index ee17e84..0000000
--- a/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragment.java
+++ /dev/null
@@ -1,1176 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.content.Context;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.RestrictTo;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.animation.LogAccelerateInterpolator;
-import android.support.v17.leanback.animation.LogDecelerateInterpolator;
-import android.support.v17.leanback.media.PlaybackGlueHost;
-import android.support.v17.leanback.widget.ArrayObjectAdapter;
-import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
-import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
-import android.support.v17.leanback.widget.ClassPresenterSelector;
-import android.support.v17.leanback.widget.ItemAlignmentFacet;
-import android.support.v17.leanback.widget.ItemBridgeAdapter;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.PlaybackRowPresenter;
-import android.support.v17.leanback.widget.PlaybackSeekDataProvider;
-import android.support.v17.leanback.widget.PlaybackSeekUi;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.PresenterSelector;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
-import android.support.v17.leanback.widget.VerticalGridView;
-import android.support.v4.app.Fragment;
-import android.support.v7.widget.RecyclerView;
-import android.util.Log;
-import android.view.InputEvent;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.AccelerateInterpolator;
-
-/**
- * A fragment for displaying playback controls and related content.
- *
- * <p>
- * A PlaybackSupportFragment renders the elements of its {@link ObjectAdapter} as a set
- * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
- * of {@link RowPresenter}.
- * </p>
- * <p>
- * A playback row is a row rendered by {@link PlaybackRowPresenter}.
- * App can call {@link #setPlaybackRow(Row)} to set playback row for the first element of adapter.
- * App can call {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} to set presenter for it.
- * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} are
- * optional, app can pass playback row and PlaybackRowPresenter in the adapter using
- * {@link #setAdapter(ObjectAdapter)}.
- * </p>
- * <p>
- * Auto hide controls upon playing: best practice is calling
- * {@link #setControlsOverlayAutoHideEnabled(boolean)} upon play/pause. The auto hiding timer will
- * be cancelled upon {@link #tickle()} triggered by input event.
- * </p>
- */
-public class PlaybackSupportFragment extends Fragment {
-    static final String BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW = "controlvisible_oncreateview";
-
-    /**
-     * No background.
-     */
-    public static final int BG_NONE = 0;
-
-    /**
-     * A dark translucent background.
-     */
-    public static final int BG_DARK = 1;
-    PlaybackGlueHost.HostCallback mHostCallback;
-
-    PlaybackSeekUi.Client mSeekUiClient;
-    boolean mInSeek;
-    ProgressBarManager mProgressBarManager = new ProgressBarManager();
-
-    /**
-     * Resets the focus on the button in the middle of control row.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public void resetFocus() {
-        ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView()
-                .findViewHolderForAdapterPosition(0);
-        if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
-            ((PlaybackRowPresenter) vh.getPresenter()).onReappear(
-                    (RowPresenter.ViewHolder) vh.getViewHolder());
-        }
-    }
-
-    private class SetSelectionRunnable implements Runnable {
-        int mPosition;
-        boolean mSmooth = true;
-
-        @Override
-        public void run() {
-            if (mRowsSupportFragment == null) {
-                return;
-            }
-            mRowsSupportFragment.setSelectedPosition(mPosition, mSmooth);
-        }
-    }
-
-    /**
-     * A light translucent background.
-     */
-    public static final int BG_LIGHT = 2;
-    RowsSupportFragment mRowsSupportFragment;
-    ObjectAdapter mAdapter;
-    PlaybackRowPresenter mPresenter;
-    Row mRow;
-    BaseOnItemViewSelectedListener mExternalItemSelectedListener;
-    BaseOnItemViewClickedListener mExternalItemClickedListener;
-    BaseOnItemViewClickedListener mPlaybackItemClickedListener;
-
-    private final BaseOnItemViewClickedListener mOnItemViewClickedListener =
-            new BaseOnItemViewClickedListener() {
-                @Override
-                public void onItemClicked(Presenter.ViewHolder itemViewHolder,
-                                          Object item,
-                                          RowPresenter.ViewHolder rowViewHolder,
-                                          Object row) {
-                    if (mPlaybackItemClickedListener != null
-                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder) {
-                        mPlaybackItemClickedListener.onItemClicked(
-                                itemViewHolder, item, rowViewHolder, row);
-                    }
-                    if (mExternalItemClickedListener != null) {
-                        mExternalItemClickedListener.onItemClicked(
-                                itemViewHolder, item, rowViewHolder, row);
-                    }
-                }
-            };
-
-    private final BaseOnItemViewSelectedListener mOnItemViewSelectedListener =
-            new BaseOnItemViewSelectedListener() {
-                @Override
-                public void onItemSelected(Presenter.ViewHolder itemViewHolder,
-                                           Object item,
-                                           RowPresenter.ViewHolder rowViewHolder,
-                                           Object row) {
-                    if (mExternalItemSelectedListener != null) {
-                        mExternalItemSelectedListener.onItemSelected(
-                                itemViewHolder, item, rowViewHolder, row);
-                    }
-                }
-            };
-
-    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
-
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    /**
-     * Listener allowing the application to receive notification of fade in and/or fade out
-     * completion events.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public static class OnFadeCompleteListener {
-        public void onFadeInComplete() {
-        }
-
-        public void onFadeOutComplete() {
-        }
-    }
-
-    private static final String TAG = "PlaybackSupportFragment";
-    private static final boolean DEBUG = false;
-    private static final int ANIMATION_MULTIPLIER = 1;
-
-    private static int START_FADE_OUT = 1;
-
-    // Fading status
-    private static final int IDLE = 0;
-    private static final int ANIMATING = 1;
-
-    int mPaddingBottom;
-    int mOtherRowsCenterToBottom;
-    View mRootView;
-    View mBackgroundView;
-    int mBackgroundType = BG_DARK;
-    int mBgDarkColor;
-    int mBgLightColor;
-    int mShowTimeMs;
-    int mMajorFadeTranslateY, mMinorFadeTranslateY;
-    int mAnimationTranslateY;
-    OnFadeCompleteListener mFadeCompleteListener;
-    View.OnKeyListener mInputEventHandler;
-    boolean mFadingEnabled = true;
-    boolean mControlVisibleBeforeOnCreateView = true;
-    boolean mControlVisible = true;
-    int mBgAlpha;
-    ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
-    ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
-    ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
-
-    private final Animator.AnimatorListener mFadeListener =
-            new Animator.AnimatorListener() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    enableVerticalGridAnimations(false);
-                }
-
-                @Override
-                public void onAnimationRepeat(Animator animation) {
-                }
-
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                }
-
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
-                    if (mBgAlpha > 0) {
-                        enableVerticalGridAnimations(true);
-                        if (mFadeCompleteListener != null) {
-                            mFadeCompleteListener.onFadeInComplete();
-                        }
-                    } else {
-                        VerticalGridView verticalView = getVerticalGridView();
-                        // reset focus to the primary actions only if the selected row was the controls row
-                        if (verticalView != null && verticalView.getSelectedPosition() == 0) {
-                            ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder)
-                                    verticalView.findViewHolderForAdapterPosition(0);
-                            if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
-                                ((PlaybackRowPresenter)vh.getPresenter()).onReappear(
-                                        (RowPresenter.ViewHolder) vh.getViewHolder());
-                            }
-                        }
-                        if (mFadeCompleteListener != null) {
-                            mFadeCompleteListener.onFadeOutComplete();
-                        }
-                    }
-                }
-            };
-
-    public PlaybackSupportFragment() {
-        mProgressBarManager.setInitialDelay(500);
-    }
-
-    VerticalGridView getVerticalGridView() {
-        if (mRowsSupportFragment == null) {
-            return null;
-        }
-        return mRowsSupportFragment.getVerticalGridView();
-    }
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message message) {
-            if (message.what == START_FADE_OUT && mFadingEnabled) {
-                hideControlsOverlay(true);
-            }
-        }
-    };
-
-    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
-            new VerticalGridView.OnTouchInterceptListener() {
-                @Override
-                public boolean onInterceptTouchEvent(MotionEvent event) {
-                    return onInterceptInputEvent(event);
-                }
-            };
-
-    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
-            new VerticalGridView.OnKeyInterceptListener() {
-                @Override
-                public boolean onInterceptKeyEvent(KeyEvent event) {
-                    return onInterceptInputEvent(event);
-                }
-            };
-
-    private void setBgAlpha(int alpha) {
-        mBgAlpha = alpha;
-        if (mBackgroundView != null) {
-            mBackgroundView.getBackground().setAlpha(alpha);
-        }
-    }
-
-    private void enableVerticalGridAnimations(boolean enable) {
-        if (getVerticalGridView() != null) {
-            getVerticalGridView().setAnimateChildLayout(enable);
-        }
-    }
-
-    /**
-     * Enables or disables auto hiding controls overlay after a short delay fragment is resumed.
-     * If enabled and fragment is resumed, the view will fade out after a time period.
-     * {@link #tickle()} will kill the timer, next time fragment is resumed,
-     * the timer will be started again if {@link #isControlsOverlayAutoHideEnabled()} is true.
-     */
-    public void setControlsOverlayAutoHideEnabled(boolean enabled) {
-        if (DEBUG) Log.v(TAG, "setControlsOverlayAutoHideEnabled " + enabled);
-        if (enabled != mFadingEnabled) {
-            mFadingEnabled = enabled;
-            if (isResumed() && getView().hasFocus()) {
-                showControlsOverlay(true);
-                if (enabled) {
-                    // StateGraph 7->2 5->2
-                    startFadeTimer();
-                } else {
-                    // StateGraph 4->5 2->5
-                    stopFadeTimer();
-                }
-            } else {
-                // StateGraph 6->1 1->6
-            }
-        }
-    }
-
-    /**
-     * Returns true if controls will be auto hidden after a delay when fragment is resumed.
-     */
-    public boolean isControlsOverlayAutoHideEnabled() {
-        return mFadingEnabled;
-    }
-
-    /**
-     * @deprecated Uses {@link #setControlsOverlayAutoHideEnabled(boolean)}
-     */
-    @Deprecated
-    public void setFadingEnabled(boolean enabled) {
-        setControlsOverlayAutoHideEnabled(enabled);
-    }
-
-    /**
-     * @deprecated Uses {@link #isControlsOverlayAutoHideEnabled()}
-     */
-    @Deprecated
-    public boolean isFadingEnabled() {
-        return isControlsOverlayAutoHideEnabled();
-    }
-
-    /**
-     * Sets the listener to be called when fade in or out has completed.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
-        mFadeCompleteListener = listener;
-    }
-
-    /**
-     * Returns the listener to be called when fade in or out has completed.
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    public OnFadeCompleteListener getFadeCompleteListener() {
-        return mFadeCompleteListener;
-    }
-
-    /**
-     * Sets the input event handler.
-     */
-    public final void setOnKeyInterceptListener(View.OnKeyListener handler) {
-        mInputEventHandler = handler;
-    }
-
-    /**
-     * Tickles the playback controls. Fades in the view if it was faded out. {@link #tickle()} will
-     * also kill the timer created by {@link #setControlsOverlayAutoHideEnabled(boolean)}. When
-     * next time fragment is resumed, the timer will be started again if
-     * {@link #isControlsOverlayAutoHideEnabled()} is true. In most cases app does not need call
-     * this method, tickling on input events is handled by the fragment.
-     */
-    public void tickle() {
-        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
-        //StateGraph 2->4
-        stopFadeTimer();
-        showControlsOverlay(true);
-    }
-
-    private boolean onInterceptInputEvent(InputEvent event) {
-        final boolean controlsHidden = !mControlVisible;
-        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
-        boolean consumeEvent = false;
-        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
-        int keyAction = 0;
-
-        if (event instanceof KeyEvent) {
-            keyCode = ((KeyEvent) event).getKeyCode();
-            keyAction = ((KeyEvent) event).getAction();
-            if (mInputEventHandler != null) {
-                consumeEvent = mInputEventHandler.onKey(getView(), keyCode, (KeyEvent) event);
-            }
-        }
-
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_DPAD_DOWN:
-            case KeyEvent.KEYCODE_DPAD_UP:
-            case KeyEvent.KEYCODE_DPAD_LEFT:
-            case KeyEvent.KEYCODE_DPAD_RIGHT:
-                // Event may be consumed; regardless, if controls are hidden then these keys will
-                // bring up the controls.
-                if (controlsHidden) {
-                    consumeEvent = true;
-                }
-                if (keyAction == KeyEvent.ACTION_DOWN) {
-                    tickle();
-                }
-                break;
-            case KeyEvent.KEYCODE_BACK:
-            case KeyEvent.KEYCODE_ESCAPE:
-                if (mInSeek) {
-                    // when in seek, the SeekUi will handle the BACK.
-                    return false;
-                }
-                // If controls are not hidden, back will be consumed to fade
-                // them out (even if the key was consumed by the handler).
-                if (!controlsHidden) {
-                    consumeEvent = true;
-
-                    if (((KeyEvent) event).getAction() == KeyEvent.ACTION_UP) {
-                        hideControlsOverlay(true);
-                    }
-                }
-                break;
-            default:
-                if (consumeEvent) {
-                    if (keyAction == KeyEvent.ACTION_DOWN) {
-                        tickle();
-                    }
-                }
-        }
-        return consumeEvent;
-    }
-
-    @Override
-    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
-        super.onViewCreated(view, savedInstanceState);
-        // controls view are initially visible, make it invisible
-        // if app has called hideControlsOverlay() before view created.
-        mControlVisible = true;
-        if (!mControlVisibleBeforeOnCreateView) {
-            showControlsOverlay(false, false);
-            mControlVisibleBeforeOnCreateView = true;
-        }
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-
-        if (mControlVisible) {
-            //StateGraph: 6->5 1->2
-            if (mFadingEnabled) {
-                // StateGraph 1->2
-                startFadeTimer();
-            }
-        } else {
-            //StateGraph: 6->7 1->3
-        }
-        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
-        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
-        if (mHostCallback != null) {
-            mHostCallback.onHostResume();
-        }
-    }
-
-    private void stopFadeTimer() {
-        if (mHandler != null) {
-            mHandler.removeMessages(START_FADE_OUT);
-        }
-    }
-
-    private void startFadeTimer() {
-        if (mHandler != null) {
-            mHandler.removeMessages(START_FADE_OUT);
-            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
-        }
-    }
-
-    private static ValueAnimator loadAnimator(Context context, int resId) {
-        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
-        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
-        return animator;
-    }
-
-    private void loadBgAnimator() {
-        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                setBgAlpha((Integer) arg0.getAnimatedValue());
-            }
-        };
-
-        Context context = getContext();
-        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
-        mBgFadeInAnimator.addUpdateListener(listener);
-        mBgFadeInAnimator.addListener(mFadeListener);
-
-        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
-        mBgFadeOutAnimator.addUpdateListener(listener);
-        mBgFadeOutAnimator.addListener(mFadeListener);
-    }
-
-    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100, 0);
-    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100, 0);
-
-    private void loadControlRowAnimator() {
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                RecyclerView.ViewHolder vh = getVerticalGridView()
-                        .findViewHolderForAdapterPosition(0);
-                if (vh == null) {
-                    return;
-                }
-                View view = vh.itemView;
-                if (view != null) {
-                    final float fraction = (Float) arg0.getAnimatedValue();
-                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
-                    view.setAlpha(fraction);
-                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                }
-            }
-        };
-
-        Context context = getContext();
-        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mControlRowFadeInAnimator.addUpdateListener(updateListener);
-        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mControlRowFadeOutAnimator = loadAnimator(context,
-                R.animator.lb_playback_controls_fade_out);
-        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
-        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
-    }
-
-    private void loadOtherRowAnimator() {
-        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator arg0) {
-                if (getVerticalGridView() == null) {
-                    return;
-                }
-                final float fraction = (Float) arg0.getAnimatedValue();
-                final int count = getVerticalGridView().getChildCount();
-                for (int i = 0; i < count; i++) {
-                    View view = getVerticalGridView().getChildAt(i);
-                    if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
-                        view.setAlpha(fraction);
-                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
-                    }
-                }
-            }
-        };
-
-        Context context = getContext();
-        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
-        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
-
-        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
-        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
-        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
-    }
-
-    /**
-     * Fades out the playback overlay immediately.
-     * @deprecated Call {@link #hideControlsOverlay(boolean)}
-     */
-    @Deprecated
-    public void fadeOut() {
-        showControlsOverlay(false, false);
-    }
-
-    /**
-     * Show controls overlay.
-     *
-     * @param runAnimation True to run animation, false otherwise.
-     */
-    public void showControlsOverlay(boolean runAnimation) {
-        showControlsOverlay(true, runAnimation);
-    }
-
-    /**
-     * Returns true if controls overlay is visible, false otherwise.
-     *
-     * @return True if controls overlay is visible, false otherwise.
-     * @see #showControlsOverlay(boolean)
-     * @see #hideControlsOverlay(boolean)
-     */
-    public boolean isControlsOverlayVisible() {
-        return mControlVisible;
-    }
-
-    /**
-     * Hide controls overlay.
-     *
-     * @param runAnimation True to run animation, false otherwise.
-     */
-    public void hideControlsOverlay(boolean runAnimation) {
-        showControlsOverlay(false, runAnimation);
-    }
-
-    /**
-     * if first animator is still running, reverse it; otherwise start second animator.
-     */
-    static void reverseFirstOrStartSecond(ValueAnimator first, ValueAnimator second,
-            boolean runAnimation) {
-        if (first.isStarted()) {
-            first.reverse();
-            if (!runAnimation) {
-                first.end();
-            }
-        } else {
-            second.start();
-            if (!runAnimation) {
-                second.end();
-            }
-        }
-    }
-
-    /**
-     * End first or second animator if they are still running.
-     */
-    static void endAll(ValueAnimator first, ValueAnimator second) {
-        if (first.isStarted()) {
-            first.end();
-        } else if (second.isStarted()) {
-            second.end();
-        }
-    }
-
-    /**
-     * Fade in or fade out rows and background.
-     *
-     * @param show True to fade in, false to fade out.
-     * @param animation True to run animation.
-     */
-    void showControlsOverlay(boolean show, boolean animation) {
-        if (DEBUG) Log.v(TAG, "showControlsOverlay " + show);
-        if (getView() == null) {
-            mControlVisibleBeforeOnCreateView = show;
-            return;
-        }
-        // force no animation when fragment is not resumed
-        if (!isResumed()) {
-            animation = false;
-        }
-        if (show == mControlVisible) {
-            if (!animation) {
-                // End animation if needed
-                endAll(mBgFadeInAnimator, mBgFadeOutAnimator);
-                endAll(mControlRowFadeInAnimator, mControlRowFadeOutAnimator);
-                endAll(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator);
-            }
-            return;
-        }
-        // StateGraph: 7<->5 4<->3 2->3
-        mControlVisible = show;
-        if (!mControlVisible) {
-            // StateGraph 2->3
-            stopFadeTimer();
-        }
-
-        mAnimationTranslateY = (getVerticalGridView() == null
-                || getVerticalGridView().getSelectedPosition() == 0)
-                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
-
-        if (show) {
-            reverseFirstOrStartSecond(mBgFadeOutAnimator, mBgFadeInAnimator, animation);
-            reverseFirstOrStartSecond(mControlRowFadeOutAnimator, mControlRowFadeInAnimator,
-                    animation);
-            reverseFirstOrStartSecond(mOtherRowFadeOutAnimator, mOtherRowFadeInAnimator, animation);
-        } else {
-            reverseFirstOrStartSecond(mBgFadeInAnimator, mBgFadeOutAnimator, animation);
-            reverseFirstOrStartSecond(mControlRowFadeInAnimator, mControlRowFadeOutAnimator,
-                    animation);
-            reverseFirstOrStartSecond(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator, animation);
-        }
-        if (animation) {
-            getView().announceForAccessibility(getString(show
-                    ? R.string.lb_playback_controls_shown
-                    : R.string.lb_playback_controls_hidden));
-        }
-    }
-
-    /**
-     * Sets the selected row position with smooth animation.
-     */
-    public void setSelectedPosition(int position) {
-        setSelectedPosition(position, true);
-    }
-
-    /**
-     * Sets the selected row position.
-     */
-    public void setSelectedPosition(int position, boolean smooth) {
-        mSetSelectionRunnable.mPosition = position;
-        mSetSelectionRunnable.mSmooth = smooth;
-        if (getView() != null && getView().getHandler() != null) {
-            getView().getHandler().post(mSetSelectionRunnable);
-        }
-    }
-
-    private void setupChildFragmentLayout() {
-        setVerticalGridViewLayout(mRowsSupportFragment.getVerticalGridView());
-    }
-
-    void setVerticalGridViewLayout(VerticalGridView listview) {
-        if (listview == null) {
-            return;
-        }
-
-        // we set the base line of alignment to -paddingBottom
-        listview.setWindowAlignmentOffset(-mPaddingBottom);
-        listview.setWindowAlignmentOffsetPercent(
-                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-
-        // align other rows that arent the last to center of screen, since our baseline is
-        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
-        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
-        listview.setItemAlignmentOffsetPercent(50);
-
-        // Push last row to the bottom padding
-        // Padding affects alignment when last row is focused
-        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
-                listview.getPaddingRight(), mPaddingBottom);
-        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
-    }
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        mOtherRowsCenterToBottom = getResources()
-                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
-        mPaddingBottom =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
-        mBgDarkColor =
-                getResources().getColor(R.color.lb_playback_controls_background_dark);
-        mBgLightColor =
-                getResources().getColor(R.color.lb_playback_controls_background_light);
-        mShowTimeMs =
-                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
-        mMajorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
-        mMinorFadeTranslateY =
-                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
-
-        loadBgAnimator();
-        loadControlRowAnimator();
-        loadOtherRowAnimator();
-    }
-
-    /**
-     * Sets the background type.
-     *
-     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
-     */
-    public void setBackgroundType(int type) {
-        switch (type) {
-            case BG_LIGHT:
-            case BG_DARK:
-            case BG_NONE:
-                if (type != mBackgroundType) {
-                    mBackgroundType = type;
-                    updateBackground();
-                }
-                break;
-            default:
-                throw new IllegalArgumentException("Invalid background type");
-        }
-    }
-
-    /**
-     * Returns the background type.
-     */
-    public int getBackgroundType() {
-        return mBackgroundType;
-    }
-
-    private void updateBackground() {
-        if (mBackgroundView != null) {
-            int color = mBgDarkColor;
-            switch (mBackgroundType) {
-                case BG_DARK:
-                    break;
-                case BG_LIGHT:
-                    color = mBgLightColor;
-                    break;
-                case BG_NONE:
-                    color = Color.TRANSPARENT;
-                    break;
-            }
-            mBackgroundView.setBackground(new ColorDrawable(color));
-            setBgAlpha(mBgAlpha);
-        }
-    }
-
-    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
-            new ItemBridgeAdapter.AdapterListener() {
-                @Override
-                public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
-                    if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
-                    if (!mControlVisible) {
-                        if (DEBUG) Log.v(TAG, "setting alpha to 0");
-                        vh.getViewHolder().view.setAlpha(0);
-                    }
-                }
-
-                @Override
-                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
-                    Presenter.ViewHolder viewHolder = vh.getViewHolder();
-                    if (viewHolder instanceof PlaybackSeekUi) {
-                        ((PlaybackSeekUi) viewHolder).setPlaybackSeekUiClient(mChainedClient);
-                    }
-                }
-
-                @Override
-                public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
-                    if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
-                    // Reset animation state
-                    vh.getViewHolder().view.setAlpha(1f);
-                    vh.getViewHolder().view.setTranslationY(0);
-                    vh.getViewHolder().view.setAlpha(1f);
-                }
-
-                @Override
-                public void onBind(ItemBridgeAdapter.ViewHolder vh) {
-                }
-            };
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
-        mRootView = inflater.inflate(R.layout.lb_playback_fragment, container, false);
-        mBackgroundView = mRootView.findViewById(R.id.playback_fragment_background);
-        mRowsSupportFragment = (RowsSupportFragment) getChildFragmentManager().findFragmentById(
-                R.id.playback_controls_dock);
-        if (mRowsSupportFragment == null) {
-            mRowsSupportFragment = new RowsSupportFragment();
-            getChildFragmentManager().beginTransaction()
-                    .replace(R.id.playback_controls_dock, mRowsSupportFragment)
-                    .commit();
-        }
-        if (mAdapter == null) {
-            setAdapter(new ArrayObjectAdapter(new ClassPresenterSelector()));
-        } else {
-            mRowsSupportFragment.setAdapter(mAdapter);
-        }
-        mRowsSupportFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
-        mRowsSupportFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
-
-        mBgAlpha = 255;
-        updateBackground();
-        mRowsSupportFragment.setExternalAdapterListener(mAdapterListener);
-        ProgressBarManager progressBarManager = getProgressBarManager();
-        if (progressBarManager != null) {
-            progressBarManager.setRootView((ViewGroup) mRootView);
-        }
-        return mRootView;
-    }
-
-    /**
-     * Sets the {@link PlaybackGlueHost.HostCallback}. Implementor of this interface will
-     * take appropriate actions to take action when the hosting fragment starts/stops processing.
-     */
-    public void setHostCallback(PlaybackGlueHost.HostCallback hostCallback) {
-        this.mHostCallback = hostCallback;
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        setupChildFragmentLayout();
-        mRowsSupportFragment.setAdapter(mAdapter);
-        if (mHostCallback != null) {
-            mHostCallback.onHostStart();
-        }
-    }
-
-    @Override
-    public void onStop() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostStop();
-        }
-        super.onStop();
-    }
-
-    @Override
-    public void onPause() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostPause();
-        }
-        if (mHandler.hasMessages(START_FADE_OUT)) {
-            // StateGraph: 2->1
-            mHandler.removeMessages(START_FADE_OUT);
-        } else {
-            // StateGraph: 5->6, 7->6, 4->1, 3->1
-        }
-        super.onPause();
-    }
-
-    /**
-     * This listener is called every time there is a selection in {@link RowsSupportFragment}. This can
-     * be used by users to take additional actions such as animations.
-     */
-    public void setOnItemViewSelectedListener(final BaseOnItemViewSelectedListener listener) {
-        mExternalItemSelectedListener = listener;
-    }
-
-    /**
-     * This listener is called every time there is a click in {@link RowsSupportFragment}. This can
-     * be used by users to take additional actions such as animations.
-     */
-    public void setOnItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
-        mExternalItemClickedListener = listener;
-    }
-
-    /**
-     * Sets the {@link BaseOnItemViewClickedListener} that would be invoked for clicks
-     * only on {@link android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder}.
-     */
-    public void setOnPlaybackItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
-        mPlaybackItemClickedListener = listener;
-    }
-
-    @Override
-    public void onDestroyView() {
-        mRootView = null;
-        mBackgroundView = null;
-        super.onDestroyView();
-    }
-
-    @Override
-    public void onDestroy() {
-        if (mHostCallback != null) {
-            mHostCallback.onHostDestroy();
-        }
-        super.onDestroy();
-    }
-
-    /**
-     * Sets the playback row for the playback controls. The row will be set as first element
-     * of adapter if the adapter is {@link ArrayObjectAdapter} or {@link SparseArrayObjectAdapter}.
-     * @param row The row that represents the playback.
-     */
-    public void setPlaybackRow(Row row) {
-        this.mRow = row;
-        setupRow();
-        setupPresenter();
-    }
-
-    /**
-     * Sets the presenter for rendering the playback row set by {@link #setPlaybackRow(Row)}. If
-     * adapter does not set a {@link PresenterSelector}, {@link #setAdapter(ObjectAdapter)} will
-     * create a {@link ClassPresenterSelector} by default and map from the row object class to this
-     * {@link PlaybackRowPresenter}.
-     *
-     * @param  presenter Presenter used to render {@link #setPlaybackRow(Row)}.
-     */
-    public void setPlaybackRowPresenter(PlaybackRowPresenter presenter) {
-        this.mPresenter = presenter;
-        setupPresenter();
-        setPlaybackRowPresenterAlignment();
-    }
-
-    void setPlaybackRowPresenterAlignment() {
-        if (mAdapter != null && mAdapter.getPresenterSelector() != null) {
-            Presenter[] presenters = mAdapter.getPresenterSelector().getPresenters();
-            if (presenters != null) {
-                for (int i = 0; i < presenters.length; i++) {
-                    if (presenters[i] instanceof PlaybackRowPresenter
-                            && presenters[i].getFacet(ItemAlignmentFacet.class) == null) {
-                        ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
-                        ItemAlignmentFacet.ItemAlignmentDef def =
-                                new ItemAlignmentFacet.ItemAlignmentDef();
-                        def.setItemAlignmentOffset(0);
-                        def.setItemAlignmentOffsetPercent(100);
-                        itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
-                                {def});
-                        presenters[i].setFacet(ItemAlignmentFacet.class, itemAlignment);
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Updates the ui when the row data changes.
-     */
-    public void notifyPlaybackRowChanged() {
-        if (mAdapter == null) {
-            return;
-        }
-        mAdapter.notifyItemRangeChanged(0, 1);
-    }
-
-    /**
-     * Sets the list of rows for the fragment. A default {@link ClassPresenterSelector} will be
-     * created if {@link ObjectAdapter#getPresenterSelector()} is null. if user provides
-     * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)},
-     * the row and presenter will be set onto the adapter.
-     *
-     * @param adapter The adapter that contains related rows and optional playback row.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        setupRow();
-        setupPresenter();
-        setPlaybackRowPresenterAlignment();
-
-        if (mRowsSupportFragment != null) {
-            mRowsSupportFragment.setAdapter(adapter);
-        }
-    }
-
-    private void setupRow() {
-        if (mAdapter instanceof ArrayObjectAdapter && mRow != null) {
-            ArrayObjectAdapter adapter = ((ArrayObjectAdapter) mAdapter);
-            if (adapter.size() == 0) {
-                adapter.add(mRow);
-            } else {
-                adapter.replace(0, mRow);
-            }
-        } else if (mAdapter instanceof SparseArrayObjectAdapter && mRow != null) {
-            SparseArrayObjectAdapter adapter = ((SparseArrayObjectAdapter) mAdapter);
-            adapter.set(0, mRow);
-        }
-    }
-
-    private void setupPresenter() {
-        if (mAdapter != null && mRow != null && mPresenter != null) {
-            PresenterSelector selector = mAdapter.getPresenterSelector();
-            if (selector == null) {
-                selector = new ClassPresenterSelector();
-                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
-                mAdapter.setPresenterSelector(selector);
-            } else if (selector instanceof ClassPresenterSelector) {
-                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
-            }
-        }
-    }
-
-    final PlaybackSeekUi.Client mChainedClient = new PlaybackSeekUi.Client() {
-        @Override
-        public boolean isSeekEnabled() {
-            return mSeekUiClient == null ? false : mSeekUiClient.isSeekEnabled();
-        }
-
-        @Override
-        public void onSeekStarted() {
-            if (mSeekUiClient != null) {
-                mSeekUiClient.onSeekStarted();
-            }
-            setSeekMode(true);
-        }
-
-        @Override
-        public PlaybackSeekDataProvider getPlaybackSeekDataProvider() {
-            return mSeekUiClient == null ? null : mSeekUiClient.getPlaybackSeekDataProvider();
-        }
-
-        @Override
-        public void onSeekPositionChanged(long pos) {
-            if (mSeekUiClient != null) {
-                mSeekUiClient.onSeekPositionChanged(pos);
-            }
-        }
-
-        @Override
-        public void onSeekFinished(boolean cancelled) {
-            if (mSeekUiClient != null) {
-                mSeekUiClient.onSeekFinished(cancelled);
-            }
-            setSeekMode(false);
-        }
-    };
-
-    /**
-     * Interface to be implemented by UI widget to support PlaybackSeekUi.
-     */
-    public void setPlaybackSeekUiClient(PlaybackSeekUi.Client client) {
-        mSeekUiClient = client;
-    }
-
-    /**
-     * Show or hide other rows other than PlaybackRow.
-     * @param inSeek True to make other rows visible, false to make other rows invisible.
-     */
-    void setSeekMode(boolean inSeek) {
-        if (mInSeek == inSeek) {
-            return;
-        }
-        mInSeek = inSeek;
-        getVerticalGridView().setSelectedPosition(0);
-        if (mInSeek) {
-            stopFadeTimer();
-        }
-        // immediately fade in control row.
-        showControlsOverlay(true);
-        final int count = getVerticalGridView().getChildCount();
-        for (int i = 0; i < count; i++) {
-            View view = getVerticalGridView().getChildAt(i);
-            if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
-                view.setVisibility(mInSeek ? View.INVISIBLE : View.VISIBLE);
-            }
-        }
-    }
-
-    /**
-     * Called when size of the video changes. App may override.
-     * @param videoWidth Intrinsic width of video
-     * @param videoHeight Intrinsic height of video
-     */
-    protected void onVideoSizeChanged(int videoWidth, int videoHeight) {
-    }
-
-    /**
-     * Called when media has start or stop buffering. App may override. The default initial state
-     * is not buffering.
-     * @param start True for buffering start, false otherwise.
-     */
-    protected void onBufferingStateChanged(boolean start) {
-        ProgressBarManager progressBarManager = getProgressBarManager();
-        if (progressBarManager != null) {
-            if (start) {
-                progressBarManager.show();
-            } else {
-                progressBarManager.hide();
-            }
-        }
-    }
-
-    /**
-     * Called when media has error. App may override.
-     * @param errorCode Optional error code for specific implementation.
-     * @param errorMessage Optional error message for specific implementation.
-     */
-    protected void onError(int errorCode, CharSequence errorMessage) {
-    }
-
-    /**
-     * Returns the ProgressBarManager that will show or hide progress bar in
-     * {@link #onBufferingStateChanged(boolean)}.
-     * @return The ProgressBarManager that will show or hide progress bar in
-     * {@link #onBufferingStateChanged(boolean)}.
-     */
-    public ProgressBarManager getProgressBarManager() {
-        return mProgressBarManager;
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java b/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
deleted file mode 100644
index bff3dba..0000000
--- a/leanback/src/android/support/v17/leanback/app/VerticalGridFragment.java
+++ /dev/null
@@ -1,260 +0,0 @@
-// CHECKSTYLE:OFF Generated code
-/* This file is auto-generated from VerticalGridSupportFragment.java.  DO NOT MODIFY. */
-
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.os.Bundle;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.util.StateMachine.State;
-import android.support.v17.leanback.widget.BrowseFrameLayout;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.OnChildLaidOutListener;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridPresenter;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * A fragment for creating leanback vertical grids.
- *
- * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
- * an {@link ObjectAdapter}.
- * @deprecated use {@link VerticalGridSupportFragment}
- */
-@Deprecated
-public class VerticalGridFragment extends BaseFragment {
-    static final String TAG = "VerticalGF";
-    static boolean DEBUG = false;
-
-    private ObjectAdapter mAdapter;
-    private VerticalGridPresenter mGridPresenter;
-    VerticalGridPresenter.ViewHolder mGridViewHolder;
-    OnItemViewSelectedListener mOnItemViewSelectedListener;
-    private OnItemViewClickedListener mOnItemViewClickedListener;
-    private Object mSceneAfterEntranceTransition;
-    private int mSelectedPosition = -1;
-
-    /**
-     * State to setEntranceTransitionState(false)
-     */
-    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
-        @Override
-        public void run() {
-            setEntranceTransitionState(false);
-        }
-    };
-
-    @Override
-    void createStateMachineStates() {
-        super.createStateMachineStates();
-        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
-    }
-
-    @Override
-    void createStateMachineTransitions() {
-        super.createStateMachineTransitions();
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
-                STATE_SET_ENTRANCE_START_STATE, EVT_ON_CREATEVIEW);
-    }
-
-    /**
-     * Sets the grid presenter.
-     */
-    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
-        if (gridPresenter == null) {
-            throw new IllegalArgumentException("Grid presenter may not be null");
-        }
-        mGridPresenter = gridPresenter;
-        mGridPresenter.setOnItemViewSelectedListener(mViewSelectedListener);
-        if (mOnItemViewClickedListener != null) {
-            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
-    }
-
-    /**
-     * Returns the grid presenter.
-     */
-    public VerticalGridPresenter getGridPresenter() {
-        return mGridPresenter;
-    }
-
-    /**
-     * Sets the object adapter for the fragment.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        updateAdapter();
-    }
-
-    /**
-     * Returns the object adapter.
-     */
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    final private OnItemViewSelectedListener mViewSelectedListener =
-            new OnItemViewSelectedListener() {
-        @Override
-        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                RowPresenter.ViewHolder rowViewHolder, Row row) {
-            int position = mGridViewHolder.getGridView().getSelectedPosition();
-            if (DEBUG) Log.v(TAG, "grid selected position " + position);
-            gridOnItemSelected(position);
-            if (mOnItemViewSelectedListener != null) {
-                mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
-                        rowViewHolder, row);
-            }
-        }
-    };
-
-    final private OnChildLaidOutListener mChildLaidOutListener =
-            new OnChildLaidOutListener() {
-        @Override
-        public void onChildLaidOut(ViewGroup parent, View view, int position, long id) {
-            if (position == 0) {
-                showOrHideTitle();
-            }
-        }
-    };
-
-    /**
-     * Sets an item selection listener.
-     */
-    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
-        mOnItemViewSelectedListener = listener;
-    }
-
-    void gridOnItemSelected(int position) {
-        if (position != mSelectedPosition) {
-            mSelectedPosition = position;
-            showOrHideTitle();
-        }
-    }
-
-    void showOrHideTitle() {
-        if (mGridViewHolder.getGridView().findViewHolderForAdapterPosition(mSelectedPosition)
-                == null) {
-            return;
-        }
-        if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(mSelectedPosition)) {
-            showTitle(true);
-        } else {
-            showTitle(false);
-        }
-    }
-
-    /**
-     * Sets an item clicked listener.
-     */
-    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        mOnItemViewClickedListener = listener;
-        if (mGridPresenter != null) {
-            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
-    }
-
-    /**
-     * Returns the item clicked listener.
-     */
-    public OnItemViewClickedListener getOnItemViewClickedListener() {
-        return mOnItemViewClickedListener;
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
-                container, false);
-        ViewGroup gridFrame = (ViewGroup) root.findViewById(R.id.grid_frame);
-        installTitleView(inflater, gridFrame, savedInstanceState);
-        getProgressBarManager().setRootView(root);
-
-        ViewGroup gridDock = (ViewGroup) root.findViewById(R.id.browse_grid_dock);
-        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
-        gridDock.addView(mGridViewHolder.view);
-        mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
-
-        mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
-            @Override
-            public void run() {
-                setEntranceTransitionState(true);
-            }
-        });
-
-        updateAdapter();
-        return root;
-    }
-
-    private void setupFocusSearchListener() {
-        BrowseFrameLayout browseFrameLayout = (BrowseFrameLayout) getView().findViewById(
-                R.id.grid_frame);
-        browseFrameLayout.setOnFocusSearchListener(getTitleHelper().getOnFocusSearchListener());
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        setupFocusSearchListener();
-    }
-
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-        mGridViewHolder = null;
-    }
-
-    /**
-     * Sets the selected item position.
-     */
-    public void setSelectedPosition(int position) {
-        mSelectedPosition = position;
-        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
-            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
-        }
-    }
-
-    private void updateAdapter() {
-        if (mGridViewHolder != null) {
-            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
-            if (mSelectedPosition != -1) {
-                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
-            }
-        }
-    }
-
-    @Override
-    protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(FragmentUtil.getContext(VerticalGridFragment.this),
-                R.transition.lb_vertical_grid_entrance_transition);
-    }
-
-    @Override
-    protected void runEntranceTransition(Object entranceTransition) {
-        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
-    }
-
-    void setEntranceTransitionState(boolean afterTransition) {
-        mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java b/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
deleted file mode 100644
index 4cfe981..0000000
--- a/leanback/src/android/support/v17/leanback/app/VerticalGridSupportFragment.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.app;
-
-import android.os.Bundle;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.util.StateMachine.State;
-import android.support.v17.leanback.widget.BrowseFrameLayout;
-import android.support.v17.leanback.widget.ObjectAdapter;
-import android.support.v17.leanback.widget.OnChildLaidOutListener;
-import android.support.v17.leanback.widget.OnItemViewClickedListener;
-import android.support.v17.leanback.widget.OnItemViewSelectedListener;
-import android.support.v17.leanback.widget.Presenter;
-import android.support.v17.leanback.widget.Row;
-import android.support.v17.leanback.widget.RowPresenter;
-import android.support.v17.leanback.widget.VerticalGridPresenter;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * A fragment for creating leanback vertical grids.
- *
- * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
- * an {@link ObjectAdapter}.
- */
-public class VerticalGridSupportFragment extends BaseSupportFragment {
-    static final String TAG = "VerticalGF";
-    static boolean DEBUG = false;
-
-    private ObjectAdapter mAdapter;
-    private VerticalGridPresenter mGridPresenter;
-    VerticalGridPresenter.ViewHolder mGridViewHolder;
-    OnItemViewSelectedListener mOnItemViewSelectedListener;
-    private OnItemViewClickedListener mOnItemViewClickedListener;
-    private Object mSceneAfterEntranceTransition;
-    private int mSelectedPosition = -1;
-
-    /**
-     * State to setEntranceTransitionState(false)
-     */
-    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
-        @Override
-        public void run() {
-            setEntranceTransitionState(false);
-        }
-    };
-
-    @Override
-    void createStateMachineStates() {
-        super.createStateMachineStates();
-        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
-    }
-
-    @Override
-    void createStateMachineTransitions() {
-        super.createStateMachineTransitions();
-        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
-                STATE_SET_ENTRANCE_START_STATE, EVT_ON_CREATEVIEW);
-    }
-
-    /**
-     * Sets the grid presenter.
-     */
-    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
-        if (gridPresenter == null) {
-            throw new IllegalArgumentException("Grid presenter may not be null");
-        }
-        mGridPresenter = gridPresenter;
-        mGridPresenter.setOnItemViewSelectedListener(mViewSelectedListener);
-        if (mOnItemViewClickedListener != null) {
-            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
-    }
-
-    /**
-     * Returns the grid presenter.
-     */
-    public VerticalGridPresenter getGridPresenter() {
-        return mGridPresenter;
-    }
-
-    /**
-     * Sets the object adapter for the fragment.
-     */
-    public void setAdapter(ObjectAdapter adapter) {
-        mAdapter = adapter;
-        updateAdapter();
-    }
-
-    /**
-     * Returns the object adapter.
-     */
-    public ObjectAdapter getAdapter() {
-        return mAdapter;
-    }
-
-    final private OnItemViewSelectedListener mViewSelectedListener =
-            new OnItemViewSelectedListener() {
-        @Override
-        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
-                RowPresenter.ViewHolder rowViewHolder, Row row) {
-            int position = mGridViewHolder.getGridView().getSelectedPosition();
-            if (DEBUG) Log.v(TAG, "grid selected position " + position);
-            gridOnItemSelected(position);
-            if (mOnItemViewSelectedListener != null) {
-                mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
-                        rowViewHolder, row);
-            }
-        }
-    };
-
-    final private OnChildLaidOutListener mChildLaidOutListener =
-            new OnChildLaidOutListener() {
-        @Override
-        public void onChildLaidOut(ViewGroup parent, View view, int position, long id) {
-            if (position == 0) {
-                showOrHideTitle();
-            }
-        }
-    };
-
-    /**
-     * Sets an item selection listener.
-     */
-    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
-        mOnItemViewSelectedListener = listener;
-    }
-
-    void gridOnItemSelected(int position) {
-        if (position != mSelectedPosition) {
-            mSelectedPosition = position;
-            showOrHideTitle();
-        }
-    }
-
-    void showOrHideTitle() {
-        if (mGridViewHolder.getGridView().findViewHolderForAdapterPosition(mSelectedPosition)
-                == null) {
-            return;
-        }
-        if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(mSelectedPosition)) {
-            showTitle(true);
-        } else {
-            showTitle(false);
-        }
-    }
-
-    /**
-     * Sets an item clicked listener.
-     */
-    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
-        mOnItemViewClickedListener = listener;
-        if (mGridPresenter != null) {
-            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
-        }
-    }
-
-    /**
-     * Returns the item clicked listener.
-     */
-    public OnItemViewClickedListener getOnItemViewClickedListener() {
-        return mOnItemViewClickedListener;
-    }
-
-    @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
-        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
-                container, false);
-        ViewGroup gridFrame = (ViewGroup) root.findViewById(R.id.grid_frame);
-        installTitleView(inflater, gridFrame, savedInstanceState);
-        getProgressBarManager().setRootView(root);
-
-        ViewGroup gridDock = (ViewGroup) root.findViewById(R.id.browse_grid_dock);
-        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
-        gridDock.addView(mGridViewHolder.view);
-        mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
-
-        mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
-            @Override
-            public void run() {
-                setEntranceTransitionState(true);
-            }
-        });
-
-        updateAdapter();
-        return root;
-    }
-
-    private void setupFocusSearchListener() {
-        BrowseFrameLayout browseFrameLayout = (BrowseFrameLayout) getView().findViewById(
-                R.id.grid_frame);
-        browseFrameLayout.setOnFocusSearchListener(getTitleHelper().getOnFocusSearchListener());
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-        setupFocusSearchListener();
-    }
-
-    @Override
-    public void onDestroyView() {
-        super.onDestroyView();
-        mGridViewHolder = null;
-    }
-
-    /**
-     * Sets the selected item position.
-     */
-    public void setSelectedPosition(int position) {
-        mSelectedPosition = position;
-        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
-            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
-        }
-    }
-
-    private void updateAdapter() {
-        if (mGridViewHolder != null) {
-            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
-            if (mSelectedPosition != -1) {
-                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
-            }
-        }
-    }
-
-    @Override
-    protected Object createEntranceTransition() {
-        return TransitionHelper.loadTransition(getContext(),
-                R.transition.lb_vertical_grid_entrance_transition);
-    }
-
-    @Override
-    protected void runEntranceTransition(Object entranceTransition) {
-        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
-    }
-
-    void setEntranceTransitionState(boolean afterTransition) {
-        mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/util/StateMachine.java b/leanback/src/android/support/v17/leanback/util/StateMachine.java
deleted file mode 100644
index dfc228c..0000000
--- a/leanback/src/android/support/v17/leanback/util/StateMachine.java
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.util;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.support.annotation.RestrictTo;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-/**
- * State: each State has incoming Transitions and outgoing Transitions.
- * When {@link State#mBranchStart} is true, all the outgoing Transitions may be triggered, when
- * {@link State#mBranchStart} is false, only first outgoing Transition will be triggered.
- * When {@link State#mBranchEnd} is true, all the incoming Transitions must be triggered for the
- * State to run. When {@link State#mBranchEnd} is false, only need one incoming Transition triggered
- * for the State to run.
- * Transition: three types:
- * 1. Event based transition, transition will be triggered when {@link #fireEvent(Event)} is called.
- * 2. Auto transition, transition will be triggered when {@link Transition#mFromState} is executed.
- * 3. Condiitonal Auto transition, transition will be triggered when {@link Transition#mFromState}
- * is executed and {@link Transition#mCondition} passes.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public final class StateMachine {
-
-    static boolean DEBUG = false;
-    static final String TAG = "StateMachine";
-
-    /**
-     * No request on the State
-     */
-    public static final int STATUS_ZERO = 0;
-
-    /**
-     * Has been executed
-     */
-    public static final int STATUS_INVOKED = 1;
-
-    /**
-     * Used in Transition
-     */
-    public static class Event {
-        final String mName;
-
-        public Event(String name) {
-            mName = name;
-        }
-    }
-
-    /**
-     * Used in transition
-     */
-    public static class Condition {
-        final String mName;
-
-        public Condition(String name) {
-            mName = name;
-        }
-
-        /**
-         * @return True if can proceed and mark the transition INVOKED
-         */
-        public boolean canProceed() {
-            return true;
-        }
-    }
-
-    static class Transition {
-        final State mFromState;
-        final State mToState;
-        final Event mEvent;
-        final Condition mCondition;
-        int mState = STATUS_ZERO;
-
-        Transition(State fromState, State toState, Event event) {
-            if (event == null) {
-                throw new IllegalArgumentException();
-            }
-            mFromState = fromState;
-            mToState = toState;
-            mEvent = event;
-            mCondition = null;
-        }
-
-        Transition(State fromState, State toState) {
-            mFromState = fromState;
-            mToState = toState;
-            mEvent = null;
-            mCondition = null;
-        }
-
-        Transition(State fromState, State toState, Condition condition) {
-            if (condition == null) {
-                throw new IllegalArgumentException();
-            }
-            mFromState = fromState;
-            mToState = toState;
-            mEvent = null;
-            mCondition = condition;
-        }
-
-        @Override
-        public String toString() {
-            String signalName;
-            if (mEvent != null) {
-                signalName = mEvent.mName;
-            } else if (mCondition != null) {
-                signalName = mCondition.mName;
-            } else {
-                signalName = "auto";
-            }
-            return "[" + mFromState.mName + " -> " + mToState.mName + " <"
-                    + signalName + ">]";
-        }
-    }
-
-    /**
-     * @see StateMachine
-     */
-    public static class State {
-
-        final String mName;
-        final boolean mBranchStart;
-        final boolean mBranchEnd;
-        int mStatus = STATUS_ZERO;
-        int mInvokedOutTransitions = 0;
-        ArrayList<Transition> mIncomings;
-        ArrayList<Transition> mOutgoings;
-
-        @Override
-        public String toString() {
-            return "[" + mName + " " + mStatus + "]";
-        }
-
-        /**
-         * Create a State which is not branch start and a branch end.
-         */
-        public State(String name) {
-            this(name, false, true);
-        }
-
-        /**
-         * Create a State
-         * @param branchStart True if can run all out going transitions or false execute the first
-         *                    out going transition.
-         * @param branchEnd True if wait all incoming transitions executed or false
-         *                              only need one of the transition executed.
-         */
-        public State(String name, boolean branchStart, boolean branchEnd) {
-            mName = name;
-            mBranchStart = branchStart;
-            mBranchEnd = branchEnd;
-        }
-
-        void addIncoming(Transition t) {
-            if (mIncomings == null) {
-                mIncomings = new ArrayList();
-            }
-            mIncomings.add(t);
-        }
-
-        void addOutgoing(Transition t) {
-            if (mOutgoings == null) {
-                mOutgoings = new ArrayList();
-            }
-            mOutgoings.add(t);
-        }
-
-        /**
-         * Run State, Subclass may override.
-         */
-        public void run() {
-        }
-
-        final boolean checkPreCondition() {
-            if (mIncomings == null) {
-                return true;
-            }
-            if (mBranchEnd) {
-                for (Transition t: mIncomings) {
-                    if (t.mState != STATUS_INVOKED) {
-                        return false;
-                    }
-                }
-                return true;
-            } else {
-                for (Transition t: mIncomings) {
-                    if (t.mState == STATUS_INVOKED) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-        }
-
-        /**
-         * @return True if the State has been executed.
-         */
-        final boolean runIfNeeded() {
-            if (mStatus != STATUS_INVOKED) {
-                if (checkPreCondition()) {
-                    if (DEBUG) {
-                        Log.d(TAG, "execute " + this);
-                    }
-                    mStatus = STATUS_INVOKED;
-                    run();
-                    signalAutoTransitionsAfterRun();
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        final void signalAutoTransitionsAfterRun() {
-            if (mOutgoings != null) {
-                for (Transition t: mOutgoings) {
-                    if (t.mEvent == null) {
-                        if (t.mCondition == null || t.mCondition.canProceed()) {
-                            if (DEBUG) {
-                                Log.d(TAG, "signal " + t);
-                            }
-                            mInvokedOutTransitions++;
-                            t.mState = STATUS_INVOKED;
-                            if (!mBranchStart) {
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        /**
-         * Get status, return one of {@link #STATUS_ZERO}, {@link #STATUS_INVOKED}.
-         * @return Status of the State.
-         */
-        public final int getStatus() {
-            return mStatus;
-        }
-    }
-
-    final ArrayList<State> mStates = new ArrayList<State>();
-    final ArrayList<State> mFinishedStates = new ArrayList();
-    final ArrayList<State> mUnfinishedStates = new ArrayList();
-
-    public StateMachine() {
-    }
-
-    /**
-     * Add a State to StateMachine, ignore if it is already added.
-     * @param state The state to add.
-     */
-    public void addState(State state) {
-        if (!mStates.contains(state)) {
-            mStates.add(state);
-        }
-    }
-
-    /**
-     * Add event-triggered transition between two states.
-     * @param fromState The from state.
-     * @param toState The to state.
-     * @param event The event that needed to perform the transition.
-     */
-    public void addTransition(State fromState, State toState, Event event) {
-        Transition transition = new Transition(fromState, toState, event);
-        toState.addIncoming(transition);
-        fromState.addOutgoing(transition);
-    }
-
-    /**
-     * Add a conditional auto transition between two states.
-     * @param fromState The from state.
-     * @param toState The to state.
-     */
-    public void addTransition(State fromState, State toState, Condition condition) {
-        Transition transition = new Transition(fromState, toState, condition);
-        toState.addIncoming(transition);
-        fromState.addOutgoing(transition);
-    }
-
-    /**
-     * Add an auto transition between two states.
-     * @param fromState The from state to add.
-     * @param toState The to state to add.
-     */
-    public void addTransition(State fromState, State toState) {
-        Transition transition = new Transition(fromState, toState);
-        toState.addIncoming(transition);
-        fromState.addOutgoing(transition);
-    }
-
-    /**
-     * Start the state machine.
-     */
-    public void start() {
-        if (DEBUG) {
-            Log.d(TAG, "start");
-        }
-        mUnfinishedStates.addAll(mStates);
-        runUnfinishedStates();
-    }
-
-    void runUnfinishedStates() {
-        boolean changed;
-        do {
-            changed = false;
-            for (int i = mUnfinishedStates.size() - 1; i >= 0; i--) {
-                State state = mUnfinishedStates.get(i);
-                if (state.runIfNeeded()) {
-                    mUnfinishedStates.remove(i);
-                    mFinishedStates.add(state);
-                    changed = true;
-                }
-            }
-        } while (changed);
-    }
-
-    /**
-     * Find outgoing Transitions of invoked State whose Event matches, mark the Transition invoked.
-     */
-    public void fireEvent(Event event) {
-        for (int i = 0; i < mFinishedStates.size(); i++) {
-            State state = mFinishedStates.get(i);
-            if (state.mOutgoings != null) {
-                if (!state.mBranchStart && state.mInvokedOutTransitions > 0) {
-                    continue;
-                }
-                for (Transition t : state.mOutgoings) {
-                    if (t.mState != STATUS_INVOKED && t.mEvent == event) {
-                        if (DEBUG) {
-                            Log.d(TAG, "signal " + t);
-                        }
-                        t.mState = STATUS_INVOKED;
-                        state.mInvokedOutTransitions++;
-                        if (!state.mBranchStart) {
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-        runUnfinishedStates();
-    }
-
-    /**
-     * Reset status to orignal status
-     */
-    public void reset() {
-        if (DEBUG) {
-            Log.d(TAG, "reset");
-        }
-        mUnfinishedStates.clear();
-        mFinishedStates.clear();
-        for (State state: mStates) {
-            state.mStatus = STATUS_ZERO;
-            state.mInvokedOutTransitions = 0;
-            if (state.mOutgoings != null) {
-                for (Transition t: state.mOutgoings) {
-                    t.mState = STATUS_ZERO;
-                }
-            }
-        }
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
deleted file mode 100644
index d360d15..0000000
--- a/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ /dev/null
@@ -1,3833 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.widget;
-
-import static android.support.v7.widget.RecyclerView.HORIZONTAL;
-import static android.support.v7.widget.RecyclerView.NO_ID;
-import static android.support.v7.widget.RecyclerView.NO_POSITION;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static android.support.v7.widget.RecyclerView.VERTICAL;
-
-import android.content.Context;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.os.TraceCompat;
-import android.support.v4.util.CircularIntArray;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.widget.LinearSmoothScroller;
-import android.support.v7.widget.OrientationHelper;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Recycler;
-import android.support.v7.widget.RecyclerView.State;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.SparseIntArray;
-import android.view.FocusFinder;
-import android.view.Gravity;
-import android.view.View;
-import android.view.View.MeasureSpec;
-import android.view.ViewGroup;
-import android.view.ViewGroup.MarginLayoutParams;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-final class GridLayoutManager extends RecyclerView.LayoutManager {
-
-    /*
-     * LayoutParams for {@link HorizontalGridView} and {@link VerticalGridView}.
-     * The class currently does two internal jobs:
-     * - Saves optical bounds insets.
-     * - Caches focus align view center.
-     */
-    final static class LayoutParams extends RecyclerView.LayoutParams {
-
-        // For placement
-        int mLeftInset;
-        int mTopInset;
-        int mRightInset;
-        int mBottomInset;
-
-        // For alignment
-        private int mAlignX;
-        private int mAlignY;
-        private int[] mAlignMultiple;
-        private ItemAlignmentFacet mAlignmentFacet;
-
-        public LayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-        }
-
-        public LayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public LayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(RecyclerView.LayoutParams source) {
-            super(source);
-        }
-
-        public LayoutParams(LayoutParams source) {
-            super(source);
-        }
-
-        int getAlignX() {
-            return mAlignX;
-        }
-
-        int getAlignY() {
-            return mAlignY;
-        }
-
-        int getOpticalLeft(View view) {
-            return view.getLeft() + mLeftInset;
-        }
-
-        int getOpticalTop(View view) {
-            return view.getTop() + mTopInset;
-        }
-
-        int getOpticalRight(View view) {
-            return view.getRight() - mRightInset;
-        }
-
-        int getOpticalBottom(View view) {
-            return view.getBottom() - mBottomInset;
-        }
-
-        int getOpticalWidth(View view) {
-            return view.getWidth() - mLeftInset - mRightInset;
-        }
-
-        int getOpticalHeight(View view) {
-            return view.getHeight() - mTopInset - mBottomInset;
-        }
-
-        int getOpticalLeftInset() {
-            return mLeftInset;
-        }
-
-        int getOpticalRightInset() {
-            return mRightInset;
-        }
-
-        int getOpticalTopInset() {
-            return mTopInset;
-        }
-
-        int getOpticalBottomInset() {
-            return mBottomInset;
-        }
-
-        void setAlignX(int alignX) {
-            mAlignX = alignX;
-        }
-
-        void setAlignY(int alignY) {
-            mAlignY = alignY;
-        }
-
-        void setItemAlignmentFacet(ItemAlignmentFacet facet) {
-            mAlignmentFacet = facet;
-        }
-
-        ItemAlignmentFacet getItemAlignmentFacet() {
-            return mAlignmentFacet;
-        }
-
-        void calculateItemAlignments(int orientation, View view) {
-            ItemAlignmentFacet.ItemAlignmentDef[] defs = mAlignmentFacet.getAlignmentDefs();
-            if (mAlignMultiple == null || mAlignMultiple.length != defs.length) {
-                mAlignMultiple = new int[defs.length];
-            }
-            for (int i = 0; i < defs.length; i++) {
-                mAlignMultiple[i] = ItemAlignmentFacetHelper
-                        .getAlignmentPosition(view, defs[i], orientation);
-            }
-            if (orientation == HORIZONTAL) {
-                mAlignX = mAlignMultiple[0];
-            } else {
-                mAlignY = mAlignMultiple[0];
-            }
-        }
-
-        int[] getAlignMultiple() {
-            return mAlignMultiple;
-        }
-
-        void setOpticalInsets(int leftInset, int topInset, int rightInset, int bottomInset) {
-            mLeftInset = leftInset;
-            mTopInset = topInset;
-            mRightInset = rightInset;
-            mBottomInset = bottomInset;
-        }
-
-    }
-
-    /**
-     * Base class which scrolls to selected view in onStop().
-     */
-    abstract class GridLinearSmoothScroller extends LinearSmoothScroller {
-        GridLinearSmoothScroller() {
-            super(mBaseGridView.getContext());
-        }
-
-        @Override
-        protected void onStop() {
-            mFlag |= PF_IN_ONSTOP_SMOOTHSCROLLER;
-            try {
-                onStopInternal();
-            } finally {
-                mFlag &= ~PF_IN_ONSTOP_SMOOTHSCROLLER;
-            }
-        }
-
-        protected void onStopInternal() {
-            // onTargetFound() may not be called if we hit the "wall" first or get cancelled.
-            View targetView = findViewByPosition(getTargetPosition());
-            if (targetView == null) {
-                if (getTargetPosition() >= 0) {
-                    // if smooth scroller is stopped without target, immediately jumps
-                    // to the target position.
-                    scrollToSelection(getTargetPosition(), 0, false, 0);
-                }
-                super.onStop();
-                return;
-            }
-            if (mFocusPosition != getTargetPosition()) {
-                // This should not happen since we cropped value in startPositionSmoothScroller()
-                mFocusPosition = getTargetPosition();
-            }
-            if (hasFocus()) {
-                mFlag |= PF_IN_SELECTION;
-                targetView.requestFocus();
-                mFlag &= ~PF_IN_SELECTION;
-            }
-            dispatchChildSelected();
-            dispatchChildSelectedAndPositioned();
-            super.onStop();
-        }
-
-        @Override
-        protected int calculateTimeForScrolling(int dx) {
-            int ms = super.calculateTimeForScrolling(dx);
-            if (mWindowAlignment.mainAxis().getSize() > 0) {
-                float minMs = (float) MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN
-                        / mWindowAlignment.mainAxis().getSize() * dx;
-                if (ms < minMs) {
-                    ms = (int) minMs;
-                }
-            }
-            return ms;
-        }
-
-        @Override
-        protected void onTargetFound(View targetView,
-                RecyclerView.State state, Action action) {
-            if (getScrollPosition(targetView, null, sTwoInts)) {
-                int dx, dy;
-                if (mOrientation == HORIZONTAL) {
-                    dx = sTwoInts[0];
-                    dy = sTwoInts[1];
-                } else {
-                    dx = sTwoInts[1];
-                    dy = sTwoInts[0];
-                }
-                final int distance = (int) Math.sqrt(dx * dx + dy * dy);
-                final int time = calculateTimeForDeceleration(distance);
-                action.update(dx, dy, time, mDecelerateInterpolator);
-            }
-        }
-    }
-
-    /**
-     * The SmoothScroller that remembers pending DPAD keys and consume pending keys
-     * during scroll.
-     */
-    final class PendingMoveSmoothScroller extends GridLinearSmoothScroller {
-        // -2 is a target position that LinearSmoothScroller can never find until
-        // consumePendingMovesXXX() sets real targetPosition.
-        final static int TARGET_UNDEFINED = -2;
-        // whether the grid is staggered.
-        private final boolean mStaggeredGrid;
-        // Number of pending movements on primary direction, negative if PREV_ITEM.
-        private int mPendingMoves;
-
-        PendingMoveSmoothScroller(int initialPendingMoves, boolean staggeredGrid) {
-            mPendingMoves = initialPendingMoves;
-            mStaggeredGrid = staggeredGrid;
-            setTargetPosition(TARGET_UNDEFINED);
-        }
-
-        void increasePendingMoves() {
-            if (mPendingMoves < mMaxPendingMoves) {
-                mPendingMoves++;
-            }
-        }
-
-        void decreasePendingMoves() {
-            if (mPendingMoves > -mMaxPendingMoves) {
-                mPendingMoves--;
-            }
-        }
-
-        /**
-         * Called before laid out an item when non-staggered grid can handle pending movements
-         * by skipping "mNumRows" per movement;  staggered grid will have to wait the item
-         * has been laid out in consumePendingMovesAfterLayout().
-         */
-        void consumePendingMovesBeforeLayout() {
-            if (mStaggeredGrid || mPendingMoves == 0) {
-                return;
-            }
-            View newSelected = null;
-            int startPos = mPendingMoves > 0 ? mFocusPosition + mNumRows :
-                    mFocusPosition - mNumRows;
-            for (int pos = startPos; mPendingMoves != 0;
-                    pos = mPendingMoves > 0 ? pos + mNumRows: pos - mNumRows) {
-                View v = findViewByPosition(pos);
-                if (v == null) {
-                    break;
-                }
-                if (!canScrollTo(v)) {
-                    continue;
-                }
-                newSelected = v;
-                mFocusPosition = pos;
-                mSubFocusPosition = 0;
-                if (mPendingMoves > 0) {
-                    mPendingMoves--;
-                } else {
-                    mPendingMoves++;
-                }
-            }
-            if (newSelected != null && hasFocus()) {
-                mFlag |= PF_IN_SELECTION;
-                newSelected.requestFocus();
-                mFlag &= ~PF_IN_SELECTION;
-            }
-        }
-
-        /**
-         * Called after laid out an item.  Staggered grid should find view on same
-         * Row and consume pending movements.
-         */
-        void consumePendingMovesAfterLayout() {
-            if (mStaggeredGrid && mPendingMoves != 0) {
-                // consume pending moves, focus to item on the same row.
-                mPendingMoves = processSelectionMoves(true, mPendingMoves);
-            }
-            if (mPendingMoves == 0 || (mPendingMoves > 0 && hasCreatedLastItem())
-                    || (mPendingMoves < 0 && hasCreatedFirstItem())) {
-                setTargetPosition(mFocusPosition);
-                stop();
-            }
-        }
-
-        @Override
-        protected void updateActionForInterimTarget(Action action) {
-            if (mPendingMoves == 0) {
-                return;
-            }
-            super.updateActionForInterimTarget(action);
-        }
-
-        @Override
-        public PointF computeScrollVectorForPosition(int targetPosition) {
-            if (mPendingMoves == 0) {
-                return null;
-            }
-            int direction = ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
-                    ? mPendingMoves > 0 : mPendingMoves < 0)
-                    ? -1 : 1;
-            if (mOrientation == HORIZONTAL) {
-                return new PointF(direction, 0);
-            } else {
-                return new PointF(0, direction);
-            }
-        }
-
-        @Override
-        protected void onStopInternal() {
-            super.onStopInternal();
-            // if we hit wall,  need clear the remaining pending moves.
-            mPendingMoves = 0;
-            mPendingMoveSmoothScroller = null;
-            View v = findViewByPosition(getTargetPosition());
-            if (v != null) scrollToView(v, true);
-        }
-    };
-
-    private static final String TAG = "GridLayoutManager";
-    static final boolean DEBUG = false;
-    static final boolean TRACE = false;
-
-    // maximum pending movement in one direction.
-    static final int DEFAULT_MAX_PENDING_MOVES = 10;
-    int mMaxPendingMoves = DEFAULT_MAX_PENDING_MOVES;
-    // minimal milliseconds to scroll window size in major direction,  we put a cap to prevent the
-    // effect smooth scrolling too over to bind an item view then drag the item view back.
-    final static int MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN = 30;
-
-    String getTag() {
-        return TAG + ":" + mBaseGridView.getId();
-    }
-
-    final BaseGridView mBaseGridView;
-
-    /**
-     * Note on conventions in the presence of RTL layout directions:
-     * Many properties and method names reference entities related to the
-     * beginnings and ends of things.  In the presence of RTL flows,
-     * it may not be clear whether this is intended to reference a
-     * quantity that changes direction in RTL cases, or a quantity that
-     * does not.  Here are the conventions in use:
-     *
-     * start/end: coordinate quantities - do reverse
-     * (optical) left/right: coordinate quantities - do not reverse
-     * low/high: coordinate quantities - do not reverse
-     * min/max: coordinate quantities - do not reverse
-     * scroll offset - coordinate quantities - do not reverse
-     * first/last: positional indices - do not reverse
-     * front/end: positional indices - do not reverse
-     * prepend/append: related to positional indices - do not reverse
-     *
-     * Note that although quantities do not reverse in RTL flows, their
-     * relationship does.  In LTR flows, the first positional index is
-     * leftmost; in RTL flows, it is rightmost.  Thus, anywhere that
-     * positional quantities are mapped onto coordinate quantities,
-     * the flow must be checked and the logic reversed.
-     */
-
-    /**
-     * The orientation of a "row".
-     */
-    @RecyclerView.Orientation
-    int mOrientation = HORIZONTAL;
-    private OrientationHelper mOrientationHelper = OrientationHelper.createHorizontalHelper(this);
-
-    RecyclerView.State mState;
-    // Suppose currently showing 4, 5, 6, 7; removing 2,3,4 will make the layoutPosition to be
-    // 2(deleted), 3, 4, 5 in prelayout pass. So when we add item in prelayout, we must subtract 2
-    // from index of Grid.createItem.
-    int mPositionDeltaInPreLayout;
-    // Extra layout space needs to fill in prelayout pass. Note we apply the extra space to both
-    // appends and prepends due to the fact leanback is doing mario scrolling: removing items to
-    // the left of focused item might need extra layout on the right.
-    int mExtraLayoutSpaceInPreLayout;
-    // mPositionToRowInPostLayout and mDisappearingPositions are temp variables in post layout.
-    final SparseIntArray mPositionToRowInPostLayout = new SparseIntArray();
-    int[] mDisappearingPositions;
-
-    RecyclerView.Recycler mRecycler;
-
-    private static final Rect sTempRect = new Rect();
-
-    // 2 bits mask is for 3 STAGEs: 0, PF_STAGE_LAYOUT or PF_STAGE_SCROLL.
-    static final int PF_STAGE_MASK = 0x3;
-    static final int PF_STAGE_LAYOUT = 0x1;
-    static final int PF_STAGE_SCROLL = 0x2;
-
-    // Flag for "in fast relayout", determined by layoutInit() result.
-    static final int PF_FAST_RELAYOUT = 1 << 2;
-
-    // Flag for the selected item being updated in fast relayout.
-    static final int PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION = 1 << 3;
-    /**
-     * During full layout pass, when GridView had focus: onLayoutChildren will
-     * skip non-focusable child and adjust mFocusPosition.
-     */
-    static final int PF_IN_LAYOUT_SEARCH_FOCUS = 1 << 4;
-
-    // flag to prevent reentry if it's already processing selection request.
-    static final int PF_IN_SELECTION = 1 << 5;
-
-    // Represents whether child views are temporarily sliding out
-    static final int PF_SLIDING = 1 << 6;
-    static final int PF_LAYOUT_EATEN_IN_SLIDING = 1 << 7;
-
-    /**
-     * Force a full layout under certain situations.  E.g. Rows change, jump to invisible child.
-     */
-    static final int PF_FORCE_FULL_LAYOUT = 1 << 8;
-
-    /**
-     * True if layout is enabled.
-     */
-    static final int PF_LAYOUT_ENABLED = 1 << 9;
-
-    /**
-     * Flag controlling whether the current/next layout should
-     * be updating the secondary size of rows.
-     */
-    static final int PF_ROW_SECONDARY_SIZE_REFRESH = 1 << 10;
-
-    /**
-     *  Allow DPAD key to navigate out at the front of the View (where position = 0),
-     *  default is false.
-     */
-    static final int PF_FOCUS_OUT_FRONT = 1 << 11;
-
-    /**
-     * Allow DPAD key to navigate out at the end of the view, default is false.
-     */
-    static final int PF_FOCUS_OUT_END = 1 << 12;
-
-    static final int PF_FOCUS_OUT_MASKS = PF_FOCUS_OUT_FRONT | PF_FOCUS_OUT_END;
-
-    /**
-     *  Allow DPAD key to navigate out of second axis.
-     *  default is true.
-     */
-    static final int PF_FOCUS_OUT_SIDE_START = 1 << 13;
-
-    /**
-     * Allow DPAD key to navigate out of second axis.
-     */
-    static final int PF_FOCUS_OUT_SIDE_END = 1 << 14;
-
-    static final int PF_FOCUS_OUT_SIDE_MASKS = PF_FOCUS_OUT_SIDE_START | PF_FOCUS_OUT_SIDE_END;
-
-    /**
-     * True if focus search is disabled.
-     */
-    static final int PF_FOCUS_SEARCH_DISABLED = 1 << 15;
-
-    /**
-     * True if prune child,  might be disabled during transition.
-     */
-    static final int PF_PRUNE_CHILD = 1 << 16;
-
-    /**
-     * True if scroll content,  might be disabled during transition.
-     */
-    static final int PF_SCROLL_ENABLED = 1 << 17;
-
-    /**
-     * Set to true for RTL layout in horizontal orientation
-     */
-    static final int PF_REVERSE_FLOW_PRIMARY = 1 << 18;
-
-    /**
-     * Set to true for RTL layout in vertical orientation
-     */
-    static final int PF_REVERSE_FLOW_SECONDARY = 1 << 19;
-
-    static final int PF_REVERSE_FLOW_MASK = PF_REVERSE_FLOW_PRIMARY | PF_REVERSE_FLOW_SECONDARY;
-
-    /**
-     * flag to prevent calling stop() in onStop() which will lead to stack overflow crash
-     * TODO: fix RecyclerView.SmoothScroller#stop() instead
-     */
-    static final int PF_IN_ONSTOP_SMOOTHSCROLLER = 1 << 20;
-
-    int mFlag = PF_LAYOUT_ENABLED
-            | PF_FOCUS_OUT_SIDE_START | PF_FOCUS_OUT_SIDE_END
-            | PF_PRUNE_CHILD | PF_SCROLL_ENABLED;
-
-    private OnChildSelectedListener mChildSelectedListener = null;
-
-    private ArrayList<OnChildViewHolderSelectedListener> mChildViewHolderSelectedListeners = null;
-
-    OnChildLaidOutListener mChildLaidOutListener = null;
-
-    /**
-     * The focused position, it's not the currently visually aligned position
-     * but it is the final position that we intend to focus on. If there are
-     * multiple setSelection() called, mFocusPosition saves last value.
-     */
-    int mFocusPosition = NO_POSITION;
-
-    /**
-     * A view can have multiple alignment position,  this is the index of which
-     * alignment is used,  by default is 0.
-     */
-    int mSubFocusPosition = 0;
-
-    /**
-     * LinearSmoothScroller that consume pending DPAD movements.
-     */
-    PendingMoveSmoothScroller mPendingMoveSmoothScroller;
-
-    /**
-     * The offset to be applied to mFocusPosition, due to adapter change, on the next
-     * layout.  Set to Integer.MIN_VALUE means we should stop adding delta to mFocusPosition
-     * until next layout cycler.
-     * TODO:  This is somewhat duplication of RecyclerView getOldPosition() which is
-     * unfortunately cleared after prelayout.
-     */
-    private int mFocusPositionOffset = 0;
-
-    /**
-     * Extra pixels applied on primary direction.
-     */
-    private int mPrimaryScrollExtra;
-
-    /**
-     * override child visibility
-     */
-    @Visibility
-    int mChildVisibility;
-
-    /**
-     * Pixels that scrolled in secondary forward direction. Negative value means backward.
-     * Note that we treat secondary differently than main. For the main axis, update scroll min/max
-     * based on first/last item's view location. For second axis, we don't use item's view location.
-     * We are using the {@link #getRowSizeSecondary(int)} plus mScrollOffsetSecondary. see
-     * details in {@link #updateSecondaryScrollLimits()}.
-     */
-    int mScrollOffsetSecondary;
-
-    /**
-     * User-specified row height/column width.  Can be WRAP_CONTENT.
-     */
-    private int mRowSizeSecondaryRequested;
-
-    /**
-     * The fixed size of each grid item in the secondary direction. This corresponds to
-     * the row height, equal for all rows. Grid items may have variable length
-     * in the primary direction.
-     */
-    private int mFixedRowSizeSecondary;
-
-    /**
-     * Tracks the secondary size of each row.
-     */
-    private int[] mRowSizeSecondary;
-
-    /**
-     * The maximum measured size of the view.
-     */
-    private int mMaxSizeSecondary;
-
-    /**
-     * Margin between items.
-     */
-    private int mHorizontalSpacing;
-    /**
-     * Margin between items vertically.
-     */
-    private int mVerticalSpacing;
-    /**
-     * Margin in main direction.
-     */
-    private int mSpacingPrimary;
-    /**
-     * Margin in second direction.
-     */
-    private int mSpacingSecondary;
-    /**
-     * How to position child in secondary direction.
-     */
-    private int mGravity = Gravity.START | Gravity.TOP;
-    /**
-     * The number of rows in the grid.
-     */
-    int mNumRows;
-    /**
-     * Number of rows requested, can be 0 to be determined by parent size and
-     * rowHeight.
-     */
-    private int mNumRowsRequested = 1;
-
-    /**
-     * Saves grid information of each view.
-     */
-    Grid mGrid;
-
-    /**
-     * Focus Scroll strategy.
-     */
-    private int mFocusScrollStrategy = BaseGridView.FOCUS_SCROLL_ALIGNED;
-    /**
-     * Defines how item view is aligned in the window.
-     */
-    final WindowAlignment mWindowAlignment = new WindowAlignment();
-
-    /**
-     * Defines how item view is aligned.
-     */
-    private final ItemAlignment mItemAlignment = new ItemAlignment();
-
-    /**
-     * Dimensions of the view, width or height depending on orientation.
-     */
-    private int mSizePrimary;
-
-    /**
-     * Pixels of extra space for layout item (outside the widget)
-     */
-    private int mExtraLayoutSpace;
-
-    /**
-     * Temporary variable: an int array of length=2.
-     */
-    static int[] sTwoInts = new int[2];
-
-    /**
-     * Temporaries used for measuring.
-     */
-    private int[] mMeasuredDimension = new int[2];
-
-    final ViewsStateBundle mChildrenStates = new ViewsStateBundle();
-
-    /**
-     * Optional interface implemented by Adapter.
-     */
-    private FacetProviderAdapter mFacetProviderAdapter;
-
-    public GridLayoutManager(BaseGridView baseGridView) {
-        mBaseGridView = baseGridView;
-        mChildVisibility = -1;
-        // disable prefetch by default, prefetch causes regression on low power chipset
-        setItemPrefetchEnabled(false);
-    }
-
-    public void setOrientation(@RecyclerView.Orientation int orientation) {
-        if (orientation != HORIZONTAL && orientation != VERTICAL) {
-            if (DEBUG) Log.v(getTag(), "invalid orientation: " + orientation);
-            return;
-        }
-
-        mOrientation = orientation;
-        mOrientationHelper = OrientationHelper.createOrientationHelper(this, mOrientation);
-        mWindowAlignment.setOrientation(orientation);
-        mItemAlignment.setOrientation(orientation);
-        mFlag |= PF_FORCE_FULL_LAYOUT;
-    }
-
-    public void onRtlPropertiesChanged(int layoutDirection) {
-        final int flags;
-        if (mOrientation == HORIZONTAL) {
-            flags = layoutDirection == View.LAYOUT_DIRECTION_RTL ? PF_REVERSE_FLOW_PRIMARY : 0;
-        } else {
-            flags = layoutDirection == View.LAYOUT_DIRECTION_RTL ? PF_REVERSE_FLOW_SECONDARY : 0;
-        }
-        if ((mFlag & PF_REVERSE_FLOW_MASK) == flags) {
-            return;
-        }
-        mFlag = (mFlag & ~PF_REVERSE_FLOW_MASK) | flags;
-        mFlag |= PF_FORCE_FULL_LAYOUT;
-        mWindowAlignment.horizontal.setReversedFlow(layoutDirection == View.LAYOUT_DIRECTION_RTL);
-    }
-
-    public int getFocusScrollStrategy() {
-        return mFocusScrollStrategy;
-    }
-
-    public void setFocusScrollStrategy(int focusScrollStrategy) {
-        mFocusScrollStrategy = focusScrollStrategy;
-    }
-
-    public void setWindowAlignment(int windowAlignment) {
-        mWindowAlignment.mainAxis().setWindowAlignment(windowAlignment);
-    }
-
-    public int getWindowAlignment() {
-        return mWindowAlignment.mainAxis().getWindowAlignment();
-    }
-
-    public void setWindowAlignmentOffset(int alignmentOffset) {
-        mWindowAlignment.mainAxis().setWindowAlignmentOffset(alignmentOffset);
-    }
-
-    public int getWindowAlignmentOffset() {
-        return mWindowAlignment.mainAxis().getWindowAlignmentOffset();
-    }
-
-    public void setWindowAlignmentOffsetPercent(float offsetPercent) {
-        mWindowAlignment.mainAxis().setWindowAlignmentOffsetPercent(offsetPercent);
-    }
-
-    public float getWindowAlignmentOffsetPercent() {
-        return mWindowAlignment.mainAxis().getWindowAlignmentOffsetPercent();
-    }
-
-    public void setItemAlignmentOffset(int alignmentOffset) {
-        mItemAlignment.mainAxis().setItemAlignmentOffset(alignmentOffset);
-        updateChildAlignments();
-    }
-
-    public int getItemAlignmentOffset() {
-        return mItemAlignment.mainAxis().getItemAlignmentOffset();
-    }
-
-    public void setItemAlignmentOffsetWithPadding(boolean withPadding) {
-        mItemAlignment.mainAxis().setItemAlignmentOffsetWithPadding(withPadding);
-        updateChildAlignments();
-    }
-
-    public boolean isItemAlignmentOffsetWithPadding() {
-        return mItemAlignment.mainAxis().isItemAlignmentOffsetWithPadding();
-    }
-
-    public void setItemAlignmentOffsetPercent(float offsetPercent) {
-        mItemAlignment.mainAxis().setItemAlignmentOffsetPercent(offsetPercent);
-        updateChildAlignments();
-    }
-
-    public float getItemAlignmentOffsetPercent() {
-        return mItemAlignment.mainAxis().getItemAlignmentOffsetPercent();
-    }
-
-    public void setItemAlignmentViewId(int viewId) {
-        mItemAlignment.mainAxis().setItemAlignmentViewId(viewId);
-        updateChildAlignments();
-    }
-
-    public int getItemAlignmentViewId() {
-        return mItemAlignment.mainAxis().getItemAlignmentViewId();
-    }
-
-    public void setFocusOutAllowed(boolean throughFront, boolean throughEnd) {
-        mFlag = (mFlag & ~PF_FOCUS_OUT_MASKS)
-                | (throughFront ? PF_FOCUS_OUT_FRONT : 0)
-                | (throughEnd ? PF_FOCUS_OUT_END : 0);
-    }
-
-    public void setFocusOutSideAllowed(boolean throughStart, boolean throughEnd) {
-        mFlag = (mFlag & ~PF_FOCUS_OUT_SIDE_MASKS)
-                | (throughStart ? PF_FOCUS_OUT_SIDE_START : 0)
-                | (throughEnd ? PF_FOCUS_OUT_SIDE_END : 0);
-    }
-
-    public void setNumRows(int numRows) {
-        if (numRows < 0) throw new IllegalArgumentException();
-        mNumRowsRequested = numRows;
-    }
-
-    /**
-     * Set the row height. May be WRAP_CONTENT, or a size in pixels.
-     */
-    public void setRowHeight(int height) {
-        if (height >= 0 || height == ViewGroup.LayoutParams.WRAP_CONTENT) {
-            mRowSizeSecondaryRequested = height;
-        } else {
-            throw new IllegalArgumentException("Invalid row height: " + height);
-        }
-    }
-
-    public void setItemSpacing(int space) {
-        mVerticalSpacing = mHorizontalSpacing = space;
-        mSpacingPrimary = mSpacingSecondary = space;
-    }
-
-    public void setVerticalSpacing(int space) {
-        if (mOrientation == VERTICAL) {
-            mSpacingPrimary = mVerticalSpacing = space;
-        } else {
-            mSpacingSecondary = mVerticalSpacing = space;
-        }
-    }
-
-    public void setHorizontalSpacing(int space) {
-        if (mOrientation == HORIZONTAL) {
-            mSpacingPrimary = mHorizontalSpacing = space;
-        } else {
-            mSpacingSecondary = mHorizontalSpacing = space;
-        }
-    }
-
-    public int getVerticalSpacing() {
-        return mVerticalSpacing;
-    }
-
-    public int getHorizontalSpacing() {
-        return mHorizontalSpacing;
-    }
-
-    public void setGravity(int gravity) {
-        mGravity = gravity;
-    }
-
-    protected boolean hasDoneFirstLayout() {
-        return mGrid != null;
-    }
-
-    public void setOnChildSelectedListener(OnChildSelectedListener listener) {
-        mChildSelectedListener = listener;
-    }
-
-    public void setOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) {
-        if (listener == null) {
-            mChildViewHolderSelectedListeners = null;
-            return;
-        }
-        if (mChildViewHolderSelectedListeners == null) {
-            mChildViewHolderSelectedListeners = new ArrayList<OnChildViewHolderSelectedListener>();
-        } else {
-            mChildViewHolderSelectedListeners.clear();
-        }
-        mChildViewHolderSelectedListeners.add(listener);
-    }
-
-    public void addOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) {
-        if (mChildViewHolderSelectedListeners == null) {
-            mChildViewHolderSelectedListeners = new ArrayList<OnChildViewHolderSelectedListener>();
-        }
-        mChildViewHolderSelectedListeners.add(listener);
-    }
-
-    public void removeOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener
-            listener) {
-        if (mChildViewHolderSelectedListeners != null) {
-            mChildViewHolderSelectedListeners.remove(listener);
-        }
-    }
-
-    boolean hasOnChildViewHolderSelectedListener() {
-        return mChildViewHolderSelectedListeners != null
-                && mChildViewHolderSelectedListeners.size() > 0;
-    }
-
-    void fireOnChildViewHolderSelected(RecyclerView parent, RecyclerView.ViewHolder child,
-            int position, int subposition) {
-        if (mChildViewHolderSelectedListeners == null) {
-            return;
-        }
-        for (int i = mChildViewHolderSelectedListeners.size() - 1; i >= 0 ; i--) {
-            mChildViewHolderSelectedListeners.get(i).onChildViewHolderSelected(parent, child,
-                    position, subposition);
-        }
-    }
-
-    void fireOnChildViewHolderSelectedAndPositioned(RecyclerView parent, RecyclerView.ViewHolder
-            child, int position, int subposition) {
-        if (mChildViewHolderSelectedListeners == null) {
-            return;
-        }
-        for (int i = mChildViewHolderSelectedListeners.size() - 1; i >= 0 ; i--) {
-            mChildViewHolderSelectedListeners.get(i).onChildViewHolderSelectedAndPositioned(parent,
-                    child, position, subposition);
-        }
-    }
-
-    void setOnChildLaidOutListener(OnChildLaidOutListener listener) {
-        mChildLaidOutListener = listener;
-    }
-
-    private int getAdapterPositionByView(View view) {
-        if (view == null) {
-            return NO_POSITION;
-        }
-        LayoutParams params = (LayoutParams) view.getLayoutParams();
-        if (params == null || params.isItemRemoved()) {
-            // when item is removed, the position value can be any value.
-            return NO_POSITION;
-        }
-        return params.getViewAdapterPosition();
-    }
-
-    int getSubPositionByView(View view, View childView) {
-        if (view == null || childView == null) {
-            return 0;
-        }
-        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-        final ItemAlignmentFacet facet = lp.getItemAlignmentFacet();
-        if (facet != null) {
-            final ItemAlignmentFacet.ItemAlignmentDef[] defs = facet.getAlignmentDefs();
-            if (defs.length > 1) {
-                while (childView != view) {
-                    int id = childView.getId();
-                    if (id != View.NO_ID) {
-                        for (int i = 1; i < defs.length; i++) {
-                            if (defs[i].getItemAlignmentFocusViewId() == id) {
-                                return i;
-                            }
-                        }
-                    }
-                    childView = (View) childView.getParent();
-                }
-            }
-        }
-        return 0;
-    }
-
-    private int getAdapterPositionByIndex(int index) {
-        return getAdapterPositionByView(getChildAt(index));
-    }
-
-    void dispatchChildSelected() {
-        if (mChildSelectedListener == null && !hasOnChildViewHolderSelectedListener()) {
-            return;
-        }
-
-        if (TRACE) TraceCompat.beginSection("onChildSelected");
-        View view = mFocusPosition == NO_POSITION ? null : findViewByPosition(mFocusPosition);
-        if (view != null) {
-            RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(view);
-            if (mChildSelectedListener != null) {
-                mChildSelectedListener.onChildSelected(mBaseGridView, view, mFocusPosition,
-                        vh == null? NO_ID: vh.getItemId());
-            }
-            fireOnChildViewHolderSelected(mBaseGridView, vh, mFocusPosition, mSubFocusPosition);
-        } else {
-            if (mChildSelectedListener != null) {
-                mChildSelectedListener.onChildSelected(mBaseGridView, null, NO_POSITION, NO_ID);
-            }
-            fireOnChildViewHolderSelected(mBaseGridView, null, NO_POSITION, 0);
-        }
-        if (TRACE) TraceCompat.endSection();
-
-        // Children may request layout when a child selection event occurs (such as a change of
-        // padding on the current and previously selected rows).
-        // If in layout, a child requesting layout may have been laid out before the selection
-        // callback.
-        // If it was not, the child will be laid out after the selection callback.
-        // If so, the layout request will be honoured though the view system will emit a double-
-        // layout warning.
-        // If not in layout, we may be scrolling in which case the child layout request will be
-        // eaten by recyclerview.  Post a requestLayout.
-        if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT && !mBaseGridView.isLayoutRequested()) {
-            int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                if (getChildAt(i).isLayoutRequested()) {
-                    forceRequestLayout();
-                    break;
-                }
-            }
-        }
-    }
-
-    private void dispatchChildSelectedAndPositioned() {
-        if (!hasOnChildViewHolderSelectedListener()) {
-            return;
-        }
-
-        if (TRACE) TraceCompat.beginSection("onChildSelectedAndPositioned");
-        View view = mFocusPosition == NO_POSITION ? null : findViewByPosition(mFocusPosition);
-        if (view != null) {
-            RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(view);
-            fireOnChildViewHolderSelectedAndPositioned(mBaseGridView, vh, mFocusPosition,
-                    mSubFocusPosition);
-        } else {
-            if (mChildSelectedListener != null) {
-                mChildSelectedListener.onChildSelected(mBaseGridView, null, NO_POSITION, NO_ID);
-            }
-            fireOnChildViewHolderSelectedAndPositioned(mBaseGridView, null, NO_POSITION, 0);
-        }
-        if (TRACE) TraceCompat.endSection();
-
-    }
-
-    @Override
-    public boolean canScrollHorizontally() {
-        // We can scroll horizontally if we have horizontal orientation, or if
-        // we are vertical and have more than one column.
-        return mOrientation == HORIZONTAL || mNumRows > 1;
-    }
-
-    @Override
-    public boolean canScrollVertically() {
-        // We can scroll vertically if we have vertical orientation, or if we
-        // are horizontal and have more than one row.
-        return mOrientation == VERTICAL || mNumRows > 1;
-    }
-
-    @Override
-    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
-        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
-    }
-
-    @Override
-    public RecyclerView.LayoutParams generateLayoutParams(Context context, AttributeSet attrs) {
-        return new LayoutParams(context, attrs);
-    }
-
-    @Override
-    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
-        if (lp instanceof LayoutParams) {
-            return new LayoutParams((LayoutParams) lp);
-        } else if (lp instanceof RecyclerView.LayoutParams) {
-            return new LayoutParams((RecyclerView.LayoutParams) lp);
-        } else if (lp instanceof MarginLayoutParams) {
-            return new LayoutParams((MarginLayoutParams) lp);
-        } else {
-            return new LayoutParams(lp);
-        }
-    }
-
-    protected View getViewForPosition(int position) {
-        return mRecycler.getViewForPosition(position);
-    }
-
-    final int getOpticalLeft(View v) {
-        return ((LayoutParams) v.getLayoutParams()).getOpticalLeft(v);
-    }
-
-    final int getOpticalRight(View v) {
-        return ((LayoutParams) v.getLayoutParams()).getOpticalRight(v);
-    }
-
-    final int getOpticalTop(View v) {
-        return ((LayoutParams) v.getLayoutParams()).getOpticalTop(v);
-    }
-
-    final int getOpticalBottom(View v) {
-        return ((LayoutParams) v.getLayoutParams()).getOpticalBottom(v);
-    }
-
-    @Override
-    public int getDecoratedLeft(View child) {
-        return super.getDecoratedLeft(child) + ((LayoutParams) child.getLayoutParams()).mLeftInset;
-    }
-
-    @Override
-    public int getDecoratedTop(View child) {
-        return super.getDecoratedTop(child) + ((LayoutParams) child.getLayoutParams()).mTopInset;
-    }
-
-    @Override
-    public int getDecoratedRight(View child) {
-        return super.getDecoratedRight(child)
-                - ((LayoutParams) child.getLayoutParams()).mRightInset;
-    }
-
-    @Override
-    public int getDecoratedBottom(View child) {
-        return super.getDecoratedBottom(child)
-                - ((LayoutParams) child.getLayoutParams()).mBottomInset;
-    }
-
-    @Override
-    public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
-        super.getDecoratedBoundsWithMargins(view, outBounds);
-        LayoutParams params = ((LayoutParams) view.getLayoutParams());
-        outBounds.left += params.mLeftInset;
-        outBounds.top += params.mTopInset;
-        outBounds.right -= params.mRightInset;
-        outBounds.bottom -= params.mBottomInset;
-    }
-
-    int getViewMin(View v) {
-        return mOrientationHelper.getDecoratedStart(v);
-    }
-
-    int getViewMax(View v) {
-        return mOrientationHelper.getDecoratedEnd(v);
-    }
-
-    int getViewPrimarySize(View view) {
-        getDecoratedBoundsWithMargins(view, sTempRect);
-        return mOrientation == HORIZONTAL ? sTempRect.width() : sTempRect.height();
-    }
-
-    private int getViewCenter(View view) {
-        return (mOrientation == HORIZONTAL) ? getViewCenterX(view) : getViewCenterY(view);
-    }
-
-    private int getAdjustedViewCenter(View view) {
-        if (view.hasFocus()) {
-            View child = view.findFocus();
-            if (child != null && child != view) {
-                return getAdjustedPrimaryAlignedScrollDistance(getViewCenter(view), view, child);
-            }
-        }
-        return getViewCenter(view);
-    }
-
-    private int getViewCenterSecondary(View view) {
-        return (mOrientation == HORIZONTAL) ? getViewCenterY(view) : getViewCenterX(view);
-    }
-
-    private int getViewCenterX(View v) {
-        LayoutParams p = (LayoutParams) v.getLayoutParams();
-        return p.getOpticalLeft(v) + p.getAlignX();
-    }
-
-    private int getViewCenterY(View v) {
-        LayoutParams p = (LayoutParams) v.getLayoutParams();
-        return p.getOpticalTop(v) + p.getAlignY();
-    }
-
-    /**
-     * Save Recycler and State for convenience.  Must be paired with leaveContext().
-     */
-    private void saveContext(Recycler recycler, State state) {
-        if (mRecycler != null || mState != null) {
-            Log.e(TAG, "Recycler information was not released, bug!");
-        }
-        mRecycler = recycler;
-        mState = state;
-        mPositionDeltaInPreLayout = 0;
-        mExtraLayoutSpaceInPreLayout = 0;
-    }
-
-    /**
-     * Discard saved Recycler and State.
-     */
-    private void leaveContext() {
-        mRecycler = null;
-        mState = null;
-        mPositionDeltaInPreLayout = 0;
-        mExtraLayoutSpaceInPreLayout = 0;
-    }
-
-    /**
-     * Re-initialize data structures for a data change or handling invisible
-     * selection. The method tries its best to preserve position information so
-     * that staggered grid looks same before and after re-initialize.
-     * @return true if can fastRelayout()
-     */
-    private boolean layoutInit() {
-        final int newItemCount = mState.getItemCount();
-        if (newItemCount == 0) {
-            mFocusPosition = NO_POSITION;
-            mSubFocusPosition = 0;
-        } else if (mFocusPosition >= newItemCount) {
-            mFocusPosition = newItemCount - 1;
-            mSubFocusPosition = 0;
-        } else if (mFocusPosition == NO_POSITION && newItemCount > 0) {
-            // if focus position is never set before,  initialize it to 0
-            mFocusPosition = 0;
-            mSubFocusPosition = 0;
-        }
-        if (!mState.didStructureChange() && mGrid != null && mGrid.getFirstVisibleIndex() >= 0
-                && (mFlag & PF_FORCE_FULL_LAYOUT) == 0 && mGrid.getNumRows() == mNumRows) {
-            updateScrollController();
-            updateSecondaryScrollLimits();
-            mGrid.setSpacing(mSpacingPrimary);
-            return true;
-        } else {
-            mFlag &= ~PF_FORCE_FULL_LAYOUT;
-
-            if (mGrid == null || mNumRows != mGrid.getNumRows()
-                    || ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0) != mGrid.isReversedFlow()) {
-                mGrid = Grid.createGrid(mNumRows);
-                mGrid.setProvider(mGridProvider);
-                mGrid.setReversedFlow((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0);
-            }
-            initScrollController();
-            updateSecondaryScrollLimits();
-            mGrid.setSpacing(mSpacingPrimary);
-            detachAndScrapAttachedViews(mRecycler);
-            mGrid.resetVisibleIndex();
-            mWindowAlignment.mainAxis().invalidateScrollMin();
-            mWindowAlignment.mainAxis().invalidateScrollMax();
-            return false;
-        }
-    }
-
-    private int getRowSizeSecondary(int rowIndex) {
-        if (mFixedRowSizeSecondary != 0) {
-            return mFixedRowSizeSecondary;
-        }
-        if (mRowSizeSecondary == null) {
-            return 0;
-        }
-        return mRowSizeSecondary[rowIndex];
-    }
-
-    int getRowStartSecondary(int rowIndex) {
-        int start = 0;
-        // Iterate from left to right, which is a different index traversal
-        // in RTL flow
-        if ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0) {
-            for (int i = mNumRows-1; i > rowIndex; i--) {
-                start += getRowSizeSecondary(i) + mSpacingSecondary;
-            }
-        } else {
-            for (int i = 0; i < rowIndex; i++) {
-                start += getRowSizeSecondary(i) + mSpacingSecondary;
-            }
-        }
-        return start;
-    }
-
-    private int getSizeSecondary() {
-        int rightmostIndex = (mFlag & PF_REVERSE_FLOW_SECONDARY) != 0 ? 0 : mNumRows - 1;
-        return getRowStartSecondary(rightmostIndex) + getRowSizeSecondary(rightmostIndex);
-    }
-
-    int getDecoratedMeasuredWidthWithMargin(View v) {
-        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
-        return getDecoratedMeasuredWidth(v) + lp.leftMargin + lp.rightMargin;
-    }
-
-    int getDecoratedMeasuredHeightWithMargin(View v) {
-        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
-        return getDecoratedMeasuredHeight(v) + lp.topMargin + lp.bottomMargin;
-    }
-
-    private void measureScrapChild(int position, int widthSpec, int heightSpec,
-            int[] measuredDimension) {
-        View view = mRecycler.getViewForPosition(position);
-        if (view != null) {
-            final LayoutParams p = (LayoutParams) view.getLayoutParams();
-            calculateItemDecorationsForChild(view, sTempRect);
-            int widthUsed = p.leftMargin + p.rightMargin + sTempRect.left + sTempRect.right;
-            int heightUsed = p.topMargin + p.bottomMargin + sTempRect.top + sTempRect.bottom;
-
-            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
-                    getPaddingLeft() + getPaddingRight() + widthUsed, p.width);
-            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
-                    getPaddingTop() + getPaddingBottom() + heightUsed, p.height);
-            view.measure(childWidthSpec, childHeightSpec);
-
-            measuredDimension[0] = getDecoratedMeasuredWidthWithMargin(view);
-            measuredDimension[1] = getDecoratedMeasuredHeightWithMargin(view);
-            mRecycler.recycleView(view);
-        }
-    }
-
-    private boolean processRowSizeSecondary(boolean measure) {
-        if (mFixedRowSizeSecondary != 0 || mRowSizeSecondary == null) {
-            return false;
-        }
-
-        if (TRACE) TraceCompat.beginSection("processRowSizeSecondary");
-        CircularIntArray[] rows = mGrid == null ? null : mGrid.getItemPositionsInRows();
-        boolean changed = false;
-        int scrapeChildSize = -1;
-
-        for (int rowIndex = 0; rowIndex < mNumRows; rowIndex++) {
-            CircularIntArray row = rows == null ? null : rows[rowIndex];
-            final int rowItemsPairCount = row == null ? 0 : row.size();
-            int rowSize = -1;
-            for (int rowItemPairIndex = 0; rowItemPairIndex < rowItemsPairCount;
-                    rowItemPairIndex += 2) {
-                final int rowIndexStart = row.get(rowItemPairIndex);
-                final int rowIndexEnd = row.get(rowItemPairIndex + 1);
-                for (int i = rowIndexStart; i <= rowIndexEnd; i++) {
-                    final View view = findViewByPosition(i - mPositionDeltaInPreLayout);
-                    if (view == null) {
-                        continue;
-                    }
-                    if (measure) {
-                        measureChild(view);
-                    }
-                    final int secondarySize = mOrientation == HORIZONTAL
-                            ? getDecoratedMeasuredHeightWithMargin(view)
-                            : getDecoratedMeasuredWidthWithMargin(view);
-                    if (secondarySize > rowSize) {
-                        rowSize = secondarySize;
-                    }
-                }
-            }
-
-            final int itemCount = mState.getItemCount();
-            if (!mBaseGridView.hasFixedSize() && measure && rowSize < 0 && itemCount > 0) {
-                if (scrapeChildSize < 0) {
-                    // measure a child that is close to mFocusPosition but not currently visible
-                    int position = mFocusPosition;
-                    if (position < 0) {
-                        position = 0;
-                    } else if (position >= itemCount) {
-                        position = itemCount - 1;
-                    }
-                    if (getChildCount() > 0) {
-                        int firstPos = mBaseGridView.getChildViewHolder(
-                                getChildAt(0)).getLayoutPosition();
-                        int lastPos = mBaseGridView.getChildViewHolder(
-                                getChildAt(getChildCount() - 1)).getLayoutPosition();
-                        // if mFocusPosition is between first and last, choose either
-                        // first - 1 or last + 1
-                        if (position >= firstPos && position <= lastPos) {
-                            position = (position - firstPos <= lastPos - position)
-                                    ? (firstPos - 1) : (lastPos + 1);
-                            // try the other value if the position is invalid. if both values are
-                            // invalid, skip measureScrapChild below.
-                            if (position < 0 && lastPos < itemCount - 1) {
-                                position = lastPos + 1;
-                            } else if (position >= itemCount && firstPos > 0) {
-                                position = firstPos - 1;
-                            }
-                        }
-                    }
-                    if (position >= 0 && position < itemCount) {
-                        measureScrapChild(position,
-                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
-                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
-                                mMeasuredDimension);
-                        scrapeChildSize = mOrientation == HORIZONTAL ? mMeasuredDimension[1] :
-                                mMeasuredDimension[0];
-                        if (DEBUG) {
-                            Log.v(TAG, "measured scrap child: " + mMeasuredDimension[0] + " "
-                                    + mMeasuredDimension[1]);
-                        }
-                    }
-                }
-                if (scrapeChildSize >= 0) {
-                    rowSize = scrapeChildSize;
-                }
-            }
-            if (rowSize < 0) {
-                rowSize = 0;
-            }
-            if (mRowSizeSecondary[rowIndex] != rowSize) {
-                if (DEBUG) {
-                    Log.v(getTag(), "row size secondary changed: " + mRowSizeSecondary[rowIndex]
-                            + ", " + rowSize);
-                }
-                mRowSizeSecondary[rowIndex] = rowSize;
-                changed = true;
-            }
-        }
-
-        if (TRACE) TraceCompat.endSection();
-        return changed;
-    }
-
-    /**
-     * Checks if we need to update row secondary sizes.
-     */
-    private void updateRowSecondarySizeRefresh() {
-        mFlag = (mFlag & ~PF_ROW_SECONDARY_SIZE_REFRESH)
-                | (processRowSizeSecondary(false) ? PF_ROW_SECONDARY_SIZE_REFRESH : 0);
-        if ((mFlag & PF_ROW_SECONDARY_SIZE_REFRESH) != 0) {
-            if (DEBUG) Log.v(getTag(), "mRowSecondarySizeRefresh now set");
-            forceRequestLayout();
-        }
-    }
-
-    private void forceRequestLayout() {
-        if (DEBUG) Log.v(getTag(), "forceRequestLayout");
-        // RecyclerView prevents us from requesting layout in many cases
-        // (during layout, during scroll, etc.)
-        // For secondary row size wrap_content support we currently need a
-        // second layout pass to update the measured size after having measured
-        // and added child views in layoutChildren.
-        // Force the second layout by posting a delayed runnable.
-        // TODO: investigate allowing a second layout pass,
-        // or move child add/measure logic to the measure phase.
-        ViewCompat.postOnAnimation(mBaseGridView, mRequestLayoutRunnable);
-    }
-
-    private final Runnable mRequestLayoutRunnable = new Runnable() {
-        @Override
-        public void run() {
-            if (DEBUG) Log.v(getTag(), "request Layout from runnable");
-            requestLayout();
-        }
-    };
-
-    @Override
-    public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) {
-        saveContext(recycler, state);
-
-        int sizePrimary, sizeSecondary, modeSecondary, paddingSecondary;
-        int measuredSizeSecondary;
-        if (mOrientation == HORIZONTAL) {
-            sizePrimary = MeasureSpec.getSize(widthSpec);
-            sizeSecondary = MeasureSpec.getSize(heightSpec);
-            modeSecondary = MeasureSpec.getMode(heightSpec);
-            paddingSecondary = getPaddingTop() + getPaddingBottom();
-        } else {
-            sizeSecondary = MeasureSpec.getSize(widthSpec);
-            sizePrimary = MeasureSpec.getSize(heightSpec);
-            modeSecondary = MeasureSpec.getMode(widthSpec);
-            paddingSecondary = getPaddingLeft() + getPaddingRight();
-        }
-        if (DEBUG) {
-            Log.v(getTag(), "onMeasure widthSpec " + Integer.toHexString(widthSpec)
-                    + " heightSpec " + Integer.toHexString(heightSpec)
-                    + " modeSecondary " + Integer.toHexString(modeSecondary)
-                    + " sizeSecondary " + sizeSecondary + " " + this);
-        }
-
-        mMaxSizeSecondary = sizeSecondary;
-
-        if (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT) {
-            mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
-            mFixedRowSizeSecondary = 0;
-
-            if (mRowSizeSecondary == null || mRowSizeSecondary.length != mNumRows) {
-                mRowSizeSecondary = new int[mNumRows];
-            }
-
-            if (mState.isPreLayout()) {
-                updatePositionDeltaInPreLayout();
-            }
-            // Measure all current children and update cached row height or column width
-            processRowSizeSecondary(true);
-
-            switch (modeSecondary) {
-                case MeasureSpec.UNSPECIFIED:
-                    measuredSizeSecondary = getSizeSecondary() + paddingSecondary;
-                    break;
-                case MeasureSpec.AT_MOST:
-                    measuredSizeSecondary = Math.min(getSizeSecondary() + paddingSecondary,
-                            mMaxSizeSecondary);
-                    break;
-                case MeasureSpec.EXACTLY:
-                    measuredSizeSecondary = mMaxSizeSecondary;
-                    break;
-                default:
-                    throw new IllegalStateException("wrong spec");
-            }
-
-        } else {
-            switch (modeSecondary) {
-                case MeasureSpec.UNSPECIFIED:
-                    mFixedRowSizeSecondary = mRowSizeSecondaryRequested == 0
-                            ? sizeSecondary - paddingSecondary : mRowSizeSecondaryRequested;
-                    mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
-                    measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mSpacingSecondary
-                            * (mNumRows - 1) + paddingSecondary;
-                    break;
-                case MeasureSpec.AT_MOST:
-                case MeasureSpec.EXACTLY:
-                    if (mNumRowsRequested == 0 && mRowSizeSecondaryRequested == 0) {
-                        mNumRows = 1;
-                        mFixedRowSizeSecondary = sizeSecondary - paddingSecondary;
-                    } else if (mNumRowsRequested == 0) {
-                        mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
-                        mNumRows = (sizeSecondary + mSpacingSecondary)
-                                / (mRowSizeSecondaryRequested + mSpacingSecondary);
-                    } else if (mRowSizeSecondaryRequested == 0) {
-                        mNumRows = mNumRowsRequested;
-                        mFixedRowSizeSecondary = (sizeSecondary - paddingSecondary
-                                - mSpacingSecondary * (mNumRows - 1)) / mNumRows;
-                    } else {
-                        mNumRows = mNumRowsRequested;
-                        mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
-                    }
-                    measuredSizeSecondary = sizeSecondary;
-                    if (modeSecondary == MeasureSpec.AT_MOST) {
-                        int childrenSize = mFixedRowSizeSecondary * mNumRows + mSpacingSecondary
-                                * (mNumRows - 1) + paddingSecondary;
-                        if (childrenSize < measuredSizeSecondary) {
-                            measuredSizeSecondary = childrenSize;
-                        }
-                    }
-                    break;
-                default:
-                    throw new IllegalStateException("wrong spec");
-            }
-        }
-        if (mOrientation == HORIZONTAL) {
-            setMeasuredDimension(sizePrimary, measuredSizeSecondary);
-        } else {
-            setMeasuredDimension(measuredSizeSecondary, sizePrimary);
-        }
-        if (DEBUG) {
-            Log.v(getTag(), "onMeasure sizePrimary " + sizePrimary
-                    + " measuredSizeSecondary " + measuredSizeSecondary
-                    + " mFixedRowSizeSecondary " + mFixedRowSizeSecondary
-                    + " mNumRows " + mNumRows);
-        }
-        leaveContext();
-    }
-
-    void measureChild(View child) {
-        if (TRACE) TraceCompat.beginSection("measureChild");
-        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-        calculateItemDecorationsForChild(child, sTempRect);
-        int widthUsed = lp.leftMargin + lp.rightMargin + sTempRect.left + sTempRect.right;
-        int heightUsed = lp.topMargin + lp.bottomMargin + sTempRect.top + sTempRect.bottom;
-
-        final int secondarySpec =
-                (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT)
-                        ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
-                        : MeasureSpec.makeMeasureSpec(mFixedRowSizeSecondary, MeasureSpec.EXACTLY);
-        int widthSpec, heightSpec;
-
-        if (mOrientation == HORIZONTAL) {
-            widthSpec = ViewGroup.getChildMeasureSpec(
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), widthUsed, lp.width);
-            heightSpec = ViewGroup.getChildMeasureSpec(secondarySpec, heightUsed, lp.height);
-        } else {
-            heightSpec = ViewGroup.getChildMeasureSpec(
-                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightUsed, lp.height);
-            widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, widthUsed, lp.width);
-        }
-        child.measure(widthSpec, heightSpec);
-        if (DEBUG) {
-            Log.v(getTag(), "measureChild secondarySpec " + Integer.toHexString(secondarySpec)
-                    + " widthSpec " + Integer.toHexString(widthSpec)
-                    + " heightSpec " + Integer.toHexString(heightSpec)
-                    + " measuredWidth " + child.getMeasuredWidth()
-                    + " measuredHeight " + child.getMeasuredHeight());
-        }
-        if (DEBUG) Log.v(getTag(), "child lp width " + lp.width + " height " + lp.height);
-        if (TRACE) TraceCompat.endSection();
-    }
-
-    /**
-     * Get facet from the ViewHolder or the viewType.
-     */
-    <E> E getFacet(RecyclerView.ViewHolder vh, Class<? extends E> facetClass) {
-        E facet = null;
-        if (vh instanceof FacetProvider) {
-            facet = (E) ((FacetProvider) vh).getFacet(facetClass);
-        }
-        if (facet == null && mFacetProviderAdapter != null) {
-            FacetProvider p = mFacetProviderAdapter.getFacetProvider(vh.getItemViewType());
-            if (p != null) {
-                facet = (E) p.getFacet(facetClass);
-            }
-        }
-        return facet;
-    }
-
-    private Grid.Provider mGridProvider = new Grid.Provider() {
-
-        @Override
-        public int getMinIndex() {
-            return mPositionDeltaInPreLayout;
-        }
-
-        @Override
-        public int getCount() {
-            return mState.getItemCount() + mPositionDeltaInPreLayout;
-        }
-
-        @Override
-        public int createItem(int index, boolean append, Object[] item, boolean disappearingItem) {
-            if (TRACE) TraceCompat.beginSection("createItem");
-            if (TRACE) TraceCompat.beginSection("getview");
-            View v = getViewForPosition(index - mPositionDeltaInPreLayout);
-            if (TRACE) TraceCompat.endSection();
-            LayoutParams lp = (LayoutParams) v.getLayoutParams();
-            RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(v);
-            lp.setItemAlignmentFacet((ItemAlignmentFacet)getFacet(vh, ItemAlignmentFacet.class));
-            // See recyclerView docs:  we don't need re-add scraped view if it was removed.
-            if (!lp.isItemRemoved()) {
-                if (TRACE) TraceCompat.beginSection("addView");
-                if (disappearingItem) {
-                    if (append) {
-                        addDisappearingView(v);
-                    } else {
-                        addDisappearingView(v, 0);
-                    }
-                } else {
-                    if (append) {
-                        addView(v);
-                    } else {
-                        addView(v, 0);
-                    }
-                }
-                if (TRACE) TraceCompat.endSection();
-                if (mChildVisibility != -1) {
-                    v.setVisibility(mChildVisibility);
-                }
-
-                if (mPendingMoveSmoothScroller != null) {
-                    mPendingMoveSmoothScroller.consumePendingMovesBeforeLayout();
-                }
-                int subindex = getSubPositionByView(v, v.findFocus());
-                if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT) {
-                    // when we are appending item during scroll pass and the item's position
-                    // matches the mFocusPosition,  we should signal a childSelected event.
-                    // However if we are still running PendingMoveSmoothScroller,  we defer and
-                    // signal the event in PendingMoveSmoothScroller.onStop().  This can
-                    // avoid lots of childSelected events during a long smooth scrolling and
-                    // increase performance.
-                    if (index == mFocusPosition && subindex == mSubFocusPosition
-                            && mPendingMoveSmoothScroller == null) {
-                        dispatchChildSelected();
-                    }
-                } else if ((mFlag & PF_FAST_RELAYOUT) == 0) {
-                    // fastRelayout will dispatch event at end of onLayoutChildren().
-                    // For full layout, two situations here:
-                    // 1. mInLayoutSearchFocus is false, dispatchChildSelected() at mFocusPosition.
-                    // 2. mInLayoutSearchFocus is true:  dispatchChildSelected() on first child
-                    //    equal to or after mFocusPosition that can take focus.
-                    if ((mFlag & PF_IN_LAYOUT_SEARCH_FOCUS) == 0 && index == mFocusPosition
-                            && subindex == mSubFocusPosition) {
-                        dispatchChildSelected();
-                    } else if ((mFlag & PF_IN_LAYOUT_SEARCH_FOCUS) != 0 && index >= mFocusPosition
-                            && v.hasFocusable()) {
-                        mFocusPosition = index;
-                        mSubFocusPosition = subindex;
-                        mFlag &= ~PF_IN_LAYOUT_SEARCH_FOCUS;
-                        dispatchChildSelected();
-                    }
-                }
-                measureChild(v);
-            }
-            item[0] = v;
-            return mOrientation == HORIZONTAL ? getDecoratedMeasuredWidthWithMargin(v)
-                    : getDecoratedMeasuredHeightWithMargin(v);
-        }
-
-        @Override
-        public void addItem(Object item, int index, int length, int rowIndex, int edge) {
-            View v = (View) item;
-            int start, end;
-            if (edge == Integer.MIN_VALUE || edge == Integer.MAX_VALUE) {
-                edge = !mGrid.isReversedFlow() ? mWindowAlignment.mainAxis().getPaddingMin()
-                        : mWindowAlignment.mainAxis().getSize()
-                                - mWindowAlignment.mainAxis().getPaddingMax();
-            }
-            boolean edgeIsMin = !mGrid.isReversedFlow();
-            if (edgeIsMin) {
-                start = edge;
-                end = edge + length;
-            } else {
-                start = edge - length;
-                end = edge;
-            }
-            int startSecondary = getRowStartSecondary(rowIndex)
-                    + mWindowAlignment.secondAxis().getPaddingMin() - mScrollOffsetSecondary;
-            mChildrenStates.loadView(v, index);
-            layoutChild(rowIndex, v, start, end, startSecondary);
-            if (DEBUG) {
-                Log.d(getTag(), "addView " + index + " " + v);
-            }
-            if (TRACE) TraceCompat.endSection();
-
-            if (!mState.isPreLayout()) {
-                updateScrollLimits();
-            }
-            if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT && mPendingMoveSmoothScroller != null) {
-                mPendingMoveSmoothScroller.consumePendingMovesAfterLayout();
-            }
-            if (mChildLaidOutListener != null) {
-                RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(v);
-                mChildLaidOutListener.onChildLaidOut(mBaseGridView, v, index,
-                        vh == null ? NO_ID : vh.getItemId());
-            }
-        }
-
-        @Override
-        public void removeItem(int index) {
-            if (TRACE) TraceCompat.beginSection("removeItem");
-            View v = findViewByPosition(index - mPositionDeltaInPreLayout);
-            if ((mFlag & PF_STAGE_MASK) == PF_STAGE_LAYOUT) {
-                detachAndScrapView(v, mRecycler);
-            } else {
-                removeAndRecycleView(v, mRecycler);
-            }
-            if (TRACE) TraceCompat.endSection();
-        }
-
-        @Override
-        public int getEdge(int index) {
-            View v = findViewByPosition(index - mPositionDeltaInPreLayout);
-            return (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0 ? getViewMax(v) : getViewMin(v);
-        }
-
-        @Override
-        public int getSize(int index) {
-            return getViewPrimarySize(findViewByPosition(index - mPositionDeltaInPreLayout));
-        }
-    };
-
-    void layoutChild(int rowIndex, View v, int start, int end, int startSecondary) {
-        if (TRACE) TraceCompat.beginSection("layoutChild");
-        int sizeSecondary = mOrientation == HORIZONTAL ? getDecoratedMeasuredHeightWithMargin(v)
-                : getDecoratedMeasuredWidthWithMargin(v);
-        if (mFixedRowSizeSecondary > 0) {
-            sizeSecondary = Math.min(sizeSecondary, mFixedRowSizeSecondary);
-        }
-        final int verticalGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
-        final int horizontalGravity = (mFlag & PF_REVERSE_FLOW_MASK) != 0
-                ? 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)) {
-            // do nothing
-        } 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)) {
-            startSecondary += (getRowSizeSecondary(rowIndex) - sizeSecondary) / 2;
-        }
-        int left, top, right, bottom;
-        if (mOrientation == HORIZONTAL) {
-            left = start;
-            top = startSecondary;
-            right = end;
-            bottom = startSecondary + sizeSecondary;
-        } else {
-            top = start;
-            left = startSecondary;
-            bottom = end;
-            right = startSecondary + sizeSecondary;
-        }
-        LayoutParams params = (LayoutParams) v.getLayoutParams();
-        layoutDecoratedWithMargins(v, left, top, right, bottom);
-        // Now super.getDecoratedBoundsWithMargins() includes the extra space for optical bounds,
-        // subtracting it from value passed in layoutDecoratedWithMargins(), we can get the optical
-        // bounds insets.
-        super.getDecoratedBoundsWithMargins(v, sTempRect);
-        params.setOpticalInsets(left - sTempRect.left, top - sTempRect.top,
-                sTempRect.right - right, sTempRect.bottom - bottom);
-        updateChildAlignments(v);
-        if (TRACE) TraceCompat.endSection();
-    }
-
-    private void updateChildAlignments(View v) {
-        final LayoutParams p = (LayoutParams) v.getLayoutParams();
-        if (p.getItemAlignmentFacet() == null) {
-            // Fallback to global settings on grid view
-            p.setAlignX(mItemAlignment.horizontal.getAlignmentPosition(v));
-            p.setAlignY(mItemAlignment.vertical.getAlignmentPosition(v));
-        } else {
-            // Use ItemAlignmentFacet defined on specific ViewHolder
-            p.calculateItemAlignments(mOrientation, v);
-            if (mOrientation == HORIZONTAL) {
-                p.setAlignY(mItemAlignment.vertical.getAlignmentPosition(v));
-            } else {
-                p.setAlignX(mItemAlignment.horizontal.getAlignmentPosition(v));
-            }
-        }
-    }
-
-    private void updateChildAlignments() {
-        for (int i = 0, c = getChildCount(); i < c; i++) {
-            updateChildAlignments(getChildAt(i));
-        }
-    }
-
-    void setExtraLayoutSpace(int extraLayoutSpace) {
-        if (mExtraLayoutSpace == extraLayoutSpace) {
-            return;
-        } else if (mExtraLayoutSpace < 0) {
-            throw new IllegalArgumentException("ExtraLayoutSpace must >= 0");
-        }
-        mExtraLayoutSpace = extraLayoutSpace;
-        requestLayout();
-    }
-
-    int getExtraLayoutSpace() {
-        return mExtraLayoutSpace;
-    }
-
-    private void removeInvisibleViewsAtEnd() {
-        if ((mFlag & (PF_PRUNE_CHILD | PF_SLIDING)) == PF_PRUNE_CHILD) {
-            mGrid.removeInvisibleItemsAtEnd(mFocusPosition, (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
-                    ? -mExtraLayoutSpace : mSizePrimary + mExtraLayoutSpace);
-        }
-    }
-
-    private void removeInvisibleViewsAtFront() {
-        if ((mFlag & (PF_PRUNE_CHILD | PF_SLIDING)) == PF_PRUNE_CHILD) {
-            mGrid.removeInvisibleItemsAtFront(mFocusPosition, (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
-                    ? mSizePrimary + mExtraLayoutSpace : -mExtraLayoutSpace);
-        }
-    }
-
-    private boolean appendOneColumnVisibleItems() {
-        return mGrid.appendOneColumnVisibleItems();
-    }
-
-    void slideIn() {
-        if ((mFlag & PF_SLIDING) != 0) {
-            mFlag &= ~PF_SLIDING;
-            if (mFocusPosition >= 0) {
-                scrollToSelection(mFocusPosition, mSubFocusPosition, true, mPrimaryScrollExtra);
-            } else {
-                mFlag &= ~PF_LAYOUT_EATEN_IN_SLIDING;
-                requestLayout();
-            }
-            if ((mFlag & PF_LAYOUT_EATEN_IN_SLIDING) != 0) {
-                mFlag &= ~PF_LAYOUT_EATEN_IN_SLIDING;
-                if (mBaseGridView.getScrollState() != SCROLL_STATE_IDLE || isSmoothScrolling()) {
-                    mBaseGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-                        @Override
-                        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                            if (newState == SCROLL_STATE_IDLE) {
-                                mBaseGridView.removeOnScrollListener(this);
-                                requestLayout();
-                            }
-                        }
-                    });
-                } else {
-                    requestLayout();
-                }
-            }
-        }
-    }
-
-    int getSlideOutDistance() {
-        int distance;
-        if (mOrientation == VERTICAL) {
-            distance = -getHeight();
-            if (getChildCount() > 0) {
-                int top = getChildAt(0).getTop();
-                if (top < 0) {
-                    // scroll more if first child is above top edge
-                    distance = distance + top;
-                }
-            }
-        } else {
-            if ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0) {
-                distance = getWidth();
-                if (getChildCount() > 0) {
-                    int start = getChildAt(0).getRight();
-                    if (start > distance) {
-                        // scroll more if first child is outside right edge
-                        distance = start;
-                    }
-                }
-            } else {
-                distance = -getWidth();
-                if (getChildCount() > 0) {
-                    int start = getChildAt(0).getLeft();
-                    if (start < 0) {
-                        // scroll more if first child is out side left edge
-                        distance = distance + start;
-                    }
-                }
-            }
-        }
-        return distance;
-    }
-
-    boolean isSlidingChildViews() {
-        return (mFlag & PF_SLIDING) != 0;
-    }
-
-    /**
-     * Temporarily slide out child and block layout and scroll requests.
-     */
-    void slideOut() {
-        if ((mFlag & PF_SLIDING) != 0) {
-            return;
-        }
-        mFlag |= PF_SLIDING;
-        if (getChildCount() == 0) {
-            return;
-        }
-        if (mOrientation == VERTICAL) {
-            mBaseGridView.smoothScrollBy(0, getSlideOutDistance(),
-                    new AccelerateDecelerateInterpolator());
-        } else {
-            mBaseGridView.smoothScrollBy(getSlideOutDistance(), 0,
-                    new AccelerateDecelerateInterpolator());
-        }
-    }
-
-    private boolean prependOneColumnVisibleItems() {
-        return mGrid.prependOneColumnVisibleItems();
-    }
-
-    private void appendVisibleItems() {
-        mGrid.appendVisibleItems((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
-                ? -mExtraLayoutSpace - mExtraLayoutSpaceInPreLayout
-                : mSizePrimary + mExtraLayoutSpace + mExtraLayoutSpaceInPreLayout);
-    }
-
-    private void prependVisibleItems() {
-        mGrid.prependVisibleItems((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
-                ? mSizePrimary + mExtraLayoutSpace + mExtraLayoutSpaceInPreLayout
-                : -mExtraLayoutSpace - mExtraLayoutSpaceInPreLayout);
-    }
-
-    /**
-     * Fast layout when there is no structure change, adapter change, etc.
-     * It will layout all views was layout requested or updated, until hit a view
-     * with different size,  then it break and detachAndScrap all views after that.
-     */
-    private void fastRelayout() {
-        boolean invalidateAfter = false;
-        final int childCount = getChildCount();
-        int position = mGrid.getFirstVisibleIndex();
-        int index = 0;
-        mFlag &= ~PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION;
-        for (; index < childCount; index++, position++) {
-            View view = getChildAt(index);
-            // We don't hit fastRelayout() if State.didStructure() is true, but prelayout may add
-            // extra views and invalidate existing Grid position. Also the prelayout calling
-            // getViewForPosotion() may retrieve item from cache with FLAG_INVALID. The adapter
-            // postion will be -1 for this case. Either case, we should invalidate after this item
-            // and call getViewForPosition() again to rebind.
-            if (position != getAdapterPositionByView(view)) {
-                invalidateAfter = true;
-                break;
-            }
-            Grid.Location location = mGrid.getLocation(position);
-            if (location == null) {
-                invalidateAfter = true;
-                break;
-            }
-
-            int startSecondary = getRowStartSecondary(location.row)
-                    + mWindowAlignment.secondAxis().getPaddingMin() - mScrollOffsetSecondary;
-            int primarySize, end;
-            int start = getViewMin(view);
-            int oldPrimarySize = getViewPrimarySize(view);
-
-            LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            if (lp.viewNeedsUpdate()) {
-                mFlag |= PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION;
-                detachAndScrapView(view, mRecycler);
-                view = getViewForPosition(position);
-                addView(view, index);
-            }
-
-            measureChild(view);
-            if (mOrientation == HORIZONTAL) {
-                primarySize = getDecoratedMeasuredWidthWithMargin(view);
-                end = start + primarySize;
-            } else {
-                primarySize = getDecoratedMeasuredHeightWithMargin(view);
-                end = start + primarySize;
-            }
-            layoutChild(location.row, view, start, end, startSecondary);
-            if (oldPrimarySize != primarySize) {
-                // size changed invalidate remaining Locations
-                if (DEBUG) Log.d(getTag(), "fastRelayout: view size changed at " + position);
-                invalidateAfter = true;
-                break;
-            }
-        }
-        if (invalidateAfter) {
-            final int savedLastPos = mGrid.getLastVisibleIndex();
-            for (int i = childCount - 1; i >= index; i--) {
-                View v = getChildAt(i);
-                detachAndScrapView(v, mRecycler);
-            }
-            mGrid.invalidateItemsAfter(position);
-            if ((mFlag & PF_PRUNE_CHILD) != 0) {
-                // in regular prune child mode, we just append items up to edge limit
-                appendVisibleItems();
-                if (mFocusPosition >= 0 && mFocusPosition <= savedLastPos) {
-                    // make sure add focus view back:  the view might be outside edge limit
-                    // when there is delta in onLayoutChildren().
-                    while (mGrid.getLastVisibleIndex() < mFocusPosition) {
-                        mGrid.appendOneColumnVisibleItems();
-                    }
-                }
-            } else {
-                // prune disabled(e.g. in RowsFragment transition): append all removed items
-                while (mGrid.appendOneColumnVisibleItems()
-                        && mGrid.getLastVisibleIndex() < savedLastPos);
-            }
-        }
-        updateScrollLimits();
-        updateSecondaryScrollLimits();
-    }
-
-    @Override
-    public void removeAndRecycleAllViews(RecyclerView.Recycler recycler) {
-        if (TRACE) TraceCompat.beginSection("removeAndRecycleAllViews");
-        if (DEBUG) Log.v(TAG, "removeAndRecycleAllViews " + getChildCount());
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            removeAndRecycleViewAt(i, recycler);
-        }
-        if (TRACE) TraceCompat.endSection();
-    }
-
-    // called by onLayoutChildren, either focus to FocusPosition or declare focusViewAvailable
-    // and scroll to the view if framework focus on it.
-    private void focusToViewInLayout(boolean hadFocus, boolean alignToView, int extraDelta,
-            int extraDeltaSecondary) {
-        View focusView = findViewByPosition(mFocusPosition);
-        if (focusView != null && alignToView) {
-            scrollToView(focusView, false, extraDelta, extraDeltaSecondary);
-        }
-        if (focusView != null && hadFocus && !focusView.hasFocus()) {
-            focusView.requestFocus();
-        } else if (!hadFocus && !mBaseGridView.hasFocus()) {
-            if (focusView != null && focusView.hasFocusable()) {
-                mBaseGridView.focusableViewAvailable(focusView);
-            } else {
-                for (int i = 0, count = getChildCount(); i < count; i++) {
-                    focusView = getChildAt(i);
-                    if (focusView != null && focusView.hasFocusable()) {
-                        mBaseGridView.focusableViewAvailable(focusView);
-                        break;
-                    }
-                }
-            }
-            // focusViewAvailable() might focus to the view, scroll to it if that is the case.
-            if (alignToView && focusView != null && focusView.hasFocus()) {
-                scrollToView(focusView, false, extraDelta, extraDeltaSecondary);
-            }
-        }
-    }
-
-    @VisibleForTesting
-    public static class OnLayoutCompleteListener {
-        public void onLayoutCompleted(RecyclerView.State state) {
-        }
-    }
-
-    @VisibleForTesting
-    OnLayoutCompleteListener mLayoutCompleteListener;
-
-    @Override
-    public void onLayoutCompleted(State state) {
-        if (mLayoutCompleteListener != null) {
-            mLayoutCompleteListener.onLayoutCompleted(state);
-        }
-    }
-
-    @Override
-    public boolean supportsPredictiveItemAnimations() {
-        return true;
-    }
-
-    void updatePositionToRowMapInPostLayout() {
-        mPositionToRowInPostLayout.clear();
-        final int childCount = getChildCount();
-        for (int i = 0;  i < childCount; i++) {
-            // Grid still maps to old positions at this point, use old position to get row infor
-            int position = mBaseGridView.getChildViewHolder(getChildAt(i)).getOldPosition();
-            if (position >= 0) {
-                Grid.Location loc = mGrid.getLocation(position);
-                if (loc != null) {
-                    mPositionToRowInPostLayout.put(position, loc.row);
-                }
-            }
-        }
-    }
-
-    void fillScrapViewsInPostLayout() {
-        List<RecyclerView.ViewHolder> scrapList = mRecycler.getScrapList();
-        final int scrapSize = scrapList.size();
-        if (scrapSize == 0) {
-            return;
-        }
-        // initialize the int array or re-allocate the array.
-        if (mDisappearingPositions == null  || scrapSize > mDisappearingPositions.length) {
-            int length = mDisappearingPositions == null ? 16 : mDisappearingPositions.length;
-            while (length < scrapSize) {
-                length = length << 1;
-            }
-            mDisappearingPositions = new int[length];
-        }
-        int totalItems = 0;
-        for (int i = 0; i < scrapSize; i++) {
-            int pos = scrapList.get(i).getAdapterPosition();
-            if (pos >= 0) {
-                mDisappearingPositions[totalItems++] = pos;
-            }
-        }
-        // totalItems now has the length of disappearing items
-        if (totalItems > 0) {
-            Arrays.sort(mDisappearingPositions, 0, totalItems);
-            mGrid.fillDisappearingItems(mDisappearingPositions, totalItems,
-                    mPositionToRowInPostLayout);
-        }
-        mPositionToRowInPostLayout.clear();
-    }
-
-    // in prelayout, first child's getViewPosition can be smaller than old adapter position
-    // if there were items removed before first visible index. For example:
-    // visible items are 3, 4, 5, 6, deleting 1, 2, 3 from adapter; the view position in
-    // prelayout are not 3(deleted), 4, 5, 6. Instead it's 1(deleted), 2, 3, 4.
-    // So there is a delta (2 in this case) between last cached position and prelayout position.
-    void updatePositionDeltaInPreLayout() {
-        if (getChildCount() > 0) {
-            View view = getChildAt(0);
-            LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            mPositionDeltaInPreLayout = mGrid.getFirstVisibleIndex()
-                    - lp.getViewLayoutPosition();
-        } else {
-            mPositionDeltaInPreLayout = 0;
-        }
-    }
-
-    // Lays out items based on the current scroll position
-    @Override
-    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-        if (DEBUG) {
-            Log.v(getTag(), "layoutChildren start numRows " + mNumRows
-                    + " inPreLayout " + state.isPreLayout()
-                    + " didStructureChange " + state.didStructureChange()
-                    + " mForceFullLayout " + ((mFlag & PF_FORCE_FULL_LAYOUT) != 0));
-            Log.v(getTag(), "width " + getWidth() + " height " + getHeight());
-        }
-
-        if (mNumRows == 0) {
-            // haven't done measure yet
-            return;
-        }
-        final int itemCount = state.getItemCount();
-        if (itemCount < 0) {
-            return;
-        }
-
-        if ((mFlag & PF_SLIDING) != 0) {
-            // if there is already children, delay the layout process until slideIn(), if it's
-            // first time layout children: scroll them offscreen at end of onLayoutChildren()
-            if (getChildCount() > 0) {
-                mFlag |= PF_LAYOUT_EATEN_IN_SLIDING;
-                return;
-            }
-        }
-        if ((mFlag & PF_LAYOUT_ENABLED) == 0) {
-            discardLayoutInfo();
-            removeAndRecycleAllViews(recycler);
-            return;
-        }
-        mFlag = (mFlag & ~PF_STAGE_MASK) | PF_STAGE_LAYOUT;
-
-        saveContext(recycler, state);
-        if (state.isPreLayout()) {
-            updatePositionDeltaInPreLayout();
-            int childCount = getChildCount();
-            if (mGrid != null && childCount > 0) {
-                int minChangedEdge = Integer.MAX_VALUE;
-                int maxChangeEdge = Integer.MIN_VALUE;
-                int minOldAdapterPosition = mBaseGridView.getChildViewHolder(
-                        getChildAt(0)).getOldPosition();
-                int maxOldAdapterPosition = mBaseGridView.getChildViewHolder(
-                        getChildAt(childCount - 1)).getOldPosition();
-                for (int i = 0; i < childCount; i++) {
-                    View view = getChildAt(i);
-                    LayoutParams lp = (LayoutParams) view.getLayoutParams();
-                    int newAdapterPosition = mBaseGridView.getChildAdapterPosition(view);
-                    // if either of following happening
-                    // 1. item itself has changed or layout parameter changed
-                    // 2. item is losing focus
-                    // 3. item is gaining focus
-                    // 4. item is moved out of old adapter position range.
-                    if (lp.isItemChanged() || lp.isItemRemoved() || view.isLayoutRequested()
-                            || (!view.hasFocus() && mFocusPosition == lp.getViewAdapterPosition())
-                            || (view.hasFocus() && mFocusPosition != lp.getViewAdapterPosition())
-                            || newAdapterPosition < minOldAdapterPosition
-                            || newAdapterPosition > maxOldAdapterPosition) {
-                        minChangedEdge = Math.min(minChangedEdge, getViewMin(view));
-                        maxChangeEdge = Math.max(maxChangeEdge, getViewMax(view));
-                    }
-                }
-                if (maxChangeEdge > minChangedEdge) {
-                    mExtraLayoutSpaceInPreLayout = maxChangeEdge - minChangedEdge;
-                }
-                // append items for mExtraLayoutSpaceInPreLayout
-                appendVisibleItems();
-                prependVisibleItems();
-            }
-            mFlag &= ~PF_STAGE_MASK;
-            leaveContext();
-            if (DEBUG) Log.v(getTag(), "layoutChildren end");
-            return;
-        }
-
-        // save all view's row information before detach all views
-        if (state.willRunPredictiveAnimations()) {
-            updatePositionToRowMapInPostLayout();
-        }
-        // check if we need align to mFocusPosition, this is usually true unless in smoothScrolling
-        final boolean scrollToFocus = !isSmoothScrolling()
-                && mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_ALIGNED;
-        if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE) {
-            mFocusPosition = mFocusPosition + mFocusPositionOffset;
-            mSubFocusPosition = 0;
-        }
-        mFocusPositionOffset = 0;
-
-        View savedFocusView = findViewByPosition(mFocusPosition);
-        int savedFocusPos = mFocusPosition;
-        int savedSubFocusPos = mSubFocusPosition;
-        boolean hadFocus = mBaseGridView.hasFocus();
-        final int firstVisibleIndex = mGrid != null ? mGrid.getFirstVisibleIndex() : NO_POSITION;
-        final int lastVisibleIndex = mGrid != null ? mGrid.getLastVisibleIndex() : NO_POSITION;
-        final int deltaPrimary;
-        final int deltaSecondary;
-        if (mOrientation == HORIZONTAL) {
-            deltaPrimary = state.getRemainingScrollHorizontal();
-            deltaSecondary = state.getRemainingScrollVertical();
-        } else {
-            deltaSecondary = state.getRemainingScrollHorizontal();
-            deltaPrimary = state.getRemainingScrollVertical();
-        }
-        if (layoutInit()) {
-            mFlag |= PF_FAST_RELAYOUT;
-            // If grid view is empty, we will start from mFocusPosition
-            mGrid.setStart(mFocusPosition);
-            fastRelayout();
-        } else {
-            mFlag &= ~PF_FAST_RELAYOUT;
-            // layoutInit() has detached all views, so start from scratch
-            mFlag = (mFlag & ~PF_IN_LAYOUT_SEARCH_FOCUS)
-                    | (hadFocus ? PF_IN_LAYOUT_SEARCH_FOCUS : 0);
-            int startFromPosition, endPos;
-            if (scrollToFocus && (firstVisibleIndex < 0 || mFocusPosition > lastVisibleIndex
-                    || mFocusPosition < firstVisibleIndex)) {
-                startFromPosition = endPos = mFocusPosition;
-            } else {
-                startFromPosition = firstVisibleIndex;
-                endPos = lastVisibleIndex;
-            }
-            mGrid.setStart(startFromPosition);
-            if (endPos != NO_POSITION) {
-                while (appendOneColumnVisibleItems() && findViewByPosition(endPos) == null) {
-                    // continuously append items until endPos
-                }
-            }
-        }
-        // multiple rounds: scrollToView of first round may drag first/last child into
-        // "visible window" and we update scrollMin/scrollMax then run second scrollToView
-        // we must do this for fastRelayout() for the append item case
-        int oldFirstVisible;
-        int oldLastVisible;
-        do {
-            updateScrollLimits();
-            oldFirstVisible = mGrid.getFirstVisibleIndex();
-            oldLastVisible = mGrid.getLastVisibleIndex();
-            focusToViewInLayout(hadFocus, scrollToFocus, -deltaPrimary, -deltaSecondary);
-            appendVisibleItems();
-            prependVisibleItems();
-            // b/67370222: do not removeInvisibleViewsAtFront/End() in the loop, otherwise
-            // loop may bounce between scroll forward and scroll backward forever. Example:
-            // Assuming there are 19 items, child#18 and child#19 are both in RV, we are
-            // trying to focus to child#18 and there are 200px remaining scroll distance.
-            //   1  focusToViewInLayout() tries scroll forward 50 px to align focused child#18 on
-            //      right edge, but there to compensate remaining scroll 200px, also scroll
-            //      backward 200px, 150px pushes last child#19 out side of right edge.
-            //   2  removeInvisibleViewsAtEnd() remove last child#19, updateScrollLimits()
-            //      invalidates scroll max
-            //   3  In next iteration, when scroll max/min is unknown, focusToViewInLayout() will
-            //      align focused child#18 at center of screen.
-            //   4  Because #18 is aligned at center, appendVisibleItems() will fill child#19 to
-            //      the right.
-            //   5  (back to 1 and loop forever)
-        } while (mGrid.getFirstVisibleIndex() != oldFirstVisible
-                || mGrid.getLastVisibleIndex() != oldLastVisible);
-        removeInvisibleViewsAtFront();
-        removeInvisibleViewsAtEnd();
-
-        if (state.willRunPredictiveAnimations()) {
-            fillScrapViewsInPostLayout();
-        }
-
-        if (DEBUG) {
-            StringWriter sw = new StringWriter();
-            PrintWriter pw = new PrintWriter(sw);
-            mGrid.debugPrint(pw);
-            Log.d(getTag(), sw.toString());
-        }
-
-        if ((mFlag & PF_ROW_SECONDARY_SIZE_REFRESH) != 0) {
-            mFlag &= ~PF_ROW_SECONDARY_SIZE_REFRESH;
-        } else {
-            updateRowSecondarySizeRefresh();
-        }
-
-        // For fastRelayout, only dispatch event when focus position changes or selected item
-        // being updated.
-        if ((mFlag & PF_FAST_RELAYOUT) != 0 && (mFocusPosition != savedFocusPos || mSubFocusPosition
-                != savedSubFocusPos || findViewByPosition(mFocusPosition) != savedFocusView
-                || (mFlag & PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION) != 0)) {
-            dispatchChildSelected();
-        } else if ((mFlag & (PF_FAST_RELAYOUT | PF_IN_LAYOUT_SEARCH_FOCUS))
-                == PF_IN_LAYOUT_SEARCH_FOCUS) {
-            // For full layout we dispatchChildSelected() in createItem() unless searched all
-            // children and found none is focusable then dispatchChildSelected() here.
-            dispatchChildSelected();
-        }
-        dispatchChildSelectedAndPositioned();
-        if ((mFlag & PF_SLIDING) != 0) {
-            scrollDirectionPrimary(getSlideOutDistance());
-        }
-
-        mFlag &= ~PF_STAGE_MASK;
-        leaveContext();
-        if (DEBUG) Log.v(getTag(), "layoutChildren end");
-    }
-
-    private void offsetChildrenSecondary(int increment) {
-        final int childCount = getChildCount();
-        if (mOrientation == HORIZONTAL) {
-            for (int i = 0; i < childCount; i++) {
-                getChildAt(i).offsetTopAndBottom(increment);
-            }
-        } else {
-            for (int i = 0; i < childCount; i++) {
-                getChildAt(i).offsetLeftAndRight(increment);
-            }
-        }
-    }
-
-    private void offsetChildrenPrimary(int increment) {
-        final int childCount = getChildCount();
-        if (mOrientation == VERTICAL) {
-            for (int i = 0; i < childCount; i++) {
-                getChildAt(i).offsetTopAndBottom(increment);
-            }
-        } else {
-            for (int i = 0; i < childCount; i++) {
-                getChildAt(i).offsetLeftAndRight(increment);
-            }
-        }
-    }
-
-    @Override
-    public int scrollHorizontallyBy(int dx, Recycler recycler, RecyclerView.State state) {
-        if (DEBUG) Log.v(getTag(), "scrollHorizontallyBy " + dx);
-        if ((mFlag & PF_LAYOUT_ENABLED) == 0 || !hasDoneFirstLayout()) {
-            return 0;
-        }
-        saveContext(recycler, state);
-        mFlag = (mFlag & ~PF_STAGE_MASK) | PF_STAGE_SCROLL;
-        int result;
-        if (mOrientation == HORIZONTAL) {
-            result = scrollDirectionPrimary(dx);
-        } else {
-            result = scrollDirectionSecondary(dx);
-        }
-        leaveContext();
-        mFlag &= ~PF_STAGE_MASK;
-        return result;
-    }
-
-    @Override
-    public int scrollVerticallyBy(int dy, Recycler recycler, RecyclerView.State state) {
-        if (DEBUG) Log.v(getTag(), "scrollVerticallyBy " + dy);
-        if ((mFlag & PF_LAYOUT_ENABLED) == 0 || !hasDoneFirstLayout()) {
-            return 0;
-        }
-        mFlag = (mFlag & ~PF_STAGE_MASK) | PF_STAGE_SCROLL;
-        saveContext(recycler, state);
-        int result;
-        if (mOrientation == VERTICAL) {
-            result = scrollDirectionPrimary(dy);
-        } else {
-            result = scrollDirectionSecondary(dy);
-        }
-        leaveContext();
-        mFlag &= ~PF_STAGE_MASK;
-        return result;
-    }
-
-    // scroll in main direction may add/prune views
-    private int scrollDirectionPrimary(int da) {
-        if (TRACE) TraceCompat.beginSection("scrollPrimary");
-        // We apply the cap of maxScroll/minScroll to the delta, except for two cases:
-        // 1. when children are in sliding out mode
-        // 2. During onLayoutChildren(), it may compensate the remaining scroll delta,
-        //    we should honor the request regardless if it goes over minScroll / maxScroll.
-        //    (see b/64931938 testScrollAndRemove and testScrollAndRemoveSample1)
-        if ((mFlag & PF_SLIDING) == 0 && (mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT) {
-            if (da > 0) {
-                if (!mWindowAlignment.mainAxis().isMaxUnknown()) {
-                    int maxScroll = mWindowAlignment.mainAxis().getMaxScroll();
-                    if (da > maxScroll) {
-                        da = maxScroll;
-                    }
-                }
-            } else if (da < 0) {
-                if (!mWindowAlignment.mainAxis().isMinUnknown()) {
-                    int minScroll = mWindowAlignment.mainAxis().getMinScroll();
-                    if (da < minScroll) {
-                        da = minScroll;
-                    }
-                }
-            }
-        }
-        if (da == 0) {
-            if (TRACE) TraceCompat.endSection();
-            return 0;
-        }
-        offsetChildrenPrimary(-da);
-        if ((mFlag & PF_STAGE_MASK) == PF_STAGE_LAYOUT) {
-            updateScrollLimits();
-            if (TRACE) TraceCompat.endSection();
-            return da;
-        }
-
-        int childCount = getChildCount();
-        boolean updated;
-
-        if ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0 ? da > 0 : da < 0) {
-            prependVisibleItems();
-        } else {
-            appendVisibleItems();
-        }
-        updated = getChildCount() > childCount;
-        childCount = getChildCount();
-
-        if (TRACE) TraceCompat.beginSection("remove");
-        if ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0 ? da > 0 : da < 0) {
-            removeInvisibleViewsAtEnd();
-        } else {
-            removeInvisibleViewsAtFront();
-        }
-        if (TRACE) TraceCompat.endSection();
-        updated |= getChildCount() < childCount;
-        if (updated) {
-            updateRowSecondarySizeRefresh();
-        }
-
-        mBaseGridView.invalidate();
-        updateScrollLimits();
-        if (TRACE) TraceCompat.endSection();
-        return da;
-    }
-
-    // scroll in second direction will not add/prune views
-    private int scrollDirectionSecondary(int dy) {
-        if (dy == 0) {
-            return 0;
-        }
-        offsetChildrenSecondary(-dy);
-        mScrollOffsetSecondary += dy;
-        updateSecondaryScrollLimits();
-        mBaseGridView.invalidate();
-        return dy;
-    }
-
-    @Override
-    public void collectAdjacentPrefetchPositions(int dx, int dy, State state,
-            LayoutPrefetchRegistry layoutPrefetchRegistry) {
-        try {
-            saveContext(null, state);
-            int da = (mOrientation == HORIZONTAL) ? dx : dy;
-            if (getChildCount() == 0 || da == 0) {
-                // can't support this scroll, so don't bother prefetching
-                return;
-            }
-
-            int fromLimit = da < 0
-                    ? -mExtraLayoutSpace
-                    : mSizePrimary + mExtraLayoutSpace;
-            mGrid.collectAdjacentPrefetchPositions(fromLimit, da, layoutPrefetchRegistry);
-        } finally {
-            leaveContext();
-        }
-    }
-
-    @Override
-    public void collectInitialPrefetchPositions(int adapterItemCount,
-            LayoutPrefetchRegistry layoutPrefetchRegistry) {
-        int numToPrefetch = mBaseGridView.mInitialPrefetchItemCount;
-        if (adapterItemCount != 0 && numToPrefetch != 0) {
-            // prefetch items centered around mFocusPosition
-            int initialPos = Math.max(0, Math.min(mFocusPosition - (numToPrefetch - 1)/ 2,
-                    adapterItemCount - numToPrefetch));
-            for (int i = initialPos; i < adapterItemCount && i < initialPos + numToPrefetch; i++) {
-                layoutPrefetchRegistry.addPosition(i, 0);
-            }
-        }
-    }
-
-    void updateScrollLimits() {
-        if (mState.getItemCount() == 0) {
-            return;
-        }
-        int highVisiblePos, lowVisiblePos;
-        int highMaxPos, lowMinPos;
-        if ((mFlag & PF_REVERSE_FLOW_PRIMARY) == 0) {
-            highVisiblePos = mGrid.getLastVisibleIndex();
-            highMaxPos = mState.getItemCount() - 1;
-            lowVisiblePos = mGrid.getFirstVisibleIndex();
-            lowMinPos = 0;
-        } else {
-            highVisiblePos = mGrid.getFirstVisibleIndex();
-            highMaxPos = 0;
-            lowVisiblePos = mGrid.getLastVisibleIndex();
-            lowMinPos = mState.getItemCount() - 1;
-        }
-        if (highVisiblePos < 0 || lowVisiblePos < 0) {
-            return;
-        }
-        final boolean highAvailable = highVisiblePos == highMaxPos;
-        final boolean lowAvailable = lowVisiblePos == lowMinPos;
-        if (!highAvailable && mWindowAlignment.mainAxis().isMaxUnknown()
-                && !lowAvailable && mWindowAlignment.mainAxis().isMinUnknown()) {
-            return;
-        }
-        int maxEdge, maxViewCenter;
-        if (highAvailable) {
-            maxEdge = mGrid.findRowMax(true, sTwoInts);
-            View maxChild = findViewByPosition(sTwoInts[1]);
-            maxViewCenter = getViewCenter(maxChild);
-            final LayoutParams lp = (LayoutParams) maxChild.getLayoutParams();
-            int[] multipleAligns = lp.getAlignMultiple();
-            if (multipleAligns != null && multipleAligns.length > 0) {
-                maxViewCenter += multipleAligns[multipleAligns.length - 1] - multipleAligns[0];
-            }
-        } else {
-            maxEdge = Integer.MAX_VALUE;
-            maxViewCenter = Integer.MAX_VALUE;
-        }
-        int minEdge, minViewCenter;
-        if (lowAvailable) {
-            minEdge = mGrid.findRowMin(false, sTwoInts);
-            View minChild = findViewByPosition(sTwoInts[1]);
-            minViewCenter = getViewCenter(minChild);
-        } else {
-            minEdge = Integer.MIN_VALUE;
-            minViewCenter = Integer.MIN_VALUE;
-        }
-        mWindowAlignment.mainAxis().updateMinMax(minEdge, maxEdge, minViewCenter, maxViewCenter);
-    }
-
-    /**
-     * Update secondary axis's scroll min/max, should be updated in
-     * {@link #scrollDirectionSecondary(int)}.
-     */
-    private void updateSecondaryScrollLimits() {
-        WindowAlignment.Axis secondAxis = mWindowAlignment.secondAxis();
-        int minEdge = secondAxis.getPaddingMin() - mScrollOffsetSecondary;
-        int maxEdge = minEdge + getSizeSecondary();
-        secondAxis.updateMinMax(minEdge, maxEdge, minEdge, maxEdge);
-    }
-
-    private void initScrollController() {
-        mWindowAlignment.reset();
-        mWindowAlignment.horizontal.setSize(getWidth());
-        mWindowAlignment.vertical.setSize(getHeight());
-        mWindowAlignment.horizontal.setPadding(getPaddingLeft(), getPaddingRight());
-        mWindowAlignment.vertical.setPadding(getPaddingTop(), getPaddingBottom());
-        mSizePrimary = mWindowAlignment.mainAxis().getSize();
-        mScrollOffsetSecondary = 0;
-
-        if (DEBUG) {
-            Log.v(getTag(), "initScrollController mSizePrimary " + mSizePrimary
-                    + " mWindowAlignment " + mWindowAlignment);
-        }
-    }
-
-    private void updateScrollController() {
-        mWindowAlignment.horizontal.setSize(getWidth());
-        mWindowAlignment.vertical.setSize(getHeight());
-        mWindowAlignment.horizontal.setPadding(getPaddingLeft(), getPaddingRight());
-        mWindowAlignment.vertical.setPadding(getPaddingTop(), getPaddingBottom());
-        mSizePrimary = mWindowAlignment.mainAxis().getSize();
-
-        if (DEBUG) {
-            Log.v(getTag(), "updateScrollController mSizePrimary " + mSizePrimary
-                    + " mWindowAlignment " + mWindowAlignment);
-        }
-    }
-
-    @Override
-    public void scrollToPosition(int position) {
-        setSelection(position, 0, false, 0);
-    }
-
-    @Override
-    public void smoothScrollToPosition(RecyclerView recyclerView, State state,
-            int position) {
-        setSelection(position, 0, true, 0);
-    }
-
-    public void setSelection(int position,
-            int primaryScrollExtra) {
-        setSelection(position, 0, false, primaryScrollExtra);
-    }
-
-    public void setSelectionSmooth(int position) {
-        setSelection(position, 0, true, 0);
-    }
-
-    public void setSelectionWithSub(int position, int subposition,
-            int primaryScrollExtra) {
-        setSelection(position, subposition, false, primaryScrollExtra);
-    }
-
-    public void setSelectionSmoothWithSub(int position, int subposition) {
-        setSelection(position, subposition, true, 0);
-    }
-
-    public int getSelection() {
-        return mFocusPosition;
-    }
-
-    public int getSubSelection() {
-        return mSubFocusPosition;
-    }
-
-    public void setSelection(int position, int subposition, boolean smooth,
-            int primaryScrollExtra) {
-        if ((mFocusPosition != position && position != NO_POSITION)
-                || subposition != mSubFocusPosition || primaryScrollExtra != mPrimaryScrollExtra) {
-            scrollToSelection(position, subposition, smooth, primaryScrollExtra);
-        }
-    }
-
-    void scrollToSelection(int position, int subposition,
-            boolean smooth, int primaryScrollExtra) {
-        if (TRACE) TraceCompat.beginSection("scrollToSelection");
-        mPrimaryScrollExtra = primaryScrollExtra;
-
-        View view = findViewByPosition(position);
-        // scrollToView() is based on Adapter position. Only call scrollToView() when item
-        // is still valid and no layout is requested, otherwise defer to next layout pass.
-        // If it is still in smoothScrolling, we should either update smoothScroller or initiate
-        // a layout.
-        final boolean notSmoothScrolling = !isSmoothScrolling()
-                || (mFlag & PF_IN_ONSTOP_SMOOTHSCROLLER) != 0;
-        if (notSmoothScrolling && !mBaseGridView.isLayoutRequested()
-                && view != null && getAdapterPositionByView(view) == position) {
-            mFlag |= PF_IN_SELECTION;
-            scrollToView(view, smooth);
-            mFlag &= ~PF_IN_SELECTION;
-        } else {
-            if ((mFlag & PF_LAYOUT_ENABLED) == 0 || (mFlag & PF_SLIDING) != 0) {
-                mFocusPosition = position;
-                mSubFocusPosition = subposition;
-                mFocusPositionOffset = Integer.MIN_VALUE;
-                return;
-            }
-            if (smooth) {
-                mFocusPosition = position;
-                mSubFocusPosition = subposition;
-                mFocusPositionOffset = Integer.MIN_VALUE;
-                if (!hasDoneFirstLayout()) {
-                    Log.w(getTag(), "setSelectionSmooth should "
-                            + "not be called before first layout pass");
-                    return;
-                }
-                position = startPositionSmoothScroller(position);
-                if (position != mFocusPosition) {
-                    // gets cropped by adapter size
-                    mFocusPosition = position;
-                    mSubFocusPosition = 0;
-                }
-            } else {
-                // stopScroll might change mFocusPosition, so call it before assign value to
-                // mFocusPosition
-                if (!notSmoothScrolling) {
-                    mBaseGridView.stopScroll();
-                }
-                mFocusPosition = position;
-                mSubFocusPosition = subposition;
-                mFocusPositionOffset = Integer.MIN_VALUE;
-                mFlag |= PF_FORCE_FULL_LAYOUT;
-                requestLayout();
-            }
-        }
-        if (TRACE) TraceCompat.endSection();
-    }
-
-    int startPositionSmoothScroller(int position) {
-        LinearSmoothScroller linearSmoothScroller = new GridLinearSmoothScroller() {
-            @Override
-            public PointF computeScrollVectorForPosition(int targetPosition) {
-                if (getChildCount() == 0) {
-                    return null;
-                }
-                final int firstChildPos = getPosition(getChildAt(0));
-                // TODO We should be able to deduce direction from bounds of current and target
-                // focus, rather than making assumptions about positions and directionality
-                final boolean isStart = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
-                        ? targetPosition > firstChildPos
-                        : targetPosition < firstChildPos;
-                final int direction = isStart ? -1 : 1;
-                if (mOrientation == HORIZONTAL) {
-                    return new PointF(direction, 0);
-                } else {
-                    return new PointF(0, direction);
-                }
-            }
-
-        };
-        linearSmoothScroller.setTargetPosition(position);
-        startSmoothScroll(linearSmoothScroller);
-        return linearSmoothScroller.getTargetPosition();
-    }
-
-    private void processPendingMovement(boolean forward) {
-        if (forward ? hasCreatedLastItem() : hasCreatedFirstItem()) {
-            return;
-        }
-        if (mPendingMoveSmoothScroller == null) {
-            // Stop existing scroller and create a new PendingMoveSmoothScroller.
-            mBaseGridView.stopScroll();
-            PendingMoveSmoothScroller linearSmoothScroller = new PendingMoveSmoothScroller(
-                    forward ? 1 : -1, mNumRows > 1);
-            mFocusPositionOffset = 0;
-            startSmoothScroll(linearSmoothScroller);
-            if (linearSmoothScroller.isRunning()) {
-                mPendingMoveSmoothScroller = linearSmoothScroller;
-            }
-        } else {
-            if (forward) {
-                mPendingMoveSmoothScroller.increasePendingMoves();
-            } else {
-                mPendingMoveSmoothScroller.decreasePendingMoves();
-            }
-        }
-    }
-
-    @Override
-    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
-        if (DEBUG) Log.v(getTag(), "onItemsAdded positionStart "
-                + positionStart + " itemCount " + itemCount);
-        if (mFocusPosition != NO_POSITION && mGrid != null && mGrid.getFirstVisibleIndex() >= 0
-                && mFocusPositionOffset != Integer.MIN_VALUE) {
-            int pos = mFocusPosition + mFocusPositionOffset;
-            if (positionStart <= pos) {
-                mFocusPositionOffset += itemCount;
-            }
-        }
-        mChildrenStates.clear();
-    }
-
-    @Override
-    public void onItemsChanged(RecyclerView recyclerView) {
-        if (DEBUG) Log.v(getTag(), "onItemsChanged");
-        mFocusPositionOffset = 0;
-        mChildrenStates.clear();
-    }
-
-    @Override
-    public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
-        if (DEBUG) Log.v(getTag(), "onItemsRemoved positionStart "
-                + positionStart + " itemCount " + itemCount);
-        if (mFocusPosition != NO_POSITION  && mGrid != null && mGrid.getFirstVisibleIndex() >= 0
-                && mFocusPositionOffset != Integer.MIN_VALUE) {
-            int pos = mFocusPosition + mFocusPositionOffset;
-            if (positionStart <= pos) {
-                if (positionStart + itemCount > pos) {
-                    // stop updating offset after the focus item was removed
-                    mFocusPositionOffset += positionStart - pos;
-                    mFocusPosition += mFocusPositionOffset;
-                    mFocusPositionOffset = Integer.MIN_VALUE;
-                } else {
-                    mFocusPositionOffset -= itemCount;
-                }
-            }
-        }
-        mChildrenStates.clear();
-    }
-
-    @Override
-    public void onItemsMoved(RecyclerView recyclerView, int fromPosition, int toPosition,
-            int itemCount) {
-        if (DEBUG) Log.v(getTag(), "onItemsMoved fromPosition "
-                + fromPosition + " toPosition " + toPosition);
-        if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE) {
-            int pos = mFocusPosition + mFocusPositionOffset;
-            if (fromPosition <= pos && pos < fromPosition + itemCount) {
-                // moved items include focused position
-                mFocusPositionOffset += toPosition - fromPosition;
-            } else if (fromPosition < pos && toPosition > pos - itemCount) {
-                // move items before focus position to after focused position
-                mFocusPositionOffset -= itemCount;
-            } else if (fromPosition > pos && toPosition < pos) {
-                // move items after focus position to before focused position
-                mFocusPositionOffset += itemCount;
-            }
-        }
-        mChildrenStates.clear();
-    }
-
-    @Override
-    public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) {
-        if (DEBUG) Log.v(getTag(), "onItemsUpdated positionStart "
-                + positionStart + " itemCount " + itemCount);
-        for (int i = positionStart, end = positionStart + itemCount; i < end; i++) {
-            mChildrenStates.remove(i);
-        }
-    }
-
-    @Override
-    public boolean onRequestChildFocus(RecyclerView parent, View child, View focused) {
-        if ((mFlag & PF_FOCUS_SEARCH_DISABLED) != 0) {
-            return true;
-        }
-        if (getAdapterPositionByView(child) == NO_POSITION) {
-            // This is could be the last view in DISAPPEARING animation.
-            return true;
-        }
-        if ((mFlag & (PF_STAGE_MASK | PF_IN_SELECTION)) == 0) {
-            scrollToView(child, focused, true);
-        }
-        return true;
-    }
-
-    @Override
-    public boolean requestChildRectangleOnScreen(RecyclerView parent, View view, Rect rect,
-            boolean immediate) {
-        if (DEBUG) Log.v(getTag(), "requestChildRectangleOnScreen " + view + " " + rect);
-        return false;
-    }
-
-    public void getViewSelectedOffsets(View view, int[] offsets) {
-        if (mOrientation == HORIZONTAL) {
-            offsets[0] = getPrimaryAlignedScrollDistance(view);
-            offsets[1] = getSecondaryScrollDistance(view);
-        } else {
-            offsets[1] = getPrimaryAlignedScrollDistance(view);
-            offsets[0] = getSecondaryScrollDistance(view);
-        }
-    }
-
-    /**
-     * Return the scroll delta on primary direction to make the view selected. If the return value
-     * is 0, there is no need to scroll.
-     */
-    private int getPrimaryAlignedScrollDistance(View view) {
-        return mWindowAlignment.mainAxis().getScroll(getViewCenter(view));
-    }
-
-    /**
-     * Get adjusted primary position for a given childView (if there is multiple ItemAlignment
-     * defined on the view).
-     */
-    private int getAdjustedPrimaryAlignedScrollDistance(int scrollPrimary, View view,
-            View childView) {
-        int subindex = getSubPositionByView(view, childView);
-        if (subindex != 0) {
-            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
-            scrollPrimary += lp.getAlignMultiple()[subindex] - lp.getAlignMultiple()[0];
-        }
-        return scrollPrimary;
-    }
-
-    private int getSecondaryScrollDistance(View view) {
-        int viewCenterSecondary = getViewCenterSecondary(view);
-        return mWindowAlignment.secondAxis().getScroll(viewCenterSecondary);
-    }
-
-    /**
-     * Scroll to a given child view and change mFocusPosition. Ignored when in slideOut() state.
-     */
-    void scrollToView(View view, boolean smooth) {
-        scrollToView(view, view == null ? null : view.findFocus(), smooth);
-    }
-
-    void scrollToView(View view, boolean smooth, int extraDelta, int extraDeltaSecondary) {
-        scrollToView(view, view == null ? null : view.findFocus(), smooth, extraDelta,
-                extraDeltaSecondary);
-    }
-
-    private void scrollToView(View view, View childView, boolean smooth) {
-        scrollToView(view, childView, smooth, 0, 0);
-    }
-    /**
-     * Scroll to a given child view and change mFocusPosition. Ignored when in slideOut() state.
-     */
-    private void scrollToView(View view, View childView, boolean smooth, int extraDelta,
-            int extraDeltaSecondary) {
-        if ((mFlag & PF_SLIDING) != 0) {
-            return;
-        }
-        int newFocusPosition = getAdapterPositionByView(view);
-        int newSubFocusPosition = getSubPositionByView(view, childView);
-        if (newFocusPosition != mFocusPosition || newSubFocusPosition != mSubFocusPosition) {
-            mFocusPosition = newFocusPosition;
-            mSubFocusPosition = newSubFocusPosition;
-            mFocusPositionOffset = 0;
-            if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT) {
-                dispatchChildSelected();
-            }
-            if (mBaseGridView.isChildrenDrawingOrderEnabledInternal()) {
-                mBaseGridView.invalidate();
-            }
-        }
-        if (view == null) {
-            return;
-        }
-        if (!view.hasFocus() && mBaseGridView.hasFocus()) {
-            // transfer focus to the child if it does not have focus yet (e.g. triggered
-            // by setSelection())
-            view.requestFocus();
-        }
-        if ((mFlag & PF_SCROLL_ENABLED) == 0 && smooth) {
-            return;
-        }
-        if (getScrollPosition(view, childView, sTwoInts)
-                || extraDelta != 0 || extraDeltaSecondary != 0) {
-            scrollGrid(sTwoInts[0] + extraDelta, sTwoInts[1] + extraDeltaSecondary, smooth);
-        }
-    }
-
-    boolean getScrollPosition(View view, View childView, int[] deltas) {
-        switch (mFocusScrollStrategy) {
-            case BaseGridView.FOCUS_SCROLL_ALIGNED:
-            default:
-                return getAlignedPosition(view, childView, deltas);
-            case BaseGridView.FOCUS_SCROLL_ITEM:
-            case BaseGridView.FOCUS_SCROLL_PAGE:
-                return getNoneAlignedPosition(view, deltas);
-        }
-    }
-
-    private boolean getNoneAlignedPosition(View view, int[] deltas) {
-        int pos = getAdapterPositionByView(view);
-        int viewMin = getViewMin(view);
-        int viewMax = getViewMax(view);
-        // we either align "firstView" to left/top padding edge
-        // or align "lastView" to right/bottom padding edge
-        View firstView = null;
-        View lastView = null;
-        int paddingMin = mWindowAlignment.mainAxis().getPaddingMin();
-        int clientSize = mWindowAlignment.mainAxis().getClientSize();
-        final int row = mGrid.getRowIndex(pos);
-        if (viewMin < paddingMin) {
-            // view enters low padding area:
-            firstView = view;
-            if (mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_PAGE) {
-                // scroll one "page" left/top,
-                // align first visible item of the "page" at the low padding edge.
-                while (prependOneColumnVisibleItems()) {
-                    CircularIntArray positions =
-                            mGrid.getItemPositionsInRows(mGrid.getFirstVisibleIndex(), pos)[row];
-                    firstView = findViewByPosition(positions.get(0));
-                    if (viewMax - getViewMin(firstView) > clientSize) {
-                        if (positions.size() > 2) {
-                            firstView = findViewByPosition(positions.get(2));
-                        }
-                        break;
-                    }
-                }
-            }
-        } else if (viewMax > clientSize + paddingMin) {
-            // view enters high padding area:
-            if (mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_PAGE) {
-                // scroll whole one page right/bottom, align view at the low padding edge.
-                firstView = view;
-                do {
-                    CircularIntArray positions =
-                            mGrid.getItemPositionsInRows(pos, mGrid.getLastVisibleIndex())[row];
-                    lastView = findViewByPosition(positions.get(positions.size() - 1));
-                    if (getViewMax(lastView) - viewMin > clientSize) {
-                        lastView = null;
-                        break;
-                    }
-                } while (appendOneColumnVisibleItems());
-                if (lastView != null) {
-                    // however if we reached end,  we should align last view.
-                    firstView = null;
-                }
-            } else {
-                lastView = view;
-            }
-        }
-        int scrollPrimary = 0;
-        int scrollSecondary = 0;
-        if (firstView != null) {
-            scrollPrimary = getViewMin(firstView) - paddingMin;
-        } else if (lastView != null) {
-            scrollPrimary = getViewMax(lastView) - (paddingMin + clientSize);
-        }
-        View secondaryAlignedView;
-        if (firstView != null) {
-            secondaryAlignedView = firstView;
-        } else if (lastView != null) {
-            secondaryAlignedView = lastView;
-        } else {
-            secondaryAlignedView = view;
-        }
-        scrollSecondary = getSecondaryScrollDistance(secondaryAlignedView);
-        if (scrollPrimary != 0 || scrollSecondary != 0) {
-            deltas[0] = scrollPrimary;
-            deltas[1] = scrollSecondary;
-            return true;
-        }
-        return false;
-    }
-
-    private boolean getAlignedPosition(View view, View childView, int[] deltas) {
-        int scrollPrimary = getPrimaryAlignedScrollDistance(view);
-        if (childView != null) {
-            scrollPrimary = getAdjustedPrimaryAlignedScrollDistance(scrollPrimary, view, childView);
-        }
-        int scrollSecondary = getSecondaryScrollDistance(view);
-        if (DEBUG) {
-            Log.v(getTag(), "getAlignedPosition " + scrollPrimary + " " + scrollSecondary
-                    + " " + mPrimaryScrollExtra + " " + mWindowAlignment);
-        }
-        scrollPrimary += mPrimaryScrollExtra;
-        if (scrollPrimary != 0 || scrollSecondary != 0) {
-            deltas[0] = scrollPrimary;
-            deltas[1] = scrollSecondary;
-            return true;
-        } else {
-            deltas[0] = 0;
-            deltas[1] = 0;
-        }
-        return false;
-    }
-
-    private void scrollGrid(int scrollPrimary, int scrollSecondary, boolean smooth) {
-        if ((mFlag & PF_STAGE_MASK) == PF_STAGE_LAYOUT) {
-            scrollDirectionPrimary(scrollPrimary);
-            scrollDirectionSecondary(scrollSecondary);
-        } else {
-            int scrollX;
-            int scrollY;
-            if (mOrientation == HORIZONTAL) {
-                scrollX = scrollPrimary;
-                scrollY = scrollSecondary;
-            } else {
-                scrollX = scrollSecondary;
-                scrollY = scrollPrimary;
-            }
-            if (smooth) {
-                mBaseGridView.smoothScrollBy(scrollX, scrollY);
-            } else {
-                mBaseGridView.scrollBy(scrollX, scrollY);
-                dispatchChildSelectedAndPositioned();
-            }
-        }
-    }
-
-    public void setPruneChild(boolean pruneChild) {
-        if (((mFlag & PF_PRUNE_CHILD) != 0) != pruneChild) {
-            mFlag = (mFlag & ~PF_PRUNE_CHILD) | (pruneChild ? PF_PRUNE_CHILD : 0);
-            if (pruneChild) {
-                requestLayout();
-            }
-        }
-    }
-
-    public boolean getPruneChild() {
-        return (mFlag & PF_PRUNE_CHILD) != 0;
-    }
-
-    public void setScrollEnabled(boolean scrollEnabled) {
-        if (((mFlag & PF_SCROLL_ENABLED) != 0) != scrollEnabled) {
-            mFlag = (mFlag & ~PF_SCROLL_ENABLED) | (scrollEnabled ? PF_SCROLL_ENABLED : 0);
-            if (((mFlag & PF_SCROLL_ENABLED) != 0)
-                    && mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_ALIGNED
-                    && mFocusPosition != NO_POSITION) {
-                scrollToSelection(mFocusPosition, mSubFocusPosition,
-                        true, mPrimaryScrollExtra);
-            }
-        }
-    }
-
-    public boolean isScrollEnabled() {
-        return (mFlag & PF_SCROLL_ENABLED) != 0;
-    }
-
-    private int findImmediateChildIndex(View view) {
-        if (mBaseGridView != null && view != mBaseGridView) {
-            view = findContainingItemView(view);
-            if (view != null) {
-                for (int i = 0, count = getChildCount(); i < count; i++) {
-                    if (getChildAt(i) == view) {
-                        return i;
-                    }
-                }
-            }
-        }
-        return NO_POSITION;
-    }
-
-    void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
-        if (gainFocus) {
-            // if gridview.requestFocus() is called, select first focusable child.
-            for (int i = mFocusPosition; ;i++) {
-                View view = findViewByPosition(i);
-                if (view == null) {
-                    break;
-                }
-                if (view.getVisibility() == View.VISIBLE && view.hasFocusable()) {
-                    view.requestFocus();
-                    break;
-                }
-            }
-        }
-    }
-
-    void setFocusSearchDisabled(boolean disabled) {
-        mFlag = (mFlag & ~PF_FOCUS_SEARCH_DISABLED) | (disabled ? PF_FOCUS_SEARCH_DISABLED : 0);
-    }
-
-    boolean isFocusSearchDisabled() {
-        return (mFlag & PF_FOCUS_SEARCH_DISABLED) != 0;
-    }
-
-    @Override
-    public View onInterceptFocusSearch(View focused, int direction) {
-        if ((mFlag & PF_FOCUS_SEARCH_DISABLED) != 0) {
-            return focused;
-        }
-
-        final FocusFinder ff = FocusFinder.getInstance();
-        View result = null;
-        if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
-            // convert direction to absolute direction and see if we have a view there and if not
-            // tell LayoutManager to add if it can.
-            if (canScrollVertically()) {
-                final int absDir =
-                        direction == View.FOCUS_FORWARD ? View.FOCUS_DOWN : View.FOCUS_UP;
-                result = ff.findNextFocus(mBaseGridView, focused, absDir);
-            }
-            if (canScrollHorizontally()) {
-                boolean rtl = getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
-                final int absDir = (direction == View.FOCUS_FORWARD) ^ rtl
-                        ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
-                result = ff.findNextFocus(mBaseGridView, focused, absDir);
-            }
-        } else {
-            result = ff.findNextFocus(mBaseGridView, focused, direction);
-        }
-        if (result != null) {
-            return result;
-        }
-
-        if (mBaseGridView.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS) {
-            return mBaseGridView.getParent().focusSearch(focused, direction);
-        }
-
-        if (DEBUG) Log.v(getTag(), "regular focusSearch failed direction " + direction);
-        int movement = getMovement(direction);
-        final boolean isScroll = mBaseGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE;
-        if (movement == NEXT_ITEM) {
-            if (isScroll || (mFlag & PF_FOCUS_OUT_END) == 0) {
-                result = focused;
-            }
-            if ((mFlag & PF_SCROLL_ENABLED) != 0 && !hasCreatedLastItem()) {
-                processPendingMovement(true);
-                result = focused;
-            }
-        } else if (movement == PREV_ITEM) {
-            if (isScroll || (mFlag & PF_FOCUS_OUT_FRONT) == 0) {
-                result = focused;
-            }
-            if ((mFlag & PF_SCROLL_ENABLED) != 0 && !hasCreatedFirstItem()) {
-                processPendingMovement(false);
-                result = focused;
-            }
-        } else if (movement == NEXT_ROW) {
-            if (isScroll || (mFlag & PF_FOCUS_OUT_SIDE_END) == 0) {
-                result = focused;
-            }
-        } else if (movement == PREV_ROW) {
-            if (isScroll || (mFlag & PF_FOCUS_OUT_SIDE_START) == 0) {
-                result = focused;
-            }
-        }
-        if (result != null) {
-            return result;
-        }
-
-        if (DEBUG) Log.v(getTag(), "now focusSearch in parent");
-        result = mBaseGridView.getParent().focusSearch(focused, direction);
-        if (result != null) {
-            return result;
-        }
-        return focused != null ? focused : mBaseGridView;
-    }
-
-    boolean hasPreviousViewInSameRow(int pos) {
-        if (mGrid == null || pos == NO_POSITION || mGrid.getFirstVisibleIndex() < 0) {
-            return false;
-        }
-        if (mGrid.getFirstVisibleIndex() > 0) {
-            return true;
-        }
-        final int focusedRow = mGrid.getLocation(pos).row;
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            int position = getAdapterPositionByIndex(i);
-            Grid.Location loc = mGrid.getLocation(position);
-            if (loc != null && loc.row == focusedRow) {
-                if (position < pos) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean onAddFocusables(RecyclerView recyclerView,
-            ArrayList<View> views, int direction, int focusableMode) {
-        if ((mFlag & PF_FOCUS_SEARCH_DISABLED) != 0) {
-            return true;
-        }
-        // If this viewgroup or one of its children currently has focus then we
-        // consider our children for focus searching in main direction on the same row.
-        // If this viewgroup has no focus and using focus align, we want the system
-        // to ignore our children and pass focus to the viewgroup, which will pass
-        // focus on to its children appropriately.
-        // If this viewgroup has no focus and not using focus align, we want to
-        // consider the child that does not overlap with padding area.
-        if (recyclerView.hasFocus()) {
-            if (mPendingMoveSmoothScroller != null) {
-                // don't find next focusable if has pending movement.
-                return true;
-            }
-            final int movement = getMovement(direction);
-            final View focused = recyclerView.findFocus();
-            final int focusedIndex = findImmediateChildIndex(focused);
-            final int focusedPos = getAdapterPositionByIndex(focusedIndex);
-            // Even if focusedPos != NO_POSITION, findViewByPosition could return null if the view
-            // is ignored or getLayoutPosition does not match the adapter position of focused view.
-            final View immediateFocusedChild = (focusedPos == NO_POSITION) ? null
-                    : findViewByPosition(focusedPos);
-            // Add focusables of focused item.
-            if (immediateFocusedChild != null) {
-                immediateFocusedChild.addFocusables(views,  direction, focusableMode);
-            }
-            if (mGrid == null || getChildCount() == 0) {
-                // no grid information, or no child, bail out.
-                return true;
-            }
-            if ((movement == NEXT_ROW || movement == PREV_ROW) && mGrid.getNumRows() <= 1) {
-                // For single row, cannot navigate to previous/next row.
-                return true;
-            }
-            // Add focusables of neighbor depending on the focus search direction.
-            final int focusedRow = mGrid != null && immediateFocusedChild != null
-                    ? mGrid.getLocation(focusedPos).row : NO_POSITION;
-            final int focusableCount = views.size();
-            int inc = movement == NEXT_ITEM || movement == NEXT_ROW ? 1 : -1;
-            int loop_end = inc > 0 ? getChildCount() - 1 : 0;
-            int loop_start;
-            if (focusedIndex == NO_POSITION) {
-                loop_start = inc > 0 ? 0 : getChildCount() - 1;
-            } else {
-                loop_start = focusedIndex + inc;
-            }
-            for (int i = loop_start; inc > 0 ? i <= loop_end : i >= loop_end; i += inc) {
-                final View child = getChildAt(i);
-                if (child.getVisibility() != View.VISIBLE || !child.hasFocusable()) {
-                    continue;
-                }
-                // if there wasn't any focused item, add the very first focusable
-                // items and stop.
-                if (immediateFocusedChild == null) {
-                    child.addFocusables(views,  direction, focusableMode);
-                    if (views.size() > focusableCount) {
-                        break;
-                    }
-                    continue;
-                }
-                int position = getAdapterPositionByIndex(i);
-                Grid.Location loc = mGrid.getLocation(position);
-                if (loc == null) {
-                    continue;
-                }
-                if (movement == NEXT_ITEM) {
-                    // Add first focusable item on the same row
-                    if (loc.row == focusedRow && position > focusedPos) {
-                        child.addFocusables(views,  direction, focusableMode);
-                        if (views.size() > focusableCount) {
-                            break;
-                        }
-                    }
-                } else if (movement == PREV_ITEM) {
-                    // Add first focusable item on the same row
-                    if (loc.row == focusedRow && position < focusedPos) {
-                        child.addFocusables(views,  direction, focusableMode);
-                        if (views.size() > focusableCount) {
-                            break;
-                        }
-                    }
-                } else if (movement == NEXT_ROW) {
-                    // Add all focusable items after this item whose row index is bigger
-                    if (loc.row == focusedRow) {
-                        continue;
-                    } else if (loc.row < focusedRow) {
-                        break;
-                    }
-                    child.addFocusables(views,  direction, focusableMode);
-                } else if (movement == PREV_ROW) {
-                    // Add all focusable items before this item whose row index is smaller
-                    if (loc.row == focusedRow) {
-                        continue;
-                    } else if (loc.row > focusedRow) {
-                        break;
-                    }
-                    child.addFocusables(views,  direction, focusableMode);
-                }
-            }
-        } else {
-            int focusableCount = views.size();
-            if (mFocusScrollStrategy != BaseGridView.FOCUS_SCROLL_ALIGNED) {
-                // adding views not overlapping padding area to avoid scrolling in gaining focus
-                int left = mWindowAlignment.mainAxis().getPaddingMin();
-                int right = mWindowAlignment.mainAxis().getClientSize() + left;
-                for (int i = 0, count = getChildCount(); i < count; i++) {
-                    View child = getChildAt(i);
-                    if (child.getVisibility() == View.VISIBLE) {
-                        if (getViewMin(child) >= left && getViewMax(child) <= right) {
-                            child.addFocusables(views, direction, focusableMode);
-                        }
-                    }
-                }
-                // if we cannot find any, then just add all children.
-                if (views.size() == focusableCount) {
-                    for (int i = 0, count = getChildCount(); i < count; i++) {
-                        View child = getChildAt(i);
-                        if (child.getVisibility() == View.VISIBLE) {
-                            child.addFocusables(views, direction, focusableMode);
-                        }
-                    }
-                }
-            } else {
-                View view = findViewByPosition(mFocusPosition);
-                if (view != null) {
-                    view.addFocusables(views, direction, focusableMode);
-                }
-            }
-            // if still cannot find any, fall through and add itself
-            if (views.size() != focusableCount) {
-                return true;
-            }
-            if (recyclerView.isFocusable()) {
-                views.add(recyclerView);
-            }
-        }
-        return true;
-    }
-
-    boolean hasCreatedLastItem() {
-        int count = getItemCount();
-        return count == 0 || mBaseGridView.findViewHolderForAdapterPosition(count - 1) != null;
-    }
-
-    boolean hasCreatedFirstItem() {
-        int count = getItemCount();
-        return count == 0 || mBaseGridView.findViewHolderForAdapterPosition(0) != null;
-    }
-
-    boolean isItemFullyVisible(int pos) {
-        RecyclerView.ViewHolder vh = mBaseGridView.findViewHolderForAdapterPosition(pos);
-        if (vh == null) {
-            return false;
-        }
-        return vh.itemView.getLeft() >= 0 && vh.itemView.getRight() < mBaseGridView.getWidth()
-                && vh.itemView.getTop() >= 0 && vh.itemView.getBottom() < mBaseGridView.getHeight();
-    }
-
-    boolean canScrollTo(View view) {
-        return view.getVisibility() == View.VISIBLE && (!hasFocus() || view.hasFocusable());
-    }
-
-    boolean gridOnRequestFocusInDescendants(RecyclerView recyclerView, int direction,
-            Rect previouslyFocusedRect) {
-        switch (mFocusScrollStrategy) {
-            case BaseGridView.FOCUS_SCROLL_ALIGNED:
-            default:
-                return gridOnRequestFocusInDescendantsAligned(recyclerView,
-                        direction, previouslyFocusedRect);
-            case BaseGridView.FOCUS_SCROLL_PAGE:
-            case BaseGridView.FOCUS_SCROLL_ITEM:
-                return gridOnRequestFocusInDescendantsUnaligned(recyclerView,
-                        direction, previouslyFocusedRect);
-        }
-    }
-
-    private boolean gridOnRequestFocusInDescendantsAligned(RecyclerView recyclerView,
-            int direction, Rect previouslyFocusedRect) {
-        View view = findViewByPosition(mFocusPosition);
-        if (view != null) {
-            boolean result = view.requestFocus(direction, previouslyFocusedRect);
-            if (!result && DEBUG) {
-                Log.w(getTag(), "failed to request focus on " + view);
-            }
-            return result;
-        }
-        return false;
-    }
-
-    private boolean gridOnRequestFocusInDescendantsUnaligned(RecyclerView recyclerView,
-            int direction, Rect previouslyFocusedRect) {
-        // focus to view not overlapping padding area to avoid scrolling in gaining focus
-        int index;
-        int increment;
-        int end;
-        int count = getChildCount();
-        if ((direction & View.FOCUS_FORWARD) != 0) {
-            index = 0;
-            increment = 1;
-            end = count;
-        } else {
-            index = count - 1;
-            increment = -1;
-            end = -1;
-        }
-        int left = mWindowAlignment.mainAxis().getPaddingMin();
-        int right = mWindowAlignment.mainAxis().getClientSize() + left;
-        for (int i = index; i != end; i += increment) {
-            View child = getChildAt(i);
-            if (child.getVisibility() == View.VISIBLE) {
-                if (getViewMin(child) >= left && getViewMax(child) <= right) {
-                    if (child.requestFocus(direction, previouslyFocusedRect)) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
-    private final static int PREV_ITEM = 0;
-    private final static int NEXT_ITEM = 1;
-    private final static int PREV_ROW = 2;
-    private final static int NEXT_ROW = 3;
-
-    private int getMovement(int direction) {
-        int movement = View.FOCUS_LEFT;
-
-        if (mOrientation == HORIZONTAL) {
-            switch(direction) {
-                case View.FOCUS_LEFT:
-                    movement = (mFlag & PF_REVERSE_FLOW_PRIMARY) == 0 ? PREV_ITEM : NEXT_ITEM;
-                    break;
-                case View.FOCUS_RIGHT:
-                    movement = (mFlag & PF_REVERSE_FLOW_PRIMARY) == 0 ? NEXT_ITEM : PREV_ITEM;
-                    break;
-                case View.FOCUS_UP:
-                    movement = PREV_ROW;
-                    break;
-                case View.FOCUS_DOWN:
-                    movement = NEXT_ROW;
-                    break;
-            }
-        } else if (mOrientation == VERTICAL) {
-            switch(direction) {
-                case View.FOCUS_LEFT:
-                    movement = (mFlag & PF_REVERSE_FLOW_SECONDARY) == 0 ? PREV_ROW : NEXT_ROW;
-                    break;
-                case View.FOCUS_RIGHT:
-                    movement = (mFlag & PF_REVERSE_FLOW_SECONDARY) == 0 ? NEXT_ROW : PREV_ROW;
-                    break;
-                case View.FOCUS_UP:
-                    movement = PREV_ITEM;
-                    break;
-                case View.FOCUS_DOWN:
-                    movement = NEXT_ITEM;
-                    break;
-            }
-        }
-
-        return movement;
-    }
-
-    int getChildDrawingOrder(RecyclerView recyclerView, int childCount, int i) {
-        View view = findViewByPosition(mFocusPosition);
-        if (view == null) {
-            return i;
-        }
-        int focusIndex = recyclerView.indexOfChild(view);
-        // supposely 0 1 2 3 4 5 6 7 8 9, 4 is the center item
-        // drawing order is 0 1 2 3 9 8 7 6 5 4
-        if (i < focusIndex) {
-            return i;
-        } else if (i < childCount - 1) {
-            return focusIndex + childCount - 1 - i;
-        } else {
-            return focusIndex;
-        }
-    }
-
-    @Override
-    public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
-            RecyclerView.Adapter newAdapter) {
-        if (DEBUG) Log.v(getTag(), "onAdapterChanged to " + newAdapter);
-        if (oldAdapter != null) {
-            discardLayoutInfo();
-            mFocusPosition = NO_POSITION;
-            mFocusPositionOffset = 0;
-            mChildrenStates.clear();
-        }
-        if (newAdapter instanceof FacetProviderAdapter) {
-            mFacetProviderAdapter = (FacetProviderAdapter) newAdapter;
-        } else {
-            mFacetProviderAdapter = null;
-        }
-        super.onAdapterChanged(oldAdapter, newAdapter);
-    }
-
-    private void discardLayoutInfo() {
-        mGrid = null;
-        mRowSizeSecondary = null;
-        mFlag &= ~PF_ROW_SECONDARY_SIZE_REFRESH;
-    }
-
-    public void setLayoutEnabled(boolean layoutEnabled) {
-        if (((mFlag & PF_LAYOUT_ENABLED) != 0) != layoutEnabled) {
-            mFlag = (mFlag & ~PF_LAYOUT_ENABLED) | (layoutEnabled ? PF_LAYOUT_ENABLED : 0);
-            requestLayout();
-        }
-    }
-
-    void setChildrenVisibility(int visibility) {
-        mChildVisibility = visibility;
-        if (mChildVisibility != -1) {
-            int count = getChildCount();
-            for (int i= 0; i < count; i++) {
-                getChildAt(i).setVisibility(mChildVisibility);
-            }
-        }
-    }
-
-    final static class SavedState implements Parcelable {
-
-        int index; // index inside adapter of the current view
-        Bundle childStates = Bundle.EMPTY;
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(index);
-            out.writeBundle(childStates);
-        }
-
-        @SuppressWarnings("hiding")
-        public static final Parcelable.Creator<SavedState> CREATOR =
-                new Parcelable.Creator<SavedState>() {
-                    @Override
-                    public SavedState createFromParcel(Parcel in) {
-                        return new SavedState(in);
-                    }
-
-                    @Override
-                    public SavedState[] newArray(int size) {
-                        return new SavedState[size];
-                    }
-                };
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        SavedState(Parcel in) {
-            index = in.readInt();
-            childStates = in.readBundle(GridLayoutManager.class.getClassLoader());
-        }
-
-        SavedState() {
-        }
-    }
-
-    @Override
-    public Parcelable onSaveInstanceState() {
-        if (DEBUG) Log.v(getTag(), "onSaveInstanceState getSelection() " + getSelection());
-        SavedState ss = new SavedState();
-        // save selected index
-        ss.index = getSelection();
-        // save offscreen child (state when they are recycled)
-        Bundle bundle = mChildrenStates.saveAsBundle();
-        // save views currently is on screen (TODO save cached views)
-        for (int i = 0, count = getChildCount(); i < count; i++) {
-            View view = getChildAt(i);
-            int position = getAdapterPositionByView(view);
-            if (position != NO_POSITION) {
-                bundle = mChildrenStates.saveOnScreenView(bundle, view, position);
-            }
-        }
-        ss.childStates = bundle;
-        return ss;
-    }
-
-    void onChildRecycled(RecyclerView.ViewHolder holder) {
-        final int position = holder.getAdapterPosition();
-        if (position != NO_POSITION) {
-            mChildrenStates.saveOffscreenView(holder.itemView, position);
-        }
-    }
-
-    @Override
-    public void onRestoreInstanceState(Parcelable state) {
-        if (!(state instanceof SavedState)) {
-            return;
-        }
-        SavedState loadingState = (SavedState)state;
-        mFocusPosition = loadingState.index;
-        mFocusPositionOffset = 0;
-        mChildrenStates.loadFromBundle(loadingState.childStates);
-        mFlag |= PF_FORCE_FULL_LAYOUT;
-        requestLayout();
-        if (DEBUG) Log.v(getTag(), "onRestoreInstanceState mFocusPosition " + mFocusPosition);
-    }
-
-    @Override
-    public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
-            RecyclerView.State state) {
-        if (mOrientation == HORIZONTAL && mGrid != null) {
-            return mGrid.getNumRows();
-        }
-        return super.getRowCountForAccessibility(recycler, state);
-    }
-
-    @Override
-    public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
-            RecyclerView.State state) {
-        if (mOrientation == VERTICAL && mGrid != null) {
-            return mGrid.getNumRows();
-        }
-        return super.getColumnCountForAccessibility(recycler, state);
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
-            RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
-        ViewGroup.LayoutParams lp = host.getLayoutParams();
-        if (mGrid == null || !(lp instanceof LayoutParams)) {
-            return;
-        }
-        LayoutParams glp = (LayoutParams) lp;
-        int position = glp.getViewAdapterPosition();
-        int rowIndex = position >= 0 ? mGrid.getRowIndex(position) : -1;
-        if (rowIndex < 0) {
-            return;
-        }
-        int guessSpanIndex = position / mGrid.getNumRows();
-        if (mOrientation == HORIZONTAL) {
-            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
-                    rowIndex, 1, guessSpanIndex, 1, false, false));
-        } else {
-            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
-                    guessSpanIndex, 1, rowIndex, 1, false, false));
-        }
-    }
-
-    /*
-     * Leanback widget is different than the default implementation because the "scroll" is driven
-     * by selection change.
-     */
-    @Override
-    public boolean performAccessibilityAction(Recycler recycler, State state, int action,
-            Bundle args) {
-        saveContext(recycler, state);
-        int translatedAction = action;
-        boolean reverseFlowPrimary = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0;
-        if (Build.VERSION.SDK_INT >= 23) {
-            if (mOrientation == HORIZONTAL) {
-                if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                        .ACTION_SCROLL_LEFT.getId()) {
-                    translatedAction = reverseFlowPrimary
-                            ? AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD :
-                            AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
-                } else if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                        .ACTION_SCROLL_RIGHT.getId()) {
-                    translatedAction = reverseFlowPrimary
-                            ? AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD :
-                            AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
-                }
-            } else { // VERTICAL layout
-                if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP
-                        .getId()) {
-                    translatedAction = AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
-                } else if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                        .ACTION_SCROLL_DOWN.getId()) {
-                    translatedAction = AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
-                }
-            }
-        }
-        switch (translatedAction) {
-            case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
-                processPendingMovement(false);
-                processSelectionMoves(false, -1);
-                break;
-            case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
-                processPendingMovement(true);
-                processSelectionMoves(false, 1);
-                break;
-        }
-        leaveContext();
-        return true;
-    }
-
-    /*
-     * Move mFocusPosition multiple steps on the same row in main direction.
-     * Stops when moves are all consumed or reach first/last visible item.
-     * Returning remaining moves.
-     */
-    int processSelectionMoves(boolean preventScroll, int moves) {
-        if (mGrid == null) {
-            return moves;
-        }
-        int focusPosition = mFocusPosition;
-        int focusedRow = focusPosition != NO_POSITION
-                ? mGrid.getRowIndex(focusPosition) : NO_POSITION;
-        View newSelected = null;
-        for (int i = 0, count = getChildCount(); i < count && moves != 0; i++) {
-            int index = moves > 0 ? i : count - 1 - i;
-            final View child = getChildAt(index);
-            if (!canScrollTo(child)) {
-                continue;
-            }
-            int position = getAdapterPositionByIndex(index);
-            int rowIndex = mGrid.getRowIndex(position);
-            if (focusedRow == NO_POSITION) {
-                focusPosition = position;
-                newSelected = child;
-                focusedRow = rowIndex;
-            } else if (rowIndex == focusedRow) {
-                if ((moves > 0 && position > focusPosition)
-                        || (moves < 0 && position < focusPosition)) {
-                    focusPosition = position;
-                    newSelected = child;
-                    if (moves > 0) {
-                        moves--;
-                    } else {
-                        moves++;
-                    }
-                }
-            }
-        }
-        if (newSelected != null) {
-            if (preventScroll) {
-                if (hasFocus()) {
-                    mFlag |= PF_IN_SELECTION;
-                    newSelected.requestFocus();
-                    mFlag &= ~PF_IN_SELECTION;
-                }
-                mFocusPosition = focusPosition;
-                mSubFocusPosition = 0;
-            } else {
-                scrollToView(newSelected, true);
-            }
-        }
-        return moves;
-    }
-
-    @Override
-    public void onInitializeAccessibilityNodeInfo(Recycler recycler, State state,
-            AccessibilityNodeInfoCompat info) {
-        saveContext(recycler, state);
-        int count = state.getItemCount();
-        boolean reverseFlowPrimary = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0;
-        if (count > 1 && !isItemFullyVisible(0)) {
-            if (Build.VERSION.SDK_INT >= 23) {
-                if (mOrientation == HORIZONTAL) {
-                    info.addAction(reverseFlowPrimary
-                            ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                                    .ACTION_SCROLL_RIGHT :
-                            AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                                    .ACTION_SCROLL_LEFT);
-                } else {
-                    info.addAction(
-                            AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP);
-                }
-            } else {
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
-            }
-            info.setScrollable(true);
-        }
-        if (count > 1 && !isItemFullyVisible(count - 1)) {
-            if (Build.VERSION.SDK_INT >= 23) {
-                if (mOrientation == HORIZONTAL) {
-                    info.addAction(reverseFlowPrimary
-                            ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                                    .ACTION_SCROLL_LEFT :
-                            AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                                    .ACTION_SCROLL_RIGHT);
-                } else {
-                    info.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat
-                                    .ACTION_SCROLL_DOWN);
-                }
-            } else {
-                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
-            }
-            info.setScrollable(true);
-        }
-        final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo =
-                AccessibilityNodeInfoCompat.CollectionInfoCompat
-                        .obtain(getRowCountForAccessibility(recycler, state),
-                                getColumnCountForAccessibility(recycler, state),
-                                isLayoutHierarchical(recycler, state),
-                                getSelectionModeForAccessibility(recycler, state));
-        info.setCollectionInfo(collectionInfo);
-        leaveContext();
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedAction.java b/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
deleted file mode 100644
index a0c198d..0000000
--- a/leanback/src/android/support/v17/leanback/widget/GuidedAction.java
+++ /dev/null
@@ -1,956 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.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.text.InputType;
-
-import java.util.List;
-
-/**
- * A data class which represents an action within a {@link
- * android.support.v17.leanback.app.GuidedStepFragment}. GuidedActions contain at minimum a title
- * and a description, and typically also an icon.
- * <p>
- * A GuidedAction typically represents a single action a user may take, but may also represent a
- * possible choice out of a group of mutually exclusive choices (similar to radio buttons), or an
- * information-only label (in which case the item cannot be clicked).
- * <p>
- * GuidedActions may optionally be checked. They may also indicate that they will request further
- * user input on selection, in which case they will be displayed with a chevron indicator.
- * <p>
- * GuidedAction recommends to use {@link Builder}. When application subclass GuidedAction, it
- * can subclass {@link BuilderBase}, implement its own builder() method where it should
- * call {@link BuilderBase#applyValues(GuidedAction)}.
- */
-public class GuidedAction extends Action {
-
-    private static final String TAG = "GuidedAction";
-
-    /**
-     * Special check set Id that is neither checkbox nor radio.
-     */
-    public static final int NO_CHECK_SET = 0;
-    /**
-     * Default checkset Id for radio.
-     */
-    public static final int DEFAULT_CHECK_SET_ID = 1;
-    /**
-     * Checkset Id for checkbox.
-     */
-    public static final int CHECKBOX_CHECK_SET_ID = -1;
-
-    /**
-     * When finishing editing, goes to next action.
-     */
-    public static final long ACTION_ID_NEXT = -2;
-    /**
-     * When finishing editing, stay on current action.
-     */
-    public static final long ACTION_ID_CURRENT = -3;
-
-    /**
-     * Id of standard OK action.
-     */
-    public static final long ACTION_ID_OK = -4;
-
-    /**
-     * Id of standard Cancel action.
-     */
-    public static final long ACTION_ID_CANCEL = -5;
-
-    /**
-     * Id of standard Finish action.
-     */
-    public static final long ACTION_ID_FINISH = -6;
-
-    /**
-     * Id of standard Finish action.
-     */
-    public static final long ACTION_ID_CONTINUE = -7;
-
-    /**
-     * Id of standard Yes action.
-     */
-    public static final long ACTION_ID_YES = -8;
-
-    /**
-     * Id of standard No action.
-     */
-    public static final long ACTION_ID_NO = -9;
-
-    static final int EDITING_NONE = 0;
-    static final int EDITING_TITLE = 1;
-    static final int EDITING_DESCRIPTION = 2;
-    static final int EDITING_ACTIVATOR_VIEW = 3;
-
-    /**
-     * Base builder class to build a {@link GuidedAction} object.  When subclass GuidedAction, you
-     * can override this BuilderBase class, implements your build() method which should call
-     * {@link #applyValues(GuidedAction)}.  When using GuidedAction directly, use {@link Builder}.
-     */
-    public abstract static class BuilderBase<B extends BuilderBase> {
-        private Context mContext;
-        private long mId;
-        private CharSequence mTitle;
-        private CharSequence mEditTitle;
-        private CharSequence mDescription;
-        private CharSequence mEditDescription;
-        private Drawable mIcon;
-        /**
-         * The mActionFlags holds various action states such as whether title or description are
-         * editable, or the action is focusable.
-         *
-         */
-        private int mActionFlags;
-
-        private int mEditable = EDITING_NONE;
-        private int mInputType = InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
-        private int mDescriptionInputType = InputType.TYPE_CLASS_TEXT
-                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
-        private int mEditInputType = InputType.TYPE_CLASS_TEXT;
-        private int mDescriptionEditInputType = InputType.TYPE_CLASS_TEXT;
-        private int mCheckSetId = NO_CHECK_SET;
-        private List<GuidedAction> mSubActions;
-        private Intent mIntent;
-
-        /**
-         * Creates a BuilderBase for GuidedAction or its subclass.
-         * @param context Context object used to build the GuidedAction.
-         */
-        public BuilderBase(Context context) {
-            mContext = context;
-            mActionFlags = PF_ENABLED | PF_FOCUSABLE | PF_AUTORESTORE;
-        }
-
-        /**
-         * Returns Context of this Builder.
-         * @return Context of this Builder.
-         */
-        public Context getContext() {
-            return mContext;
-        }
-
-        private void setFlags(int flag, int mask) {
-            mActionFlags = (mActionFlags & ~mask) | (flag & mask);
-        }
-
-        /**
-         * Subclass of BuilderBase should call this function to apply values.
-         * @param action GuidedAction to apply BuilderBase values.
-         */
-        protected final void applyValues(GuidedAction action) {
-            // Base Action values
-            action.setId(mId);
-            action.setLabel1(mTitle);
-            action.setEditTitle(mEditTitle);
-            action.setLabel2(mDescription);
-            action.setEditDescription(mEditDescription);
-            action.setIcon(mIcon);
-
-            // Subclass values
-            action.mIntent = mIntent;
-            action.mEditable = mEditable;
-            action.mInputType = mInputType;
-            action.mDescriptionInputType = mDescriptionInputType;
-            action.mEditInputType = mEditInputType;
-            action.mDescriptionEditInputType = mDescriptionEditInputType;
-            action.mActionFlags = mActionFlags;
-            action.mCheckSetId = mCheckSetId;
-            action.mSubActions = mSubActions;
-        }
-
-        /**
-         * Construct a clickable action with associated id and auto assign pre-defined title for the
-         * action. If the id is not supported, the method simply does nothing.
-         * @param id One of {@link GuidedAction#ACTION_ID_OK} {@link GuidedAction#ACTION_ID_CANCEL}
-         * {@link GuidedAction#ACTION_ID_FINISH} {@link GuidedAction#ACTION_ID_CONTINUE}
-         * {@link GuidedAction#ACTION_ID_YES} {@link GuidedAction#ACTION_ID_NO}.
-         * @return The same BuilderBase object.
-         */
-        public B clickAction(long id) {
-            if (id == ACTION_ID_OK) {
-                mId = ACTION_ID_OK;
-                mTitle = mContext.getString(android.R.string.ok);
-            } else if (id == ACTION_ID_CANCEL) {
-                mId = ACTION_ID_CANCEL;
-                mTitle = mContext.getString(android.R.string.cancel);
-            } else if (id == ACTION_ID_FINISH) {
-                mId = ACTION_ID_FINISH;
-                mTitle = mContext.getString(R.string.lb_guidedaction_finish_title);
-            } else if (id == ACTION_ID_CONTINUE) {
-                mId = ACTION_ID_CONTINUE;
-                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.ok);
-            } else if (id == ACTION_ID_NO) {
-                mId = ACTION_ID_NO;
-                mTitle = mContext.getString(android.R.string.cancel);
-            }
-            return (B) this;
-        }
-
-        /**
-         * Sets the ID associated with this action.  The ID can be any value the client wishes;
-         * it is typically used to determine what to do when an action is clicked.
-         * @param id The ID to associate with this action.
-         */
-        public B id(long id) {
-            mId = id;
-            return (B) this;
-        }
-
-        /**
-         * Sets the title for this action.  The title is typically a short string indicating the
-         * action to be taken on click, e.g. "Continue" or "Cancel".
-         * @param title The title for this action.
-         */
-        public B title(CharSequence title) {
-            mTitle = title;
-            return (B) this;
-        }
-
-        /**
-         * Sets the title for this action.  The title is typically a short string indicating the
-         * action to be taken on click, e.g. "Continue" or "Cancel".
-         * @param titleResourceId The resource id of title for this action.
-         */
-        public B title(@StringRes int titleResourceId) {
-            mTitle = getContext().getString(titleResourceId);
-            return (B) this;
-        }
-
-        /**
-         * Sets the optional title text to edit.  When TextView is activated, the edit title
-         * replaces the string of title.
-         * @param editTitle The optional title text to edit when TextView is activated.
-         */
-        public B editTitle(CharSequence editTitle) {
-            mEditTitle = editTitle;
-            return (B) this;
-        }
-
-        /**
-         * Sets the optional title text to edit.  When TextView is activated, the edit title
-         * replaces the string of title.
-         * @param editTitleResourceId String resource id of the optional title text to edit when
-         * TextView is activated.
-         */
-        public B editTitle(@StringRes int editTitleResourceId) {
-            mEditTitle = getContext().getString(editTitleResourceId);
-            return (B) this;
-        }
-
-        /**
-         * Sets the description for this action.  The description is typically a longer string
-         * providing extra information on what the action will do.
-         * @param description The description for this action.
-         */
-        public B description(CharSequence description) {
-            mDescription = description;
-            return (B) this;
-        }
-
-        /**
-         * Sets the description for this action.  The description is typically a longer string
-         * providing extra information on what the action will do.
-         * @param descriptionResourceId String resource id of the description for this action.
-         */
-        public B description(@StringRes int descriptionResourceId) {
-            mDescription = getContext().getString(descriptionResourceId);
-            return (B) this;
-        }
-
-        /**
-         * Sets the optional description text to edit.  When TextView is activated, the edit
-         * description replaces the string of description.
-         * @param description The description to edit for this action.
-         */
-        public B editDescription(CharSequence description) {
-            mEditDescription = description;
-            return (B) this;
-        }
-
-        /**
-         * Sets the optional description text to edit.  When TextView is activated, the edit
-         * description replaces the string of description.
-         * @param descriptionResourceId String resource id of the description to edit for this
-         * action.
-         */
-        public B editDescription(@StringRes int descriptionResourceId) {
-            mEditDescription = getContext().getString(descriptionResourceId);
-            return (B) this;
-        }
-
-        /**
-         * Sets the intent associated with this action.  Clients would typically fire this intent
-         * directly when the action is clicked.
-         * @param intent The intent associated with this action.
-         */
-        public B intent(Intent intent) {
-            mIntent = intent;
-            return (B) this;
-        }
-
-        /**
-         * Sets the action's icon drawable.
-         * @param icon The drawable for the icon associated with this action.
-         */
-        public B icon(Drawable icon) {
-            mIcon = icon;
-            return (B) this;
-        }
-
-        /**
-         * Sets the action's icon drawable by retrieving it by resource ID from the specified
-         * context. This is a convenience function that simply looks up the drawable and calls
-         * {@link #icon(Drawable)}.
-         * @param iconResourceId The resource ID for the icon associated with this action.
-         * @param context The context whose resource ID should be retrieved.
-         * @deprecated Use {@link #icon(int)}.
-         */
-        @Deprecated
-        public B iconResourceId(@DrawableRes int iconResourceId, Context context) {
-            return icon(ContextCompat.getDrawable(context, iconResourceId));
-        }
-
-        /**
-         * Sets the action's icon drawable by retrieving it by resource ID from Builder's
-         * context. This is a convenience function that simply looks up the drawable and calls
-         * {@link #icon(Drawable)}.
-         * @param iconResourceId The resource ID for the icon associated with this action.
-         */
-        public B icon(@DrawableRes int iconResourceId) {
-            return icon(ContextCompat.getDrawable(getContext(), iconResourceId));
-        }
-
-        /**
-         * Indicates whether this action title is editable. Note: Editable actions cannot also be
-         * checked, or belong to a check set.
-         * @param editable Whether this action is editable.
-         */
-        public B editable(boolean editable) {
-            if (!editable) {
-                if (mEditable == EDITING_TITLE) {
-                    mEditable = EDITING_NONE;
-                }
-                return (B) this;
-            }
-            mEditable = EDITING_TITLE;
-            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
-                throw new IllegalArgumentException("Editable actions cannot also be checked");
-            }
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether this action's description is editable
-         * @param editable Whether this action description is editable.
-         */
-        public B descriptionEditable(boolean editable) {
-            if (!editable) {
-                if (mEditable == EDITING_DESCRIPTION) {
-                    mEditable = EDITING_NONE;
-                }
-                return (B) this;
-            }
-            mEditable = EDITING_DESCRIPTION;
-            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
-                throw new IllegalArgumentException("Editable actions cannot also be checked");
-            }
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether this action has a view can be activated to edit, e.g. a DatePicker.
-         * @param editable Whether this action has view can be activated to edit.
-         */
-        public B hasEditableActivatorView(boolean editable) {
-            if (!editable) {
-                if (mEditable == EDITING_ACTIVATOR_VIEW) {
-                    mEditable = EDITING_NONE;
-                }
-                return (B) this;
-            }
-            mEditable = EDITING_ACTIVATOR_VIEW;
-            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
-                throw new IllegalArgumentException("Editable actions cannot also be checked");
-            }
-            return (B) this;
-        }
-
-        /**
-         * Sets {@link InputType} of this action title not in editing.
-         *
-         * @param inputType InputType for the action title not in editing.
-         */
-        public B inputType(int inputType) {
-            mInputType = inputType;
-            return (B) this;
-        }
-
-        /**
-         * Sets {@link InputType} of this action description not in editing.
-         *
-         * @param inputType InputType for the action description not in editing.
-         */
-        public B descriptionInputType(int inputType) {
-            mDescriptionInputType = inputType;
-            return (B) this;
-        }
-
-
-        /**
-         * Sets {@link InputType} of this action title in editing.
-         *
-         * @param inputType InputType for the action title in editing.
-         */
-        public B editInputType(int inputType) {
-            mEditInputType = inputType;
-            return (B) this;
-        }
-
-        /**
-         * Sets {@link InputType} of this action description in editing.
-         *
-         * @param inputType InputType for the action description in editing.
-         */
-        public B descriptionEditInputType(int inputType) {
-            mDescriptionEditInputType = inputType;
-            return (B) this;
-        }
-
-
-        private boolean isChecked() {
-            return (mActionFlags & PF_CHECKED) == PF_CHECKED;
-        }
-        /**
-         * Indicates whether this action is initially checked.
-         * @param checked Whether this action is checked.
-         */
-        public B checked(boolean checked) {
-            setFlags(checked ? PF_CHECKED : 0, PF_CHECKED);
-            if (mEditable != EDITING_NONE) {
-                throw new IllegalArgumentException("Editable actions cannot also be checked");
-            }
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether this action is part of a single-select group similar to radio buttons
-         * or this action is a checkbox. When one item in a check set is checked, all others with
-         * the same check set ID will be checked automatically.
-         * @param checkSetId The check set ID, or {@link GuidedAction#NO_CHECK_SET} to indicate not
-         * radio or checkbox, or {@link GuidedAction#CHECKBOX_CHECK_SET_ID} to indicate a checkbox.
-         */
-        public B checkSetId(int checkSetId) {
-            mCheckSetId = checkSetId;
-            if (mEditable != EDITING_NONE) {
-                throw new IllegalArgumentException("Editable actions cannot also be in check sets");
-            }
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether the title and description are long, and should be displayed
-         * appropriately.
-         * @param multilineDescription Whether this action has a multiline description.
-         */
-        public B multilineDescription(boolean multilineDescription) {
-            setFlags(multilineDescription ? PF_MULTI_lINE_DESCRIPTION : 0,
-                    PF_MULTI_lINE_DESCRIPTION);
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether this action has a next state and should display a chevron.
-         * @param hasNext Whether this action has a next state.
-         */
-        public B hasNext(boolean hasNext) {
-            setFlags(hasNext ? PF_HAS_NEXT : 0, PF_HAS_NEXT);
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether this action is for information purposes only and cannot be clicked.
-         * @param infoOnly Whether this action has a next state.
-         */
-        public B infoOnly(boolean infoOnly) {
-            setFlags(infoOnly ? PF_INFO_ONLY : 0, PF_INFO_ONLY);
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether this action is enabled.  If not enabled, an action cannot be clicked.
-         * @param enabled Whether the action is enabled.
-         */
-        public B enabled(boolean enabled) {
-            setFlags(enabled ? PF_ENABLED : 0, PF_ENABLED);
-            return (B) this;
-        }
-
-        /**
-         * Indicates whether this action can take focus.
-         * @param focusable
-         * @return The same BuilderBase object.
-         */
-        public B focusable(boolean focusable) {
-            setFlags(focusable ? PF_FOCUSABLE : 0, PF_FOCUSABLE);
-            return (B) this;
-        }
-
-        /**
-         * Sets sub actions list.
-         * @param subActions
-         * @return The same BuilderBase object.
-         */
-        public B subActions(List<GuidedAction> subActions) {
-            mSubActions = subActions;
-            return (B) this;
-        }
-
-        /**
-         * Explicitly sets auto restore feature on the GuidedAction.  It's by default true.
-         * @param autoSaveRestoreEnabled True if turn on auto save/restore of GuidedAction content,
-         *                                false otherwise.
-         * @return The same BuilderBase object.
-         * @see GuidedAction#isAutoSaveRestoreEnabled()
-         */
-        public B autoSaveRestoreEnabled(boolean autoSaveRestoreEnabled) {
-            setFlags(autoSaveRestoreEnabled ? PF_AUTORESTORE : 0, PF_AUTORESTORE);
-            return (B) this;
-        }
-
-    }
-
-    /**
-     * Builds a {@link GuidedAction} object.
-     */
-    public static class Builder extends BuilderBase<Builder> {
-
-        /**
-         * @deprecated Use {@link GuidedAction.Builder#GuidedAction.Builder(Context)}.
-         */
-        @Deprecated
-        public Builder() {
-            super(null);
-        }
-
-        /**
-         * Creates a Builder for GuidedAction.
-         * @param context Context to build GuidedAction.
-         */
-        public Builder(Context context) {
-            super(context);
-        }
-
-        /**
-         * Builds the GuidedAction corresponding to this Builder.
-         * @return The GuidedAction as configured through this Builder.
-         */
-        public GuidedAction build() {
-            GuidedAction action = new GuidedAction();
-            applyValues(action);
-            return action;
-        }
-
-    }
-
-    static final int PF_CHECKED = 0x00000001;
-    static final int PF_MULTI_lINE_DESCRIPTION = 0x00000002;
-    static final int PF_HAS_NEXT = 0x00000004;
-    static final int PF_INFO_ONLY = 0x00000008;
-    static final int PF_ENABLED = 0x00000010;
-    static final int PF_FOCUSABLE = 0x00000020;
-    static final int PF_AUTORESTORE = 0x00000040;
-    int mActionFlags;
-
-    private CharSequence mEditTitle;
-    private CharSequence mEditDescription;
-    int mEditable;
-    int mInputType;
-    int mDescriptionInputType;
-    int mEditInputType;
-    int mDescriptionEditInputType;
-
-    int mCheckSetId;
-
-    List<GuidedAction> mSubActions;
-
-    Intent mIntent;
-
-    protected GuidedAction() {
-        super(0);
-    }
-
-    private void setFlags(int flag, int mask) {
-        mActionFlags = (mActionFlags & ~mask) | (flag & mask);
-    }
-
-    /**
-     * Returns the title of this action.
-     * @return The title set when this action was built.
-     */
-    public CharSequence getTitle() {
-        return getLabel1();
-    }
-
-    /**
-     * Sets the title of this action.
-     * @param title The title set when this action was built.
-     */
-    public void setTitle(CharSequence title) {
-        setLabel1(title);
-    }
-
-    /**
-     * Returns the optional title text to edit.  When not null, it is being edited instead of
-     * {@link #getTitle()}.
-     * @return Optional title text to edit instead of {@link #getTitle()}.
-     */
-    public CharSequence getEditTitle() {
-        return mEditTitle;
-    }
-
-    /**
-     * Sets the optional title text to edit instead of {@link #setTitle(CharSequence)}.
-     * @param editTitle Optional title text to edit instead of {@link #setTitle(CharSequence)}.
-     */
-    public void setEditTitle(CharSequence editTitle) {
-        mEditTitle = editTitle;
-    }
-
-    /**
-     * Returns the optional description text to edit.  When not null, it is being edited instead of
-     * {@link #getDescription()}.
-     * @return Optional description text to edit instead of {@link #getDescription()}.
-     */
-    public CharSequence getEditDescription() {
-        return mEditDescription;
-    }
-
-    /**
-     * Sets the optional description text to edit instead of {@link #setDescription(CharSequence)}.
-     * @param editDescription Optional description text to edit instead of
-     * {@link #setDescription(CharSequence)}.
-     */
-    public void setEditDescription(CharSequence editDescription) {
-        mEditDescription = editDescription;
-    }
-
-    /**
-     * Returns true if {@link #getEditTitle()} is not null.  When true, the {@link #getEditTitle()}
-     * is being edited instead of {@link #getTitle()}.
-     * @return true if {@link #getEditTitle()} is not null.
-     */
-    public boolean isEditTitleUsed() {
-        return mEditTitle != null;
-    }
-
-    /**
-     * Returns the description of this action.
-     * @return The description of this action.
-     */
-    public CharSequence getDescription() {
-        return getLabel2();
-    }
-
-    /**
-     * Sets the description of this action.
-     * @param description The description of the action.
-     */
-    public void setDescription(CharSequence description) {
-        setLabel2(description);
-    }
-
-    /**
-     * Returns the intent associated with this action.
-     * @return The intent set when this action was built.
-     */
-    public Intent getIntent() {
-        return mIntent;
-    }
-
-    /**
-     * Sets the intent of this action.
-     * @param intent New intent to set on this action.
-     */
-    public void setIntent(Intent intent) {
-        mIntent = intent;
-    }
-
-    /**
-     * Returns whether this action title is editable.
-     * @return true if the action title is editable, false otherwise.
-     */
-    public boolean isEditable() {
-        return mEditable == EDITING_TITLE;
-    }
-
-    /**
-     * Returns whether this action description is editable.
-     * @return true if the action description is editable, false otherwise.
-     */
-    public boolean isDescriptionEditable() {
-        return mEditable == EDITING_DESCRIPTION;
-    }
-
-    /**
-     * Returns if this action has editable title or editable description.
-     * @return True if this action has editable title or editable description, false otherwise.
-     */
-    public boolean hasTextEditable() {
-        return mEditable == EDITING_TITLE || mEditable == EDITING_DESCRIPTION;
-    }
-
-    /**
-     * Returns whether this action can be activated to edit, e.g. a DatePicker.
-     * @return true if the action can be activated to edit.
-     */
-    public boolean hasEditableActivatorView() {
-        return mEditable == EDITING_ACTIVATOR_VIEW;
-    }
-
-    /**
-     * Returns InputType of action title in editing; only valid when {@link #isEditable()} is true.
-     * @return InputType of action title in editing.
-     */
-    public int getEditInputType() {
-        return mEditInputType;
-    }
-
-    /**
-     * Returns InputType of action description in editing; only valid when
-     * {@link #isDescriptionEditable()} is true.
-     * @return InputType of action description in editing.
-     */
-    public int getDescriptionEditInputType() {
-        return mDescriptionEditInputType;
-    }
-
-    /**
-     * Returns InputType of action title not in editing.
-     * @return InputType of action title not in editing.
-     */
-    public int getInputType() {
-        return mInputType;
-    }
-
-    /**
-     * Returns InputType of action description not in editing.
-     * @return InputType of action description not in editing.
-     */
-    public int getDescriptionInputType() {
-        return mDescriptionInputType;
-    }
-
-    /**
-     * Returns whether this action is checked.
-     * @return true if the action is currently checked, false otherwise.
-     */
-    public boolean isChecked() {
-        return (mActionFlags & PF_CHECKED) == PF_CHECKED;
-    }
-
-    /**
-     * Sets whether this action is checked.
-     * @param checked Whether this action should be checked.
-     */
-    public void setChecked(boolean checked) {
-        setFlags(checked ? PF_CHECKED : 0, PF_CHECKED);
-    }
-
-    /**
-     * Returns the check set id this action is a part of. All actions in the same list with the same
-     * check set id are considered linked. When one of the actions within that set is selected, that
-     * action becomes checked, while all the other actions become unchecked.
-     *
-     * @return an integer representing the check set this action is a part of, or
-     *         {@link #CHECKBOX_CHECK_SET_ID} if this is a checkbox, or {@link #NO_CHECK_SET} if
-     *         this action is not a checkbox or radiobutton.
-     */
-    public int getCheckSetId() {
-        return mCheckSetId;
-    }
-
-    /**
-     * Returns whether this action is has a multiline description.
-     * @return true if the action was constructed as having a multiline description, false
-     * otherwise.
-     */
-    public boolean hasMultilineDescription() {
-        return (mActionFlags & PF_MULTI_lINE_DESCRIPTION) == PF_MULTI_lINE_DESCRIPTION;
-    }
-
-    /**
-     * Returns whether this action is enabled.
-     * @return true if the action is currently enabled, false otherwise.
-     */
-    public boolean isEnabled() {
-        return (mActionFlags & PF_ENABLED) == PF_ENABLED;
-    }
-
-    /**
-     * Sets whether this action is enabled.
-     * @param enabled Whether this action should be enabled.
-     */
-    public void setEnabled(boolean enabled) {
-        setFlags(enabled ? PF_ENABLED : 0, PF_ENABLED);
-    }
-
-    /**
-     * Returns whether this action is focusable.
-     * @return true if the action is currently focusable, false otherwise.
-     */
-    public boolean isFocusable() {
-        return (mActionFlags & PF_FOCUSABLE) == PF_FOCUSABLE;
-    }
-
-    /**
-     * Sets whether this action is focusable.
-     * @param focusable Whether this action should be focusable.
-     */
-    public void setFocusable(boolean focusable) {
-        setFlags(focusable ? PF_FOCUSABLE : 0, PF_FOCUSABLE);
-    }
-
-    /**
-     * Returns whether this action will request further user input when selected, such as showing
-     * another GuidedStepFragment or launching a new activity. Configured during construction.
-     * @return true if the action will request further user input when selected, false otherwise.
-     */
-    public boolean hasNext() {
-        return (mActionFlags & PF_HAS_NEXT) == PF_HAS_NEXT;
-    }
-
-    /**
-     * Returns whether the action will only display information and is thus not clickable. If both
-     * this and {@link #hasNext()} are true, infoOnly takes precedence. The default is false. For
-     * example, this might represent e.g. the amount of storage a document uses, or the cost of an
-     * app.
-     * @return true if will only display information, false otherwise.
-     */
-    public boolean infoOnly() {
-        return (mActionFlags & PF_INFO_ONLY) == PF_INFO_ONLY;
-    }
-
-    /**
-     * Change sub actions list.
-     * @param actions Sub actions list to set on this action.  Sets null to disable sub actions.
-     */
-    public void setSubActions(List<GuidedAction> actions) {
-        mSubActions = actions;
-    }
-
-    /**
-     * @return List of sub actions or null if sub actions list is not enabled.
-     */
-    public List<GuidedAction> getSubActions() {
-        return mSubActions;
-    }
-
-    /**
-     * @return True if has sub actions list, even it's currently empty.
-     */
-    public boolean hasSubActions() {
-        return mSubActions != null;
-    }
-
-    /**
-     * Returns true if Action will be saved to instanceState and restored later, false otherwise.
-     * The default value is true.  When isAutoSaveRestoreEnabled() is true and {@link #getId()} is
-     * not {@link #NO_ID}:
-     * <li>{@link #isEditable()} is true: save text of {@link #getTitle()}</li>
-     * <li>{@link #isDescriptionEditable()} is true: save text of {@link #getDescription()}</li>
-     * <li>{@link #getCheckSetId()} is not {@link #NO_CHECK_SET}: save {@link #isChecked()}}</li>
-     * <li>{@link GuidedDatePickerAction} will be saved</li>
-     * App may explicitly disable auto restore and handle by itself. App should override Fragment
-     * onSaveInstanceState() and onCreateActions()
-     * @return True if Action will be saved to instanceState and restored later, false otherwise.
-     */
-    public final boolean isAutoSaveRestoreEnabled() {
-        return (mActionFlags & PF_AUTORESTORE) == PF_AUTORESTORE;
-    }
-
-    /**
-     * Save action into a bundle using a given key. When isAutoRestoreEna() is true:
-     * <li>{@link #isEditable()} is true: save text of {@link #getTitle()}</li>
-     * <li>{@link #isDescriptionEditable()} is true: save text of {@link #getDescription()}</li>
-     * <li>{@link #getCheckSetId()} is not {@link #NO_CHECK_SET}: save {@link #isChecked()}}</li>
-     * <li>{@link GuidedDatePickerAction} will be saved</li>
-     * Subclass may override this method.
-     * @param bundle  Bundle to save the Action.
-     * @param key Key used to save the Action.
-     */
-    public void onSaveInstanceState(Bundle bundle, String key) {
-        if (needAutoSaveTitle() && getTitle() != null) {
-            bundle.putString(key, getTitle().toString());
-        } else if (needAutoSaveDescription() && getDescription() != null) {
-            bundle.putString(key, getDescription().toString());
-        } else if (getCheckSetId() != NO_CHECK_SET) {
-            bundle.putBoolean(key, isChecked());
-        }
-    }
-
-    /**
-     * Restore action from a bundle using a given key. When isAutoRestore() is true:
-     * <li>{@link #isEditable()} is true: save text of {@link #getTitle()}</li>
-     * <li>{@link #isDescriptionEditable()} is true: save text of {@link #getDescription()}</li>
-     * <li>{@link #getCheckSetId()} is not {@link #NO_CHECK_SET}: save {@link #isChecked()}}</li>
-     * <li>{@link GuidedDatePickerAction} will be saved</li>
-     * Subclass may override this method.
-     * @param bundle  Bundle to restore the Action from.
-     * @param key Key used to restore the Action.
-     */
-    public void onRestoreInstanceState(Bundle bundle, String key) {
-        if (needAutoSaveTitle()) {
-            String title = bundle.getString(key);
-            if (title != null) {
-                setTitle(title);
-            }
-        } else if (needAutoSaveDescription()) {
-            String description = bundle.getString(key);
-            if (description != null) {
-                setDescription(description);
-            }
-        } else if (getCheckSetId() != NO_CHECK_SET) {
-            setChecked(bundle.getBoolean(key, isChecked()));
-        }
-    }
-
-    static boolean isPasswordVariant(int inputType) {
-        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
-        return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
-                || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
-                || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
-    }
-
-    final boolean needAutoSaveTitle() {
-        return isEditable() && !isPasswordVariant(getEditInputType());
-    }
-
-    final boolean needAutoSaveDescription() {
-        return isDescriptionEditable() && !isPasswordVariant(getDescriptionEditInputType());
-    }
-
-}
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java b/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
deleted file mode 100644
index a2ece56..0000000
--- a/leanback/src/android/support/v17/leanback/widget/GuidedActionsStylist.java
+++ /dev/null
@@ -1,1523 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_ACTIVATOR_VIEW;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_DESCRIPTION;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_NONE;
-import static android.support.v17.leanback.widget.GuidedAction.EDITING_TITLE;
-
-import android.animation.Animator;
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Build.VERSION;
-import android.support.annotation.CallSuper;
-import android.support.annotation.NonNull;
-import android.support.annotation.RestrictTo;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.transition.TransitionEpicenterCallback;
-import android.support.v17.leanback.transition.TransitionHelper;
-import android.support.v17.leanback.transition.TransitionListener;
-import android.support.v17.leanback.widget.GuidedActionAdapter.EditListener;
-import android.support.v17.leanback.widget.picker.DatePicker;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.widget.RecyclerView;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.inputmethod.EditorInfo;
-import android.widget.Checkable;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * GuidedActionsStylist is used within a {@link android.support.v17.leanback.app.GuidedStepFragment}
- * to supply the right-side panel where users can take actions. It consists of a container for the
- * list of actions, and a stationary selector view that indicates visually the location of focus.
- * GuidedActionsStylist has two different layouts: default is for normal actions including text,
- * radio, checkbox, DatePicker, etc, the other when {@link #setAsButtonActions()} is called is
- * recommended for button actions such as "yes", "no".
- * <p>
- * Many aspects of the base GuidedActionsStylist can be customized through theming; see the
- * theme attributes below. Note that these attributes are not set on individual elements in layout
- * XML, but instead would be set in a custom theme. See
- * <a href="http://developer.android.com/guide/topics/ui/themes.html">Styles and Themes</a>
- * for more information.
- * <p>
- * If these hooks are insufficient, this class may also be subclassed. Subclasses may wish to
- * override the {@link #onProvideLayoutId} method to change the layout used to display the
- * list container and selector; override {@link #onProvideItemLayoutId(int)} and
- * {@link #getItemViewType(GuidedAction)} method to change the layout used to display each action.
- * <p>
- * To support a "click to activate" view similar to DatePicker, app needs:
- * <li> Override {@link #onProvideItemLayoutId(int)} and {@link #getItemViewType(GuidedAction)},
- * provides a layout id for the action.
- * <li> The layout must include a widget with id "guidedactions_activator_item", the widget is
- * toggled edit mode by {@link View#setActivated(boolean)}.
- * <li> Override {@link #onBindActivatorView(ViewHolder, GuidedAction)} to populate values into View.
- * <li> Override {@link #onUpdateActivatorView(ViewHolder, GuidedAction)} to update action.
- * <p>
- * Note: If an alternate list layout is provided, the following view IDs must be supplied:
- * <ul>
- * <li>{@link android.support.v17.leanback.R.id#guidedactions_list}</li>
- * </ul><p>
- * These view IDs must be present in order for the stylist to function. The list ID must correspond
- * to a {@link VerticalGridView} or subclass.
- * <p>
- * If an alternate item layout is provided, the following view IDs should be used to refer to base
- * elements:
- * <ul>
- * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_content}</li>
- * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_title}</li>
- * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_description}</li>
- * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_icon}</li>
- * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_checkmark}</li>
- * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_chevron}</li>
- * </ul><p>
- * These view IDs are allowed to be missing, in which case the corresponding views in {@link
- * GuidedActionsStylist.ViewHolder} will be null.
- * <p>
- * In order to support editable actions, the view associated with guidedactions_item_title should
- * be a subclass of {@link android.widget.EditText}, and should satisfy the {@link
- * ImeKeyMonitor} interface.
- *
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorDrawable
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsListStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedSubActionsListStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedButtonActionsListStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContainerStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemCheckmarkStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemIconStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContentStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemTitleStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemDescriptionStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemChevronStyle
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionPressedAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUnpressedAnimation
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionEnabledChevronAlpha
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDisabledChevronAlpha
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMinLines
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMaxLines
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDescriptionMinLines
- * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionVerticalPadding
- * @see android.R.styleable#Theme_listChoiceIndicatorSingle
- * @see android.R.styleable#Theme_listChoiceIndicatorMultiple
- * @see android.support.v17.leanback.app.GuidedStepFragment
- * @see GuidedAction
- */
-public class GuidedActionsStylist implements FragmentAnimationProvider {
-
-    /**
-     * Default viewType that associated with default layout Id for the action item.
-     * @see #getItemViewType(GuidedAction)
-     * @see #onProvideItemLayoutId(int)
-     * @see #onCreateViewHolder(ViewGroup, int)
-     */
-    public static final int VIEW_TYPE_DEFAULT = 0;
-
-    /**
-     * ViewType for DatePicker.
-     */
-    public static final int VIEW_TYPE_DATE_PICKER = 1;
-
-    final static ItemAlignmentFacet sGuidedActionItemAlignFacet;
-
-    static {
-        sGuidedActionItemAlignFacet = new ItemAlignmentFacet();
-        ItemAlignmentFacet.ItemAlignmentDef alignedDef = new ItemAlignmentFacet.ItemAlignmentDef();
-        alignedDef.setItemAlignmentViewId(R.id.guidedactions_item_title);
-        alignedDef.setAlignedToTextViewBaseline(true);
-        alignedDef.setItemAlignmentOffset(0);
-        alignedDef.setItemAlignmentOffsetWithPadding(true);
-        alignedDef.setItemAlignmentOffsetPercent(0);
-        sGuidedActionItemAlignFacet.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]{alignedDef});
-    }
-
-    /**
-     * ViewHolder caches information about the action item layouts' subviews. Subclasses of {@link
-     * GuidedActionsStylist} may also wish to subclass this in order to add fields.
-     * @see GuidedAction
-     */
-    public static class ViewHolder extends RecyclerView.ViewHolder implements FacetProvider {
-
-        GuidedAction mAction;
-        private View mContentView;
-        TextView mTitleView;
-        TextView mDescriptionView;
-        View mActivatorView;
-        ImageView mIconView;
-        ImageView mCheckmarkView;
-        ImageView mChevronView;
-        int mEditingMode = EDITING_NONE;
-        private final boolean mIsSubAction;
-        Animator mPressAnimator;
-
-        final AccessibilityDelegate mDelegate = new AccessibilityDelegate() {
-            @Override
-            public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
-                super.onInitializeAccessibilityEvent(host, event);
-                event.setChecked(mAction != null && mAction.isChecked());
-            }
-
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                info.setCheckable(
-                        mAction != null && mAction.getCheckSetId() != GuidedAction.NO_CHECK_SET);
-                info.setChecked(mAction != null && mAction.isChecked());
-            }
-        };
-
-        /**
-         * Constructs an ViewHolder and caches the relevant subviews.
-         */
-        public ViewHolder(View v) {
-            this(v, false);
-        }
-
-        /**
-         * Constructs an ViewHolder for sub action and caches the relevant subviews.
-         */
-        public ViewHolder(View v, boolean isSubAction) {
-            super(v);
-
-            mContentView = v.findViewById(R.id.guidedactions_item_content);
-            mTitleView = (TextView) v.findViewById(R.id.guidedactions_item_title);
-            mActivatorView = v.findViewById(R.id.guidedactions_activator_item);
-            mDescriptionView = (TextView) v.findViewById(R.id.guidedactions_item_description);
-            mIconView = (ImageView) v.findViewById(R.id.guidedactions_item_icon);
-            mCheckmarkView = (ImageView) v.findViewById(R.id.guidedactions_item_checkmark);
-            mChevronView = (ImageView) v.findViewById(R.id.guidedactions_item_chevron);
-            mIsSubAction = isSubAction;
-
-            v.setAccessibilityDelegate(mDelegate);
-        }
-
-        /**
-         * Returns the content view within this view holder's view, where title and description are
-         * shown.
-         */
-        public View getContentView() {
-            return mContentView;
-        }
-
-        /**
-         * Returns the title view within this view holder's view.
-         */
-        public TextView getTitleView() {
-            return mTitleView;
-        }
-
-        /**
-         * Convenience method to return an editable version of the title, if possible,
-         * or null if the title view isn't an EditText.
-         */
-        public EditText getEditableTitleView() {
-            return (mTitleView instanceof EditText) ? (EditText)mTitleView : null;
-        }
-
-        /**
-         * Returns the description view within this view holder's view.
-         */
-        public TextView getDescriptionView() {
-            return mDescriptionView;
-        }
-
-        /**
-         * Convenience method to return an editable version of the description, if possible,
-         * or null if the description view isn't an EditText.
-         */
-        public EditText getEditableDescriptionView() {
-            return (mDescriptionView instanceof EditText) ? (EditText)mDescriptionView : null;
-        }
-
-        /**
-         * Returns the icon view within this view holder's view.
-         */
-        public ImageView getIconView() {
-            return mIconView;
-        }
-
-        /**
-         * Returns the checkmark view within this view holder's view.
-         */
-        public ImageView getCheckmarkView() {
-            return mCheckmarkView;
-        }
-
-        /**
-         * Returns the chevron view within this view holder's view.
-         */
-        public ImageView getChevronView() {
-            return mChevronView;
-        }
-
-        /**
-         * Returns true if in editing title, description, or activator View, false otherwise.
-         */
-        public boolean isInEditing() {
-            return mEditingMode != EDITING_NONE;
-        }
-
-        /**
-         * Returns true if in editing title, description, so IME would be open.
-         * @return True if in editing title, description, so IME would be open, false otherwise.
-         */
-        public boolean isInEditingText() {
-            return mEditingMode == EDITING_TITLE || mEditingMode == EDITING_DESCRIPTION;
-        }
-
-        /**
-         * Returns true if the TextView is in editing title, false otherwise.
-         */
-        public boolean isInEditingTitle() {
-            return mEditingMode == EDITING_TITLE;
-        }
-
-        /**
-         * Returns true if the TextView is in editing description, false otherwise.
-         */
-        public boolean isInEditingDescription() {
-            return mEditingMode == EDITING_DESCRIPTION;
-        }
-
-        /**
-         * Returns true if is in editing activator view with id guidedactions_activator_item, false
-         * otherwise.
-         */
-        public boolean isInEditingActivatorView() {
-            return mEditingMode == EDITING_ACTIVATOR_VIEW;
-        }
-
-        /**
-         * @return Current editing title view or description view or activator view or null if not
-         * in editing.
-         */
-        public View getEditingView() {
-            switch(mEditingMode) {
-            case EDITING_TITLE:
-                return mTitleView;
-            case EDITING_DESCRIPTION:
-                return mDescriptionView;
-            case EDITING_ACTIVATOR_VIEW:
-                return mActivatorView;
-            case EDITING_NONE:
-            default:
-                return null;
-            }
-        }
-
-        /**
-         * @return True if bound action is inside {@link GuidedAction#getSubActions()}, false
-         * otherwise.
-         */
-        public boolean isSubAction() {
-            return mIsSubAction;
-        }
-
-        /**
-         * @return Currently bound action.
-         */
-        public GuidedAction getAction() {
-            return mAction;
-        }
-
-        void setActivated(boolean activated) {
-            mActivatorView.setActivated(activated);
-            if (itemView instanceof GuidedActionItemContainer) {
-                ((GuidedActionItemContainer) itemView).setFocusOutAllowed(!activated);
-            }
-        }
-
-        @Override
-        public Object getFacet(Class<?> facetClass) {
-            if (facetClass == ItemAlignmentFacet.class) {
-                return sGuidedActionItemAlignFacet;
-            }
-            return null;
-        }
-
-        void press(boolean pressed) {
-            if (mPressAnimator != null) {
-                mPressAnimator.cancel();
-                mPressAnimator = null;
-            }
-            final int themeAttrId = pressed ? R.attr.guidedActionPressedAnimation :
-                    R.attr.guidedActionUnpressedAnimation;
-            Context ctx = itemView.getContext();
-            TypedValue typedValue = new TypedValue();
-            if (ctx.getTheme().resolveAttribute(themeAttrId, typedValue, true)) {
-                mPressAnimator = AnimatorInflater.loadAnimator(ctx, typedValue.resourceId);
-                mPressAnimator.setTarget(itemView);
-                mPressAnimator.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        mPressAnimator = null;
-                    }
-                });
-                mPressAnimator.start();
-            }
-        }
-    }
-
-    private static String TAG = "GuidedActionsStylist";
-
-    ViewGroup mMainView;
-    private VerticalGridView mActionsGridView;
-    VerticalGridView mSubActionsGridView;
-    private View mSubActionsBackground;
-    private View mBgView;
-    private View mContentView;
-    private boolean mButtonActions;
-
-    // Cached values from resources
-    private float mEnabledTextAlpha;
-    private float mDisabledTextAlpha;
-    private float mEnabledDescriptionAlpha;
-    private float mDisabledDescriptionAlpha;
-    private float mEnabledChevronAlpha;
-    private float mDisabledChevronAlpha;
-    private int mTitleMinLines;
-    private int mTitleMaxLines;
-    private int mDescriptionMinLines;
-    private int mVerticalPadding;
-    private int mDisplayHeight;
-
-    private EditListener mEditListener;
-
-    private GuidedAction mExpandedAction = null;
-    Object mExpandTransition;
-    private boolean mBackToCollapseSubActions = true;
-    private boolean mBackToCollapseActivatorView = true;
-
-    private float mKeyLinePercent;
-
-    /**
-     * Creates a view appropriate for displaying a list of GuidedActions, using the provided
-     * inflater and container.
-     * <p>
-     * <i>Note: Does not actually add the created view to the container; the caller should do
-     * this.</i>
-     * @param inflater The layout inflater to be used when constructing the view.
-     * @param container The view group to be passed in the call to
-     * <code>LayoutInflater.inflate</code>.
-     * @return The view to be added to the caller's view hierarchy.
-     */
-    public View onCreateView(LayoutInflater inflater, final ViewGroup container) {
-        TypedArray ta = inflater.getContext().getTheme().obtainStyledAttributes(
-                R.styleable.LeanbackGuidedStepTheme);
-        float keylinePercent = ta.getFloat(R.styleable.LeanbackGuidedStepTheme_guidedStepKeyline,
-                40);
-        mMainView = (ViewGroup) inflater.inflate(onProvideLayoutId(), container, false);
-        mContentView = mMainView.findViewById(mButtonActions ? R.id.guidedactions_content2 :
-                R.id.guidedactions_content);
-        mBgView = mMainView.findViewById(mButtonActions ? R.id.guidedactions_list_background2 :
-                R.id.guidedactions_list_background);
-        if (mMainView instanceof VerticalGridView) {
-            mActionsGridView = (VerticalGridView) mMainView;
-        } else {
-            mActionsGridView = (VerticalGridView) mMainView.findViewById(mButtonActions
-                    ? R.id.guidedactions_list2 : R.id.guidedactions_list);
-            if (mActionsGridView == null) {
-                throw new IllegalStateException("No ListView exists.");
-            }
-            mActionsGridView.setWindowAlignmentOffsetPercent(keylinePercent);
-            mActionsGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
-            if (!mButtonActions) {
-                mSubActionsGridView = (VerticalGridView) mMainView.findViewById(
-                        R.id.guidedactions_sub_list);
-                mSubActionsBackground = mMainView.findViewById(
-                        R.id.guidedactions_sub_list_background);
-            }
-        }
-        mActionsGridView.setFocusable(false);
-        mActionsGridView.setFocusableInTouchMode(false);
-
-        // Cache widths, chevron alpha values, max and min text lines, etc
-        Context ctx = mMainView.getContext();
-        TypedValue val = new TypedValue();
-        mEnabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionEnabledChevronAlpha);
-        mDisabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionDisabledChevronAlpha);
-        mTitleMinLines = getInteger(ctx, val, R.attr.guidedActionTitleMinLines);
-        mTitleMaxLines = getInteger(ctx, val, R.attr.guidedActionTitleMaxLines);
-        mDescriptionMinLines = getInteger(ctx, val, R.attr.guidedActionDescriptionMinLines);
-        mVerticalPadding = getDimension(ctx, val, R.attr.guidedActionVerticalPadding);
-        mDisplayHeight = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
-                .getDefaultDisplay().getHeight();
-
-        mEnabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
-                .lb_guidedactions_item_unselected_text_alpha));
-        mDisabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
-                .lb_guidedactions_item_disabled_text_alpha));
-        mEnabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
-                .lb_guidedactions_item_unselected_description_text_alpha));
-        mDisabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
-                .lb_guidedactions_item_disabled_description_text_alpha));
-
-        mKeyLinePercent = GuidanceStylingRelativeLayout.getKeyLinePercent(ctx);
-        if (mContentView instanceof GuidedActionsRelativeLayout) {
-            ((GuidedActionsRelativeLayout) mContentView).setInterceptKeyEventListener(
-                    new GuidedActionsRelativeLayout.InterceptKeyEventListener() {
-                        @Override
-                        public boolean onInterceptKeyEvent(KeyEvent event) {
-                            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
-                                    && event.getAction() == KeyEvent.ACTION_UP
-                                    && mExpandedAction != null) {
-                                if ((mExpandedAction.hasSubActions()
-                                        && isBackKeyToCollapseSubActions())
-                                        || (mExpandedAction.hasEditableActivatorView()
-                                        && isBackKeyToCollapseActivatorView())) {
-                                    collapseAction(true);
-                                    return true;
-                                }
-                            }
-                            return false;
-                        }
-                    }
-            );
-        }
-        return mMainView;
-    }
-
-    /**
-     * Choose the layout resource for button actions in {@link #onProvideLayoutId()}.
-     */
-    public void setAsButtonActions() {
-        if (mMainView != null) {
-            throw new IllegalStateException("setAsButtonActions() must be called before creating "
-                    + "views");
-        }
-        mButtonActions = true;
-    }
-
-    /**
-     * Returns true if it is button actions list, false for normal actions list.
-     * @return True if it is button actions list, false for normal actions list.
-     */
-    public boolean isButtonActions() {
-        return mButtonActions;
-    }
-
-    /**
-     * Called when destroy the View created by GuidedActionsStylist.
-     */
-    public void onDestroyView() {
-        mExpandedAction = null;
-        mExpandTransition = null;
-        mActionsGridView = null;
-        mSubActionsGridView = null;
-        mSubActionsBackground = null;
-        mContentView = null;
-        mBgView = null;
-        mMainView = null;
-    }
-
-    /**
-     * Returns the VerticalGridView that displays the list of GuidedActions.
-     * @return The VerticalGridView for this presenter.
-     */
-    public VerticalGridView getActionsGridView() {
-        return mActionsGridView;
-    }
-
-    /**
-     * Returns the VerticalGridView that displays the sub actions list of an expanded action.
-     * @return The VerticalGridView that displays the sub actions list of an expanded action.
-     */
-    public VerticalGridView getSubActionsGridView() {
-        return mSubActionsGridView;
-    }
-
-    /**
-     * Provides the resource ID of the layout defining the host view for the list of guided actions.
-     * Subclasses may override to provide their own customized layouts. The base implementation
-     * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions} or
-     * {@link android.support.v17.leanback.R.layout#lb_guidedbuttonactions} if
-     * {@link #isButtonActions()} is true. If overridden, the substituted layout should contain
-     * matching IDs for any views that should be managed by the base class; this can be achieved by
-     * starting with a copy of the base layout file.
-     *
-     * @return The resource ID of the layout to be inflated to define the host view for the list of
-     *         GuidedActions.
-     */
-    public int onProvideLayoutId() {
-        return mButtonActions ? R.layout.lb_guidedbuttonactions : R.layout.lb_guidedactions;
-    }
-
-    /**
-     * Return view type of action, each different type can have differently associated layout Id.
-     * Default implementation returns {@link #VIEW_TYPE_DEFAULT}.
-     * @param action  The action object.
-     * @return View type that used in {@link #onProvideItemLayoutId(int)}.
-     */
-    public int getItemViewType(GuidedAction action) {
-        if (action instanceof GuidedDatePickerAction) {
-            return VIEW_TYPE_DATE_PICKER;
-        }
-        return VIEW_TYPE_DEFAULT;
-    }
-
-    /**
-     * Provides the resource ID of the layout defining the view for an individual guided actions.
-     * Subclasses may override to provide their own customized layouts. The base implementation
-     * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden,
-     * the substituted layout should contain matching IDs for any views that should be managed by
-     * the base class; this can be achieved by starting with a copy of the base layout file. Note
-     * that in order for the item to support editing, the title view should both subclass {@link
-     * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link
-     * GuidedActionEditText}.  To support different types of Layouts, override {@link
-     * #onProvideItemLayoutId(int)}.
-     * @return The resource ID of the layout to be inflated to define the view to display an
-     * individual GuidedAction.
-     */
-    public int onProvideItemLayoutId() {
-        return R.layout.lb_guidedactions_item;
-    }
-
-    /**
-     * Provides the resource ID of the layout defining the view for an individual guided actions.
-     * Subclasses may override to provide their own customized layouts. The base implementation
-     * supports:
-     * <li>{@link android.support.v17.leanback.R.layout#lb_guidedactions_item}
-     * <li>{{@link android.support.v17.leanback.R.layout#lb_guidedactions_datepicker_item}. If
-     * overridden, the substituted layout should contain matching IDs for any views that should be
-     * managed by the base class; this can be achieved by starting with a copy of the base layout
-     * file. Note that in order for the item to support editing, the title view should both subclass
-     * {@link android.widget.EditText} and implement {@link ImeKeyMonitor}; see
-     * {@link GuidedActionEditText}.
-     *
-     * @param viewType View type returned by {@link #getItemViewType(GuidedAction)}
-     * @return The resource ID of the layout to be inflated to define the view to display an
-     *         individual GuidedAction.
-     */
-    public int onProvideItemLayoutId(int viewType) {
-        if (viewType == VIEW_TYPE_DEFAULT) {
-            return onProvideItemLayoutId();
-        } else if (viewType == VIEW_TYPE_DATE_PICKER) {
-            return R.layout.lb_guidedactions_datepicker_item;
-        } else {
-            throw new RuntimeException("ViewType " + viewType
-                    + " not supported in GuidedActionsStylist");
-        }
-    }
-
-    /**
-     * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
-     * may choose to return a subclass of ViewHolder.  To support different view types, override
-     * {@link #onCreateViewHolder(ViewGroup, int)}
-     * <p>
-     * <i>Note: Should not actually add the created view to the parent; the caller will do
-     * this.</i>
-     * @param parent The view group to be used as the parent of the new view.
-     * @return The view to be added to the caller's view hierarchy.
-     */
-    public ViewHolder onCreateViewHolder(ViewGroup parent) {
-        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
-        View v = inflater.inflate(onProvideItemLayoutId(), parent, false);
-        return new ViewHolder(v, parent == mSubActionsGridView);
-    }
-
-    /**
-     * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
-     * may choose to return a subclass of ViewHolder.
-     * <p>
-     * <i>Note: Should not actually add the created view to the parent; the caller will do
-     * this.</i>
-     * @param parent The view group to be used as the parent of the new view.
-     * @param viewType The viewType returned by {@link #getItemViewType(GuidedAction)}
-     * @return The view to be added to the caller's view hierarchy.
-     */
-    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        if (viewType == VIEW_TYPE_DEFAULT) {
-            return onCreateViewHolder(parent);
-        }
-        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
-        View v = inflater.inflate(onProvideItemLayoutId(viewType), parent, false);
-        return new ViewHolder(v, parent == mSubActionsGridView);
-    }
-
-    /**
-     * Binds a {@link ViewHolder} to a particular {@link GuidedAction}.
-     * @param vh The view holder to be associated with the given action.
-     * @param action The guided action to be displayed by the view holder's view.
-     * @return The view to be added to the caller's view hierarchy.
-     */
-    public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
-        vh.mAction = action;
-        if (vh.mTitleView != null) {
-            vh.mTitleView.setInputType(action.getInputType());
-            vh.mTitleView.setText(action.getTitle());
-            vh.mTitleView.setAlpha(action.isEnabled() ? mEnabledTextAlpha : mDisabledTextAlpha);
-            vh.mTitleView.setFocusable(false);
-            vh.mTitleView.setClickable(false);
-            vh.mTitleView.setLongClickable(false);
-        }
-        if (vh.mDescriptionView != null) {
-            vh.mDescriptionView.setInputType(action.getDescriptionInputType());
-            vh.mDescriptionView.setText(action.getDescription());
-            vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription())
-                    ? View.GONE : View.VISIBLE);
-            vh.mDescriptionView.setAlpha(action.isEnabled() ? mEnabledDescriptionAlpha :
-                mDisabledDescriptionAlpha);
-            vh.mDescriptionView.setFocusable(false);
-            vh.mDescriptionView.setClickable(false);
-            vh.mDescriptionView.setLongClickable(false);
-        }
-        // Clients might want the check mark view to be gone entirely, in which case, ignore it.
-        if (vh.mCheckmarkView != null) {
-            onBindCheckMarkView(vh, action);
-        }
-        setIcon(vh.mIconView, action);
-
-        if (action.hasMultilineDescription()) {
-            if (vh.mTitleView != null) {
-                setMaxLines(vh.mTitleView, mTitleMaxLines);
-                vh.mTitleView.setInputType(
-                        vh.mTitleView.getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
-                if (vh.mDescriptionView != null) {
-                    vh.mDescriptionView.setInputType(vh.mDescriptionView.getInputType()
-                            | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
-                    vh.mDescriptionView.setMaxHeight(getDescriptionMaxHeight(
-                            vh.itemView.getContext(), vh.mTitleView));
-                }
-            }
-        } else {
-            if (vh.mTitleView != null) {
-                setMaxLines(vh.mTitleView, mTitleMinLines);
-            }
-            if (vh.mDescriptionView != null) {
-                setMaxLines(vh.mDescriptionView, mDescriptionMinLines);
-            }
-        }
-        if (vh.mActivatorView != null) {
-            onBindActivatorView(vh, action);
-        }
-        setEditingMode(vh, false /*editing*/, false /*withTransition*/);
-        if (action.isFocusable()) {
-            vh.itemView.setFocusable(true);
-            ((ViewGroup) vh.itemView).setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-        } else {
-            vh.itemView.setFocusable(false);
-            ((ViewGroup) vh.itemView).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-        }
-        setupImeOptions(vh, action);
-
-        updateChevronAndVisibility(vh);
-    }
-
-    /**
-     * Switches action to edit mode and pops up the keyboard.
-     */
-    public void openInEditMode(GuidedAction action) {
-        final GuidedActionAdapter guidedActionAdapter =
-                (GuidedActionAdapter) getActionsGridView().getAdapter();
-        int actionIndex = guidedActionAdapter.getActions().indexOf(action);
-        if (actionIndex < 0 || !action.isEditable()) {
-            return;
-        }
-
-        getActionsGridView().setSelectedPosition(actionIndex, new ViewHolderTask() {
-            @Override
-            public void run(RecyclerView.ViewHolder viewHolder) {
-                ViewHolder vh = (ViewHolder) viewHolder;
-                guidedActionAdapter.mGroup.openIme(guidedActionAdapter, vh);
-            }
-        });
-    }
-
-    private static void setMaxLines(TextView view, int maxLines) {
-        // setSingleLine must be called before setMaxLines because it resets maximum to
-        // Integer.MAX_VALUE.
-        if (maxLines == 1) {
-            view.setSingleLine(true);
-        } else {
-            view.setSingleLine(false);
-            view.setMaxLines(maxLines);
-        }
-    }
-
-    /**
-     * Called by {@link #onBindViewHolder(ViewHolder, GuidedAction)} to setup IME options.  Default
-     * implementation assigns {@link EditorInfo#IME_ACTION_DONE}.  Subclass may override.
-     * @param vh The view holder to be associated with the given action.
-     * @param action The guided action to be displayed by the view holder's view.
-     */
-    protected void setupImeOptions(ViewHolder vh, GuidedAction action) {
-        setupNextImeOptions(vh.getEditableTitleView());
-        setupNextImeOptions(vh.getEditableDescriptionView());
-    }
-
-    private void setupNextImeOptions(EditText edit) {
-        if (edit != null) {
-            edit.setImeOptions(EditorInfo.IME_ACTION_NEXT);
-        }
-    }
-
-    /**
-     * @deprecated This method is for internal library use only and should not
-     *             be called directly.
-     */
-    @Deprecated
-    public void setEditingMode(ViewHolder vh, GuidedAction action, boolean editing) {
-        if (editing != vh.isInEditing() && isInExpandTransition()) {
-            onEditingModeChange(vh, action, editing);
-        }
-    }
-
-    void setEditingMode(ViewHolder vh, boolean editing) {
-        setEditingMode(vh, editing, true /*withTransition*/);
-    }
-
-    void setEditingMode(ViewHolder vh, boolean editing, boolean withTransition) {
-        if (editing != vh.isInEditing() && !isInExpandTransition()) {
-            onEditingModeChange(vh, editing, withTransition);
-        }
-    }
-
-    /**
-     * @deprecated Use {@link #onEditingModeChange(ViewHolder, boolean, boolean)}.
-     */
-    @Deprecated
-    protected void onEditingModeChange(ViewHolder vh, GuidedAction action, boolean editing) {
-    }
-
-    /**
-     * Called when editing mode of an ViewHolder is changed.  Subclass must call
-     * <code>super.onEditingModeChange(vh,editing,withTransition)</code>.
-     *
-     * @param vh                ViewHolder to change editing mode.
-     * @param editing           True to enable editing, false to stop editing
-     * @param withTransition    True to run expand transiiton, false otherwise.
-     */
-    @CallSuper
-    protected void onEditingModeChange(ViewHolder vh, boolean editing, boolean withTransition) {
-        GuidedAction action = vh.getAction();
-        TextView titleView = vh.getTitleView();
-        TextView descriptionView = vh.getDescriptionView();
-        if (editing) {
-            CharSequence editTitle = action.getEditTitle();
-            if (titleView != null && editTitle != null) {
-                titleView.setText(editTitle);
-            }
-            CharSequence editDescription = action.getEditDescription();
-            if (descriptionView != null && editDescription != null) {
-                descriptionView.setText(editDescription);
-            }
-            if (action.isDescriptionEditable()) {
-                if (descriptionView != null) {
-                    descriptionView.setVisibility(View.VISIBLE);
-                    descriptionView.setInputType(action.getDescriptionEditInputType());
-                }
-                vh.mEditingMode = EDITING_DESCRIPTION;
-            } else if (action.isEditable()){
-                if (titleView != null) {
-                    titleView.setInputType(action.getEditInputType());
-                }
-                vh.mEditingMode = EDITING_TITLE;
-            } else if (vh.mActivatorView != null) {
-                onEditActivatorView(vh, editing, withTransition);
-                vh.mEditingMode = EDITING_ACTIVATOR_VIEW;
-            }
-        } else {
-            if (titleView != null) {
-                titleView.setText(action.getTitle());
-            }
-            if (descriptionView != null) {
-                descriptionView.setText(action.getDescription());
-            }
-            if (vh.mEditingMode == EDITING_DESCRIPTION) {
-                if (descriptionView != null) {
-                    descriptionView.setVisibility(TextUtils.isEmpty(action.getDescription())
-                            ? View.GONE : View.VISIBLE);
-                    descriptionView.setInputType(action.getDescriptionInputType());
-                }
-            } else if (vh.mEditingMode == EDITING_TITLE) {
-                if (titleView != null) {
-                    titleView.setInputType(action.getInputType());
-                }
-            } else if (vh.mEditingMode == EDITING_ACTIVATOR_VIEW) {
-                if (vh.mActivatorView != null) {
-                    onEditActivatorView(vh, editing, withTransition);
-                }
-            }
-            vh.mEditingMode = EDITING_NONE;
-        }
-        // call deprecated method for backward compatible
-        onEditingModeChange(vh, action, editing);
-    }
-
-    /**
-     * Animates the view holder's view (or subviews thereof) when the action has had its focus
-     * state changed.
-     * @param vh The view holder associated with the relevant action.
-     * @param focused True if the action has become focused, false if it has lost focus.
-     */
-    public void onAnimateItemFocused(ViewHolder vh, boolean focused) {
-        // No animations for this, currently, because the animation is done on
-        // mSelectorView
-    }
-
-    /**
-     * Animates the view holder's view (or subviews thereof) when the action has had its press
-     * state changed.
-     * @param vh The view holder associated with the relevant action.
-     * @param pressed True if the action has been pressed, false if it has been unpressed.
-     */
-    public void onAnimateItemPressed(ViewHolder vh, boolean pressed) {
-        vh.press(pressed);
-    }
-
-    /**
-     * Resets the view holder's view to unpressed state.
-     * @param vh The view holder associated with the relevant action.
-     */
-    public void onAnimateItemPressedCancelled(ViewHolder vh) {
-        vh.press(false);
-    }
-
-    /**
-     * Animates the view holder's view (or subviews thereof) when the action has had its check state
-     * changed. Default implementation calls setChecked() if {@link ViewHolder#getCheckmarkView()}
-     * is instance of {@link Checkable}.
-     *
-     * @param vh The view holder associated with the relevant action.
-     * @param checked True if the action has become checked, false if it has become unchecked.
-     * @see #onBindCheckMarkView(ViewHolder, GuidedAction)
-     */
-    public void onAnimateItemChecked(ViewHolder vh, boolean checked) {
-        if (vh.mCheckmarkView instanceof Checkable) {
-            ((Checkable) vh.mCheckmarkView).setChecked(checked);
-        }
-    }
-
-    /**
-     * Sets states of check mark view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}
-     * when action's checkset Id is other than {@link GuidedAction#NO_CHECK_SET}. Default
-     * implementation assigns drawable loaded from theme attribute
-     * {@link android.R.attr#listChoiceIndicatorMultiple} for checkbox or
-     * {@link android.R.attr#listChoiceIndicatorSingle} for radio button. Subclass rarely needs
-     * override the method, instead app can provide its own drawable that supports transition
-     * animations, change theme attributes {@link android.R.attr#listChoiceIndicatorMultiple} and
-     * {@link android.R.attr#listChoiceIndicatorSingle} in {android.support.v17.leanback.R.
-     * styleable#LeanbackGuidedStepTheme}.
-     *
-     * @param vh The view holder associated with the relevant action.
-     * @param action The GuidedAction object to bind to.
-     * @see #onAnimateItemChecked(ViewHolder, boolean)
-     */
-    public void onBindCheckMarkView(ViewHolder vh, GuidedAction action) {
-        if (action.getCheckSetId() != GuidedAction.NO_CHECK_SET) {
-            vh.mCheckmarkView.setVisibility(View.VISIBLE);
-            int attrId = action.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID
-                    ? android.R.attr.listChoiceIndicatorMultiple
-                    : android.R.attr.listChoiceIndicatorSingle;
-            final Context context = vh.mCheckmarkView.getContext();
-            Drawable drawable = null;
-            TypedValue typedValue = new TypedValue();
-            if (context.getTheme().resolveAttribute(attrId, typedValue, true)) {
-                drawable = ContextCompat.getDrawable(context, typedValue.resourceId);
-            }
-            vh.mCheckmarkView.setImageDrawable(drawable);
-            if (vh.mCheckmarkView instanceof Checkable) {
-                ((Checkable) vh.mCheckmarkView).setChecked(action.isChecked());
-            }
-        } else {
-            vh.mCheckmarkView.setVisibility(View.GONE);
-        }
-    }
-
-    /**
-     * Performs binding activator view value to action.  Default implementation supports
-     * GuidedDatePickerAction, subclass may override to add support of other views.
-     * @param vh ViewHolder of activator view.
-     * @param action GuidedAction to bind.
-     */
-    public void onBindActivatorView(ViewHolder vh, GuidedAction action) {
-        if (action instanceof GuidedDatePickerAction) {
-            GuidedDatePickerAction dateAction = (GuidedDatePickerAction) action;
-            DatePicker dateView = (DatePicker) vh.mActivatorView;
-            dateView.setDatePickerFormat(dateAction.getDatePickerFormat());
-            if (dateAction.getMinDate() != Long.MIN_VALUE) {
-                dateView.setMinDate(dateAction.getMinDate());
-            }
-            if (dateAction.getMaxDate() != Long.MAX_VALUE) {
-                dateView.setMaxDate(dateAction.getMaxDate());
-            }
-            Calendar c = Calendar.getInstance();
-            c.setTimeInMillis(dateAction.getDate());
-            dateView.updateDate(c.get(Calendar.YEAR), c.get(Calendar.MONTH),
-                    c.get(Calendar.DAY_OF_MONTH), false);
-        }
-    }
-
-    /**
-     * Performs updating GuidedAction from activator view.  Default implementation supports
-     * GuidedDatePickerAction, subclass may override to add support of other views.
-     * @param vh ViewHolder of activator view.
-     * @param action GuidedAction to update.
-     * @return True if value has been updated, false otherwise.
-     */
-    public boolean onUpdateActivatorView(ViewHolder vh, GuidedAction action) {
-        if (action instanceof GuidedDatePickerAction) {
-            GuidedDatePickerAction dateAction = (GuidedDatePickerAction) action;
-            DatePicker dateView = (DatePicker) vh.mActivatorView;
-            if (dateAction.getDate() != dateView.getDate()) {
-                dateAction.setDate(dateView.getDate());
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Sets listener for reporting view being edited.
-     * @hide
-     */
-    @RestrictTo(LIBRARY_GROUP)
-    public void setEditListener(EditListener listener) {
-        mEditListener = listener;
-    }
-
-    void onEditActivatorView(final ViewHolder vh, boolean editing, final boolean withTransition) {
-        if (editing) {
-            startExpanded(vh, withTransition);
-            vh.itemView.setFocusable(false);
-            vh.mActivatorView.requestFocus();
-            vh.mActivatorView.setOnClickListener(new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    if (!isInExpandTransition()) {
-                        ((GuidedActionAdapter) getActionsGridView().getAdapter())
-                                .performOnActionClick(vh);
-                    }
-                }
-            });
-        } else {
-            if (onUpdateActivatorView(vh, vh.getAction())) {
-                if (mEditListener != null) {
-                    mEditListener.onGuidedActionEditedAndProceed(vh.getAction());
-                }
-            }
-            vh.itemView.setFocusable(true);
-            vh.itemView.requestFocus();
-            startExpanded(null, withTransition);
-            vh.mActivatorView.setOnClickListener(null);
-            vh.mActivatorView.setClickable(false);
-        }
-    }
-
-    /**
-     * Sets states of chevron view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}.
-     * Subclass may override.
-     *
-     * @param vh The view holder associated with the relevant action.
-     * @param action The GuidedAction object to bind to.
-     */
-    public void onBindChevronView(ViewHolder vh, GuidedAction action) {
-        final boolean hasNext = action.hasNext();
-        final boolean hasSubActions = action.hasSubActions();
-        if (hasNext || hasSubActions) {
-            vh.mChevronView.setVisibility(View.VISIBLE);
-            vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
-                    mDisabledChevronAlpha);
-            if (hasNext) {
-                float r = mMainView != null
-                        && mMainView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? 180f : 0f;
-                vh.mChevronView.setRotation(r);
-            } else if (action == mExpandedAction) {
-                vh.mChevronView.setRotation(270);
-            } else {
-                vh.mChevronView.setRotation(90);
-            }
-        } else {
-            vh.mChevronView.setVisibility(View.GONE);
-
-        }
-    }
-
-    /**
-     * Expands or collapse the sub actions list view with transition animation
-     * @param avh When not null, fill sub actions list of this ViewHolder into sub actions list and
-     * hide the other items in main list.  When null, collapse the sub actions list.
-     * @deprecated use {@link #expandAction(GuidedAction, boolean)} and
-     * {@link #collapseAction(boolean)}
-     */
-    @Deprecated
-    public void setExpandedViewHolder(ViewHolder avh) {
-        expandAction(avh == null ? null : avh.getAction(), isExpandTransitionSupported());
-    }
-
-    /**
-     * Returns true if it is running an expanding or collapsing transition, false otherwise.
-     * @return True if it is running an expanding or collapsing transition, false otherwise.
-     */
-    public boolean isInExpandTransition() {
-        return mExpandTransition != null;
-    }
-
-    /**
-     * Returns if expand/collapse animation is supported.  When this method returns true,
-     * {@link #startExpandedTransition(ViewHolder)} will be used.  When this method returns false,
-     * {@link #onUpdateExpandedViewHolder(ViewHolder)} will be called.
-     * @return True if it is running an expanding or collapsing transition, false otherwise.
-     */
-    public boolean isExpandTransitionSupported() {
-        return VERSION.SDK_INT >= 21;
-    }
-
-    /**
-     * Start transition to expand or collapse GuidedActionStylist.
-     * @param avh When not null, the GuidedActionStylist expands the sub actions of avh.  When null
-     * the GuidedActionStylist will collapse sub actions.
-     * @deprecated use {@link #expandAction(GuidedAction, boolean)} and
-     * {@link #collapseAction(boolean)}
-     */
-    @Deprecated
-    public void startExpandedTransition(ViewHolder avh) {
-        expandAction(avh == null ? null : avh.getAction(), isExpandTransitionSupported());
-    }
-
-    /**
-     * Enable or disable using BACK key to collapse sub actions list. Default is enabled.
-     *
-     * @param backToCollapse True to enable using BACK key to collapse sub actions list, false
-     *                       to disable.
-     * @see GuidedAction#hasSubActions
-     * @see GuidedAction#getSubActions
-     */
-    public final void setBackKeyToCollapseSubActions(boolean backToCollapse) {
-        mBackToCollapseSubActions = backToCollapse;
-    }
-
-    /**
-     * @return True if using BACK key to collapse sub actions list, false otherwise. Default value
-     * is true.
-     *
-     * @see GuidedAction#hasSubActions
-     * @see GuidedAction#getSubActions
-     */
-    public final boolean isBackKeyToCollapseSubActions() {
-        return mBackToCollapseSubActions;
-    }
-
-    /**
-     * Enable or disable using BACK key to collapse {@link GuidedAction} with editable activator
-     * view. Default is enabled.
-     *
-     * @param backToCollapse True to enable using BACK key to collapse {@link GuidedAction} with
-     *                       editable activator view.
-     * @see GuidedAction#hasEditableActivatorView
-     */
-    public final void setBackKeyToCollapseActivatorView(boolean backToCollapse) {
-        mBackToCollapseActivatorView = backToCollapse;
-    }
-
-    /**
-     * @return True if using BACK key to collapse {@link GuidedAction} with editable activator
-     * view, false otherwise. Default value is true.
-     *
-     * @see GuidedAction#hasEditableActivatorView
-     */
-    public final boolean isBackKeyToCollapseActivatorView() {
-        return mBackToCollapseActivatorView;
-    }
-
-    /**
-     * Expand an action. Do nothing if it is in animation or there is action expanded.
-     *
-     * @param action         Action to expand.
-     * @param withTransition True to run transition animation, false otherwsie.
-     */
-    public void expandAction(GuidedAction action, final boolean withTransition) {
-        if (isInExpandTransition() || mExpandedAction != null) {
-            return;
-        }
-        int actionPosition =
-                ((GuidedActionAdapter) getActionsGridView().getAdapter()).indexOf(action);
-        if (actionPosition < 0) {
-            return;
-        }
-        boolean runTransition = isExpandTransitionSupported() && withTransition;
-        if (!runTransition) {
-            getActionsGridView().setSelectedPosition(actionPosition,
-                    new ViewHolderTask() {
-                        @Override
-                        public void run(RecyclerView.ViewHolder vh) {
-                            GuidedActionsStylist.ViewHolder avh =
-                                    (GuidedActionsStylist.ViewHolder)vh;
-                            if (avh.getAction().hasEditableActivatorView()) {
-                                setEditingMode(avh, true /*editing*/, false /*withTransition*/);
-                            } else {
-                                onUpdateExpandedViewHolder(avh);
-                            }
-                        }
-                    });
-            if (action.hasSubActions()) {
-                onUpdateSubActionsGridView(action, true);
-            }
-        } else {
-            getActionsGridView().setSelectedPosition(actionPosition,
-                    new ViewHolderTask() {
-                        @Override
-                        public void run(RecyclerView.ViewHolder vh) {
-                            GuidedActionsStylist.ViewHolder avh =
-                                    (GuidedActionsStylist.ViewHolder)vh;
-                            if (avh.getAction().hasEditableActivatorView()) {
-                                setEditingMode(avh, true /*editing*/, true /*withTransition*/);
-                            } else {
-                                startExpanded(avh, true);
-                            }
-                        }
-                    });
-        }
-
-    }
-
-    /**
-     * Collapse expanded action. Do nothing if it is in animation or there is no action expanded.
-     *
-     * @param withTransition True to run transition animation, false otherwsie.
-     */
-    public void collapseAction(boolean withTransition) {
-        if (isInExpandTransition() || mExpandedAction == null) {
-            return;
-        }
-        boolean runTransition = isExpandTransitionSupported() && withTransition;
-        int actionPosition =
-                ((GuidedActionAdapter) getActionsGridView().getAdapter()).indexOf(mExpandedAction);
-        if (actionPosition < 0) {
-            return;
-        }
-        if (mExpandedAction.hasEditableActivatorView()) {
-            setEditingMode(
-                    ((ViewHolder) getActionsGridView().findViewHolderForPosition(actionPosition)),
-                    false /*editing*/,
-                    runTransition);
-        } else {
-            startExpanded(null, runTransition);
-        }
-    }
-
-    int getKeyLine() {
-        return (int) (mKeyLinePercent * mActionsGridView.getHeight() / 100);
-    }
-
-    /**
-     * Internal method with assumption we already scroll to the new ViewHolder or is currently
-     * expanded.
-     */
-    void startExpanded(ViewHolder avh, final boolean withTransition) {
-        ViewHolder focusAvh = null; // expand / collapse view holder
-        final int count = mActionsGridView.getChildCount();
-        for (int i = 0; i < count; i++) {
-            ViewHolder vh = (ViewHolder) mActionsGridView
-                    .getChildViewHolder(mActionsGridView.getChildAt(i));
-            if (avh == null && vh.itemView.getVisibility() == View.VISIBLE) {
-                // going to collapse this one.
-                focusAvh = vh;
-                break;
-            } else if (avh != null && vh.getAction() == avh.getAction()) {
-                // going to expand this one.
-                focusAvh = vh;
-                break;
-            }
-        }
-        if (focusAvh == null) {
-            // huh?
-            return;
-        }
-        boolean isExpand = avh != null;
-        boolean isSubActionTransition = focusAvh.getAction().hasSubActions();
-        if (withTransition) {
-            Object set = TransitionHelper.createTransitionSet(false);
-            float slideDistance = isSubActionTransition ? focusAvh.itemView.getHeight()
-                    : focusAvh.itemView.getHeight() * 0.5f;
-            Object slideAndFade = TransitionHelper.createFadeAndShortSlide(
-                    Gravity.TOP | Gravity.BOTTOM,
-                    slideDistance);
-            TransitionHelper.setEpicenterCallback(slideAndFade, new TransitionEpicenterCallback() {
-                Rect mRect = new Rect();
-                @Override
-                public Rect onGetEpicenter(Object transition) {
-                    int centerY = getKeyLine();
-                    int centerX = 0;
-                    mRect.set(centerX, centerY, centerX, centerY);
-                    return mRect;
-                }
-            });
-            Object changeFocusItemTransform = TransitionHelper.createChangeTransform();
-            Object changeFocusItemBounds = TransitionHelper.createChangeBounds(false);
-            Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN
-                    | TransitionHelper.FADE_OUT);
-            Object changeGridBounds = TransitionHelper.createChangeBounds(false);
-            if (avh == null) {
-                TransitionHelper.setStartDelay(slideAndFade, 150);
-                TransitionHelper.setStartDelay(changeFocusItemTransform, 100);
-                TransitionHelper.setStartDelay(changeFocusItemBounds, 100);
-                TransitionHelper.setStartDelay(changeGridBounds, 100);
-            } else {
-                TransitionHelper.setStartDelay(fade, 100);
-                TransitionHelper.setStartDelay(changeGridBounds, 50);
-                TransitionHelper.setStartDelay(changeFocusItemTransform, 50);
-                TransitionHelper.setStartDelay(changeFocusItemBounds, 50);
-            }
-            for (int i = 0; i < count; i++) {
-                ViewHolder vh = (ViewHolder) mActionsGridView
-                        .getChildViewHolder(mActionsGridView.getChildAt(i));
-                if (vh == focusAvh) {
-                    // going to expand/collapse this one.
-                    if (isSubActionTransition) {
-                        TransitionHelper.include(changeFocusItemTransform, vh.itemView);
-                        TransitionHelper.include(changeFocusItemBounds, vh.itemView);
-                    }
-                } else {
-                    // going to slide this item to top / bottom.
-                    TransitionHelper.include(slideAndFade, vh.itemView);
-                    TransitionHelper.exclude(fade, vh.itemView, true);
-                }
-            }
-            TransitionHelper.include(changeGridBounds, mSubActionsGridView);
-            TransitionHelper.include(changeGridBounds, mSubActionsBackground);
-            TransitionHelper.addTransition(set, slideAndFade);
-            // note that we don't run ChangeBounds for activating view due to the rounding problem
-            // of multiple level views ChangeBounds animation causing vertical jittering.
-            if (isSubActionTransition) {
-                TransitionHelper.addTransition(set, changeFocusItemTransform);
-                TransitionHelper.addTransition(set, changeFocusItemBounds);
-            }
-            TransitionHelper.addTransition(set, fade);
-            TransitionHelper.addTransition(set, changeGridBounds);
-            mExpandTransition = set;
-            TransitionHelper.addTransitionListener(mExpandTransition, new TransitionListener() {
-                @Override
-                public void onTransitionEnd(Object transition) {
-                    mExpandTransition = null;
-                }
-            });
-            if (isExpand && isSubActionTransition) {
-                // To expand sub actions, move original position of sub actions to bottom of item
-                int startY = avh.itemView.getBottom();
-                mSubActionsGridView.offsetTopAndBottom(startY - mSubActionsGridView.getTop());
-                mSubActionsBackground.offsetTopAndBottom(startY - mSubActionsBackground.getTop());
-            }
-            TransitionHelper.beginDelayedTransition(mMainView, mExpandTransition);
-        }
-        onUpdateExpandedViewHolder(avh);
-        if (isSubActionTransition) {
-            onUpdateSubActionsGridView(focusAvh.getAction(), isExpand);
-        }
-    }
-
-    /**
-     * @return True if sub actions list is expanded.
-     */
-    public boolean isSubActionsExpanded() {
-        return mExpandedAction != null && mExpandedAction.hasSubActions();
-    }
-
-    /**
-     * @return True if there is {@link #getExpandedAction()} is not null, false otherwise.
-     */
-    public boolean isExpanded() {
-        return mExpandedAction != null;
-    }
-
-    /**
-     * @return Current expanded GuidedAction or null if not expanded.
-     */
-    public GuidedAction getExpandedAction() {
-        return mExpandedAction;
-    }
-
-    /**
-     * Expand or collapse GuidedActionStylist.
-     * @param avh When not null, the GuidedActionStylist expands the sub actions of avh.  When null
-     * the GuidedActionStylist will collapse sub actions.
-     */
-    public void onUpdateExpandedViewHolder(ViewHolder avh) {
-
-        // Note about setting the prune child flag back & forth here: without this, the actions that
-        // go off the screen from the top or bottom become invisible forever. This is because once
-        // an action is expanded, it takes more space which in turn kicks out some other actions
-        // off of the screen. Once, this action is collapsed (after the second click) and the
-        // visibility flag is set back to true for all existing actions,
-        // the off-the-screen actions are pruned from the view, thus
-        // could not be accessed, had we not disabled pruning prior to this.
-        if (avh == null) {
-            mExpandedAction = null;
-            mActionsGridView.setPruneChild(true);
-        } else if (avh.getAction() != mExpandedAction) {
-            mExpandedAction = avh.getAction();
-            mActionsGridView.setPruneChild(false);
-        }
-        // In expanding mode, notifyItemChange on expanded item will reset the translationY by
-        // the default ItemAnimator.  So disable ItemAnimation in expanding mode.
-        mActionsGridView.setAnimateChildLayout(false);
-        final int count = mActionsGridView.getChildCount();
-        for (int i = 0; i < count; i++) {
-            ViewHolder vh = (ViewHolder) mActionsGridView
-                    .getChildViewHolder(mActionsGridView.getChildAt(i));
-            updateChevronAndVisibility(vh);
-        }
-    }
-
-    void onUpdateSubActionsGridView(GuidedAction action, boolean expand) {
-        if (mSubActionsGridView != null) {
-            ViewGroup.MarginLayoutParams lp =
-                    (ViewGroup.MarginLayoutParams) mSubActionsGridView.getLayoutParams();
-            GuidedActionAdapter adapter = (GuidedActionAdapter) mSubActionsGridView.getAdapter();
-            if (expand) {
-                // set to negative value so GuidedActionRelativeLayout will override with
-                // keyLine percentage.
-                lp.topMargin = -2;
-                lp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
-                mSubActionsGridView.setLayoutParams(lp);
-                mSubActionsGridView.setVisibility(View.VISIBLE);
-                mSubActionsBackground.setVisibility(View.VISIBLE);
-                mSubActionsGridView.requestFocus();
-                adapter.setActions(action.getSubActions());
-            } else {
-                // set to explicit value, which will disable the keyLine percentage calculation
-                // in GuidedRelativeLayout.
-                int actionPosition = ((GuidedActionAdapter) mActionsGridView.getAdapter())
-                        .indexOf(action);
-                lp.topMargin = mActionsGridView.getLayoutManager()
-                        .findViewByPosition(actionPosition).getBottom();
-                lp.height = 0;
-                mSubActionsGridView.setVisibility(View.INVISIBLE);
-                mSubActionsBackground.setVisibility(View.INVISIBLE);
-                mSubActionsGridView.setLayoutParams(lp);
-                adapter.setActions(Collections.EMPTY_LIST);
-                mActionsGridView.requestFocus();
-            }
-        }
-    }
-
-    private void updateChevronAndVisibility(ViewHolder vh) {
-        if (!vh.isSubAction()) {
-            if (mExpandedAction == null) {
-                vh.itemView.setVisibility(View.VISIBLE);
-                vh.itemView.setTranslationY(0);
-                if (vh.mActivatorView != null) {
-                    vh.setActivated(false);
-                }
-            } else if (vh.getAction() == mExpandedAction) {
-                vh.itemView.setVisibility(View.VISIBLE);
-                if (vh.getAction().hasSubActions()) {
-                    vh.itemView.setTranslationY(getKeyLine() - vh.itemView.getBottom());
-                } else if (vh.mActivatorView != null) {
-                    vh.itemView.setTranslationY(0);
-                    vh.setActivated(true);
-                }
-            } else {
-                vh.itemView.setVisibility(View.INVISIBLE);
-                vh.itemView.setTranslationY(0);
-            }
-        }
-        if (vh.mChevronView != null) {
-            onBindChevronView(vh, vh.getAction());
-        }
-    }
-
-    /*
-     * ==========================================
-     * FragmentAnimationProvider overrides
-     * ==========================================
-     */
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onImeAppearing(@NonNull List<Animator> animators) {
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void onImeDisappearing(@NonNull List<Animator> animators) {
-    }
-
-    /*
-     * ==========================================
-     * Private methods
-     * ==========================================
-     */
-
-    private float getFloat(Context ctx, TypedValue typedValue, int attrId) {
-        ctx.getTheme().resolveAttribute(attrId, typedValue, true);
-        // Android resources don't have a native float type, so we have to use strings.
-        return Float.valueOf(ctx.getResources().getString(typedValue.resourceId));
-    }
-
-    private int getInteger(Context ctx, TypedValue typedValue, int attrId) {
-        ctx.getTheme().resolveAttribute(attrId, typedValue, true);
-        return ctx.getResources().getInteger(typedValue.resourceId);
-    }
-
-    private int getDimension(Context ctx, TypedValue typedValue, int attrId) {
-        ctx.getTheme().resolveAttribute(attrId, typedValue, true);
-        return ctx.getResources().getDimensionPixelSize(typedValue.resourceId);
-    }
-
-    private boolean setIcon(final ImageView iconView, GuidedAction action) {
-        Drawable icon = null;
-        if (iconView != null) {
-            icon = action.getIcon();
-            if (icon != null) {
-                // setImageDrawable resets the drawable's level unless we set the view level first.
-                iconView.setImageLevel(icon.getLevel());
-                iconView.setImageDrawable(icon);
-                iconView.setVisibility(View.VISIBLE);
-            } else {
-                iconView.setVisibility(View.GONE);
-            }
-        }
-        return icon != null;
-    }
-
-    /**
-     * @return the max height in pixels the description can be such that the
-     *         action nicely takes up the entire screen.
-     */
-    private int getDescriptionMaxHeight(Context context, TextView title) {
-        // The 2 multiplier on the title height calculation is a
-        // conservative estimate for font padding which can not be
-        // calculated at this stage since the view hasn't been rendered yet.
-        return (int)(mDisplayHeight - 2*mVerticalPadding - 2*mTitleMaxLines*title.getLineHeight());
-    }
-
-}
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java b/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
deleted file mode 100644
index 5e00d99..0000000
--- a/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRow.java
+++ /dev/null
@@ -1,1083 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package android.support.v17.leanback.widget;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.support.v17.leanback.R;
-import android.support.v17.leanback.util.MathUtil;
-import android.util.TypedValue;
-import android.view.KeyEvent;
-
-/**
- * A {@link Row} of playback controls to be displayed by a {@link PlaybackControlsRowPresenter}.
- *
- * This row consists of some optional item detail, a series of primary actions,
- * and an optional series of secondary actions.
- *
- * <p>
- * Controls are specified via an {@link ObjectAdapter} containing one or more
- * {@link Action}s.
- * </p>
- * <p>
- * Adapters should have their {@link PresenterSelector} set to an instance of
- * {@link ControlButtonPresenterSelector}.
- * </p>
- */
-public class PlaybackControlsRow extends Row {
-
-    /**
-     * Listener for progress or duration change.
-     */
-    public static class OnPlaybackProgressCallback {
-        /**
-         * Called when {@link PlaybackControlsRow#getCurrentPosition()} changed.
-         * @param row The PlaybackControlsRow that current time changed.
-         * @param currentTimeMs Current time in milliseconds.
-         */
-        public void onCurrentPositionChanged(PlaybackControlsRow row, long currentTimeMs) {
-        }
-
-        /**
-         * Called when {@link PlaybackControlsRow#getDuration()} changed.
-         * @param row The PlaybackControlsRow that total time changed.
-         * @param totalTime Total time in milliseconds.
-         */
-        public void onDurationChanged(PlaybackControlsRow row, long totalTime) {
-        }
-
-        /**
-         * Called when {@link PlaybackControlsRow#getBufferedPosition()} changed.
-         * @param row The PlaybackControlsRow that buffered progress changed.
-         * @param bufferedProgressMs Buffered time in milliseconds.
-         */
-        public void onBufferedPositionChanged(PlaybackControlsRow row, long bufferedProgressMs) {
-        }
-    }
-
-    /**
-     * Base class for an action comprised of a series of icons.
-     */
-    public static abstract class MultiAction extends Action {
-        private int mIndex;
-        private Drawable[] mDrawables;
-        private String[] mLabels;
-        private String[] mLabels2;
-
-        /**
-         * Constructor
-         * @param id The id of the Action.
-         */
-        public MultiAction(int id) {
-            super(id);
-        }
-
-        /**
-         * Sets the array of drawables.  The size of the array defines the range
-         * of valid indices for this action.
-         */
-        public void setDrawables(Drawable[] drawables) {
-            mDrawables = drawables;
-            setIndex(0);
-        }
-
-        /**
-         * Sets the array of strings used as labels.  The size of the array defines the range
-         * of valid indices for this action.  The labels are used to define the accessibility
-         * content description unless secondary labels are provided.
-         */
-        public void setLabels(String[] labels) {
-            mLabels = labels;
-            setIndex(0);
-        }
-
-        /**
-         * Sets the array of strings used as secondary labels.  These labels are used
-         * in place of the primary labels for accessibility content description only.
-         */
-        public void setSecondaryLabels(String[] labels) {
-            mLabels2 = labels;
-            setIndex(0);
-        }
-
-        /**
-         * Returns the number of actions.
-         */
-        public int getActionCount() {
-            if (mDrawables != null) {
-                return mDrawables.length;
-            }
-            if (mLabels != null) {
-                return mLabels.length;
-            }
-            return 0;
-        }
-
-        /**
-         * Returns the drawable at the given index.
-         */
-        public Drawable getDrawable(int index) {
-            return mDrawables == null ? null : mDrawables[index];
-        }
-
-        /**
-         * Returns the label at the given index.
-         */
-        public String getLabel(int index) {
-            return mLabels == null ? null : mLabels[index];
-        }
-
-        /**
-         * Returns the secondary label at the given index.
-         */
-        public String getSecondaryLabel(int index) {
-            return mLabels2 == null ? null : mLabels2[index];
-        }
-
-        /**
-         * Increments the index, wrapping to zero once the end is reached.
-         */
-        public void nextIndex() {
-            setIndex(mIndex < getActionCount() - 1 ? mIndex + 1 : 0);
-        }
-
-        /**
-         * Sets the current index.
-         */
-        public void setIndex(int index) {
-            mIndex = index;
-            if (mDrawables != null) {
-                setIcon(mDrawables[mIndex]);
-            }
-            if (mLabels != null) {
-                setLabel1(mLabels[mIndex]);
-            }
-            if (mLabels2 != null) {
-                setLabel2(mLabels2[mIndex]);
-            }
-        }
-
-        /**
-         * Returns the current index.
-         */
-        public int getIndex() {
-            return mIndex;
-        }
-    }
-
-    /**
-     * An action displaying icons for play and pause.
-     */
-    public static class PlayPauseAction extends MultiAction {
-        /**
-         * Action index for the play icon.
-         * @deprecated Use {@link #INDEX_PLAY}
-         */
-        @Deprecated
-        public static int PLAY = 0;
-
-        /**
-         * Action index for the pause icon.
-         * @deprecated Use {@link #INDEX_PAUSE}
-         */
-        @Deprecated
-        public static int PAUSE = 1;
-
-        /**
-         * Action index for the play icon.
-         */
-        public static final int INDEX_PLAY = 0;
-
-        /**
-         * Action index for the pause icon.
-         */
-        public static final int INDEX_PAUSE = 1;
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public PlayPauseAction(Context context) {
-            super(R.id.lb_control_play_pause);
-            Drawable[] drawables = new Drawable[2];
-            drawables[INDEX_PLAY] = getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_play);
-            drawables[INDEX_PAUSE] = getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_pause);
-            setDrawables(drawables);
-
-            String[] labels = new String[drawables.length];
-            labels[INDEX_PLAY] = context.getString(R.string.lb_playback_controls_play);
-            labels[INDEX_PAUSE] = context.getString(R.string.lb_playback_controls_pause);
-            setLabels(labels);
-            addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
-            addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY);
-            addKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE);
-        }
-    }
-
-    /**
-     * An action displaying an icon for fast forward.
-     */
-    public static class FastForwardAction extends MultiAction {
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public FastForwardAction(Context context) {
-            this(context, 1);
-        }
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         * @param numSpeeds Number of supported fast forward speeds.
-         */
-        public FastForwardAction(Context context, int numSpeeds) {
-            super(R.id.lb_control_fast_forward);
-
-            if (numSpeeds < 1) {
-                throw new IllegalArgumentException("numSpeeds must be > 0");
-            }
-            Drawable[] drawables = new Drawable[numSpeeds + 1];
-            drawables[0] = getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_fast_forward);
-            setDrawables(drawables);
-
-            String[] labels = new String[getActionCount()];
-            labels[0] = context.getString(R.string.lb_playback_controls_fast_forward);
-
-            String[] labels2 = new String[getActionCount()];
-            labels2[0] = labels[0];
-
-            for (int i = 1; i <= numSpeeds; i++) {
-                int multiplier = i + 1;
-                labels[i] = context.getResources().getString(
-                        R.string.lb_control_display_fast_forward_multiplier, multiplier);
-                labels2[i] = context.getResources().getString(
-                        R.string.lb_playback_controls_fast_forward_multiplier, multiplier);
-            }
-            setLabels(labels);
-            setSecondaryLabels(labels2);
-            addKeyCode(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
-        }
-    }
-
-    /**
-     * An action displaying an icon for rewind.
-     */
-    public static class RewindAction extends MultiAction {
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public RewindAction(Context context) {
-            this(context, 1);
-        }
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         * @param numSpeeds Number of supported fast forward speeds.
-         */
-        public RewindAction(Context context, int numSpeeds) {
-            super(R.id.lb_control_fast_rewind);
-
-            if (numSpeeds < 1) {
-                throw new IllegalArgumentException("numSpeeds must be > 0");
-            }
-            Drawable[] drawables = new Drawable[numSpeeds + 1];
-            drawables[0] = getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_rewind);
-            setDrawables(drawables);
-
-            String[] labels = new String[getActionCount()];
-            labels[0] = context.getString(R.string.lb_playback_controls_rewind);
-
-            String[] labels2 = new String[getActionCount()];
-            labels2[0] = labels[0];
-
-            for (int i = 1; i <= numSpeeds; i++) {
-                int multiplier = i + 1;
-                labels[i] = labels[i] = context.getResources().getString(
-                        R.string.lb_control_display_rewind_multiplier, multiplier);
-                labels2[i] = context.getResources().getString(
-                        R.string.lb_playback_controls_rewind_multiplier, multiplier);
-            }
-            setLabels(labels);
-            setSecondaryLabels(labels2);
-            addKeyCode(KeyEvent.KEYCODE_MEDIA_REWIND);
-        }
-    }
-
-    /**
-     * An action displaying an icon for skip next.
-     */
-    public static class SkipNextAction extends Action {
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public SkipNextAction(Context context) {
-            super(R.id.lb_control_skip_next);
-            setIcon(getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_skip_next));
-            setLabel1(context.getString(R.string.lb_playback_controls_skip_next));
-            addKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT);
-        }
-    }
-
-    /**
-     * An action displaying an icon for skip previous.
-     */
-    public static class SkipPreviousAction extends Action {
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public SkipPreviousAction(Context context) {
-            super(R.id.lb_control_skip_previous);
-            setIcon(getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_skip_previous));
-            setLabel1(context.getString(R.string.lb_playback_controls_skip_previous));
-            addKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
-        }
-    }
-
-    /**
-     * An action displaying an icon for picture-in-picture.
-     */
-    public static class PictureInPictureAction extends Action {
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public PictureInPictureAction(Context context) {
-            super(R.id.lb_control_picture_in_picture);
-            setIcon(getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_picture_in_picture));
-            setLabel1(context.getString(R.string.lb_playback_controls_picture_in_picture));
-            addKeyCode(KeyEvent.KEYCODE_WINDOW);
-        }
-    }
-
-    /**
-     * An action displaying an icon for "more actions".
-     */
-    public static class MoreActions extends Action {
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public MoreActions(Context context) {
-            super(R.id.lb_control_more_actions);
-            setIcon(context.getResources().getDrawable(R.drawable.lb_ic_more));
-            setLabel1(context.getString(R.string.lb_playback_controls_more_actions));
-        }
-    }
-
-    /**
-     * A base class for displaying a thumbs action.
-     */
-    public static abstract class ThumbsAction extends MultiAction {
-        /**
-         * Action index for the solid thumb icon.
-         * @deprecated Use {@link #INDEX_SOLID}
-         */
-        @Deprecated
-        public static int SOLID = 0;
-
-        /**
-         * Action index for the outline thumb icon.
-         * @deprecated Use {@link #INDEX_OUTLINE}
-         */
-        @Deprecated
-        public static int OUTLINE = 1;
-
-        /**
-         * Action index for the solid thumb icon.
-         */
-        public static final int INDEX_SOLID = 0;
-
-        /**
-         * Action index for the outline thumb icon.
-         */
-        public static final int INDEX_OUTLINE = 1;
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public ThumbsAction(int id, Context context, int solidIconIndex, int outlineIconIndex) {
-            super(id);
-            Drawable[] drawables = new Drawable[2];
-            drawables[INDEX_SOLID] = getStyledDrawable(context, solidIconIndex);
-            drawables[INDEX_OUTLINE] = getStyledDrawable(context, outlineIconIndex);
-            setDrawables(drawables);
-        }
-    }
-
-    /**
-     * An action displaying an icon for thumbs up.
-     */
-    public static class ThumbsUpAction extends ThumbsAction {
-        public ThumbsUpAction(Context context) {
-            super(R.id.lb_control_thumbs_up, context,
-                    R.styleable.lbPlaybackControlsActionIcons_thumb_up,
-                    R.styleable.lbPlaybackControlsActionIcons_thumb_up_outline);
-            String[] labels = new String[getActionCount()];
-            labels[INDEX_SOLID] = context.getString(R.string.lb_playback_controls_thumb_up);
-            labels[INDEX_OUTLINE] = context.getString(
-                    R.string.lb_playback_controls_thumb_up_outline);
-            setLabels(labels);
-        }
-    }
-
-    /**
-     * An action displaying an icon for thumbs down.
-     */
-    public static class ThumbsDownAction extends ThumbsAction {
-        public ThumbsDownAction(Context context) {
-            super(R.id.lb_control_thumbs_down, context,
-                    R.styleable.lbPlaybackControlsActionIcons_thumb_down,
-                    R.styleable.lbPlaybackControlsActionIcons_thumb_down_outline);
-            String[] labels = new String[getActionCount()];
-            labels[INDEX_SOLID] = context.getString(R.string.lb_playback_controls_thumb_down);
-            labels[INDEX_OUTLINE] = context.getString(
-                    R.string.lb_playback_controls_thumb_down_outline);
-            setLabels(labels);
-        }
-    }
-
-    /**
-     * An action for displaying three repeat states: none, one, or all.
-     */
-    public static class RepeatAction extends MultiAction {
-        /**
-         * Action index for the repeat-none icon.
-         * @deprecated Use {@link #INDEX_NONE}
-         */
-        @Deprecated
-        public static int NONE = 0;
-
-        /**
-         * Action index for the repeat-all icon.
-         * @deprecated Use {@link #INDEX_ALL}
-         */
-        @Deprecated
-        public static int ALL = 1;
-
-        /**
-         * Action index for the repeat-one icon.
-         * @deprecated Use {@link #INDEX_ONE}
-         */
-        @Deprecated
-        public static int ONE = 2;
-
-        /**
-         * Action index for the repeat-none icon.
-         */
-        public static final int INDEX_NONE = 0;
-
-        /**
-         * Action index for the repeat-all icon.
-         */
-        public static final int INDEX_ALL = 1;
-
-        /**
-         * Action index for the repeat-one icon.
-         */
-        public static final int INDEX_ONE = 2;
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public RepeatAction(Context context) {
-            this(context, getIconHighlightColor(context));
-        }
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources
-         * @param highlightColor Color to display the repeat-all and repeat0one icons.
-         */
-        public RepeatAction(Context context, int highlightColor) {
-            this(context, highlightColor, highlightColor);
-        }
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources
-         * @param repeatAllColor Color to display the repeat-all icon.
-         * @param repeatOneColor Color to display the repeat-one icon.
-         */
-        public RepeatAction(Context context, int repeatAllColor, int repeatOneColor) {
-            super(R.id.lb_control_repeat);
-            Drawable[] drawables = new Drawable[3];
-            BitmapDrawable repeatDrawable = (BitmapDrawable) getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_repeat);
-            BitmapDrawable repeatOneDrawable = (BitmapDrawable) getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_repeat_one);
-            drawables[INDEX_NONE] = repeatDrawable;
-            drawables[INDEX_ALL] = repeatDrawable == null ? null
-                    : new BitmapDrawable(context.getResources(),
-                            createBitmap(repeatDrawable.getBitmap(), repeatAllColor));
-            drawables[INDEX_ONE] = repeatOneDrawable == null ? null
-                    : new BitmapDrawable(context.getResources(),
-                            createBitmap(repeatOneDrawable.getBitmap(), repeatOneColor));
-            setDrawables(drawables);
-
-            String[] labels = new String[drawables.length];
-            // Note, labels denote the action taken when clicked
-            labels[INDEX_NONE] = context.getString(R.string.lb_playback_controls_repeat_all);
-            labels[INDEX_ALL] = context.getString(R.string.lb_playback_controls_repeat_one);
-            labels[INDEX_ONE] = context.getString(R.string.lb_playback_controls_repeat_none);
-            setLabels(labels);
-        }
-    }
-
-    /**
-     * An action for displaying a shuffle icon.
-     */
-    public static class ShuffleAction extends MultiAction {
-        /**
-         * Action index for shuffle is off.
-         * @deprecated Use {@link #INDEX_OFF}
-         */
-        @Deprecated
-        public static int OFF = 0;
-
-        /**
-         * Action index for shuffle is on.
-         * @deprecated Use {@link #INDEX_ON}
-         */
-        @Deprecated
-        public static int ON = 1;
-
-        /**
-         * Action index for shuffle is off
-         */
-        public static final int INDEX_OFF = 0;
-
-        /**
-         * Action index for shuffle is on.
-         */
-        public static final int INDEX_ON = 1;
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public ShuffleAction(Context context) {
-            this(context, getIconHighlightColor(context));
-        }
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         * @param highlightColor Color for the highlighted icon state.
-         */
-        public ShuffleAction(Context context, int highlightColor) {
-            super(R.id.lb_control_shuffle);
-            BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_shuffle);
-            Drawable[] drawables = new Drawable[2];
-            drawables[INDEX_OFF] = uncoloredDrawable;
-            drawables[INDEX_ON] = new BitmapDrawable(context.getResources(),
-                    createBitmap(uncoloredDrawable.getBitmap(), highlightColor));
-            setDrawables(drawables);
-
-            String[] labels = new String[drawables.length];
-            labels[INDEX_OFF] = context.getString(R.string.lb_playback_controls_shuffle_enable);
-            labels[INDEX_ON] = context.getString(R.string.lb_playback_controls_shuffle_disable);
-            setLabels(labels);
-        }
-    }
-
-    /**
-     * An action for displaying a HQ (High Quality) icon.
-     */
-    public static class HighQualityAction extends MultiAction {
-        /**
-         * Action index for high quality is off.
-         * @deprecated Use {@link #INDEX_OFF}
-         */
-        @Deprecated
-        public static int OFF = 0;
-
-        /**
-         * Action index for high quality is on.
-         * @deprecated Use {@link #INDEX_ON}
-         */
-        @Deprecated
-        public static int ON = 1;
-
-        /**
-         * Action index for high quality is off.
-         */
-        public static final int INDEX_OFF = 0;
-
-        /**
-         * Action index for high quality is on.
-         */
-        public static final int INDEX_ON = 1;
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public HighQualityAction(Context context) {
-            this(context, getIconHighlightColor(context));
-        }
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         * @param highlightColor Color for the highlighted icon state.
-         */
-        public HighQualityAction(Context context, int highlightColor) {
-            super(R.id.lb_control_high_quality);
-            BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_high_quality);
-            Drawable[] drawables = new Drawable[2];
-            drawables[INDEX_OFF] = uncoloredDrawable;
-            drawables[INDEX_ON] = new BitmapDrawable(context.getResources(),
-                    createBitmap(uncoloredDrawable.getBitmap(), highlightColor));
-            setDrawables(drawables);
-
-            String[] labels = new String[drawables.length];
-            labels[INDEX_OFF] = context.getString(
-                    R.string.lb_playback_controls_high_quality_enable);
-            labels[INDEX_ON] = context.getString(
-                    R.string.lb_playback_controls_high_quality_disable);
-            setLabels(labels);
-        }
-    }
-
-    /**
-     * An action for displaying a CC (Closed Captioning) icon.
-     */
-    public static class ClosedCaptioningAction extends MultiAction {
-        /**
-         * Action index for closed caption is off.
-         * @deprecated Use {@link #INDEX_OFF}
-         */
-        @Deprecated
-        public static int OFF = 0;
-
-        /**
-         * Action index for closed caption is on.
-         * @deprecated Use {@link #INDEX_ON}
-         */
-        @Deprecated
-        public static int ON = 1;
-
-        /**
-         * Action index for closed caption is off.
-         */
-        public static final int INDEX_OFF = 0;
-
-        /**
-         * Action index for closed caption is on.
-         */
-        public static final int INDEX_ON = 1;
-
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         */
-        public ClosedCaptioningAction(Context context) {
-            this(context, getIconHighlightColor(context));
-        }
-
-        /**
-         * Constructor
-         * @param context Context used for loading resources.
-         * @param highlightColor Color for the highlighted icon state.
-         */
-        public ClosedCaptioningAction(Context context, int highlightColor) {
-            super(R.id.lb_control_closed_captioning);
-            BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context,
-                    R.styleable.lbPlaybackControlsActionIcons_closed_captioning);
-            Drawable[] drawables = new Drawable[2];
-            drawables[INDEX_OFF] = uncoloredDrawable;
-            drawables[INDEX_ON] = new BitmapDrawable(context.getResources(),
-                    createBitmap(uncoloredDrawable.getBitmap(), highlightColor));
-            setDrawables(drawables);
-
-            String[] labels = new String[drawables.length];
-            labels[INDEX_OFF] = context.getString(
-                    R.string.lb_playback_controls_closed_captioning_enable);
-            labels[INDEX_ON] = context.getString(
-                    R.string.lb_playback_controls_closed_captioning_disable);
-            setLabels(labels);
-        }
-    }
-
-    static Bitmap createBitmap(Bitmap bitmap, int color) {
-        Bitmap dst = bitmap.copy(bitmap.getConfig(), true);
-        Canvas canvas = new Canvas(dst);
-        Paint paint = new Paint();
-        paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
-        canvas.drawBitmap(bitmap, 0, 0, paint);
-        return dst;
-    }
-
-    static int getIconHighlightColor(Context context) {
-        TypedValue outValue = new TypedValue();
-        if (context.getTheme().resolveAttribute(R.attr.playbackControlsIconHighlightColor,
-                outValue, true)) {
-            return outValue.data;
-        }
-        return context.getResources().getColor(R.color.lb_playback_icon_highlight_no_theme);
-    }
-
-    static Drawable getStyledDrawable(Context context, int index) {
-        TypedValue outValue = new TypedValue();
-        if (!context.getTheme().resolveAttribute(
-                R.attr.playbackControlsActionIcons, outValue, false)) {
-            return null;
-        }
-        TypedArray array = context.getTheme().obtainStyledAttributes(outValue.data,
-                R.styleable.lbPlaybackControlsActionIcons);
-        Drawable drawable = array.getDrawable(index);
-        array.recycle();
-        return drawable;
-    }
-
-    private Object mItem;
-    private Drawable mImageDrawable;
-    private ObjectAdapter mPrimaryActionsAdapter;
-    private ObjectAdapter mSecondaryActionsAdapter;
-    private long mTotalTimeMs;
-    private long mCurrentTimeMs;
-    private long mBufferedProgressMs;
-    private OnPlaybackProgressCallback mListener;
-
-    /**
-     * Constructor for a PlaybackControlsRow that displays some details from
-     * the given item.
-     *
-     * @param item The main item for the row.
-     */
-    public PlaybackControlsRow(Object item) {
-        mItem = item;
-    }
-
-    /**
-     * Constructor for a PlaybackControlsRow that has no item details.
-     */
-    public PlaybackControlsRow() {
-    }
-
-    /**
-     * Returns the main item for the details page.
-     */
-    public final Object getItem() {
-        return mItem;
-    }
-
-    /**
-     * Sets a {link @Drawable} image for this row.
-     * <p>If set after the row has been bound to a view, the adapter must be notified that
-     * this row has changed.</p>
-     *
-     * @param drawable The drawable to set.
-     */
-    public final void setImageDrawable(Drawable drawable) {
-        mImageDrawable = drawable;
-    }
-
-    /**
-     * Sets a {@link Bitmap} for this row.
-     * <p>If set after the row has been bound to a view, the adapter must be notified that
-     * this row has changed.</p>
-     *
-     * @param context The context to retrieve display metrics from.
-     * @param bm The bitmap to set.
-     */
-    public final void setImageBitmap(Context context, Bitmap bm) {
-        mImageDrawable = new BitmapDrawable(context.getResources(), bm);
-    }
-
-    /**
-     * Returns the image {@link Drawable} of this row.
-     *
-     * @return The overview's image drawable, or null if no drawable has been
-     *         assigned.
-     */
-    public final Drawable getImageDrawable() {
-        return mImageDrawable;
-    }
-
-    /**
-     * Sets the primary actions {@link ObjectAdapter}.
-     * <p>If set after the row has been bound to a view, the adapter must be notified that
-     * this row has changed.</p>
-     */
-    public final void setPrimaryActionsAdapter(ObjectAdapter adapter) {
-        mPrimaryActionsAdapter = adapter;
-    }
-
-    /**
-     * Sets the secondary actions {@link ObjectAdapter}.
-     * <p>If set after the row has been bound to a view, the adapter must be notified that
-     * this row has changed.</p>
-     */
-    public final void setSecondaryActionsAdapter(ObjectAdapter adapter) {
-        mSecondaryActionsAdapter = adapter;
-    }
-
-    /**
-     * Returns the primary actions {@link ObjectAdapter}.
-     */
-    public final ObjectAdapter getPrimaryActionsAdapter() {
-        return mPrimaryActionsAdapter;
-    }
-
-    /**
-     * Returns the secondary actions {@link ObjectAdapter}.
-     */
-    public final ObjectAdapter getSecondaryActionsAdapter() {
-        return mSecondaryActionsAdapter;
-    }
-
-    /**
-     * Sets the total time in milliseconds for the playback controls row.
-     * <p>If set after the row has been bound to a view, the adapter must be notified that
-     * this row has changed.</p>
-     * @deprecated Use {@link #setDuration(long)}
-     */
-    @Deprecated
-    public void setTotalTime(int ms) {
-        setDuration((long) ms);
-    }
-
-    /**
-     * Sets the total time in milliseconds (long type) for the playback controls row.
-     * @param ms Total time in milliseconds of long type.
-     * @deprecated Use {@link #setDuration(long)}
-     */
-    @Deprecated
-    public void setTotalTimeLong(long ms) {
-        setDuration(ms);
-    }
-
-    /**
-     * Sets the total time in milliseconds (long type) for the playback controls row.
-     * If this row is bound to a view, the view will automatically
-     * be updated to reflect the new value.
-     * @param ms Total time in milliseconds of long type.
-     */
-    public void setDuration(long ms) {
-        if (mTotalTimeMs != ms) {
-            mTotalTimeMs = ms;
-            if (mListener != null) {
-                mListener.onDurationChanged(this, mTotalTimeMs);
-            }
-        }
-    }
-
-    /**
-     * Returns the total time in milliseconds for the playback controls row.
-     * @throws ArithmeticException If total time in milliseconds overflows int.
-     * @deprecated use {@link #getDuration()}
-     */
-    @Deprecated
-    public int getTotalTime() {
-        return MathUtil.safeLongToInt(getTotalTimeLong());
-    }
-
-    /**
-     * Returns the total time in milliseconds of long type for the playback controls row.
-     * @deprecated use {@link #getDuration()}
-     */
-    @Deprecated
-    public long getTotalTimeLong() {
-        return mTotalTimeMs;
-    }
-
-    /**
-     * Returns duration in milliseconds.
-     * @return Duration in milliseconds.
-     */
-    public long getDuration() {
-        return mTotalTimeMs;
-    }
-
-    /**
-     * Sets the current time in milliseconds for the playback controls row.
-     * If this row is bound to a view, the view will automatically
-     * be updated to reflect the new value.
-     * @deprecated use {@link #setCurrentPosition(long)}
-     */
-    @Deprecated
-    public void setCurrentTime(int ms) {
-        setCurrentTimeLong((long) ms);
-    }
-
-    /**
-     * Sets the current time in milliseconds for playback controls row in long type.
-     * @param ms Current time in milliseconds of long type.
-     * @deprecated use {@link #setCurrentPosition(long)}
-     */
-    @Deprecated
-    public void setCurrentTimeLong(long ms) {
-        setCurrentPosition(ms);
-    }
-
-    /**
-     * Sets the current time in milliseconds for the playback controls row.
-     * If this row is bound to a view, the view will automatically
-     * be updated to reflect the new value.
-     * @param ms Current time in milliseconds of long type.
-     */
-    public void setCurrentPosition(long ms) {
-        if (mCurrentTimeMs != ms) {
-            mCurrentTimeMs = ms;
-            if (mListener != null) {
-                mListener.onCurrentPositionChanged(this, mCurrentTimeMs);
-            }
-        }
-    }
-
-    /**
-     * Returns the current time in milliseconds for the playback controls row.
-     * @throws ArithmeticException If current time in milliseconds overflows int.
-     * @deprecated Use {@link #getCurrentPosition()}
-     */
-    @Deprecated
-    public int getCurrentTime() {
-        return MathUtil.safeLongToInt(getCurrentTimeLong());
-    }
-
-    /**
-     * Returns the current time in milliseconds of long type for playback controls row.
-     * @deprecated Use {@link #getCurrentPosition()}
-     */
-    @Deprecated
-    public long getCurrentTimeLong() {
-        return mCurrentTimeMs;
-    }
-
-    /**
-     * Returns the current time in milliseconds of long type for playback controls row.
-     */
-    public long getCurrentPosition() {
-        return mCurrentTimeMs;
-    }
-
-    /**
-     * Sets the buffered progress for the playback controls row.
-     * If this row is bound to a view, the view will automatically
-     * be updated to reflect the new value.
-     * @deprecated Use {@link #setBufferedPosition(long)}
-     */
-    @Deprecated
-    public void setBufferedProgress(int ms) {
-        setBufferedPosition((long) ms);
-    }
-
-    /**
-     * Sets the buffered progress for the playback controls row.
-     * @param ms Buffered progress in milliseconds of long type.
-     * @deprecated Use {@link #setBufferedPosition(long)}
-     */
-    @Deprecated
-    public void setBufferedProgressLong(long ms) {
-        setBufferedPosition(ms);
-    }
-
-    /**
-     * Sets the buffered progress for the playback controls row.
-     * @param ms Buffered progress in milliseconds of long type.
-     */
-    public void setBufferedPosition(long ms) {
-        if (mBufferedProgressMs != ms) {
-            mBufferedProgressMs = ms;
-            if (mListener != null) {
-                mListener.onBufferedPositionChanged(this, mBufferedProgressMs);
-            }
-        }
-    }
-    /**
-     * Returns the buffered progress for the playback controls row.
-     * @throws ArithmeticException If buffered progress in milliseconds overflows int.
-     * @deprecated Use {@link #getBufferedPosition()}
-     */
-    @Deprecated
-    public int getBufferedProgress() {
-        return MathUtil.safeLongToInt(getBufferedPosition());
-    }
-
-    /**
-     * Returns the buffered progress of long type for the playback controls row.
-     * @deprecated Use {@link #getBufferedPosition()}
-     */
-    @Deprecated
-    public long getBufferedProgressLong() {
-        return mBufferedProgressMs;
-    }
-
-    /**
-     * Returns the buffered progress of long type for the playback controls row.
-     */
-    public long getBufferedPosition() {
-        return mBufferedProgressMs;
-    }
-
-    /**
-     * Returns the Action associated with the given keycode, or null if no associated action exists.
-     * Searches the primary adapter first, then the secondary adapter.
-     */
-    public Action getActionForKeyCode(int keyCode) {
-        Action action = getActionForKeyCode(getPrimaryActionsAdapter(), keyCode);
-        if (action != null) {
-            return action;
-        }
-        return getActionForKeyCode(getSecondaryActionsAdapter(), keyCode);
-    }
-
-    /**
-     * Returns the Action associated with the given keycode, or null if no associated action exists.
-     */
-    public Action getActionForKeyCode(ObjectAdapter adapter, int keyCode) {
-        if (adapter != mPrimaryActionsAdapter && adapter != mSecondaryActionsAdapter) {
-            throw new IllegalArgumentException("Invalid adapter");
-        }
-        for (int i = 0; i < adapter.size(); i++) {
-            Action action = (Action) adapter.get(i);
-            if (action.respondsToKeyCode(keyCode)) {
-                return action;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Sets a listener to be called when the playback state changes.
-     */
-    public void setOnPlaybackProgressChangedListener(OnPlaybackProgressCallback listener) {
-        mListener = listener;
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/widget/SearchOrbView.java b/leanback/src/android/support/v17/leanback/widget/SearchOrbView.java
deleted file mode 100644
index 8269f60..0000000
--- a/leanback/src/android/support/v17/leanback/widget/SearchOrbView.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v17.leanback.widget;
-
-import android.animation.ArgbEvaluator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.support.annotation.ColorInt;
-import android.support.v17.leanback.R;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-/**
- * <p>A widget that draws a search affordance, represented by a round background and an icon.</p>
- *
- * The background color and icon can be customized.
- */
-public class SearchOrbView extends FrameLayout implements View.OnClickListener {
-    private OnClickListener mListener;
-    private View mRootView;
-    private View mSearchOrbView;
-    private ImageView mIcon;
-    private Drawable mIconDrawable;
-    private Colors mColors;
-    private final float mFocusedZoom;
-    private final int mPulseDurationMs;
-    private final int mScaleDurationMs;
-    private final float mUnfocusedZ;
-    private final float mFocusedZ;
-    private ValueAnimator mColorAnimator;
-    private boolean mColorAnimationEnabled;
-    private boolean mAttachedToWindow;
-
-    /**
-     * A set of colors used to display the search orb.
-     */
-    public static class Colors {
-        private static final float sBrightnessAlpha = 0.15f;
-
-        /**
-         * Constructs a color set using the given color for the search orb.
-         * Other colors are provided by the framework.
-         *
-         * @param color The main search orb color.
-         */
-        public Colors(@ColorInt int color) {
-            this(color, color);
-        }
-
-        /**
-         * Constructs a color set using the given colors for the search orb.
-         * Other colors are provided by the framework.
-         *
-         * @param color The main search orb color.
-         * @param brightColor A brighter version of the search orb used for animation.
-         */
-        public Colors(@ColorInt int color, @ColorInt int brightColor) {
-            this(color, brightColor, Color.TRANSPARENT);
-        }
-
-        /**
-         * Constructs a color set using the given colors.
-         *
-         * @param color The main search orb color.
-         * @param brightColor A brighter version of the search orb used for animation.
-         * @param iconColor A color used to tint the search orb icon.
-         */
-        public Colors(@ColorInt int color, @ColorInt int brightColor, @ColorInt int iconColor) {
-            this.color = color;
-            this.brightColor = brightColor == color ? getBrightColor(color) : brightColor;
-            this.iconColor = iconColor;
-        }
-
-        /**
-         * The main color of the search orb.
-         */
-        @ColorInt
-        public int color;
-
-        /**
-         * A brighter version of the search orb used for animation.
-         */
-        @ColorInt
-        public int brightColor;
-
-        /**
-         * A color used to tint the search orb icon.
-         */
-        @ColorInt
-        public int iconColor;
-
-        /**
-         * Computes a default brighter version of the given color.
-         */
-        public static int getBrightColor(int color) {
-            final float brightnessValue = 0xff * sBrightnessAlpha;
-            int red = (int)(Color.red(color) * (1 - sBrightnessAlpha) + brightnessValue);
-            int green = (int)(Color.green(color) * (1 - sBrightnessAlpha) + brightnessValue);
-            int blue = (int)(Color.blue(color) * (1 - sBrightnessAlpha) + brightnessValue);
-            int alpha = (int)(Color.alpha(color) * (1 - sBrightnessAlpha) + brightnessValue);
-            return Color.argb(alpha, red, green, blue);
-        }
-    }
-
-    private final ArgbEvaluator mColorEvaluator = new ArgbEvaluator();
-
-    private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
-            new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animator) {
-            Integer color = (Integer) animator.getAnimatedValue();
-            setOrbViewColor(color.intValue());
-        }
-    };
-
-    private ValueAnimator mShadowFocusAnimator;
-
-    private final ValueAnimator.AnimatorUpdateListener mFocusUpdateListener =
-            new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            setSearchOrbZ(animation.getAnimatedFraction());
-        }
-    };
-
-    void setSearchOrbZ(float fraction) {
-        ShadowHelper.getInstance().setZ(mSearchOrbView,
-                mUnfocusedZ + fraction * (mFocusedZ - mUnfocusedZ));
-    }
-
-    public SearchOrbView(Context context) {
-        this(context, null);
-    }
-
-    public SearchOrbView(Context context, AttributeSet attrs) {
-        this(context, attrs, R.attr.searchOrbViewStyle);
-    }
-
-    public SearchOrbView(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        final Resources res = context.getResources();
-
-        LayoutInflater inflater = (LayoutInflater) context
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mRootView = inflater.inflate(getLayoutResourceId(), this, true);
-        mSearchOrbView = mRootView.findViewById(R.id.search_orb);
-        mIcon = (ImageView) mRootView.findViewById(R.id.icon);
-
-        mFocusedZoom = context.getResources().getFraction(
-                R.fraction.lb_search_orb_focused_zoom, 1, 1);
-        mPulseDurationMs = context.getResources().getInteger(
-                R.integer.lb_search_orb_pulse_duration_ms);
-        mScaleDurationMs = context.getResources().getInteger(
-                R.integer.lb_search_orb_scale_duration_ms);
-        mFocusedZ = context.getResources().getDimensionPixelSize(
-                R.dimen.lb_search_orb_focused_z);
-        mUnfocusedZ = context.getResources().getDimensionPixelSize(
-                R.dimen.lb_search_orb_unfocused_z);
-
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbSearchOrbView,
-                defStyleAttr, 0);
-
-        Drawable img = a.getDrawable(R.styleable.lbSearchOrbView_searchOrbIcon);
-        if (img == null) {
-            img = res.getDrawable(R.drawable.lb_ic_in_app_search);
-        }
-        setOrbIcon(img);
-
-        int defColor = res.getColor(R.color.lb_default_search_color);
-        int color = a.getColor(R.styleable.lbSearchOrbView_searchOrbColor, defColor);
-        int brightColor = a.getColor(
-                R.styleable.lbSearchOrbView_searchOrbBrightColor, color);
-        int iconColor = a.getColor(R.styleable.lbSearchOrbView_searchOrbIconColor, Color.TRANSPARENT);
-        setOrbColors(new Colors(color, brightColor, iconColor));
-        a.recycle();
-
-        setFocusable(true);
-        setClipChildren(false);
-        setOnClickListener(this);
-        setSoundEffectsEnabled(false);
-        setSearchOrbZ(0);
-
-        // Icon has no background, but must be on top of the search orb view
-        ShadowHelper.getInstance().setZ(mIcon, mFocusedZ);
-    }
-
-    int getLayoutResourceId() {
-        return R.layout.lb_search_orb;
-    }
-
-    void scaleOrbViewOnly(float scale) {
-        mSearchOrbView.setScaleX(scale);
-        mSearchOrbView.setScaleY(scale);
-    }
-
-    float getFocusedZoom() {
-        return mFocusedZoom;
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (null != mListener) {
-            mListener.onClick(view);
-        }
-    }
-
-    private void startShadowFocusAnimation(boolean gainFocus, int duration) {
-        if (mShadowFocusAnimator == null) {
-            mShadowFocusAnimator = ValueAnimator.ofFloat(0f, 1f);
-            mShadowFocusAnimator.addUpdateListener(mFocusUpdateListener);
-        }
-        if (gainFocus) {
-            mShadowFocusAnimator.start();
-        } else {
-            mShadowFocusAnimator.reverse();
-        }
-        mShadowFocusAnimator.setDuration(duration);
-    }
-
-    @Override
-    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
-        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
-        animateOnFocus(gainFocus);
-    }
-
-    void animateOnFocus(boolean hasFocus) {
-        final float zoom = hasFocus ? mFocusedZoom : 1f;
-        mRootView.animate().scaleX(zoom).scaleY(zoom).setDuration(mScaleDurationMs).start();
-        startShadowFocusAnimation(hasFocus, mScaleDurationMs);
-        enableOrbColorAnimation(hasFocus);
-    }
-
-    /**
-     * Sets the orb icon.
-     * @param icon the drawable to be used as the icon
-     */
-    public void setOrbIcon(Drawable icon) {
-        mIconDrawable = icon;
-        mIcon.setImageDrawable(mIconDrawable);
-    }
-
-    /**
-     * Returns the orb icon
-     * @return the drawable used as the icon
-     */
-    public Drawable getOrbIcon() {
-        return mIconDrawable;
-    }
-
-    /**
-     * Sets the on click listener for the orb.
-     * @param listener The listener.
-     */
-    public void setOnOrbClickedListener(OnClickListener listener) {
-        mListener = listener;
-    }
-
-    /**
-     * Sets the background color of the search orb.
-     * Other colors will be provided by the framework.
-     *
-     * @param color the RGBA color
-     */
-    public void setOrbColor(int color) {
-        setOrbColors(new Colors(color, color, Color.TRANSPARENT));
-    }
-
-    /**
-     * Sets the search orb colors.
-     * Other colors are provided by the framework.
-     * @deprecated Use {@link #setOrbColors(Colors)} instead.
-     */
-    @Deprecated
-    public void setOrbColor(@ColorInt int color, @ColorInt int brightColor) {
-        setOrbColors(new Colors(color, brightColor, Color.TRANSPARENT));
-    }
-
-    /**
-     * Returns the orb color
-     * @return the RGBA color
-     */
-    @ColorInt
-    public int getOrbColor() {
-        return mColors.color;
-    }
-
-    /**
-     * Sets the {@link Colors} used to display the search orb.
-     */
-    public void setOrbColors(Colors colors) {
-        mColors = colors;
-        mIcon.setColorFilter(mColors.iconColor);
-
-        if (mColorAnimator == null) {
-            setOrbViewColor(mColors.color);
-        } else {
-            enableOrbColorAnimation(true);
-        }
-    }
-
-    /**
-     * Returns the {@link Colors} used to display the search orb.
-     */
-    public Colors getOrbColors() {
-        return mColors;
-    }
-
-    /**
-     * Enables or disables the orb color animation.
-     *
-     * <p>
-     * Orb color animation is handled automatically when the orb is focused/unfocused,
-     * however, an app may choose to override the current animation state, for example
-     * when an activity is paused.
-     * </p>
-     */
-    public void enableOrbColorAnimation(boolean enable) {
-        mColorAnimationEnabled = enable;
-        updateColorAnimator();
-    }
-
-    private void updateColorAnimator() {
-        if (mColorAnimator != null) {
-            mColorAnimator.end();
-            mColorAnimator = null;
-        }
-        if (mColorAnimationEnabled && mAttachedToWindow) {
-            // TODO: set interpolator (material if available)
-            mColorAnimator = ValueAnimator.ofObject(mColorEvaluator,
-                    mColors.color, mColors.brightColor, mColors.color);
-            mColorAnimator.setRepeatCount(ValueAnimator.INFINITE);
-            mColorAnimator.setDuration(mPulseDurationMs * 2);
-            mColorAnimator.addUpdateListener(mUpdateListener);
-            mColorAnimator.start();
-        }
-    }
-
-    void setOrbViewColor(int color) {
-        if (mSearchOrbView.getBackground() instanceof GradientDrawable) {
-            ((GradientDrawable) mSearchOrbView.getBackground()).setColor(color);
-        }
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mAttachedToWindow = true;
-        updateColorAnimator();
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        mAttachedToWindow = false;
-        // Must stop infinite animation to prevent activity leak
-        updateColorAnimator();
-        super.onDetachedFromWindow();
-    }
-}
diff --git a/leanback/src/android/support/v17/leanback/widget/picker/DatePicker.java b/leanback/src/android/support/v17/leanback/widget/picker/DatePicker.java
deleted file mode 100644
index 2744dec..0000000
--- a/leanback/src/android/support/v17/leanback/widget/picker/DatePicker.java
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.support.v17.leanback.widget.picker;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.support.annotation.RestrictTo;
-import android.support.v17.leanback.R;
-import android.text.TextUtils;
-import android.util.AttributeSet;
-import android.util.Log;
-
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * {@link DatePicker} is a directly subclass of {@link Picker}.
- * This class is a widget for selecting a date. The date can be selected by a
- * year, month, and day Columns. The "minDate" and "maxDate" from which dates to be selected
- * can be customized.  The columns can be customized by attribute "datePickerFormat" or
- * {@link #setDatePickerFormat(String)}.
- *
- * @attr ref R.styleable#lbDatePicker_android_maxDate
- * @attr ref R.styleable#lbDatePicker_android_minDate
- * @attr ref R.styleable#lbDatePicker_datePickerFormat
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class DatePicker extends Picker {
-
-    static final String LOG_TAG = "DatePicker";
-
-    private String mDatePickerFormat;
-    PickerColumn mMonthColumn;
-    PickerColumn mDayColumn;
-    PickerColumn mYearColumn;
-    int mColMonthIndex;
-    int mColDayIndex;
-    int mColYearIndex;
-
-    final static String DATE_FORMAT = "MM/dd/yyyy";
-    final DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
-    PickerUtility.DateConstant mConstant;
-
-    Calendar mMinDate;
-    Calendar mMaxDate;
-    Calendar mCurrentDate;
-    Calendar mTempDate;
-
-    public DatePicker(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public DatePicker(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-
-        updateCurrentLocale();
-
-        final TypedArray attributesArray = context.obtainStyledAttributes(attrs,
-                R.styleable.lbDatePicker);
-        String minDate = attributesArray.getString(R.styleable.lbDatePicker_android_minDate);
-        String maxDate = attributesArray.getString(R.styleable.lbDatePicker_android_maxDate);
-        mTempDate.clear();
-        if (!TextUtils.isEmpty(minDate)) {
-            if (!parseDate(minDate, mTempDate)) {
-                mTempDate.set(1900, 0, 1);
-            }
-        } else {
-            mTempDate.set(1900, 0, 1);
-        }
-        mMinDate.setTimeInMillis(mTempDate.getTimeInMillis());
-
-        mTempDate.clear();
-        if (!TextUtils.isEmpty(maxDate)) {
-            if (!parseDate(maxDate, mTempDate)) {
-                mTempDate.set(2100, 0, 1);
-            }
-        } else {
-            mTempDate.set(2100, 0, 1);
-        }
-        mMaxDate.setTimeInMillis(mTempDate.getTimeInMillis());
-
-        String datePickerFormat = attributesArray
-                .getString(R.styleable.lbDatePicker_datePickerFormat);
-        if (TextUtils.isEmpty(datePickerFormat)) {
-            datePickerFormat = new String(
-                    android.text.format.DateFormat.getDateFormatOrder(context));
-        }
-        setDatePickerFormat(datePickerFormat);
-    }
-
-    private boolean parseDate(String date, Calendar outDate) {
-        try {
-            outDate.setTime(mDateFormat.parse(date));
-            return true;
-        } catch (ParseException e) {
-            Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
-            return false;
-        }
-    }
-
-    /**
-     * Returns the best localized representation of the date for the given date format and the
-     * current locale.
-     *
-     * @param datePickerFormat The date format skeleton (e.g. "dMy") used to gather the
-     *                         appropriate representation of the date in the current locale.
-     *
-     * @return The best localized representation of the date for the given date format
-     */
-    String getBestYearMonthDayPattern(String datePickerFormat) {
-        final String yearPattern;
-        if (PickerUtility.SUPPORTS_BEST_DATE_TIME_PATTERN) {
-            yearPattern = android.text.format.DateFormat.getBestDateTimePattern(mConstant.locale,
-                    datePickerFormat);
-        } else {
-            final java.text.DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(
-                    getContext());
-            if (dateFormat instanceof SimpleDateFormat) {
-                yearPattern = ((SimpleDateFormat) dateFormat).toLocalizedPattern();
-            } else {
-                yearPattern = DATE_FORMAT;
-            }
-        }
-        return TextUtils.isEmpty(yearPattern) ? DATE_FORMAT : yearPattern;
-    }
-
-    /**
-     * Extracts the separators used to separate date fields (including before the first and after
-     * the last date field). The separators can vary based on the individual locale date format,
-     * defined in the Unicode CLDR and cannot be supposed to be "/".
-     *
-     * See http://unicode.org/cldr/trac/browser/trunk/common/main
-     *
-     * For example, for Croatian in dMy format, the best localized representation is "d. M. y". This
-     * method returns {"", ".", ".", "."}, where the first separator indicates nothing needs to be
-     * displayed to the left of the day field, "." needs to be displayed tos the right of the day
-     * field, and so forth.
-     *
-     * @return The ArrayList of separators to populate between the actual date fields in the
-     * DatePicker.
-     */
-    List<CharSequence> extractSeparators() {
-        // Obtain the time format string per the current locale (e.g. h:mm a)
-        String hmaPattern = getBestYearMonthDayPattern(mDatePickerFormat);
-
-        List<CharSequence> separators = new ArrayList<>();
-        StringBuilder sb = new StringBuilder();
-        char lastChar = '\0';
-        // See http://www.unicode.org/reports/tr35/tr35-dates.html for date formats
-        final char[] dateFormats = {'Y', 'y', 'M', 'm', 'D', 'd'};
-        boolean processingQuote = false;
-        for (int i = 0; i < hmaPattern.length(); i++) {
-            char c = hmaPattern.charAt(i);
-            if (c == ' ') {
-                continue;
-            }
-            if (c == '\'') {
-                if (!processingQuote) {
-                    sb.setLength(0);
-                    processingQuote = true;
-                } else {
-                    processingQuote = false;
-                }
-                continue;
-            }
-            if (processingQuote) {
-                sb.append(c);
-            } else {
-                if (isAnyOf(c, dateFormats)) {
-                    if (c != lastChar) {
-                        separators.add(sb.toString());
-                        sb.setLength(0);
-                    }
-                } else {
-                    sb.append(c);
-                }
-            }
-            lastChar = c;
-        }
-        separators.add(sb.toString());
-        return separators;
-    }
-
-    private static boolean isAnyOf(char c, char[] any) {
-        for (int i = 0; i < any.length; i++) {
-            if (c == any[i]) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Changes format of showing dates.  For example "YMD".
-     * @param datePickerFormat Format of showing dates.
-     */
-    public void setDatePickerFormat(String datePickerFormat) {
-        if (TextUtils.isEmpty(datePickerFormat)) {
-            datePickerFormat = new String(
-                    android.text.format.DateFormat.getDateFormatOrder(getContext()));
-        }
-        if (TextUtils.equals(mDatePickerFormat, datePickerFormat)) {
-            return;
-        }
-        mDatePickerFormat = datePickerFormat;
-        List<CharSequence> separators = extractSeparators();
-        if (separators.size() != (datePickerFormat.length() + 1)) {
-            throw new IllegalStateException("Separators size: " + separators.size() + " must equal"
-                    + " the size of datePickerFormat: " + datePickerFormat.length() + " + 1");
-        }
-        setSeparators(separators);
-        mYearColumn = mMonthColumn = mDayColumn = null;
-        mColYearIndex = mColDayIndex = mColMonthIndex = -1;
-        String dateFieldsPattern = datePickerFormat.toUpperCase();
-        ArrayList<PickerColumn> columns = new ArrayList<PickerColumn>(3);
-        for (int i = 0; i < dateFieldsPattern.length(); i++) {
-            switch (dateFieldsPattern.charAt(i)) {
-            case 'Y':
-                if (mYearColumn != null) {
-                    throw new IllegalArgumentException("datePicker format error");
-                }
-                columns.add(mYearColumn = new PickerColumn());
-                mColYearIndex = i;
-                mYearColumn.setLabelFormat("%d");
-                break;
-            case 'M':
-                if (mMonthColumn != null) {
-                    throw new IllegalArgumentException("datePicker format error");
-                }
-                columns.add(mMonthColumn = new PickerColumn());
-                mMonthColumn.setStaticLabels(mConstant.months);
-                mColMonthIndex = i;
-                break;
-            case 'D':
-                if (mDayColumn != null) {
-                    throw new IllegalArgumentException("datePicker format error");
-                }
-                columns.add(mDayColumn = new PickerColumn());
-                mDayColumn.setLabelFormat("%02d");
-                mColDayIndex = i;
-                break;
-            default:
-                throw new IllegalArgumentException("datePicker format error");
-            }
-        }
-        setColumns(columns);
-        updateSpinners(false);
-    }
-
-    /**
-     * Get format of showing dates.  For example "YMD".  Default value is from
-     * {@link android.text.format.DateFormat#getDateFormatOrder(Context)}.
-     * @return Format of showing dates.
-     */
-    public String getDatePickerFormat() {
-        return mDatePickerFormat;
-    }
-
-    private void updateCurrentLocale() {
-        mConstant = PickerUtility.getDateConstantInstance(Locale.getDefault(),
-                getContext().getResources());
-        mTempDate = PickerUtility.getCalendarForLocale(mTempDate, mConstant.locale);
-        mMinDate = PickerUtility.getCalendarForLocale(mMinDate, mConstant.locale);
-        mMaxDate = PickerUtility.getCalendarForLocale(mMaxDate, mConstant.locale);
-        mCurrentDate = PickerUtility.getCalendarForLocale(mCurrentDate, mConstant.locale);
-
-        if (mMonthColumn != null) {
-            mMonthColumn.setStaticLabels(mConstant.months);
-            setColumnAt(mColMonthIndex, mMonthColumn);
-        }
-    }
-
-    @Override
-    public final void onColumnValueChanged(int column, int newVal) {
-        mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
-        // take care of wrapping of days and months to update greater fields
-        int oldVal = getColumnAt(column).getCurrentValue();
-        if (column == mColDayIndex) {
-            mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
-        } else if (column == mColMonthIndex) {
-            mTempDate.add(Calendar.MONTH, newVal - oldVal);
-        } else if (column == mColYearIndex) {
-            mTempDate.add(Calendar.YEAR, newVal - oldVal);
-        } else {
-            throw new IllegalArgumentException();
-        }
-        setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
-                mTempDate.get(Calendar.DAY_OF_MONTH));
-        updateSpinners(false);
-    }
-
-
-    /**
-     * Sets the minimal date supported by this {@link DatePicker} in
-     * milliseconds since January 1, 1970 00:00:00 in
-     * {@link TimeZone#getDefault()} time zone.
-     *
-     * @param minDate The minimal supported date.
-     */
-    public void setMinDate(long minDate) {
-        mTempDate.setTimeInMillis(minDate);
-        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
-                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
-            return;
-        }
-        mMinDate.setTimeInMillis(minDate);
-        if (mCurrentDate.before(mMinDate)) {
-            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
-        }
-        updateSpinners(false);
-    }
-
-
-    /**
-     * Gets the minimal date supported by this {@link DatePicker} in
-     * milliseconds since January 1, 1970 00:00:00 in
-     * {@link TimeZone#getDefault()} time zone.
-     * <p>
-     * Note: The default minimal date is 01/01/1900.
-     * <p>
-     *
-     * @return The minimal supported date.
-     */
-    public long getMinDate() {
-        return mMinDate.getTimeInMillis();
-    }
-
-    /**
-     * Sets the maximal date supported by this {@link DatePicker} in
-     * milliseconds since January 1, 1970 00:00:00 in
-     * {@link TimeZone#getDefault()} time zone.
-     *
-     * @param maxDate The maximal supported date.
-     */
-    public void setMaxDate(long maxDate) {
-        mTempDate.setTimeInMillis(maxDate);
-        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
-                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
-            return;
-        }
-        mMaxDate.setTimeInMillis(maxDate);
-        if (mCurrentDate.after(mMaxDate)) {
-            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
-        }
-        updateSpinners(false);
-    }
-
-    /**
-     * Gets the maximal date supported by this {@link DatePicker} in
-     * milliseconds since January 1, 1970 00:00:00 in
-     * {@link TimeZone#getDefault()} time zone.
-     * <p>
-     * Note: The default maximal date is 12/31/2100.
-     * <p>
-     *
-     * @return The maximal supported date.
-     */
-    public long getMaxDate() {
-        return mMaxDate.getTimeInMillis();
-    }
-
-    /**
-     * Gets current date value in milliseconds since January 1, 1970 00:00:00 in
-     * {@link TimeZone#getDefault()} time zone.
-     *
-     * @return Current date values.
-     */
-    public long getDate() {
-        return mCurrentDate.getTimeInMillis();
-    }
-
-    private void setDate(int year, int month, int dayOfMonth) {
-        mCurrentDate.set(year, month, dayOfMonth);
-        if (mCurrentDate.before(mMinDate)) {
-            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
-        } else if (mCurrentDate.after(mMaxDate)) {
-            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
-        }
-    }
-
-    /**
-     * Update the current date.
-     *
-     * @param year The year.
-     * @param month The month which is <strong>starting from zero</strong>.
-     * @param dayOfMonth The day of the month.
-     * @param animation True to run animation to scroll the column.
-     */
-    public void updateDate(int year, int month, int dayOfMonth, boolean animation) {
-        if (!isNewDate(year, month, dayOfMonth)) {
-            return;
-        }
-        setDate(year, month, dayOfMonth);
-        updateSpinners(animation);
-    }
-
-    private boolean isNewDate(int year, int month, int dayOfMonth) {
-        return (mCurrentDate.get(Calendar.YEAR) != year
-                || mCurrentDate.get(Calendar.MONTH) != dayOfMonth
-                || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
-    }
-
-    private static boolean updateMin(PickerColumn column, int value) {
-        if (value != column.getMinValue()) {
-            column.setMinValue(value);
-            return true;
-        }
-        return false;
-    }
-
-    private static boolean updateMax(PickerColumn column, int value) {
-        if (value != column.getMaxValue()) {
-            column.setMaxValue(value);
-            return true;
-        }
-        return false;
-    }
-
-    private static int[] DATE_FIELDS = {Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR};
-
-    // Following implementation always keeps up-to-date date ranges (min & max values) no matter
-    // what the currently selected date is. This prevents the constant updating of date values while
-    // scrolling vertically and thus fixes the animation jumps that used to happen when we reached
-    // the endpoint date field values since the adapter values do not change while scrolling up
-    // & down across a single field.
-    void updateSpinnersImpl(boolean animation) {
-        // set the spinner ranges respecting the min and max dates
-        int dateFieldIndices[] = {mColDayIndex, mColMonthIndex, mColYearIndex};
-
-        boolean allLargerDateFieldsHaveBeenEqualToMinDate = true;
-        boolean allLargerDateFieldsHaveBeenEqualToMaxDate = true;
-        for(int i = DATE_FIELDS.length - 1; i >= 0; i--) {
-            boolean dateFieldChanged = false;
-            if (dateFieldIndices[i] < 0)
-                continue;
-
-            int currField = DATE_FIELDS[i];
-            PickerColumn currPickerColumn = getColumnAt(dateFieldIndices[i]);
-
-            if (allLargerDateFieldsHaveBeenEqualToMinDate) {
-                dateFieldChanged |= updateMin(currPickerColumn,
-                        mMinDate.get(currField));
-            } else {
-                dateFieldChanged |= updateMin(currPickerColumn,
-                        mCurrentDate.getActualMinimum(currField));
-            }
-
-            if (allLargerDateFieldsHaveBeenEqualToMaxDate) {
-                dateFieldChanged |= updateMax(currPickerColumn,
-                        mMaxDate.get(currField));
-            } else {
-                dateFieldChanged |= updateMax(currPickerColumn,
-                        mCurrentDate.getActualMaximum(currField));
-            }
-
-            allLargerDateFieldsHaveBeenEqualToMinDate &=
-                    (mCurrentDate.get(currField) == mMinDate.get(currField));
-            allLargerDateFieldsHaveBeenEqualToMaxDate &=
-                    (mCurrentDate.get(currField) == mMaxDate.get(currField));
-
-            if (dateFieldChanged) {
-                setColumnAt(dateFieldIndices[i], currPickerColumn);
-            }
-            setColumnValue(dateFieldIndices[i], mCurrentDate.get(currField), animation);
-        }
-    }
-
-    private void updateSpinners(final boolean animation) {
-        // update range in a post call.  The reason is that RV does not allow notifyDataSetChange()
-        // in scroll pass.  UpdateSpinner can be called in a scroll pass, UpdateSpinner() may
-        // notifyDataSetChange to update the range.
-        post(new Runnable() {
-            @Override
-            public void run() {
-                updateSpinnersImpl(animation);
-            }
-        });
-    }
-}
\ No newline at end of file
diff --git a/leanback/tests/AndroidManifest.xml b/leanback/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from leanback/tests/AndroidManifest.xml
rename to leanback/src/androidTest/AndroidManifest.xml
diff --git a/leanback/tests/generatev4.py b/leanback/src/androidTest/generatev4.py
similarity index 100%
rename from leanback/tests/generatev4.py
rename to leanback/src/androidTest/generatev4.py
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BackgroundManagerTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/BackgroundManagerTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/BackgroundManagerTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/BackgroundManagerTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseFragmentTestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseSupportFragmentTestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseTestFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/BrowseTestFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseTestFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/BrowseTestSupportFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/DetailsFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsTestFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/DetailsTestFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsTestFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/DetailsTestSupportFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepFragmentTestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepFragmentTestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestBase.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepFragmentTestBase.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepFragmentTestBase.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepFragmentTestBase.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestBase.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestBase.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestBase.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepSupportFragmentTestBase.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepTestFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepTestFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestSupportFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepTestSupportFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/GuidedStepTestSupportFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/GuidedStepTestSupportFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/HeadersFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/HeadersFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/HeadersFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/HeadersFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/HeadersSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/HeadersSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/HeadersSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/HeadersSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/ListRowDataAdapterTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/PhotoItem.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/PhotoItem.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/PhotoItem.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/PhotoItem.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackTestFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/PlaybackTestFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackTestFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/PlaybackTestSupportFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/ProgressBarManagerTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/ProgressBarManagerTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/ProgressBarManagerTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/ProgressBarManagerTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/RowsFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/RowsFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/RowsFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/RowsFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/RowsSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/SingleFragmentTestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/SingleFragmentTestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/SingleFragmentTestBase.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/SingleSupportFragmentTestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/SingleSupportFragmentTestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/SingleSupportFragmentTestBase.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/StringPresenter.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/StringPresenter.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/StringPresenter.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/StringPresenter.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/TestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/TestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/TestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/TestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/VerticalGridFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/VerticalGridSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/VideoFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/VideoFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/VideoFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/VideoFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/VideoSupportFragmentTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/VideoSupportFragmentTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/VideoSupportFragmentTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/VideoSupportFragmentTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedDatePickerTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java b/leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/app/wizard/GuidedStepAttributesTestFragment.java
diff --git a/leanback/tests/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/graphics/CompositeDrawableTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawableTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/media/MediaControllerAdapterTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/media/MediaControllerAdapterTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/media/MediaControllerAdapterTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/media/MediaControllerAdapterTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/media/MediaPlayerGlueTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/media/MediaPlayerGlueTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/media/MediaPlayerGlueTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/media/MediaPlayerGlueTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/media/PlaybackBannerControlGlueTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackBannerControlGlueTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/media/PlaybackBannerControlGlueTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackBannerControlGlueTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/media/PlaybackControlGlueTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackControlGlueTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/media/PlaybackControlGlueTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackControlGlueTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueHostImpl.java b/leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackGlueHostImpl.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueHostImpl.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackGlueHostImpl.java
diff --git a/leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackGlueTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/media/PlaybackGlueTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackGlueTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/media/PlaybackTransportControlGlueTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java b/leanback/src/androidTest/java/android/support/v17/leanback/testutils/PollingCheck.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/testutils/PollingCheck.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/testutils/PollingCheck.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/AssertHelper.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/AssertHelper.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/AssertHelper.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/AssertHelper.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/BaseCardViewTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/BaseCardViewTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/BaseCardViewTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/BaseCardViewTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ControlBarTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ControlBarTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ControlBarTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ControlBarTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/GridActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/GridActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/GridActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/GridActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/GridTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/GridTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/GridTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/GridTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetPrefetchTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/GridWidgetPrefetchTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/GridWidgetPrefetchTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/GridWidgetPrefetchTest.java
diff --git a/leanback/src/androidTest/java/android/support/v17/leanback/widget/GridWidgetTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/GridWidgetTest.java
new file mode 100644
index 0000000..71e2e6f
--- /dev/null
+++ b/leanback/src/androidTest/java/android/support/v17/leanback/widget/GridWidgetTest.java
@@ -0,0 +1,6129 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v17.leanback.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.os.Parcelable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v17.leanback.test.R;
+import android.support.v17.leanback.testutils.PollingCheck;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v7.widget.DefaultItemAnimator;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
+import android.text.Selection;
+import android.text.Spannable;
+import android.util.DisplayMetrics;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+import android.util.TypedValue;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class GridWidgetTest {
+
+    private static final float DELTA = 1f;
+    private static final boolean HUMAN_DELAY = false;
+    private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000;
+    private static final int WAIT_FOR_LAYOUT_PASS_TIMEOUT_MS = 2000;
+    private static final int WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS = 6000;
+
+    protected ActivityTestRule<GridActivity> mActivityTestRule;
+    protected GridActivity mActivity;
+    protected BaseGridView mGridView;
+    protected GridLayoutManager mLayoutManager;
+    private GridLayoutManager.OnLayoutCompleteListener mWaitLayoutListener;
+    protected int mOrientation;
+    protected int mNumRows;
+    protected int[] mRemovedItems;
+
+    private final Comparator<View> mRowSortComparator = new Comparator<View>() {
+        @Override
+        public int compare(View lhs, View rhs) {
+            if (mOrientation == BaseGridView.HORIZONTAL) {
+                return lhs.getLeft() - rhs.getLeft();
+            } else {
+                return lhs.getTop() - rhs.getTop();
+            }
+        };
+    };
+
+    /**
+     * Verify margins between items on same row are same.
+     */
+    private final Runnable mVerifyLayout = new Runnable() {
+        @Override
+        public void run() {
+            verifyMargin();
+        }
+    };
+
+    @Rule public TestName testName = new TestName();
+
+    public static void sendKey(int keyCode) {
+        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+    }
+
+    public static void sendRepeatedKeys(int repeats, int keyCode) {
+        for (int i = 0; i < repeats; i++) {
+            InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
+        }
+    }
+
+    private void humanDelay(int delay) throws InterruptedException {
+        if (HUMAN_DELAY) Thread.sleep(delay);
+    }
+    /**
+     * Change size of the Adapter and notifyDataSetChanged.
+     */
+    private void changeArraySize(final int size) throws Throwable {
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.changeArraySize(size);
+            }
+        });
+    }
+
+    static String dumpGridView(BaseGridView gridView) {
+        return "findFocus:" + gridView.getRootView().findFocus()
+                + " isLayoutRequested:" + gridView.isLayoutRequested()
+                + " selectedPosition:" + gridView.getSelectedPosition()
+                + " adapter.itemCount:" + gridView.getAdapter().getItemCount()
+                + " itemAnimator.isRunning:" + gridView.getItemAnimator().isRunning()
+                + " scrollState:" + gridView.getScrollState();
+    }
+
+    /**
+     * Change selected position.
+     */
+    private void setSelectedPosition(final int position, final int scrollExtra) throws Throwable {
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPosition(position, scrollExtra);
+            }
+        });
+        waitForLayout(false);
+    }
+
+    private void setSelectedPosition(final int position) throws Throwable {
+        setSelectedPosition(position, 0);
+    }
+
+    private void setSelectedPositionSmooth(final int position) throws Throwable {
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(position);
+            }
+        });
+    }
+    /**
+     * Scrolls using given key.
+     */
+    protected void scroll(int key, Runnable verify) throws Throwable {
+        do {
+            if (verify != null) {
+                mActivityTestRule.runOnUiThread(verify);
+            }
+            sendRepeatedKeys(10, key);
+            try {
+                Thread.sleep(300);
+            } catch (InterruptedException ex) {
+                break;
+            }
+        } while (mGridView.getLayoutManager().isSmoothScrolling()
+                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE);
+    }
+
+    protected void scrollToBegin(Runnable verify) throws Throwable {
+        int key;
+        // first move to first column/row
+        if (mOrientation == BaseGridView.HORIZONTAL) {
+            key = KeyEvent.KEYCODE_DPAD_UP;
+        } else {
+            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+                key = KeyEvent.KEYCODE_DPAD_RIGHT;
+            } else {
+                key = KeyEvent.KEYCODE_DPAD_LEFT;
+            }
+        }
+        scroll(key, null);
+        if (mOrientation == BaseGridView.HORIZONTAL) {
+            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+                key = KeyEvent.KEYCODE_DPAD_RIGHT;
+            } else {
+                key = KeyEvent.KEYCODE_DPAD_LEFT;
+            }
+        } else {
+            key = KeyEvent.KEYCODE_DPAD_UP;
+        }
+        scroll(key, verify);
+    }
+
+    protected void scrollToEnd(Runnable verify) throws Throwable {
+        int key;
+        // first move to first column/row
+        if (mOrientation == BaseGridView.HORIZONTAL) {
+            key = KeyEvent.KEYCODE_DPAD_UP;
+        } else {
+            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+                key = KeyEvent.KEYCODE_DPAD_RIGHT;
+            } else {
+                key = KeyEvent.KEYCODE_DPAD_LEFT;
+            }
+        }
+        scroll(key, null);
+        if (mOrientation == BaseGridView.HORIZONTAL) {
+            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+                key = KeyEvent.KEYCODE_DPAD_LEFT;
+            } else {
+                key = KeyEvent.KEYCODE_DPAD_RIGHT;
+            }
+        } else {
+            key = KeyEvent.KEYCODE_DPAD_DOWN;
+        }
+        scroll(key, verify);
+    }
+
+    /**
+     * Group and sort children by their position on each row (HORIZONTAL) or column(VERTICAL).
+     */
+    protected View[][] sortByRows() {
+        final HashMap<Integer, ArrayList<View>> rows = new HashMap<Integer, ArrayList<View>>();
+        ArrayList<Integer> rowLocations = new ArrayList<>();
+        for (int i = 0; i < mGridView.getChildCount(); i++) {
+            View v = mGridView.getChildAt(i);
+            int rowLocation;
+            if (mOrientation == BaseGridView.HORIZONTAL) {
+                rowLocation = v.getTop();
+            } else {
+                rowLocation = mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL
+                        ? v.getRight() : v.getLeft();
+            }
+            ArrayList<View> views = rows.get(rowLocation);
+            if (views == null) {
+                views = new ArrayList<View>();
+                rows.put(rowLocation, views);
+                rowLocations.add(rowLocation);
+            }
+            views.add(v);
+        }
+        Object[] sortedLocations = rowLocations.toArray();
+        Arrays.sort(sortedLocations);
+        if (mNumRows != rows.size()) {
+            assertEquals("Dump Views by rows "+rows, mNumRows, rows.size());
+        }
+        View[][] sorted = new View[rows.size()][];
+        for (int i = 0; i < rowLocations.size(); i++) {
+            Integer rowLocation = rowLocations.get(i);
+            ArrayList<View> arr = rows.get(rowLocation);
+            View[] views = arr.toArray(new View[arr.size()]);
+            Arrays.sort(views, mRowSortComparator);
+            sorted[i] = views;
+        }
+        return sorted;
+    }
+
+    protected void verifyMargin() {
+        View[][] sorted = sortByRows();
+        for (int row = 0; row < sorted.length; row++) {
+            View[] views = sorted[row];
+            int margin = -1;
+            for (int i = 1; i < views.length; i++) {
+                if (mOrientation == BaseGridView.HORIZONTAL) {
+                    assertEquals(mGridView.getHorizontalMargin(),
+                            views[i].getLeft() - views[i - 1].getRight());
+                } else {
+                    assertEquals(mGridView.getVerticalMargin(),
+                            views[i].getTop() - views[i - 1].getBottom());
+                }
+            }
+        }
+    }
+
+    protected void verifyBeginAligned() {
+        View[][] sorted = sortByRows();
+        int alignedLocation = 0;
+        if (mOrientation == BaseGridView.HORIZONTAL) {
+            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+                for (int i = 0; i < sorted.length; i++) {
+                    if (i == 0) {
+                        alignedLocation = sorted[i][sorted[i].length - 1].getRight();
+                    } else {
+                        assertEquals(alignedLocation, sorted[i][sorted[i].length - 1].getRight());
+                    }
+                }
+            } else {
+                for (int i = 0; i < sorted.length; i++) {
+                    if (i == 0) {
+                        alignedLocation = sorted[i][0].getLeft();
+                    } else {
+                        assertEquals(alignedLocation, sorted[i][0].getLeft());
+                    }
+                }
+            }
+        } else {
+            for (int i = 0; i < sorted.length; i++) {
+                if (i == 0) {
+                    alignedLocation = sorted[i][0].getTop();
+                } else {
+                    assertEquals(alignedLocation, sorted[i][0].getTop());
+                }
+            }
+        }
+    }
+
+    protected int[] getEndEdges() {
+        View[][] sorted = sortByRows();
+        int[] edges = new int[sorted.length];
+        if (mOrientation == BaseGridView.HORIZONTAL) {
+            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+                for (int i = 0; i < sorted.length; i++) {
+                    edges[i] = sorted[i][0].getLeft();
+                }
+            } else {
+                for (int i = 0; i < sorted.length; i++) {
+                    edges[i] = sorted[i][sorted[i].length - 1].getRight();
+                }
+            }
+        } else {
+            for (int i = 0; i < sorted.length; i++) {
+                edges[i] = sorted[i][sorted[i].length - 1].getBottom();
+            }
+        }
+        return edges;
+    }
+
+    protected void verifyEdgesSame(int[] edges, int[] edges2) {
+        assertEquals(edges.length, edges2.length);
+        for (int i = 0; i < edges.length; i++) {
+            assertEquals(edges[i], edges2[i]);
+        }
+    }
+
+    protected void verifyBoundCount(int count) {
+        if (mActivity.getBoundCount() != count) {
+            StringBuffer b = new StringBuffer();
+            b.append("ItemsLength: ");
+            for (int i = 0; i < mActivity.mItemLengths.length; i++) {
+                b.append(mActivity.mItemLengths[i]).append(",");
+            }
+            assertEquals("Bound count does not match, ItemsLengths: "+ b,
+                    count, mActivity.getBoundCount());
+        }
+    }
+
+    private static int getCenterY(View v) {
+        return (v.getTop() + v.getBottom())/2;
+    }
+
+    private static int getCenterX(View v) {
+        return (v.getLeft() + v.getRight())/2;
+    }
+
+    private void initActivity(Intent intent) throws Throwable {
+        mActivityTestRule = new ActivityTestRule<GridActivity>(GridActivity.class, false, false);
+        mActivity = mActivityTestRule.launchActivity(intent);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mActivity.setTitle(testName.getMethodName());
+                }
+            });
+        Thread.sleep(1000);
+        mGridView = mActivity.mGridView;
+        mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager();
+    }
+
+    @After
+    public void clearTest() {
+        mWaitLayoutListener = null;
+        mLayoutManager = null;
+        mGridView = null;
+        mActivity = null;
+        mActivityTestRule = null;
+    }
+
+    /**
+     * Must be called before waitForLayout() to prepare layout listener.
+     */
+    protected void startWaitLayout() {
+        if (mWaitLayoutListener != null) {
+            throw new IllegalStateException("startWaitLayout() already called");
+        }
+        if (mLayoutManager.mLayoutCompleteListener != null) {
+            throw new IllegalStateException("Cannot startWaitLayout()");
+        }
+        mWaitLayoutListener = mLayoutManager.mLayoutCompleteListener =
+                mock(GridLayoutManager.OnLayoutCompleteListener.class);
+    }
+
+    /**
+     * wait layout to be called and remove the listener.
+     */
+    protected void waitForLayout() {
+        waitForLayout(true);
+    }
+
+    /**
+     * wait layout to be called and remove the listener.
+     * @param force True if always wait regardless if layout requested
+     */
+    protected void waitForLayout(boolean force) {
+        if (mWaitLayoutListener == null) {
+            throw new IllegalStateException("startWaitLayout() not called");
+        }
+        if (mWaitLayoutListener != mLayoutManager.mLayoutCompleteListener) {
+            throw new IllegalStateException("layout listener inconistent");
+        }
+        try {
+            if (force || mGridView.isLayoutRequested()) {
+                verify(mWaitLayoutListener, timeout(WAIT_FOR_LAYOUT_PASS_TIMEOUT_MS).atLeastOnce())
+                        .onLayoutCompleted(any(RecyclerView.State.class));
+            }
+        } finally {
+            mWaitLayoutListener = null;
+            mLayoutManager.mLayoutCompleteListener = null;
+        }
+    }
+
+    /**
+     * If currently running animator, wait for it to finish, otherwise return immediately.
+     * To wait the ItemAnimator start, you can use waitForLayout() to make sure layout pass has
+     * processed adapter change.
+     */
+    protected void waitForItemAnimation(int timeoutMs) throws Throwable {
+        final RecyclerView.ItemAnimator.ItemAnimatorFinishedListener listener = mock(
+                RecyclerView.ItemAnimator.ItemAnimatorFinishedListener.class);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().isRunning(listener);
+            }
+        });
+        verify(listener, timeout(timeoutMs).atLeastOnce()).onAnimationsFinished();
+    }
+
+    protected void waitForItemAnimation() throws Throwable {
+        waitForItemAnimation(WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS);
+    }
+
+    /**
+     * wait animation start
+     */
+    protected void waitForItemAnimationStart() throws Throwable {
+        long totalWait = 0;
+        while (!mGridView.getItemAnimator().isRunning()) {
+            Thread.sleep(10);
+            if ((totalWait += 10) > WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS) {
+                throw new RuntimeException("waitForItemAnimationStart Timeout");
+            }
+        }
+    }
+
+    /**
+     * Run task in UI thread and wait for layout and ItemAnimator finishes.
+     */
+    protected void performAndWaitForAnimation(Runnable task) throws Throwable {
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(task);
+        waitForLayout();
+        waitForItemAnimation();
+    }
+
+    protected void waitForScrollIdle() throws Throwable {
+        waitForScrollIdle(null);
+    }
+
+    /**
+     * Wait for grid view stop scroll and optionally verify state of grid view.
+     */
+    protected void waitForScrollIdle(Runnable verify) throws Throwable {
+        Thread.sleep(100);
+        int total = 0;
+        while (mGridView.getLayoutManager().isSmoothScrolling()
+                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
+            if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) {
+                throw new RuntimeException("waitForScrollIdle Timeout");
+            }
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException ex) {
+                break;
+            }
+            if (verify != null) {
+                mActivityTestRule.runOnUiThread(verify);
+            }
+        }
+    }
+
+    @Test
+    public void testThreeRowHorizontalBasic() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        scrollToEnd(mVerifyLayout);
+
+        scrollToBegin(mVerifyLayout);
+
+        verifyBeginAligned();
+    }
+
+    static class DividerDecoration extends RecyclerView.ItemDecoration {
+
+        private ColorDrawable mTopDivider;
+        private ColorDrawable mBottomDivider;
+        private int mLeftOffset;
+        private int mRightOffset;
+        private int mTopOffset;
+        private int mBottomOffset;
+
+        DividerDecoration(int leftOffset, int topOffset, int rightOffset, int bottomOffset) {
+            mLeftOffset = leftOffset;
+            mTopOffset = topOffset;
+            mRightOffset = rightOffset;
+            mBottomOffset = bottomOffset;
+        }
+
+        @Override
+        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
+            if (mTopDivider == null) {
+                mTopDivider = new ColorDrawable(Color.RED);
+            }
+            if (mBottomDivider == null) {
+                mBottomDivider = new ColorDrawable(Color.BLUE);
+            }
+            final int childCount = parent.getChildCount();
+            final int width = parent.getWidth();
+            for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
+                final View view = parent.getChildAt(childViewIndex);
+                mTopDivider.setBounds(0, (int) view.getY() - mTopOffset, width, (int) view.getY());
+                mTopDivider.draw(c);
+                mBottomDivider.setBounds(0, (int) view.getY() + view.getHeight(), width,
+                        (int) view.getY() + view.getHeight() + mBottomOffset);
+                mBottomDivider.draw(c);
+            }
+        }
+
+        @Override
+        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                                   RecyclerView.State state) {
+            outRect.left = mLeftOffset;
+            outRect.top = mTopOffset;
+            outRect.right = mRightOffset;
+            outRect.bottom = mBottomOffset;
+        }
+    }
+
+    @Test
+    public void testItemDecorationAndMargins() throws Throwable {
+
+        final int leftMargin = 3;
+        final int topMargin = 4;
+        final int rightMargin = 7;
+        final int bottomMargin = 8;
+        final int itemHeight = 100;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight});
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS,
+                new int[]{leftMargin, topMargin, rightMargin, bottomMargin});
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        final int paddingLeft = mGridView.getPaddingLeft();
+        final int paddingTop = mGridView.getPaddingTop();
+        final int verticalSpace = mGridView.getVerticalMargin();
+        final int decorationLeft = 17;
+        final int decorationTop = 1;
+        final int decorationRight = 19;
+        final int decorationBottom = 2;
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
+                        decorationRight, decorationBottom));
+            }
+        });
+
+        View child0 = mGridView.getChildAt(0);
+        View child1 = mGridView.getChildAt(1);
+        View child2 = mGridView.getChildAt(2);
+
+        assertEquals(itemHeight, child0.getBottom() - child0.getTop());
+
+        // verify left margins
+        assertEquals(paddingLeft + leftMargin + decorationLeft, child0.getLeft());
+        assertEquals(paddingLeft + leftMargin + decorationLeft, child1.getLeft());
+        assertEquals(paddingLeft + leftMargin + decorationLeft, child2.getLeft());
+        // verify top bottom margins and decoration offset
+        assertEquals(paddingTop + topMargin + decorationTop, child0.getTop());
+        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
+                child1.getTop() - child0.getBottom());
+        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
+                child2.getTop() - child1.getBottom());
+
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+    @Test
+    public void testItemDecorationAndMarginsAndOpticalBounds() throws Throwable {
+        final int leftMargin = 3;
+        final int topMargin = 4;
+        final int rightMargin = 7;
+        final int bottomMargin = 8;
+        final int itemHeight = 100;
+        final int ninePatchDrawableResourceId = R.drawable.lb_card_shadow_focused;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight});
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS,
+                new int[]{leftMargin, topMargin, rightMargin, bottomMargin});
+        intent.putExtra(GridActivity.EXTRA_NINEPATCH_SHADOW, ninePatchDrawableResourceId);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        final int paddingLeft = mGridView.getPaddingLeft();
+        final int paddingTop = mGridView.getPaddingTop();
+        final int verticalSpace = mGridView.getVerticalMargin();
+        final int decorationLeft = 17;
+        final int decorationTop = 1;
+        final int decorationRight = 19;
+        final int decorationBottom = 2;
+
+        final Rect opticalPaddings = new Rect();
+        mGridView.getResources().getDrawable(ninePatchDrawableResourceId)
+                .getPadding(opticalPaddings);
+        final int opticalInsetsLeft = opticalPaddings.left;
+        final int opticalInsetsTop = opticalPaddings.top;
+        final int opticalInsetsRight = opticalPaddings.right;
+        final int opticalInsetsBottom = opticalPaddings.bottom;
+        assertTrue(opticalInsetsLeft > 0);
+        assertTrue(opticalInsetsTop > 0);
+        assertTrue(opticalInsetsRight > 0);
+        assertTrue(opticalInsetsBottom > 0);
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
+                        decorationRight, decorationBottom));
+            }
+        });
+
+        View child0 = mGridView.getChildAt(0);
+        View child1 = mGridView.getChildAt(1);
+        View child2 = mGridView.getChildAt(2);
+
+        assertEquals(itemHeight + opticalInsetsTop + opticalInsetsBottom,
+                child0.getBottom() - child0.getTop());
+
+        // verify left margins decoration and optical insets
+        assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft,
+                child0.getLeft());
+        assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft,
+                child1.getLeft());
+        assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft,
+                child2.getLeft());
+        // verify top bottom margins decoration offset and optical insets
+        assertEquals(paddingTop + topMargin + decorationTop, child0.getTop() + opticalInsetsTop);
+        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
+                (child1.getTop() + opticalInsetsTop) - (child0.getBottom() - opticalInsetsBottom));
+        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
+                (child2.getTop() + opticalInsetsTop) - (child1.getBottom() - opticalInsetsBottom));
+
+    }
+
+    @Test
+    public void testThreeColumnVerticalBasic() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+
+        scrollToEnd(mVerifyLayout);
+
+        scrollToBegin(mVerifyLayout);
+
+        verifyBeginAligned();
+    }
+
+    @Test
+    public void testRedundantAppendRemove() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid_testredundantappendremove);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
+                149,177,128,234,227,187,163,223,146,210,228,148,227,193,182,197,177,142,225,207,
+                157,171,209,204,187,184,123,221,197,153,202,179,193,214,226,173,225,143,188,159,
+                139,193,233,143,227,203,222,124,228,223,164,131,228,126,211,160,165,152,235,184,
+                155,224,149,181,171,229,200,234,177,130,164,172,188,139,132,203,179,220,147,131,
+                226,127,230,239,183,203,206,227,123,170,239,234,200,149,237,204,160,133,202,234,
+                173,122,139,149,151,153,216,231,121,145,227,153,186,174,223,180,123,215,206,216,
+                239,222,219,207,193,218,140,133,171,153,183,132,233,138,159,174,189,171,143,128,
+                152,222,141,202,224,190,134,120,181,231,230,136,132,224,136,210,207,150,128,183,
+                221,194,179,220,126,221,137,205,223,193,172,132,226,209,133,191,227,127,159,171,
+                180,149,237,177,194,207,170,202,161,144,147,199,205,186,164,140,193,203,224,129});
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+
+        scrollToEnd(mVerifyLayout);
+
+        scrollToBegin(mVerifyLayout);
+
+        verifyBeginAligned();
+    }
+
+    @Test
+    public void testRedundantAppendRemove2() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid_testredundantappendremove2);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
+                318,333,199,224,246,273,269,289,340,313,265,306,349,269,185,282,257,354,316,252,
+                237,290,283,343,196,313,290,343,191,262,342,228,343,349,251,203,226,305,265,213,
+                216,333,295,188,187,281,288,311,244,232,224,332,290,181,267,276,226,261,335,355,
+                225,217,219,183,234,285,257,304,182,250,244,223,257,219,342,185,347,205,302,315,
+                299,309,292,237,192,309,228,250,347,227,337,298,299,185,185,331,223,284,265,351});
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+        mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager();
+
+        // test append without staggered result cache
+        scrollToEnd(mVerifyLayout);
+
+        int[] endEdges = getEndEdges();
+
+        scrollToBegin(mVerifyLayout);
+
+        verifyBeginAligned();
+
+        // now test append with staggered result cache
+        changeArraySize(3);
+        assertEquals("Staggerd cache should be kept as is when no item size change",
+                100, ((StaggeredGrid) mLayoutManager.mGrid).mLocations.size());
+
+        changeArraySize(100);
+
+        scrollToEnd(mVerifyLayout);
+
+        // we should get same aligned end edges
+        int[] endEdges2 = getEndEdges();
+        verifyEdgesSame(endEdges, endEdges2);
+    }
+
+
+    @Test
+    public void testLayoutWhenAViewIsInvalidated() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
+        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, true);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mNumRows = 1;
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        waitOneUiCycle();
+
+        // push views to cache.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.mItemLengths[0] = mActivity.mItemLengths[0] * 3;
+                mActivity.mGridView.getAdapter().notifyItemChanged(0);
+            }
+        });
+        waitForItemAnimation();
+
+        // notifyDataSetChange will mark the cached views FLAG_INVALID
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.mGridView.getAdapter().notifyDataSetChanged();
+            }
+        });
+        waitForItemAnimation();
+
+        // Cached views will be added in prelayout with FLAG_INVALID, in post layout we should
+        // handle it properly
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.mItemLengths[0] = mActivity.mItemLengths[0] / 3;
+                mActivity.mGridView.getAdapter().notifyItemChanged(0);
+            }
+        });
+
+        waitForItemAnimation();
+    }
+
+    @Test
+    public void testWrongInsertViewIndexInFastRelayout() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mNumRows = 1;
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+
+        // removing two children, they will be hidden views as first 2 children of RV.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setRemoveDuration(2000);
+                mActivity.removeItems(0, 2);
+            }
+        });
+        waitForItemAnimationStart();
+
+        // add three views and notify change of the first item.
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(0, new int[]{161, 161, 161});
+            }
+        });
+        waitForLayout();
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getAdapter().notifyItemChanged(0);
+            }
+        });
+        waitForLayout();
+        // after layout, the viewholder should still be the first child of LayoutManager.
+        assertEquals(0, mGridView.getChildAdapterPosition(
+                mGridView.getLayoutManager().getChildAt(0)));
+    }
+
+    @Test
+    public void testMoveIntoPrelayoutItems() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mNumRows = 1;
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+
+        final int lastItemPos = mGridView.getChildCount() - 1;
+        assertTrue(mGridView.getChildCount() >= 4);
+        // notify change of 3 items, so prelayout will layout extra 3 items, then move an item
+        // into the extra layout range. Post layout's fastRelayout() should handle this properly.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getAdapter().notifyItemChanged(lastItemPos - 3);
+                mGridView.getAdapter().notifyItemChanged(lastItemPos - 2);
+                mGridView.getAdapter().notifyItemChanged(lastItemPos - 1);
+                mActivity.moveItem(900, lastItemPos + 2, true);
+            }
+        });
+        waitForItemAnimation();
+    }
+
+    @Test
+    public void testMoveIntoPrelayoutItems2() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mNumRows = 1;
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+
+        setSelectedPosition(999);
+        final int firstItemPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(0));
+        assertTrue(mGridView.getChildCount() >= 4);
+        // notify change of 3 items, so prelayout will layout extra 3 items, then move an item
+        // into the extra layout range. Post layout's fastRelayout() should handle this properly.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getAdapter().notifyItemChanged(firstItemPos + 1);
+                mGridView.getAdapter().notifyItemChanged(firstItemPos + 2);
+                mGridView.getAdapter().notifyItemChanged(firstItemPos + 3);
+                mActivity.moveItem(0, firstItemPos - 2, true);
+            }
+        });
+        waitForItemAnimation();
+    }
+
+    void preparePredictiveLayout() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setAddDuration(1000);
+                mGridView.getItemAnimator().setRemoveDuration(1000);
+                mGridView.getItemAnimator().setMoveDuration(1000);
+                mGridView.getItemAnimator().setChangeDuration(1000);
+                mGridView.setSelectedPositionSmooth(50);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+    }
+
+    @Test
+    public void testPredictiveLayoutAdd1() throws Throwable {
+        preparePredictiveLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(51, new int[]{300, 300, 300, 300});
+            }
+        });
+        waitForItemAnimationStart();
+        waitForItemAnimation();
+        assertEquals(50, mGridView.getSelectedPosition());
+        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
+    }
+
+    @Test
+    public void testPredictiveLayoutAdd2() throws Throwable {
+        preparePredictiveLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(50, new int[]{300, 300, 300, 300});
+            }
+        });
+        waitForItemAnimationStart();
+        waitForItemAnimation();
+        assertEquals(54, mGridView.getSelectedPosition());
+        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
+    }
+
+    @Test
+    public void testPredictiveLayoutRemove1() throws Throwable {
+        preparePredictiveLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(51, 3);
+            }
+        });
+        waitForItemAnimationStart();
+        waitForItemAnimation();
+        assertEquals(50, mGridView.getSelectedPosition());
+        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
+    }
+
+    @Test
+    public void testPredictiveLayoutRemove2() throws Throwable {
+        preparePredictiveLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(47, 3);
+            }
+        });
+        waitForItemAnimationStart();
+        waitForItemAnimation();
+        assertEquals(47, mGridView.getSelectedPosition());
+        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
+    }
+
+    @Test
+    public void testPredictiveLayoutRemove3() throws Throwable {
+        preparePredictiveLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(0, 51);
+            }
+        });
+        waitForItemAnimationStart();
+        waitForItemAnimation();
+        assertEquals(0, mGridView.getSelectedPosition());
+        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
+    }
+
+    @Test
+    public void testPredictiveOnMeasureWrapContent() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear_wrap_content);
+        int count = 50;
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, count);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        waitForScrollIdle(mVerifyLayout);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setHasFixedSize(false);
+            }
+        });
+
+        for (int i = 0; i < 30; i++) {
+            final int oldCount = count;
+            final int newCount = i;
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (oldCount > 0) {
+                        mActivity.removeItems(0, oldCount);
+                    }
+                    if (newCount > 0) {
+                        int[] newItems = new int[newCount];
+                        for (int i = 0; i < newCount; i++) {
+                            newItems[i] = 400;
+                        }
+                        mActivity.addItems(0, newItems);
+                    }
+                }
+            });
+            waitForItemAnimationStart();
+            waitForItemAnimation();
+            count = newCount;
+        }
+
+    }
+
+    @Test
+    public void testPredictiveLayoutRemove4() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(50);
+            }
+        });
+        waitForScrollIdle();
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(0, 49);
+            }
+        });
+        assertEquals(1, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testPredictiveLayoutRemove5() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(50);
+            }
+        });
+        waitForScrollIdle();
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(50, 40);
+            }
+        });
+        assertEquals(50, mGridView.getSelectedPosition());
+        scrollToBegin(mVerifyLayout);
+        verifyBeginAligned();
+    }
+
+    void waitOneUiCycle() throws Throwable {
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+            }
+        });
+    }
+
+    @Test
+    public void testDontPruneMovingItem() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setMoveDuration(2000);
+                mGridView.setSelectedPosition(50);
+            }
+        });
+        waitForScrollIdle();
+        final ArrayList<RecyclerView.ViewHolder> moveViewHolders = new ArrayList();
+        for (int i = 51;; i++) {
+            RecyclerView.ViewHolder vh = mGridView.findViewHolderForAdapterPosition(i);
+            if (vh == null) {
+                break;
+            }
+            moveViewHolders.add(vh);
+        }
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // add a lot of items, so we will push everything to right of 51 out side window
+                int[] lots_items = new int[1000];
+                for (int i = 0; i < lots_items.length; i++) {
+                    lots_items[i] = 300;
+                }
+                mActivity.addItems(51, lots_items);
+            }
+        });
+        waitOneUiCycle();
+        // run a scroll pass, the scroll pass should not remove the animating views even they are
+        // outside visible areas.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.scrollBy(-3, 0);
+            }
+        });
+        waitOneUiCycle();
+        for (int i = 0; i < moveViewHolders.size(); i++) {
+            assertSame(mGridView, moveViewHolders.get(i).itemView.getParent());
+        }
+    }
+
+    @Test
+    public void testMoveItemToTheRight() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setAddDuration(2000);
+                mGridView.getItemAnimator().setMoveDuration(2000);
+                mGridView.setSelectedPosition(50);
+            }
+        });
+        waitForScrollIdle();
+        RecyclerView.ViewHolder moveViewHolder = mGridView.findViewHolderForAdapterPosition(51);
+
+        int lastPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(
+                mGridView.getChildCount() - 1));
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.moveItem(51, 1000, true);
+            }
+        });
+        final ArrayList<View> moveInViewHolders = new ArrayList();
+        waitForItemAnimationStart();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mGridView.getLayoutManager().getChildCount(); i++) {
+                    View v = mGridView.getLayoutManager().getChildAt(i);
+                    if (mGridView.getChildAdapterPosition(v) >= 51) {
+                        moveInViewHolders.add(v);
+                    }
+                }
+            }
+        });
+        waitOneUiCycle();
+        assertTrue("prelayout should layout extra items to slide in",
+                moveInViewHolders.size() > lastPos - 51);
+        // run a scroll pass, the scroll pass should not remove the animating views even they are
+        // outside visible areas.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.scrollBy(-3, 0);
+            }
+        });
+        waitOneUiCycle();
+        for (int i = 0; i < moveInViewHolders.size(); i++) {
+            assertSame(mGridView, moveInViewHolders.get(i).getParent());
+        }
+        assertSame(mGridView, moveViewHolder.itemView.getParent());
+        assertFalse(moveViewHolder.isRecyclable());
+        waitForItemAnimation();
+        assertNull(moveViewHolder.itemView.getParent());
+        assertTrue(moveViewHolder.isRecyclable());
+    }
+
+    @Test
+    public void testMoveItemToTheLeft() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setAddDuration(2000);
+                mGridView.getItemAnimator().setMoveDuration(2000);
+                mGridView.setSelectedPosition(1500);
+            }
+        });
+        waitForScrollIdle();
+        RecyclerView.ViewHolder moveViewHolder = mGridView.findViewHolderForAdapterPosition(1499);
+
+        int firstPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(0));
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.moveItem(1499, 1, true);
+            }
+        });
+        final ArrayList<View> moveInViewHolders = new ArrayList();
+        waitForItemAnimationStart();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mGridView.getLayoutManager().getChildCount(); i++) {
+                    View v = mGridView.getLayoutManager().getChildAt(i);
+                    if (mGridView.getChildAdapterPosition(v) <= 1499) {
+                        moveInViewHolders.add(v);
+                    }
+                }
+            }
+        });
+        waitOneUiCycle();
+        assertTrue("prelayout should layout extra items to slide in ",
+                moveInViewHolders.size() > 1499 - firstPos);
+        // run a scroll pass, the scroll pass should not remove the animating views even they are
+        // outside visible areas.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.scrollBy(3, 0);
+            }
+        });
+        waitOneUiCycle();
+        for (int i = 0; i < moveInViewHolders.size(); i++) {
+            assertSame(mGridView, moveInViewHolders.get(i).getParent());
+        }
+        assertSame(mGridView, moveViewHolder.itemView.getParent());
+        assertFalse(moveViewHolder.isRecyclable());
+        waitForItemAnimation();
+        assertNull(moveViewHolder.itemView.getParent());
+        assertTrue(moveViewHolder.isRecyclable());
+    }
+
+    @Test
+    public void testContinuousSwapForward() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(150);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        for (int i = 150; i < 199; i++) {
+            final int swapIndex = i;
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mActivity.swap(swapIndex, swapIndex + 1);
+                }
+            });
+            Thread.sleep(10);
+        }
+        waitForItemAnimation();
+        assertEquals(199, mGridView.getSelectedPosition());
+        // check if ItemAnimation finishes at aligned positions:
+        int leftEdge = mGridView.getLayoutManager().findViewByPosition(199).getLeft();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(199).getLeft());
+    }
+
+    @Test
+    public void testContinuousSwapBackward() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(50);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        for (int i = 50; i > 0; i--) {
+            final int swapIndex = i;
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mActivity.swap(swapIndex, swapIndex - 1);
+                }
+            });
+            Thread.sleep(10);
+        }
+        waitForItemAnimation();
+        assertEquals(0, mGridView.getSelectedPosition());
+        // check if ItemAnimation finishes at aligned positions:
+        int leftEdge = mGridView.getLayoutManager().findViewByPosition(0).getLeft();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(0).getLeft());
+    }
+
+    @Test
+    public void testScrollAndStuck() throws Throwable {
+        // see b/67370222 fastRelayout() may be stuck.
+        final int numItems = 19;
+        final int[] itemsLength = new int[numItems];
+        for (int i = 0; i < numItems; i++) {
+            itemsLength[i] = 288;
+        }
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        // set left right padding to 112, space between items to be 16.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ViewGroup.LayoutParams lp = mGridView.getLayoutParams();
+                lp.width = 1920;
+                mGridView.setLayoutParams(lp);
+                mGridView.setPadding(112, mGridView.getPaddingTop(), 112,
+                        mGridView.getPaddingBottom());
+                mGridView.setItemSpacing(16);
+            }
+        });
+        waitOneUiCycle();
+
+        int scrollPos = 0;
+        while (true) {
+            final View view = mGridView.getChildAt(mGridView.getChildCount() - 1);
+            final int pos = mGridView.getChildViewHolder(view).getAdapterPosition();
+            if (scrollPos != pos) {
+                scrollPos = pos;
+                mActivityTestRule.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        mGridView.smoothScrollToPosition(pos);
+                    }
+                });
+            }
+            // wait until we see 2nd from last:
+            if (pos >= 17) {
+                if (pos == 17) {
+                    // great we can test fastRelayout() bug.
+                    Thread.sleep(50);
+                    mActivityTestRule.runOnUiThread(new Runnable() {
+                        @Override
+                        public void run() {
+                            view.requestLayout();
+                        }
+                    });
+                }
+                break;
+            }
+            Thread.sleep(16);
+        }
+        waitForScrollIdle();
+    }
+
+    @Test
+    public void testSwapAfterScroll() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setMoveDuration(1000);
+                mGridView.setSelectedPositionSmooth(150);
+            }
+        });
+        waitForScrollIdle();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(151);
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // we want to swap and select new target which is at 150 before swap
+                mGridView.setSelectedPositionSmooth(150);
+                mActivity.swap(150, 151);
+            }
+        });
+        waitForItemAnimation();
+        waitForScrollIdle();
+        assertEquals(151, mGridView.getSelectedPosition());
+        // check if ItemAnimation finishes at aligned positions:
+        int leftEdge = mGridView.getLayoutManager().findViewByPosition(151).getLeft();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(151).getLeft());
+    }
+
+    void testScrollInSmoothScrolling(final boolean smooth, final boolean scrollToInvisible,
+            final boolean useRecyclerViewMethod) throws Throwable {
+        final int numItems = 100;
+        final int[] itemsLength = new int[numItems];
+        for (int i = 0; i < numItems; i++) {
+            itemsLength[i] = 288;
+        }
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        // start a smoothScroller
+        final int selectedPosition = 99;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.smoothScrollToPosition(selectedPosition);
+            }
+        });
+        Thread.sleep(50);
+        // while smoothScroller is still running, scroll to a different position
+        final int[] existing_position = new int[1];
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                existing_position[0] = mGridView.getChildAdapterPosition(
+                        mGridView.getChildAt(mGridView.getChildCount() - 1));
+                if (scrollToInvisible) {
+                    existing_position[0] = existing_position[0] + 3;
+                }
+                if (useRecyclerViewMethod) {
+                    if (smooth) {
+                        mGridView.smoothScrollToPosition(existing_position[0]);
+                    } else {
+                        mGridView.scrollToPosition(existing_position[0]);
+                    }
+                } else {
+                    if (smooth) {
+                        mGridView.setSelectedPositionSmooth(existing_position[0]);
+                    } else {
+                        mGridView.setSelectedPosition(existing_position[0]);
+                    }
+                }
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(existing_position[0], mGridView.getSelectedPosition());
+        assertTrue(mGridView.findViewHolderForAdapterPosition(existing_position[0])
+                .itemView.hasFocus());
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling1() throws Throwable {
+        testScrollInSmoothScrolling(false, false, false);
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling2() throws Throwable {
+        testScrollInSmoothScrolling(false, false, true);
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling3() throws Throwable {
+        testScrollInSmoothScrolling(false, true, false);
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling4() throws Throwable {
+        testScrollInSmoothScrolling(false, true, true);
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling5() throws Throwable {
+        testScrollInSmoothScrolling(true, false, false);
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling6() throws Throwable {
+        testScrollInSmoothScrolling(true, false, true);
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling7() throws Throwable {
+        testScrollInSmoothScrolling(true, true, false);
+    }
+
+    @Test
+    public void testScrollInSmoothScrolling8() throws Throwable {
+        testScrollInSmoothScrolling(true, true, true);
+    }
+
+    @Test
+    public void testScrollAfterRequestLayout() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setHasFixedSize(false);
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffsetPercent(30);
+            }
+        });
+        waitOneUiCycle();
+
+        final boolean[] scrolled = new boolean[1];
+        mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                if (dx != 0)  scrolled[0] = true;
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+                mGridView.setSelectedPosition(1);
+            }
+        });
+        waitOneUiCycle();
+        assertFalse(scrolled[0]);
+    }
+
+    @Test
+    public void testScrollAfterItemAnimator() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setHasFixedSize(false);
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffsetPercent(30);
+            }
+        });
+        waitOneUiCycle();
+
+        final boolean[] scrolled = new boolean[1];
+        mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                if (dx != 0)  scrolled[0] = true;
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.changeItem(0, 10);
+                mGridView.setSelectedPosition(1);
+            }
+        });
+        waitOneUiCycle();
+        assertFalse(scrolled[0]);
+    }
+
+    @Test
+    public void testItemMovedHorizontal() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(150);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.swap(150, 152);
+            }
+        });
+        mActivityTestRule.runOnUiThread(mVerifyLayout);
+
+        scrollToBegin(mVerifyLayout);
+
+        verifyBeginAligned();
+    }
+
+    @Test
+    public void testItemMovedHorizontalRtl() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear_rtl);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[] {40, 40, 40});
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.moveItem(0, 1, true);
+            }
+        });
+        assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(),
+                mGridView.findViewHolderForAdapterPosition(0).itemView.getRight());
+    }
+
+    @Test
+    public void testScrollSecondaryCannotScroll() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+        final int topPadding = 2;
+        final int bottomPadding = 2;
+        final int height = mGridView.getHeight();
+        final int spacing = 2;
+        final int rowHeight = (height - topPadding - bottomPadding) / 4 - spacing;
+        final HorizontalGridView horizontalGridView = (HorizontalGridView) mGridView;
+
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                horizontalGridView.setPadding(0, topPadding, 0, bottomPadding);
+                horizontalGridView.setItemSpacing(spacing);
+                horizontalGridView.setNumRows(mNumRows);
+                horizontalGridView.setRowHeight(rowHeight);
+            }
+        });
+        waitForLayout();
+        // navigate vertically in first column, first row should always be aligned to top padding
+        for (int i = 0; i < 3; i++) {
+            setSelectedPosition(i);
+            assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView
+                    .getTop());
+        }
+        // navigate vertically in 100th column, first row should always be aligned to top padding
+        for (int i = 300; i < 301; i++) {
+            setSelectedPosition(i);
+            assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(300).itemView
+                    .getTop());
+        }
+    }
+
+    @Test
+    public void testScrollSecondaryNeedScroll() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        // test a lot of rows so we have to scroll vertically to reach
+        mNumRows = 9;
+        final int topPadding = 2;
+        final int bottomPadding = 2;
+        final int height = mGridView.getHeight();
+        final int spacing = 2;
+        final int rowHeight = (height - topPadding - bottomPadding) / 4 - spacing;
+        final HorizontalGridView horizontalGridView = (HorizontalGridView) mGridView;
+
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                horizontalGridView.setPadding(0, topPadding, 0, bottomPadding);
+                horizontalGridView.setItemSpacing(spacing);
+                horizontalGridView.setNumRows(mNumRows);
+                horizontalGridView.setRowHeight(rowHeight);
+            }
+        });
+        waitForLayout();
+        View view;
+        // first row should be aligned to top padding
+        setSelectedPosition(0);
+        assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView.getTop());
+        // middle row should be aligned to keyline (1/2 of screen height)
+        setSelectedPosition(4);
+        view = mGridView.findViewHolderForAdapterPosition(4).itemView;
+        assertEquals(height / 2, (view.getTop() + view.getBottom()) / 2);
+        // last row should be aligned to bottom padding.
+        setSelectedPosition(8);
+        view = mGridView.findViewHolderForAdapterPosition(8).itemView;
+        assertEquals(height, view.getTop() + rowHeight + bottomPadding);
+        setSelectedPositionSmooth(4);
+        waitForScrollIdle();
+        // middle row should be aligned to keyline (1/2 of screen height)
+        setSelectedPosition(4);
+        view = mGridView.findViewHolderForAdapterPosition(4).itemView;
+        assertEquals(height / 2, (view.getTop() + view.getBottom()) / 2);
+        // first row should be aligned to top padding
+        setSelectedPositionSmooth(0);
+        waitForScrollIdle();
+        assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView.getTop());
+    }
+
+    @Test
+    public void testItemMovedVertical() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+
+        mGridView.setSelectedPositionSmooth(150);
+        waitForScrollIdle(mVerifyLayout);
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.swap(150, 152);
+            }
+        });
+        mActivityTestRule.runOnUiThread(mVerifyLayout);
+
+        scrollToEnd(mVerifyLayout);
+        scrollToBegin(mVerifyLayout);
+
+        verifyBeginAligned();
+    }
+
+    @Test
+    public void testAddLastItemHorizontal() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        mGridView.setSelectedPositionSmooth(49);
+                    }
+                }
+        );
+        waitForScrollIdle(mVerifyLayout);
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(50, new int[]{150});
+            }
+        });
+
+        // assert new added item aligned to right edge
+        assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(),
+                mGridView.getLayoutManager().findViewByPosition(50).getRight());
+    }
+
+    @Test
+    public void testAddMultipleLastItemsHorizontal() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_BOTH_EDGE);
+                        mGridView.setWindowAlignmentOffsetPercent(50);
+                        mGridView.setSelectedPositionSmooth(49);
+                    }
+                }
+        );
+        waitForScrollIdle(mVerifyLayout);
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(50, new int[]{150, 150, 150, 150, 150, 150, 150, 150, 150,
+                        150, 150, 150, 150, 150});
+            }
+        });
+
+        // The focused item will be at center of window
+        View view = mGridView.getLayoutManager().findViewByPosition(49);
+        assertEquals(mGridView.getWidth() / 2, (view.getLeft() + view.getRight()) / 2);
+    }
+
+    @Test
+    public void testItemAddRemoveHorizontal() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        scrollToEnd(mVerifyLayout);
+        int[] endEdges = getEndEdges();
+
+        mGridView.setSelectedPositionSmooth(150);
+        waitForScrollIdle(mVerifyLayout);
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mRemovedItems = mActivity.removeItems(151, 4);
+            }
+        });
+
+        scrollToEnd(mVerifyLayout);
+        mGridView.setSelectedPositionSmooth(150);
+        waitForScrollIdle(mVerifyLayout);
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(151, mRemovedItems);
+            }
+        });
+        scrollToEnd(mVerifyLayout);
+
+        // we should get same aligned end edges
+        int[] endEdges2 = getEndEdges();
+        verifyEdgesSame(endEdges, endEdges2);
+
+        scrollToBegin(mVerifyLayout);
+        verifyBeginAligned();
+    }
+
+    @Test
+    public void testSetSelectedPositionDetached() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int focusToIndex = 49;
+        final ViewGroup parent = (ViewGroup) mGridView.getParent();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                parent.removeView(mGridView);
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                parent.addView(mGridView);
+                mGridView.requestFocus();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(mGridView.getSelectedPosition(), focusToIndex);
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex).hasFocus());
+
+        final int focusToIndex2 = 0;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                parent.removeView(mGridView);
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPosition(focusToIndex2);
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                parent.addView(mGridView);
+                mGridView.requestFocus();
+            }
+        });
+        assertEquals(mGridView.getSelectedPosition(), focusToIndex2);
+        waitForScrollIdle();
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex2).hasFocus());
+    }
+
+    @Test
+    public void testBug22209986() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int focusToIndex = mGridView.getChildCount() - 1;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+
+        waitForScrollIdle();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex + 1);
+            }
+        });
+        // let the scroll running for a while and requestLayout during scroll
+        Thread.sleep(80);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(mGridView.getScrollState(), BaseGridView.SCROLL_STATE_SETTLING);
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+
+        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(leftEdge,
+                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
+    }
+
+    void testScrollAndRemove(int[] itemsLength, int numItems) throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        if (itemsLength != null) {
+            intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength);
+        } else {
+            intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        }
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int focusToIndex = mGridView.getChildCount() - 1;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(focusToIndex, 1);
+            }
+        });
+
+        waitOneUiCycle();
+        waitForScrollIdle();
+        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(leftEdge,
+                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(), DELTA);
+    }
+
+    @Test
+    public void testScrollAndRemove() throws Throwable {
+        // test random lengths for 50 items
+        testScrollAndRemove(null, 50);
+    }
+
+    /**
+     * This test verifies if scroll limits are ignored when onLayoutChildren compensate remaining
+     * scroll distance. b/64931938
+     * In the test, second child is long, other children are short.
+     * Test scrolls to the long child, and when scrolling, remove the long child. We made it long
+     * to have enough remaining scroll distance when the layout pass kicks in.
+     * The onLayoutChildren() would compensate the remaining scroll distance, moving all items
+     * toward right, which will make the first item's left edge bigger than left padding,
+     * which would violate the "scroll limit of left" in a regular scroll case, but
+     * in layout pass, we still honor that scroll request, ignoring the scroll limit.
+     */
+    @Test
+    public void testScrollAndRemoveSample1() throws Throwable {
+        DisplayMetrics dm = InstrumentationRegistry.getInstrumentation().getTargetContext()
+                .getResources().getDisplayMetrics();
+        // screen width for long item and 4DP for other items
+        int longItemLength = dm.widthPixels;
+        int shortItemLength = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, dm);
+        int[] items = new int[1000];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = shortItemLength;
+        }
+        items[1] = longItemLength;
+        testScrollAndRemove(items, 0);
+    }
+
+    @Test
+    public void testScrollAndInsert() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        int[] items = new int[1000];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300 + (int)(Math.random() * 100);
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(150);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+
+        View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
+        final int focusToIndex = mGridView.getChildAdapterPosition(view);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                int[] newItems = new int[]{300, 300, 300};
+                mActivity.addItems(0, newItems);
+            }
+        });
+        waitForScrollIdle();
+        int topEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getTop();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(topEdge,
+                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getTop());
+    }
+
+    @Test
+    public void testScrollAndInsertBeforeVisibleItem() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        int[] items = new int[1000];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300 + (int)(Math.random() * 100);
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(150);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+
+        View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
+        final int focusToIndex = mGridView.getChildAdapterPosition(view);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                int[] newItems = new int[]{300, 300, 300};
+                mActivity.addItems(focusToIndex, newItems);
+            }
+        });
+    }
+
+    @Test
+    public void testSmoothScrollAndRemove() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int focusToIndex = 200;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(focusToIndex, 1);
+            }
+        });
+
+        assertTrue("removing the index of not attached child should not affect smooth scroller",
+                mGridView.getLayoutManager().isSmoothScrolling());
+        waitForScrollIdle();
+        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(leftEdge,
+                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
+    }
+
+    @Test
+    public void testSmoothScrollAndRemove2() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int focusToIndex = 200;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusToIndex);
+            }
+        });
+
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final int removeIndex = mGridView.getChildViewHolder(
+                        mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition();
+                mActivity.removeItems(removeIndex, 1);
+            }
+        });
+        waitForLayout();
+
+        assertTrue("removing the index of attached child should not kill smooth scroller",
+                mGridView.getLayoutManager().isSmoothScrolling());
+        waitForItemAnimation();
+        waitForScrollIdle();
+        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(leftEdge,
+                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
+    }
+
+    @Test
+    public void testPendingSmoothScrollAndRemove() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 630 + (int)(Math.random() * 100);
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(0);
+        waitForScrollIdle(mVerifyLayout);
+        assertTrue(mGridView.getChildAt(0).hasFocus());
+
+        // Pressing lots of key to make sure smooth scroller is running
+        mGridView.mLayoutManager.mMaxPendingMoves = 100;
+        for (int i = 0; i < 100; i++) {
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+
+        assertTrue(mGridView.getLayoutManager().isSmoothScrolling());
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final int removeIndex = mGridView.getChildViewHolder(
+                        mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition();
+                mActivity.removeItems(removeIndex, 1);
+            }
+        });
+        waitForLayout();
+
+        assertTrue("removing the index of attached child should not kill smooth scroller",
+                mGridView.getLayoutManager().isSmoothScrolling());
+
+        waitForItemAnimation();
+        waitForScrollIdle();
+        int focusIndex = mGridView.getSelectedPosition();
+        int topEdge = mGridView.getLayoutManager().findViewByPosition(focusIndex).getTop();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+            }
+        });
+        waitForScrollIdle();
+        assertEquals(topEdge,
+                mGridView.getLayoutManager().findViewByPosition(focusIndex).getTop());
+    }
+
+    @Test
+    public void testFocusToFirstItem() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mRemovedItems = mActivity.removeItems(0, 200);
+            }
+        });
+
+        humanDelay(500);
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(0, mRemovedItems);
+            }
+        });
+
+        humanDelay(500);
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus());
+
+        changeArraySize(0);
+
+        changeArraySize(200);
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus());
+    }
+
+    @Test
+    public void testNonFocusableHorizontal() throws Throwable {
+        final int numItems = 200;
+        final int startPos = 45;
+        final int skips = 20;
+        final int numColumns = 3;
+        final int endPos = startPos + numColumns * (skips + 1);
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = numColumns;
+        boolean[] focusable = new boolean[numItems];
+        for (int i = 0; i < focusable.length; i++) {
+            focusable[i] = true;
+        }
+        for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) {
+            focusable[i] = false;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(startPos);
+        waitForScrollIdle(mVerifyLayout);
+
+        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        } else {
+            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        }
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(endPos, mGridView.getSelectedPosition());
+
+        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        } else {
+            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        }
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(startPos, mGridView.getSelectedPosition());
+
+    }
+
+    @Test
+    public void testNoInitialFocusable() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        final int numItems = 100;
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+        boolean[] focusable = new boolean[numItems];
+        final int firstFocusableIndex = 10;
+        for (int i = 0; i < firstFocusableIndex; i++) {
+            focusable[i] = false;
+        }
+        for (int i = firstFocusableIndex; i < focusable.length; i++) {
+            focusable[i] = true;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+        assertTrue(mGridView.isFocused());
+
+        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        } else {
+            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        }
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(firstFocusableIndex, mGridView.getSelectedPosition());
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus());
+    }
+
+    @Test
+    public void testFocusOutOfEmptyListView() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        final int numItems = 100;
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+        initActivity(intent);
+
+        final View horizontalGridView = new HorizontalGridViewEx(mGridView.getContext());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                horizontalGridView.setFocusable(true);
+                horizontalGridView.setFocusableInTouchMode(true);
+                horizontalGridView.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+                ((ViewGroup) mGridView.getParent()).addView(horizontalGridView, 0);
+                horizontalGridView.requestFocus();
+            }
+        });
+
+        assertTrue(horizontalGridView.isFocused());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+
+        assertTrue(mGridView.hasFocus());
+    }
+
+    @Test
+    public void testTransferFocusToChildWhenGainFocus() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        final int numItems = 100;
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+        boolean[] focusable = new boolean[numItems];
+        final int firstFocusableIndex = 1;
+        for (int i = 0; i < firstFocusableIndex; i++) {
+            focusable[i] = false;
+        }
+        for (int i = firstFocusableIndex; i < focusable.length; i++) {
+            focusable[i] = true;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        assertEquals(firstFocusableIndex, mGridView.getSelectedPosition());
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus());
+    }
+
+    @Test
+    public void testFocusFromSecondChild() throws Throwable {
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        final int numItems = 100;
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+        boolean[] focusable = new boolean[numItems];
+        for (int i = 0; i < focusable.length; i++) {
+            focusable[i] = false;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        // switching Adapter to cause a full rebind,  test if it will focus to second item.
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.mNumItems = numItems;
+                mActivity.mItemFocusables[1] = true;
+                mActivity.rebindToNewAdapter();
+            }
+        });
+        assertTrue(mGridView.findViewHolderForAdapterPosition(1).itemView.hasFocus());
+    }
+
+    @Test
+    public void removeFocusableItemAndFocusableRecyclerViewGetsFocus() throws Throwable {
+        final int numItems = 100;
+        final int numColumns = 3;
+        final int focusableIndex = 2;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = numColumns;
+        boolean[] focusable = new boolean[numItems];
+        for (int i = 0; i < focusable.length; i++) {
+            focusable[i] = false;
+        }
+        focusable[focusableIndex] = true;
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(focusableIndex);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(focusableIndex, mGridView.getSelectedPosition());
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(focusableIndex, 1);
+            }
+        });
+        assertTrue(dumpGridView(mGridView), mGridView.isFocused());
+    }
+
+    @Test
+    public void removeFocusableItemAndUnFocusableRecyclerViewLosesFocus() throws Throwable {
+        final int numItems = 100;
+        final int numColumns = 3;
+        final int focusableIndex = 2;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = numColumns;
+        boolean[] focusable = new boolean[numItems];
+        for (int i = 0; i < focusable.length; i++) {
+            focusable[i] = false;
+        }
+        focusable[focusableIndex] = true;
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setFocusableInTouchMode(false);
+                mGridView.setFocusable(false);
+                mGridView.setSelectedPositionSmooth(focusableIndex);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(focusableIndex, mGridView.getSelectedPosition());
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(focusableIndex, 1);
+            }
+        });
+        assertFalse(dumpGridView(mGridView), mGridView.hasFocus());
+    }
+
+    @Test
+    public void testNonFocusableVertical() throws Throwable {
+        final int numItems = 200;
+        final int startPos = 44;
+        final int skips = 20;
+        final int numColumns = 3;
+        final int endPos = startPos + numColumns * (skips + 1);
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = numColumns;
+        boolean[] focusable = new boolean[numItems];
+        for (int i = 0; i < focusable.length; i++) {
+            focusable[i] = true;
+        }
+        for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) {
+            focusable[i] = false;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(startPos);
+        waitForScrollIdle(mVerifyLayout);
+
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(endPos, mGridView.getSelectedPosition());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(startPos, mGridView.getSelectedPosition());
+
+    }
+
+    @Test
+    public void testLtrFocusOutStartDisabled() throws Throwable {
+        final int numItems = 200;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_ltr);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 2;
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestFocus();
+                mGridView.setSelectedPositionSmooth(0);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        waitForScrollIdle(mVerifyLayout);
+        assertTrue(mGridView.hasFocus());
+    }
+
+    @Test
+    public void testVerticalGridRtl() throws Throwable {
+        final int numItems = 200;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_rtl);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 2;
+        initActivity(intent);
+
+        waitForScrollIdle(mVerifyLayout);
+
+        View item0 = mGridView.findViewHolderForAdapterPosition(0).itemView;
+        View item1 = mGridView.findViewHolderForAdapterPosition(1).itemView;
+        assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(), item0.getRight());
+        assertEquals(item0.getLeft(), item1.getRight() + mGridView.getHorizontalSpacing());
+    }
+
+    @Test
+    public void testRtlFocusOutStartDisabled() throws Throwable {
+        final int numItems = 200;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_rtl);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestFocus();
+                mGridView.setSelectedPositionSmooth(0);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        waitForScrollIdle(mVerifyLayout);
+        assertTrue(mGridView.hasFocus());
+    }
+
+    @Test
+    public void testTransferFocusable() throws Throwable {
+        final int numItems = 200;
+        final int numColumns = 3;
+        final int startPos = 1;
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = numColumns;
+        boolean[] focusable = new boolean[numItems];
+        for (int i = 0; i < focusable.length; i++) {
+            focusable[i] = true;
+        }
+        for (int i = 0; i < startPos; i++) {
+            focusable[i] = false;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        changeArraySize(0);
+        assertTrue(mGridView.isFocused());
+
+        changeArraySize(numItems);
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
+    }
+
+    @Test
+    public void testTransferFocusable2() throws Throwable {
+        final int numItems = 200;
+        final int numColumns = 3;
+        final int startPos = 3; // make sure view at startPos is in visible area.
+
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = numColumns;
+        boolean[] focusable = new boolean[numItems];
+        for (int i = 0; i < focusable.length; i++) {
+            focusable[i] = true;
+        }
+        for (int i = 0; i < startPos; i++) {
+            focusable[i] = false;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
+        initActivity(intent);
+
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
+
+        changeArraySize(0);
+        assertTrue(mGridView.isFocused());
+
+        changeArraySize(numItems);
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
+    }
+
+    @Test
+    public void testNonFocusableLoseInFastLayout() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        int[] items = new int[300];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 480;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+        int pressDown = 15;
+
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(0);
+        waitForScrollIdle(mVerifyLayout);
+
+        for (int i = 0; i < pressDown; i++) {
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        waitForScrollIdle(mVerifyLayout);
+        assertFalse(mGridView.isFocused());
+
+    }
+
+    @Test
+    public void testFocusableViewAvailable() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE,
+                new boolean[]{false, false, true, false, false});
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // RecyclerView does not respect focusable and focusableInTouchMode flag, so
+                // set flags in code.
+                mGridView.setFocusableInTouchMode(false);
+                mGridView.setFocusable(false);
+            }
+        });
+
+        assertFalse(mGridView.isFocused());
+
+        final boolean[] scrolled = new boolean[]{false};
+        mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy){
+                if (dy > 0) {
+                    scrolled[0] = true;
+                }
+            }
+        });
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(0, new int[]{200, 300, 500, 500, 200});
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+
+        assertFalse("GridView should not be scrolled", scrolled[0]);
+        assertTrue(mGridView.getLayoutManager().findViewByPosition(2).hasFocus());
+
+    }
+
+    @Test
+    public void testSetSelectionWithDelta() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(3);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        int top1 = mGridView.getLayoutManager().findViewByPosition(3).getTop();
+
+        humanDelay(1000);
+
+        // scroll to position with delta
+        setSelectedPosition(3, 100);
+        int top2 = mGridView.getLayoutManager().findViewByPosition(3).getTop();
+        assertEquals(top1 - 100, top2);
+
+        // scroll to same position without delta, it will be reset
+        setSelectedPosition(3, 0);
+        int top3 = mGridView.getLayoutManager().findViewByPosition(3).getTop();
+        assertEquals(top1, top3);
+
+        // scroll invisible item after last visible item
+        final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
+                .mGrid.getLastVisibleIndex();
+        setSelectedPosition(lastVisiblePos + 1, 100);
+        int top4 = mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1).getTop();
+        assertEquals(top1 - 100, top4);
+
+        // scroll invisible item before first visible item
+        final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
+                .mGrid.getFirstVisibleIndex();
+        setSelectedPosition(firstVisiblePos - 1, 100);
+        int top5 = mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1).getTop();
+        assertEquals(top1 - 100, top5);
+
+        // scroll to invisible item that is far away.
+        setSelectedPosition(50, 100);
+        int top6 = mGridView.getLayoutManager().findViewByPosition(50).getTop();
+        assertEquals(top1 - 100, top6);
+
+        // scroll to invisible item that is far away.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(100);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        int top7 = mGridView.getLayoutManager().findViewByPosition(100).getTop();
+        assertEquals(top1, top7);
+
+        // scroll to invisible item that is far away.
+        setSelectedPosition(10, 50);
+        int top8 = mGridView.getLayoutManager().findViewByPosition(10).getTop();
+        assertEquals(top1 - 50, top8);
+    }
+
+    @Test
+    public void testSetSelectionWithDeltaInGrid() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(10);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
+
+        humanDelay(500);
+
+        // scroll to position with delta
+        setSelectedPosition(20, 100);
+        int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
+        assertEquals(top1 - 100, top2);
+
+        // scroll to same position without delta, it will be reset
+        setSelectedPosition(20, 0);
+        int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
+        assertEquals(top1, top3);
+
+        // scroll invisible item after last visible item
+        final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
+                .mGrid.getLastVisibleIndex();
+        setSelectedPosition(lastVisiblePos + 1, 100);
+        int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1));
+        verifyMargin();
+        assertEquals(top1 - 100, top4);
+
+        // scroll invisible item before first visible item
+        final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
+                .mGrid.getFirstVisibleIndex();
+        setSelectedPosition(firstVisiblePos - 1, 100);
+        int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1));
+        assertEquals(top1 - 100, top5);
+
+        // scroll to invisible item that is far away.
+        setSelectedPosition(100, 100);
+        int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100));
+        assertEquals(top1 - 100, top6);
+
+        // scroll to invisible item that is far away.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(200);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        Thread.sleep(500);
+        int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200));
+        assertEquals(top1, top7);
+
+        // scroll to invisible item that is far away.
+        setSelectedPosition(10, 50);
+        int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
+        assertEquals(top1 - 50, top8);
+    }
+
+
+    @Test
+    public void testSetSelectionWithDeltaInGrid1() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
+                193,176,153,141,203,184,232,139,177,206,222,136,132,237,172,137,
+                188,172,163,213,158,219,209,147,133,229,170,197,138,215,188,205,
+                223,192,225,170,195,127,229,229,210,195,134,142,160,139,130,222,
+                150,163,180,176,157,137,234,169,159,167,182,150,224,231,202,236,
+                123,140,181,223,120,185,183,221,123,210,134,158,166,208,149,128,
+                192,214,212,198,133,140,158,133,229,173,226,141,180,128,127,218,
+                192,235,183,213,216,150,143,193,125,141,219,210,195,195,192,191,
+                212,236,157,189,160,220,147,158,220,199,233,231,201,180,168,141,
+                156,204,191,183,190,153,123,210,238,151,139,221,223,200,175,191,
+                132,184,197,204,236,157,230,151,195,219,212,143,172,149,219,184,
+                164,211,132,187,172,142,174,146,127,147,206,238,188,129,199,226,
+                132,220,210,159,235,153,208,182,196,123,180,159,131,135,175,226,
+                127,134,237,211,133,225,132,124,160,226,224,200,173,137,217,169,
+                182,183,176,185,122,168,195,159,172,129,126,129,166,136,149,220,
+                178,191,192,238,180,208,234,154,222,206,239,228,129,140,203,125,
+                214,175,125,169,196,132,234,138,192,142,234,190,215,232,239,122,
+                188,158,128,221,159,237,207,157,232,138,132,214,122,199,121,191,
+                199,209,126,164,175,187,173,186,194,224,191,196,146,208,213,210,
+                164,176,202,213,123,157,179,138,217,129,186,166,237,211,157,130,
+                137,132,171,232,216,239,180,151,137,132,190,133,218,155,171,227,
+                193,147,197,164,120,218,193,154,170,196,138,222,161,235,143,154,
+                192,178,228,195,178,133,203,178,173,206,178,212,136,157,169,124,
+                172,121,128,223,238,125,217,187,184,156,169,215,231,124,210,174,
+                146,226,185,134,223,228,183,182,136,133,199,146,180,233,226,225,
+                174,233,145,235,216,170,192,171,132,132,134,223,233,148,154,162,
+                192,179,197,203,139,197,174,187,135,132,180,136,192,195,124,221,
+                120,189,233,233,146,225,234,163,215,143,132,198,156,205,151,190,
+                204,239,221,229,123,138,134,217,219,136,218,215,167,139,195,125,
+                202,225,178,226,145,208,130,194,228,197,157,215,124,147,174,123,
+                237,140,172,181,161,151,229,216,199,199,179,213,146,122,222,162,
+                139,173,165,150,160,217,207,137,165,175,129,158,134,133,178,199,
+                215,213,122,197
+        });
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(10);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
+
+        humanDelay(500);
+
+        // scroll to position with delta
+        setSelectedPosition(20, 100);
+        int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
+        assertEquals(top1 - 100, top2);
+
+        // scroll to same position without delta, it will be reset
+        setSelectedPosition(20, 0);
+        int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
+        assertEquals(top1, top3);
+
+        // scroll invisible item after last visible item
+        final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
+                .mGrid.getLastVisibleIndex();
+        setSelectedPosition(lastVisiblePos + 1, 100);
+        int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1));
+        verifyMargin();
+        assertEquals(top1 - 100, top4);
+
+        // scroll invisible item before first visible item
+        final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
+                .mGrid.getFirstVisibleIndex();
+        setSelectedPosition(firstVisiblePos - 1, 100);
+        int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1));
+        assertEquals(top1 - 100, top5);
+
+        // scroll to invisible item that is far away.
+        setSelectedPosition(100, 100);
+        int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100));
+        assertEquals(top1 - 100, top6);
+
+        // scroll to invisible item that is far away.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(200);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        Thread.sleep(500);
+        int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200));
+        assertEquals(top1, top7);
+
+        // scroll to invisible item that is far away.
+        setSelectedPosition(10, 50);
+        int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
+        assertEquals(top1 - 50, top8);
+    }
+
+    @Test
+    public void testSmoothScrollSelectionEvents() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(30);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        humanDelay(500);
+
+        final ArrayList<Integer> selectedPositions = new ArrayList<Integer>();
+        mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+            @Override
+            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+                selectedPositions.add(position);
+            }
+        });
+
+        sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP);
+        humanDelay(500);
+        waitForScrollIdle(mVerifyLayout);
+        // should only get childselected event for item 0 once
+        assertTrue(selectedPositions.size() > 0);
+        assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue());
+        for (int i = selectedPositions.size() - 2; i >= 0; i--) {
+            assertFalse(0 == selectedPositions.get(i).intValue());
+        }
+
+    }
+
+    @Test
+    public void testSmoothScrollSelectionEventsLinear() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(10);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        humanDelay(500);
+
+        final ArrayList<Integer> selectedPositions = new ArrayList<Integer>();
+        mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+            @Override
+            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+                selectedPositions.add(position);
+            }
+        });
+
+        sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP);
+        humanDelay(500);
+        waitForScrollIdle(mVerifyLayout);
+        // should only get childselected event for item 0 once
+        assertTrue(selectedPositions.size() > 0);
+        assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue());
+        for (int i = selectedPositions.size() - 2; i >= 0; i--) {
+            assertFalse(0 == selectedPositions.get(i).intValue());
+        }
+
+    }
+
+    @Test
+    public void testScrollToNoneExisting() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 3;
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(99);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        humanDelay(500);
+
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(50);
+            }
+        });
+        Thread.sleep(100);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestLayout();
+                mGridView.setSelectedPositionSmooth(0);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        humanDelay(500);
+
+    }
+
+    @Test
+    public void testSmoothscrollerInterrupted() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 680;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(0);
+        waitForScrollIdle(mVerifyLayout);
+        assertTrue(mGridView.getChildAt(0).hasFocus());
+
+        // Pressing lots of key to make sure smooth scroller is running
+        for (int i = 0; i < 20; i++) {
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+        while (mGridView.getLayoutManager().isSmoothScrolling()
+                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
+            // Repeatedly pressing to make sure pending keys does not drop to zero.
+            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        }
+    }
+
+    @Test
+    public void testSmoothscrollerCancelled() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 680;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(0);
+        waitForScrollIdle(mVerifyLayout);
+        assertTrue(mGridView.getChildAt(0).hasFocus());
+
+        int targetPosition = items.length - 1;
+        mGridView.setSelectedPositionSmooth(targetPosition);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.stopScroll();
+            }
+        });
+        waitForScrollIdle();
+        waitForItemAnimation();
+        assertEquals(mGridView.getSelectedPosition(), targetPosition);
+        assertSame(mGridView.getLayoutManager().findViewByPosition(targetPosition),
+                mGridView.findFocus());
+    }
+
+    @Test
+    public void testSetNumRowsAndAddItem() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[2];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mGridView.setSelectedPositionSmooth(0);
+        waitForScrollIdle(mVerifyLayout);
+
+        mActivity.addItems(items.length, new int[]{300});
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ((VerticalGridView) mGridView).setNumColumns(2);
+            }
+        });
+        Thread.sleep(1000);
+        assertTrue(mGridView.getChildAt(2).getLeft() != mGridView.getChildAt(1).getLeft());
+    }
+
+
+    @Test
+    public void testRequestLayoutBugInLayout() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(1);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        waitForScrollIdle(mVerifyLayout);
+
+        assertEquals("Line 2", ((TextView) mGridView.findFocus()).getText().toString());
+    }
+
+
+    @Test
+    public void testChangeLayoutInChild() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_wrap_content);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
+        int[] items = new int[2];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(0);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        verifyMargin();
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(1);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        verifyMargin();
+    }
+
+    @Test
+    public void testWrapContent() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_grid_wrap);
+        int[] items = new int[200];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.attachToNewAdapter(new int[0]);
+            }
+        });
+
+    }
+
+    @Test
+    public void testZeroFixedSecondarySize() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_measured_with_zero);
+        intent.putExtra(GridActivity.EXTRA_SECONDARY_SIZE_ZERO, true);
+        int[] items = new int[2];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 0;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+    }
+
+    @Test
+    public void testChildStates() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 200;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+        mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD);
+
+        final SparseArray<Parcelable> container = new SparseArray<Parcelable>();
+
+        // 1 Save view states
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
+                        .getText()), 0, 1);
+                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1))
+                        .getText()), 0, 1);
+                mGridView.saveHierarchyState(container);
+            }
+        });
+
+        // 2 Change view states
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
+                        .getText()), 1, 2);
+                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1))
+                        .getText()), 1, 2);
+            }
+        });
+
+        // 3 Detached and re-attached,  should still maintain state of (2)
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(1);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
+        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
+        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
+        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2);
+
+        // 4 Recycled and rebound, should load state from (2)
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(20);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPositionSmooth(0);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
+        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
+        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
+        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2);
+    }
+
+
+    @Test
+    public void testNoDispatchSaveChildState() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 200;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+        mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_NO_CHILD);
+
+        final SparseArray<Parcelable> container = new SparseArray<Parcelable>();
+
+        // 1. Set text selection, save view states should do nothing on child
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mGridView.getChildCount(); i++) {
+                    Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(i))
+                            .getText()), 0, 1);
+                }
+                mGridView.saveHierarchyState(container);
+            }
+        });
+
+        // 2. clear the text selection
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mGridView.getChildCount(); i++) {
+                    Selection.removeSelection((Spannable)(((TextView) mGridView.getChildAt(i))
+                            .getText()));
+                }
+            }
+        });
+
+        // 3. Restore view states should be a no-op for child
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.restoreHierarchyState(container);
+                for (int i = 0; i < mGridView.getChildCount(); i++) {
+                    assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionStart());
+                    assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionEnd());
+                }
+            }
+        });
+    }
+
+
+    static interface ViewTypeProvider {
+        public int getViewType(int position);
+    }
+
+    static interface ItemAlignmentFacetProvider {
+        public ItemAlignmentFacet getItemAlignmentFacet(int viewType);
+    }
+
+    static class TwoViewTypesProvider implements ViewTypeProvider {
+        static int VIEW_TYPE_FIRST = 1;
+        static int VIEW_TYPE_DEFAULT = 0;
+        @Override
+        public int getViewType(int position) {
+            if (position == 0) {
+                return VIEW_TYPE_FIRST;
+            } else {
+                return VIEW_TYPE_DEFAULT;
+            }
+        }
+    }
+
+    static class ChangeableViewTypesProvider implements ViewTypeProvider {
+        static SparseIntArray sViewTypes = new SparseIntArray();
+        @Override
+        public int getViewType(int position) {
+            return sViewTypes.get(position);
+        }
+        public static void clear() {
+            sViewTypes.clear();
+        }
+        public static void setViewType(int position, int type) {
+            sViewTypes.put(position, type);
+        }
+    }
+
+    static class PositionItemAlignmentFacetProviderForRelativeLayout1
+            implements ItemAlignmentFacetProvider {
+        ItemAlignmentFacet mMultipleFacet;
+
+        PositionItemAlignmentFacetProviderForRelativeLayout1() {
+            mMultipleFacet = new ItemAlignmentFacet();
+            ItemAlignmentFacet.ItemAlignmentDef[] defs =
+                    new ItemAlignmentFacet.ItemAlignmentDef[2];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t1);
+            defs[1] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[1].setItemAlignmentViewId(R.id.t2);
+            defs[1].setItemAlignmentOffsetPercent(100);
+            defs[1].setItemAlignmentOffset(-10);
+            mMultipleFacet.setAlignmentDefs(defs);
+        }
+
+        @Override
+        public ItemAlignmentFacet getItemAlignmentFacet(int position) {
+            if (position == 0) {
+                return mMultipleFacet;
+            } else {
+                return null;
+            }
+        }
+    }
+
+    @Test
+    public void testMultipleScrollPosition1() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                TwoViewTypesProvider.class.getName());
+        // Set ItemAlignment for each ViewHolder and view type,  ViewHolder should
+        // override the view type settings.
+        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
+                PositionItemAlignmentFacetProviderForRelativeLayout1.class.getName());
+        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS,
+                ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName());
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top",
+                mGridView.getPaddingTop(), mGridView.getChildAt(0).getTop());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        waitForScrollIdle(mVerifyLayout);
+
+        final View v = mGridView.getChildAt(0);
+        View t1 = v.findViewById(R.id.t1);
+        int t1align = (t1.getTop() + t1.getBottom()) / 2;
+        View t2 = v.findViewById(R.id.t2);
+        int t2align = t2.getBottom() - 10;
+        assertEquals("Expected alignment for 2nd textview",
+                mGridView.getPaddingTop() - (t2align - t1align),
+                v.getTop());
+    }
+
+    static class PositionItemAlignmentFacetProviderForRelativeLayout2 implements
+            ItemAlignmentFacetProvider {
+        ItemAlignmentFacet mMultipleFacet;
+
+        PositionItemAlignmentFacetProviderForRelativeLayout2() {
+            mMultipleFacet = new ItemAlignmentFacet();
+            ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t1);
+            defs[0].setItemAlignmentOffsetPercent(0);
+            defs[1] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[1].setItemAlignmentViewId(R.id.t2);
+            defs[1].setItemAlignmentOffsetPercent(ItemAlignmentFacet.ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+            defs[1].setItemAlignmentOffset(-10);
+            mMultipleFacet.setAlignmentDefs(defs);
+        }
+
+        @Override
+        public ItemAlignmentFacet getItemAlignmentFacet(int position) {
+            if (position == 0) {
+                return mMultipleFacet;
+            } else {
+                return null;
+            }
+        }
+    }
+
+    @Test
+    public void testMultipleScrollPosition2() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                TwoViewTypesProvider.class.getName());
+        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
+                PositionItemAlignmentFacetProviderForRelativeLayout2.class.getName());
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        waitForScrollIdle(mVerifyLayout);
+
+        final View v = mGridView.getChildAt(0);
+        View t1 = v.findViewById(R.id.t1);
+        int t1align = t1.getTop();
+        View t2 = v.findViewById(R.id.t2);
+        int t2align = t2.getTop() - 10;
+        assertEquals("Expected alignment for 2nd textview",
+                mGridView.getPaddingTop() - (t2align - t1align), v.getTop());
+    }
+
+    static class ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2 implements
+            ItemAlignmentFacetProvider {
+        ItemAlignmentFacet mMultipleFacet;
+
+        ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2() {
+            mMultipleFacet = new ItemAlignmentFacet();
+            ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t1);
+            defs[0].setItemAlignmentOffsetPercent(0);
+            defs[1] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[1].setItemAlignmentViewId(R.id.t2);
+            defs[1].setItemAlignmentOffsetPercent(100);
+            defs[1].setItemAlignmentOffset(-10);
+            mMultipleFacet.setAlignmentDefs(defs);
+        }
+
+        @Override
+        public ItemAlignmentFacet getItemAlignmentFacet(int viewType) {
+            if (viewType == TwoViewTypesProvider.VIEW_TYPE_FIRST) {
+                return mMultipleFacet;
+            } else {
+                return null;
+            }
+        }
+    }
+
+    @Test
+    public void testMultipleScrollPosition3() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                TwoViewTypesProvider.class.getName());
+        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS,
+                ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName());
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        waitForScrollIdle(mVerifyLayout);
+
+        final View v = mGridView.getChildAt(0);
+        View t1 = v.findViewById(R.id.t1);
+        int t1align = t1.getTop();
+        View t2 = v.findViewById(R.id.t2);
+        int t2align = t2.getBottom() - 10;
+        assertEquals("Expected alignment for 2nd textview",
+                mGridView.getPaddingTop() - (t2align - t1align), v.getTop());
+    }
+
+    @Test
+    public void testSelectionAndAddItemInOneCycle() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(0, new int[]{300, 300});
+                mGridView.setSelectedPosition(0);
+            }
+        });
+        assertEquals(0, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testSelectViewTaskSmoothWithAdapterChange() throws Throwable {
+        testSelectViewTaskWithAdapterChange(true /*smooth*/);
+    }
+
+    @Test
+    public void testSelectViewTaskWithAdapterChange() throws Throwable {
+        testSelectViewTaskWithAdapterChange(false /*smooth*/);
+    }
+
+    private void testSelectViewTaskWithAdapterChange(final boolean smooth) throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final View firstView = mGridView.getLayoutManager().findViewByPosition(0);
+        final View[] selectedViewByTask = new View[1];
+        final ViewHolderTask task = new ViewHolderTask() {
+            @Override
+            public void run(RecyclerView.ViewHolder viewHolder) {
+                selectedViewByTask[0] = viewHolder.itemView;
+            }
+        };
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(0, 1);
+                if (smooth) {
+                    mGridView.setSelectedPositionSmooth(0, task);
+                } else {
+                    mGridView.setSelectedPosition(0, task);
+                }
+            }
+        });
+        assertEquals(0, mGridView.getSelectedPosition());
+        assertNotNull(selectedViewByTask[0]);
+        assertNotSame(firstView, selectedViewByTask[0]);
+        assertSame(mGridView.getLayoutManager().findViewByPosition(0), selectedViewByTask[0]);
+    }
+
+    @Test
+    public void testNotifyItemTypeChangedSelectionEvent() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                ChangeableViewTypesProvider.class.getName());
+        ChangeableViewTypesProvider.clear();
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final ArrayList<Integer> selectedLog = new ArrayList<Integer>();
+        mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
+            @Override
+            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
+                selectedLog.add(position);
+            }
+        });
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                ChangeableViewTypesProvider.setViewType(0, 1);
+                mGridView.getAdapter().notifyItemChanged(0, 1);
+            }
+        });
+        assertEquals(0, mGridView.getSelectedPosition());
+        assertEquals(selectedLog.size(), 1);
+        assertEquals((int) selectedLog.get(0), 0);
+    }
+
+    @Test
+    public void testNotifyItemChangedSelectionEvent() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        OnChildViewHolderSelectedListener listener =
+                Mockito.mock(OnChildViewHolderSelectedListener.class);
+        mGridView.setOnChildViewHolderSelectedListener(listener);
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getAdapter().notifyItemChanged(0, 1);
+            }
+        });
+        Mockito.verify(listener, times(1)).onChildViewHolderSelected(any(RecyclerView.class),
+                any(RecyclerView.ViewHolder.class), anyInt(), anyInt());
+        assertEquals(0, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.addItems(0, new int[]{300, 300});
+                mGridView.setSelectedPositionSmooth(0);
+            }
+        });
+        assertEquals(0, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testExtraLayoutSpace() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+
+        final int windowSize = mGridView.getHeight();
+        final int extraLayoutSize = windowSize;
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        // add extra layout space
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setExtraLayoutSpace(extraLayoutSize);
+            }
+        });
+        waitForLayout();
+        View v;
+        v = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        assertTrue(v.getTop() < windowSize + extraLayoutSize);
+        assertTrue(v.getBottom() >= windowSize + extraLayoutSize - mGridView.getVerticalMargin());
+
+        mGridView.setSelectedPositionSmooth(150);
+        waitForScrollIdle(mVerifyLayout);
+        v = mGridView.getChildAt(0);
+        assertTrue(v.getBottom() > - extraLayoutSize);
+        assertTrue(v.getTop() <= -extraLayoutSize + mGridView.getVerticalMargin());
+
+        // clear extra layout space
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setExtraLayoutSpace(0);
+                verifyMargin();
+            }
+        });
+        Thread.sleep(50);
+        v = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        assertTrue(v.getTop() < windowSize);
+        assertTrue(v.getBottom() >= windowSize - mGridView.getVerticalMargin());
+    }
+
+    @Test
+    public void testFocusFinder() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 3);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        // test focus from button to vertical grid view
+        final View button = mActivity.findViewById(R.id.button);
+        assertTrue(button.isFocused());
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertFalse(mGridView.isFocused());
+        assertTrue(mGridView.hasFocus());
+
+        // FocusFinder should find last focused(2nd) item on DPAD_DOWN
+        final View secondChild = mGridView.getChildAt(1);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                secondChild.requestFocus();
+                button.requestFocus();
+            }
+        });
+        assertTrue(button.isFocused());
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue(secondChild.isFocused());
+
+        // Bug 26918143 Even VerticalGridView is not focusable, FocusFinder should find last focused
+        // (2nd) item on DPAD_DOWN.
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                button.requestFocus();
+            }
+        });
+        mGridView.setFocusable(false);
+        mGridView.setFocusableInTouchMode(false);
+        assertTrue(button.isFocused());
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        assertTrue(secondChild.isFocused());
+    }
+
+    @Test
+    public void testRestoreIndexAndAddItems() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 4);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        assertEquals(mGridView.getSelectedPosition(), 0);
+        final SparseArray<Parcelable> states = new SparseArray<>();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.saveHierarchyState(states);
+                mGridView.setAdapter(null);
+            }
+
+        });
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.restoreHierarchyState(states);
+                mActivity.attachToNewAdapter(new int[0]);
+                mActivity.addItems(0, new int[]{100, 100, 100, 100});
+            }
+
+        });
+        assertEquals(mGridView.getSelectedPosition(), 0);
+    }
+
+    @Test
+    public void testRestoreIndexAndAddItemsSelect1() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 4);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPosition(1);
+            }
+
+        });
+        assertEquals(mGridView.getSelectedPosition(), 1);
+        final SparseArray<Parcelable> states = new SparseArray<>();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.saveHierarchyState(states);
+                mGridView.setAdapter(null);
+            }
+
+        });
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.restoreHierarchyState(states);
+                mActivity.attachToNewAdapter(new int[0]);
+                mActivity.addItems(0, new int[]{100, 100, 100, 100});
+            }
+
+        });
+        assertEquals(mGridView.getSelectedPosition(), 1);
+    }
+
+    @Test
+    public void testRestoreStateAfterAdapterChange() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view);
+        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{50, 50, 50, 50});
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setSelectedPosition(1);
+                mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD);
+            }
+
+        });
+        assertEquals(mGridView.getSelectedPosition(), 1);
+        final SparseArray<Parcelable> states = new SparseArray<>();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Selection.setSelection((Spannable) (((TextView) mGridView.getChildAt(0))
+                        .getText()), 1, 2);
+                Selection.setSelection((Spannable) (((TextView) mGridView.getChildAt(1))
+                        .getText()), 0, 1);
+                mGridView.saveHierarchyState(states);
+                mGridView.setAdapter(null);
+            }
+
+        });
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.restoreHierarchyState(states);
+                mActivity.attachToNewAdapter(new int[]{50, 50, 50, 50});
+            }
+
+        });
+        assertEquals(mGridView.getSelectedPosition(), 1);
+        assertEquals(1, ((TextView) mGridView.getChildAt(0)).getSelectionStart());
+        assertEquals(2, ((TextView) mGridView.getChildAt(0)).getSelectionEnd());
+        assertEquals(0, ((TextView) mGridView.getChildAt(1)).getSelectionStart());
+        assertEquals(1, ((TextView) mGridView.getChildAt(1)).getSelectionEnd());
+    }
+
+    @Test
+    public void test27766012() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        // set remove animator two seconds
+        mGridView.getItemAnimator().setRemoveDuration(2000);
+        final View view = mGridView.getChildAt(1);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                view.requestFocus();
+            }
+        });
+        assertTrue(view.hasFocus());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(0, 2);
+            }
+
+        });
+        // wait one second, removing second view is still attached to parent
+        Thread.sleep(1000);
+        assertSame(view.getParent(), mGridView);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // refocus to the removed item and do a focus search.
+                view.requestFocus();
+                view.focusSearch(View.FOCUS_UP);
+            }
+
+        });
+    }
+
+    @Test
+    public void testBug27258366() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        // move item1 500 pixels right, when focus is on item1, default focus finder will pick
+        // item0 and item2 for the best match of focusSearch(FOCUS_LEFT).  The grid widget
+        // must override default addFocusables(), not to add item0 or item2.
+        mActivity.mAdapterListener = new GridActivity.AdapterListener() {
+            @Override
+            public void onBind(RecyclerView.ViewHolder vh, int position) {
+                if (position == 1) {
+                    vh.itemView.setPaddingRelative(500, 0, 0, 0);
+                } else {
+                    vh.itemView.setPaddingRelative(0, 0, 0, 0);
+                }
+            }
+        };
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getAdapter().notifyDataSetChanged();
+            }
+        });
+        Thread.sleep(100);
+
+        final ViewGroup secondChild = (ViewGroup) mGridView.getChildAt(1);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                secondChild.requestFocus();
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        Thread.sleep(100);
+        final View button = mActivity.findViewById(R.id.button);
+        assertTrue(button.isFocused());
+    }
+
+    @Test
+    public void testUpdateHeightScrollHorizontal() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, true);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int childTop = mGridView.getChildAt(0).getTop();
+        // scroll to end, all children's top should not change.
+        scrollToEnd(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mGridView.getChildCount(); i++) {
+                    assertEquals(childTop, mGridView.getChildAt(i).getTop());
+                }
+            }
+        });
+        // sanity check last child has focus with a larger height.
+        assertTrue(mGridView.getChildAt(0).getHeight()
+                < mGridView.getChildAt(mGridView.getChildCount() - 1).getHeight());
+    }
+
+    @Test
+    public void testUpdateWidthScrollHorizontal() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, true);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int childTop = mGridView.getChildAt(0).getTop();
+        // scroll to end, all children's top should not change.
+        scrollToEnd(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mGridView.getChildCount(); i++) {
+                    assertEquals(childTop, mGridView.getChildAt(i).getTop());
+                }
+            }
+        });
+        // sanity check last child has focus with a larger width.
+        assertTrue(mGridView.getChildAt(0).getWidth()
+                < mGridView.getChildAt(mGridView.getChildCount() - 1).getWidth());
+        if (mGridView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+            assertEquals(mGridView.getPaddingLeft(),
+                    mGridView.getChildAt(mGridView.getChildCount() - 1).getLeft());
+        } else {
+            assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(),
+                    mGridView.getChildAt(mGridView.getChildCount() - 1).getRight());
+        }
+    }
+
+    @Test
+    public void testUpdateWidthScrollHorizontalRtl() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear_rtl);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, true);
+        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        final int childTop = mGridView.getChildAt(0).getTop();
+        // scroll to end, all children's top should not change.
+        scrollToEnd(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < mGridView.getChildCount(); i++) {
+                    assertEquals(childTop, mGridView.getChildAt(i).getTop());
+                }
+            }
+        });
+        // sanity check last child has focus with a larger width.
+        assertTrue(mGridView.getChildAt(0).getWidth()
+                < mGridView.getChildAt(mGridView.getChildCount() - 1).getWidth());
+        assertEquals(mGridView.getPaddingLeft(),
+                mGridView.getChildAt(mGridView.getChildCount() - 1).getLeft());
+    }
+
+    @Test
+    public void testAccessibility() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        assertTrue(0 == mGridView.getSelectedPosition());
+
+        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        assertTrue("test sanity", info.isScrollable());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.performAccessibilityAction(mGridView,
+                        AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        int selectedPosition1 = mGridView.getSelectedPosition();
+        assertTrue(0 < selectedPosition1);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        assertTrue("test sanity", info.isScrollable());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.performAccessibilityAction(mGridView,
+                        AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        int selectedPosition2 = mGridView.getSelectedPosition();
+        assertTrue(selectedPosition2 < selectedPosition1);
+    }
+
+    @Test
+    public void testAccessibilityScrollForwardHalfVisible() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom);
+        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        int height = mGridView.getHeight() - mGridView.getPaddingTop()
+                - mGridView.getPaddingBottom();
+        final int childHeight = height - mGridView.getVerticalSpacing() - 100;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffset(100);
+                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
+                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+                mGridView.setItemAlignmentOffset(0);
+                mGridView.setItemAlignmentOffsetPercent(BaseGridView
+                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+            }
+        });
+        mActivity.addItems(0, new int[]{childHeight, childHeight});
+        waitForItemAnimation();
+        setSelectedPosition(0);
+
+        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        assertTrue("test sanity", info.isScrollable());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.performAccessibilityAction(mGridView,
+                        AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(1, mGridView.getSelectedPosition());
+    }
+
+    private boolean hasAction(AccessibilityNodeInfoCompat info, Object action) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            AccessibilityNodeInfoCompat.AccessibilityActionCompat convertedAction =
+                    (AccessibilityNodeInfoCompat.AccessibilityActionCompat) action;
+            return ((info.getActions() & convertedAction.getId()) != 0);
+        } else {
+            int convertedAction = (int) action;
+            return ((info.getActions() & convertedAction) != 0);
+        }
+    }
+
+    private void setUpActivityForScrollingTest(final boolean isRTL, boolean isHorizontal,
+            int numChildViews, boolean isSiblingViewVisible) throws Throwable {
+        Intent intent = new Intent();
+        int layout;
+        if (isHorizontal) {
+            layout = isRTL ? R.layout.horizontal_linear_rtl : R.layout.horizontal_linear;
+        } else {
+            layout = R.layout.vertical_linear;
+        }
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, layout);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom);
+        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = isHorizontal ? BaseGridView.HORIZONTAL : BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        final int offset = (isSiblingViewVisible ? 2 : 1) * (isHorizontal
+                ? mGridView.getHorizontalSpacing() : mGridView.getVerticalSpacing());
+        final int childSize = (isHorizontal ? mGridView.getWidth() : mGridView.getHeight())
+                - offset - (isHorizontal ? 2 * mGridView.getHorizontalSpacing() :
+                mGridView.getVerticalSpacing());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (isRTL) {
+                    mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+                }
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffset(offset);
+                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
+                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+                mGridView.setItemAlignmentOffset(0);
+                mGridView.setItemAlignmentOffsetPercent(BaseGridView
+                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+            }
+        });
+        int[] widthArrays = new int[numChildViews];
+        Arrays.fill(widthArrays, childSize);
+        mActivity.addItems(0, widthArrays);
+    }
+
+    private void testScrollingAction(boolean isRTL, boolean isHorizontal) throws Throwable {
+        waitForItemAnimation();
+        setSelectedPosition(1);
+        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        // We are currently focusing on item 1, calculating the direction to get me to item 0
+        final AccessibilityNodeInfoCompat.AccessibilityActionCompat itemZeroDirection;
+        if (isHorizontal) {
+            itemZeroDirection = isRTL
+                    ? AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT :
+                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT;
+        } else {
+            itemZeroDirection =
+                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP;
+        }
+        final int translatedItemZeroDirection = AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
+
+        assertTrue("test sanity", info.isScrollable());
+        if (Build.VERSION.SDK_INT >= 23) {
+            assertTrue("test sanity", hasAction(info, itemZeroDirection));
+        } else {
+            assertTrue("test sanity", hasAction(info, translatedItemZeroDirection));
+        }
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (Build.VERSION.SDK_INT >= 23) {
+                    delegateCompat.performAccessibilityAction(mGridView, itemZeroDirection.getId(),
+                            null);
+                } else {
+                    delegateCompat.performAccessibilityAction(mGridView,
+                            translatedItemZeroDirection, null);
+                }
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(0, mGridView.getSelectedPosition());
+        setSelectedPosition(0);
+        // We are at item 0, calculate the direction that lead us to the item 1
+        final AccessibilityNodeInfoCompat.AccessibilityActionCompat itemOneDirection;
+        if (isHorizontal) {
+            itemOneDirection = isRTL
+                    ? AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT
+                    : AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT;
+        } else {
+            itemOneDirection =
+                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN;
+        }
+        final int translatedItemOneDirection = AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        if (Build.VERSION.SDK_INT >= 23) {
+            assertTrue("test sanity", hasAction(info, itemOneDirection));
+        } else {
+            assertTrue("test sanity", hasAction(info, translatedItemOneDirection));
+        }
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (Build.VERSION.SDK_INT >= 23) {
+                    delegateCompat.performAccessibilityAction(mGridView, itemOneDirection.getId(),
+                            null);
+                } else {
+                    delegateCompat.performAccessibilityAction(mGridView, translatedItemOneDirection,
+                            null);
+                }
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(1, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testAccessibilityRespondToLeftRightInvisible() throws Throwable {
+        boolean isRTL = false;
+        boolean isHorizontal = true;
+        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
+                false /* next child partially visible */);
+        testScrollingAction(isRTL, isHorizontal);
+    }
+
+    @Test
+    public void testAccessibilityRespondToLeftRightPartiallyVisible() throws Throwable {
+        boolean isRTL = false;
+        boolean isHorizontal = true;
+        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
+                true /* next child partially visible */);
+        testScrollingAction(isRTL, isHorizontal);
+    }
+
+    @Test
+    public void testAccessibilityRespondToLeftRightRtlInvisible()
+            throws Throwable {
+        boolean isRTL = true;
+        boolean isHorizontal = true;
+        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
+                false /* next child partially visible */);
+        testScrollingAction(isRTL, isHorizontal);
+    }
+
+    @Test
+    public void testAccessibilityRespondToLeftRightRtlPartiallyVisible() throws Throwable {
+        boolean isRTL = true;
+        boolean isHorizontal = true;
+        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
+                true /* next child partially visible */);
+        testScrollingAction(isRTL, isHorizontal);
+    }
+
+    @Test
+    public void testAccessibilityRespondToScrollUpDownActionInvisible() throws Throwable {
+        boolean isRTL = false;
+        boolean isHorizontal = false;
+        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
+                false /* next child partially visible */);
+        testScrollingAction(isRTL, isHorizontal);
+    }
+
+    @Test
+    public void testAccessibilityRespondToScrollUpDownActionPartiallyVisible() throws Throwable {
+        boolean isRTL = false;
+        boolean isHorizontal = false;
+        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
+                true /* next child partially visible */);
+        testScrollingAction(isRTL, isHorizontal);
+    }
+
+    @Test
+    public void testAccessibilityScrollBackwardHalfVisible() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_top);
+        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        initActivity(intent);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        int height = mGridView.getHeight() - mGridView.getPaddingTop()
+                - mGridView.getPaddingBottom();
+        final int childHeight = height - mGridView.getVerticalSpacing() - 100;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffset(100);
+                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
+                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+                mGridView.setItemAlignmentOffset(0);
+                mGridView.setItemAlignmentOffsetPercent(BaseGridView
+                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+            }
+        });
+        mActivity.addItems(0, new int[]{childHeight, childHeight});
+        waitForItemAnimation();
+        setSelectedPosition(1);
+
+        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
+            }
+        });
+        assertTrue("test sanity", info.isScrollable());
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.performAccessibilityAction(mGridView,
+                        AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertEquals(0, mGridView.getSelectedPosition());
+    }
+
+    void slideInAndWaitIdle() throws Throwable {
+        slideInAndWaitIdle(5000);
+    }
+
+    void slideInAndWaitIdle(long timeout) throws Throwable {
+        // animateIn() would reset position
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateIn();
+            }
+        });
+        PollingCheck.waitFor(timeout, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return !mGridView.getLayoutManager().isSmoothScrolling()
+                        && mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+    }
+
+    @Test
+    public void testAnimateOutBlockScrollTo() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateOut();
+            }
+        });
+        // wait until sliding out.
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
+            }
+        });
+        // scrollToPosition() should not affect slideOut status
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.scrollToPosition(0);
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
+                >= mGridView.getHeight());
+
+        slideInAndWaitIdle();
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+    }
+
+    @Test
+    public void testAnimateOutBlockSmoothScrolling() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        int[] items = new int[30];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateOut();
+            }
+        });
+        // wait until sliding out.
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
+            }
+        });
+        // smoothScrollToPosition() should not affect slideOut status
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.smoothScrollToPosition(29);
+            }
+        });
+        PollingCheck.waitFor(10000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
+                >= mGridView.getHeight());
+
+        slideInAndWaitIdle();
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        assertSame("Scrolled to last child",
+                mGridView.findViewHolderForAdapterPosition(29).itemView, lastChild);
+    }
+
+    @Test
+    public void testAnimateOutBlockLongScrollTo() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        int[] items = new int[30];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateOut();
+            }
+        });
+        // wait until sliding out.
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
+            }
+        });
+        // smoothScrollToPosition() should not affect slideOut status
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.scrollToPosition(29);
+            }
+        });
+        PollingCheck.waitFor(10000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
+                >= mGridView.getHeight());
+
+        slideInAndWaitIdle();
+        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+        assertSame("Scrolled to last child",
+                mGridView.findViewHolderForAdapterPosition(29).itemView, lastChild);
+    }
+
+    @Test
+    public void testAnimateOutBlockLayout() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateOut();
+            }
+        });
+        // wait until sliding out.
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
+            }
+        });
+        // change adapter should not affect slideOut status
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.changeItem(0, 200);
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
+                >= mGridView.getHeight());
+        assertEquals("onLayout suppressed during slide out", 300,
+                mGridView.getChildAt(0).getHeight());
+
+        slideInAndWaitIdle();
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+        // size of item should be updated immediately after slide in animation finishes:
+        PollingCheck.waitFor(1000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return 200 == mGridView.getChildAt(0).getHeight();
+            }
+        });
+    }
+
+    @Test
+    public void testAnimateOutBlockFocusChange() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateOut();
+                mActivity.findViewById(R.id.button).requestFocus();
+            }
+        });
+        assertTrue(mActivity.findViewById(R.id.button).hasFocus());
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.requestFocus();
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
+                >= mGridView.getHeight());
+
+        slideInAndWaitIdle();
+        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
+                mGridView.getChildAt(0).getTop());
+    }
+
+    @Test
+    public void testHorizontalAnimateOutBlockScrollTo() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding left", mGridView.getPaddingLeft(),
+                mGridView.getChildAt(0).getLeft());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateOut();
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getChildAt(0).getLeft() > mGridView.getPaddingLeft();
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.scrollToPosition(0);
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+
+        assertTrue("First view is slided out", mGridView.getChildAt(0).getLeft()
+                > mGridView.getWidth());
+
+        slideInAndWaitIdle();
+        assertEquals("First view is aligned with padding left", mGridView.getPaddingLeft(),
+                mGridView.getChildAt(0).getLeft());
+
+    }
+
+    @Test
+    public void testHorizontalAnimateOutRtl() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.horizontal_linear_rtl);
+        int[] items = new int[100];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        assertEquals("First view is aligned with padding right",
+                mGridView.getWidth() - mGridView.getPaddingRight(),
+                mGridView.getChildAt(0).getRight());
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.animateOut();
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getChildAt(0).getRight()
+                        < mGridView.getWidth() - mGridView.getPaddingRight();
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.smoothScrollToPosition(0);
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
+            }
+        });
+
+        assertTrue("First view is slided out", mGridView.getChildAt(0).getRight() < 0);
+
+        slideInAndWaitIdle();
+        assertEquals("First view is aligned with padding right",
+                mGridView.getWidth() - mGridView.getPaddingRight(),
+                mGridView.getChildAt(0).getRight());
+    }
+
+    @Test
+    public void testSmoothScrollerOutRange() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
+                R.layout.vertical_linear_with_button_onleft);
+        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
+        int[] items = new int[30];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 680;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        final View button = mActivity.findViewById(R.id.button);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            public void run() {
+                button.requestFocus();
+            }
+        });
+
+        mGridView.setSelectedPositionSmooth(0);
+        waitForScrollIdle(mVerifyLayout);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            public void run() {
+                mGridView.setSelectedPositionSmooth(120);
+            }
+        });
+        waitForScrollIdle(mVerifyLayout);
+        assertTrue(button.hasFocus());
+        int key;
+        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
+            key = KeyEvent.KEYCODE_DPAD_LEFT;
+        } else {
+            key = KeyEvent.KEYCODE_DPAD_RIGHT;
+        }
+        sendKey(key);
+        // the GridView should has focus in its children
+        assertTrue(mGridView.hasFocus());
+        assertFalse(mGridView.isFocused());
+        assertEquals(29, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testRemoveLastItemWithStableId() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, true);
+        int[] items = new int[1];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 680;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setRemoveDuration(2000);
+                mActivity.removeItems(0, 1, false);
+                mGridView.getAdapter().notifyDataSetChanged();
+            }
+        });
+        Thread.sleep(500);
+        assertEquals(-1, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testUpdateAndSelect1() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getAdapter().notifyDataSetChanged();
+                mGridView.setSelectedPosition(1);
+            }
+        });
+        waitOneUiCycle();
+        assertEquals(1, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testUpdateAndSelect2() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getAdapter().notifyDataSetChanged();
+                mGridView.setSelectedPosition(50);
+            }
+        });
+        waitOneUiCycle();
+        assertEquals(50, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testUpdateAndSelect3() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                int[] newItems = new int[100];
+                for (int i = 0; i < newItems.length; i++) {
+                    newItems[i] = mActivity.mItemLengths[0];
+                }
+                mActivity.addItems(0, newItems, false);
+                mGridView.getAdapter().notifyDataSetChanged();
+                mGridView.setSelectedPosition(50);
+            }
+        });
+        waitOneUiCycle();
+        assertEquals(50, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testFocusedPositonAfterRemoved1() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        final int[] items = new int[2];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+        setSelectedPosition(1);
+        assertEquals(1, mGridView.getSelectedPosition());
+
+        final int[] newItems = new int[3];
+        for (int i = 0; i < newItems.length; i++) {
+            newItems[i] = 300;
+        }
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(0, 2, true);
+                mActivity.addItems(0, newItems, true);
+            }
+        });
+        assertEquals(0, mGridView.getSelectedPosition());
+    }
+
+    @Test
+    public void testFocusedPositonAfterRemoved2() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        final int[] items = new int[2];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+        setSelectedPosition(1);
+        assertEquals(1, mGridView.getSelectedPosition());
+
+        final int[] newItems = new int[3];
+        for (int i = 0; i < newItems.length; i++) {
+            newItems[i] = 300;
+        }
+        performAndWaitForAnimation(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.removeItems(1, 1, true);
+                mActivity.addItems(1, newItems, true);
+            }
+        });
+        assertEquals(1, mGridView.getSelectedPosition());
+    }
+
+    static void assertNoCollectionItemInfo(AccessibilityNodeInfoCompat info) {
+        AccessibilityNodeInfoCompat.CollectionItemInfoCompat nodeInfoCompat =
+                info.getCollectionItemInfo();
+        if (nodeInfoCompat == null) {
+            return;
+        }
+        assertTrue(nodeInfoCompat.getRowIndex() < 0);
+        assertTrue(nodeInfoCompat.getColumnIndex() < 0);
+    }
+
+    /**
+     * This test would need talkback on.
+     */
+    @Test
+    public void testAccessibilityOfItemsBeingPushedOut() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        final int lastPos = mGridView.getChildAdapterPosition(
+                mGridView.getChildAt(mGridView.getChildCount() - 1));
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getLayoutManager().setItemPrefetchEnabled(false);
+            }
+        });
+        final int numItemsToPushOut = mNumRows;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // set longer enough so that accessibility service will initialize node
+                // within setImportantForAccessibility().
+                mGridView.getItemAnimator().setRemoveDuration(2000);
+                mGridView.getItemAnimator().setAddDuration(2000);
+                final int[] newItems = new int[numItemsToPushOut];
+                final int newItemValue = mActivity.mItemLengths[0];
+                for (int i = 0; i < newItems.length; i++) {
+                    newItems[i] = newItemValue;
+                }
+                mActivity.addItems(lastPos - numItemsToPushOut + 1, newItems);
+            }
+        });
+        waitForItemAnimation();
+    }
+
+    /**
+     * This test simulates talkback by calling setImportanceForAccessibility at end of animation
+     */
+    @Test
+    public void simulatesAccessibilityOfItemsBeingPushedOut() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        final HashSet<View> moveAnimationViews = new HashSet();
+        mActivity.mImportantForAccessibilityListener =
+                new GridActivity.ImportantForAccessibilityListener() {
+            RecyclerView.LayoutManager mLM = mGridView.getLayoutManager();
+            @Override
+            public void onImportantForAccessibilityChanged(View view, int newValue) {
+                // simulates talkack, having setImportantForAccessibility to call
+                // onInitializeAccessibilityNodeInfoForItem() for the DISAPPEARING items.
+                if (moveAnimationViews.contains(view)) {
+                    AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+                    mLM.onInitializeAccessibilityNodeInfoForItem(
+                            null, null, view, info);
+                }
+            }
+        };
+        final int lastPos = mGridView.getChildAdapterPosition(
+                mGridView.getChildAt(mGridView.getChildCount() - 1));
+        final int numItemsToPushOut = mNumRows;
+        for (int i = 0; i < numItemsToPushOut; i++) {
+            moveAnimationViews.add(
+                    mGridView.getChildAt(mGridView.getChildCount() - 1 - i));
+        }
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setItemAnimator(new DefaultItemAnimator() {
+                    @Override
+                    public void onMoveFinished(RecyclerView.ViewHolder item) {
+                        moveAnimationViews.remove(item.itemView);
+                    }
+                });
+                mGridView.getLayoutManager().setItemPrefetchEnabled(false);
+            }
+        });
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final int[] newItems = new int[numItemsToPushOut];
+                final int newItemValue = mActivity.mItemLengths[0] + 1;
+                for (int i = 0; i < newItems.length; i++) {
+                    newItems[i] = newItemValue;
+                }
+                mActivity.addItems(lastPos - numItemsToPushOut + 1, newItems);
+            }
+        });
+        while (moveAnimationViews.size() != 0) {
+            Thread.sleep(100);
+        }
+    }
+
+    @Test
+    public void testAccessibilityNodeInfoOnRemovedFirstItem() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 6);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        final View lastView = mGridView.findViewHolderForAdapterPosition(0).itemView;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setRemoveDuration(20000);
+                mActivity.removeItems(0, 1);
+            }
+        });
+        waitForItemAnimationStart();
+        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(lastView);
+        mGridView.getLayoutManager().onInitializeAccessibilityNodeInfoForItem(null, null,
+                lastView, info);
+        assertNoCollectionItemInfo(info);
+    }
+
+    @Test
+    public void testAccessibilityNodeInfoOnRemovedLastItem() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
+        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 6);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 3;
+
+        initActivity(intent);
+
+        final View lastView = mGridView.findViewHolderForAdapterPosition(5).itemView;
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.getItemAnimator().setRemoveDuration(20000);
+                mActivity.removeItems(5, 1);
+            }
+        });
+        waitForItemAnimationStart();
+        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(lastView);
+        mGridView.getLayoutManager().onInitializeAccessibilityNodeInfoForItem(null, null,
+                lastView, info);
+        assertNoCollectionItemInfo(info);
+    }
+
+    static class FiveViewTypesProvider implements ViewTypeProvider {
+
+        @Override
+        public int getViewType(int position) {
+            switch (position) {
+                case 0:
+                    return 0;
+                case 1:
+                    return 1;
+                case 2:
+                    return 2;
+                case 3:
+                    return 3;
+                case 4:
+                    return 4;
+            }
+            return 199;
+        }
+    }
+
+    // Used by testItemAlignmentVertical() testItemAlignmentHorizontal()
+    static class ItemAlignmentWithPaddingFacetProvider implements
+            ItemAlignmentFacetProvider {
+        final ItemAlignmentFacet mFacet0;
+        final ItemAlignmentFacet mFacet1;
+        final ItemAlignmentFacet mFacet2;
+        final ItemAlignmentFacet mFacet3;
+        final ItemAlignmentFacet mFacet4;
+
+        ItemAlignmentWithPaddingFacetProvider() {
+            ItemAlignmentFacet.ItemAlignmentDef[] defs;
+            mFacet0 = new ItemAlignmentFacet();
+            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t1);
+            defs[0].setItemAlignmentOffsetPercent(0);
+            defs[0].setItemAlignmentOffsetWithPadding(false);
+            mFacet0.setAlignmentDefs(defs);
+            mFacet1 = new ItemAlignmentFacet();
+            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t1);
+            defs[0].setItemAlignmentOffsetPercent(0);
+            defs[0].setItemAlignmentOffsetWithPadding(true);
+            mFacet1.setAlignmentDefs(defs);
+            mFacet2 = new ItemAlignmentFacet();
+            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t2);
+            defs[0].setItemAlignmentOffsetPercent(100);
+            defs[0].setItemAlignmentOffsetWithPadding(true);
+            mFacet2.setAlignmentDefs(defs);
+            mFacet3 = new ItemAlignmentFacet();
+            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t2);
+            defs[0].setItemAlignmentOffsetPercent(50);
+            defs[0].setItemAlignmentOffsetWithPadding(true);
+            mFacet3.setAlignmentDefs(defs);
+            mFacet4 = new ItemAlignmentFacet();
+            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
+            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
+            defs[0].setItemAlignmentViewId(R.id.t2);
+            defs[0].setItemAlignmentOffsetPercent(50);
+            defs[0].setItemAlignmentOffsetWithPadding(false);
+            mFacet4.setAlignmentDefs(defs);
+        }
+
+        @Override
+        public ItemAlignmentFacet getItemAlignmentFacet(int viewType) {
+            switch (viewType) {
+                case 0:
+                    return mFacet0;
+                case 1:
+                    return mFacet1;
+                case 2:
+                    return mFacet2;
+                case 3:
+                    return mFacet3;
+                case 4:
+                    return mFacet4;
+            }
+            return null;
+        }
+    }
+
+    @Test
+    public void testItemAlignmentVertical() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout2);
+        int[] items = new int[5];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                FiveViewTypesProvider.class.getName());
+        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
+                ItemAlignmentWithPaddingFacetProvider.class.getName());
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffsetPercent(50);
+                mGridView.setWindowAlignmentOffset(0);
+            }
+        });
+        waitForLayout();
+
+        final float windowAlignCenter = mGridView.getHeight() / 2f;
+        Rect rect = new Rect();
+        View textView;
+
+        // test 1: does not include padding
+        textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1);
+        rect.set(0, 0, textView.getWidth(), textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.top, DELTA);
+
+        // test 2: including low padding
+        setSelectedPosition(1);
+        textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1);
+        assertTrue(textView.getPaddingTop() > 0);
+        rect.set(0, textView.getPaddingTop(), textView.getWidth(), textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.top, DELTA);
+
+        // test 3: including high padding
+        setSelectedPosition(2);
+        textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingBottom() > 0);
+        rect.set(0, 0, textView.getWidth(),
+                textView.getHeight() - textView.getPaddingBottom());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.bottom, DELTA);
+
+        // test 4: including padding will be ignored if offsetPercent is not 0 or 100
+        setSelectedPosition(3);
+        textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingTop() != textView.getPaddingBottom());
+        rect.set(0, 0, textView.getWidth(), textView.getHeight() / 2);
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.bottom, DELTA);
+
+        // test 5: does not include padding
+        setSelectedPosition(4);
+        textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingTop() != textView.getPaddingBottom());
+        rect.set(0, 0, textView.getWidth(), textView.getHeight() / 2);
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.bottom, DELTA);
+    }
+
+    @Test
+    public void testItemAlignmentHorizontal() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout3);
+        int[] items = new int[5];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                FiveViewTypesProvider.class.getName());
+        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
+                ItemAlignmentWithPaddingFacetProvider.class.getName());
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffsetPercent(50);
+                mGridView.setWindowAlignmentOffset(0);
+            }
+        });
+        waitForLayout();
+
+        final float windowAlignCenter = mGridView.getWidth() / 2f;
+        Rect rect = new Rect();
+        View textView;
+
+        // test 1: does not include padding
+        textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1);
+        rect.set(0, 0, textView.getWidth(), textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.left, DELTA);
+
+        // test 2: including low padding
+        setSelectedPosition(1);
+        textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1);
+        assertTrue(textView.getPaddingLeft() > 0);
+        rect.set(textView.getPaddingLeft(), 0, textView.getWidth(), textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.left, DELTA);
+
+        // test 3: including high padding
+        setSelectedPosition(2);
+        textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingRight() > 0);
+        rect.set(0, 0, textView.getWidth() - textView.getPaddingRight(),
+                textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.right, DELTA);
+
+        // test 4: including padding will be ignored if offsetPercent is not 0 or 100
+        setSelectedPosition(3);
+        textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
+        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.right, DELTA);
+
+        // test 5: does not include padding
+        setSelectedPosition(4);
+        textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
+        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.right, DELTA);
+    }
+
+    @Test
+    public void testItemAlignmentHorizontalRtl() throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout3);
+        int[] items = new int[5];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 300;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
+                FiveViewTypesProvider.class.getName());
+        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
+                ItemAlignmentWithPaddingFacetProvider.class.getName());
+        mOrientation = BaseGridView.VERTICAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
+                mGridView.setWindowAlignmentOffsetPercent(50);
+                mGridView.setWindowAlignmentOffset(0);
+            }
+        });
+        waitForLayout();
+
+        final float windowAlignCenter = mGridView.getWidth() / 2f;
+        Rect rect = new Rect();
+        View textView;
+
+        // test 1: does not include padding
+        textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1);
+        rect.set(0, 0, textView.getWidth(), textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.right, DELTA);
+
+        // test 2: including low padding
+        setSelectedPosition(1);
+        textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1);
+        assertTrue(textView.getPaddingRight() > 0);
+        rect.set(0, 0, textView.getWidth() - textView.getPaddingRight(),
+                textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.right, DELTA);
+
+        // test 3: including high padding
+        setSelectedPosition(2);
+        textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingLeft() > 0);
+        rect.set(textView.getPaddingLeft(), 0, textView.getWidth(),
+                textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.left, DELTA);
+
+        // test 4: including padding will be ignored if offsetPercent is not 0 or 100
+        setSelectedPosition(3);
+        textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
+        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.right, DELTA);
+
+        // test 5: does not include padding
+        setSelectedPosition(4);
+        textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2);
+        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
+        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
+        mGridView.offsetDescendantRectToMyCoords(textView, rect);
+        assertEquals(windowAlignCenter, rect.right, DELTA);
+    }
+
+    enum ItemLocation {
+        ITEM_AT_LOW,
+        ITEM_AT_KEY_LINE,
+        ITEM_AT_HIGH
+    };
+
+    static class ItemAt {
+        final int mScrollPosition;
+        final int mPosition;
+        final ItemLocation mLocation;
+
+        ItemAt(int scrollPosition, int position, ItemLocation loc) {
+            mScrollPosition = scrollPosition;
+            mPosition = position;
+            mLocation = loc;
+        }
+
+        ItemAt(int position, ItemLocation loc) {
+            mScrollPosition = position;
+            mPosition = position;
+            mLocation = loc;
+        }
+    }
+
+    /**
+     * When scroll to position, item at position is expected at given location.
+     */
+    static ItemAt itemAt(int position, ItemLocation location) {
+        return new ItemAt(position, location);
+    }
+
+    /**
+     * When scroll to scrollPosition, item at position is expected at given location.
+     */
+    static ItemAt itemAt(int scrollPosition, int position, ItemLocation location) {
+        return new ItemAt(scrollPosition, position, location);
+    }
+
+    void prepareKeyLineTest(int numItems) throws Throwable {
+        Intent intent = new Intent();
+        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
+        int[] items = new int[numItems];
+        for (int i = 0; i < items.length; i++) {
+            items[i] = 32;
+        }
+        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
+        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
+        mOrientation = BaseGridView.HORIZONTAL;
+        mNumRows = 1;
+
+        initActivity(intent);
+    }
+
+    public void testPreferKeyLine(final int windowAlignment,
+            final boolean preferKeyLineOverLow,
+            final boolean preferKeyLineOverHigh,
+            ItemLocation assertFirstItemLocation,
+            ItemLocation assertLastItemLocation) throws Throwable {
+        testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh,
+                itemAt(0, assertFirstItemLocation),
+                itemAt(mActivity.mNumItems - 1, assertLastItemLocation));
+    }
+
+    public void testPreferKeyLine(final int windowAlignment,
+            final boolean preferKeyLineOverLow,
+            final boolean preferKeyLineOverHigh,
+            ItemLocation assertFirstItemLocation,
+            ItemAt assertLastItemLocation) throws Throwable {
+        testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh,
+                itemAt(0, assertFirstItemLocation),
+                assertLastItemLocation);
+    }
+
+    public void testPreferKeyLine(final int windowAlignment,
+            final boolean preferKeyLineOverLow,
+            final boolean preferKeyLineOverHigh,
+            ItemAt assertFirstItemLocation,
+            ItemLocation assertLastItemLocation) throws Throwable {
+        testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh,
+                assertFirstItemLocation,
+                itemAt(mActivity.mNumItems - 1, assertLastItemLocation));
+    }
+
+    public void testPreferKeyLine(final int windowAlignment,
+            final boolean preferKeyLineOverLow,
+            final boolean preferKeyLineOverHigh,
+            ItemAt assertFirstItemLocation,
+            ItemAt assertLastItemLocation) throws Throwable {
+        TestPreferKeyLineOptions options = new TestPreferKeyLineOptions();
+        options.mAssertItemLocations = new ItemAt[] {assertFirstItemLocation,
+                assertLastItemLocation};
+        options.mPreferKeyLineOverLow = preferKeyLineOverLow;
+        options.mPreferKeyLineOverHigh = preferKeyLineOverHigh;
+        options.mWindowAlignment = windowAlignment;
+
+        options.mRtl = false;
+        testPreferKeyLine(options);
+
+        options.mRtl = true;
+        testPreferKeyLine(options);
+    }
+
+    static class TestPreferKeyLineOptions {
+        int mWindowAlignment;
+        boolean mPreferKeyLineOverLow;
+        boolean mPreferKeyLineOverHigh;
+        ItemAt[] mAssertItemLocations;
+        boolean mRtl;
+    }
+
+    public void testPreferKeyLine(final TestPreferKeyLineOptions options) throws Throwable {
+        startWaitLayout();
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (options.mRtl) {
+                    mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
+                } else {
+                    mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
+                }
+                mGridView.setWindowAlignment(options.mWindowAlignment);
+                mGridView.setWindowAlignmentOffsetPercent(50);
+                mGridView.setWindowAlignmentOffset(0);
+                mGridView.setWindowAlignmentPreferKeyLineOverLowEdge(options.mPreferKeyLineOverLow);
+                mGridView.setWindowAlignmentPreferKeyLineOverHighEdge(
+                        options.mPreferKeyLineOverHigh);
+            }
+        });
+        waitForLayout();
+
+        final int paddingStart = mGridView.getPaddingStart();
+        final int paddingEnd = mGridView.getPaddingEnd();
+        final int windowAlignCenter = mGridView.getWidth() / 2;
+
+        for (int i = 0; i < options.mAssertItemLocations.length; i++) {
+            ItemAt assertItemLocation = options.mAssertItemLocations[i];
+            setSelectedPosition(assertItemLocation.mScrollPosition);
+            View view = mGridView.findViewHolderForAdapterPosition(assertItemLocation.mPosition)
+                    .itemView;
+            switch (assertItemLocation.mLocation) {
+                case ITEM_AT_LOW:
+                    if (options.mRtl) {
+                        assertEquals(mGridView.getWidth() - paddingStart, view.getRight());
+                    } else {
+                        assertEquals(paddingStart, view.getLeft());
+                    }
+                    break;
+                case ITEM_AT_HIGH:
+                    if (options.mRtl) {
+                        assertEquals(paddingEnd, view.getLeft());
+                    } else {
+                        assertEquals(mGridView.getWidth() - paddingEnd, view.getRight());
+                    }
+                    break;
+                case ITEM_AT_KEY_LINE:
+                    assertEquals(windowAlignCenter, (view.getLeft() + view.getRight()) / 2, DELTA);
+                    break;
+            }
+        }
+    }
+
+    @Test
+    public void testPreferKeyLine1() throws Throwable {
+        prepareKeyLineTest(1);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false,
+                ItemLocation.ITEM_AT_HIGH, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false,
+                ItemLocation.ITEM_AT_HIGH, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+    }
+
+    @Test
+    public void testPreferKeyLine2() throws Throwable {
+        prepareKeyLineTest(2);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false,
+                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true,
+                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false,
+                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
+                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true,
+                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
+                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false,
+                itemAt(0, 1, ItemLocation.ITEM_AT_HIGH),
+                itemAt(1, 1, ItemLocation.ITEM_AT_HIGH));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true,
+                itemAt(0, 0, ItemLocation.ITEM_AT_KEY_LINE),
+                itemAt(1, 0, ItemLocation.ITEM_AT_KEY_LINE));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false,
+                itemAt(0, 1, ItemLocation.ITEM_AT_HIGH),
+                itemAt(1, 1, ItemLocation.ITEM_AT_HIGH));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true,
+                itemAt(0, 0, ItemLocation.ITEM_AT_KEY_LINE),
+                itemAt(1, 0, ItemLocation.ITEM_AT_KEY_LINE));
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false,
+                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true,
+                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false,
+                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
+                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true,
+                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
+                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
+    }
+
+    @Test
+    public void testPreferKeyLine10000() throws Throwable {
+        prepareKeyLineTest(10000);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true,
+                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
+
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
+        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true,
+                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
+    }
+}
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/GuidedActionStylistTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/GuidedActionStylistTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/GuidedActionStylistTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/GuidedActionStylistTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/HorizontalGridViewEx.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/HorizontalGridViewEx.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/HorizontalGridViewEx.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/HorizontalGridViewEx.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ImageCardViewTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ImageCardViewTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ImageCardViewTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ImageCardViewTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ListRowPresenterTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ListRowPresenterTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ListRowPresenterTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ListRowPresenterTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/MediaNowPlayingViewTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/MediaNowPlayingViewTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/MediaNowPlayingViewTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/MediaNowPlayingViewTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ObjectAdapterTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ObjectAdapterTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ObjectAdapterTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ObjectAdapterTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/PagingIndicatorTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/PagingIndicatorTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/PagingIndicatorTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/PagingIndicatorTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxFloatEffectTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxFloatTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxIntEffectTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxIntTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ParallaxIntTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ParallaxIntTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/PlaybackGlueHostImplWithViewHolder.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/PlaybackSeekProviderSample.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/PlaybackSeekProviderSample.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/PlaybackSeekProviderSample.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/PlaybackSeekProviderSample.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenterTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/PresenterTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/PresenterTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/PresenterTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ShadowOverlayContainerTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/SingleRowTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/SingleRowTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/SingleRowTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/StaggeredGridDefaultTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/ThumbsBarTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/ThumbsBarTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/ThumbsBarTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/ThumbsBarTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/TitleViewAdapterTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/TitleViewAdapterTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/TitleViewAdapterTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/TitleViewAdapterTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/VerticalGridViewEx.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/VerticalGridViewEx.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/VerticalGridViewEx.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/VerticalGridViewEx.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/picker/DatePickerActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/DatePickerActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/picker/DatePickerActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/DatePickerActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/picker/DatePickerTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/DatePickerTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/picker/DatePickerTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/DatePickerTest.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/picker/TimePickerActivity.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/TimePickerActivity.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/picker/TimePickerActivity.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/TimePickerActivity.java
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/picker/TimePickerTest.java b/leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/TimePickerTest.java
similarity index 100%
rename from leanback/tests/java/android/support/v17/leanback/widget/picker/TimePickerTest.java
rename to leanback/src/androidTest/java/android/support/v17/leanback/widget/picker/TimePickerTest.java
diff --git a/leanback/tests/res/drawable/ic_action_a.png b/leanback/src/androidTest/res/drawable/ic_action_a.png
similarity index 100%
rename from leanback/tests/res/drawable/ic_action_a.png
rename to leanback/src/androidTest/res/drawable/ic_action_a.png
Binary files differ
diff --git a/leanback/tests/res/drawable/spiderman.jpg b/leanback/src/androidTest/res/drawable/spiderman.jpg
similarity index 100%
rename from leanback/tests/res/drawable/spiderman.jpg
rename to leanback/src/androidTest/res/drawable/spiderman.jpg
Binary files differ
diff --git a/leanback/tests/res/layout/browse.xml b/leanback/src/androidTest/res/layout/browse.xml
similarity index 100%
rename from leanback/tests/res/layout/browse.xml
rename to leanback/src/androidTest/res/layout/browse.xml
diff --git a/leanback/tests/res/layout/datepicker_alone.xml b/leanback/src/androidTest/res/layout/datepicker_alone.xml
similarity index 100%
rename from leanback/tests/res/layout/datepicker_alone.xml
rename to leanback/src/androidTest/res/layout/datepicker_alone.xml
diff --git a/leanback/tests/res/layout/datepicker_with_other_widgets.xml b/leanback/src/androidTest/res/layout/datepicker_with_other_widgets.xml
similarity index 100%
rename from leanback/tests/res/layout/datepicker_with_other_widgets.xml
rename to leanback/src/androidTest/res/layout/datepicker_with_other_widgets.xml
diff --git a/leanback/tests/res/layout/details.xml b/leanback/src/androidTest/res/layout/details.xml
similarity index 100%
rename from leanback/tests/res/layout/details.xml
rename to leanback/src/androidTest/res/layout/details.xml
diff --git a/leanback/tests/res/layout/horizontal_grid.xml b/leanback/src/androidTest/res/layout/horizontal_grid.xml
similarity index 100%
rename from leanback/tests/res/layout/horizontal_grid.xml
rename to leanback/src/androidTest/res/layout/horizontal_grid.xml
diff --git a/leanback/tests/res/layout/horizontal_grid_testredundantappendremove2.xml b/leanback/src/androidTest/res/layout/horizontal_grid_testredundantappendremove2.xml
similarity index 100%
rename from leanback/tests/res/layout/horizontal_grid_testredundantappendremove2.xml
rename to leanback/src/androidTest/res/layout/horizontal_grid_testredundantappendremove2.xml
diff --git a/leanback/tests/res/layout/horizontal_grid_wrap.xml b/leanback/src/androidTest/res/layout/horizontal_grid_wrap.xml
similarity index 100%
rename from leanback/tests/res/layout/horizontal_grid_wrap.xml
rename to leanback/src/androidTest/res/layout/horizontal_grid_wrap.xml
diff --git a/leanback/tests/res/layout/horizontal_item.xml b/leanback/src/androidTest/res/layout/horizontal_item.xml
similarity index 100%
rename from leanback/tests/res/layout/horizontal_item.xml
rename to leanback/src/androidTest/res/layout/horizontal_item.xml
diff --git a/leanback/tests/res/layout/horizontal_linear.xml b/leanback/src/androidTest/res/layout/horizontal_linear.xml
similarity index 100%
rename from leanback/tests/res/layout/horizontal_linear.xml
rename to leanback/src/androidTest/res/layout/horizontal_linear.xml
diff --git a/leanback/tests/res/layout/horizontal_linear_rtl.xml b/leanback/src/androidTest/res/layout/horizontal_linear_rtl.xml
similarity index 100%
rename from leanback/tests/res/layout/horizontal_linear_rtl.xml
rename to leanback/src/androidTest/res/layout/horizontal_linear_rtl.xml
diff --git a/leanback/tests/res/layout/horizontal_linear_wrap_content.xml b/leanback/src/androidTest/res/layout/horizontal_linear_wrap_content.xml
similarity index 100%
rename from leanback/tests/res/layout/horizontal_linear_wrap_content.xml
rename to leanback/src/androidTest/res/layout/horizontal_linear_wrap_content.xml
diff --git a/leanback/tests/res/layout/item_button_at_bottom.xml b/leanback/src/androidTest/res/layout/item_button_at_bottom.xml
similarity index 100%
rename from leanback/tests/res/layout/item_button_at_bottom.xml
rename to leanback/src/androidTest/res/layout/item_button_at_bottom.xml
diff --git a/leanback/tests/res/layout/item_button_at_top.xml b/leanback/src/androidTest/res/layout/item_button_at_top.xml
similarity index 100%
rename from leanback/tests/res/layout/item_button_at_top.xml
rename to leanback/src/androidTest/res/layout/item_button_at_top.xml
diff --git a/leanback/tests/res/layout/page_fragment.xml b/leanback/src/androidTest/res/layout/page_fragment.xml
similarity index 100%
rename from leanback/tests/res/layout/page_fragment.xml
rename to leanback/src/androidTest/res/layout/page_fragment.xml
diff --git a/leanback/tests/res/layout/playback_controls_with_video.xml b/leanback/src/androidTest/res/layout/playback_controls_with_video.xml
similarity index 100%
rename from leanback/tests/res/layout/playback_controls_with_video.xml
rename to leanback/src/androidTest/res/layout/playback_controls_with_video.xml
diff --git a/leanback/tests/res/layout/relative_layout.xml b/leanback/src/androidTest/res/layout/relative_layout.xml
similarity index 100%
rename from leanback/tests/res/layout/relative_layout.xml
rename to leanback/src/androidTest/res/layout/relative_layout.xml
diff --git a/leanback/tests/res/layout/relative_layout2.xml b/leanback/src/androidTest/res/layout/relative_layout2.xml
similarity index 100%
rename from leanback/tests/res/layout/relative_layout2.xml
rename to leanback/src/androidTest/res/layout/relative_layout2.xml
diff --git a/leanback/tests/res/layout/relative_layout3.xml b/leanback/src/androidTest/res/layout/relative_layout3.xml
similarity index 100%
rename from leanback/tests/res/layout/relative_layout3.xml
rename to leanback/src/androidTest/res/layout/relative_layout3.xml
diff --git a/leanback/tests/res/layout/selectable_text_view.xml b/leanback/src/androidTest/res/layout/selectable_text_view.xml
similarity index 100%
rename from leanback/tests/res/layout/selectable_text_view.xml
rename to leanback/src/androidTest/res/layout/selectable_text_view.xml
diff --git a/leanback/tests/res/layout/single_fragment.xml b/leanback/src/androidTest/res/layout/single_fragment.xml
similarity index 100%
rename from leanback/tests/res/layout/single_fragment.xml
rename to leanback/src/androidTest/res/layout/single_fragment.xml
diff --git a/leanback/tests/res/layout/timepicker_alone.xml b/leanback/src/androidTest/res/layout/timepicker_alone.xml
similarity index 100%
rename from leanback/tests/res/layout/timepicker_alone.xml
rename to leanback/src/androidTest/res/layout/timepicker_alone.xml
diff --git a/leanback/tests/res/layout/timepicker_with_other_widgets.xml b/leanback/src/androidTest/res/layout/timepicker_with_other_widgets.xml
similarity index 100%
rename from leanback/tests/res/layout/timepicker_with_other_widgets.xml
rename to leanback/src/androidTest/res/layout/timepicker_with_other_widgets.xml
diff --git a/leanback/tests/res/layout/vertical_grid.xml b/leanback/src/androidTest/res/layout/vertical_grid.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_grid.xml
rename to leanback/src/androidTest/res/layout/vertical_grid.xml
diff --git a/leanback/tests/res/layout/vertical_grid_ltr.xml b/leanback/src/androidTest/res/layout/vertical_grid_ltr.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_grid_ltr.xml
rename to leanback/src/androidTest/res/layout/vertical_grid_ltr.xml
diff --git a/leanback/src/androidTest/res/layout/vertical_grid_rtl.xml b/leanback/src/androidTest/res/layout/vertical_grid_rtl.xml
new file mode 100644
index 0000000..7f00ab1
--- /dev/null
+++ b/leanback/src/androidTest/res/layout/vertical_grid_rtl.xml
@@ -0,0 +1,33 @@
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:lb="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layoutDirection="rtl"
+    >
+  <Button android:id="@+id/button"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_alignParentStart="true"
+      android:text="button"
+      />
+  <android.support.v17.leanback.widget.VerticalGridViewEx
+      android:id="@+id/gridview"
+      android:layout_width="match_parent"
+      android:layout_height="match_parent"
+      android:layout_toEndOf="@id/button"
+      android:clipToPadding="false"
+      android:focusable="true"
+      android:focusableInTouchMode="true"
+      android:background="#00ffff"
+      android:horizontalSpacing="12dip"
+      android:verticalSpacing="24dip"
+      lb:numberOfColumns="2"
+      lb:columnWidth="wrap_content"
+      lb:focusOutSideStart="false"
+      lb:focusOutSideEnd="true"
+      android:paddingBottom="12dip"
+      android:paddingLeft="12dip"
+      android:paddingRight="12dip"
+      android:paddingTop="12dip" />
+</RelativeLayout>
diff --git a/leanback/tests/res/layout/vertical_grid_testredundantappendremove.xml b/leanback/src/androidTest/res/layout/vertical_grid_testredundantappendremove.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_grid_testredundantappendremove.xml
rename to leanback/src/androidTest/res/layout/vertical_grid_testredundantappendremove.xml
diff --git a/leanback/tests/res/layout/vertical_linear.xml b/leanback/src/androidTest/res/layout/vertical_linear.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_linear.xml
rename to leanback/src/androidTest/res/layout/vertical_linear.xml
diff --git a/leanback/tests/res/layout/vertical_linear_measured_with_zero.xml b/leanback/src/androidTest/res/layout/vertical_linear_measured_with_zero.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_linear_measured_with_zero.xml
rename to leanback/src/androidTest/res/layout/vertical_linear_measured_with_zero.xml
diff --git a/leanback/tests/res/layout/vertical_linear_with_button.xml b/leanback/src/androidTest/res/layout/vertical_linear_with_button.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_linear_with_button.xml
rename to leanback/src/androidTest/res/layout/vertical_linear_with_button.xml
diff --git a/leanback/tests/res/layout/vertical_linear_with_button_onleft.xml b/leanback/src/androidTest/res/layout/vertical_linear_with_button_onleft.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_linear_with_button_onleft.xml
rename to leanback/src/androidTest/res/layout/vertical_linear_with_button_onleft.xml
diff --git a/leanback/tests/res/layout/vertical_linear_wrap_content.xml b/leanback/src/androidTest/res/layout/vertical_linear_wrap_content.xml
similarity index 100%
rename from leanback/tests/res/layout/vertical_linear_wrap_content.xml
rename to leanback/src/androidTest/res/layout/vertical_linear_wrap_content.xml
diff --git a/leanback/tests/res/layout/video_fragment_with_controls.xml b/leanback/src/androidTest/res/layout/video_fragment_with_controls.xml
similarity index 100%
rename from leanback/tests/res/layout/video_fragment_with_controls.xml
rename to leanback/src/androidTest/res/layout/video_fragment_with_controls.xml
diff --git a/leanback/tests/res/raw/track_01.mp3 b/leanback/src/androidTest/res/raw/track_01.mp3
similarity index 100%
rename from leanback/tests/res/raw/track_01.mp3
rename to leanback/src/androidTest/res/raw/track_01.mp3
Binary files differ
diff --git a/leanback/tests/res/raw/video.mp4 b/leanback/src/androidTest/res/raw/video.mp4
similarity index 100%
rename from leanback/tests/res/raw/video.mp4
rename to leanback/src/androidTest/res/raw/video.mp4
Binary files differ
diff --git a/leanback/tests/res/values/strings.xml b/leanback/src/androidTest/res/values/strings.xml
similarity index 100%
rename from leanback/tests/res/values/strings.xml
rename to leanback/src/androidTest/res/values/strings.xml
diff --git a/leanback/src/main/AndroidManifest.xml b/leanback/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..959b923
--- /dev/null
+++ b/leanback/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.v17.leanback"/>
diff --git a/leanback/src/android/support/v17/leanback/animation/LogAccelerateInterpolator.java b/leanback/src/main/java/android/support/v17/leanback/animation/LogAccelerateInterpolator.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/animation/LogAccelerateInterpolator.java
rename to leanback/src/main/java/android/support/v17/leanback/animation/LogAccelerateInterpolator.java
diff --git a/leanback/src/android/support/v17/leanback/animation/LogDecelerateInterpolator.java b/leanback/src/main/java/android/support/v17/leanback/animation/LogDecelerateInterpolator.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/animation/LogDecelerateInterpolator.java
rename to leanback/src/main/java/android/support/v17/leanback/animation/LogDecelerateInterpolator.java
diff --git a/leanback/src/android/support/v17/leanback/app/BackgroundFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BackgroundFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/BackgroundFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/BackgroundFragment.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/BackgroundManager.java b/leanback/src/main/java/android/support/v17/leanback/app/BackgroundManager.java
new file mode 100644
index 0000000..2d010e7
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/BackgroundManager.java
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.os.Build;
+import android.os.Handler;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.BackgroundHelper;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.view.animation.FastOutLinearInInterpolator;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Supports background image continuity between multiple Activities.
+ *
+ * <p>An Activity should instantiate a BackgroundManager and {@link #attach}
+ * to the Activity's window.  When the Activity is started, the background is
+ * initialized to the current background values stored in a continuity service.
+ * The background continuity service is updated as the background is updated.
+ *
+ * <p>At some point, for example when it is stopped, the Activity may release
+ * its background state.
+ *
+ * <p>When an Activity is resumed, if the BackgroundManager has not been
+ * released, the continuity service is updated from the BackgroundManager state.
+ * If the BackgroundManager was released, the BackgroundManager inherits the
+ * current state from the continuity service.
+ *
+ * <p>When the last Activity is destroyed, the background state is reset.
+ *
+ * <p>Backgrounds consist of several layers, from back to front:
+ * <ul>
+ *   <li>the background Drawable of the theme</li>
+ *   <li>a solid color (set via {@link #setColor})</li>
+ *   <li>two Drawables, previous and current (set via {@link #setBitmap} or
+ *   {@link #setDrawable}), which may be in transition</li>
+ * </ul>
+ *
+ * <p>BackgroundManager holds references to potentially large bitmap Drawables.
+ * Call {@link #release} to release these references when the Activity is not
+ * visible.
+ */
+// TODO: support for multiple app processes requires a proper android service
+// instead of the shared memory "service" implemented here. Such a service could
+// support continuity between fragments of different applications if desired.
+public final class BackgroundManager {
+
+    static final String TAG = "BackgroundManager";
+    static final boolean DEBUG = false;
+
+    static final int FULL_ALPHA = 255;
+    private static final int CHANGE_BG_DELAY_MS = 500;
+    private static final int FADE_DURATION = 500;
+
+    private static final String FRAGMENT_TAG = BackgroundManager.class.getCanonicalName();
+
+    Activity mContext;
+    Handler mHandler;
+    private View mBgView;
+    private BackgroundContinuityService mService;
+    private int mThemeDrawableResourceId;
+    private BackgroundFragment mFragmentState;
+    private boolean mAutoReleaseOnStop = true;
+
+    private int mHeightPx;
+    private int mWidthPx;
+    int mBackgroundColor;
+    Drawable mBackgroundDrawable;
+    private boolean mAttached;
+    private long mLastSetTime;
+
+    private final Interpolator mAccelerateInterpolator;
+    private final Interpolator mDecelerateInterpolator;
+    final ValueAnimator mAnimator;
+
+    static class BitmapDrawable extends Drawable {
+
+        static final class ConstantState extends Drawable.ConstantState {
+            final Bitmap mBitmap;
+            final Matrix mMatrix;
+            final Paint mPaint = new Paint();
+
+            ConstantState(Bitmap bitmap, Matrix matrix) {
+                mBitmap = bitmap;
+                mMatrix = matrix != null ? matrix : new Matrix();
+                mPaint.setFilterBitmap(true);
+            }
+
+            ConstantState(ConstantState copyFrom) {
+                mBitmap = copyFrom.mBitmap;
+                mMatrix = copyFrom.mMatrix != null ? new Matrix(copyFrom.mMatrix) : new Matrix();
+                if (copyFrom.mPaint.getAlpha() != FULL_ALPHA) {
+                    mPaint.setAlpha(copyFrom.mPaint.getAlpha());
+                }
+                if (copyFrom.mPaint.getColorFilter() != null) {
+                    mPaint.setColorFilter(copyFrom.mPaint.getColorFilter());
+                }
+                mPaint.setFilterBitmap(true);
+            }
+
+            @Override
+            public Drawable newDrawable() {
+                return new BitmapDrawable(this);
+            }
+
+            @Override
+            public int getChangingConfigurations() {
+                return 0;
+            }
+        }
+
+        ConstantState mState;
+        boolean mMutated;
+
+        BitmapDrawable(Resources resources, Bitmap bitmap) {
+            this(resources, bitmap, null);
+        }
+
+        BitmapDrawable(Resources resources, Bitmap bitmap, Matrix matrix) {
+            mState = new ConstantState(bitmap, matrix);
+        }
+
+        BitmapDrawable(ConstantState state) {
+            mState = state;
+        }
+
+        Bitmap getBitmap() {
+            return mState.mBitmap;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            if (mState.mBitmap == null) {
+                return;
+            }
+            if (mState.mPaint.getAlpha() < FULL_ALPHA && mState.mPaint.getColorFilter() != null) {
+                throw new IllegalStateException("Can't draw with translucent alpha and color filter");
+            }
+            canvas.drawBitmap(mState.mBitmap, mState.mMatrix, mState.mPaint);
+        }
+
+        @Override
+        public int getOpacity() {
+            return android.graphics.PixelFormat.TRANSLUCENT;
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            mutate();
+            if (mState.mPaint.getAlpha() != alpha) {
+                mState.mPaint.setAlpha(alpha);
+                invalidateSelf();
+            }
+        }
+
+        /**
+         * Does not invalidateSelf to avoid recursion issues.
+         * Caller must ensure appropriate invalidation.
+         */
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+            mutate();
+            mState.mPaint.setColorFilter(cf);
+            invalidateSelf();
+        }
+
+        @Override
+        public ColorFilter getColorFilter() {
+            return mState.mPaint.getColorFilter();
+        }
+
+        @Override
+        public ConstantState getConstantState() {
+            return mState;
+        }
+
+        @NonNull
+        @Override
+        public Drawable mutate() {
+            if (!mMutated) {
+                mMutated = true;
+                mState = new ConstantState(mState);
+            }
+            return this;
+        }
+    }
+
+    static final class DrawableWrapper {
+        int mAlpha = FULL_ALPHA;
+        final Drawable mDrawable;
+
+        public DrawableWrapper(Drawable drawable) {
+            mDrawable = drawable;
+        }
+        public DrawableWrapper(DrawableWrapper wrapper, Drawable drawable) {
+            mDrawable = drawable;
+            mAlpha = wrapper.mAlpha;
+        }
+
+        public Drawable getDrawable() {
+            return mDrawable;
+        }
+
+        public void setColor(int color) {
+            ((ColorDrawable) mDrawable).setColor(color);
+        }
+    }
+
+    static final class TranslucentLayerDrawable extends LayerDrawable {
+        DrawableWrapper[] mWrapper;
+        int mAlpha = FULL_ALPHA;
+        boolean mSuspendInvalidation;
+        WeakReference<BackgroundManager> mManagerWeakReference;
+
+        TranslucentLayerDrawable(BackgroundManager manager, Drawable[] drawables) {
+            super(drawables);
+            mManagerWeakReference = new WeakReference(manager);
+            int count = drawables.length;
+            mWrapper = new DrawableWrapper[count];
+            for (int i = 0; i < count; i++) {
+                mWrapper[i] = new DrawableWrapper(drawables[i]);
+            }
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+            if (mAlpha != alpha) {
+                mAlpha = alpha;
+                invalidateSelf();
+                BackgroundManager manager = mManagerWeakReference.get();
+                if (manager != null) {
+                    manager.postChangeRunnable();
+                }
+            }
+        }
+
+        void setWrapperAlpha(int wrapperIndex, int alpha) {
+            if (mWrapper[wrapperIndex] != null) {
+                mWrapper[wrapperIndex].mAlpha = alpha;
+                invalidateSelf();
+            }
+        }
+
+        // Queried by system transitions
+        @Override
+        public int getAlpha() {
+            return mAlpha;
+        }
+
+        @Override
+        public Drawable mutate() {
+            Drawable drawable = super.mutate();
+            int count = getNumberOfLayers();
+            for (int i = 0; i < count; i++) {
+                if (mWrapper[i] != null) {
+                    mWrapper[i] = new DrawableWrapper(mWrapper[i], getDrawable(i));
+                }
+            }
+            return drawable;
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.TRANSLUCENT;
+        }
+
+        @Override
+        public boolean setDrawableByLayerId(int id, Drawable drawable) {
+            return updateDrawable(id, drawable) != null;
+        }
+
+        public DrawableWrapper updateDrawable(int id, Drawable drawable) {
+            super.setDrawableByLayerId(id, drawable);
+            for (int i = 0; i < getNumberOfLayers(); i++) {
+                if (getId(i) == id) {
+                    mWrapper[i] = new DrawableWrapper(drawable);
+                    // Must come after mWrapper was updated so it can be seen by updateColorFilter
+                    invalidateSelf();
+                    return mWrapper[i];
+                }
+            }
+            return null;
+        }
+
+        public void clearDrawable(int id, Context context) {
+            for (int i = 0; i < getNumberOfLayers(); i++) {
+                if (getId(i) == id) {
+                    mWrapper[i] = null;
+                    if (!(getDrawable(i) instanceof EmptyDrawable)) {
+                        super.setDrawableByLayerId(id, createEmptyDrawable(context));
+                    }
+                    break;
+                }
+            }
+        }
+
+        public int findWrapperIndexById(int id) {
+            for (int i = 0; i < getNumberOfLayers(); i++) {
+                if (getId(i) == id) {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        @Override
+        public void invalidateDrawable(Drawable who) {
+            // Prevent invalidate when temporarily change child drawable's alpha in draw()
+            if (!mSuspendInvalidation) {
+                super.invalidateDrawable(who);
+            }
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            for (int i = 0; i < mWrapper.length; i++) {
+                final Drawable d;
+                // For each child drawable, we multiple Wrapper's alpha and LayerDrawable's alpha
+                // temporarily using mSuspendInvalidation to suppress invalidate event.
+                if (mWrapper[i] != null && (d = mWrapper[i].getDrawable()) != null) {
+                    int alpha = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
+                            ? DrawableCompat.getAlpha(d) : FULL_ALPHA;
+                    final int savedAlpha = alpha;
+                    int multiple = 0;
+                    if (mAlpha < FULL_ALPHA) {
+                        alpha = alpha * mAlpha;
+                        multiple++;
+                    }
+                    if (mWrapper[i].mAlpha < FULL_ALPHA) {
+                        alpha = alpha * mWrapper[i].mAlpha;
+                        multiple++;
+                    }
+                    if (multiple == 0) {
+                        d.draw(canvas);
+                    } else {
+                        if (multiple == 1) {
+                            alpha = alpha / FULL_ALPHA;
+                        } else if (multiple == 2) {
+                            alpha = alpha / (FULL_ALPHA * FULL_ALPHA);
+                        }
+                        try {
+                            mSuspendInvalidation = true;
+                            d.setAlpha(alpha);
+                            d.draw(canvas);
+                            d.setAlpha(savedAlpha);
+                        } finally {
+                            mSuspendInvalidation = false;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    TranslucentLayerDrawable createTranslucentLayerDrawable(
+            LayerDrawable layerDrawable) {
+        int numChildren = layerDrawable.getNumberOfLayers();
+        Drawable[] drawables = new Drawable[numChildren];
+        for (int i = 0; i < numChildren; i++) {
+            drawables[i] = layerDrawable.getDrawable(i);
+        }
+        TranslucentLayerDrawable result = new TranslucentLayerDrawable(this, drawables);
+        for (int i = 0; i < numChildren; i++) {
+            result.setId(i, layerDrawable.getId(i));
+        }
+        return result;
+    }
+
+    TranslucentLayerDrawable mLayerDrawable;
+    int mImageInWrapperIndex;
+    int mImageOutWrapperIndex;
+    ChangeBackgroundRunnable mChangeRunnable;
+    private boolean mChangeRunnablePending;
+
+    private final Animator.AnimatorListener mAnimationListener = new Animator.AnimatorListener() {
+        final Runnable mRunnable = new Runnable() {
+            @Override
+            public void run() {
+                postChangeRunnable();
+            }
+        };
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+        }
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (mLayerDrawable != null) {
+                mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
+            }
+            mHandler.post(mRunnable);
+        }
+        @Override
+        public void onAnimationCancel(Animator animation) {
+        }
+    };
+
+    private final ValueAnimator.AnimatorUpdateListener mAnimationUpdateListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            int fadeInAlpha = (Integer) animation.getAnimatedValue();
+            if (mImageInWrapperIndex != -1) {
+                mLayerDrawable.setWrapperAlpha(mImageInWrapperIndex, fadeInAlpha);
+            }
+        }
+    };
+
+    /**
+     * Shared memory continuity service.
+     */
+    private static class BackgroundContinuityService {
+        private static final String TAG = "BackgroundContinuity";
+        private static final boolean DEBUG = BackgroundManager.DEBUG;
+
+        private static BackgroundContinuityService sService = new BackgroundContinuityService();
+
+        private int mColor;
+        private Drawable mDrawable;
+        private int mCount;
+
+        /** Single cache of theme drawable */
+        private int mLastThemeDrawableId;
+        private WeakReference<Drawable.ConstantState> mLastThemeDrawableState;
+
+        private BackgroundContinuityService() {
+            reset();
+        }
+
+        private void reset() {
+            mColor = Color.TRANSPARENT;
+            mDrawable = null;
+        }
+
+        public static BackgroundContinuityService getInstance() {
+            final int count = sService.mCount++;
+            if (DEBUG) Log.v(TAG, "Returning instance with new count " + count);
+            return sService;
+        }
+
+        public void unref() {
+            if (mCount <= 0) throw new IllegalStateException("Can't unref, count " + mCount);
+            if (--mCount == 0) {
+                if (DEBUG) Log.v(TAG, "mCount is zero, resetting");
+                reset();
+            }
+        }
+        public int getColor() {
+            return mColor;
+        }
+        public Drawable getDrawable() {
+            return mDrawable;
+        }
+        public void setColor(int color) {
+            mColor = color;
+            mDrawable = null;
+        }
+        public void setDrawable(Drawable drawable) {
+            mDrawable = drawable;
+        }
+        public Drawable getThemeDrawable(Context context, int themeDrawableId) {
+            Drawable drawable = null;
+            if (mLastThemeDrawableState != null && mLastThemeDrawableId == themeDrawableId) {
+                Drawable.ConstantState drawableState = mLastThemeDrawableState.get();
+                if (DEBUG) Log.v(TAG, "got cached theme drawable state " + drawableState);
+                if (drawableState != null) {
+                    drawable = drawableState.newDrawable();
+                }
+            }
+            if (drawable == null) {
+                drawable = ContextCompat.getDrawable(context, themeDrawableId);
+                if (DEBUG) Log.v(TAG, "loaded theme drawable " + drawable);
+                mLastThemeDrawableState = new WeakReference<Drawable.ConstantState>(
+                        drawable.getConstantState());
+                mLastThemeDrawableId = themeDrawableId;
+            }
+            // No mutate required because this drawable is never manipulated.
+            return drawable;
+        }
+    }
+
+    Drawable getDefaultDrawable() {
+        if (mBackgroundColor != Color.TRANSPARENT) {
+            return new ColorDrawable(mBackgroundColor);
+        } else {
+            return getThemeDrawable();
+        }
+    }
+
+    private Drawable getThemeDrawable() {
+        Drawable drawable = null;
+        if (mThemeDrawableResourceId != -1) {
+            drawable = mService.getThemeDrawable(mContext, mThemeDrawableResourceId);
+        }
+        if (drawable == null) {
+            drawable = createEmptyDrawable(mContext);
+        }
+        return drawable;
+    }
+
+    /**
+     * Returns the BackgroundManager associated with the given Activity.
+     * <p>
+     * The BackgroundManager will be created on-demand for each individual
+     * Activity. Subsequent calls will return the same BackgroundManager created
+     * for this Activity.
+     */
+    public static BackgroundManager getInstance(Activity activity) {
+        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
+                .findFragmentByTag(FRAGMENT_TAG);
+        if (fragment != null) {
+            BackgroundManager manager = fragment.getBackgroundManager();
+            if (manager != null) {
+                return manager;
+            }
+            // manager is null: this is a fragment restored by FragmentManager,
+            // fall through to create a BackgroundManager attach to it.
+        }
+        return new BackgroundManager(activity);
+    }
+
+    private BackgroundManager(Activity activity) {
+        mContext = activity;
+        mService = BackgroundContinuityService.getInstance();
+        mHeightPx = mContext.getResources().getDisplayMetrics().heightPixels;
+        mWidthPx = mContext.getResources().getDisplayMetrics().widthPixels;
+        mHandler = new Handler();
+
+        Interpolator defaultInterpolator = new FastOutLinearInInterpolator();
+        mAccelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.anim.accelerate_interpolator);
+        mDecelerateInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.anim.decelerate_interpolator);
+
+        mAnimator = ValueAnimator.ofInt(0, FULL_ALPHA);
+        mAnimator.addListener(mAnimationListener);
+        mAnimator.addUpdateListener(mAnimationUpdateListener);
+        mAnimator.setInterpolator(defaultInterpolator);
+
+        TypedArray ta = activity.getTheme().obtainStyledAttributes(new int[] {
+                android.R.attr.windowBackground });
+        mThemeDrawableResourceId = ta.getResourceId(0, -1);
+        if (mThemeDrawableResourceId < 0) {
+            if (DEBUG) Log.v(TAG, "BackgroundManager no window background resource!");
+        }
+        ta.recycle();
+
+        createFragment(activity);
+    }
+
+    private void createFragment(Activity activity) {
+        // Use a fragment to ensure the background manager gets detached properly.
+        BackgroundFragment fragment = (BackgroundFragment) activity.getFragmentManager()
+                .findFragmentByTag(FRAGMENT_TAG);
+        if (fragment == null) {
+            fragment = new BackgroundFragment();
+            activity.getFragmentManager().beginTransaction().add(fragment, FRAGMENT_TAG).commit();
+        } else {
+            if (fragment.getBackgroundManager() != null) {
+                throw new IllegalStateException("Created duplicated BackgroundManager for same "
+                        + "activity, please use getInstance() instead");
+            }
+        }
+        fragment.setBackgroundManager(this);
+        mFragmentState = fragment;
+    }
+
+    DrawableWrapper getImageInWrapper() {
+        return mLayerDrawable == null
+                ? null : mLayerDrawable.mWrapper[mImageInWrapperIndex];
+    }
+
+    DrawableWrapper getImageOutWrapper() {
+        return mLayerDrawable == null
+                ? null : mLayerDrawable.mWrapper[mImageOutWrapperIndex];
+    }
+
+    /**
+     * Synchronizes state when the owning Activity is started.
+     * At that point the view becomes visible.
+     */
+    void onActivityStart() {
+        updateImmediate();
+    }
+
+    void onStop() {
+        if (isAutoReleaseOnStop()) {
+            release();
+        }
+    }
+
+    void onResume() {
+        if (DEBUG) Log.v(TAG, "onResume " + this);
+        postChangeRunnable();
+    }
+
+    private void syncWithService() {
+        int color = mService.getColor();
+        Drawable drawable = mService.getDrawable();
+
+        if (DEBUG) Log.v(TAG, "syncWithService color " + Integer.toHexString(color)
+                + " drawable " + drawable);
+
+        mBackgroundColor = color;
+        mBackgroundDrawable = drawable == null ? null :
+            drawable.getConstantState().newDrawable().mutate();
+
+        updateImmediate();
+    }
+
+    /**
+     * Makes the background visible on the given Window. The background manager must be attached
+     * when the background is set.
+     */
+    public void attach(Window window) {
+        attachToViewInternal(window.getDecorView());
+    }
+
+    /**
+     * Sets the resource id for the drawable to be shown when there is no background set.
+     * Overrides the window background drawable from the theme. This should
+     * be called before attaching.
+     */
+    public void setThemeDrawableResourceId(int resourceId) {
+        mThemeDrawableResourceId = resourceId;
+    }
+
+    /**
+     * Adds the composite drawable to the given view.
+     */
+    public void attachToView(View sceneRoot) {
+        attachToViewInternal(sceneRoot);
+        // clear background to reduce overdraw since the View will act as background.
+        // Activity transition below O has ghost effect for null window background where we
+        // need set a transparent background to force redraw the whole window.
+        mContext.getWindow().getDecorView().setBackground(
+                Build.VERSION.SDK_INT >= 26 ? null : new ColorDrawable(Color.TRANSPARENT));
+    }
+
+    void attachToViewInternal(View sceneRoot) {
+        if (mAttached) {
+            throw new IllegalStateException("Already attached to " + mBgView);
+        }
+        mBgView = sceneRoot;
+        mAttached = true;
+        syncWithService();
+    }
+
+    /**
+     * Returns true if the background manager is currently attached; false otherwise.
+     */
+    public boolean isAttached() {
+        return mAttached;
+    }
+
+    /**
+     * Release references to Drawables and put the BackgroundManager into the
+     * detached state. Called when the associated Activity is destroyed.
+     */
+    void detach() {
+        if (DEBUG) Log.v(TAG, "detach " + this);
+        release();
+
+        mBgView = null;
+        mAttached = false;
+
+        if (mService != null) {
+            mService.unref();
+            mService = null;
+        }
+    }
+
+    /**
+     * Release references to Drawable/Bitmap. Typically called in Activity onStop() to reduce memory
+     * overhead when not visible. It's app's responsibility to restore the drawable/bitmap in
+     * Activity onStart(). The method is automatically called in onStop() when
+     * {@link #isAutoReleaseOnStop()} is true.
+     * @see #setAutoReleaseOnStop(boolean)
+     */
+    public void release() {
+        if (DEBUG) Log.v(TAG, "release " + this);
+        if (mChangeRunnable != null) {
+            mHandler.removeCallbacks(mChangeRunnable);
+            mChangeRunnable = null;
+        }
+        if (mAnimator.isStarted()) {
+            mAnimator.cancel();
+        }
+        if (mLayerDrawable != null) {
+            mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
+            mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
+            mLayerDrawable = null;
+        }
+        mBackgroundDrawable = null;
+    }
+
+    /**
+     * Sets the drawable used as a dim layer.
+     * @deprecated No longer support dim layer.
+     */
+    @Deprecated
+    public void setDimLayer(Drawable drawable) {
+    }
+
+    /**
+     * Returns the drawable used as a dim layer.
+     * @deprecated No longer support dim layer.
+     */
+    @Deprecated
+    public Drawable getDimLayer() {
+        return null;
+    }
+
+    /**
+     * Returns the default drawable used as a dim layer.
+     * @deprecated No longer support dim layer.
+     */
+    @Deprecated
+    public Drawable getDefaultDimLayer() {
+        return ContextCompat.getDrawable(mContext, R.color.lb_background_protection);
+    }
+
+    void postChangeRunnable() {
+        if (mChangeRunnable == null || !mChangeRunnablePending) {
+            return;
+        }
+
+        // Postpone a pending change runnable until: no existing change animation in progress &&
+        // activity is resumed (in the foreground) && layerdrawable fully opaque.
+        // If the layerdrawable is translucent then an activity transition is in progress
+        // and we want to use the optimized drawing path for performance reasons (see
+        // OptimizedTranslucentLayerDrawable).
+        if (mAnimator.isStarted()) {
+            if (DEBUG) Log.v(TAG, "animation in progress");
+        } else if (!mFragmentState.isResumed()) {
+            if (DEBUG) Log.v(TAG, "not resumed");
+        } else if (mLayerDrawable.getAlpha() < FULL_ALPHA) {
+            if (DEBUG) Log.v(TAG, "in transition, alpha " + mLayerDrawable.getAlpha());
+        } else {
+            long delayMs = getRunnableDelay();
+            if (DEBUG) Log.v(TAG, "posting runnable delayMs " + delayMs);
+            mLastSetTime = System.currentTimeMillis();
+            mHandler.postDelayed(mChangeRunnable, delayMs);
+            mChangeRunnablePending = false;
+        }
+    }
+
+    private void lazyInit() {
+        if (mLayerDrawable != null) {
+            return;
+        }
+
+        LayerDrawable layerDrawable = (LayerDrawable)
+                ContextCompat.getDrawable(mContext, R.drawable.lb_background).mutate();
+        mLayerDrawable = createTranslucentLayerDrawable(layerDrawable);
+        mImageInWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imagein);
+        mImageOutWrapperIndex = mLayerDrawable.findWrapperIndexById(R.id.background_imageout);
+        BackgroundHelper.setBackgroundPreservingAlpha(mBgView, mLayerDrawable);
+    }
+
+    private void updateImmediate() {
+        if (!mAttached) {
+            return;
+        }
+        lazyInit();
+
+        if (mBackgroundDrawable == null) {
+            if (DEBUG) Log.v(TAG, "Use defefault background");
+            mLayerDrawable.updateDrawable(R.id.background_imagein, getDefaultDrawable());
+        } else {
+            if (DEBUG) Log.v(TAG, "Background drawable is available " + mBackgroundDrawable);
+            mLayerDrawable.updateDrawable(R.id.background_imagein, mBackgroundDrawable);
+        }
+        mLayerDrawable.clearDrawable(R.id.background_imageout, mContext);
+    }
+
+    /**
+     * Sets the background to the given color. The timing for when this becomes
+     * visible in the app is undefined and may take place after a small delay.
+     */
+    public void setColor(@ColorInt int color) {
+        if (DEBUG) Log.v(TAG, "setColor " + Integer.toHexString(color));
+
+        mService.setColor(color);
+        mBackgroundColor = color;
+        mBackgroundDrawable = null;
+        if (mLayerDrawable == null) {
+            return;
+        }
+        setDrawableInternal(getDefaultDrawable());
+    }
+
+    /**
+     * Sets the given drawable into the background. The provided Drawable will be
+     * used unmodified as the background, without any scaling or cropping
+     * applied to it. The timing for when this becomes visible in the app is
+     * undefined and may take place after a small delay.
+     */
+    public void setDrawable(Drawable drawable) {
+        if (DEBUG) Log.v(TAG, "setBackgroundDrawable " + drawable);
+
+        mService.setDrawable(drawable);
+        mBackgroundDrawable = drawable;
+        if (mLayerDrawable == null) {
+            return;
+        }
+        if (drawable == null) {
+            setDrawableInternal(getDefaultDrawable());
+        } else {
+            setDrawableInternal(drawable);
+        }
+    }
+
+    /**
+     * Clears the Drawable set by {@link #setDrawable(Drawable)} or {@link #setBitmap(Bitmap)}.
+     * BackgroundManager will show a solid color set by {@link #setColor(int)} or theme drawable
+     * if color is not provided.
+     */
+    public void clearDrawable() {
+        setDrawable(null);
+    }
+
+    private void setDrawableInternal(Drawable drawable) {
+        if (!mAttached) {
+            throw new IllegalStateException("Must attach before setting background drawable");
+        }
+
+        if (mChangeRunnable != null) {
+            if (sameDrawable(drawable, mChangeRunnable.mDrawable)) {
+                if (DEBUG) Log.v(TAG, "new drawable same as pending");
+                return;
+            }
+            mHandler.removeCallbacks(mChangeRunnable);
+            mChangeRunnable = null;
+        }
+
+        mChangeRunnable = new ChangeBackgroundRunnable(drawable);
+        mChangeRunnablePending = true;
+
+        postChangeRunnable();
+    }
+
+    private long getRunnableDelay() {
+        return Math.max(0, mLastSetTime + CHANGE_BG_DELAY_MS - System.currentTimeMillis());
+    }
+
+    /**
+     * Sets the given bitmap into the background. When using setCoverImageBitmap to set the
+     * background, the provided bitmap will be scaled and cropped to correctly
+     * fit within the dimensions of the view. The timing for when this becomes
+     * visible in the app is undefined and may take place after a small delay.
+     */
+    public void setBitmap(Bitmap bitmap) {
+        if (DEBUG) {
+            Log.v(TAG, "setCoverImageBitmap " + bitmap);
+        }
+
+        if (bitmap == null) {
+            setDrawable(null);
+            return;
+        }
+
+        if (bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
+            if (DEBUG) {
+                Log.v(TAG, "invalid bitmap width or height");
+            }
+            return;
+        }
+
+        Matrix matrix = null;
+
+        if ((bitmap.getWidth() != mWidthPx || bitmap.getHeight() != mHeightPx)) {
+            int dwidth = bitmap.getWidth();
+            int dheight = bitmap.getHeight();
+            float scale;
+
+            // Scale proportionately to fit width and height.
+            if (dwidth * mHeightPx > mWidthPx * dheight) {
+                scale = (float) mHeightPx / (float) dheight;
+            } else {
+                scale = (float) mWidthPx / (float) dwidth;
+            }
+
+            int subX = Math.min((int) (mWidthPx / scale), dwidth);
+            int dx = Math.max(0, (dwidth - subX) / 2);
+
+            matrix = new Matrix();
+            matrix.setScale(scale, scale);
+            matrix.preTranslate(-dx, 0);
+
+            if (DEBUG) {
+                Log.v(TAG, "original image size " + bitmap.getWidth() + "x" + bitmap.getHeight()
+                        + " scale " + scale + " dx " + dx);
+            }
+        }
+
+        BitmapDrawable bitmapDrawable = new BitmapDrawable(mContext.getResources(), bitmap, matrix);
+
+        setDrawable(bitmapDrawable);
+    }
+
+    /**
+     * Enable or disable call release() in Activity onStop(). Default is true.
+     * @param autoReleaseOnStop True to call release() in Activity onStop(), false otherwise.
+     */
+    public void setAutoReleaseOnStop(boolean autoReleaseOnStop) {
+        mAutoReleaseOnStop = autoReleaseOnStop;
+    }
+
+    /**
+     * @return True if release() in Activity.onStop(), false otherwise.
+     */
+    public boolean isAutoReleaseOnStop() {
+        return mAutoReleaseOnStop;
+    }
+
+    /**
+     * Returns the current background color.
+     */
+    @ColorInt
+    public final int getColor() {
+        return mBackgroundColor;
+    }
+
+    /**
+     * Returns the current background {@link Drawable}.
+     */
+    public Drawable getDrawable() {
+        return mBackgroundDrawable;
+    }
+
+    boolean sameDrawable(Drawable first, Drawable second) {
+        if (first == null || second == null) {
+            return false;
+        }
+        if (first == second) {
+            return true;
+        }
+        if (first instanceof BitmapDrawable && second instanceof BitmapDrawable) {
+            if (((BitmapDrawable) first).getBitmap().sameAs(((BitmapDrawable) second).getBitmap())) {
+                return true;
+            }
+        }
+        if (first instanceof ColorDrawable && second instanceof ColorDrawable) {
+            if (((ColorDrawable) first).getColor() == ((ColorDrawable) second).getColor()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Task which changes the background.
+     */
+    final class ChangeBackgroundRunnable implements Runnable {
+        final Drawable mDrawable;
+
+        ChangeBackgroundRunnable(Drawable drawable) {
+            mDrawable = drawable;
+        }
+
+        @Override
+        public void run() {
+            runTask();
+            mChangeRunnable = null;
+        }
+
+        private void runTask() {
+            if (mLayerDrawable == null) {
+                if (DEBUG) Log.v(TAG, "runTask while released - should not happen");
+                return;
+            }
+
+            DrawableWrapper imageInWrapper = getImageInWrapper();
+            if (imageInWrapper != null) {
+                if (sameDrawable(mDrawable, imageInWrapper.getDrawable())) {
+                    if (DEBUG) Log.v(TAG, "new drawable same as current");
+                    return;
+                }
+
+                if (DEBUG) Log.v(TAG, "moving image in to image out");
+                // Order is important! Setting a drawable "removes" the
+                // previous one from the view
+                mLayerDrawable.clearDrawable(R.id.background_imagein, mContext);
+                mLayerDrawable.updateDrawable(R.id.background_imageout,
+                        imageInWrapper.getDrawable());
+            }
+
+            applyBackgroundChanges();
+        }
+
+        void applyBackgroundChanges() {
+            if (!mAttached) {
+                return;
+            }
+
+            if (DEBUG) Log.v(TAG, "applyBackgroundChanges drawable " + mDrawable);
+
+            DrawableWrapper imageInWrapper = getImageInWrapper();
+            if (imageInWrapper == null && mDrawable != null) {
+                if (DEBUG) Log.v(TAG, "creating new imagein drawable");
+                imageInWrapper = mLayerDrawable.updateDrawable(
+                        R.id.background_imagein, mDrawable);
+                if (DEBUG) Log.v(TAG, "imageInWrapper animation starting");
+                mLayerDrawable.setWrapperAlpha(mImageInWrapperIndex, 0);
+            }
+
+            mAnimator.setDuration(FADE_DURATION);
+            mAnimator.start();
+
+        }
+
+    }
+
+    static class EmptyDrawable extends BitmapDrawable {
+        EmptyDrawable(Resources res) {
+            super(res, (Bitmap) null);
+        }
+    }
+
+    static Drawable createEmptyDrawable(Context context) {
+        return new EmptyDrawable(context.getResources());
+    }
+
+}
diff --git a/leanback/src/android/support/v17/leanback/app/BaseFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BaseFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/BaseFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/BaseFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/BaseRowFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BaseRowFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/BaseRowFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/BaseRowFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/BaseRowSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BaseRowSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/BaseRowSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/BaseRowSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BaseSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/BaseSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/BaseSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/BrandedFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BrandedFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/BrandedFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/BrandedFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/BrandedSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BrandedSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/BrandedSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/BrandedSupportFragment.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/BrowseFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BrowseFragment.java
new file mode 100644
index 0000000..d98287e
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/BrowseFragment.java
@@ -0,0 +1,1871 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from BrowseSupportFragment.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.transition.TransitionListener;
+import android.support.v17.leanback.util.StateMachine.Event;
+import android.support.v17.leanback.util.StateMachine.State;
+import android.support.v17.leanback.widget.BrowseFrameLayout;
+import android.support.v17.leanback.widget.InvisibleRowPresenter;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.PageRow;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowHeaderPresenter;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.ScaleFrameLayout;
+import android.support.v17.leanback.widget.TitleViewAdapter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentManager.BackStackEntry;
+import android.app.FragmentTransaction;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.ViewTreeObserver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A fragment for creating Leanback browse screens. It is composed of a
+ * RowsFragment and a HeadersFragment.
+ * <p>
+ * A BrowseFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list. The elements in this adapter must be subclasses
+ * of {@link Row}.
+ * <p>
+ * The HeadersFragment can be set to be either shown or hidden by default, or
+ * may be disabled entirely. See {@link #setHeadersState} for details.
+ * <p>
+ * By default the BrowseFragment includes support for returning to the headers
+ * when the user presses Back. For Activities that customize {@link
+ * android.app.Activity#onBackPressed()}, you must disable this default Back key support by
+ * calling {@link #setHeadersTransitionOnBackEnabled(boolean)} with false and
+ * use {@link BrowseFragment.BrowseTransitionListener} and
+ * {@link #startHeadersTransition(boolean)}.
+ * <p>
+ * The recommended theme to use with a BrowseFragment is
+ * {@link android.support.v17.leanback.R.style#Theme_Leanback_Browse}.
+ * </p>
+ * @deprecated use {@link BrowseSupportFragment}
+ */
+@Deprecated
+public class BrowseFragment extends BaseFragment {
+
+    // BUNDLE attribute for saving header show/hide status when backstack is used:
+    static final String HEADER_STACK_INDEX = "headerStackIndex";
+    // BUNDLE attribute for saving header show/hide status when backstack is not used:
+    static final String HEADER_SHOW = "headerShow";
+    private static final String IS_PAGE_ROW = "isPageRow";
+    private static final String CURRENT_SELECTED_POSITION = "currentSelectedPosition";
+
+    /**
+     * State to hide headers fragment.
+     */
+    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
+        @Override
+        public void run() {
+            setEntranceTransitionStartState();
+        }
+    };
+
+    /**
+     * Event for Header fragment view is created, we could perform
+     * {@link #setEntranceTransitionStartState()} to hide headers fragment initially.
+     */
+    final Event EVT_HEADER_VIEW_CREATED = new Event("headerFragmentViewCreated");
+
+    /**
+     * Event for {@link #getMainFragment()} view is created, it's additional requirement to execute
+     * {@link #onEntranceTransitionPrepare()}.
+     */
+    final Event EVT_MAIN_FRAGMENT_VIEW_CREATED = new Event("mainFragmentViewCreated");
+
+    /**
+     * Event that data for the screen is ready, this is additional requirement to launch entrance
+     * transition.
+     */
+    final Event EVT_SCREEN_DATA_READY = new Event("screenDataReady");
+
+    @Override
+    void createStateMachineStates() {
+        super.createStateMachineStates();
+        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
+    }
+
+    @Override
+    void createStateMachineTransitions() {
+        super.createStateMachineTransitions();
+        // when headers fragment view is created we could setEntranceTransitionStartState()
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED, STATE_SET_ENTRANCE_START_STATE,
+                EVT_HEADER_VIEW_CREATED);
+
+        // add additional requirement for onEntranceTransitionPrepare()
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
+                STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
+                EVT_MAIN_FRAGMENT_VIEW_CREATED);
+        // add additional requirement to launch entrance transition.
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,  STATE_ENTRANCE_PERFORM,
+                EVT_SCREEN_DATA_READY);
+    }
+
+    final class BackStackListener implements FragmentManager.OnBackStackChangedListener {
+        int mLastEntryCount;
+        int mIndexOfHeadersBackStack;
+
+        BackStackListener() {
+            mLastEntryCount = getFragmentManager().getBackStackEntryCount();
+            mIndexOfHeadersBackStack = -1;
+        }
+
+        void load(Bundle savedInstanceState) {
+            if (savedInstanceState != null) {
+                mIndexOfHeadersBackStack = savedInstanceState.getInt(HEADER_STACK_INDEX, -1);
+                mShowingHeaders = mIndexOfHeadersBackStack == -1;
+            } else {
+                if (!mShowingHeaders) {
+                    getFragmentManager().beginTransaction()
+                            .addToBackStack(mWithHeadersBackStackName).commit();
+                }
+            }
+        }
+
+        void save(Bundle outState) {
+            outState.putInt(HEADER_STACK_INDEX, mIndexOfHeadersBackStack);
+        }
+
+
+        @Override
+        public void onBackStackChanged() {
+            if (getFragmentManager() == null) {
+                Log.w(TAG, "getFragmentManager() is null, stack:", new Exception());
+                return;
+            }
+            int count = getFragmentManager().getBackStackEntryCount();
+            // if backstack is growing and last pushed entry is "headers" backstack,
+            // remember the index of the entry.
+            if (count > mLastEntryCount) {
+                BackStackEntry entry = getFragmentManager().getBackStackEntryAt(count - 1);
+                if (mWithHeadersBackStackName.equals(entry.getName())) {
+                    mIndexOfHeadersBackStack = count - 1;
+                }
+            } else if (count < mLastEntryCount) {
+                // if popped "headers" backstack, initiate the show header transition if needed
+                if (mIndexOfHeadersBackStack >= count) {
+                    if (!isHeadersDataReady()) {
+                        // if main fragment was restored first before BrowseFragment's adapter gets
+                        // restored: don't start header transition, but add the entry back.
+                        getFragmentManager().beginTransaction()
+                                .addToBackStack(mWithHeadersBackStackName).commit();
+                        return;
+                    }
+                    mIndexOfHeadersBackStack = -1;
+                    if (!mShowingHeaders) {
+                        startHeadersTransitionInternal(true);
+                    }
+                }
+            }
+            mLastEntryCount = count;
+        }
+    }
+
+    /**
+     * Listener for transitions between browse headers and rows.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public static class BrowseTransitionListener {
+        /**
+         * Callback when headers transition starts.
+         *
+         * @param withHeaders True if the transition will result in headers
+         *        being shown, false otherwise.
+         */
+        public void onHeadersTransitionStart(boolean withHeaders) {
+        }
+        /**
+         * Callback when headers transition stops.
+         *
+         * @param withHeaders True if the transition will result in headers
+         *        being shown, false otherwise.
+         */
+        public void onHeadersTransitionStop(boolean withHeaders) {
+        }
+    }
+
+    private class SetSelectionRunnable implements Runnable {
+        static final int TYPE_INVALID = -1;
+        static final int TYPE_INTERNAL_SYNC = 0;
+        static final int TYPE_USER_REQUEST = 1;
+
+        private int mPosition;
+        private int mType;
+        private boolean mSmooth;
+
+        SetSelectionRunnable() {
+            reset();
+        }
+
+        void post(int position, int type, boolean smooth) {
+            // Posting the set selection, rather than calling it immediately, prevents an issue
+            // with adapter changes.  Example: a row is added before the current selected row;
+            // first the fast lane view updates its selection, then the rows fragment has that
+            // new selection propagated immediately; THEN the rows view processes the same adapter
+            // change and moves the selection again.
+            if (type >= mType) {
+                mPosition = position;
+                mType = type;
+                mSmooth = smooth;
+                mBrowseFrame.removeCallbacks(this);
+                mBrowseFrame.post(this);
+            }
+        }
+
+        @Override
+        public void run() {
+            setSelection(mPosition, mSmooth);
+            reset();
+        }
+
+        private void reset() {
+            mPosition = -1;
+            mType = TYPE_INVALID;
+            mSmooth = false;
+        }
+    }
+
+    /**
+     * Possible set of actions that {@link BrowseFragment} exposes to clients. Custom
+     * fragments can interact with {@link BrowseFragment} using this interface.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public interface FragmentHost {
+        /**
+         * Fragments are required to invoke this callback once their view is created
+         * inside {@link Fragment#onViewCreated} method. {@link BrowseFragment} starts the entrance
+         * animation only after receiving this callback. Failure to invoke this method
+         * will lead to fragment not showing up.
+         *
+         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
+         */
+        void notifyViewCreated(MainFragmentAdapter fragmentAdapter);
+
+        /**
+         * Fragments mapped to {@link PageRow} are required to invoke this callback once their data
+         * is created for transition, the entrance animation only after receiving this callback.
+         * Failure to invoke this method will lead to fragment not showing up.
+         *
+         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
+         */
+        void notifyDataReady(MainFragmentAdapter fragmentAdapter);
+
+        /**
+         * Show or hide title view in {@link BrowseFragment} for fragments mapped to
+         * {@link PageRow}.  Otherwise the request is ignored, in that case BrowseFragment is fully
+         * in control of showing/hiding title view.
+         * <p>
+         * When HeadersFragment is visible, BrowseFragment will hide search affordance view if
+         * there are other focusable rows above currently focused row.
+         *
+         * @param show Boolean indicating whether or not to show the title view.
+         */
+        void showTitleView(boolean show);
+    }
+
+    /**
+     * Default implementation of {@link FragmentHost} that is used only by
+     * {@link BrowseFragment}.
+     */
+    private final class FragmentHostImpl implements FragmentHost {
+        boolean mShowTitleView = true;
+
+        FragmentHostImpl() {
+        }
+
+        @Override
+        public void notifyViewCreated(MainFragmentAdapter fragmentAdapter) {
+            mStateMachine.fireEvent(EVT_MAIN_FRAGMENT_VIEW_CREATED);
+            if (!mIsPageRow) {
+                // If it's not a PageRow: it's a ListRow, so we already have data ready.
+                mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
+            }
+        }
+
+        @Override
+        public void notifyDataReady(MainFragmentAdapter fragmentAdapter) {
+            // If fragment host is not the currently active fragment (in BrowseFragment), then
+            // ignore the request.
+            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
+                return;
+            }
+
+            // We only honor showTitle request for PageRows.
+            if (!mIsPageRow) {
+                return;
+            }
+
+            mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
+        }
+
+        @Override
+        public void showTitleView(boolean show) {
+            mShowTitleView = show;
+
+            // If fragment host is not the currently active fragment (in BrowseFragment), then
+            // ignore the request.
+            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
+                return;
+            }
+
+            // We only honor showTitle request for PageRows.
+            if (!mIsPageRow) {
+                return;
+            }
+
+            updateTitleViewVisibility();
+        }
+    }
+
+    /**
+     * Interface that defines the interaction between {@link BrowseFragment} and its main
+     * content fragment. The key method is {@link MainFragmentAdapter#getFragment()},
+     * it will be used to get the fragment to be shown in the content section. Clients can
+     * provide any implementation of fragment and customize its interaction with
+     * {@link BrowseFragment} by overriding the necessary methods.
+     *
+     * <p>
+     * Clients are expected to provide
+     * an instance of {@link MainFragmentAdapterRegistry} which will be responsible for providing
+     * implementations of {@link MainFragmentAdapter} for given content types. Currently
+     * we support different types of content - {@link ListRow}, {@link PageRow} or any subtype
+     * of {@link Row}. We provide an out of the box adapter implementation for any rows other than
+     * {@link PageRow} - {@link android.support.v17.leanback.app.RowsFragment.MainFragmentAdapter}.
+     *
+     * <p>
+     * {@link PageRow} is intended to give full flexibility to developers in terms of Fragment
+     * design. Users will have to provide an implementation of {@link MainFragmentAdapter}
+     * and provide that through {@link MainFragmentAdapterRegistry}.
+     * {@link MainFragmentAdapter} implementation can supply any fragment and override
+     * just those interactions that makes sense.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public static class MainFragmentAdapter<T extends Fragment> {
+        private boolean mScalingEnabled;
+        private final T mFragment;
+        FragmentHostImpl mFragmentHost;
+
+        public MainFragmentAdapter(T fragment) {
+            this.mFragment = fragment;
+        }
+
+        public final T getFragment() {
+            return mFragment;
+        }
+
+        /**
+         * Returns whether its scrolling.
+         */
+        public boolean isScrolling() {
+            return false;
+        }
+
+        /**
+         * Set the visibility of titles/hover card of browse rows.
+         */
+        public void setExpand(boolean expand) {
+        }
+
+        /**
+         * For rows that willing to participate entrance transition,  this function
+         * hide views if afterTransition is true,  show views if afterTransition is false.
+         */
+        public void setEntranceTransitionState(boolean state) {
+        }
+
+        /**
+         * Sets the window alignment and also the pivots for scale operation.
+         */
+        public void setAlignment(int windowAlignOffsetFromTop) {
+        }
+
+        /**
+         * Callback indicating transition prepare start.
+         */
+        public boolean onTransitionPrepare() {
+            return false;
+        }
+
+        /**
+         * Callback indicating transition start.
+         */
+        public void onTransitionStart() {
+        }
+
+        /**
+         * Callback indicating transition end.
+         */
+        public void onTransitionEnd() {
+        }
+
+        /**
+         * Returns whether row scaling is enabled.
+         */
+        public boolean isScalingEnabled() {
+            return mScalingEnabled;
+        }
+
+        /**
+         * Sets the row scaling property.
+         */
+        public void setScalingEnabled(boolean scalingEnabled) {
+            this.mScalingEnabled = scalingEnabled;
+        }
+
+        /**
+         * Returns the current host interface so that main fragment can interact with
+         * {@link BrowseFragment}.
+         */
+        public final FragmentHost getFragmentHost() {
+            return mFragmentHost;
+        }
+
+        void setFragmentHost(FragmentHostImpl fragmentHost) {
+            this.mFragmentHost = fragmentHost;
+        }
+    }
+
+    /**
+     * Interface to be implemented by all fragments for providing an instance of
+     * {@link MainFragmentAdapter}. Both {@link RowsFragment} and custom fragment provided
+     * against {@link PageRow} will need to implement this interface.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public interface MainFragmentAdapterProvider {
+        /**
+         * Returns an instance of {@link MainFragmentAdapter} that {@link BrowseFragment}
+         * would use to communicate with the target fragment.
+         */
+        MainFragmentAdapter getMainFragmentAdapter();
+    }
+
+    /**
+     * Interface to be implemented by {@link RowsFragment} and its subclasses for providing
+     * an instance of {@link MainFragmentRowsAdapter}.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public interface MainFragmentRowsAdapterProvider {
+        /**
+         * Returns an instance of {@link MainFragmentRowsAdapter} that {@link BrowseFragment}
+         * would use to communicate with the target fragment.
+         */
+        MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+    }
+
+    /**
+     * This is used to pass information to {@link RowsFragment} or its subclasses.
+     * {@link BrowseFragment} uses this interface to pass row based interaction events to
+     * the target fragment.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public static class MainFragmentRowsAdapter<T extends Fragment> {
+        private final T mFragment;
+
+        public MainFragmentRowsAdapter(T fragment) {
+            if (fragment == null) {
+                throw new IllegalArgumentException("Fragment can't be null");
+            }
+            this.mFragment = fragment;
+        }
+
+        public final T getFragment() {
+            return mFragment;
+        }
+        /**
+         * Set the visibility titles/hover of browse rows.
+         */
+        public void setAdapter(ObjectAdapter adapter) {
+        }
+
+        /**
+         * Sets an item clicked listener on the fragment.
+         */
+        public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+        }
+
+        /**
+         * Sets an item selection listener.
+         */
+        public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
+        }
+
+        /**
+         * Selects a Row and perform an optional task on the Row.
+         */
+        public void setSelectedPosition(int rowPosition,
+                                        boolean smooth,
+                                        final Presenter.ViewHolderTask rowHolderTask) {
+        }
+
+        /**
+         * Selects a Row.
+         */
+        public void setSelectedPosition(int rowPosition, boolean smooth) {
+        }
+
+        /**
+         * @return The position of selected row.
+         */
+        public int getSelectedPosition() {
+            return 0;
+        }
+
+        /**
+         * @param position Position of Row.
+         * @return Row ViewHolder.
+         */
+        public RowPresenter.ViewHolder findRowViewHolderByPosition(int position) {
+            return null;
+        }
+    }
+
+    private boolean createMainFragment(ObjectAdapter adapter, int position) {
+        Object item = null;
+        if (!mCanShowHeaders) {
+            // when header is disabled, we can decide to use RowsFragment even no data.
+        } else if (adapter == null || adapter.size() == 0) {
+            return false;
+        } else {
+            if (position < 0) {
+                position = 0;
+            } else if (position >= adapter.size()) {
+                throw new IllegalArgumentException(
+                        String.format("Invalid position %d requested", position));
+            }
+            item = adapter.get(position);
+        }
+
+        boolean oldIsPageRow = mIsPageRow;
+        Object oldPageRow = mPageRow;
+        mIsPageRow = mCanShowHeaders && item instanceof PageRow;
+        mPageRow = mIsPageRow ? item : null;
+        boolean swap;
+
+        if (mMainFragment == null) {
+            swap = true;
+        } else {
+            if (oldIsPageRow) {
+                if (mIsPageRow) {
+                    if (oldPageRow == null) {
+                        // fragment is restored, page row object not yet set, so just set the
+                        // mPageRow object and there is no need to replace the fragment
+                        swap = false;
+                    } else {
+                        // swap if page row object changes
+                        swap = oldPageRow != mPageRow;
+                    }
+                } else {
+                    swap = true;
+                }
+            } else {
+                swap = mIsPageRow;
+            }
+        }
+
+        if (swap) {
+            mMainFragment = mMainFragmentAdapterRegistry.createFragment(item);
+            if (!(mMainFragment instanceof MainFragmentAdapterProvider)) {
+                throw new IllegalArgumentException(
+                        "Fragment must implement MainFragmentAdapterProvider");
+            }
+
+            setMainFragmentAdapter();
+        }
+
+        return swap;
+    }
+
+    void setMainFragmentAdapter() {
+        mMainFragmentAdapter = ((MainFragmentAdapterProvider) mMainFragment)
+                .getMainFragmentAdapter();
+        mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
+        if (!mIsPageRow) {
+            if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
+                setMainFragmentRowsAdapter(((MainFragmentRowsAdapterProvider) mMainFragment)
+                        .getMainFragmentRowsAdapter());
+            } else {
+                setMainFragmentRowsAdapter(null);
+            }
+            mIsPageRow = mMainFragmentRowsAdapter == null;
+        } else {
+            setMainFragmentRowsAdapter(null);
+        }
+    }
+
+    /**
+     * Factory class responsible for creating fragment given the current item. {@link ListRow}
+     * should return {@link RowsFragment} or its subclass whereas {@link PageRow}
+     * can return any fragment class.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public abstract static class FragmentFactory<T extends Fragment> {
+        public abstract T createFragment(Object row);
+    }
+
+    /**
+     * FragmentFactory implementation for {@link ListRow}.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public static class ListRowFragmentFactory extends FragmentFactory<RowsFragment> {
+        @Override
+        public RowsFragment createFragment(Object row) {
+            return new RowsFragment();
+        }
+    }
+
+    /**
+     * Registry class maintaining the mapping of {@link Row} subclasses to {@link FragmentFactory}.
+     * BrowseRowFragment automatically registers {@link ListRowFragmentFactory} for
+     * handling {@link ListRow}. Developers can override that and also if they want to
+     * use custom fragment, they can register a custom {@link FragmentFactory}
+     * against {@link PageRow}.
+     * @deprecated use {@link BrowseSupportFragment}
+     */
+    @Deprecated
+    public final static class MainFragmentAdapterRegistry {
+        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
+        private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
+
+        public MainFragmentAdapterRegistry() {
+            registerFragment(ListRow.class, sDefaultFragmentFactory);
+        }
+
+        public void registerFragment(Class rowClass, FragmentFactory factory) {
+            mItemToFragmentFactoryMapping.put(rowClass, factory);
+        }
+
+        public Fragment createFragment(Object item) {
+            FragmentFactory fragmentFactory = item == null ? sDefaultFragmentFactory :
+                    mItemToFragmentFactoryMapping.get(item.getClass());
+            if (fragmentFactory == null && !(item instanceof PageRow)) {
+                fragmentFactory = sDefaultFragmentFactory;
+            }
+
+            return fragmentFactory.createFragment(item);
+        }
+    }
+
+    static final String TAG = "BrowseFragment";
+
+    private static final String LB_HEADERS_BACKSTACK = "lbHeadersBackStack_";
+
+    static final boolean DEBUG = false;
+
+    /** The headers fragment is enabled and shown by default. */
+    public static final int HEADERS_ENABLED = 1;
+
+    /** The headers fragment is enabled and hidden by default. */
+    public static final int HEADERS_HIDDEN = 2;
+
+    /** The headers fragment is disabled and will never be shown. */
+    public static final int HEADERS_DISABLED = 3;
+
+    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry =
+            new MainFragmentAdapterRegistry();
+    MainFragmentAdapter mMainFragmentAdapter;
+    Fragment mMainFragment;
+    HeadersFragment mHeadersFragment;
+    MainFragmentRowsAdapter mMainFragmentRowsAdapter;
+    ListRowDataAdapter mMainFragmentListRowDataAdapter;
+
+    private ObjectAdapter mAdapter;
+    private PresenterSelector mAdapterPresenter;
+
+    private int mHeadersState = HEADERS_ENABLED;
+    private int mBrandColor = Color.TRANSPARENT;
+    private boolean mBrandColorSet;
+
+    BrowseFrameLayout mBrowseFrame;
+    private ScaleFrameLayout mScaleFrameLayout;
+    boolean mHeadersBackStackEnabled = true;
+    String mWithHeadersBackStackName;
+    boolean mShowingHeaders = true;
+    boolean mCanShowHeaders = true;
+    private int mContainerListMarginStart;
+    private int mContainerListAlignTop;
+    private boolean mMainFragmentScaleEnabled = true;
+    OnItemViewSelectedListener mExternalOnItemViewSelectedListener;
+    private OnItemViewClickedListener mOnItemViewClickedListener;
+    private int mSelectedPosition = -1;
+    private float mScaleFactor;
+    boolean mIsPageRow;
+    Object mPageRow;
+
+    private PresenterSelector mHeaderPresenterSelector;
+    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    // transition related:
+    Object mSceneWithHeaders;
+    Object mSceneWithoutHeaders;
+    private Object mSceneAfterEntranceTransition;
+    Object mHeadersTransition;
+    BackStackListener mBackStackChangedListener;
+    BrowseTransitionListener mBrowseTransitionListener;
+
+    private static final String ARG_TITLE = BrowseFragment.class.getCanonicalName() + ".title";
+    private static final String ARG_HEADERS_STATE =
+        BrowseFragment.class.getCanonicalName() + ".headersState";
+
+    /**
+     * Creates arguments for a browse fragment.
+     *
+     * @param args The Bundle to place arguments into, or null if the method
+     *        should return a new Bundle.
+     * @param title The title of the BrowseFragment.
+     * @param headersState The initial state of the headers of the
+     *        BrowseFragment. Must be one of {@link #HEADERS_ENABLED}, {@link
+     *        #HEADERS_HIDDEN}, or {@link #HEADERS_DISABLED}.
+     * @return A Bundle with the given arguments for creating a BrowseFragment.
+     */
+    public static Bundle createArgs(Bundle args, String title, int headersState) {
+        if (args == null) {
+            args = new Bundle();
+        }
+        args.putString(ARG_TITLE, title);
+        args.putInt(ARG_HEADERS_STATE, headersState);
+        return args;
+    }
+
+    /**
+     * Sets the brand color for the browse fragment. The brand color is used as
+     * the primary color for UI elements in the browse fragment. For example,
+     * the background color of the headers fragment uses the brand color.
+     *
+     * @param color The color to use as the brand color of the fragment.
+     */
+    public void setBrandColor(@ColorInt int color) {
+        mBrandColor = color;
+        mBrandColorSet = true;
+
+        if (mHeadersFragment != null) {
+            mHeadersFragment.setBackgroundColor(mBrandColor);
+        }
+    }
+
+    /**
+     * Returns the brand color for the browse fragment.
+     * The default is transparent.
+     */
+    @ColorInt
+    public int getBrandColor() {
+        return mBrandColor;
+    }
+
+    /**
+     * Wrapping app provided PresenterSelector to support InvisibleRowPresenter for SectionRow
+     * DividerRow and PageRow.
+     */
+    private void updateWrapperPresenter() {
+        if (mAdapter == null) {
+            mAdapterPresenter = null;
+            return;
+        }
+        final PresenterSelector adapterPresenter = mAdapter.getPresenterSelector();
+        if (adapterPresenter == null) {
+            throw new IllegalArgumentException("Adapter.getPresenterSelector() is null");
+        }
+        if (adapterPresenter == mAdapterPresenter) {
+            return;
+        }
+        mAdapterPresenter = adapterPresenter;
+
+        Presenter[] presenters = adapterPresenter.getPresenters();
+        final Presenter invisibleRowPresenter = new InvisibleRowPresenter();
+        final Presenter[] allPresenters = new Presenter[presenters.length + 1];
+        System.arraycopy(allPresenters, 0, presenters, 0, presenters.length);
+        allPresenters[allPresenters.length - 1] = invisibleRowPresenter;
+        mAdapter.setPresenterSelector(new PresenterSelector() {
+            @Override
+            public Presenter getPresenter(Object item) {
+                Row row = (Row) item;
+                if (row.isRenderedAsRowView()) {
+                    return adapterPresenter.getPresenter(item);
+                } else {
+                    return invisibleRowPresenter;
+                }
+            }
+
+            @Override
+            public Presenter[] getPresenters() {
+                return allPresenters;
+            }
+        });
+    }
+
+    /**
+     * Sets the adapter containing the rows for the fragment.
+     *
+     * <p>The items referenced by the adapter must be be derived from
+     * {@link Row}. These rows will be used by the rows fragment and the headers
+     * fragment (if not disabled) to render the browse rows.
+     *
+     * @param adapter An ObjectAdapter for the browse rows. All items must
+     *        derive from {@link Row}.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        updateWrapperPresenter();
+        if (getView() == null) {
+            return;
+        }
+
+        updateMainFragmentRowsAdapter();
+        mHeadersFragment.setAdapter(mAdapter);
+    }
+
+    void setMainFragmentRowsAdapter(MainFragmentRowsAdapter mainFragmentRowsAdapter) {
+        if (mainFragmentRowsAdapter == mMainFragmentRowsAdapter) {
+            return;
+        }
+        // first clear previous mMainFragmentRowsAdapter and set a new mMainFragmentRowsAdapter
+        if (mMainFragmentRowsAdapter != null) {
+            // RowsFragment cannot change click/select listeners after view created.
+            // The main fragment and adapter should be GCed as long as there is no reference from
+            // BrowseFragment to it.
+            mMainFragmentRowsAdapter.setAdapter(null);
+        }
+        mMainFragmentRowsAdapter = mainFragmentRowsAdapter;
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setOnItemViewSelectedListener(
+                    new MainFragmentItemViewSelectedListener(mMainFragmentRowsAdapter));
+            mMainFragmentRowsAdapter.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        }
+        // second update mMainFragmentListRowDataAdapter set on mMainFragmentRowsAdapter
+        updateMainFragmentRowsAdapter();
+    }
+
+    /**
+     * Update mMainFragmentListRowDataAdapter and set it on mMainFragmentRowsAdapter.
+     * It also clears old mMainFragmentListRowDataAdapter.
+     */
+    void updateMainFragmentRowsAdapter() {
+        if (mMainFragmentListRowDataAdapter != null) {
+            mMainFragmentListRowDataAdapter.detach();
+            mMainFragmentListRowDataAdapter = null;
+        }
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentListRowDataAdapter = mAdapter == null
+                    ? null : new ListRowDataAdapter(mAdapter);
+            mMainFragmentRowsAdapter.setAdapter(mMainFragmentListRowDataAdapter);
+        }
+    }
+
+    public final MainFragmentAdapterRegistry getMainFragmentRegistry() {
+        return mMainFragmentAdapterRegistry;
+    }
+
+    /**
+     * Returns the adapter containing the rows for the fragment.
+     */
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Sets an item selection listener.
+     */
+    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
+        mExternalOnItemViewSelectedListener = listener;
+    }
+
+    /**
+     * Returns an item selection listener.
+     */
+    public OnItemViewSelectedListener getOnItemViewSelectedListener() {
+        return mExternalOnItemViewSelectedListener;
+    }
+
+    /**
+     * Get RowsFragment if it's bound to BrowseFragment or null if either BrowseFragment has
+     * not been created yet or a different fragment is bound to it.
+     *
+     * @return RowsFragment if it's bound to BrowseFragment or null otherwise.
+     */
+    public RowsFragment getRowsFragment() {
+        if (mMainFragment instanceof RowsFragment) {
+            return (RowsFragment) mMainFragment;
+        }
+
+        return null;
+    }
+
+    /**
+     * @return Current main fragment or null if not created.
+     */
+    public Fragment getMainFragment() {
+        return mMainFragment;
+    }
+
+    /**
+     * Get currently bound HeadersFragment or null if HeadersFragment has not been created yet.
+     * @return Currently bound HeadersFragment or null if HeadersFragment has not been created yet.
+     */
+    public HeadersFragment getHeadersFragment() {
+        return mHeadersFragment;
+    }
+
+    /**
+     * Sets an item clicked listener on the fragment.
+     * OnItemViewClickedListener will override {@link View.OnClickListener} that
+     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
+     * So in general, developer should choose one of the listeners but not both.
+     */
+    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+        mOnItemViewClickedListener = listener;
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setOnItemViewClickedListener(listener);
+        }
+    }
+
+    /**
+     * Returns the item Clicked listener.
+     */
+    public OnItemViewClickedListener getOnItemViewClickedListener() {
+        return mOnItemViewClickedListener;
+    }
+
+    /**
+     * Starts a headers transition.
+     *
+     * <p>This method will begin a transition to either show or hide the
+     * headers, depending on the value of withHeaders. If headers are disabled
+     * for this browse fragment, this method will throw an exception.
+     *
+     * @param withHeaders True if the headers should transition to being shown,
+     *        false if the transition should result in headers being hidden.
+     */
+    public void startHeadersTransition(boolean withHeaders) {
+        if (!mCanShowHeaders) {
+            throw new IllegalStateException("Cannot start headers transition");
+        }
+        if (isInHeadersTransition() || mShowingHeaders == withHeaders) {
+            return;
+        }
+        startHeadersTransitionInternal(withHeaders);
+    }
+
+    /**
+     * Returns true if the headers transition is currently running.
+     */
+    public boolean isInHeadersTransition() {
+        return mHeadersTransition != null;
+    }
+
+    /**
+     * Returns true if headers are shown.
+     */
+    public boolean isShowingHeaders() {
+        return mShowingHeaders;
+    }
+
+    /**
+     * Sets a listener for browse fragment transitions.
+     *
+     * @param listener The listener to call when a browse headers transition
+     *        begins or ends.
+     */
+    public void setBrowseTransitionListener(BrowseTransitionListener listener) {
+        mBrowseTransitionListener = listener;
+    }
+
+    /**
+     * @deprecated use {@link BrowseFragment#enableMainFragmentScaling(boolean)} instead.
+     *
+     * @param enable true to enable row scaling
+     */
+    @Deprecated
+    public void enableRowScaling(boolean enable) {
+        enableMainFragmentScaling(enable);
+    }
+
+    /**
+     * Enables scaling of main fragment when headers are present. For the page/row fragment,
+     * scaling is enabled only when both this method and
+     * {@link MainFragmentAdapter#isScalingEnabled()} are enabled.
+     *
+     * @param enable true to enable row scaling
+     */
+    public void enableMainFragmentScaling(boolean enable) {
+        mMainFragmentScaleEnabled = enable;
+    }
+
+    void startHeadersTransitionInternal(final boolean withHeaders) {
+        if (getFragmentManager().isDestroyed()) {
+            return;
+        }
+        if (!isHeadersDataReady()) {
+            return;
+        }
+        mShowingHeaders = withHeaders;
+        mMainFragmentAdapter.onTransitionPrepare();
+        mMainFragmentAdapter.onTransitionStart();
+        onExpandTransitionStart(!withHeaders, new Runnable() {
+            @Override
+            public void run() {
+                mHeadersFragment.onTransitionPrepare();
+                mHeadersFragment.onTransitionStart();
+                createHeadersTransition();
+                if (mBrowseTransitionListener != null) {
+                    mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
+                }
+                TransitionHelper.runTransition(
+                        withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders, mHeadersTransition);
+                if (mHeadersBackStackEnabled) {
+                    if (!withHeaders) {
+                        getFragmentManager().beginTransaction()
+                                .addToBackStack(mWithHeadersBackStackName).commit();
+                    } else {
+                        int index = mBackStackChangedListener.mIndexOfHeadersBackStack;
+                        if (index >= 0) {
+                            BackStackEntry entry = getFragmentManager().getBackStackEntryAt(index);
+                            getFragmentManager().popBackStackImmediate(entry.getId(),
+                                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    boolean isVerticalScrolling() {
+        // don't run transition
+        return mHeadersFragment.isScrolling() || mMainFragmentAdapter.isScrolling();
+    }
+
+
+    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
+            new BrowseFrameLayout.OnFocusSearchListener() {
+        @Override
+        public View onFocusSearch(View focused, int direction) {
+            // if headers is running transition,  focus stays
+            if (mCanShowHeaders && isInHeadersTransition()) {
+                return focused;
+            }
+            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
+
+            if (getTitleView() != null && focused != getTitleView()
+                    && direction == View.FOCUS_UP) {
+                return getTitleView();
+            }
+            if (getTitleView() != null && getTitleView().hasFocus()
+                    && direction == View.FOCUS_DOWN) {
+                return mCanShowHeaders && mShowingHeaders
+                        ? mHeadersFragment.getVerticalGridView() : mMainFragment.getView();
+            }
+
+            boolean isRtl = ViewCompat.getLayoutDirection(focused)
+                    == ViewCompat.LAYOUT_DIRECTION_RTL;
+            int towardStart = isRtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
+            int towardEnd = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
+            if (mCanShowHeaders && direction == towardStart) {
+                if (isVerticalScrolling() || mShowingHeaders || !isHeadersDataReady()) {
+                    return focused;
+                }
+                return mHeadersFragment.getVerticalGridView();
+            } else if (direction == towardEnd) {
+                if (isVerticalScrolling()) {
+                    return focused;
+                } else if (mMainFragment != null && mMainFragment.getView() != null) {
+                    return mMainFragment.getView();
+                }
+                return focused;
+            } else if (direction == View.FOCUS_DOWN && mShowingHeaders) {
+                // disable focus_down moving into PageFragment.
+                return focused;
+            } else {
+                return null;
+            }
+        }
+    };
+
+    final boolean isHeadersDataReady() {
+        return mAdapter != null && mAdapter.size() != 0;
+    }
+
+    private final BrowseFrameLayout.OnChildFocusListener mOnChildFocusListener =
+            new BrowseFrameLayout.OnChildFocusListener() {
+
+        @Override
+        public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+            if (getChildFragmentManager().isDestroyed()) {
+                return true;
+            }
+            // Make sure not changing focus when requestFocus() is called.
+            if (mCanShowHeaders && mShowingHeaders) {
+                if (mHeadersFragment != null && mHeadersFragment.getView() != null
+                        && mHeadersFragment.getView().requestFocus(
+                                direction, previouslyFocusedRect)) {
+                    return true;
+                }
+            }
+            if (mMainFragment != null && mMainFragment.getView() != null
+                    && mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
+                return true;
+            }
+            return getTitleView() != null
+                    && getTitleView().requestFocus(direction, previouslyFocusedRect);
+        }
+
+        @Override
+        public void onRequestChildFocus(View child, View focused) {
+            if (getChildFragmentManager().isDestroyed()) {
+                return;
+            }
+            if (!mCanShowHeaders || isInHeadersTransition()) return;
+            int childId = child.getId();
+            if (childId == R.id.browse_container_dock && mShowingHeaders) {
+                startHeadersTransitionInternal(false);
+            } else if (childId == R.id.browse_headers_dock && !mShowingHeaders) {
+                startHeadersTransitionInternal(true);
+            }
+        }
+    };
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(CURRENT_SELECTED_POSITION, mSelectedPosition);
+        outState.putBoolean(IS_PAGE_ROW, mIsPageRow);
+
+        if (mBackStackChangedListener != null) {
+            mBackStackChangedListener.save(outState);
+        } else {
+            outState.putBoolean(HEADER_SHOW, mShowingHeaders);
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final Context context = FragmentUtil.getContext(BrowseFragment.this);
+        TypedArray ta = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
+        mContainerListMarginStart = (int) ta.getDimension(
+                R.styleable.LeanbackTheme_browseRowsMarginStart, context.getResources()
+                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
+        mContainerListAlignTop = (int) ta.getDimension(
+                R.styleable.LeanbackTheme_browseRowsMarginTop, context.getResources()
+                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
+        ta.recycle();
+
+        readArguments(getArguments());
+
+        if (mCanShowHeaders) {
+            if (mHeadersBackStackEnabled) {
+                mWithHeadersBackStackName = LB_HEADERS_BACKSTACK + this;
+                mBackStackChangedListener = new BackStackListener();
+                getFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
+                mBackStackChangedListener.load(savedInstanceState);
+            } else {
+                if (savedInstanceState != null) {
+                    mShowingHeaders = savedInstanceState.getBoolean(HEADER_SHOW);
+                }
+            }
+        }
+
+        mScaleFactor = getResources().getFraction(R.fraction.lb_browse_rows_scale, 1, 1);
+    }
+
+    @Override
+    public void onDestroyView() {
+        setMainFragmentRowsAdapter(null);
+        mPageRow = null;
+        mMainFragmentAdapter = null;
+        mMainFragment = null;
+        mHeadersFragment = null;
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mBackStackChangedListener != null) {
+            getFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
+        }
+        super.onDestroy();
+    }
+
+    /**
+     * Creates a new {@link HeadersFragment} instance. Subclass of BrowseFragment may override and
+     * return an instance of subclass of HeadersFragment, e.g. when app wants to replace presenter
+     * to render HeaderItem.
+     *
+     * @return A new instance of {@link HeadersFragment} or its subclass.
+     */
+    public HeadersFragment onCreateHeadersFragment() {
+        return new HeadersFragment();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+
+        if (getChildFragmentManager().findFragmentById(R.id.scale_frame) == null) {
+            mHeadersFragment = onCreateHeadersFragment();
+
+            createMainFragment(mAdapter, mSelectedPosition);
+            FragmentTransaction ft = getChildFragmentManager().beginTransaction()
+                    .replace(R.id.browse_headers_dock, mHeadersFragment);
+
+            if (mMainFragment != null) {
+                ft.replace(R.id.scale_frame, mMainFragment);
+            } else {
+                // Empty adapter used to guard against lazy adapter loading. When this
+                // fragment is instantiated, mAdapter might not have the data or might not
+                // have been set. In either of those cases mFragmentAdapter will be null.
+                // This way we can maintain the invariant that mMainFragmentAdapter is never
+                // null and it avoids doing null checks all over the code.
+                mMainFragmentAdapter = new MainFragmentAdapter(null);
+                mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
+            }
+
+            ft.commit();
+        } else {
+            mHeadersFragment = (HeadersFragment) getChildFragmentManager()
+                    .findFragmentById(R.id.browse_headers_dock);
+            mMainFragment = getChildFragmentManager().findFragmentById(R.id.scale_frame);
+
+            mIsPageRow = savedInstanceState != null
+                    && savedInstanceState.getBoolean(IS_PAGE_ROW, false);
+            // mPageRow object is unable to restore, if its null and mIsPageRow is true, this is
+            // the case for restoring, later if setSelection() triggers a createMainFragment(),
+            // should not create fragment.
+
+            mSelectedPosition = savedInstanceState != null
+                    ? savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
+
+            setMainFragmentAdapter();
+        }
+
+        mHeadersFragment.setHeadersGone(!mCanShowHeaders);
+        if (mHeaderPresenterSelector != null) {
+            mHeadersFragment.setPresenterSelector(mHeaderPresenterSelector);
+        }
+        mHeadersFragment.setAdapter(mAdapter);
+        mHeadersFragment.setOnHeaderViewSelectedListener(mHeaderViewSelectedListener);
+        mHeadersFragment.setOnHeaderClickedListener(mHeaderClickedListener);
+
+        View root = inflater.inflate(R.layout.lb_browse_fragment, container, false);
+
+        getProgressBarManager().setRootView((ViewGroup)root);
+
+        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
+        mBrowseFrame.setOnChildFocusListener(mOnChildFocusListener);
+        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
+
+        installTitleView(inflater, mBrowseFrame, savedInstanceState);
+
+        mScaleFrameLayout = (ScaleFrameLayout) root.findViewById(R.id.scale_frame);
+        mScaleFrameLayout.setPivotX(0);
+        mScaleFrameLayout.setPivotY(mContainerListAlignTop);
+
+        if (mBrandColorSet) {
+            mHeadersFragment.setBackgroundColor(mBrandColor);
+        }
+
+        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
+            @Override
+            public void run() {
+                showHeaders(true);
+            }
+        });
+        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
+            @Override
+            public void run() {
+                showHeaders(false);
+            }
+        });
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
+            @Override
+            public void run() {
+                setEntranceTransitionEndState();
+            }
+        });
+
+        return root;
+    }
+
+    void createHeadersTransition() {
+        mHeadersTransition = TransitionHelper.loadTransition(FragmentUtil.getContext(BrowseFragment.this),
+                mShowingHeaders
+                        ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
+
+        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
+            @Override
+            public void onTransitionStart(Object transition) {
+            }
+            @Override
+            public void onTransitionEnd(Object transition) {
+                mHeadersTransition = null;
+                if (mMainFragmentAdapter != null) {
+                    mMainFragmentAdapter.onTransitionEnd();
+                    if (!mShowingHeaders && mMainFragment != null) {
+                        View mainFragmentView = mMainFragment.getView();
+                        if (mainFragmentView != null && !mainFragmentView.hasFocus()) {
+                            mainFragmentView.requestFocus();
+                        }
+                    }
+                }
+                if (mHeadersFragment != null) {
+                    mHeadersFragment.onTransitionEnd();
+                    if (mShowingHeaders) {
+                        VerticalGridView headerGridView = mHeadersFragment.getVerticalGridView();
+                        if (headerGridView != null && !headerGridView.hasFocus()) {
+                            headerGridView.requestFocus();
+                        }
+                    }
+                }
+
+                // Animate TitleView once header animation is complete.
+                updateTitleViewVisibility();
+
+                if (mBrowseTransitionListener != null) {
+                    mBrowseTransitionListener.onHeadersTransitionStop(mShowingHeaders);
+                }
+            }
+        });
+    }
+
+    void updateTitleViewVisibility() {
+        if (!mShowingHeaders) {
+            boolean showTitleView;
+            if (mIsPageRow && mMainFragmentAdapter != null) {
+                // page fragment case:
+                showTitleView = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
+            } else {
+                // regular row view case:
+                showTitleView = isFirstRowWithContent(mSelectedPosition);
+            }
+            if (showTitleView) {
+                showTitle(TitleViewAdapter.FULL_VIEW_VISIBLE);
+            } else {
+                showTitle(false);
+            }
+        } else {
+            // when HeaderFragment is showing,  showBranding and showSearch are slightly different
+            boolean showBranding;
+            boolean showSearch;
+            if (mIsPageRow && mMainFragmentAdapter != null) {
+                showBranding = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
+            } else {
+                showBranding = isFirstRowWithContent(mSelectedPosition);
+            }
+            showSearch = isFirstRowWithContentOrPageRow(mSelectedPosition);
+            int flags = 0;
+            if (showBranding) flags |= TitleViewAdapter.BRANDING_VIEW_VISIBLE;
+            if (showSearch) flags |= TitleViewAdapter.SEARCH_VIEW_VISIBLE;
+            if (flags != 0) {
+                showTitle(flags);
+            } else {
+                showTitle(false);
+            }
+        }
+    }
+
+    boolean isFirstRowWithContentOrPageRow(int rowPosition) {
+        if (mAdapter == null || mAdapter.size() == 0) {
+            return true;
+        }
+        for (int i = 0; i < mAdapter.size(); i++) {
+            final Row row = (Row) mAdapter.get(i);
+            if (row.isRenderedAsRowView() || row instanceof PageRow) {
+                return rowPosition == i;
+            }
+        }
+        return true;
+    }
+
+    boolean isFirstRowWithContent(int rowPosition) {
+        if (mAdapter == null || mAdapter.size() == 0) {
+            return true;
+        }
+        for (int i = 0; i < mAdapter.size(); i++) {
+            final Row row = (Row) mAdapter.get(i);
+            if (row.isRenderedAsRowView()) {
+                return rowPosition == i;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Sets the {@link PresenterSelector} used to render the row headers.
+     *
+     * @param headerPresenterSelector The PresenterSelector that will determine
+     *        the Presenter for each row header.
+     */
+    public void setHeaderPresenterSelector(PresenterSelector headerPresenterSelector) {
+        mHeaderPresenterSelector = headerPresenterSelector;
+        if (mHeadersFragment != null) {
+            mHeadersFragment.setPresenterSelector(mHeaderPresenterSelector);
+        }
+    }
+
+    private void setHeadersOnScreen(boolean onScreen) {
+        MarginLayoutParams lp;
+        View containerList;
+        containerList = mHeadersFragment.getView();
+        lp = (MarginLayoutParams) containerList.getLayoutParams();
+        lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
+        containerList.setLayoutParams(lp);
+    }
+
+    void showHeaders(boolean show) {
+        if (DEBUG) Log.v(TAG, "showHeaders " + show);
+        mHeadersFragment.setHeadersEnabled(show);
+        setHeadersOnScreen(show);
+        expandMainFragment(!show);
+    }
+
+    private void expandMainFragment(boolean expand) {
+        MarginLayoutParams params = (MarginLayoutParams) mScaleFrameLayout.getLayoutParams();
+        params.setMarginStart(!expand ? mContainerListMarginStart : 0);
+        mScaleFrameLayout.setLayoutParams(params);
+        mMainFragmentAdapter.setExpand(expand);
+
+        setMainFragmentAlignment();
+        final float scaleFactor = !expand
+                && mMainFragmentScaleEnabled
+                && mMainFragmentAdapter.isScalingEnabled() ? mScaleFactor : 1;
+        mScaleFrameLayout.setLayoutScaleY(scaleFactor);
+        mScaleFrameLayout.setChildScale(scaleFactor);
+    }
+
+    private HeadersFragment.OnHeaderClickedListener mHeaderClickedListener =
+        new HeadersFragment.OnHeaderClickedListener() {
+            @Override
+            public void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
+                if (!mCanShowHeaders || !mShowingHeaders || isInHeadersTransition()) {
+                    return;
+                }
+                if (mMainFragment == null || mMainFragment.getView() == null) {
+                    return;
+                }
+                startHeadersTransitionInternal(false);
+                mMainFragment.getView().requestFocus();
+            }
+        };
+
+    class MainFragmentItemViewSelectedListener implements OnItemViewSelectedListener {
+        MainFragmentRowsAdapter mMainFragmentRowsAdapter;
+
+        public MainFragmentItemViewSelectedListener(MainFragmentRowsAdapter fragmentRowsAdapter) {
+            mMainFragmentRowsAdapter = fragmentRowsAdapter;
+        }
+
+        @Override
+        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                RowPresenter.ViewHolder rowViewHolder, Row row) {
+            int position = mMainFragmentRowsAdapter.getSelectedPosition();
+            if (DEBUG) Log.v(TAG, "row selected position " + position);
+            onRowSelected(position);
+            if (mExternalOnItemViewSelectedListener != null) {
+                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
+                        rowViewHolder, row);
+            }
+        }
+    };
+
+    private HeadersFragment.OnHeaderViewSelectedListener mHeaderViewSelectedListener =
+            new HeadersFragment.OnHeaderViewSelectedListener() {
+        @Override
+        public void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
+            int position = mHeadersFragment.getSelectedPosition();
+            if (DEBUG) Log.v(TAG, "header selected position " + position);
+            onRowSelected(position);
+        }
+    };
+
+    void onRowSelected(int position) {
+        // even position is same, it could be data changed, always post selection runnable
+        // to possibly swap main fragment.
+        mSetSelectionRunnable.post(
+                position, SetSelectionRunnable.TYPE_INTERNAL_SYNC, true);
+    }
+
+    void setSelection(int position, boolean smooth) {
+        if (position == NO_POSITION) {
+            return;
+        }
+
+        mSelectedPosition = position;
+        if (mHeadersFragment == null || mMainFragmentAdapter == null) {
+            // onDestroyView() called
+            return;
+        }
+        mHeadersFragment.setSelectedPosition(position, smooth);
+        replaceMainFragment(position);
+
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setSelectedPosition(position, smooth);
+        }
+
+        updateTitleViewVisibility();
+    }
+
+    private void replaceMainFragment(int position) {
+        if (createMainFragment(mAdapter, position)) {
+            swapToMainFragment();
+            expandMainFragment(!(mCanShowHeaders && mShowingHeaders));
+        }
+    }
+
+    private void swapToMainFragment() {
+        final VerticalGridView gridView = mHeadersFragment.getVerticalGridView();
+        if (isShowingHeaders() && gridView != null
+                && gridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
+            // if user is scrolling HeadersFragment,  swap to empty fragment and wait scrolling
+            // finishes.
+            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) {
+                        gridView.removeOnScrollListener(this);
+                        FragmentManager fm = getChildFragmentManager();
+                        Fragment currentFragment = fm.findFragmentById(R.id.scale_frame);
+                        if (currentFragment != mMainFragment) {
+                            fm.beginTransaction().replace(R.id.scale_frame, mMainFragment).commit();
+                        }
+                    }
+                }
+            });
+        } else {
+            // Otherwise swap immediately
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.scale_frame, mMainFragment).commit();
+        }
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Gets position of currently selected row.
+     * @return Position of currently selected row.
+     */
+    public int getSelectedPosition() {
+        return mSelectedPosition;
+    }
+
+    /**
+     * @return selected row ViewHolder inside fragment created by {@link MainFragmentRowsAdapter}.
+     */
+    public RowPresenter.ViewHolder getSelectedRowViewHolder() {
+        if (mMainFragmentRowsAdapter != null) {
+            int rowPos = mMainFragmentRowsAdapter.getSelectedPosition();
+            return mMainFragmentRowsAdapter.findRowViewHolderByPosition(rowPos);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.post(
+                position, SetSelectionRunnable.TYPE_USER_REQUEST, smooth);
+    }
+
+    /**
+     * Selects a Row and perform an optional task on the Row. For example
+     * <code>setSelectedPosition(10, true, new ListRowPresenterSelectItemViewHolderTask(5))</code>
+     * scrolls to 11th row and selects 6th item on that row.  The method will be ignored if
+     * RowsFragment has not been created (i.e. before {@link #onCreateView(LayoutInflater,
+     * ViewGroup, Bundle)}).
+     *
+     * @param rowPosition Which row to select.
+     * @param smooth True to scroll to the row, false for no animation.
+     * @param rowHolderTask Optional task to perform on the Row.  When the task is not null, headers
+     * fragment will be collapsed.
+     */
+    public void setSelectedPosition(int rowPosition, boolean smooth,
+            final Presenter.ViewHolderTask rowHolderTask) {
+        if (mMainFragmentAdapterRegistry == null) {
+            return;
+        }
+        if (rowHolderTask != null) {
+            startHeadersTransition(false);
+        }
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setSelectedPosition(rowPosition, smooth, rowHolderTask);
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mHeadersFragment.setAlignment(mContainerListAlignTop);
+        setMainFragmentAlignment();
+
+        if (mCanShowHeaders && mShowingHeaders && mHeadersFragment != null
+                && mHeadersFragment.getView() != null) {
+            mHeadersFragment.getView().requestFocus();
+        } else if ((!mCanShowHeaders || !mShowingHeaders) && mMainFragment != null
+                && mMainFragment.getView() != null) {
+            mMainFragment.getView().requestFocus();
+        }
+
+        if (mCanShowHeaders) {
+            showHeaders(mShowingHeaders);
+        }
+
+        mStateMachine.fireEvent(EVT_HEADER_VIEW_CREATED);
+    }
+
+    private void onExpandTransitionStart(boolean expand, final Runnable callback) {
+        if (expand) {
+            callback.run();
+            return;
+        }
+        // Run a "pre" layout when we go non-expand, in order to get the initial
+        // positions of added rows.
+        new ExpandPreLayout(callback, mMainFragmentAdapter, getView()).execute();
+    }
+
+    private void setMainFragmentAlignment() {
+        int alignOffset = mContainerListAlignTop;
+        if (mMainFragmentScaleEnabled
+                && mMainFragmentAdapter.isScalingEnabled()
+                && mShowingHeaders) {
+            alignOffset = (int) (alignOffset / mScaleFactor + 0.5f);
+        }
+        mMainFragmentAdapter.setAlignment(alignOffset);
+    }
+
+    /**
+     * Enables/disables headers transition on back key support. This is enabled by
+     * default. The BrowseFragment will add a back stack entry when headers are
+     * showing. Running a headers transition when the back key is pressed only
+     * works when the headers state is {@link #HEADERS_ENABLED} or
+     * {@link #HEADERS_HIDDEN}.
+     * <p>
+     * NOTE: If an Activity has its own onBackPressed() handling, you must
+     * disable this feature. You may use {@link #startHeadersTransition(boolean)}
+     * and {@link BrowseTransitionListener} in your own back stack handling.
+     */
+    public final void setHeadersTransitionOnBackEnabled(boolean headersBackStackEnabled) {
+        mHeadersBackStackEnabled = headersBackStackEnabled;
+    }
+
+    /**
+     * Returns true if headers transition on back key support is enabled.
+     */
+    public final boolean isHeadersTransitionOnBackEnabled() {
+        return mHeadersBackStackEnabled;
+    }
+
+    private void readArguments(Bundle args) {
+        if (args == null) {
+            return;
+        }
+        if (args.containsKey(ARG_TITLE)) {
+            setTitle(args.getString(ARG_TITLE));
+        }
+        if (args.containsKey(ARG_HEADERS_STATE)) {
+            setHeadersState(args.getInt(ARG_HEADERS_STATE));
+        }
+    }
+
+    /**
+     * Sets the state for the headers column in the browse fragment. Must be one
+     * of {@link #HEADERS_ENABLED}, {@link #HEADERS_HIDDEN}, or
+     * {@link #HEADERS_DISABLED}.
+     *
+     * @param headersState The state of the headers for the browse fragment.
+     */
+    public void setHeadersState(int headersState) {
+        if (headersState < HEADERS_ENABLED || headersState > HEADERS_DISABLED) {
+            throw new IllegalArgumentException("Invalid headers state: " + headersState);
+        }
+        if (DEBUG) Log.v(TAG, "setHeadersState " + headersState);
+
+        if (headersState != mHeadersState) {
+            mHeadersState = headersState;
+            switch (headersState) {
+                case HEADERS_ENABLED:
+                    mCanShowHeaders = true;
+                    mShowingHeaders = true;
+                    break;
+                case HEADERS_HIDDEN:
+                    mCanShowHeaders = true;
+                    mShowingHeaders = false;
+                    break;
+                case HEADERS_DISABLED:
+                    mCanShowHeaders = false;
+                    mShowingHeaders = false;
+                    break;
+                default:
+                    Log.w(TAG, "Unknown headers state: " + headersState);
+                    break;
+            }
+            if (mHeadersFragment != null) {
+                mHeadersFragment.setHeadersGone(!mCanShowHeaders);
+            }
+        }
+    }
+
+    /**
+     * Returns the state of the headers column in the browse fragment.
+     */
+    public int getHeadersState() {
+        return mHeadersState;
+    }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(FragmentUtil.getContext(BrowseFragment.this),
+                R.transition.lb_browse_entrance_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    @Override
+    protected void onEntranceTransitionPrepare() {
+        mHeadersFragment.onTransitionPrepare();
+        mMainFragmentAdapter.setEntranceTransitionState(false);
+        mMainFragmentAdapter.onTransitionPrepare();
+    }
+
+    @Override
+    protected void onEntranceTransitionStart() {
+        mHeadersFragment.onTransitionStart();
+        mMainFragmentAdapter.onTransitionStart();
+    }
+
+    @Override
+    protected void onEntranceTransitionEnd() {
+        if (mMainFragmentAdapter != null) {
+            mMainFragmentAdapter.onTransitionEnd();
+        }
+
+        if (mHeadersFragment != null) {
+            mHeadersFragment.onTransitionEnd();
+        }
+    }
+
+    void setSearchOrbViewOnScreen(boolean onScreen) {
+        View searchOrbView = getTitleViewAdapter().getSearchAffordanceView();
+        if (searchOrbView != null) {
+            MarginLayoutParams lp = (MarginLayoutParams) searchOrbView.getLayoutParams();
+            lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
+            searchOrbView.setLayoutParams(lp);
+        }
+    }
+
+    void setEntranceTransitionStartState() {
+        setHeadersOnScreen(false);
+        setSearchOrbViewOnScreen(false);
+        // NOTE that mMainFragmentAdapter.setEntranceTransitionState(false) will be called
+        // in onEntranceTransitionPrepare() because mMainFragmentAdapter is still the dummy
+        // one when setEntranceTransitionStartState() is called.
+    }
+
+    void setEntranceTransitionEndState() {
+        setHeadersOnScreen(mShowingHeaders);
+        setSearchOrbViewOnScreen(true);
+        mMainFragmentAdapter.setEntranceTransitionState(true);
+    }
+
+    private class ExpandPreLayout implements ViewTreeObserver.OnPreDrawListener {
+
+        private final View mView;
+        private final Runnable mCallback;
+        private int mState;
+        private MainFragmentAdapter mainFragmentAdapter;
+
+        final static int STATE_INIT = 0;
+        final static int STATE_FIRST_DRAW = 1;
+        final static int STATE_SECOND_DRAW = 2;
+
+        ExpandPreLayout(Runnable callback, MainFragmentAdapter adapter, View view) {
+            mView = view;
+            mCallback = callback;
+            mainFragmentAdapter = adapter;
+        }
+
+        void execute() {
+            mView.getViewTreeObserver().addOnPreDrawListener(this);
+            mainFragmentAdapter.setExpand(false);
+            // always trigger onPreDraw even adapter setExpand() does nothing.
+            mView.invalidate();
+            mState = STATE_INIT;
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            if (getView() == null || FragmentUtil.getContext(BrowseFragment.this) == null) {
+                mView.getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
+            if (mState == STATE_INIT) {
+                mainFragmentAdapter.setExpand(true);
+                // always trigger onPreDraw even adapter setExpand() does nothing.
+                mView.invalidate();
+                mState = STATE_FIRST_DRAW;
+            } else if (mState == STATE_FIRST_DRAW) {
+                mCallback.run();
+                mView.getViewTreeObserver().removeOnPreDrawListener(this);
+                mState = STATE_SECOND_DRAW;
+            }
+            return false;
+        }
+    }
+}
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/BrowseSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/BrowseSupportFragment.java
new file mode 100644
index 0000000..3055e1f
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/BrowseSupportFragment.java
@@ -0,0 +1,1848 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.transition.TransitionListener;
+import android.support.v17.leanback.util.StateMachine.Event;
+import android.support.v17.leanback.util.StateMachine.State;
+import android.support.v17.leanback.widget.BrowseFrameLayout;
+import android.support.v17.leanback.widget.InvisibleRowPresenter;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.PageRow;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowHeaderPresenter;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.ScaleFrameLayout;
+import android.support.v17.leanback.widget.TitleViewAdapter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentManager.BackStackEntry;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.ViewTreeObserver;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A fragment for creating Leanback browse screens. It is composed of a
+ * RowsSupportFragment and a HeadersSupportFragment.
+ * <p>
+ * A BrowseSupportFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list. The elements in this adapter must be subclasses
+ * of {@link Row}.
+ * <p>
+ * The HeadersSupportFragment can be set to be either shown or hidden by default, or
+ * may be disabled entirely. See {@link #setHeadersState} for details.
+ * <p>
+ * By default the BrowseSupportFragment includes support for returning to the headers
+ * when the user presses Back. For Activities that customize {@link
+ * android.support.v4.app.FragmentActivity#onBackPressed()}, you must disable this default Back key support by
+ * calling {@link #setHeadersTransitionOnBackEnabled(boolean)} with false and
+ * use {@link BrowseSupportFragment.BrowseTransitionListener} and
+ * {@link #startHeadersTransition(boolean)}.
+ * <p>
+ * The recommended theme to use with a BrowseSupportFragment is
+ * {@link android.support.v17.leanback.R.style#Theme_Leanback_Browse}.
+ * </p>
+ */
+public class BrowseSupportFragment extends BaseSupportFragment {
+
+    // BUNDLE attribute for saving header show/hide status when backstack is used:
+    static final String HEADER_STACK_INDEX = "headerStackIndex";
+    // BUNDLE attribute for saving header show/hide status when backstack is not used:
+    static final String HEADER_SHOW = "headerShow";
+    private static final String IS_PAGE_ROW = "isPageRow";
+    private static final String CURRENT_SELECTED_POSITION = "currentSelectedPosition";
+
+    /**
+     * State to hide headers fragment.
+     */
+    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
+        @Override
+        public void run() {
+            setEntranceTransitionStartState();
+        }
+    };
+
+    /**
+     * Event for Header fragment view is created, we could perform
+     * {@link #setEntranceTransitionStartState()} to hide headers fragment initially.
+     */
+    final Event EVT_HEADER_VIEW_CREATED = new Event("headerFragmentViewCreated");
+
+    /**
+     * Event for {@link #getMainFragment()} view is created, it's additional requirement to execute
+     * {@link #onEntranceTransitionPrepare()}.
+     */
+    final Event EVT_MAIN_FRAGMENT_VIEW_CREATED = new Event("mainFragmentViewCreated");
+
+    /**
+     * Event that data for the screen is ready, this is additional requirement to launch entrance
+     * transition.
+     */
+    final Event EVT_SCREEN_DATA_READY = new Event("screenDataReady");
+
+    @Override
+    void createStateMachineStates() {
+        super.createStateMachineStates();
+        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
+    }
+
+    @Override
+    void createStateMachineTransitions() {
+        super.createStateMachineTransitions();
+        // when headers fragment view is created we could setEntranceTransitionStartState()
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED, STATE_SET_ENTRANCE_START_STATE,
+                EVT_HEADER_VIEW_CREATED);
+
+        // add additional requirement for onEntranceTransitionPrepare()
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
+                STATE_ENTRANCE_ON_PREPARED_ON_CREATEVIEW,
+                EVT_MAIN_FRAGMENT_VIEW_CREATED);
+        // add additional requirement to launch entrance transition.
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,  STATE_ENTRANCE_PERFORM,
+                EVT_SCREEN_DATA_READY);
+    }
+
+    final class BackStackListener implements FragmentManager.OnBackStackChangedListener {
+        int mLastEntryCount;
+        int mIndexOfHeadersBackStack;
+
+        BackStackListener() {
+            mLastEntryCount = getFragmentManager().getBackStackEntryCount();
+            mIndexOfHeadersBackStack = -1;
+        }
+
+        void load(Bundle savedInstanceState) {
+            if (savedInstanceState != null) {
+                mIndexOfHeadersBackStack = savedInstanceState.getInt(HEADER_STACK_INDEX, -1);
+                mShowingHeaders = mIndexOfHeadersBackStack == -1;
+            } else {
+                if (!mShowingHeaders) {
+                    getFragmentManager().beginTransaction()
+                            .addToBackStack(mWithHeadersBackStackName).commit();
+                }
+            }
+        }
+
+        void save(Bundle outState) {
+            outState.putInt(HEADER_STACK_INDEX, mIndexOfHeadersBackStack);
+        }
+
+
+        @Override
+        public void onBackStackChanged() {
+            if (getFragmentManager() == null) {
+                Log.w(TAG, "getFragmentManager() is null, stack:", new Exception());
+                return;
+            }
+            int count = getFragmentManager().getBackStackEntryCount();
+            // if backstack is growing and last pushed entry is "headers" backstack,
+            // remember the index of the entry.
+            if (count > mLastEntryCount) {
+                BackStackEntry entry = getFragmentManager().getBackStackEntryAt(count - 1);
+                if (mWithHeadersBackStackName.equals(entry.getName())) {
+                    mIndexOfHeadersBackStack = count - 1;
+                }
+            } else if (count < mLastEntryCount) {
+                // if popped "headers" backstack, initiate the show header transition if needed
+                if (mIndexOfHeadersBackStack >= count) {
+                    if (!isHeadersDataReady()) {
+                        // if main fragment was restored first before BrowseSupportFragment's adapter gets
+                        // restored: don't start header transition, but add the entry back.
+                        getFragmentManager().beginTransaction()
+                                .addToBackStack(mWithHeadersBackStackName).commit();
+                        return;
+                    }
+                    mIndexOfHeadersBackStack = -1;
+                    if (!mShowingHeaders) {
+                        startHeadersTransitionInternal(true);
+                    }
+                }
+            }
+            mLastEntryCount = count;
+        }
+    }
+
+    /**
+     * Listener for transitions between browse headers and rows.
+     */
+    public static class BrowseTransitionListener {
+        /**
+         * Callback when headers transition starts.
+         *
+         * @param withHeaders True if the transition will result in headers
+         *        being shown, false otherwise.
+         */
+        public void onHeadersTransitionStart(boolean withHeaders) {
+        }
+        /**
+         * Callback when headers transition stops.
+         *
+         * @param withHeaders True if the transition will result in headers
+         *        being shown, false otherwise.
+         */
+        public void onHeadersTransitionStop(boolean withHeaders) {
+        }
+    }
+
+    private class SetSelectionRunnable implements Runnable {
+        static final int TYPE_INVALID = -1;
+        static final int TYPE_INTERNAL_SYNC = 0;
+        static final int TYPE_USER_REQUEST = 1;
+
+        private int mPosition;
+        private int mType;
+        private boolean mSmooth;
+
+        SetSelectionRunnable() {
+            reset();
+        }
+
+        void post(int position, int type, boolean smooth) {
+            // Posting the set selection, rather than calling it immediately, prevents an issue
+            // with adapter changes.  Example: a row is added before the current selected row;
+            // first the fast lane view updates its selection, then the rows fragment has that
+            // new selection propagated immediately; THEN the rows view processes the same adapter
+            // change and moves the selection again.
+            if (type >= mType) {
+                mPosition = position;
+                mType = type;
+                mSmooth = smooth;
+                mBrowseFrame.removeCallbacks(this);
+                mBrowseFrame.post(this);
+            }
+        }
+
+        @Override
+        public void run() {
+            setSelection(mPosition, mSmooth);
+            reset();
+        }
+
+        private void reset() {
+            mPosition = -1;
+            mType = TYPE_INVALID;
+            mSmooth = false;
+        }
+    }
+
+    /**
+     * Possible set of actions that {@link BrowseSupportFragment} exposes to clients. Custom
+     * fragments can interact with {@link BrowseSupportFragment} using this interface.
+     */
+    public interface FragmentHost {
+        /**
+         * Fragments are required to invoke this callback once their view is created
+         * inside {@link Fragment#onViewCreated} method. {@link BrowseSupportFragment} starts the entrance
+         * animation only after receiving this callback. Failure to invoke this method
+         * will lead to fragment not showing up.
+         *
+         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
+         */
+        void notifyViewCreated(MainFragmentAdapter fragmentAdapter);
+
+        /**
+         * Fragments mapped to {@link PageRow} are required to invoke this callback once their data
+         * is created for transition, the entrance animation only after receiving this callback.
+         * Failure to invoke this method will lead to fragment not showing up.
+         *
+         * @param fragmentAdapter {@link MainFragmentAdapter} used by the current fragment.
+         */
+        void notifyDataReady(MainFragmentAdapter fragmentAdapter);
+
+        /**
+         * Show or hide title view in {@link BrowseSupportFragment} for fragments mapped to
+         * {@link PageRow}.  Otherwise the request is ignored, in that case BrowseSupportFragment is fully
+         * in control of showing/hiding title view.
+         * <p>
+         * When HeadersSupportFragment is visible, BrowseSupportFragment will hide search affordance view if
+         * there are other focusable rows above currently focused row.
+         *
+         * @param show Boolean indicating whether or not to show the title view.
+         */
+        void showTitleView(boolean show);
+    }
+
+    /**
+     * Default implementation of {@link FragmentHost} that is used only by
+     * {@link BrowseSupportFragment}.
+     */
+    private final class FragmentHostImpl implements FragmentHost {
+        boolean mShowTitleView = true;
+
+        FragmentHostImpl() {
+        }
+
+        @Override
+        public void notifyViewCreated(MainFragmentAdapter fragmentAdapter) {
+            mStateMachine.fireEvent(EVT_MAIN_FRAGMENT_VIEW_CREATED);
+            if (!mIsPageRow) {
+                // If it's not a PageRow: it's a ListRow, so we already have data ready.
+                mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
+            }
+        }
+
+        @Override
+        public void notifyDataReady(MainFragmentAdapter fragmentAdapter) {
+            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
+            // ignore the request.
+            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
+                return;
+            }
+
+            // We only honor showTitle request for PageRows.
+            if (!mIsPageRow) {
+                return;
+            }
+
+            mStateMachine.fireEvent(EVT_SCREEN_DATA_READY);
+        }
+
+        @Override
+        public void showTitleView(boolean show) {
+            mShowTitleView = show;
+
+            // If fragment host is not the currently active fragment (in BrowseSupportFragment), then
+            // ignore the request.
+            if (mMainFragmentAdapter == null || mMainFragmentAdapter.getFragmentHost() != this) {
+                return;
+            }
+
+            // We only honor showTitle request for PageRows.
+            if (!mIsPageRow) {
+                return;
+            }
+
+            updateTitleViewVisibility();
+        }
+    }
+
+    /**
+     * Interface that defines the interaction between {@link BrowseSupportFragment} and its main
+     * content fragment. The key method is {@link MainFragmentAdapter#getFragment()},
+     * it will be used to get the fragment to be shown in the content section. Clients can
+     * provide any implementation of fragment and customize its interaction with
+     * {@link BrowseSupportFragment} by overriding the necessary methods.
+     *
+     * <p>
+     * Clients are expected to provide
+     * an instance of {@link MainFragmentAdapterRegistry} which will be responsible for providing
+     * implementations of {@link MainFragmentAdapter} for given content types. Currently
+     * we support different types of content - {@link ListRow}, {@link PageRow} or any subtype
+     * of {@link Row}. We provide an out of the box adapter implementation for any rows other than
+     * {@link PageRow} - {@link android.support.v17.leanback.app.RowsSupportFragment.MainFragmentAdapter}.
+     *
+     * <p>
+     * {@link PageRow} is intended to give full flexibility to developers in terms of Fragment
+     * design. Users will have to provide an implementation of {@link MainFragmentAdapter}
+     * and provide that through {@link MainFragmentAdapterRegistry}.
+     * {@link MainFragmentAdapter} implementation can supply any fragment and override
+     * just those interactions that makes sense.
+     */
+    public static class MainFragmentAdapter<T extends Fragment> {
+        private boolean mScalingEnabled;
+        private final T mFragment;
+        FragmentHostImpl mFragmentHost;
+
+        public MainFragmentAdapter(T fragment) {
+            this.mFragment = fragment;
+        }
+
+        public final T getFragment() {
+            return mFragment;
+        }
+
+        /**
+         * Returns whether its scrolling.
+         */
+        public boolean isScrolling() {
+            return false;
+        }
+
+        /**
+         * Set the visibility of titles/hover card of browse rows.
+         */
+        public void setExpand(boolean expand) {
+        }
+
+        /**
+         * For rows that willing to participate entrance transition,  this function
+         * hide views if afterTransition is true,  show views if afterTransition is false.
+         */
+        public void setEntranceTransitionState(boolean state) {
+        }
+
+        /**
+         * Sets the window alignment and also the pivots for scale operation.
+         */
+        public void setAlignment(int windowAlignOffsetFromTop) {
+        }
+
+        /**
+         * Callback indicating transition prepare start.
+         */
+        public boolean onTransitionPrepare() {
+            return false;
+        }
+
+        /**
+         * Callback indicating transition start.
+         */
+        public void onTransitionStart() {
+        }
+
+        /**
+         * Callback indicating transition end.
+         */
+        public void onTransitionEnd() {
+        }
+
+        /**
+         * Returns whether row scaling is enabled.
+         */
+        public boolean isScalingEnabled() {
+            return mScalingEnabled;
+        }
+
+        /**
+         * Sets the row scaling property.
+         */
+        public void setScalingEnabled(boolean scalingEnabled) {
+            this.mScalingEnabled = scalingEnabled;
+        }
+
+        /**
+         * Returns the current host interface so that main fragment can interact with
+         * {@link BrowseSupportFragment}.
+         */
+        public final FragmentHost getFragmentHost() {
+            return mFragmentHost;
+        }
+
+        void setFragmentHost(FragmentHostImpl fragmentHost) {
+            this.mFragmentHost = fragmentHost;
+        }
+    }
+
+    /**
+     * Interface to be implemented by all fragments for providing an instance of
+     * {@link MainFragmentAdapter}. Both {@link RowsSupportFragment} and custom fragment provided
+     * against {@link PageRow} will need to implement this interface.
+     */
+    public interface MainFragmentAdapterProvider {
+        /**
+         * Returns an instance of {@link MainFragmentAdapter} that {@link BrowseSupportFragment}
+         * would use to communicate with the target fragment.
+         */
+        MainFragmentAdapter getMainFragmentAdapter();
+    }
+
+    /**
+     * Interface to be implemented by {@link RowsSupportFragment} and its subclasses for providing
+     * an instance of {@link MainFragmentRowsAdapter}.
+     */
+    public interface MainFragmentRowsAdapterProvider {
+        /**
+         * Returns an instance of {@link MainFragmentRowsAdapter} that {@link BrowseSupportFragment}
+         * would use to communicate with the target fragment.
+         */
+        MainFragmentRowsAdapter getMainFragmentRowsAdapter();
+    }
+
+    /**
+     * This is used to pass information to {@link RowsSupportFragment} or its subclasses.
+     * {@link BrowseSupportFragment} uses this interface to pass row based interaction events to
+     * the target fragment.
+     */
+    public static class MainFragmentRowsAdapter<T extends Fragment> {
+        private final T mFragment;
+
+        public MainFragmentRowsAdapter(T fragment) {
+            if (fragment == null) {
+                throw new IllegalArgumentException("Fragment can't be null");
+            }
+            this.mFragment = fragment;
+        }
+
+        public final T getFragment() {
+            return mFragment;
+        }
+        /**
+         * Set the visibility titles/hover of browse rows.
+         */
+        public void setAdapter(ObjectAdapter adapter) {
+        }
+
+        /**
+         * Sets an item clicked listener on the fragment.
+         */
+        public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+        }
+
+        /**
+         * Sets an item selection listener.
+         */
+        public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
+        }
+
+        /**
+         * Selects a Row and perform an optional task on the Row.
+         */
+        public void setSelectedPosition(int rowPosition,
+                                        boolean smooth,
+                                        final Presenter.ViewHolderTask rowHolderTask) {
+        }
+
+        /**
+         * Selects a Row.
+         */
+        public void setSelectedPosition(int rowPosition, boolean smooth) {
+        }
+
+        /**
+         * @return The position of selected row.
+         */
+        public int getSelectedPosition() {
+            return 0;
+        }
+
+        /**
+         * @param position Position of Row.
+         * @return Row ViewHolder.
+         */
+        public RowPresenter.ViewHolder findRowViewHolderByPosition(int position) {
+            return null;
+        }
+    }
+
+    private boolean createMainFragment(ObjectAdapter adapter, int position) {
+        Object item = null;
+        if (!mCanShowHeaders) {
+            // when header is disabled, we can decide to use RowsSupportFragment even no data.
+        } else if (adapter == null || adapter.size() == 0) {
+            return false;
+        } else {
+            if (position < 0) {
+                position = 0;
+            } else if (position >= adapter.size()) {
+                throw new IllegalArgumentException(
+                        String.format("Invalid position %d requested", position));
+            }
+            item = adapter.get(position);
+        }
+
+        boolean oldIsPageRow = mIsPageRow;
+        Object oldPageRow = mPageRow;
+        mIsPageRow = mCanShowHeaders && item instanceof PageRow;
+        mPageRow = mIsPageRow ? item : null;
+        boolean swap;
+
+        if (mMainFragment == null) {
+            swap = true;
+        } else {
+            if (oldIsPageRow) {
+                if (mIsPageRow) {
+                    if (oldPageRow == null) {
+                        // fragment is restored, page row object not yet set, so just set the
+                        // mPageRow object and there is no need to replace the fragment
+                        swap = false;
+                    } else {
+                        // swap if page row object changes
+                        swap = oldPageRow != mPageRow;
+                    }
+                } else {
+                    swap = true;
+                }
+            } else {
+                swap = mIsPageRow;
+            }
+        }
+
+        if (swap) {
+            mMainFragment = mMainFragmentAdapterRegistry.createFragment(item);
+            if (!(mMainFragment instanceof MainFragmentAdapterProvider)) {
+                throw new IllegalArgumentException(
+                        "Fragment must implement MainFragmentAdapterProvider");
+            }
+
+            setMainFragmentAdapter();
+        }
+
+        return swap;
+    }
+
+    void setMainFragmentAdapter() {
+        mMainFragmentAdapter = ((MainFragmentAdapterProvider) mMainFragment)
+                .getMainFragmentAdapter();
+        mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
+        if (!mIsPageRow) {
+            if (mMainFragment instanceof MainFragmentRowsAdapterProvider) {
+                setMainFragmentRowsAdapter(((MainFragmentRowsAdapterProvider) mMainFragment)
+                        .getMainFragmentRowsAdapter());
+            } else {
+                setMainFragmentRowsAdapter(null);
+            }
+            mIsPageRow = mMainFragmentRowsAdapter == null;
+        } else {
+            setMainFragmentRowsAdapter(null);
+        }
+    }
+
+    /**
+     * Factory class responsible for creating fragment given the current item. {@link ListRow}
+     * should return {@link RowsSupportFragment} or its subclass whereas {@link PageRow}
+     * can return any fragment class.
+     */
+    public abstract static class FragmentFactory<T extends Fragment> {
+        public abstract T createFragment(Object row);
+    }
+
+    /**
+     * FragmentFactory implementation for {@link ListRow}.
+     */
+    public static class ListRowFragmentFactory extends FragmentFactory<RowsSupportFragment> {
+        @Override
+        public RowsSupportFragment createFragment(Object row) {
+            return new RowsSupportFragment();
+        }
+    }
+
+    /**
+     * Registry class maintaining the mapping of {@link Row} subclasses to {@link FragmentFactory}.
+     * BrowseRowFragment automatically registers {@link ListRowFragmentFactory} for
+     * handling {@link ListRow}. Developers can override that and also if they want to
+     * use custom fragment, they can register a custom {@link FragmentFactory}
+     * against {@link PageRow}.
+     */
+    public final static class MainFragmentAdapterRegistry {
+        private final Map<Class, FragmentFactory> mItemToFragmentFactoryMapping = new HashMap<>();
+        private final static FragmentFactory sDefaultFragmentFactory = new ListRowFragmentFactory();
+
+        public MainFragmentAdapterRegistry() {
+            registerFragment(ListRow.class, sDefaultFragmentFactory);
+        }
+
+        public void registerFragment(Class rowClass, FragmentFactory factory) {
+            mItemToFragmentFactoryMapping.put(rowClass, factory);
+        }
+
+        public Fragment createFragment(Object item) {
+            FragmentFactory fragmentFactory = item == null ? sDefaultFragmentFactory :
+                    mItemToFragmentFactoryMapping.get(item.getClass());
+            if (fragmentFactory == null && !(item instanceof PageRow)) {
+                fragmentFactory = sDefaultFragmentFactory;
+            }
+
+            return fragmentFactory.createFragment(item);
+        }
+    }
+
+    static final String TAG = "BrowseSupportFragment";
+
+    private static final String LB_HEADERS_BACKSTACK = "lbHeadersBackStack_";
+
+    static final boolean DEBUG = false;
+
+    /** The headers fragment is enabled and shown by default. */
+    public static final int HEADERS_ENABLED = 1;
+
+    /** The headers fragment is enabled and hidden by default. */
+    public static final int HEADERS_HIDDEN = 2;
+
+    /** The headers fragment is disabled and will never be shown. */
+    public static final int HEADERS_DISABLED = 3;
+
+    private MainFragmentAdapterRegistry mMainFragmentAdapterRegistry =
+            new MainFragmentAdapterRegistry();
+    MainFragmentAdapter mMainFragmentAdapter;
+    Fragment mMainFragment;
+    HeadersSupportFragment mHeadersSupportFragment;
+    MainFragmentRowsAdapter mMainFragmentRowsAdapter;
+    ListRowDataAdapter mMainFragmentListRowDataAdapter;
+
+    private ObjectAdapter mAdapter;
+    private PresenterSelector mAdapterPresenter;
+
+    private int mHeadersState = HEADERS_ENABLED;
+    private int mBrandColor = Color.TRANSPARENT;
+    private boolean mBrandColorSet;
+
+    BrowseFrameLayout mBrowseFrame;
+    private ScaleFrameLayout mScaleFrameLayout;
+    boolean mHeadersBackStackEnabled = true;
+    String mWithHeadersBackStackName;
+    boolean mShowingHeaders = true;
+    boolean mCanShowHeaders = true;
+    private int mContainerListMarginStart;
+    private int mContainerListAlignTop;
+    private boolean mMainFragmentScaleEnabled = true;
+    OnItemViewSelectedListener mExternalOnItemViewSelectedListener;
+    private OnItemViewClickedListener mOnItemViewClickedListener;
+    private int mSelectedPosition = -1;
+    private float mScaleFactor;
+    boolean mIsPageRow;
+    Object mPageRow;
+
+    private PresenterSelector mHeaderPresenterSelector;
+    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    // transition related:
+    Object mSceneWithHeaders;
+    Object mSceneWithoutHeaders;
+    private Object mSceneAfterEntranceTransition;
+    Object mHeadersTransition;
+    BackStackListener mBackStackChangedListener;
+    BrowseTransitionListener mBrowseTransitionListener;
+
+    private static final String ARG_TITLE = BrowseSupportFragment.class.getCanonicalName() + ".title";
+    private static final String ARG_HEADERS_STATE =
+        BrowseSupportFragment.class.getCanonicalName() + ".headersState";
+
+    /**
+     * Creates arguments for a browse fragment.
+     *
+     * @param args The Bundle to place arguments into, or null if the method
+     *        should return a new Bundle.
+     * @param title The title of the BrowseSupportFragment.
+     * @param headersState The initial state of the headers of the
+     *        BrowseSupportFragment. Must be one of {@link #HEADERS_ENABLED}, {@link
+     *        #HEADERS_HIDDEN}, or {@link #HEADERS_DISABLED}.
+     * @return A Bundle with the given arguments for creating a BrowseSupportFragment.
+     */
+    public static Bundle createArgs(Bundle args, String title, int headersState) {
+        if (args == null) {
+            args = new Bundle();
+        }
+        args.putString(ARG_TITLE, title);
+        args.putInt(ARG_HEADERS_STATE, headersState);
+        return args;
+    }
+
+    /**
+     * Sets the brand color for the browse fragment. The brand color is used as
+     * the primary color for UI elements in the browse fragment. For example,
+     * the background color of the headers fragment uses the brand color.
+     *
+     * @param color The color to use as the brand color of the fragment.
+     */
+    public void setBrandColor(@ColorInt int color) {
+        mBrandColor = color;
+        mBrandColorSet = true;
+
+        if (mHeadersSupportFragment != null) {
+            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
+        }
+    }
+
+    /**
+     * Returns the brand color for the browse fragment.
+     * The default is transparent.
+     */
+    @ColorInt
+    public int getBrandColor() {
+        return mBrandColor;
+    }
+
+    /**
+     * Wrapping app provided PresenterSelector to support InvisibleRowPresenter for SectionRow
+     * DividerRow and PageRow.
+     */
+    private void updateWrapperPresenter() {
+        if (mAdapter == null) {
+            mAdapterPresenter = null;
+            return;
+        }
+        final PresenterSelector adapterPresenter = mAdapter.getPresenterSelector();
+        if (adapterPresenter == null) {
+            throw new IllegalArgumentException("Adapter.getPresenterSelector() is null");
+        }
+        if (adapterPresenter == mAdapterPresenter) {
+            return;
+        }
+        mAdapterPresenter = adapterPresenter;
+
+        Presenter[] presenters = adapterPresenter.getPresenters();
+        final Presenter invisibleRowPresenter = new InvisibleRowPresenter();
+        final Presenter[] allPresenters = new Presenter[presenters.length + 1];
+        System.arraycopy(allPresenters, 0, presenters, 0, presenters.length);
+        allPresenters[allPresenters.length - 1] = invisibleRowPresenter;
+        mAdapter.setPresenterSelector(new PresenterSelector() {
+            @Override
+            public Presenter getPresenter(Object item) {
+                Row row = (Row) item;
+                if (row.isRenderedAsRowView()) {
+                    return adapterPresenter.getPresenter(item);
+                } else {
+                    return invisibleRowPresenter;
+                }
+            }
+
+            @Override
+            public Presenter[] getPresenters() {
+                return allPresenters;
+            }
+        });
+    }
+
+    /**
+     * Sets the adapter containing the rows for the fragment.
+     *
+     * <p>The items referenced by the adapter must be be derived from
+     * {@link Row}. These rows will be used by the rows fragment and the headers
+     * fragment (if not disabled) to render the browse rows.
+     *
+     * @param adapter An ObjectAdapter for the browse rows. All items must
+     *        derive from {@link Row}.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        updateWrapperPresenter();
+        if (getView() == null) {
+            return;
+        }
+
+        updateMainFragmentRowsAdapter();
+        mHeadersSupportFragment.setAdapter(mAdapter);
+    }
+
+    void setMainFragmentRowsAdapter(MainFragmentRowsAdapter mainFragmentRowsAdapter) {
+        if (mainFragmentRowsAdapter == mMainFragmentRowsAdapter) {
+            return;
+        }
+        // first clear previous mMainFragmentRowsAdapter and set a new mMainFragmentRowsAdapter
+        if (mMainFragmentRowsAdapter != null) {
+            // RowsFragment cannot change click/select listeners after view created.
+            // The main fragment and adapter should be GCed as long as there is no reference from
+            // BrowseSupportFragment to it.
+            mMainFragmentRowsAdapter.setAdapter(null);
+        }
+        mMainFragmentRowsAdapter = mainFragmentRowsAdapter;
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setOnItemViewSelectedListener(
+                    new MainFragmentItemViewSelectedListener(mMainFragmentRowsAdapter));
+            mMainFragmentRowsAdapter.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        }
+        // second update mMainFragmentListRowDataAdapter set on mMainFragmentRowsAdapter
+        updateMainFragmentRowsAdapter();
+    }
+
+    /**
+     * Update mMainFragmentListRowDataAdapter and set it on mMainFragmentRowsAdapter.
+     * It also clears old mMainFragmentListRowDataAdapter.
+     */
+    void updateMainFragmentRowsAdapter() {
+        if (mMainFragmentListRowDataAdapter != null) {
+            mMainFragmentListRowDataAdapter.detach();
+            mMainFragmentListRowDataAdapter = null;
+        }
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentListRowDataAdapter = mAdapter == null
+                    ? null : new ListRowDataAdapter(mAdapter);
+            mMainFragmentRowsAdapter.setAdapter(mMainFragmentListRowDataAdapter);
+        }
+    }
+
+    public final MainFragmentAdapterRegistry getMainFragmentRegistry() {
+        return mMainFragmentAdapterRegistry;
+    }
+
+    /**
+     * Returns the adapter containing the rows for the fragment.
+     */
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Sets an item selection listener.
+     */
+    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
+        mExternalOnItemViewSelectedListener = listener;
+    }
+
+    /**
+     * Returns an item selection listener.
+     */
+    public OnItemViewSelectedListener getOnItemViewSelectedListener() {
+        return mExternalOnItemViewSelectedListener;
+    }
+
+    /**
+     * Get RowsSupportFragment if it's bound to BrowseSupportFragment or null if either BrowseSupportFragment has
+     * not been created yet or a different fragment is bound to it.
+     *
+     * @return RowsSupportFragment if it's bound to BrowseSupportFragment or null otherwise.
+     */
+    public RowsSupportFragment getRowsSupportFragment() {
+        if (mMainFragment instanceof RowsSupportFragment) {
+            return (RowsSupportFragment) mMainFragment;
+        }
+
+        return null;
+    }
+
+    /**
+     * @return Current main fragment or null if not created.
+     */
+    public Fragment getMainFragment() {
+        return mMainFragment;
+    }
+
+    /**
+     * Get currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
+     * @return Currently bound HeadersSupportFragment or null if HeadersSupportFragment has not been created yet.
+     */
+    public HeadersSupportFragment getHeadersSupportFragment() {
+        return mHeadersSupportFragment;
+    }
+
+    /**
+     * Sets an item clicked listener on the fragment.
+     * OnItemViewClickedListener will override {@link View.OnClickListener} that
+     * item presenter sets during {@link Presenter#onCreateViewHolder(ViewGroup)}.
+     * So in general, developer should choose one of the listeners but not both.
+     */
+    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+        mOnItemViewClickedListener = listener;
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setOnItemViewClickedListener(listener);
+        }
+    }
+
+    /**
+     * Returns the item Clicked listener.
+     */
+    public OnItemViewClickedListener getOnItemViewClickedListener() {
+        return mOnItemViewClickedListener;
+    }
+
+    /**
+     * Starts a headers transition.
+     *
+     * <p>This method will begin a transition to either show or hide the
+     * headers, depending on the value of withHeaders. If headers are disabled
+     * for this browse fragment, this method will throw an exception.
+     *
+     * @param withHeaders True if the headers should transition to being shown,
+     *        false if the transition should result in headers being hidden.
+     */
+    public void startHeadersTransition(boolean withHeaders) {
+        if (!mCanShowHeaders) {
+            throw new IllegalStateException("Cannot start headers transition");
+        }
+        if (isInHeadersTransition() || mShowingHeaders == withHeaders) {
+            return;
+        }
+        startHeadersTransitionInternal(withHeaders);
+    }
+
+    /**
+     * Returns true if the headers transition is currently running.
+     */
+    public boolean isInHeadersTransition() {
+        return mHeadersTransition != null;
+    }
+
+    /**
+     * Returns true if headers are shown.
+     */
+    public boolean isShowingHeaders() {
+        return mShowingHeaders;
+    }
+
+    /**
+     * Sets a listener for browse fragment transitions.
+     *
+     * @param listener The listener to call when a browse headers transition
+     *        begins or ends.
+     */
+    public void setBrowseTransitionListener(BrowseTransitionListener listener) {
+        mBrowseTransitionListener = listener;
+    }
+
+    /**
+     * @deprecated use {@link BrowseSupportFragment#enableMainFragmentScaling(boolean)} instead.
+     *
+     * @param enable true to enable row scaling
+     */
+    @Deprecated
+    public void enableRowScaling(boolean enable) {
+        enableMainFragmentScaling(enable);
+    }
+
+    /**
+     * Enables scaling of main fragment when headers are present. For the page/row fragment,
+     * scaling is enabled only when both this method and
+     * {@link MainFragmentAdapter#isScalingEnabled()} are enabled.
+     *
+     * @param enable true to enable row scaling
+     */
+    public void enableMainFragmentScaling(boolean enable) {
+        mMainFragmentScaleEnabled = enable;
+    }
+
+    void startHeadersTransitionInternal(final boolean withHeaders) {
+        if (getFragmentManager().isDestroyed()) {
+            return;
+        }
+        if (!isHeadersDataReady()) {
+            return;
+        }
+        mShowingHeaders = withHeaders;
+        mMainFragmentAdapter.onTransitionPrepare();
+        mMainFragmentAdapter.onTransitionStart();
+        onExpandTransitionStart(!withHeaders, new Runnable() {
+            @Override
+            public void run() {
+                mHeadersSupportFragment.onTransitionPrepare();
+                mHeadersSupportFragment.onTransitionStart();
+                createHeadersTransition();
+                if (mBrowseTransitionListener != null) {
+                    mBrowseTransitionListener.onHeadersTransitionStart(withHeaders);
+                }
+                TransitionHelper.runTransition(
+                        withHeaders ? mSceneWithHeaders : mSceneWithoutHeaders, mHeadersTransition);
+                if (mHeadersBackStackEnabled) {
+                    if (!withHeaders) {
+                        getFragmentManager().beginTransaction()
+                                .addToBackStack(mWithHeadersBackStackName).commit();
+                    } else {
+                        int index = mBackStackChangedListener.mIndexOfHeadersBackStack;
+                        if (index >= 0) {
+                            BackStackEntry entry = getFragmentManager().getBackStackEntryAt(index);
+                            getFragmentManager().popBackStackImmediate(entry.getId(),
+                                    FragmentManager.POP_BACK_STACK_INCLUSIVE);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    boolean isVerticalScrolling() {
+        // don't run transition
+        return mHeadersSupportFragment.isScrolling() || mMainFragmentAdapter.isScrolling();
+    }
+
+
+    private final BrowseFrameLayout.OnFocusSearchListener mOnFocusSearchListener =
+            new BrowseFrameLayout.OnFocusSearchListener() {
+        @Override
+        public View onFocusSearch(View focused, int direction) {
+            // if headers is running transition,  focus stays
+            if (mCanShowHeaders && isInHeadersTransition()) {
+                return focused;
+            }
+            if (DEBUG) Log.v(TAG, "onFocusSearch focused " + focused + " + direction " + direction);
+
+            if (getTitleView() != null && focused != getTitleView()
+                    && direction == View.FOCUS_UP) {
+                return getTitleView();
+            }
+            if (getTitleView() != null && getTitleView().hasFocus()
+                    && direction == View.FOCUS_DOWN) {
+                return mCanShowHeaders && mShowingHeaders
+                        ? mHeadersSupportFragment.getVerticalGridView() : mMainFragment.getView();
+            }
+
+            boolean isRtl = ViewCompat.getLayoutDirection(focused)
+                    == ViewCompat.LAYOUT_DIRECTION_RTL;
+            int towardStart = isRtl ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
+            int towardEnd = isRtl ? View.FOCUS_LEFT : View.FOCUS_RIGHT;
+            if (mCanShowHeaders && direction == towardStart) {
+                if (isVerticalScrolling() || mShowingHeaders || !isHeadersDataReady()) {
+                    return focused;
+                }
+                return mHeadersSupportFragment.getVerticalGridView();
+            } else if (direction == towardEnd) {
+                if (isVerticalScrolling()) {
+                    return focused;
+                } else if (mMainFragment != null && mMainFragment.getView() != null) {
+                    return mMainFragment.getView();
+                }
+                return focused;
+            } else if (direction == View.FOCUS_DOWN && mShowingHeaders) {
+                // disable focus_down moving into PageFragment.
+                return focused;
+            } else {
+                return null;
+            }
+        }
+    };
+
+    final boolean isHeadersDataReady() {
+        return mAdapter != null && mAdapter.size() != 0;
+    }
+
+    private final BrowseFrameLayout.OnChildFocusListener mOnChildFocusListener =
+            new BrowseFrameLayout.OnChildFocusListener() {
+
+        @Override
+        public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+            if (getChildFragmentManager().isDestroyed()) {
+                return true;
+            }
+            // Make sure not changing focus when requestFocus() is called.
+            if (mCanShowHeaders && mShowingHeaders) {
+                if (mHeadersSupportFragment != null && mHeadersSupportFragment.getView() != null
+                        && mHeadersSupportFragment.getView().requestFocus(
+                                direction, previouslyFocusedRect)) {
+                    return true;
+                }
+            }
+            if (mMainFragment != null && mMainFragment.getView() != null
+                    && mMainFragment.getView().requestFocus(direction, previouslyFocusedRect)) {
+                return true;
+            }
+            return getTitleView() != null
+                    && getTitleView().requestFocus(direction, previouslyFocusedRect);
+        }
+
+        @Override
+        public void onRequestChildFocus(View child, View focused) {
+            if (getChildFragmentManager().isDestroyed()) {
+                return;
+            }
+            if (!mCanShowHeaders || isInHeadersTransition()) return;
+            int childId = child.getId();
+            if (childId == R.id.browse_container_dock && mShowingHeaders) {
+                startHeadersTransitionInternal(false);
+            } else if (childId == R.id.browse_headers_dock && !mShowingHeaders) {
+                startHeadersTransitionInternal(true);
+            }
+        }
+    };
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(CURRENT_SELECTED_POSITION, mSelectedPosition);
+        outState.putBoolean(IS_PAGE_ROW, mIsPageRow);
+
+        if (mBackStackChangedListener != null) {
+            mBackStackChangedListener.save(outState);
+        } else {
+            outState.putBoolean(HEADER_SHOW, mShowingHeaders);
+        }
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final Context context = getContext();
+        TypedArray ta = context.obtainStyledAttributes(R.styleable.LeanbackTheme);
+        mContainerListMarginStart = (int) ta.getDimension(
+                R.styleable.LeanbackTheme_browseRowsMarginStart, context.getResources()
+                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_start));
+        mContainerListAlignTop = (int) ta.getDimension(
+                R.styleable.LeanbackTheme_browseRowsMarginTop, context.getResources()
+                .getDimensionPixelSize(R.dimen.lb_browse_rows_margin_top));
+        ta.recycle();
+
+        readArguments(getArguments());
+
+        if (mCanShowHeaders) {
+            if (mHeadersBackStackEnabled) {
+                mWithHeadersBackStackName = LB_HEADERS_BACKSTACK + this;
+                mBackStackChangedListener = new BackStackListener();
+                getFragmentManager().addOnBackStackChangedListener(mBackStackChangedListener);
+                mBackStackChangedListener.load(savedInstanceState);
+            } else {
+                if (savedInstanceState != null) {
+                    mShowingHeaders = savedInstanceState.getBoolean(HEADER_SHOW);
+                }
+            }
+        }
+
+        mScaleFactor = getResources().getFraction(R.fraction.lb_browse_rows_scale, 1, 1);
+    }
+
+    @Override
+    public void onDestroyView() {
+        setMainFragmentRowsAdapter(null);
+        mPageRow = null;
+        mMainFragmentAdapter = null;
+        mMainFragment = null;
+        mHeadersSupportFragment = null;
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mBackStackChangedListener != null) {
+            getFragmentManager().removeOnBackStackChangedListener(mBackStackChangedListener);
+        }
+        super.onDestroy();
+    }
+
+    /**
+     * Creates a new {@link HeadersSupportFragment} instance. Subclass of BrowseSupportFragment may override and
+     * return an instance of subclass of HeadersSupportFragment, e.g. when app wants to replace presenter
+     * to render HeaderItem.
+     *
+     * @return A new instance of {@link HeadersSupportFragment} or its subclass.
+     */
+    public HeadersSupportFragment onCreateHeadersSupportFragment() {
+        return new HeadersSupportFragment();
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+
+        if (getChildFragmentManager().findFragmentById(R.id.scale_frame) == null) {
+            mHeadersSupportFragment = onCreateHeadersSupportFragment();
+
+            createMainFragment(mAdapter, mSelectedPosition);
+            FragmentTransaction ft = getChildFragmentManager().beginTransaction()
+                    .replace(R.id.browse_headers_dock, mHeadersSupportFragment);
+
+            if (mMainFragment != null) {
+                ft.replace(R.id.scale_frame, mMainFragment);
+            } else {
+                // Empty adapter used to guard against lazy adapter loading. When this
+                // fragment is instantiated, mAdapter might not have the data or might not
+                // have been set. In either of those cases mFragmentAdapter will be null.
+                // This way we can maintain the invariant that mMainFragmentAdapter is never
+                // null and it avoids doing null checks all over the code.
+                mMainFragmentAdapter = new MainFragmentAdapter(null);
+                mMainFragmentAdapter.setFragmentHost(new FragmentHostImpl());
+            }
+
+            ft.commit();
+        } else {
+            mHeadersSupportFragment = (HeadersSupportFragment) getChildFragmentManager()
+                    .findFragmentById(R.id.browse_headers_dock);
+            mMainFragment = getChildFragmentManager().findFragmentById(R.id.scale_frame);
+
+            mIsPageRow = savedInstanceState != null
+                    && savedInstanceState.getBoolean(IS_PAGE_ROW, false);
+            // mPageRow object is unable to restore, if its null and mIsPageRow is true, this is
+            // the case for restoring, later if setSelection() triggers a createMainFragment(),
+            // should not create fragment.
+
+            mSelectedPosition = savedInstanceState != null
+                    ? savedInstanceState.getInt(CURRENT_SELECTED_POSITION, 0) : 0;
+
+            setMainFragmentAdapter();
+        }
+
+        mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
+        if (mHeaderPresenterSelector != null) {
+            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
+        }
+        mHeadersSupportFragment.setAdapter(mAdapter);
+        mHeadersSupportFragment.setOnHeaderViewSelectedListener(mHeaderViewSelectedListener);
+        mHeadersSupportFragment.setOnHeaderClickedListener(mHeaderClickedListener);
+
+        View root = inflater.inflate(R.layout.lb_browse_fragment, container, false);
+
+        getProgressBarManager().setRootView((ViewGroup)root);
+
+        mBrowseFrame = (BrowseFrameLayout) root.findViewById(R.id.browse_frame);
+        mBrowseFrame.setOnChildFocusListener(mOnChildFocusListener);
+        mBrowseFrame.setOnFocusSearchListener(mOnFocusSearchListener);
+
+        installTitleView(inflater, mBrowseFrame, savedInstanceState);
+
+        mScaleFrameLayout = (ScaleFrameLayout) root.findViewById(R.id.scale_frame);
+        mScaleFrameLayout.setPivotX(0);
+        mScaleFrameLayout.setPivotY(mContainerListAlignTop);
+
+        if (mBrandColorSet) {
+            mHeadersSupportFragment.setBackgroundColor(mBrandColor);
+        }
+
+        mSceneWithHeaders = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
+            @Override
+            public void run() {
+                showHeaders(true);
+            }
+        });
+        mSceneWithoutHeaders =  TransitionHelper.createScene(mBrowseFrame, new Runnable() {
+            @Override
+            public void run() {
+                showHeaders(false);
+            }
+        });
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(mBrowseFrame, new Runnable() {
+            @Override
+            public void run() {
+                setEntranceTransitionEndState();
+            }
+        });
+
+        return root;
+    }
+
+    void createHeadersTransition() {
+        mHeadersTransition = TransitionHelper.loadTransition(getContext(),
+                mShowingHeaders
+                        ? R.transition.lb_browse_headers_in : R.transition.lb_browse_headers_out);
+
+        TransitionHelper.addTransitionListener(mHeadersTransition, new TransitionListener() {
+            @Override
+            public void onTransitionStart(Object transition) {
+            }
+            @Override
+            public void onTransitionEnd(Object transition) {
+                mHeadersTransition = null;
+                if (mMainFragmentAdapter != null) {
+                    mMainFragmentAdapter.onTransitionEnd();
+                    if (!mShowingHeaders && mMainFragment != null) {
+                        View mainFragmentView = mMainFragment.getView();
+                        if (mainFragmentView != null && !mainFragmentView.hasFocus()) {
+                            mainFragmentView.requestFocus();
+                        }
+                    }
+                }
+                if (mHeadersSupportFragment != null) {
+                    mHeadersSupportFragment.onTransitionEnd();
+                    if (mShowingHeaders) {
+                        VerticalGridView headerGridView = mHeadersSupportFragment.getVerticalGridView();
+                        if (headerGridView != null && !headerGridView.hasFocus()) {
+                            headerGridView.requestFocus();
+                        }
+                    }
+                }
+
+                // Animate TitleView once header animation is complete.
+                updateTitleViewVisibility();
+
+                if (mBrowseTransitionListener != null) {
+                    mBrowseTransitionListener.onHeadersTransitionStop(mShowingHeaders);
+                }
+            }
+        });
+    }
+
+    void updateTitleViewVisibility() {
+        if (!mShowingHeaders) {
+            boolean showTitleView;
+            if (mIsPageRow && mMainFragmentAdapter != null) {
+                // page fragment case:
+                showTitleView = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
+            } else {
+                // regular row view case:
+                showTitleView = isFirstRowWithContent(mSelectedPosition);
+            }
+            if (showTitleView) {
+                showTitle(TitleViewAdapter.FULL_VIEW_VISIBLE);
+            } else {
+                showTitle(false);
+            }
+        } else {
+            // when HeaderFragment is showing,  showBranding and showSearch are slightly different
+            boolean showBranding;
+            boolean showSearch;
+            if (mIsPageRow && mMainFragmentAdapter != null) {
+                showBranding = mMainFragmentAdapter.mFragmentHost.mShowTitleView;
+            } else {
+                showBranding = isFirstRowWithContent(mSelectedPosition);
+            }
+            showSearch = isFirstRowWithContentOrPageRow(mSelectedPosition);
+            int flags = 0;
+            if (showBranding) flags |= TitleViewAdapter.BRANDING_VIEW_VISIBLE;
+            if (showSearch) flags |= TitleViewAdapter.SEARCH_VIEW_VISIBLE;
+            if (flags != 0) {
+                showTitle(flags);
+            } else {
+                showTitle(false);
+            }
+        }
+    }
+
+    boolean isFirstRowWithContentOrPageRow(int rowPosition) {
+        if (mAdapter == null || mAdapter.size() == 0) {
+            return true;
+        }
+        for (int i = 0; i < mAdapter.size(); i++) {
+            final Row row = (Row) mAdapter.get(i);
+            if (row.isRenderedAsRowView() || row instanceof PageRow) {
+                return rowPosition == i;
+            }
+        }
+        return true;
+    }
+
+    boolean isFirstRowWithContent(int rowPosition) {
+        if (mAdapter == null || mAdapter.size() == 0) {
+            return true;
+        }
+        for (int i = 0; i < mAdapter.size(); i++) {
+            final Row row = (Row) mAdapter.get(i);
+            if (row.isRenderedAsRowView()) {
+                return rowPosition == i;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Sets the {@link PresenterSelector} used to render the row headers.
+     *
+     * @param headerPresenterSelector The PresenterSelector that will determine
+     *        the Presenter for each row header.
+     */
+    public void setHeaderPresenterSelector(PresenterSelector headerPresenterSelector) {
+        mHeaderPresenterSelector = headerPresenterSelector;
+        if (mHeadersSupportFragment != null) {
+            mHeadersSupportFragment.setPresenterSelector(mHeaderPresenterSelector);
+        }
+    }
+
+    private void setHeadersOnScreen(boolean onScreen) {
+        MarginLayoutParams lp;
+        View containerList;
+        containerList = mHeadersSupportFragment.getView();
+        lp = (MarginLayoutParams) containerList.getLayoutParams();
+        lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
+        containerList.setLayoutParams(lp);
+    }
+
+    void showHeaders(boolean show) {
+        if (DEBUG) Log.v(TAG, "showHeaders " + show);
+        mHeadersSupportFragment.setHeadersEnabled(show);
+        setHeadersOnScreen(show);
+        expandMainFragment(!show);
+    }
+
+    private void expandMainFragment(boolean expand) {
+        MarginLayoutParams params = (MarginLayoutParams) mScaleFrameLayout.getLayoutParams();
+        params.setMarginStart(!expand ? mContainerListMarginStart : 0);
+        mScaleFrameLayout.setLayoutParams(params);
+        mMainFragmentAdapter.setExpand(expand);
+
+        setMainFragmentAlignment();
+        final float scaleFactor = !expand
+                && mMainFragmentScaleEnabled
+                && mMainFragmentAdapter.isScalingEnabled() ? mScaleFactor : 1;
+        mScaleFrameLayout.setLayoutScaleY(scaleFactor);
+        mScaleFrameLayout.setChildScale(scaleFactor);
+    }
+
+    private HeadersSupportFragment.OnHeaderClickedListener mHeaderClickedListener =
+        new HeadersSupportFragment.OnHeaderClickedListener() {
+            @Override
+            public void onHeaderClicked(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
+                if (!mCanShowHeaders || !mShowingHeaders || isInHeadersTransition()) {
+                    return;
+                }
+                if (mMainFragment == null || mMainFragment.getView() == null) {
+                    return;
+                }
+                startHeadersTransitionInternal(false);
+                mMainFragment.getView().requestFocus();
+            }
+        };
+
+    class MainFragmentItemViewSelectedListener implements OnItemViewSelectedListener {
+        MainFragmentRowsAdapter mMainFragmentRowsAdapter;
+
+        public MainFragmentItemViewSelectedListener(MainFragmentRowsAdapter fragmentRowsAdapter) {
+            mMainFragmentRowsAdapter = fragmentRowsAdapter;
+        }
+
+        @Override
+        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                RowPresenter.ViewHolder rowViewHolder, Row row) {
+            int position = mMainFragmentRowsAdapter.getSelectedPosition();
+            if (DEBUG) Log.v(TAG, "row selected position " + position);
+            onRowSelected(position);
+            if (mExternalOnItemViewSelectedListener != null) {
+                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
+                        rowViewHolder, row);
+            }
+        }
+    };
+
+    private HeadersSupportFragment.OnHeaderViewSelectedListener mHeaderViewSelectedListener =
+            new HeadersSupportFragment.OnHeaderViewSelectedListener() {
+        @Override
+        public void onHeaderSelected(RowHeaderPresenter.ViewHolder viewHolder, Row row) {
+            int position = mHeadersSupportFragment.getSelectedPosition();
+            if (DEBUG) Log.v(TAG, "header selected position " + position);
+            onRowSelected(position);
+        }
+    };
+
+    void onRowSelected(int position) {
+        // even position is same, it could be data changed, always post selection runnable
+        // to possibly swap main fragment.
+        mSetSelectionRunnable.post(
+                position, SetSelectionRunnable.TYPE_INTERNAL_SYNC, true);
+    }
+
+    void setSelection(int position, boolean smooth) {
+        if (position == NO_POSITION) {
+            return;
+        }
+
+        mSelectedPosition = position;
+        if (mHeadersSupportFragment == null || mMainFragmentAdapter == null) {
+            // onDestroyView() called
+            return;
+        }
+        mHeadersSupportFragment.setSelectedPosition(position, smooth);
+        replaceMainFragment(position);
+
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setSelectedPosition(position, smooth);
+        }
+
+        updateTitleViewVisibility();
+    }
+
+    private void replaceMainFragment(int position) {
+        if (createMainFragment(mAdapter, position)) {
+            swapToMainFragment();
+            expandMainFragment(!(mCanShowHeaders && mShowingHeaders));
+        }
+    }
+
+    private void swapToMainFragment() {
+        final VerticalGridView gridView = mHeadersSupportFragment.getVerticalGridView();
+        if (isShowingHeaders() && gridView != null
+                && gridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
+            // if user is scrolling HeadersSupportFragment,  swap to empty fragment and wait scrolling
+            // finishes.
+            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) {
+                        gridView.removeOnScrollListener(this);
+                        FragmentManager fm = getChildFragmentManager();
+                        Fragment currentFragment = fm.findFragmentById(R.id.scale_frame);
+                        if (currentFragment != mMainFragment) {
+                            fm.beginTransaction().replace(R.id.scale_frame, mMainFragment).commit();
+                        }
+                    }
+                }
+            });
+        } else {
+            // Otherwise swap immediately
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.scale_frame, mMainFragment).commit();
+        }
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Gets position of currently selected row.
+     * @return Position of currently selected row.
+     */
+    public int getSelectedPosition() {
+        return mSelectedPosition;
+    }
+
+    /**
+     * @return selected row ViewHolder inside fragment created by {@link MainFragmentRowsAdapter}.
+     */
+    public RowPresenter.ViewHolder getSelectedRowViewHolder() {
+        if (mMainFragmentRowsAdapter != null) {
+            int rowPos = mMainFragmentRowsAdapter.getSelectedPosition();
+            return mMainFragmentRowsAdapter.findRowViewHolderByPosition(rowPos);
+        }
+        return null;
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.post(
+                position, SetSelectionRunnable.TYPE_USER_REQUEST, smooth);
+    }
+
+    /**
+     * Selects a Row and perform an optional task on the Row. For example
+     * <code>setSelectedPosition(10, true, new ListRowPresenterSelectItemViewHolderTask(5))</code>
+     * scrolls to 11th row and selects 6th item on that row.  The method will be ignored if
+     * RowsSupportFragment has not been created (i.e. before {@link #onCreateView(LayoutInflater,
+     * ViewGroup, Bundle)}).
+     *
+     * @param rowPosition Which row to select.
+     * @param smooth True to scroll to the row, false for no animation.
+     * @param rowHolderTask Optional task to perform on the Row.  When the task is not null, headers
+     * fragment will be collapsed.
+     */
+    public void setSelectedPosition(int rowPosition, boolean smooth,
+            final Presenter.ViewHolderTask rowHolderTask) {
+        if (mMainFragmentAdapterRegistry == null) {
+            return;
+        }
+        if (rowHolderTask != null) {
+            startHeadersTransition(false);
+        }
+        if (mMainFragmentRowsAdapter != null) {
+            mMainFragmentRowsAdapter.setSelectedPosition(rowPosition, smooth, rowHolderTask);
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        mHeadersSupportFragment.setAlignment(mContainerListAlignTop);
+        setMainFragmentAlignment();
+
+        if (mCanShowHeaders && mShowingHeaders && mHeadersSupportFragment != null
+                && mHeadersSupportFragment.getView() != null) {
+            mHeadersSupportFragment.getView().requestFocus();
+        } else if ((!mCanShowHeaders || !mShowingHeaders) && mMainFragment != null
+                && mMainFragment.getView() != null) {
+            mMainFragment.getView().requestFocus();
+        }
+
+        if (mCanShowHeaders) {
+            showHeaders(mShowingHeaders);
+        }
+
+        mStateMachine.fireEvent(EVT_HEADER_VIEW_CREATED);
+    }
+
+    private void onExpandTransitionStart(boolean expand, final Runnable callback) {
+        if (expand) {
+            callback.run();
+            return;
+        }
+        // Run a "pre" layout when we go non-expand, in order to get the initial
+        // positions of added rows.
+        new ExpandPreLayout(callback, mMainFragmentAdapter, getView()).execute();
+    }
+
+    private void setMainFragmentAlignment() {
+        int alignOffset = mContainerListAlignTop;
+        if (mMainFragmentScaleEnabled
+                && mMainFragmentAdapter.isScalingEnabled()
+                && mShowingHeaders) {
+            alignOffset = (int) (alignOffset / mScaleFactor + 0.5f);
+        }
+        mMainFragmentAdapter.setAlignment(alignOffset);
+    }
+
+    /**
+     * Enables/disables headers transition on back key support. This is enabled by
+     * default. The BrowseSupportFragment will add a back stack entry when headers are
+     * showing. Running a headers transition when the back key is pressed only
+     * works when the headers state is {@link #HEADERS_ENABLED} or
+     * {@link #HEADERS_HIDDEN}.
+     * <p>
+     * NOTE: If an Activity has its own onBackPressed() handling, you must
+     * disable this feature. You may use {@link #startHeadersTransition(boolean)}
+     * and {@link BrowseTransitionListener} in your own back stack handling.
+     */
+    public final void setHeadersTransitionOnBackEnabled(boolean headersBackStackEnabled) {
+        mHeadersBackStackEnabled = headersBackStackEnabled;
+    }
+
+    /**
+     * Returns true if headers transition on back key support is enabled.
+     */
+    public final boolean isHeadersTransitionOnBackEnabled() {
+        return mHeadersBackStackEnabled;
+    }
+
+    private void readArguments(Bundle args) {
+        if (args == null) {
+            return;
+        }
+        if (args.containsKey(ARG_TITLE)) {
+            setTitle(args.getString(ARG_TITLE));
+        }
+        if (args.containsKey(ARG_HEADERS_STATE)) {
+            setHeadersState(args.getInt(ARG_HEADERS_STATE));
+        }
+    }
+
+    /**
+     * Sets the state for the headers column in the browse fragment. Must be one
+     * of {@link #HEADERS_ENABLED}, {@link #HEADERS_HIDDEN}, or
+     * {@link #HEADERS_DISABLED}.
+     *
+     * @param headersState The state of the headers for the browse fragment.
+     */
+    public void setHeadersState(int headersState) {
+        if (headersState < HEADERS_ENABLED || headersState > HEADERS_DISABLED) {
+            throw new IllegalArgumentException("Invalid headers state: " + headersState);
+        }
+        if (DEBUG) Log.v(TAG, "setHeadersState " + headersState);
+
+        if (headersState != mHeadersState) {
+            mHeadersState = headersState;
+            switch (headersState) {
+                case HEADERS_ENABLED:
+                    mCanShowHeaders = true;
+                    mShowingHeaders = true;
+                    break;
+                case HEADERS_HIDDEN:
+                    mCanShowHeaders = true;
+                    mShowingHeaders = false;
+                    break;
+                case HEADERS_DISABLED:
+                    mCanShowHeaders = false;
+                    mShowingHeaders = false;
+                    break;
+                default:
+                    Log.w(TAG, "Unknown headers state: " + headersState);
+                    break;
+            }
+            if (mHeadersSupportFragment != null) {
+                mHeadersSupportFragment.setHeadersGone(!mCanShowHeaders);
+            }
+        }
+    }
+
+    /**
+     * Returns the state of the headers column in the browse fragment.
+     */
+    public int getHeadersState() {
+        return mHeadersState;
+    }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(getContext(),
+                R.transition.lb_browse_entrance_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    @Override
+    protected void onEntranceTransitionPrepare() {
+        mHeadersSupportFragment.onTransitionPrepare();
+        mMainFragmentAdapter.setEntranceTransitionState(false);
+        mMainFragmentAdapter.onTransitionPrepare();
+    }
+
+    @Override
+    protected void onEntranceTransitionStart() {
+        mHeadersSupportFragment.onTransitionStart();
+        mMainFragmentAdapter.onTransitionStart();
+    }
+
+    @Override
+    protected void onEntranceTransitionEnd() {
+        if (mMainFragmentAdapter != null) {
+            mMainFragmentAdapter.onTransitionEnd();
+        }
+
+        if (mHeadersSupportFragment != null) {
+            mHeadersSupportFragment.onTransitionEnd();
+        }
+    }
+
+    void setSearchOrbViewOnScreen(boolean onScreen) {
+        View searchOrbView = getTitleViewAdapter().getSearchAffordanceView();
+        if (searchOrbView != null) {
+            MarginLayoutParams lp = (MarginLayoutParams) searchOrbView.getLayoutParams();
+            lp.setMarginStart(onScreen ? 0 : -mContainerListMarginStart);
+            searchOrbView.setLayoutParams(lp);
+        }
+    }
+
+    void setEntranceTransitionStartState() {
+        setHeadersOnScreen(false);
+        setSearchOrbViewOnScreen(false);
+        // NOTE that mMainFragmentAdapter.setEntranceTransitionState(false) will be called
+        // in onEntranceTransitionPrepare() because mMainFragmentAdapter is still the dummy
+        // one when setEntranceTransitionStartState() is called.
+    }
+
+    void setEntranceTransitionEndState() {
+        setHeadersOnScreen(mShowingHeaders);
+        setSearchOrbViewOnScreen(true);
+        mMainFragmentAdapter.setEntranceTransitionState(true);
+    }
+
+    private class ExpandPreLayout implements ViewTreeObserver.OnPreDrawListener {
+
+        private final View mView;
+        private final Runnable mCallback;
+        private int mState;
+        private MainFragmentAdapter mainFragmentAdapter;
+
+        final static int STATE_INIT = 0;
+        final static int STATE_FIRST_DRAW = 1;
+        final static int STATE_SECOND_DRAW = 2;
+
+        ExpandPreLayout(Runnable callback, MainFragmentAdapter adapter, View view) {
+            mView = view;
+            mCallback = callback;
+            mainFragmentAdapter = adapter;
+        }
+
+        void execute() {
+            mView.getViewTreeObserver().addOnPreDrawListener(this);
+            mainFragmentAdapter.setExpand(false);
+            // always trigger onPreDraw even adapter setExpand() does nothing.
+            mView.invalidate();
+            mState = STATE_INIT;
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            if (getView() == null || getContext() == null) {
+                mView.getViewTreeObserver().removeOnPreDrawListener(this);
+                return true;
+            }
+            if (mState == STATE_INIT) {
+                mainFragmentAdapter.setExpand(true);
+                // always trigger onPreDraw even adapter setExpand() does nothing.
+                mView.invalidate();
+                mState = STATE_FIRST_DRAW;
+            } else if (mState == STATE_FIRST_DRAW) {
+                mCallback.run();
+                mView.getViewTreeObserver().removeOnPreDrawListener(this);
+                mState = STATE_SECOND_DRAW;
+            }
+            return false;
+        }
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java b/leanback/src/main/java/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/app/DetailsBackgroundVideoHelper.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/DetailsFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/DetailsFragment.java
new file mode 100644
index 0000000..d64efe5
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/DetailsFragment.java
@@ -0,0 +1,934 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from DetailsSupportFragment.java.  DO NOT MODIFY. */
+
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from DetailsFragment.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.CallSuper;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.transition.TransitionListener;
+import android.support.v17.leanback.util.StateMachine.Event;
+import android.support.v17.leanback.util.StateMachine.State;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
+import android.support.v17.leanback.widget.BrowseFrameLayout;
+import android.support.v17.leanback.widget.DetailsParallax;
+import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
+import android.support.v17.leanback.widget.ItemBridgeAdapter;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A fragment for creating Leanback details screens.
+ *
+ * <p>
+ * A DetailsFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list.The Adapter's {@link PresenterSelector} must maintain subclasses
+ * of {@link RowPresenter}.
+ * </p>
+ *
+ * When {@link FullWidthDetailsOverviewRowPresenter} is found in adapter,  DetailsFragment will
+ * setup default behavior of the DetailsOverviewRow:
+ * <li>
+ * The alignment of FullWidthDetailsOverviewRowPresenter is setup in
+ * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}.
+ * </li>
+ * <li>
+ * The view status switching of FullWidthDetailsOverviewRowPresenter is done in
+ * {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
+ * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)}.
+ * </li>
+ *
+ * <p>
+ * The recommended activity themes to use with a DetailsFragment are
+ * <li>
+ * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details} with activity
+ * shared element transition for {@link FullWidthDetailsOverviewRowPresenter}.
+ * </li>
+ * <li>
+ * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details_NoSharedElementTransition}
+ * if shared element transition is not needed, for example if first row is not rendered by
+ * {@link FullWidthDetailsOverviewRowPresenter}.
+ * </li>
+ * </p>
+ *
+ * <p>
+ * DetailsFragment can use {@link DetailsFragmentBackgroundController} to add a parallax drawable
+ * background and embedded video playing fragment.
+ * </p>
+ * @deprecated use {@link DetailsSupportFragment}
+ */
+@Deprecated
+public class DetailsFragment extends BaseFragment {
+    static final String TAG = "DetailsFragment";
+    static final boolean DEBUG = false;
+
+    final State STATE_SET_ENTRANCE_START_STATE = new State("STATE_SET_ENTRANCE_START_STATE") {
+        @Override
+        public void run() {
+            mRowsFragment.setEntranceTransitionState(false);
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_INIT = new State("STATE_ENTER_TRANSIITON_INIT");
+
+    void switchToVideoBeforeVideoFragmentCreated() {
+        // if the video fragment is not ready: immediately fade out covering drawable,
+        // hide title and mark mPendingFocusOnVideo and set focus on it later.
+        mDetailsBackgroundController.switchToVideoBeforeCreate();
+        showTitle(false);
+        mPendingFocusOnVideo = true;
+        slideOutGridView();
+    }
+
+    final State STATE_SWITCH_TO_VIDEO_IN_ON_CREATE = new State("STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
+            false, false) {
+        @Override
+        public void run() {
+            switchToVideoBeforeVideoFragmentCreated();
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_CANCEL = new State("STATE_ENTER_TRANSITION_CANCEL",
+            false, false) {
+        @Override
+        public void run() {
+            if (mWaitEnterTransitionTimeout != null) {
+                mWaitEnterTransitionTimeout.mRef.clear();
+            }
+            // clear the activity enter/sharedElement transition, return transitions are kept.
+            // keep the return transitions and clear enter transition
+            if (getActivity() != null) {
+                Window window = getActivity().getWindow();
+                Object returnTransition = TransitionHelper.getReturnTransition(window);
+                Object sharedReturnTransition = TransitionHelper
+                        .getSharedElementReturnTransition(window);
+                TransitionHelper.setEnterTransition(window, null);
+                TransitionHelper.setSharedElementEnterTransition(window, null);
+                TransitionHelper.setReturnTransition(window, returnTransition);
+                TransitionHelper.setSharedElementReturnTransition(window, sharedReturnTransition);
+            }
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_COMPLETE = new State("STATE_ENTER_TRANSIITON_COMPLETE",
+            true, false);
+
+    final State STATE_ENTER_TRANSITION_ADDLISTENER = new State("STATE_ENTER_TRANSITION_PENDING") {
+        @Override
+        public void run() {
+            Object transition = TransitionHelper.getEnterTransition(getActivity().getWindow());
+            TransitionHelper.addTransitionListener(transition, mEnterTransitionListener);
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_PENDING = new State("STATE_ENTER_TRANSITION_PENDING") {
+        @Override
+        public void run() {
+            if (mWaitEnterTransitionTimeout == null) {
+                new WaitEnterTransitionTimeout(DetailsFragment.this);
+            }
+        }
+    };
+
+    /**
+     * Start this task when first DetailsOverviewRow is created, if there is no entrance transition
+     * started, it will clear PF_ENTRANCE_TRANSITION_PENDING.
+     */
+    static class WaitEnterTransitionTimeout implements Runnable {
+        static final long WAIT_ENTERTRANSITION_START = 200;
+
+        final WeakReference<DetailsFragment> mRef;
+
+        WaitEnterTransitionTimeout(DetailsFragment f) {
+            mRef = new WeakReference<>(f);
+            f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
+        }
+
+        @Override
+        public void run() {
+            DetailsFragment f = mRef.get();
+            if (f != null) {
+                f.mStateMachine.fireEvent(f.EVT_ENTER_TRANSIITON_DONE);
+            }
+        }
+    }
+
+    final State STATE_ON_SAFE_START = new State("STATE_ON_SAFE_START") {
+        @Override
+        public void run() {
+            onSafeStart();
+        }
+    };
+
+    final Event EVT_ONSTART = new Event("onStart");
+
+    final Event EVT_NO_ENTER_TRANSITION = new Event("EVT_NO_ENTER_TRANSITION");
+
+    final Event EVT_DETAILS_ROW_LOADED = new Event("onFirstRowLoaded");
+
+    final Event EVT_ENTER_TRANSIITON_DONE = new Event("onEnterTransitionDone");
+
+    final Event EVT_SWITCH_TO_VIDEO = new Event("switchToVideo");
+
+    @Override
+    void createStateMachineStates() {
+        super.createStateMachineStates();
+        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
+        mStateMachine.addState(STATE_ON_SAFE_START);
+        mStateMachine.addState(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_INIT);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_ADDLISTENER);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_CANCEL);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_PENDING);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_COMPLETE);
+    }
+
+    @Override
+    void createStateMachineTransitions() {
+        super.createStateMachineTransitions();
+        /**
+         * Part 1: Processing enter transitions after fragment.onCreate
+         */
+        mStateMachine.addTransition(STATE_START, STATE_ENTER_TRANSITION_INIT, EVT_ON_CREATE);
+        // if transition is not supported, skip to complete
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
+                COND_TRANSITION_NOT_SUPPORTED);
+        // if transition is not set on Activity, skip to complete
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
+                EVT_NO_ENTER_TRANSITION);
+        // if switchToVideo is called before EVT_ON_CREATEVIEW, clear enter transition and skip to
+        // complete.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_CANCEL,
+                EVT_SWITCH_TO_VIDEO);
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_CANCEL, STATE_ENTER_TRANSITION_COMPLETE);
+        // once after onCreateView, we cannot skip the enter transition, add a listener and wait
+        // it to finish
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_ADDLISTENER,
+                EVT_ON_CREATEVIEW);
+        // when enter transition finishes, go to complete, however this might never happen if
+        // the activity is not giving transition options in startActivity, there is no API to query
+        // if this activity is started in a enter transition mode. So we rely on a timer below:
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
+                STATE_ENTER_TRANSITION_COMPLETE, EVT_ENTER_TRANSIITON_DONE);
+        // we are expecting app to start delayed enter transition shortly after details row is
+        // loaded, so create a timer and wait for enter transition start.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
+                STATE_ENTER_TRANSITION_PENDING, EVT_DETAILS_ROW_LOADED);
+        // if enter transition not started in the timer, skip to DONE, this can be also true when
+        // startActivity is not giving transition option.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_PENDING, STATE_ENTER_TRANSITION_COMPLETE,
+                EVT_ENTER_TRANSIITON_DONE);
+
+        /**
+         * Part 2: modification to the entrance transition defined in BaseFragment
+         */
+        // Must finish enter transition before perform entrance transition.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ENTRANCE_PERFORM);
+        // Calling switch to video would hide immediately and skip entrance transition
+        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
+                EVT_SWITCH_TO_VIDEO);
+        mStateMachine.addTransition(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE, STATE_ENTRANCE_COMPLETE);
+        // if the entrance transition is skipped to complete by COND_TRANSITION_NOT_SUPPORTED, we
+        // still need to do the switchToVideo.
+        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
+                EVT_SWITCH_TO_VIDEO);
+
+        // for once the view is created in onStart and prepareEntranceTransition was called, we
+        // could setEntranceStartState:
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
+                STATE_SET_ENTRANCE_START_STATE, EVT_ONSTART);
+
+        /**
+         * Part 3: onSafeStart()
+         */
+        // for onSafeStart: the condition is onStart called, entrance transition complete
+        mStateMachine.addTransition(STATE_START, STATE_ON_SAFE_START, EVT_ONSTART);
+        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_ON_SAFE_START);
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ON_SAFE_START);
+    }
+
+    private class SetSelectionRunnable implements Runnable {
+        int mPosition;
+        boolean mSmooth = true;
+
+        SetSelectionRunnable() {
+        }
+
+        @Override
+        public void run() {
+            if (mRowsFragment == null) {
+                return;
+            }
+            mRowsFragment.setSelectedPosition(mPosition, mSmooth);
+        }
+    }
+
+    TransitionListener mEnterTransitionListener = new TransitionListener() {
+        @Override
+        public void onTransitionStart(Object transition) {
+            if (mWaitEnterTransitionTimeout != null) {
+                // cancel task of WaitEnterTransitionTimeout, we will clearPendingEnterTransition
+                // when transition finishes.
+                mWaitEnterTransitionTimeout.mRef.clear();
+            }
+        }
+
+        @Override
+        public void onTransitionCancel(Object transition) {
+            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
+        }
+
+        @Override
+        public void onTransitionEnd(Object transition) {
+            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
+        }
+    };
+
+    TransitionListener mReturnTransitionListener = new TransitionListener() {
+        @Override
+        public void onTransitionStart(Object transition) {
+            onReturnTransitionStart();
+        }
+    };
+
+    BrowseFrameLayout mRootView;
+    View mBackgroundView;
+    Drawable mBackgroundDrawable;
+    Fragment mVideoFragment;
+    DetailsParallax mDetailsParallax;
+    RowsFragment mRowsFragment;
+    ObjectAdapter mAdapter;
+    int mContainerListAlignTop;
+    BaseOnItemViewSelectedListener mExternalOnItemViewSelectedListener;
+    BaseOnItemViewClickedListener mOnItemViewClickedListener;
+    DetailsFragmentBackgroundController mDetailsBackgroundController;
+
+    // A temporarily flag when switchToVideo() is called in onCreate(), if mPendingFocusOnVideo is
+    // true, we will focus to VideoFragment immediately after video fragment's view is created.
+    boolean mPendingFocusOnVideo = false;
+
+    WaitEnterTransitionTimeout mWaitEnterTransitionTimeout;
+
+    Object mSceneAfterEntranceTransition;
+
+    final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    final BaseOnItemViewSelectedListener<Object> mOnItemViewSelectedListener =
+            new BaseOnItemViewSelectedListener<Object>() {
+        @Override
+        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                                   RowPresenter.ViewHolder rowViewHolder, Object row) {
+            int position = mRowsFragment.getVerticalGridView().getSelectedPosition();
+            int subposition = mRowsFragment.getVerticalGridView().getSelectedSubPosition();
+            if (DEBUG) Log.v(TAG, "row selected position " + position
+                    + " subposition " + subposition);
+            onRowSelected(position, subposition);
+            if (mExternalOnItemViewSelectedListener != null) {
+                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
+                        rowViewHolder, row);
+            }
+        }
+    };
+
+    /**
+     * Sets the list of rows for the fragment.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        Presenter[] presenters = adapter.getPresenterSelector().getPresenters();
+        if (presenters != null) {
+            for (int i = 0; i < presenters.length; i++) {
+                setupPresenter(presenters[i]);
+            }
+        } else {
+            Log.e(TAG, "PresenterSelector.getPresenters() not implemented");
+        }
+        if (mRowsFragment != null) {
+            mRowsFragment.setAdapter(adapter);
+        }
+    }
+
+    /**
+     * Returns the list of rows.
+     */
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Sets an item selection listener.
+     */
+    public void setOnItemViewSelectedListener(BaseOnItemViewSelectedListener listener) {
+        mExternalOnItemViewSelectedListener = listener;
+    }
+
+    /**
+     * Sets an item clicked listener.
+     */
+    public void setOnItemViewClickedListener(BaseOnItemViewClickedListener listener) {
+        if (mOnItemViewClickedListener != listener) {
+            mOnItemViewClickedListener = listener;
+            if (mRowsFragment != null) {
+                mRowsFragment.setOnItemViewClickedListener(listener);
+            }
+        }
+    }
+
+    /**
+     * Returns the item clicked listener.
+     */
+    public BaseOnItemViewClickedListener getOnItemViewClickedListener() {
+        return mOnItemViewClickedListener;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContainerListAlignTop =
+            getResources().getDimensionPixelSize(R.dimen.lb_details_rows_align_top);
+
+        Activity activity = getActivity();
+        if (activity != null) {
+            Object transition = TransitionHelper.getEnterTransition(activity.getWindow());
+            if (transition == null) {
+                mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
+            }
+            transition = TransitionHelper.getReturnTransition(activity.getWindow());
+            if (transition != null) {
+                TransitionHelper.addTransitionListener(transition, mReturnTransitionListener);
+            }
+        } else {
+            mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        mRootView = (BrowseFrameLayout) inflater.inflate(
+                R.layout.lb_details_fragment, container, false);
+        mBackgroundView = mRootView.findViewById(R.id.details_background_view);
+        if (mBackgroundView != null) {
+            mBackgroundView.setBackground(mBackgroundDrawable);
+        }
+        mRowsFragment = (RowsFragment) getChildFragmentManager().findFragmentById(
+                R.id.details_rows_dock);
+        if (mRowsFragment == null) {
+            mRowsFragment = new RowsFragment();
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.details_rows_dock, mRowsFragment).commit();
+        }
+        installTitleView(inflater, mRootView, savedInstanceState);
+        mRowsFragment.setAdapter(mAdapter);
+        mRowsFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
+        mRowsFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(mRootView, new Runnable() {
+            @Override
+            public void run() {
+                mRowsFragment.setEntranceTransitionState(true);
+            }
+        });
+
+        setupDpadNavigation();
+
+        if (Build.VERSION.SDK_INT >= 21) {
+            // Setup adapter listener to work with ParallaxTransition (>= API 21).
+            mRowsFragment.setExternalAdapterListener(new ItemBridgeAdapter.AdapterListener() {
+                @Override
+                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
+                    if (mDetailsParallax != null && vh.getViewHolder()
+                            instanceof FullWidthDetailsOverviewRowPresenter.ViewHolder) {
+                        FullWidthDetailsOverviewRowPresenter.ViewHolder rowVh =
+                                (FullWidthDetailsOverviewRowPresenter.ViewHolder)
+                                        vh.getViewHolder();
+                        rowVh.getOverviewView().setTag(R.id.lb_parallax_source,
+                                mDetailsParallax);
+                    }
+                }
+            });
+        }
+        return mRootView;
+    }
+
+    /**
+     * @deprecated override {@link #onInflateTitleView(LayoutInflater,ViewGroup,Bundle)} instead.
+     */
+    @Deprecated
+    protected View inflateTitle(LayoutInflater inflater, ViewGroup parent,
+            Bundle savedInstanceState) {
+        return super.onInflateTitleView(inflater, parent, savedInstanceState);
+    }
+
+    @Override
+    public View onInflateTitleView(LayoutInflater inflater, ViewGroup parent,
+                                   Bundle savedInstanceState) {
+        return inflateTitle(inflater, parent, savedInstanceState);
+    }
+
+    void setVerticalGridViewLayout(VerticalGridView listview) {
+        // align the top edge of item to a fixed position
+        listview.setItemAlignmentOffset(-mContainerListAlignTop);
+        listview.setItemAlignmentOffsetPercent(VerticalGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+        listview.setWindowAlignmentOffset(0);
+        listview.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
+    }
+
+    /**
+     * Called to setup each Presenter of Adapter passed in {@link #setAdapter(ObjectAdapter)}.Note
+     * that setup should only change the Presenter behavior that is meaningful in DetailsFragment.
+     * For example how a row is aligned in details Fragment.   The default implementation invokes
+     * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}
+     *
+     */
+    protected void setupPresenter(Presenter rowPresenter) {
+        if (rowPresenter instanceof FullWidthDetailsOverviewRowPresenter) {
+            setupDetailsOverviewRowPresenter((FullWidthDetailsOverviewRowPresenter) rowPresenter);
+        }
+    }
+
+    /**
+     * Called to setup {@link FullWidthDetailsOverviewRowPresenter}.  The default implementation
+     * adds two alignment positions({@link ItemAlignmentFacet}) for ViewHolder of
+     * FullWidthDetailsOverviewRowPresenter to align in fragment.
+     */
+    protected void setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter presenter) {
+        ItemAlignmentFacet facet = new ItemAlignmentFacet();
+        // by default align details_frame to half window height
+        ItemAlignmentFacet.ItemAlignmentDef alignDef1 = new ItemAlignmentFacet.ItemAlignmentDef();
+        alignDef1.setItemAlignmentViewId(R.id.details_frame);
+        alignDef1.setItemAlignmentOffset(- getResources()
+                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions));
+        alignDef1.setItemAlignmentOffsetPercent(0);
+        // when description is selected, align details_frame to top edge
+        ItemAlignmentFacet.ItemAlignmentDef alignDef2 = new ItemAlignmentFacet.ItemAlignmentDef();
+        alignDef2.setItemAlignmentViewId(R.id.details_frame);
+        alignDef2.setItemAlignmentFocusViewId(R.id.details_overview_description);
+        alignDef2.setItemAlignmentOffset(- getResources()
+                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description));
+        alignDef2.setItemAlignmentOffsetPercent(0);
+        ItemAlignmentFacet.ItemAlignmentDef[] defs =
+                new ItemAlignmentFacet.ItemAlignmentDef[] {alignDef1, alignDef2};
+        facet.setAlignmentDefs(defs);
+        presenter.setFacet(ItemAlignmentFacet.class, facet);
+    }
+
+    VerticalGridView getVerticalGridView() {
+        return mRowsFragment == null ? null : mRowsFragment.getVerticalGridView();
+    }
+
+    /**
+     * Gets embedded RowsFragment showing multiple rows for DetailsFragment.  If view of
+     * DetailsFragment is not created, the method returns null.
+     * @return Embedded RowsFragment showing multiple rows for DetailsFragment.
+     */
+    public RowsFragment getRowsFragment() {
+        return mRowsFragment;
+    }
+
+    /**
+     * Setup dimensions that are only meaningful when the child Fragments are inside
+     * DetailsFragment.
+     */
+    private void setupChildFragmentLayout() {
+        setVerticalGridViewLayout(mRowsFragment.getVerticalGridView());
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.mPosition = position;
+        mSetSelectionRunnable.mSmooth = smooth;
+        if (getView() != null && getView().getHandler() != null) {
+            getView().getHandler().post(mSetSelectionRunnable);
+        }
+    }
+
+    void switchToVideo() {
+        if (mVideoFragment != null && mVideoFragment.getView() != null) {
+            mVideoFragment.getView().requestFocus();
+        } else {
+            mStateMachine.fireEvent(EVT_SWITCH_TO_VIDEO);
+        }
+    }
+
+    void switchToRows() {
+        mPendingFocusOnVideo = false;
+        VerticalGridView verticalGridView = getVerticalGridView();
+        if (verticalGridView != null && verticalGridView.getChildCount() > 0) {
+            verticalGridView.requestFocus();
+        }
+    }
+
+    /**
+     * This method asks DetailsFragmentBackgroundController to add a fragment for rendering video.
+     * In case the fragment is already there, it will return the existing one. The method must be
+     * called after calling super.onCreate(). App usually does not call this method directly.
+     *
+     * @return Fragment the added or restored fragment responsible for rendering video.
+     * @see DetailsFragmentBackgroundController#onCreateVideoFragment()
+     */
+    final Fragment findOrCreateVideoFragment() {
+        if (mVideoFragment != null) {
+            return mVideoFragment;
+        }
+        Fragment fragment = getChildFragmentManager()
+                .findFragmentById(R.id.video_surface_container);
+        if (fragment == null && mDetailsBackgroundController != null) {
+            FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
+            ft2.add(android.support.v17.leanback.R.id.video_surface_container,
+                    fragment = mDetailsBackgroundController.onCreateVideoFragment());
+            ft2.commit();
+            if (mPendingFocusOnVideo) {
+                // wait next cycle for Fragment view created so we can focus on it.
+                // This is a bit hack eventually we will do commitNow() which get view immediately.
+                getView().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (getView() != null) {
+                            switchToVideo();
+                        }
+                        mPendingFocusOnVideo = false;
+                    }
+                });
+            }
+        }
+        mVideoFragment = fragment;
+        return mVideoFragment;
+    }
+
+    void onRowSelected(int selectedPosition, int selectedSubPosition) {
+        ObjectAdapter adapter = getAdapter();
+        if (( mRowsFragment != null && mRowsFragment.getView() != null
+                && mRowsFragment.getView().hasFocus() && !mPendingFocusOnVideo)
+                && (adapter == null || adapter.size() == 0
+                || (getVerticalGridView().getSelectedPosition() == 0
+                && getVerticalGridView().getSelectedSubPosition() == 0))) {
+            showTitle(true);
+        } else {
+            showTitle(false);
+        }
+        if (adapter != null && adapter.size() > selectedPosition) {
+            final VerticalGridView gridView = getVerticalGridView();
+            final int count = gridView.getChildCount();
+            if (count > 0) {
+                mStateMachine.fireEvent(EVT_DETAILS_ROW_LOADED);
+            }
+            for (int i = 0; i < count; i++) {
+                ItemBridgeAdapter.ViewHolder bridgeViewHolder = (ItemBridgeAdapter.ViewHolder)
+                        gridView.getChildViewHolder(gridView.getChildAt(i));
+                RowPresenter rowPresenter = (RowPresenter) bridgeViewHolder.getPresenter();
+                onSetRowStatus(rowPresenter,
+                        rowPresenter.getRowViewHolder(bridgeViewHolder.getViewHolder()),
+                        bridgeViewHolder.getAdapterPosition(),
+                        selectedPosition, selectedSubPosition);
+            }
+        }
+    }
+
+    /**
+     * Called when onStart and enter transition (postponed/none postponed) and entrance transition
+     * are all finished.
+     */
+    @CallSuper
+    void onSafeStart() {
+        if (mDetailsBackgroundController != null) {
+            mDetailsBackgroundController.onStart();
+        }
+    }
+
+    @CallSuper
+    void onReturnTransitionStart() {
+        if (mDetailsBackgroundController != null) {
+            // first disable parallax effect that auto-start PlaybackGlue.
+            boolean isVideoVisible = mDetailsBackgroundController.disableVideoParallax();
+            // if video is not visible we can safely remove VideoFragment,
+            // otherwise let video playing during return transition.
+            if (!isVideoVisible && mVideoFragment != null) {
+                FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
+                ft2.remove(mVideoFragment);
+                ft2.commit();
+                mVideoFragment = null;
+            }
+        }
+    }
+
+    @Override
+    public void onStop() {
+        if (mDetailsBackgroundController != null) {
+            mDetailsBackgroundController.onStop();
+        }
+        super.onStop();
+    }
+
+    /**
+     * Called on every visible row to change view status when current selected row position
+     * or selected sub position changed.  Subclass may override.   The default
+     * implementation calls {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
+     * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)} if presenter is
+     * instance of {@link FullWidthDetailsOverviewRowPresenter}.
+     *
+     * @param presenter   The presenter used to create row ViewHolder.
+     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
+     *                    be selected.
+     * @param adapterPosition  The adapter position of viewHolder inside adapter.
+     * @param selectedPosition The adapter position of currently selected row.
+     * @param selectedSubPosition The sub position within currently selected row.  This is used
+     *                            When a row has multiple alignment positions.
+     */
+    protected void onSetRowStatus(RowPresenter presenter, RowPresenter.ViewHolder viewHolder, int
+            adapterPosition, int selectedPosition, int selectedSubPosition) {
+        if (presenter instanceof FullWidthDetailsOverviewRowPresenter) {
+            onSetDetailsOverviewRowStatus((FullWidthDetailsOverviewRowPresenter) presenter,
+                    (FullWidthDetailsOverviewRowPresenter.ViewHolder) viewHolder,
+                    adapterPosition, selectedPosition, selectedSubPosition);
+        }
+    }
+
+    /**
+     * Called to change DetailsOverviewRow view status when current selected row position
+     * or selected sub position changed.  Subclass may override.   The default
+     * implementation switches between three states based on the positions:
+     * {@link FullWidthDetailsOverviewRowPresenter#STATE_HALF},
+     * {@link FullWidthDetailsOverviewRowPresenter#STATE_FULL} and
+     * {@link FullWidthDetailsOverviewRowPresenter#STATE_SMALL}.
+     *
+     * @param presenter   The presenter used to create row ViewHolder.
+     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
+     *                    be selected.
+     * @param adapterPosition  The adapter position of viewHolder inside adapter.
+     * @param selectedPosition The adapter position of currently selected row.
+     * @param selectedSubPosition The sub position within currently selected row.  This is used
+     *                            When a row has multiple alignment positions.
+     */
+    protected void onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter presenter,
+            FullWidthDetailsOverviewRowPresenter.ViewHolder viewHolder, int adapterPosition,
+            int selectedPosition, int selectedSubPosition) {
+        if (selectedPosition > adapterPosition) {
+            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
+        } else if (selectedPosition == adapterPosition && selectedSubPosition == 1) {
+            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
+        } else if (selectedPosition == adapterPosition && selectedSubPosition == 0){
+            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_FULL);
+        } else {
+            presenter.setState(viewHolder,
+                    FullWidthDetailsOverviewRowPresenter.STATE_SMALL);
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        setupChildFragmentLayout();
+        mStateMachine.fireEvent(EVT_ONSTART);
+        if (mDetailsParallax != null) {
+            mDetailsParallax.setRecyclerView(mRowsFragment.getVerticalGridView());
+        }
+        if (mPendingFocusOnVideo) {
+            slideOutGridView();
+        } else if (!getView().hasFocus()) {
+            mRowsFragment.getVerticalGridView().requestFocus();
+        }
+    }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(FragmentUtil.getContext(DetailsFragment.this),
+                R.transition.lb_details_enter_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    @Override
+    protected void onEntranceTransitionEnd() {
+        mRowsFragment.onTransitionEnd();
+    }
+
+    @Override
+    protected void onEntranceTransitionPrepare() {
+        mRowsFragment.onTransitionPrepare();
+    }
+
+    @Override
+    protected void onEntranceTransitionStart() {
+        mRowsFragment.onTransitionStart();
+    }
+
+    /**
+     * Returns the {@link DetailsParallax} instance used by
+     * {@link DetailsFragmentBackgroundController} to configure parallax effect of background and
+     * control embedded video playback. App usually does not use this method directly.
+     * App may use this method for other custom parallax tasks.
+     *
+     * @return The DetailsParallax instance attached to the DetailsFragment.
+     */
+    public DetailsParallax getParallax() {
+        if (mDetailsParallax == null) {
+            mDetailsParallax = new DetailsParallax();
+            if (mRowsFragment != null && mRowsFragment.getView() != null) {
+                mDetailsParallax.setRecyclerView(mRowsFragment.getVerticalGridView());
+            }
+        }
+        return mDetailsParallax;
+    }
+
+    /**
+     * Set background drawable shown below foreground rows UI and above
+     * {@link #findOrCreateVideoFragment()}.
+     *
+     * @see DetailsFragmentBackgroundController
+     */
+    void setBackgroundDrawable(Drawable drawable) {
+        if (mBackgroundView != null) {
+            mBackgroundView.setBackground(drawable);
+        }
+        mBackgroundDrawable = drawable;
+    }
+
+    /**
+     * This method does the following
+     * <ul>
+     * <li>sets up focus search handling logic in the root view to enable transitioning between
+     * half screen/full screen/no video mode.</li>
+     *
+     * <li>Sets up the key listener in the root view to intercept events like UP/DOWN and
+     * transition to appropriate mode like half/full screen video.</li>
+     * </ul>
+     */
+    void setupDpadNavigation() {
+        mRootView.setOnChildFocusListener(new BrowseFrameLayout.OnChildFocusListener() {
+
+            @Override
+            public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+                return false;
+            }
+
+            @Override
+            public void onRequestChildFocus(View child, View focused) {
+                if (child != mRootView.getFocusedChild()) {
+                    if (child.getId() == R.id.details_fragment_root) {
+                        if (!mPendingFocusOnVideo) {
+                            slideInGridView();
+                            showTitle(true);
+                        }
+                    } else if (child.getId() == R.id.video_surface_container) {
+                        slideOutGridView();
+                        showTitle(false);
+                    } else {
+                        showTitle(true);
+                    }
+                }
+            }
+        });
+        mRootView.setOnFocusSearchListener(new BrowseFrameLayout.OnFocusSearchListener() {
+            @Override
+            public View onFocusSearch(View focused, int direction) {
+                if (mRowsFragment.getVerticalGridView() != null
+                        && mRowsFragment.getVerticalGridView().hasFocus()) {
+                    if (direction == View.FOCUS_UP) {
+                        if (mDetailsBackgroundController != null
+                                && mDetailsBackgroundController.canNavigateToVideoFragment()
+                                && mVideoFragment != null && mVideoFragment.getView() != null) {
+                            return mVideoFragment.getView();
+                        } else if (getTitleView() != null && getTitleView().hasFocusable()) {
+                            return getTitleView();
+                        }
+                    }
+                } else if (getTitleView() != null && getTitleView().hasFocus()) {
+                    if (direction == View.FOCUS_DOWN) {
+                        if (mRowsFragment.getVerticalGridView() != null) {
+                            return mRowsFragment.getVerticalGridView();
+                        }
+                    }
+                }
+                return focused;
+            }
+        });
+
+        // If we press BACK on remote while in full screen video mode, we should
+        // transition back to half screen video playback mode.
+        mRootView.setOnDispatchKeyListener(new View.OnKeyListener() {
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                // This is used to check if we are in full screen video mode. This is somewhat
+                // hacky and relies on the behavior of the video helper class to update the
+                // focusability of the video surface view.
+                if (mVideoFragment != null && mVideoFragment.getView() != null
+                        && mVideoFragment.getView().hasFocus()) {
+                    if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
+                        if (getVerticalGridView().getChildCount() > 0) {
+                            getVerticalGridView().requestFocus();
+                            return true;
+                        }
+                    }
+                }
+
+                return false;
+            }
+        });
+    }
+
+    /**
+     * Slides vertical grid view (displaying media item details) out of the screen from below.
+     */
+    void slideOutGridView() {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().animateOut();
+        }
+    }
+
+    void slideInGridView() {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().animateIn();
+        }
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java b/leanback/src/main/java/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java
rename to leanback/src/main/java/android/support/v17/leanback/app/DetailsFragmentBackgroundController.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/DetailsSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/DetailsSupportFragment.java
new file mode 100644
index 0000000..a6025b3
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/DetailsSupportFragment.java
@@ -0,0 +1,929 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from DetailsFragment.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.CallSuper;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.transition.TransitionListener;
+import android.support.v17.leanback.util.StateMachine.Event;
+import android.support.v17.leanback.util.StateMachine.State;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
+import android.support.v17.leanback.widget.BrowseFrameLayout;
+import android.support.v17.leanback.widget.DetailsParallax;
+import android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
+import android.support.v17.leanback.widget.ItemBridgeAdapter;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A fragment for creating Leanback details screens.
+ *
+ * <p>
+ * A DetailsSupportFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list.The Adapter's {@link PresenterSelector} must maintain subclasses
+ * of {@link RowPresenter}.
+ * </p>
+ *
+ * When {@link FullWidthDetailsOverviewRowPresenter} is found in adapter,  DetailsSupportFragment will
+ * setup default behavior of the DetailsOverviewRow:
+ * <li>
+ * The alignment of FullWidthDetailsOverviewRowPresenter is setup in
+ * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}.
+ * </li>
+ * <li>
+ * The view status switching of FullWidthDetailsOverviewRowPresenter is done in
+ * {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
+ * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)}.
+ * </li>
+ *
+ * <p>
+ * The recommended activity themes to use with a DetailsSupportFragment are
+ * <li>
+ * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details} with activity
+ * shared element transition for {@link FullWidthDetailsOverviewRowPresenter}.
+ * </li>
+ * <li>
+ * {@link android.support.v17.leanback.R.style#Theme_Leanback_Details_NoSharedElementTransition}
+ * if shared element transition is not needed, for example if first row is not rendered by
+ * {@link FullWidthDetailsOverviewRowPresenter}.
+ * </li>
+ * </p>
+ *
+ * <p>
+ * DetailsSupportFragment can use {@link DetailsSupportFragmentBackgroundController} to add a parallax drawable
+ * background and embedded video playing fragment.
+ * </p>
+ */
+public class DetailsSupportFragment extends BaseSupportFragment {
+    static final String TAG = "DetailsSupportFragment";
+    static final boolean DEBUG = false;
+
+    final State STATE_SET_ENTRANCE_START_STATE = new State("STATE_SET_ENTRANCE_START_STATE") {
+        @Override
+        public void run() {
+            mRowsSupportFragment.setEntranceTransitionState(false);
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_INIT = new State("STATE_ENTER_TRANSIITON_INIT");
+
+    void switchToVideoBeforeVideoSupportFragmentCreated() {
+        // if the video fragment is not ready: immediately fade out covering drawable,
+        // hide title and mark mPendingFocusOnVideo and set focus on it later.
+        mDetailsBackgroundController.switchToVideoBeforeCreate();
+        showTitle(false);
+        mPendingFocusOnVideo = true;
+        slideOutGridView();
+    }
+
+    final State STATE_SWITCH_TO_VIDEO_IN_ON_CREATE = new State("STATE_SWITCH_TO_VIDEO_IN_ON_CREATE",
+            false, false) {
+        @Override
+        public void run() {
+            switchToVideoBeforeVideoSupportFragmentCreated();
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_CANCEL = new State("STATE_ENTER_TRANSITION_CANCEL",
+            false, false) {
+        @Override
+        public void run() {
+            if (mWaitEnterTransitionTimeout != null) {
+                mWaitEnterTransitionTimeout.mRef.clear();
+            }
+            // clear the activity enter/sharedElement transition, return transitions are kept.
+            // keep the return transitions and clear enter transition
+            if (getActivity() != null) {
+                Window window = getActivity().getWindow();
+                Object returnTransition = TransitionHelper.getReturnTransition(window);
+                Object sharedReturnTransition = TransitionHelper
+                        .getSharedElementReturnTransition(window);
+                TransitionHelper.setEnterTransition(window, null);
+                TransitionHelper.setSharedElementEnterTransition(window, null);
+                TransitionHelper.setReturnTransition(window, returnTransition);
+                TransitionHelper.setSharedElementReturnTransition(window, sharedReturnTransition);
+            }
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_COMPLETE = new State("STATE_ENTER_TRANSIITON_COMPLETE",
+            true, false);
+
+    final State STATE_ENTER_TRANSITION_ADDLISTENER = new State("STATE_ENTER_TRANSITION_PENDING") {
+        @Override
+        public void run() {
+            Object transition = TransitionHelper.getEnterTransition(getActivity().getWindow());
+            TransitionHelper.addTransitionListener(transition, mEnterTransitionListener);
+        }
+    };
+
+    final State STATE_ENTER_TRANSITION_PENDING = new State("STATE_ENTER_TRANSITION_PENDING") {
+        @Override
+        public void run() {
+            if (mWaitEnterTransitionTimeout == null) {
+                new WaitEnterTransitionTimeout(DetailsSupportFragment.this);
+            }
+        }
+    };
+
+    /**
+     * Start this task when first DetailsOverviewRow is created, if there is no entrance transition
+     * started, it will clear PF_ENTRANCE_TRANSITION_PENDING.
+     */
+    static class WaitEnterTransitionTimeout implements Runnable {
+        static final long WAIT_ENTERTRANSITION_START = 200;
+
+        final WeakReference<DetailsSupportFragment> mRef;
+
+        WaitEnterTransitionTimeout(DetailsSupportFragment f) {
+            mRef = new WeakReference<>(f);
+            f.getView().postDelayed(this, WAIT_ENTERTRANSITION_START);
+        }
+
+        @Override
+        public void run() {
+            DetailsSupportFragment f = mRef.get();
+            if (f != null) {
+                f.mStateMachine.fireEvent(f.EVT_ENTER_TRANSIITON_DONE);
+            }
+        }
+    }
+
+    final State STATE_ON_SAFE_START = new State("STATE_ON_SAFE_START") {
+        @Override
+        public void run() {
+            onSafeStart();
+        }
+    };
+
+    final Event EVT_ONSTART = new Event("onStart");
+
+    final Event EVT_NO_ENTER_TRANSITION = new Event("EVT_NO_ENTER_TRANSITION");
+
+    final Event EVT_DETAILS_ROW_LOADED = new Event("onFirstRowLoaded");
+
+    final Event EVT_ENTER_TRANSIITON_DONE = new Event("onEnterTransitionDone");
+
+    final Event EVT_SWITCH_TO_VIDEO = new Event("switchToVideo");
+
+    @Override
+    void createStateMachineStates() {
+        super.createStateMachineStates();
+        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
+        mStateMachine.addState(STATE_ON_SAFE_START);
+        mStateMachine.addState(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_INIT);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_ADDLISTENER);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_CANCEL);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_PENDING);
+        mStateMachine.addState(STATE_ENTER_TRANSITION_COMPLETE);
+    }
+
+    @Override
+    void createStateMachineTransitions() {
+        super.createStateMachineTransitions();
+        /**
+         * Part 1: Processing enter transitions after fragment.onCreate
+         */
+        mStateMachine.addTransition(STATE_START, STATE_ENTER_TRANSITION_INIT, EVT_ON_CREATE);
+        // if transition is not supported, skip to complete
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
+                COND_TRANSITION_NOT_SUPPORTED);
+        // if transition is not set on Activity, skip to complete
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_COMPLETE,
+                EVT_NO_ENTER_TRANSITION);
+        // if switchToVideo is called before EVT_ON_CREATEVIEW, clear enter transition and skip to
+        // complete.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_CANCEL,
+                EVT_SWITCH_TO_VIDEO);
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_CANCEL, STATE_ENTER_TRANSITION_COMPLETE);
+        // once after onCreateView, we cannot skip the enter transition, add a listener and wait
+        // it to finish
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_INIT, STATE_ENTER_TRANSITION_ADDLISTENER,
+                EVT_ON_CREATEVIEW);
+        // when enter transition finishes, go to complete, however this might never happen if
+        // the activity is not giving transition options in startActivity, there is no API to query
+        // if this activity is started in a enter transition mode. So we rely on a timer below:
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
+                STATE_ENTER_TRANSITION_COMPLETE, EVT_ENTER_TRANSIITON_DONE);
+        // we are expecting app to start delayed enter transition shortly after details row is
+        // loaded, so create a timer and wait for enter transition start.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_ADDLISTENER,
+                STATE_ENTER_TRANSITION_PENDING, EVT_DETAILS_ROW_LOADED);
+        // if enter transition not started in the timer, skip to DONE, this can be also true when
+        // startActivity is not giving transition option.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_PENDING, STATE_ENTER_TRANSITION_COMPLETE,
+                EVT_ENTER_TRANSIITON_DONE);
+
+        /**
+         * Part 2: modification to the entrance transition defined in BaseSupportFragment
+         */
+        // Must finish enter transition before perform entrance transition.
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ENTRANCE_PERFORM);
+        // Calling switch to video would hide immediately and skip entrance transition
+        mStateMachine.addTransition(STATE_ENTRANCE_INIT, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
+                EVT_SWITCH_TO_VIDEO);
+        mStateMachine.addTransition(STATE_SWITCH_TO_VIDEO_IN_ON_CREATE, STATE_ENTRANCE_COMPLETE);
+        // if the entrance transition is skipped to complete by COND_TRANSITION_NOT_SUPPORTED, we
+        // still need to do the switchToVideo.
+        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_SWITCH_TO_VIDEO_IN_ON_CREATE,
+                EVT_SWITCH_TO_VIDEO);
+
+        // for once the view is created in onStart and prepareEntranceTransition was called, we
+        // could setEntranceStartState:
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
+                STATE_SET_ENTRANCE_START_STATE, EVT_ONSTART);
+
+        /**
+         * Part 3: onSafeStart()
+         */
+        // for onSafeStart: the condition is onStart called, entrance transition complete
+        mStateMachine.addTransition(STATE_START, STATE_ON_SAFE_START, EVT_ONSTART);
+        mStateMachine.addTransition(STATE_ENTRANCE_COMPLETE, STATE_ON_SAFE_START);
+        mStateMachine.addTransition(STATE_ENTER_TRANSITION_COMPLETE, STATE_ON_SAFE_START);
+    }
+
+    private class SetSelectionRunnable implements Runnable {
+        int mPosition;
+        boolean mSmooth = true;
+
+        SetSelectionRunnable() {
+        }
+
+        @Override
+        public void run() {
+            if (mRowsSupportFragment == null) {
+                return;
+            }
+            mRowsSupportFragment.setSelectedPosition(mPosition, mSmooth);
+        }
+    }
+
+    TransitionListener mEnterTransitionListener = new TransitionListener() {
+        @Override
+        public void onTransitionStart(Object transition) {
+            if (mWaitEnterTransitionTimeout != null) {
+                // cancel task of WaitEnterTransitionTimeout, we will clearPendingEnterTransition
+                // when transition finishes.
+                mWaitEnterTransitionTimeout.mRef.clear();
+            }
+        }
+
+        @Override
+        public void onTransitionCancel(Object transition) {
+            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
+        }
+
+        @Override
+        public void onTransitionEnd(Object transition) {
+            mStateMachine.fireEvent(EVT_ENTER_TRANSIITON_DONE);
+        }
+    };
+
+    TransitionListener mReturnTransitionListener = new TransitionListener() {
+        @Override
+        public void onTransitionStart(Object transition) {
+            onReturnTransitionStart();
+        }
+    };
+
+    BrowseFrameLayout mRootView;
+    View mBackgroundView;
+    Drawable mBackgroundDrawable;
+    Fragment mVideoSupportFragment;
+    DetailsParallax mDetailsParallax;
+    RowsSupportFragment mRowsSupportFragment;
+    ObjectAdapter mAdapter;
+    int mContainerListAlignTop;
+    BaseOnItemViewSelectedListener mExternalOnItemViewSelectedListener;
+    BaseOnItemViewClickedListener mOnItemViewClickedListener;
+    DetailsSupportFragmentBackgroundController mDetailsBackgroundController;
+
+    // A temporarily flag when switchToVideo() is called in onCreate(), if mPendingFocusOnVideo is
+    // true, we will focus to VideoSupportFragment immediately after video fragment's view is created.
+    boolean mPendingFocusOnVideo = false;
+
+    WaitEnterTransitionTimeout mWaitEnterTransitionTimeout;
+
+    Object mSceneAfterEntranceTransition;
+
+    final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    final BaseOnItemViewSelectedListener<Object> mOnItemViewSelectedListener =
+            new BaseOnItemViewSelectedListener<Object>() {
+        @Override
+        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                                   RowPresenter.ViewHolder rowViewHolder, Object row) {
+            int position = mRowsSupportFragment.getVerticalGridView().getSelectedPosition();
+            int subposition = mRowsSupportFragment.getVerticalGridView().getSelectedSubPosition();
+            if (DEBUG) Log.v(TAG, "row selected position " + position
+                    + " subposition " + subposition);
+            onRowSelected(position, subposition);
+            if (mExternalOnItemViewSelectedListener != null) {
+                mExternalOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
+                        rowViewHolder, row);
+            }
+        }
+    };
+
+    /**
+     * Sets the list of rows for the fragment.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        Presenter[] presenters = adapter.getPresenterSelector().getPresenters();
+        if (presenters != null) {
+            for (int i = 0; i < presenters.length; i++) {
+                setupPresenter(presenters[i]);
+            }
+        } else {
+            Log.e(TAG, "PresenterSelector.getPresenters() not implemented");
+        }
+        if (mRowsSupportFragment != null) {
+            mRowsSupportFragment.setAdapter(adapter);
+        }
+    }
+
+    /**
+     * Returns the list of rows.
+     */
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Sets an item selection listener.
+     */
+    public void setOnItemViewSelectedListener(BaseOnItemViewSelectedListener listener) {
+        mExternalOnItemViewSelectedListener = listener;
+    }
+
+    /**
+     * Sets an item clicked listener.
+     */
+    public void setOnItemViewClickedListener(BaseOnItemViewClickedListener listener) {
+        if (mOnItemViewClickedListener != listener) {
+            mOnItemViewClickedListener = listener;
+            if (mRowsSupportFragment != null) {
+                mRowsSupportFragment.setOnItemViewClickedListener(listener);
+            }
+        }
+    }
+
+    /**
+     * Returns the item clicked listener.
+     */
+    public BaseOnItemViewClickedListener getOnItemViewClickedListener() {
+        return mOnItemViewClickedListener;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mContainerListAlignTop =
+            getResources().getDimensionPixelSize(R.dimen.lb_details_rows_align_top);
+
+        FragmentActivity activity = getActivity();
+        if (activity != null) {
+            Object transition = TransitionHelper.getEnterTransition(activity.getWindow());
+            if (transition == null) {
+                mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
+            }
+            transition = TransitionHelper.getReturnTransition(activity.getWindow());
+            if (transition != null) {
+                TransitionHelper.addTransitionListener(transition, mReturnTransitionListener);
+            }
+        } else {
+            mStateMachine.fireEvent(EVT_NO_ENTER_TRANSITION);
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        mRootView = (BrowseFrameLayout) inflater.inflate(
+                R.layout.lb_details_fragment, container, false);
+        mBackgroundView = mRootView.findViewById(R.id.details_background_view);
+        if (mBackgroundView != null) {
+            mBackgroundView.setBackground(mBackgroundDrawable);
+        }
+        mRowsSupportFragment = (RowsSupportFragment) getChildFragmentManager().findFragmentById(
+                R.id.details_rows_dock);
+        if (mRowsSupportFragment == null) {
+            mRowsSupportFragment = new RowsSupportFragment();
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.details_rows_dock, mRowsSupportFragment).commit();
+        }
+        installTitleView(inflater, mRootView, savedInstanceState);
+        mRowsSupportFragment.setAdapter(mAdapter);
+        mRowsSupportFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
+        mRowsSupportFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(mRootView, new Runnable() {
+            @Override
+            public void run() {
+                mRowsSupportFragment.setEntranceTransitionState(true);
+            }
+        });
+
+        setupDpadNavigation();
+
+        if (Build.VERSION.SDK_INT >= 21) {
+            // Setup adapter listener to work with ParallaxTransition (>= API 21).
+            mRowsSupportFragment.setExternalAdapterListener(new ItemBridgeAdapter.AdapterListener() {
+                @Override
+                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
+                    if (mDetailsParallax != null && vh.getViewHolder()
+                            instanceof FullWidthDetailsOverviewRowPresenter.ViewHolder) {
+                        FullWidthDetailsOverviewRowPresenter.ViewHolder rowVh =
+                                (FullWidthDetailsOverviewRowPresenter.ViewHolder)
+                                        vh.getViewHolder();
+                        rowVh.getOverviewView().setTag(R.id.lb_parallax_source,
+                                mDetailsParallax);
+                    }
+                }
+            });
+        }
+        return mRootView;
+    }
+
+    /**
+     * @deprecated override {@link #onInflateTitleView(LayoutInflater,ViewGroup,Bundle)} instead.
+     */
+    @Deprecated
+    protected View inflateTitle(LayoutInflater inflater, ViewGroup parent,
+            Bundle savedInstanceState) {
+        return super.onInflateTitleView(inflater, parent, savedInstanceState);
+    }
+
+    @Override
+    public View onInflateTitleView(LayoutInflater inflater, ViewGroup parent,
+                                   Bundle savedInstanceState) {
+        return inflateTitle(inflater, parent, savedInstanceState);
+    }
+
+    void setVerticalGridViewLayout(VerticalGridView listview) {
+        // align the top edge of item to a fixed position
+        listview.setItemAlignmentOffset(-mContainerListAlignTop);
+        listview.setItemAlignmentOffsetPercent(VerticalGridView.ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
+        listview.setWindowAlignmentOffset(0);
+        listview.setWindowAlignmentOffsetPercent(VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
+    }
+
+    /**
+     * Called to setup each Presenter of Adapter passed in {@link #setAdapter(ObjectAdapter)}.Note
+     * that setup should only change the Presenter behavior that is meaningful in DetailsSupportFragment.
+     * For example how a row is aligned in details Fragment.   The default implementation invokes
+     * {@link #setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter)}
+     *
+     */
+    protected void setupPresenter(Presenter rowPresenter) {
+        if (rowPresenter instanceof FullWidthDetailsOverviewRowPresenter) {
+            setupDetailsOverviewRowPresenter((FullWidthDetailsOverviewRowPresenter) rowPresenter);
+        }
+    }
+
+    /**
+     * Called to setup {@link FullWidthDetailsOverviewRowPresenter}.  The default implementation
+     * adds two alignment positions({@link ItemAlignmentFacet}) for ViewHolder of
+     * FullWidthDetailsOverviewRowPresenter to align in fragment.
+     */
+    protected void setupDetailsOverviewRowPresenter(FullWidthDetailsOverviewRowPresenter presenter) {
+        ItemAlignmentFacet facet = new ItemAlignmentFacet();
+        // by default align details_frame to half window height
+        ItemAlignmentFacet.ItemAlignmentDef alignDef1 = new ItemAlignmentFacet.ItemAlignmentDef();
+        alignDef1.setItemAlignmentViewId(R.id.details_frame);
+        alignDef1.setItemAlignmentOffset(- getResources()
+                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_actions));
+        alignDef1.setItemAlignmentOffsetPercent(0);
+        // when description is selected, align details_frame to top edge
+        ItemAlignmentFacet.ItemAlignmentDef alignDef2 = new ItemAlignmentFacet.ItemAlignmentDef();
+        alignDef2.setItemAlignmentViewId(R.id.details_frame);
+        alignDef2.setItemAlignmentFocusViewId(R.id.details_overview_description);
+        alignDef2.setItemAlignmentOffset(- getResources()
+                .getDimensionPixelSize(R.dimen.lb_details_v2_align_pos_for_description));
+        alignDef2.setItemAlignmentOffsetPercent(0);
+        ItemAlignmentFacet.ItemAlignmentDef[] defs =
+                new ItemAlignmentFacet.ItemAlignmentDef[] {alignDef1, alignDef2};
+        facet.setAlignmentDefs(defs);
+        presenter.setFacet(ItemAlignmentFacet.class, facet);
+    }
+
+    VerticalGridView getVerticalGridView() {
+        return mRowsSupportFragment == null ? null : mRowsSupportFragment.getVerticalGridView();
+    }
+
+    /**
+     * Gets embedded RowsSupportFragment showing multiple rows for DetailsSupportFragment.  If view of
+     * DetailsSupportFragment is not created, the method returns null.
+     * @return Embedded RowsSupportFragment showing multiple rows for DetailsSupportFragment.
+     */
+    public RowsSupportFragment getRowsSupportFragment() {
+        return mRowsSupportFragment;
+    }
+
+    /**
+     * Setup dimensions that are only meaningful when the child Fragments are inside
+     * DetailsSupportFragment.
+     */
+    private void setupChildFragmentLayout() {
+        setVerticalGridViewLayout(mRowsSupportFragment.getVerticalGridView());
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.mPosition = position;
+        mSetSelectionRunnable.mSmooth = smooth;
+        if (getView() != null && getView().getHandler() != null) {
+            getView().getHandler().post(mSetSelectionRunnable);
+        }
+    }
+
+    void switchToVideo() {
+        if (mVideoSupportFragment != null && mVideoSupportFragment.getView() != null) {
+            mVideoSupportFragment.getView().requestFocus();
+        } else {
+            mStateMachine.fireEvent(EVT_SWITCH_TO_VIDEO);
+        }
+    }
+
+    void switchToRows() {
+        mPendingFocusOnVideo = false;
+        VerticalGridView verticalGridView = getVerticalGridView();
+        if (verticalGridView != null && verticalGridView.getChildCount() > 0) {
+            verticalGridView.requestFocus();
+        }
+    }
+
+    /**
+     * This method asks DetailsSupportFragmentBackgroundController to add a fragment for rendering video.
+     * In case the fragment is already there, it will return the existing one. The method must be
+     * called after calling super.onCreate(). App usually does not call this method directly.
+     *
+     * @return Fragment the added or restored fragment responsible for rendering video.
+     * @see DetailsSupportFragmentBackgroundController#onCreateVideoSupportFragment()
+     */
+    final Fragment findOrCreateVideoSupportFragment() {
+        if (mVideoSupportFragment != null) {
+            return mVideoSupportFragment;
+        }
+        Fragment fragment = getChildFragmentManager()
+                .findFragmentById(R.id.video_surface_container);
+        if (fragment == null && mDetailsBackgroundController != null) {
+            FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
+            ft2.add(android.support.v17.leanback.R.id.video_surface_container,
+                    fragment = mDetailsBackgroundController.onCreateVideoSupportFragment());
+            ft2.commit();
+            if (mPendingFocusOnVideo) {
+                // wait next cycle for Fragment view created so we can focus on it.
+                // This is a bit hack eventually we will do commitNow() which get view immediately.
+                getView().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        if (getView() != null) {
+                            switchToVideo();
+                        }
+                        mPendingFocusOnVideo = false;
+                    }
+                });
+            }
+        }
+        mVideoSupportFragment = fragment;
+        return mVideoSupportFragment;
+    }
+
+    void onRowSelected(int selectedPosition, int selectedSubPosition) {
+        ObjectAdapter adapter = getAdapter();
+        if (( mRowsSupportFragment != null && mRowsSupportFragment.getView() != null
+                && mRowsSupportFragment.getView().hasFocus() && !mPendingFocusOnVideo)
+                && (adapter == null || adapter.size() == 0
+                || (getVerticalGridView().getSelectedPosition() == 0
+                && getVerticalGridView().getSelectedSubPosition() == 0))) {
+            showTitle(true);
+        } else {
+            showTitle(false);
+        }
+        if (adapter != null && adapter.size() > selectedPosition) {
+            final VerticalGridView gridView = getVerticalGridView();
+            final int count = gridView.getChildCount();
+            if (count > 0) {
+                mStateMachine.fireEvent(EVT_DETAILS_ROW_LOADED);
+            }
+            for (int i = 0; i < count; i++) {
+                ItemBridgeAdapter.ViewHolder bridgeViewHolder = (ItemBridgeAdapter.ViewHolder)
+                        gridView.getChildViewHolder(gridView.getChildAt(i));
+                RowPresenter rowPresenter = (RowPresenter) bridgeViewHolder.getPresenter();
+                onSetRowStatus(rowPresenter,
+                        rowPresenter.getRowViewHolder(bridgeViewHolder.getViewHolder()),
+                        bridgeViewHolder.getAdapterPosition(),
+                        selectedPosition, selectedSubPosition);
+            }
+        }
+    }
+
+    /**
+     * Called when onStart and enter transition (postponed/none postponed) and entrance transition
+     * are all finished.
+     */
+    @CallSuper
+    void onSafeStart() {
+        if (mDetailsBackgroundController != null) {
+            mDetailsBackgroundController.onStart();
+        }
+    }
+
+    @CallSuper
+    void onReturnTransitionStart() {
+        if (mDetailsBackgroundController != null) {
+            // first disable parallax effect that auto-start PlaybackGlue.
+            boolean isVideoVisible = mDetailsBackgroundController.disableVideoParallax();
+            // if video is not visible we can safely remove VideoSupportFragment,
+            // otherwise let video playing during return transition.
+            if (!isVideoVisible && mVideoSupportFragment != null) {
+                FragmentTransaction ft2 = getChildFragmentManager().beginTransaction();
+                ft2.remove(mVideoSupportFragment);
+                ft2.commit();
+                mVideoSupportFragment = null;
+            }
+        }
+    }
+
+    @Override
+    public void onStop() {
+        if (mDetailsBackgroundController != null) {
+            mDetailsBackgroundController.onStop();
+        }
+        super.onStop();
+    }
+
+    /**
+     * Called on every visible row to change view status when current selected row position
+     * or selected sub position changed.  Subclass may override.   The default
+     * implementation calls {@link #onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter,
+     * FullWidthDetailsOverviewRowPresenter.ViewHolder, int, int, int)} if presenter is
+     * instance of {@link FullWidthDetailsOverviewRowPresenter}.
+     *
+     * @param presenter   The presenter used to create row ViewHolder.
+     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
+     *                    be selected.
+     * @param adapterPosition  The adapter position of viewHolder inside adapter.
+     * @param selectedPosition The adapter position of currently selected row.
+     * @param selectedSubPosition The sub position within currently selected row.  This is used
+     *                            When a row has multiple alignment positions.
+     */
+    protected void onSetRowStatus(RowPresenter presenter, RowPresenter.ViewHolder viewHolder, int
+            adapterPosition, int selectedPosition, int selectedSubPosition) {
+        if (presenter instanceof FullWidthDetailsOverviewRowPresenter) {
+            onSetDetailsOverviewRowStatus((FullWidthDetailsOverviewRowPresenter) presenter,
+                    (FullWidthDetailsOverviewRowPresenter.ViewHolder) viewHolder,
+                    adapterPosition, selectedPosition, selectedSubPosition);
+        }
+    }
+
+    /**
+     * Called to change DetailsOverviewRow view status when current selected row position
+     * or selected sub position changed.  Subclass may override.   The default
+     * implementation switches between three states based on the positions:
+     * {@link FullWidthDetailsOverviewRowPresenter#STATE_HALF},
+     * {@link FullWidthDetailsOverviewRowPresenter#STATE_FULL} and
+     * {@link FullWidthDetailsOverviewRowPresenter#STATE_SMALL}.
+     *
+     * @param presenter   The presenter used to create row ViewHolder.
+     * @param viewHolder  The visible (attached) row ViewHolder, note that it may or may not
+     *                    be selected.
+     * @param adapterPosition  The adapter position of viewHolder inside adapter.
+     * @param selectedPosition The adapter position of currently selected row.
+     * @param selectedSubPosition The sub position within currently selected row.  This is used
+     *                            When a row has multiple alignment positions.
+     */
+    protected void onSetDetailsOverviewRowStatus(FullWidthDetailsOverviewRowPresenter presenter,
+            FullWidthDetailsOverviewRowPresenter.ViewHolder viewHolder, int adapterPosition,
+            int selectedPosition, int selectedSubPosition) {
+        if (selectedPosition > adapterPosition) {
+            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
+        } else if (selectedPosition == adapterPosition && selectedSubPosition == 1) {
+            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_HALF);
+        } else if (selectedPosition == adapterPosition && selectedSubPosition == 0){
+            presenter.setState(viewHolder, FullWidthDetailsOverviewRowPresenter.STATE_FULL);
+        } else {
+            presenter.setState(viewHolder,
+                    FullWidthDetailsOverviewRowPresenter.STATE_SMALL);
+        }
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        setupChildFragmentLayout();
+        mStateMachine.fireEvent(EVT_ONSTART);
+        if (mDetailsParallax != null) {
+            mDetailsParallax.setRecyclerView(mRowsSupportFragment.getVerticalGridView());
+        }
+        if (mPendingFocusOnVideo) {
+            slideOutGridView();
+        } else if (!getView().hasFocus()) {
+            mRowsSupportFragment.getVerticalGridView().requestFocus();
+        }
+    }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(getContext(),
+                R.transition.lb_details_enter_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    @Override
+    protected void onEntranceTransitionEnd() {
+        mRowsSupportFragment.onTransitionEnd();
+    }
+
+    @Override
+    protected void onEntranceTransitionPrepare() {
+        mRowsSupportFragment.onTransitionPrepare();
+    }
+
+    @Override
+    protected void onEntranceTransitionStart() {
+        mRowsSupportFragment.onTransitionStart();
+    }
+
+    /**
+     * Returns the {@link DetailsParallax} instance used by
+     * {@link DetailsSupportFragmentBackgroundController} to configure parallax effect of background and
+     * control embedded video playback. App usually does not use this method directly.
+     * App may use this method for other custom parallax tasks.
+     *
+     * @return The DetailsParallax instance attached to the DetailsSupportFragment.
+     */
+    public DetailsParallax getParallax() {
+        if (mDetailsParallax == null) {
+            mDetailsParallax = new DetailsParallax();
+            if (mRowsSupportFragment != null && mRowsSupportFragment.getView() != null) {
+                mDetailsParallax.setRecyclerView(mRowsSupportFragment.getVerticalGridView());
+            }
+        }
+        return mDetailsParallax;
+    }
+
+    /**
+     * Set background drawable shown below foreground rows UI and above
+     * {@link #findOrCreateVideoSupportFragment()}.
+     *
+     * @see DetailsSupportFragmentBackgroundController
+     */
+    void setBackgroundDrawable(Drawable drawable) {
+        if (mBackgroundView != null) {
+            mBackgroundView.setBackground(drawable);
+        }
+        mBackgroundDrawable = drawable;
+    }
+
+    /**
+     * This method does the following
+     * <ul>
+     * <li>sets up focus search handling logic in the root view to enable transitioning between
+     * half screen/full screen/no video mode.</li>
+     *
+     * <li>Sets up the key listener in the root view to intercept events like UP/DOWN and
+     * transition to appropriate mode like half/full screen video.</li>
+     * </ul>
+     */
+    void setupDpadNavigation() {
+        mRootView.setOnChildFocusListener(new BrowseFrameLayout.OnChildFocusListener() {
+
+            @Override
+            public boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
+                return false;
+            }
+
+            @Override
+            public void onRequestChildFocus(View child, View focused) {
+                if (child != mRootView.getFocusedChild()) {
+                    if (child.getId() == R.id.details_fragment_root) {
+                        if (!mPendingFocusOnVideo) {
+                            slideInGridView();
+                            showTitle(true);
+                        }
+                    } else if (child.getId() == R.id.video_surface_container) {
+                        slideOutGridView();
+                        showTitle(false);
+                    } else {
+                        showTitle(true);
+                    }
+                }
+            }
+        });
+        mRootView.setOnFocusSearchListener(new BrowseFrameLayout.OnFocusSearchListener() {
+            @Override
+            public View onFocusSearch(View focused, int direction) {
+                if (mRowsSupportFragment.getVerticalGridView() != null
+                        && mRowsSupportFragment.getVerticalGridView().hasFocus()) {
+                    if (direction == View.FOCUS_UP) {
+                        if (mDetailsBackgroundController != null
+                                && mDetailsBackgroundController.canNavigateToVideoSupportFragment()
+                                && mVideoSupportFragment != null && mVideoSupportFragment.getView() != null) {
+                            return mVideoSupportFragment.getView();
+                        } else if (getTitleView() != null && getTitleView().hasFocusable()) {
+                            return getTitleView();
+                        }
+                    }
+                } else if (getTitleView() != null && getTitleView().hasFocus()) {
+                    if (direction == View.FOCUS_DOWN) {
+                        if (mRowsSupportFragment.getVerticalGridView() != null) {
+                            return mRowsSupportFragment.getVerticalGridView();
+                        }
+                    }
+                }
+                return focused;
+            }
+        });
+
+        // If we press BACK on remote while in full screen video mode, we should
+        // transition back to half screen video playback mode.
+        mRootView.setOnDispatchKeyListener(new View.OnKeyListener() {
+            @Override
+            public boolean onKey(View v, int keyCode, KeyEvent event) {
+                // This is used to check if we are in full screen video mode. This is somewhat
+                // hacky and relies on the behavior of the video helper class to update the
+                // focusability of the video surface view.
+                if (mVideoSupportFragment != null && mVideoSupportFragment.getView() != null
+                        && mVideoSupportFragment.getView().hasFocus()) {
+                    if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_ESCAPE) {
+                        if (getVerticalGridView().getChildCount() > 0) {
+                            getVerticalGridView().requestFocus();
+                            return true;
+                        }
+                    }
+                }
+
+                return false;
+            }
+        });
+    }
+
+    /**
+     * Slides vertical grid view (displaying media item details) out of the screen from below.
+     */
+    void slideOutGridView() {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().animateOut();
+        }
+    }
+
+    void slideInGridView() {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().animateIn();
+        }
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java b/leanback/src/main/java/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java
rename to leanback/src/main/java/android/support/v17/leanback/app/DetailsSupportFragmentBackgroundController.java
diff --git a/leanback/src/android/support/v17/leanback/app/ErrorFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/ErrorFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/ErrorFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/ErrorFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/ErrorSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/ErrorSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/ErrorSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/ErrorSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/FragmentUtil.java b/leanback/src/main/java/android/support/v17/leanback/app/FragmentUtil.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/FragmentUtil.java
rename to leanback/src/main/java/android/support/v17/leanback/app/FragmentUtil.java
diff --git a/leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/GuidedStepFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/GuidedStepFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/GuidedStepFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java b/leanback/src/main/java/android/support/v17/leanback/app/GuidedStepRootLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/GuidedStepRootLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/app/GuidedStepRootLayout.java
diff --git a/leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/GuidedStepSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/GuidedStepSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/GuidedStepSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/HeadersFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/HeadersFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/HeadersFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/HeadersFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/HeadersSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/HeadersSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/HeadersSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/ListRowDataAdapter.java b/leanback/src/main/java/android/support/v17/leanback/app/ListRowDataAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/ListRowDataAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/app/ListRowDataAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/app/OnboardingFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/OnboardingFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/OnboardingFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/OnboardingFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/OnboardingSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/OnboardingSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/OnboardingSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/PermissionHelper.java b/leanback/src/main/java/android/support/v17/leanback/app/PermissionHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/PermissionHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/app/PermissionHelper.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/PlaybackFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/PlaybackFragment.java
new file mode 100644
index 0000000..e13eb96
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/PlaybackFragment.java
@@ -0,0 +1,1183 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from PlaybackSupportFragment.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.animation.LogAccelerateInterpolator;
+import android.support.v17.leanback.animation.LogDecelerateInterpolator;
+import android.support.v17.leanback.media.PlaybackGlueHost;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
+import android.support.v17.leanback.widget.ItemBridgeAdapter;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
+import android.support.v17.leanback.widget.PlaybackSeekDataProvider;
+import android.support.v17.leanback.widget.PlaybackSeekUi;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.app.Fragment;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+
+/**
+ * A fragment for displaying playback controls and related content.
+ *
+ * <p>
+ * A PlaybackFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
+ * of {@link RowPresenter}.
+ * </p>
+ * <p>
+ * A playback row is a row rendered by {@link PlaybackRowPresenter}.
+ * App can call {@link #setPlaybackRow(Row)} to set playback row for the first element of adapter.
+ * App can call {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} to set presenter for it.
+ * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} are
+ * optional, app can pass playback row and PlaybackRowPresenter in the adapter using
+ * {@link #setAdapter(ObjectAdapter)}.
+ * </p>
+ * <p>
+ * Auto hide controls upon playing: best practice is calling
+ * {@link #setControlsOverlayAutoHideEnabled(boolean)} upon play/pause. The auto hiding timer will
+ * be cancelled upon {@link #tickle()} triggered by input event.
+ * </p>
+ * @deprecated use {@link PlaybackSupportFragment}
+ */
+@Deprecated
+public class PlaybackFragment extends Fragment {
+    static final String BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW = "controlvisible_oncreateview";
+
+    /**
+     * No background.
+     */
+    public static final int BG_NONE = 0;
+
+    /**
+     * A dark translucent background.
+     */
+    public static final int BG_DARK = 1;
+    PlaybackGlueHost.HostCallback mHostCallback;
+
+    PlaybackSeekUi.Client mSeekUiClient;
+    boolean mInSeek;
+    ProgressBarManager mProgressBarManager = new ProgressBarManager();
+
+    /**
+     * Resets the focus on the button in the middle of control row.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void resetFocus() {
+        ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView()
+                .findViewHolderForAdapterPosition(0);
+        if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
+            ((PlaybackRowPresenter) vh.getPresenter()).onReappear(
+                    (RowPresenter.ViewHolder) vh.getViewHolder());
+        }
+    }
+
+    private class SetSelectionRunnable implements Runnable {
+        int mPosition;
+        boolean mSmooth = true;
+
+        @Override
+        public void run() {
+            if (mRowsFragment == null) {
+                return;
+            }
+            mRowsFragment.setSelectedPosition(mPosition, mSmooth);
+        }
+    }
+
+    /**
+     * A light translucent background.
+     */
+    public static final int BG_LIGHT = 2;
+    RowsFragment mRowsFragment;
+    ObjectAdapter mAdapter;
+    PlaybackRowPresenter mPresenter;
+    Row mRow;
+    BaseOnItemViewSelectedListener mExternalItemSelectedListener;
+    BaseOnItemViewClickedListener mExternalItemClickedListener;
+    BaseOnItemViewClickedListener mPlaybackItemClickedListener;
+
+    private final BaseOnItemViewClickedListener mOnItemViewClickedListener =
+            new BaseOnItemViewClickedListener() {
+                @Override
+                public void onItemClicked(Presenter.ViewHolder itemViewHolder,
+                                          Object item,
+                                          RowPresenter.ViewHolder rowViewHolder,
+                                          Object row) {
+                    if (mPlaybackItemClickedListener != null
+                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder) {
+                        mPlaybackItemClickedListener.onItemClicked(
+                                itemViewHolder, item, rowViewHolder, row);
+                    }
+                    if (mExternalItemClickedListener != null) {
+                        mExternalItemClickedListener.onItemClicked(
+                                itemViewHolder, item, rowViewHolder, row);
+                    }
+                }
+            };
+
+    private final BaseOnItemViewSelectedListener mOnItemViewSelectedListener =
+            new BaseOnItemViewSelectedListener() {
+                @Override
+                public void onItemSelected(Presenter.ViewHolder itemViewHolder,
+                                           Object item,
+                                           RowPresenter.ViewHolder rowViewHolder,
+                                           Object row) {
+                    if (mExternalItemSelectedListener != null) {
+                        mExternalItemSelectedListener.onItemSelected(
+                                itemViewHolder, item, rowViewHolder, row);
+                    }
+                }
+            };
+
+    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Listener allowing the application to receive notification of fade in and/or fade out
+     * completion events.
+     * @hide
+     * @deprecated use {@link PlaybackSupportFragment}
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @Deprecated
+    public static class OnFadeCompleteListener {
+        public void onFadeInComplete() {
+        }
+
+        public void onFadeOutComplete() {
+        }
+    }
+
+    private static final String TAG = "PlaybackFragment";
+    private static final boolean DEBUG = false;
+    private static final int ANIMATION_MULTIPLIER = 1;
+
+    private static final int START_FADE_OUT = 1;
+
+    // Fading status
+    private static final int IDLE = 0;
+    private static final int ANIMATING = 1;
+
+    int mPaddingBottom;
+    int mOtherRowsCenterToBottom;
+    View mRootView;
+    View mBackgroundView;
+    int mBackgroundType = BG_DARK;
+    int mBgDarkColor;
+    int mBgLightColor;
+    int mShowTimeMs;
+    int mMajorFadeTranslateY, mMinorFadeTranslateY;
+    int mAnimationTranslateY;
+    OnFadeCompleteListener mFadeCompleteListener;
+    View.OnKeyListener mInputEventHandler;
+    boolean mFadingEnabled = true;
+    boolean mControlVisibleBeforeOnCreateView = true;
+    boolean mControlVisible = true;
+    int mBgAlpha;
+    ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
+    ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
+    ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
+
+    private final Animator.AnimatorListener mFadeListener =
+            new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    enableVerticalGridAnimations(false);
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
+                    if (mBgAlpha > 0) {
+                        enableVerticalGridAnimations(true);
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeInComplete();
+                        }
+                    } else {
+                        VerticalGridView verticalView = getVerticalGridView();
+                        // reset focus to the primary actions only if the selected row was the controls row
+                        if (verticalView != null && verticalView.getSelectedPosition() == 0) {
+                            ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder)
+                                    verticalView.findViewHolderForAdapterPosition(0);
+                            if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
+                                ((PlaybackRowPresenter)vh.getPresenter()).onReappear(
+                                        (RowPresenter.ViewHolder) vh.getViewHolder());
+                            }
+                        }
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeOutComplete();
+                        }
+                    }
+                }
+            };
+
+    public PlaybackFragment() {
+        mProgressBarManager.setInitialDelay(500);
+    }
+
+    VerticalGridView getVerticalGridView() {
+        if (mRowsFragment == null) {
+            return null;
+        }
+        return mRowsFragment.getVerticalGridView();
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message message) {
+            if (message.what == START_FADE_OUT && mFadingEnabled) {
+                hideControlsOverlay(true);
+            }
+        }
+    };
+
+    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
+            new VerticalGridView.OnTouchInterceptListener() {
+                @Override
+                public boolean onInterceptTouchEvent(MotionEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
+            new VerticalGridView.OnKeyInterceptListener() {
+                @Override
+                public boolean onInterceptKeyEvent(KeyEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private void setBgAlpha(int alpha) {
+        mBgAlpha = alpha;
+        if (mBackgroundView != null) {
+            mBackgroundView.getBackground().setAlpha(alpha);
+        }
+    }
+
+    private void enableVerticalGridAnimations(boolean enable) {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().setAnimateChildLayout(enable);
+        }
+    }
+
+    /**
+     * Enables or disables auto hiding controls overlay after a short delay fragment is resumed.
+     * If enabled and fragment is resumed, the view will fade out after a time period.
+     * {@link #tickle()} will kill the timer, next time fragment is resumed,
+     * the timer will be started again if {@link #isControlsOverlayAutoHideEnabled()} is true.
+     */
+    public void setControlsOverlayAutoHideEnabled(boolean enabled) {
+        if (DEBUG) Log.v(TAG, "setControlsOverlayAutoHideEnabled " + enabled);
+        if (enabled != mFadingEnabled) {
+            mFadingEnabled = enabled;
+            if (isResumed() && getView().hasFocus()) {
+                showControlsOverlay(true);
+                if (enabled) {
+                    // StateGraph 7->2 5->2
+                    startFadeTimer();
+                } else {
+                    // StateGraph 4->5 2->5
+                    stopFadeTimer();
+                }
+            } else {
+                // StateGraph 6->1 1->6
+            }
+        }
+    }
+
+    /**
+     * Returns true if controls will be auto hidden after a delay when fragment is resumed.
+     */
+    public boolean isControlsOverlayAutoHideEnabled() {
+        return mFadingEnabled;
+    }
+
+    /**
+     * @deprecated Uses {@link #setControlsOverlayAutoHideEnabled(boolean)}
+     */
+    @Deprecated
+    public void setFadingEnabled(boolean enabled) {
+        setControlsOverlayAutoHideEnabled(enabled);
+    }
+
+    /**
+     * @deprecated Uses {@link #isControlsOverlayAutoHideEnabled()}
+     */
+    @Deprecated
+    public boolean isFadingEnabled() {
+        return isControlsOverlayAutoHideEnabled();
+    }
+
+    /**
+     * Sets the listener to be called when fade in or out has completed.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
+        mFadeCompleteListener = listener;
+    }
+
+    /**
+     * Returns the listener to be called when fade in or out has completed.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public OnFadeCompleteListener getFadeCompleteListener() {
+        return mFadeCompleteListener;
+    }
+
+    /**
+     * Sets the input event handler.
+     */
+    public final void setOnKeyInterceptListener(View.OnKeyListener handler) {
+        mInputEventHandler = handler;
+    }
+
+    /**
+     * Tickles the playback controls. Fades in the view if it was faded out. {@link #tickle()} will
+     * also kill the timer created by {@link #setControlsOverlayAutoHideEnabled(boolean)}. When
+     * next time fragment is resumed, the timer will be started again if
+     * {@link #isControlsOverlayAutoHideEnabled()} is true. In most cases app does not need call
+     * this method, tickling on input events is handled by the fragment.
+     */
+    public void tickle() {
+        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
+        //StateGraph 2->4
+        stopFadeTimer();
+        showControlsOverlay(true);
+    }
+
+    private boolean onInterceptInputEvent(InputEvent event) {
+        final boolean controlsHidden = !mControlVisible;
+        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
+        boolean consumeEvent = false;
+        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
+        int keyAction = 0;
+
+        if (event instanceof KeyEvent) {
+            keyCode = ((KeyEvent) event).getKeyCode();
+            keyAction = ((KeyEvent) event).getAction();
+            if (mInputEventHandler != null) {
+                consumeEvent = mInputEventHandler.onKey(getView(), keyCode, (KeyEvent) event);
+            }
+        }
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                // Event may be consumed; regardless, if controls are hidden then these keys will
+                // bring up the controls.
+                if (controlsHidden) {
+                    consumeEvent = true;
+                }
+                if (keyAction == KeyEvent.ACTION_DOWN) {
+                    tickle();
+                }
+                break;
+            case KeyEvent.KEYCODE_BACK:
+            case KeyEvent.KEYCODE_ESCAPE:
+                if (mInSeek) {
+                    // when in seek, the SeekUi will handle the BACK.
+                    return false;
+                }
+                // If controls are not hidden, back will be consumed to fade
+                // them out (even if the key was consumed by the handler).
+                if (!controlsHidden) {
+                    consumeEvent = true;
+
+                    if (((KeyEvent) event).getAction() == KeyEvent.ACTION_UP) {
+                        hideControlsOverlay(true);
+                    }
+                }
+                break;
+            default:
+                if (consumeEvent) {
+                    if (keyAction == KeyEvent.ACTION_DOWN) {
+                        tickle();
+                    }
+                }
+        }
+        return consumeEvent;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        // controls view are initially visible, make it invisible
+        // if app has called hideControlsOverlay() before view created.
+        mControlVisible = true;
+        if (!mControlVisibleBeforeOnCreateView) {
+            showControlsOverlay(false, false);
+            mControlVisibleBeforeOnCreateView = true;
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        if (mControlVisible) {
+            //StateGraph: 6->5 1->2
+            if (mFadingEnabled) {
+                // StateGraph 1->2
+                startFadeTimer();
+            }
+        } else {
+            //StateGraph: 6->7 1->3
+        }
+        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
+        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
+        if (mHostCallback != null) {
+            mHostCallback.onHostResume();
+        }
+    }
+
+    private void stopFadeTimer() {
+        if (mHandler != null) {
+            mHandler.removeMessages(START_FADE_OUT);
+        }
+    }
+
+    private void startFadeTimer() {
+        if (mHandler != null) {
+            mHandler.removeMessages(START_FADE_OUT);
+            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
+        }
+    }
+
+    private static ValueAnimator loadAnimator(Context context, int resId) {
+        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
+        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
+        return animator;
+    }
+
+    private void loadBgAnimator() {
+        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                setBgAlpha((Integer) arg0.getAnimatedValue());
+            }
+        };
+
+        Context context = FragmentUtil.getContext(PlaybackFragment.this);
+        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
+        mBgFadeInAnimator.addUpdateListener(listener);
+        mBgFadeInAnimator.addListener(mFadeListener);
+
+        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator.addUpdateListener(listener);
+        mBgFadeOutAnimator.addListener(mFadeListener);
+    }
+
+    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100, 0);
+    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100, 0);
+
+    private void loadControlRowAnimator() {
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                RecyclerView.ViewHolder vh = getVerticalGridView()
+                        .findViewHolderForAdapterPosition(0);
+                if (vh == null) {
+                    return;
+                }
+                View view = vh.itemView;
+                if (view != null) {
+                    final float fraction = (Float) arg0.getAnimatedValue();
+                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
+                    view.setAlpha(fraction);
+                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                }
+            }
+        };
+
+        Context context = FragmentUtil.getContext(PlaybackFragment.this);
+        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
+        mControlRowFadeInAnimator.addUpdateListener(updateListener);
+        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mControlRowFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
+        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
+    }
+
+    private void loadOtherRowAnimator() {
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                final float fraction = (Float) arg0.getAnimatedValue();
+                final int count = getVerticalGridView().getChildCount();
+                for (int i = 0; i < count; i++) {
+                    View view = getVerticalGridView().getChildAt(i);
+                    if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
+                        view.setAlpha(fraction);
+                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                    }
+                }
+            }
+        };
+
+        Context context = FragmentUtil.getContext(PlaybackFragment.this);
+        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
+        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
+    }
+
+    /**
+     * Fades out the playback overlay immediately.
+     * @deprecated Call {@link #hideControlsOverlay(boolean)}
+     */
+    @Deprecated
+    public void fadeOut() {
+        showControlsOverlay(false, false);
+    }
+
+    /**
+     * Show controls overlay.
+     *
+     * @param runAnimation True to run animation, false otherwise.
+     */
+    public void showControlsOverlay(boolean runAnimation) {
+        showControlsOverlay(true, runAnimation);
+    }
+
+    /**
+     * Returns true if controls overlay is visible, false otherwise.
+     *
+     * @return True if controls overlay is visible, false otherwise.
+     * @see #showControlsOverlay(boolean)
+     * @see #hideControlsOverlay(boolean)
+     */
+    public boolean isControlsOverlayVisible() {
+        return mControlVisible;
+    }
+
+    /**
+     * Hide controls overlay.
+     *
+     * @param runAnimation True to run animation, false otherwise.
+     */
+    public void hideControlsOverlay(boolean runAnimation) {
+        showControlsOverlay(false, runAnimation);
+    }
+
+    /**
+     * if first animator is still running, reverse it; otherwise start second animator.
+     */
+    static void reverseFirstOrStartSecond(ValueAnimator first, ValueAnimator second,
+            boolean runAnimation) {
+        if (first.isStarted()) {
+            first.reverse();
+            if (!runAnimation) {
+                first.end();
+            }
+        } else {
+            second.start();
+            if (!runAnimation) {
+                second.end();
+            }
+        }
+    }
+
+    /**
+     * End first or second animator if they are still running.
+     */
+    static void endAll(ValueAnimator first, ValueAnimator second) {
+        if (first.isStarted()) {
+            first.end();
+        } else if (second.isStarted()) {
+            second.end();
+        }
+    }
+
+    /**
+     * Fade in or fade out rows and background.
+     *
+     * @param show True to fade in, false to fade out.
+     * @param animation True to run animation.
+     */
+    void showControlsOverlay(boolean show, boolean animation) {
+        if (DEBUG) Log.v(TAG, "showControlsOverlay " + show);
+        if (getView() == null) {
+            mControlVisibleBeforeOnCreateView = show;
+            return;
+        }
+        // force no animation when fragment is not resumed
+        if (!isResumed()) {
+            animation = false;
+        }
+        if (show == mControlVisible) {
+            if (!animation) {
+                // End animation if needed
+                endAll(mBgFadeInAnimator, mBgFadeOutAnimator);
+                endAll(mControlRowFadeInAnimator, mControlRowFadeOutAnimator);
+                endAll(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator);
+            }
+            return;
+        }
+        // StateGraph: 7<->5 4<->3 2->3
+        mControlVisible = show;
+        if (!mControlVisible) {
+            // StateGraph 2->3
+            stopFadeTimer();
+        }
+
+        mAnimationTranslateY = (getVerticalGridView() == null
+                || getVerticalGridView().getSelectedPosition() == 0)
+                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
+
+        if (show) {
+            reverseFirstOrStartSecond(mBgFadeOutAnimator, mBgFadeInAnimator, animation);
+            reverseFirstOrStartSecond(mControlRowFadeOutAnimator, mControlRowFadeInAnimator,
+                    animation);
+            reverseFirstOrStartSecond(mOtherRowFadeOutAnimator, mOtherRowFadeInAnimator, animation);
+        } else {
+            reverseFirstOrStartSecond(mBgFadeInAnimator, mBgFadeOutAnimator, animation);
+            reverseFirstOrStartSecond(mControlRowFadeInAnimator, mControlRowFadeOutAnimator,
+                    animation);
+            reverseFirstOrStartSecond(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator, animation);
+        }
+        if (animation) {
+            getView().announceForAccessibility(getString(show
+                    ? R.string.lb_playback_controls_shown
+                    : R.string.lb_playback_controls_hidden));
+        }
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.mPosition = position;
+        mSetSelectionRunnable.mSmooth = smooth;
+        if (getView() != null && getView().getHandler() != null) {
+            getView().getHandler().post(mSetSelectionRunnable);
+        }
+    }
+
+    private void setupChildFragmentLayout() {
+        setVerticalGridViewLayout(mRowsFragment.getVerticalGridView());
+    }
+
+    void setVerticalGridViewLayout(VerticalGridView listview) {
+        if (listview == null) {
+            return;
+        }
+
+        // we set the base line of alignment to -paddingBottom
+        listview.setWindowAlignmentOffset(-mPaddingBottom);
+        listview.setWindowAlignmentOffsetPercent(
+                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+
+        // align other rows that arent the last to center of screen, since our baseline is
+        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
+        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
+        listview.setItemAlignmentOffsetPercent(50);
+
+        // Push last row to the bottom padding
+        // Padding affects alignment when last row is focused
+        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
+                listview.getPaddingRight(), mPaddingBottom);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mOtherRowsCenterToBottom = getResources()
+                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
+        mPaddingBottom =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
+        mBgDarkColor =
+                getResources().getColor(R.color.lb_playback_controls_background_dark);
+        mBgLightColor =
+                getResources().getColor(R.color.lb_playback_controls_background_light);
+        mShowTimeMs =
+                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
+        mMajorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
+        mMinorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
+
+        loadBgAnimator();
+        loadControlRowAnimator();
+        loadOtherRowAnimator();
+    }
+
+    /**
+     * Sets the background type.
+     *
+     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
+     */
+    public void setBackgroundType(int type) {
+        switch (type) {
+            case BG_LIGHT:
+            case BG_DARK:
+            case BG_NONE:
+                if (type != mBackgroundType) {
+                    mBackgroundType = type;
+                    updateBackground();
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid background type");
+        }
+    }
+
+    /**
+     * Returns the background type.
+     */
+    public int getBackgroundType() {
+        return mBackgroundType;
+    }
+
+    private void updateBackground() {
+        if (mBackgroundView != null) {
+            int color = mBgDarkColor;
+            switch (mBackgroundType) {
+                case BG_DARK:
+                    break;
+                case BG_LIGHT:
+                    color = mBgLightColor;
+                    break;
+                case BG_NONE:
+                    color = Color.TRANSPARENT;
+                    break;
+            }
+            mBackgroundView.setBackground(new ColorDrawable(color));
+            setBgAlpha(mBgAlpha);
+        }
+    }
+
+    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
+            new ItemBridgeAdapter.AdapterListener() {
+                @Override
+                public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
+                    if (!mControlVisible) {
+                        if (DEBUG) Log.v(TAG, "setting alpha to 0");
+                        vh.getViewHolder().view.setAlpha(0);
+                    }
+                }
+
+                @Override
+                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
+                    Presenter.ViewHolder viewHolder = vh.getViewHolder();
+                    if (viewHolder instanceof PlaybackSeekUi) {
+                        ((PlaybackSeekUi) viewHolder).setPlaybackSeekUiClient(mChainedClient);
+                    }
+                }
+
+                @Override
+                public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
+                    // Reset animation state
+                    vh.getViewHolder().view.setAlpha(1f);
+                    vh.getViewHolder().view.setTranslationY(0);
+                    vh.getViewHolder().view.setAlpha(1f);
+                }
+
+                @Override
+                public void onBind(ItemBridgeAdapter.ViewHolder vh) {
+                }
+            };
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        mRootView = inflater.inflate(R.layout.lb_playback_fragment, container, false);
+        mBackgroundView = mRootView.findViewById(R.id.playback_fragment_background);
+        mRowsFragment = (RowsFragment) getChildFragmentManager().findFragmentById(
+                R.id.playback_controls_dock);
+        if (mRowsFragment == null) {
+            mRowsFragment = new RowsFragment();
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.playback_controls_dock, mRowsFragment)
+                    .commit();
+        }
+        if (mAdapter == null) {
+            setAdapter(new ArrayObjectAdapter(new ClassPresenterSelector()));
+        } else {
+            mRowsFragment.setAdapter(mAdapter);
+        }
+        mRowsFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
+        mRowsFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mBgAlpha = 255;
+        updateBackground();
+        mRowsFragment.setExternalAdapterListener(mAdapterListener);
+        ProgressBarManager progressBarManager = getProgressBarManager();
+        if (progressBarManager != null) {
+            progressBarManager.setRootView((ViewGroup) mRootView);
+        }
+        return mRootView;
+    }
+
+    /**
+     * Sets the {@link PlaybackGlueHost.HostCallback}. Implementor of this interface will
+     * take appropriate actions to take action when the hosting fragment starts/stops processing.
+     */
+    public void setHostCallback(PlaybackGlueHost.HostCallback hostCallback) {
+        this.mHostCallback = hostCallback;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        setupChildFragmentLayout();
+        mRowsFragment.setAdapter(mAdapter);
+        if (mHostCallback != null) {
+            mHostCallback.onHostStart();
+        }
+    }
+
+    @Override
+    public void onStop() {
+        if (mHostCallback != null) {
+            mHostCallback.onHostStop();
+        }
+        super.onStop();
+    }
+
+    @Override
+    public void onPause() {
+        if (mHostCallback != null) {
+            mHostCallback.onHostPause();
+        }
+        if (mHandler.hasMessages(START_FADE_OUT)) {
+            // StateGraph: 2->1
+            mHandler.removeMessages(START_FADE_OUT);
+        } else {
+            // StateGraph: 5->6, 7->6, 4->1, 3->1
+        }
+        super.onPause();
+    }
+
+    /**
+     * This listener is called every time there is a selection in {@link RowsFragment}. This can
+     * be used by users to take additional actions such as animations.
+     */
+    public void setOnItemViewSelectedListener(final BaseOnItemViewSelectedListener listener) {
+        mExternalItemSelectedListener = listener;
+    }
+
+    /**
+     * This listener is called every time there is a click in {@link RowsFragment}. This can
+     * be used by users to take additional actions such as animations.
+     */
+    public void setOnItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mExternalItemClickedListener = listener;
+    }
+
+    /**
+     * Sets the {@link BaseOnItemViewClickedListener} that would be invoked for clicks
+     * only on {@link android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder}.
+     */
+    public void setOnPlaybackItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mPlaybackItemClickedListener = listener;
+    }
+
+    @Override
+    public void onDestroyView() {
+        mRootView = null;
+        mBackgroundView = null;
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mHostCallback != null) {
+            mHostCallback.onHostDestroy();
+        }
+        super.onDestroy();
+    }
+
+    /**
+     * Sets the playback row for the playback controls. The row will be set as first element
+     * of adapter if the adapter is {@link ArrayObjectAdapter} or {@link SparseArrayObjectAdapter}.
+     * @param row The row that represents the playback.
+     */
+    public void setPlaybackRow(Row row) {
+        this.mRow = row;
+        setupRow();
+        setupPresenter();
+    }
+
+    /**
+     * Sets the presenter for rendering the playback row set by {@link #setPlaybackRow(Row)}. If
+     * adapter does not set a {@link PresenterSelector}, {@link #setAdapter(ObjectAdapter)} will
+     * create a {@link ClassPresenterSelector} by default and map from the row object class to this
+     * {@link PlaybackRowPresenter}.
+     *
+     * @param  presenter Presenter used to render {@link #setPlaybackRow(Row)}.
+     */
+    public void setPlaybackRowPresenter(PlaybackRowPresenter presenter) {
+        this.mPresenter = presenter;
+        setupPresenter();
+        setPlaybackRowPresenterAlignment();
+    }
+
+    void setPlaybackRowPresenterAlignment() {
+        if (mAdapter != null && mAdapter.getPresenterSelector() != null) {
+            Presenter[] presenters = mAdapter.getPresenterSelector().getPresenters();
+            if (presenters != null) {
+                for (int i = 0; i < presenters.length; i++) {
+                    if (presenters[i] instanceof PlaybackRowPresenter
+                            && presenters[i].getFacet(ItemAlignmentFacet.class) == null) {
+                        ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
+                        ItemAlignmentFacet.ItemAlignmentDef def =
+                                new ItemAlignmentFacet.ItemAlignmentDef();
+                        def.setItemAlignmentOffset(0);
+                        def.setItemAlignmentOffsetPercent(100);
+                        itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
+                                {def});
+                        presenters[i].setFacet(ItemAlignmentFacet.class, itemAlignment);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Updates the ui when the row data changes.
+     */
+    public void notifyPlaybackRowChanged() {
+        if (mAdapter == null) {
+            return;
+        }
+        mAdapter.notifyItemRangeChanged(0, 1);
+    }
+
+    /**
+     * Sets the list of rows for the fragment. A default {@link ClassPresenterSelector} will be
+     * created if {@link ObjectAdapter#getPresenterSelector()} is null. if user provides
+     * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)},
+     * the row and presenter will be set onto the adapter.
+     *
+     * @param adapter The adapter that contains related rows and optional playback row.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        setupRow();
+        setupPresenter();
+        setPlaybackRowPresenterAlignment();
+
+        if (mRowsFragment != null) {
+            mRowsFragment.setAdapter(adapter);
+        }
+    }
+
+    private void setupRow() {
+        if (mAdapter instanceof ArrayObjectAdapter && mRow != null) {
+            ArrayObjectAdapter adapter = ((ArrayObjectAdapter) mAdapter);
+            if (adapter.size() == 0) {
+                adapter.add(mRow);
+            } else {
+                adapter.replace(0, mRow);
+            }
+        } else if (mAdapter instanceof SparseArrayObjectAdapter && mRow != null) {
+            SparseArrayObjectAdapter adapter = ((SparseArrayObjectAdapter) mAdapter);
+            adapter.set(0, mRow);
+        }
+    }
+
+    private void setupPresenter() {
+        if (mAdapter != null && mRow != null && mPresenter != null) {
+            PresenterSelector selector = mAdapter.getPresenterSelector();
+            if (selector == null) {
+                selector = new ClassPresenterSelector();
+                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
+                mAdapter.setPresenterSelector(selector);
+            } else if (selector instanceof ClassPresenterSelector) {
+                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
+            }
+        }
+    }
+
+    final PlaybackSeekUi.Client mChainedClient = new PlaybackSeekUi.Client() {
+        @Override
+        public boolean isSeekEnabled() {
+            return mSeekUiClient == null ? false : mSeekUiClient.isSeekEnabled();
+        }
+
+        @Override
+        public void onSeekStarted() {
+            if (mSeekUiClient != null) {
+                mSeekUiClient.onSeekStarted();
+            }
+            setSeekMode(true);
+        }
+
+        @Override
+        public PlaybackSeekDataProvider getPlaybackSeekDataProvider() {
+            return mSeekUiClient == null ? null : mSeekUiClient.getPlaybackSeekDataProvider();
+        }
+
+        @Override
+        public void onSeekPositionChanged(long pos) {
+            if (mSeekUiClient != null) {
+                mSeekUiClient.onSeekPositionChanged(pos);
+            }
+        }
+
+        @Override
+        public void onSeekFinished(boolean cancelled) {
+            if (mSeekUiClient != null) {
+                mSeekUiClient.onSeekFinished(cancelled);
+            }
+            setSeekMode(false);
+        }
+    };
+
+    /**
+     * Interface to be implemented by UI widget to support PlaybackSeekUi.
+     */
+    public void setPlaybackSeekUiClient(PlaybackSeekUi.Client client) {
+        mSeekUiClient = client;
+    }
+
+    /**
+     * Show or hide other rows other than PlaybackRow.
+     * @param inSeek True to make other rows visible, false to make other rows invisible.
+     */
+    void setSeekMode(boolean inSeek) {
+        if (mInSeek == inSeek) {
+            return;
+        }
+        mInSeek = inSeek;
+        getVerticalGridView().setSelectedPosition(0);
+        if (mInSeek) {
+            stopFadeTimer();
+        }
+        // immediately fade in control row.
+        showControlsOverlay(true);
+        final int count = getVerticalGridView().getChildCount();
+        for (int i = 0; i < count; i++) {
+            View view = getVerticalGridView().getChildAt(i);
+            if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
+                view.setVisibility(mInSeek ? View.INVISIBLE : View.VISIBLE);
+            }
+        }
+    }
+
+    /**
+     * Called when size of the video changes. App may override.
+     * @param videoWidth Intrinsic width of video
+     * @param videoHeight Intrinsic height of video
+     */
+    protected void onVideoSizeChanged(int videoWidth, int videoHeight) {
+    }
+
+    /**
+     * Called when media has start or stop buffering. App may override. The default initial state
+     * is not buffering.
+     * @param start True for buffering start, false otherwise.
+     */
+    protected void onBufferingStateChanged(boolean start) {
+        ProgressBarManager progressBarManager = getProgressBarManager();
+        if (progressBarManager != null) {
+            if (start) {
+                progressBarManager.show();
+            } else {
+                progressBarManager.hide();
+            }
+        }
+    }
+
+    /**
+     * Called when media has error. App may override.
+     * @param errorCode Optional error code for specific implementation.
+     * @param errorMessage Optional error message for specific implementation.
+     */
+    protected void onError(int errorCode, CharSequence errorMessage) {
+    }
+
+    /**
+     * Returns the ProgressBarManager that will show or hide progress bar in
+     * {@link #onBufferingStateChanged(boolean)}.
+     * @return The ProgressBarManager that will show or hide progress bar in
+     * {@link #onBufferingStateChanged(boolean)}.
+     */
+    public ProgressBarManager getProgressBarManager() {
+        return mProgressBarManager;
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java b/leanback/src/main/java/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
rename to leanback/src/main/java/android/support/v17/leanback/app/PlaybackFragmentGlueHost.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/PlaybackSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/PlaybackSupportFragment.java
new file mode 100644
index 0000000..688cdbc
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/PlaybackSupportFragment.java
@@ -0,0 +1,1176 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.animation.LogAccelerateInterpolator;
+import android.support.v17.leanback.animation.LogDecelerateInterpolator;
+import android.support.v17.leanback.media.PlaybackGlueHost;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.BaseOnItemViewClickedListener;
+import android.support.v17.leanback.widget.BaseOnItemViewSelectedListener;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.ItemAlignmentFacet;
+import android.support.v17.leanback.widget.ItemBridgeAdapter;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.PlaybackRowPresenter;
+import android.support.v17.leanback.widget.PlaybackSeekDataProvider;
+import android.support.v17.leanback.widget.PlaybackSeekUi;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.InputEvent;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+
+/**
+ * A fragment for displaying playback controls and related content.
+ *
+ * <p>
+ * A PlaybackSupportFragment renders the elements of its {@link ObjectAdapter} as a set
+ * of rows in a vertical list.  The Adapter's {@link PresenterSelector} must maintain subclasses
+ * of {@link RowPresenter}.
+ * </p>
+ * <p>
+ * A playback row is a row rendered by {@link PlaybackRowPresenter}.
+ * App can call {@link #setPlaybackRow(Row)} to set playback row for the first element of adapter.
+ * App can call {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} to set presenter for it.
+ * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)} are
+ * optional, app can pass playback row and PlaybackRowPresenter in the adapter using
+ * {@link #setAdapter(ObjectAdapter)}.
+ * </p>
+ * <p>
+ * Auto hide controls upon playing: best practice is calling
+ * {@link #setControlsOverlayAutoHideEnabled(boolean)} upon play/pause. The auto hiding timer will
+ * be cancelled upon {@link #tickle()} triggered by input event.
+ * </p>
+ */
+public class PlaybackSupportFragment extends Fragment {
+    static final String BUNDLE_CONTROL_VISIBLE_ON_CREATEVIEW = "controlvisible_oncreateview";
+
+    /**
+     * No background.
+     */
+    public static final int BG_NONE = 0;
+
+    /**
+     * A dark translucent background.
+     */
+    public static final int BG_DARK = 1;
+    PlaybackGlueHost.HostCallback mHostCallback;
+
+    PlaybackSeekUi.Client mSeekUiClient;
+    boolean mInSeek;
+    ProgressBarManager mProgressBarManager = new ProgressBarManager();
+
+    /**
+     * Resets the focus on the button in the middle of control row.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void resetFocus() {
+        ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder) getVerticalGridView()
+                .findViewHolderForAdapterPosition(0);
+        if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
+            ((PlaybackRowPresenter) vh.getPresenter()).onReappear(
+                    (RowPresenter.ViewHolder) vh.getViewHolder());
+        }
+    }
+
+    private class SetSelectionRunnable implements Runnable {
+        int mPosition;
+        boolean mSmooth = true;
+
+        @Override
+        public void run() {
+            if (mRowsSupportFragment == null) {
+                return;
+            }
+            mRowsSupportFragment.setSelectedPosition(mPosition, mSmooth);
+        }
+    }
+
+    /**
+     * A light translucent background.
+     */
+    public static final int BG_LIGHT = 2;
+    RowsSupportFragment mRowsSupportFragment;
+    ObjectAdapter mAdapter;
+    PlaybackRowPresenter mPresenter;
+    Row mRow;
+    BaseOnItemViewSelectedListener mExternalItemSelectedListener;
+    BaseOnItemViewClickedListener mExternalItemClickedListener;
+    BaseOnItemViewClickedListener mPlaybackItemClickedListener;
+
+    private final BaseOnItemViewClickedListener mOnItemViewClickedListener =
+            new BaseOnItemViewClickedListener() {
+                @Override
+                public void onItemClicked(Presenter.ViewHolder itemViewHolder,
+                                          Object item,
+                                          RowPresenter.ViewHolder rowViewHolder,
+                                          Object row) {
+                    if (mPlaybackItemClickedListener != null
+                            && rowViewHolder instanceof PlaybackRowPresenter.ViewHolder) {
+                        mPlaybackItemClickedListener.onItemClicked(
+                                itemViewHolder, item, rowViewHolder, row);
+                    }
+                    if (mExternalItemClickedListener != null) {
+                        mExternalItemClickedListener.onItemClicked(
+                                itemViewHolder, item, rowViewHolder, row);
+                    }
+                }
+            };
+
+    private final BaseOnItemViewSelectedListener mOnItemViewSelectedListener =
+            new BaseOnItemViewSelectedListener() {
+                @Override
+                public void onItemSelected(Presenter.ViewHolder itemViewHolder,
+                                           Object item,
+                                           RowPresenter.ViewHolder rowViewHolder,
+                                           Object row) {
+                    if (mExternalItemSelectedListener != null) {
+                        mExternalItemSelectedListener.onItemSelected(
+                                itemViewHolder, item, rowViewHolder, row);
+                    }
+                }
+            };
+
+    private final SetSelectionRunnable mSetSelectionRunnable = new SetSelectionRunnable();
+
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    /**
+     * Listener allowing the application to receive notification of fade in and/or fade out
+     * completion events.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public static class OnFadeCompleteListener {
+        public void onFadeInComplete() {
+        }
+
+        public void onFadeOutComplete() {
+        }
+    }
+
+    private static final String TAG = "PlaybackSupportFragment";
+    private static final boolean DEBUG = false;
+    private static final int ANIMATION_MULTIPLIER = 1;
+
+    private static final int START_FADE_OUT = 1;
+
+    // Fading status
+    private static final int IDLE = 0;
+    private static final int ANIMATING = 1;
+
+    int mPaddingBottom;
+    int mOtherRowsCenterToBottom;
+    View mRootView;
+    View mBackgroundView;
+    int mBackgroundType = BG_DARK;
+    int mBgDarkColor;
+    int mBgLightColor;
+    int mShowTimeMs;
+    int mMajorFadeTranslateY, mMinorFadeTranslateY;
+    int mAnimationTranslateY;
+    OnFadeCompleteListener mFadeCompleteListener;
+    View.OnKeyListener mInputEventHandler;
+    boolean mFadingEnabled = true;
+    boolean mControlVisibleBeforeOnCreateView = true;
+    boolean mControlVisible = true;
+    int mBgAlpha;
+    ValueAnimator mBgFadeInAnimator, mBgFadeOutAnimator;
+    ValueAnimator mControlRowFadeInAnimator, mControlRowFadeOutAnimator;
+    ValueAnimator mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator;
+
+    private final Animator.AnimatorListener mFadeListener =
+            new Animator.AnimatorListener() {
+                @Override
+                public void onAnimationStart(Animator animation) {
+                    enableVerticalGridAnimations(false);
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    if (DEBUG) Log.v(TAG, "onAnimationEnd " + mBgAlpha);
+                    if (mBgAlpha > 0) {
+                        enableVerticalGridAnimations(true);
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeInComplete();
+                        }
+                    } else {
+                        VerticalGridView verticalView = getVerticalGridView();
+                        // reset focus to the primary actions only if the selected row was the controls row
+                        if (verticalView != null && verticalView.getSelectedPosition() == 0) {
+                            ItemBridgeAdapter.ViewHolder vh = (ItemBridgeAdapter.ViewHolder)
+                                    verticalView.findViewHolderForAdapterPosition(0);
+                            if (vh != null && vh.getPresenter() instanceof PlaybackRowPresenter) {
+                                ((PlaybackRowPresenter)vh.getPresenter()).onReappear(
+                                        (RowPresenter.ViewHolder) vh.getViewHolder());
+                            }
+                        }
+                        if (mFadeCompleteListener != null) {
+                            mFadeCompleteListener.onFadeOutComplete();
+                        }
+                    }
+                }
+            };
+
+    public PlaybackSupportFragment() {
+        mProgressBarManager.setInitialDelay(500);
+    }
+
+    VerticalGridView getVerticalGridView() {
+        if (mRowsSupportFragment == null) {
+            return null;
+        }
+        return mRowsSupportFragment.getVerticalGridView();
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message message) {
+            if (message.what == START_FADE_OUT && mFadingEnabled) {
+                hideControlsOverlay(true);
+            }
+        }
+    };
+
+    private final VerticalGridView.OnTouchInterceptListener mOnTouchInterceptListener =
+            new VerticalGridView.OnTouchInterceptListener() {
+                @Override
+                public boolean onInterceptTouchEvent(MotionEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private final VerticalGridView.OnKeyInterceptListener mOnKeyInterceptListener =
+            new VerticalGridView.OnKeyInterceptListener() {
+                @Override
+                public boolean onInterceptKeyEvent(KeyEvent event) {
+                    return onInterceptInputEvent(event);
+                }
+            };
+
+    private void setBgAlpha(int alpha) {
+        mBgAlpha = alpha;
+        if (mBackgroundView != null) {
+            mBackgroundView.getBackground().setAlpha(alpha);
+        }
+    }
+
+    private void enableVerticalGridAnimations(boolean enable) {
+        if (getVerticalGridView() != null) {
+            getVerticalGridView().setAnimateChildLayout(enable);
+        }
+    }
+
+    /**
+     * Enables or disables auto hiding controls overlay after a short delay fragment is resumed.
+     * If enabled and fragment is resumed, the view will fade out after a time period.
+     * {@link #tickle()} will kill the timer, next time fragment is resumed,
+     * the timer will be started again if {@link #isControlsOverlayAutoHideEnabled()} is true.
+     */
+    public void setControlsOverlayAutoHideEnabled(boolean enabled) {
+        if (DEBUG) Log.v(TAG, "setControlsOverlayAutoHideEnabled " + enabled);
+        if (enabled != mFadingEnabled) {
+            mFadingEnabled = enabled;
+            if (isResumed() && getView().hasFocus()) {
+                showControlsOverlay(true);
+                if (enabled) {
+                    // StateGraph 7->2 5->2
+                    startFadeTimer();
+                } else {
+                    // StateGraph 4->5 2->5
+                    stopFadeTimer();
+                }
+            } else {
+                // StateGraph 6->1 1->6
+            }
+        }
+    }
+
+    /**
+     * Returns true if controls will be auto hidden after a delay when fragment is resumed.
+     */
+    public boolean isControlsOverlayAutoHideEnabled() {
+        return mFadingEnabled;
+    }
+
+    /**
+     * @deprecated Uses {@link #setControlsOverlayAutoHideEnabled(boolean)}
+     */
+    @Deprecated
+    public void setFadingEnabled(boolean enabled) {
+        setControlsOverlayAutoHideEnabled(enabled);
+    }
+
+    /**
+     * @deprecated Uses {@link #isControlsOverlayAutoHideEnabled()}
+     */
+    @Deprecated
+    public boolean isFadingEnabled() {
+        return isControlsOverlayAutoHideEnabled();
+    }
+
+    /**
+     * Sets the listener to be called when fade in or out has completed.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void setFadeCompleteListener(OnFadeCompleteListener listener) {
+        mFadeCompleteListener = listener;
+    }
+
+    /**
+     * Returns the listener to be called when fade in or out has completed.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public OnFadeCompleteListener getFadeCompleteListener() {
+        return mFadeCompleteListener;
+    }
+
+    /**
+     * Sets the input event handler.
+     */
+    public final void setOnKeyInterceptListener(View.OnKeyListener handler) {
+        mInputEventHandler = handler;
+    }
+
+    /**
+     * Tickles the playback controls. Fades in the view if it was faded out. {@link #tickle()} will
+     * also kill the timer created by {@link #setControlsOverlayAutoHideEnabled(boolean)}. When
+     * next time fragment is resumed, the timer will be started again if
+     * {@link #isControlsOverlayAutoHideEnabled()} is true. In most cases app does not need call
+     * this method, tickling on input events is handled by the fragment.
+     */
+    public void tickle() {
+        if (DEBUG) Log.v(TAG, "tickle enabled " + mFadingEnabled + " isResumed " + isResumed());
+        //StateGraph 2->4
+        stopFadeTimer();
+        showControlsOverlay(true);
+    }
+
+    private boolean onInterceptInputEvent(InputEvent event) {
+        final boolean controlsHidden = !mControlVisible;
+        if (DEBUG) Log.v(TAG, "onInterceptInputEvent hidden " + controlsHidden + " " + event);
+        boolean consumeEvent = false;
+        int keyCode = KeyEvent.KEYCODE_UNKNOWN;
+        int keyAction = 0;
+
+        if (event instanceof KeyEvent) {
+            keyCode = ((KeyEvent) event).getKeyCode();
+            keyAction = ((KeyEvent) event).getAction();
+            if (mInputEventHandler != null) {
+                consumeEvent = mInputEventHandler.onKey(getView(), keyCode, (KeyEvent) event);
+            }
+        }
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+            case KeyEvent.KEYCODE_DPAD_UP:
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                // Event may be consumed; regardless, if controls are hidden then these keys will
+                // bring up the controls.
+                if (controlsHidden) {
+                    consumeEvent = true;
+                }
+                if (keyAction == KeyEvent.ACTION_DOWN) {
+                    tickle();
+                }
+                break;
+            case KeyEvent.KEYCODE_BACK:
+            case KeyEvent.KEYCODE_ESCAPE:
+                if (mInSeek) {
+                    // when in seek, the SeekUi will handle the BACK.
+                    return false;
+                }
+                // If controls are not hidden, back will be consumed to fade
+                // them out (even if the key was consumed by the handler).
+                if (!controlsHidden) {
+                    consumeEvent = true;
+
+                    if (((KeyEvent) event).getAction() == KeyEvent.ACTION_UP) {
+                        hideControlsOverlay(true);
+                    }
+                }
+                break;
+            default:
+                if (consumeEvent) {
+                    if (keyAction == KeyEvent.ACTION_DOWN) {
+                        tickle();
+                    }
+                }
+        }
+        return consumeEvent;
+    }
+
+    @Override
+    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        // controls view are initially visible, make it invisible
+        // if app has called hideControlsOverlay() before view created.
+        mControlVisible = true;
+        if (!mControlVisibleBeforeOnCreateView) {
+            showControlsOverlay(false, false);
+            mControlVisibleBeforeOnCreateView = true;
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        if (mControlVisible) {
+            //StateGraph: 6->5 1->2
+            if (mFadingEnabled) {
+                // StateGraph 1->2
+                startFadeTimer();
+            }
+        } else {
+            //StateGraph: 6->7 1->3
+        }
+        getVerticalGridView().setOnTouchInterceptListener(mOnTouchInterceptListener);
+        getVerticalGridView().setOnKeyInterceptListener(mOnKeyInterceptListener);
+        if (mHostCallback != null) {
+            mHostCallback.onHostResume();
+        }
+    }
+
+    private void stopFadeTimer() {
+        if (mHandler != null) {
+            mHandler.removeMessages(START_FADE_OUT);
+        }
+    }
+
+    private void startFadeTimer() {
+        if (mHandler != null) {
+            mHandler.removeMessages(START_FADE_OUT);
+            mHandler.sendEmptyMessageDelayed(START_FADE_OUT, mShowTimeMs);
+        }
+    }
+
+    private static ValueAnimator loadAnimator(Context context, int resId) {
+        ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(context, resId);
+        animator.setDuration(animator.getDuration() * ANIMATION_MULTIPLIER);
+        return animator;
+    }
+
+    private void loadBgAnimator() {
+        AnimatorUpdateListener listener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                setBgAlpha((Integer) arg0.getAnimatedValue());
+            }
+        };
+
+        Context context = getContext();
+        mBgFadeInAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_in);
+        mBgFadeInAnimator.addUpdateListener(listener);
+        mBgFadeInAnimator.addListener(mFadeListener);
+
+        mBgFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_bg_fade_out);
+        mBgFadeOutAnimator.addUpdateListener(listener);
+        mBgFadeOutAnimator.addListener(mFadeListener);
+    }
+
+    private TimeInterpolator mLogDecelerateInterpolator = new LogDecelerateInterpolator(100, 0);
+    private TimeInterpolator mLogAccelerateInterpolator = new LogAccelerateInterpolator(100, 0);
+
+    private void loadControlRowAnimator() {
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                RecyclerView.ViewHolder vh = getVerticalGridView()
+                        .findViewHolderForAdapterPosition(0);
+                if (vh == null) {
+                    return;
+                }
+                View view = vh.itemView;
+                if (view != null) {
+                    final float fraction = (Float) arg0.getAnimatedValue();
+                    if (DEBUG) Log.v(TAG, "fraction " + fraction);
+                    view.setAlpha(fraction);
+                    view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                }
+            }
+        };
+
+        Context context = getContext();
+        mControlRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
+        mControlRowFadeInAnimator.addUpdateListener(updateListener);
+        mControlRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mControlRowFadeOutAnimator = loadAnimator(context,
+                R.animator.lb_playback_controls_fade_out);
+        mControlRowFadeOutAnimator.addUpdateListener(updateListener);
+        mControlRowFadeOutAnimator.setInterpolator(mLogAccelerateInterpolator);
+    }
+
+    private void loadOtherRowAnimator() {
+        final AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator arg0) {
+                if (getVerticalGridView() == null) {
+                    return;
+                }
+                final float fraction = (Float) arg0.getAnimatedValue();
+                final int count = getVerticalGridView().getChildCount();
+                for (int i = 0; i < count; i++) {
+                    View view = getVerticalGridView().getChildAt(i);
+                    if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
+                        view.setAlpha(fraction);
+                        view.setTranslationY((float) mAnimationTranslateY * (1f - fraction));
+                    }
+                }
+            }
+        };
+
+        Context context = getContext();
+        mOtherRowFadeInAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_in);
+        mOtherRowFadeInAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeInAnimator.setInterpolator(mLogDecelerateInterpolator);
+
+        mOtherRowFadeOutAnimator = loadAnimator(context, R.animator.lb_playback_controls_fade_out);
+        mOtherRowFadeOutAnimator.addUpdateListener(updateListener);
+        mOtherRowFadeOutAnimator.setInterpolator(new AccelerateInterpolator());
+    }
+
+    /**
+     * Fades out the playback overlay immediately.
+     * @deprecated Call {@link #hideControlsOverlay(boolean)}
+     */
+    @Deprecated
+    public void fadeOut() {
+        showControlsOverlay(false, false);
+    }
+
+    /**
+     * Show controls overlay.
+     *
+     * @param runAnimation True to run animation, false otherwise.
+     */
+    public void showControlsOverlay(boolean runAnimation) {
+        showControlsOverlay(true, runAnimation);
+    }
+
+    /**
+     * Returns true if controls overlay is visible, false otherwise.
+     *
+     * @return True if controls overlay is visible, false otherwise.
+     * @see #showControlsOverlay(boolean)
+     * @see #hideControlsOverlay(boolean)
+     */
+    public boolean isControlsOverlayVisible() {
+        return mControlVisible;
+    }
+
+    /**
+     * Hide controls overlay.
+     *
+     * @param runAnimation True to run animation, false otherwise.
+     */
+    public void hideControlsOverlay(boolean runAnimation) {
+        showControlsOverlay(false, runAnimation);
+    }
+
+    /**
+     * if first animator is still running, reverse it; otherwise start second animator.
+     */
+    static void reverseFirstOrStartSecond(ValueAnimator first, ValueAnimator second,
+            boolean runAnimation) {
+        if (first.isStarted()) {
+            first.reverse();
+            if (!runAnimation) {
+                first.end();
+            }
+        } else {
+            second.start();
+            if (!runAnimation) {
+                second.end();
+            }
+        }
+    }
+
+    /**
+     * End first or second animator if they are still running.
+     */
+    static void endAll(ValueAnimator first, ValueAnimator second) {
+        if (first.isStarted()) {
+            first.end();
+        } else if (second.isStarted()) {
+            second.end();
+        }
+    }
+
+    /**
+     * Fade in or fade out rows and background.
+     *
+     * @param show True to fade in, false to fade out.
+     * @param animation True to run animation.
+     */
+    void showControlsOverlay(boolean show, boolean animation) {
+        if (DEBUG) Log.v(TAG, "showControlsOverlay " + show);
+        if (getView() == null) {
+            mControlVisibleBeforeOnCreateView = show;
+            return;
+        }
+        // force no animation when fragment is not resumed
+        if (!isResumed()) {
+            animation = false;
+        }
+        if (show == mControlVisible) {
+            if (!animation) {
+                // End animation if needed
+                endAll(mBgFadeInAnimator, mBgFadeOutAnimator);
+                endAll(mControlRowFadeInAnimator, mControlRowFadeOutAnimator);
+                endAll(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator);
+            }
+            return;
+        }
+        // StateGraph: 7<->5 4<->3 2->3
+        mControlVisible = show;
+        if (!mControlVisible) {
+            // StateGraph 2->3
+            stopFadeTimer();
+        }
+
+        mAnimationTranslateY = (getVerticalGridView() == null
+                || getVerticalGridView().getSelectedPosition() == 0)
+                ? mMajorFadeTranslateY : mMinorFadeTranslateY;
+
+        if (show) {
+            reverseFirstOrStartSecond(mBgFadeOutAnimator, mBgFadeInAnimator, animation);
+            reverseFirstOrStartSecond(mControlRowFadeOutAnimator, mControlRowFadeInAnimator,
+                    animation);
+            reverseFirstOrStartSecond(mOtherRowFadeOutAnimator, mOtherRowFadeInAnimator, animation);
+        } else {
+            reverseFirstOrStartSecond(mBgFadeInAnimator, mBgFadeOutAnimator, animation);
+            reverseFirstOrStartSecond(mControlRowFadeInAnimator, mControlRowFadeOutAnimator,
+                    animation);
+            reverseFirstOrStartSecond(mOtherRowFadeInAnimator, mOtherRowFadeOutAnimator, animation);
+        }
+        if (animation) {
+            getView().announceForAccessibility(getString(show
+                    ? R.string.lb_playback_controls_shown
+                    : R.string.lb_playback_controls_hidden));
+        }
+    }
+
+    /**
+     * Sets the selected row position with smooth animation.
+     */
+    public void setSelectedPosition(int position) {
+        setSelectedPosition(position, true);
+    }
+
+    /**
+     * Sets the selected row position.
+     */
+    public void setSelectedPosition(int position, boolean smooth) {
+        mSetSelectionRunnable.mPosition = position;
+        mSetSelectionRunnable.mSmooth = smooth;
+        if (getView() != null && getView().getHandler() != null) {
+            getView().getHandler().post(mSetSelectionRunnable);
+        }
+    }
+
+    private void setupChildFragmentLayout() {
+        setVerticalGridViewLayout(mRowsSupportFragment.getVerticalGridView());
+    }
+
+    void setVerticalGridViewLayout(VerticalGridView listview) {
+        if (listview == null) {
+            return;
+        }
+
+        // we set the base line of alignment to -paddingBottom
+        listview.setWindowAlignmentOffset(-mPaddingBottom);
+        listview.setWindowAlignmentOffsetPercent(
+                VerticalGridView.WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
+
+        // align other rows that arent the last to center of screen, since our baseline is
+        // -mPaddingBottom, we need subtract that from mOtherRowsCenterToBottom.
+        listview.setItemAlignmentOffset(mOtherRowsCenterToBottom - mPaddingBottom);
+        listview.setItemAlignmentOffsetPercent(50);
+
+        // Push last row to the bottom padding
+        // Padding affects alignment when last row is focused
+        listview.setPadding(listview.getPaddingLeft(), listview.getPaddingTop(),
+                listview.getPaddingRight(), mPaddingBottom);
+        listview.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mOtherRowsCenterToBottom = getResources()
+                .getDimensionPixelSize(R.dimen.lb_playback_other_rows_center_to_bottom);
+        mPaddingBottom =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_controls_padding_bottom);
+        mBgDarkColor =
+                getResources().getColor(R.color.lb_playback_controls_background_dark);
+        mBgLightColor =
+                getResources().getColor(R.color.lb_playback_controls_background_light);
+        mShowTimeMs =
+                getResources().getInteger(R.integer.lb_playback_controls_show_time_ms);
+        mMajorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_major_fade_translate_y);
+        mMinorFadeTranslateY =
+                getResources().getDimensionPixelSize(R.dimen.lb_playback_minor_fade_translate_y);
+
+        loadBgAnimator();
+        loadControlRowAnimator();
+        loadOtherRowAnimator();
+    }
+
+    /**
+     * Sets the background type.
+     *
+     * @param type One of BG_LIGHT, BG_DARK, or BG_NONE.
+     */
+    public void setBackgroundType(int type) {
+        switch (type) {
+            case BG_LIGHT:
+            case BG_DARK:
+            case BG_NONE:
+                if (type != mBackgroundType) {
+                    mBackgroundType = type;
+                    updateBackground();
+                }
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid background type");
+        }
+    }
+
+    /**
+     * Returns the background type.
+     */
+    public int getBackgroundType() {
+        return mBackgroundType;
+    }
+
+    private void updateBackground() {
+        if (mBackgroundView != null) {
+            int color = mBgDarkColor;
+            switch (mBackgroundType) {
+                case BG_DARK:
+                    break;
+                case BG_LIGHT:
+                    color = mBgLightColor;
+                    break;
+                case BG_NONE:
+                    color = Color.TRANSPARENT;
+                    break;
+            }
+            mBackgroundView.setBackground(new ColorDrawable(color));
+            setBgAlpha(mBgAlpha);
+        }
+    }
+
+    private final ItemBridgeAdapter.AdapterListener mAdapterListener =
+            new ItemBridgeAdapter.AdapterListener() {
+                @Override
+                public void onAttachedToWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onAttachedToWindow " + vh.getViewHolder().view);
+                    if (!mControlVisible) {
+                        if (DEBUG) Log.v(TAG, "setting alpha to 0");
+                        vh.getViewHolder().view.setAlpha(0);
+                    }
+                }
+
+                @Override
+                public void onCreate(ItemBridgeAdapter.ViewHolder vh) {
+                    Presenter.ViewHolder viewHolder = vh.getViewHolder();
+                    if (viewHolder instanceof PlaybackSeekUi) {
+                        ((PlaybackSeekUi) viewHolder).setPlaybackSeekUiClient(mChainedClient);
+                    }
+                }
+
+                @Override
+                public void onDetachedFromWindow(ItemBridgeAdapter.ViewHolder vh) {
+                    if (DEBUG) Log.v(TAG, "onDetachedFromWindow " + vh.getViewHolder().view);
+                    // Reset animation state
+                    vh.getViewHolder().view.setAlpha(1f);
+                    vh.getViewHolder().view.setTranslationY(0);
+                    vh.getViewHolder().view.setAlpha(1f);
+                }
+
+                @Override
+                public void onBind(ItemBridgeAdapter.ViewHolder vh) {
+                }
+            };
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                             Bundle savedInstanceState) {
+        mRootView = inflater.inflate(R.layout.lb_playback_fragment, container, false);
+        mBackgroundView = mRootView.findViewById(R.id.playback_fragment_background);
+        mRowsSupportFragment = (RowsSupportFragment) getChildFragmentManager().findFragmentById(
+                R.id.playback_controls_dock);
+        if (mRowsSupportFragment == null) {
+            mRowsSupportFragment = new RowsSupportFragment();
+            getChildFragmentManager().beginTransaction()
+                    .replace(R.id.playback_controls_dock, mRowsSupportFragment)
+                    .commit();
+        }
+        if (mAdapter == null) {
+            setAdapter(new ArrayObjectAdapter(new ClassPresenterSelector()));
+        } else {
+            mRowsSupportFragment.setAdapter(mAdapter);
+        }
+        mRowsSupportFragment.setOnItemViewSelectedListener(mOnItemViewSelectedListener);
+        mRowsSupportFragment.setOnItemViewClickedListener(mOnItemViewClickedListener);
+
+        mBgAlpha = 255;
+        updateBackground();
+        mRowsSupportFragment.setExternalAdapterListener(mAdapterListener);
+        ProgressBarManager progressBarManager = getProgressBarManager();
+        if (progressBarManager != null) {
+            progressBarManager.setRootView((ViewGroup) mRootView);
+        }
+        return mRootView;
+    }
+
+    /**
+     * Sets the {@link PlaybackGlueHost.HostCallback}. Implementor of this interface will
+     * take appropriate actions to take action when the hosting fragment starts/stops processing.
+     */
+    public void setHostCallback(PlaybackGlueHost.HostCallback hostCallback) {
+        this.mHostCallback = hostCallback;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        setupChildFragmentLayout();
+        mRowsSupportFragment.setAdapter(mAdapter);
+        if (mHostCallback != null) {
+            mHostCallback.onHostStart();
+        }
+    }
+
+    @Override
+    public void onStop() {
+        if (mHostCallback != null) {
+            mHostCallback.onHostStop();
+        }
+        super.onStop();
+    }
+
+    @Override
+    public void onPause() {
+        if (mHostCallback != null) {
+            mHostCallback.onHostPause();
+        }
+        if (mHandler.hasMessages(START_FADE_OUT)) {
+            // StateGraph: 2->1
+            mHandler.removeMessages(START_FADE_OUT);
+        } else {
+            // StateGraph: 5->6, 7->6, 4->1, 3->1
+        }
+        super.onPause();
+    }
+
+    /**
+     * This listener is called every time there is a selection in {@link RowsSupportFragment}. This can
+     * be used by users to take additional actions such as animations.
+     */
+    public void setOnItemViewSelectedListener(final BaseOnItemViewSelectedListener listener) {
+        mExternalItemSelectedListener = listener;
+    }
+
+    /**
+     * This listener is called every time there is a click in {@link RowsSupportFragment}. This can
+     * be used by users to take additional actions such as animations.
+     */
+    public void setOnItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mExternalItemClickedListener = listener;
+    }
+
+    /**
+     * Sets the {@link BaseOnItemViewClickedListener} that would be invoked for clicks
+     * only on {@link android.support.v17.leanback.widget.PlaybackRowPresenter.ViewHolder}.
+     */
+    public void setOnPlaybackItemViewClickedListener(final BaseOnItemViewClickedListener listener) {
+        mPlaybackItemClickedListener = listener;
+    }
+
+    @Override
+    public void onDestroyView() {
+        mRootView = null;
+        mBackgroundView = null;
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mHostCallback != null) {
+            mHostCallback.onHostDestroy();
+        }
+        super.onDestroy();
+    }
+
+    /**
+     * Sets the playback row for the playback controls. The row will be set as first element
+     * of adapter if the adapter is {@link ArrayObjectAdapter} or {@link SparseArrayObjectAdapter}.
+     * @param row The row that represents the playback.
+     */
+    public void setPlaybackRow(Row row) {
+        this.mRow = row;
+        setupRow();
+        setupPresenter();
+    }
+
+    /**
+     * Sets the presenter for rendering the playback row set by {@link #setPlaybackRow(Row)}. If
+     * adapter does not set a {@link PresenterSelector}, {@link #setAdapter(ObjectAdapter)} will
+     * create a {@link ClassPresenterSelector} by default and map from the row object class to this
+     * {@link PlaybackRowPresenter}.
+     *
+     * @param  presenter Presenter used to render {@link #setPlaybackRow(Row)}.
+     */
+    public void setPlaybackRowPresenter(PlaybackRowPresenter presenter) {
+        this.mPresenter = presenter;
+        setupPresenter();
+        setPlaybackRowPresenterAlignment();
+    }
+
+    void setPlaybackRowPresenterAlignment() {
+        if (mAdapter != null && mAdapter.getPresenterSelector() != null) {
+            Presenter[] presenters = mAdapter.getPresenterSelector().getPresenters();
+            if (presenters != null) {
+                for (int i = 0; i < presenters.length; i++) {
+                    if (presenters[i] instanceof PlaybackRowPresenter
+                            && presenters[i].getFacet(ItemAlignmentFacet.class) == null) {
+                        ItemAlignmentFacet itemAlignment = new ItemAlignmentFacet();
+                        ItemAlignmentFacet.ItemAlignmentDef def =
+                                new ItemAlignmentFacet.ItemAlignmentDef();
+                        def.setItemAlignmentOffset(0);
+                        def.setItemAlignmentOffsetPercent(100);
+                        itemAlignment.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]
+                                {def});
+                        presenters[i].setFacet(ItemAlignmentFacet.class, itemAlignment);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Updates the ui when the row data changes.
+     */
+    public void notifyPlaybackRowChanged() {
+        if (mAdapter == null) {
+            return;
+        }
+        mAdapter.notifyItemRangeChanged(0, 1);
+    }
+
+    /**
+     * Sets the list of rows for the fragment. A default {@link ClassPresenterSelector} will be
+     * created if {@link ObjectAdapter#getPresenterSelector()} is null. if user provides
+     * {@link #setPlaybackRow(Row)} and {@link #setPlaybackRowPresenter(PlaybackRowPresenter)},
+     * the row and presenter will be set onto the adapter.
+     *
+     * @param adapter The adapter that contains related rows and optional playback row.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        setupRow();
+        setupPresenter();
+        setPlaybackRowPresenterAlignment();
+
+        if (mRowsSupportFragment != null) {
+            mRowsSupportFragment.setAdapter(adapter);
+        }
+    }
+
+    private void setupRow() {
+        if (mAdapter instanceof ArrayObjectAdapter && mRow != null) {
+            ArrayObjectAdapter adapter = ((ArrayObjectAdapter) mAdapter);
+            if (adapter.size() == 0) {
+                adapter.add(mRow);
+            } else {
+                adapter.replace(0, mRow);
+            }
+        } else if (mAdapter instanceof SparseArrayObjectAdapter && mRow != null) {
+            SparseArrayObjectAdapter adapter = ((SparseArrayObjectAdapter) mAdapter);
+            adapter.set(0, mRow);
+        }
+    }
+
+    private void setupPresenter() {
+        if (mAdapter != null && mRow != null && mPresenter != null) {
+            PresenterSelector selector = mAdapter.getPresenterSelector();
+            if (selector == null) {
+                selector = new ClassPresenterSelector();
+                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
+                mAdapter.setPresenterSelector(selector);
+            } else if (selector instanceof ClassPresenterSelector) {
+                ((ClassPresenterSelector) selector).addClassPresenter(mRow.getClass(), mPresenter);
+            }
+        }
+    }
+
+    final PlaybackSeekUi.Client mChainedClient = new PlaybackSeekUi.Client() {
+        @Override
+        public boolean isSeekEnabled() {
+            return mSeekUiClient == null ? false : mSeekUiClient.isSeekEnabled();
+        }
+
+        @Override
+        public void onSeekStarted() {
+            if (mSeekUiClient != null) {
+                mSeekUiClient.onSeekStarted();
+            }
+            setSeekMode(true);
+        }
+
+        @Override
+        public PlaybackSeekDataProvider getPlaybackSeekDataProvider() {
+            return mSeekUiClient == null ? null : mSeekUiClient.getPlaybackSeekDataProvider();
+        }
+
+        @Override
+        public void onSeekPositionChanged(long pos) {
+            if (mSeekUiClient != null) {
+                mSeekUiClient.onSeekPositionChanged(pos);
+            }
+        }
+
+        @Override
+        public void onSeekFinished(boolean cancelled) {
+            if (mSeekUiClient != null) {
+                mSeekUiClient.onSeekFinished(cancelled);
+            }
+            setSeekMode(false);
+        }
+    };
+
+    /**
+     * Interface to be implemented by UI widget to support PlaybackSeekUi.
+     */
+    public void setPlaybackSeekUiClient(PlaybackSeekUi.Client client) {
+        mSeekUiClient = client;
+    }
+
+    /**
+     * Show or hide other rows other than PlaybackRow.
+     * @param inSeek True to make other rows visible, false to make other rows invisible.
+     */
+    void setSeekMode(boolean inSeek) {
+        if (mInSeek == inSeek) {
+            return;
+        }
+        mInSeek = inSeek;
+        getVerticalGridView().setSelectedPosition(0);
+        if (mInSeek) {
+            stopFadeTimer();
+        }
+        // immediately fade in control row.
+        showControlsOverlay(true);
+        final int count = getVerticalGridView().getChildCount();
+        for (int i = 0; i < count; i++) {
+            View view = getVerticalGridView().getChildAt(i);
+            if (getVerticalGridView().getChildAdapterPosition(view) > 0) {
+                view.setVisibility(mInSeek ? View.INVISIBLE : View.VISIBLE);
+            }
+        }
+    }
+
+    /**
+     * Called when size of the video changes. App may override.
+     * @param videoWidth Intrinsic width of video
+     * @param videoHeight Intrinsic height of video
+     */
+    protected void onVideoSizeChanged(int videoWidth, int videoHeight) {
+    }
+
+    /**
+     * Called when media has start or stop buffering. App may override. The default initial state
+     * is not buffering.
+     * @param start True for buffering start, false otherwise.
+     */
+    protected void onBufferingStateChanged(boolean start) {
+        ProgressBarManager progressBarManager = getProgressBarManager();
+        if (progressBarManager != null) {
+            if (start) {
+                progressBarManager.show();
+            } else {
+                progressBarManager.hide();
+            }
+        }
+    }
+
+    /**
+     * Called when media has error. App may override.
+     * @param errorCode Optional error code for specific implementation.
+     * @param errorMessage Optional error message for specific implementation.
+     */
+    protected void onError(int errorCode, CharSequence errorMessage) {
+    }
+
+    /**
+     * Returns the ProgressBarManager that will show or hide progress bar in
+     * {@link #onBufferingStateChanged(boolean)}.
+     * @return The ProgressBarManager that will show or hide progress bar in
+     * {@link #onBufferingStateChanged(boolean)}.
+     */
+    public ProgressBarManager getProgressBarManager() {
+        return mProgressBarManager;
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java b/leanback/src/main/java/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
rename to leanback/src/main/java/android/support/v17/leanback/app/PlaybackSupportFragmentGlueHost.java
diff --git a/leanback/src/android/support/v17/leanback/app/ProgressBarManager.java b/leanback/src/main/java/android/support/v17/leanback/app/ProgressBarManager.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/ProgressBarManager.java
rename to leanback/src/main/java/android/support/v17/leanback/app/ProgressBarManager.java
diff --git a/leanback/src/android/support/v17/leanback/app/RowsFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/RowsFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/RowsFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/RowsFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/RowsSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/RowsSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/RowsSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/SearchFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/SearchFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/SearchFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/SearchFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/SearchSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/SearchSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/SearchSupportFragment.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/VerticalGridFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/VerticalGridFragment.java
new file mode 100644
index 0000000..b21e46c
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/VerticalGridFragment.java
@@ -0,0 +1,260 @@
+// CHECKSTYLE:OFF Generated code
+/* This file is auto-generated from VerticalGridSupportFragment.java.  DO NOT MODIFY. */
+
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.os.Bundle;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.util.StateMachine.State;
+import android.support.v17.leanback.widget.BrowseFrameLayout;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.OnChildLaidOutListener;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.VerticalGridPresenter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A fragment for creating leanback vertical grids.
+ *
+ * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
+ * an {@link ObjectAdapter}.
+ * @deprecated use {@link VerticalGridSupportFragment}
+ */
+@Deprecated
+public class VerticalGridFragment extends BaseFragment {
+    static final String TAG = "VerticalGF";
+    static final boolean DEBUG = false;
+
+    private ObjectAdapter mAdapter;
+    private VerticalGridPresenter mGridPresenter;
+    VerticalGridPresenter.ViewHolder mGridViewHolder;
+    OnItemViewSelectedListener mOnItemViewSelectedListener;
+    private OnItemViewClickedListener mOnItemViewClickedListener;
+    private Object mSceneAfterEntranceTransition;
+    private int mSelectedPosition = -1;
+
+    /**
+     * State to setEntranceTransitionState(false)
+     */
+    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
+        @Override
+        public void run() {
+            setEntranceTransitionState(false);
+        }
+    };
+
+    @Override
+    void createStateMachineStates() {
+        super.createStateMachineStates();
+        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
+    }
+
+    @Override
+    void createStateMachineTransitions() {
+        super.createStateMachineTransitions();
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
+                STATE_SET_ENTRANCE_START_STATE, EVT_ON_CREATEVIEW);
+    }
+
+    /**
+     * Sets the grid presenter.
+     */
+    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
+        if (gridPresenter == null) {
+            throw new IllegalArgumentException("Grid presenter may not be null");
+        }
+        mGridPresenter = gridPresenter;
+        mGridPresenter.setOnItemViewSelectedListener(mViewSelectedListener);
+        if (mOnItemViewClickedListener != null) {
+            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        }
+    }
+
+    /**
+     * Returns the grid presenter.
+     */
+    public VerticalGridPresenter getGridPresenter() {
+        return mGridPresenter;
+    }
+
+    /**
+     * Sets the object adapter for the fragment.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        updateAdapter();
+    }
+
+    /**
+     * Returns the object adapter.
+     */
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    final private OnItemViewSelectedListener mViewSelectedListener =
+            new OnItemViewSelectedListener() {
+        @Override
+        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                RowPresenter.ViewHolder rowViewHolder, Row row) {
+            int position = mGridViewHolder.getGridView().getSelectedPosition();
+            if (DEBUG) Log.v(TAG, "grid selected position " + position);
+            gridOnItemSelected(position);
+            if (mOnItemViewSelectedListener != null) {
+                mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
+                        rowViewHolder, row);
+            }
+        }
+    };
+
+    final private OnChildLaidOutListener mChildLaidOutListener =
+            new OnChildLaidOutListener() {
+        @Override
+        public void onChildLaidOut(ViewGroup parent, View view, int position, long id) {
+            if (position == 0) {
+                showOrHideTitle();
+            }
+        }
+    };
+
+    /**
+     * Sets an item selection listener.
+     */
+    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
+        mOnItemViewSelectedListener = listener;
+    }
+
+    void gridOnItemSelected(int position) {
+        if (position != mSelectedPosition) {
+            mSelectedPosition = position;
+            showOrHideTitle();
+        }
+    }
+
+    void showOrHideTitle() {
+        if (mGridViewHolder.getGridView().findViewHolderForAdapterPosition(mSelectedPosition)
+                == null) {
+            return;
+        }
+        if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(mSelectedPosition)) {
+            showTitle(true);
+        } else {
+            showTitle(false);
+        }
+    }
+
+    /**
+     * Sets an item clicked listener.
+     */
+    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+        mOnItemViewClickedListener = listener;
+        if (mGridPresenter != null) {
+            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        }
+    }
+
+    /**
+     * Returns the item clicked listener.
+     */
+    public OnItemViewClickedListener getOnItemViewClickedListener() {
+        return mOnItemViewClickedListener;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
+                container, false);
+        ViewGroup gridFrame = (ViewGroup) root.findViewById(R.id.grid_frame);
+        installTitleView(inflater, gridFrame, savedInstanceState);
+        getProgressBarManager().setRootView(root);
+
+        ViewGroup gridDock = (ViewGroup) root.findViewById(R.id.browse_grid_dock);
+        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
+        gridDock.addView(mGridViewHolder.view);
+        mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
+
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
+            @Override
+            public void run() {
+                setEntranceTransitionState(true);
+            }
+        });
+
+        updateAdapter();
+        return root;
+    }
+
+    private void setupFocusSearchListener() {
+        BrowseFrameLayout browseFrameLayout = (BrowseFrameLayout) getView().findViewById(
+                R.id.grid_frame);
+        browseFrameLayout.setOnFocusSearchListener(getTitleHelper().getOnFocusSearchListener());
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        setupFocusSearchListener();
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        mGridViewHolder = null;
+    }
+
+    /**
+     * Sets the selected item position.
+     */
+    public void setSelectedPosition(int position) {
+        mSelectedPosition = position;
+        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
+            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
+        }
+    }
+
+    private void updateAdapter() {
+        if (mGridViewHolder != null) {
+            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
+            if (mSelectedPosition != -1) {
+                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
+            }
+        }
+    }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(FragmentUtil.getContext(VerticalGridFragment.this),
+                R.transition.lb_vertical_grid_entrance_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    void setEntranceTransitionState(boolean afterTransition) {
+        mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
+    }
+}
diff --git a/leanback/src/main/java/android/support/v17/leanback/app/VerticalGridSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/VerticalGridSupportFragment.java
new file mode 100644
index 0000000..766344d
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/app/VerticalGridSupportFragment.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.app;
+
+import android.os.Bundle;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.util.StateMachine.State;
+import android.support.v17.leanback.widget.BrowseFrameLayout;
+import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.OnChildLaidOutListener;
+import android.support.v17.leanback.widget.OnItemViewClickedListener;
+import android.support.v17.leanback.widget.OnItemViewSelectedListener;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.Row;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.support.v17.leanback.widget.VerticalGridPresenter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A fragment for creating leanback vertical grids.
+ *
+ * <p>Renders a vertical grid of objects given a {@link VerticalGridPresenter} and
+ * an {@link ObjectAdapter}.
+ */
+public class VerticalGridSupportFragment extends BaseSupportFragment {
+    static final String TAG = "VerticalGF";
+    static final boolean DEBUG = false;
+
+    private ObjectAdapter mAdapter;
+    private VerticalGridPresenter mGridPresenter;
+    VerticalGridPresenter.ViewHolder mGridViewHolder;
+    OnItemViewSelectedListener mOnItemViewSelectedListener;
+    private OnItemViewClickedListener mOnItemViewClickedListener;
+    private Object mSceneAfterEntranceTransition;
+    private int mSelectedPosition = -1;
+
+    /**
+     * State to setEntranceTransitionState(false)
+     */
+    final State STATE_SET_ENTRANCE_START_STATE = new State("SET_ENTRANCE_START_STATE") {
+        @Override
+        public void run() {
+            setEntranceTransitionState(false);
+        }
+    };
+
+    @Override
+    void createStateMachineStates() {
+        super.createStateMachineStates();
+        mStateMachine.addState(STATE_SET_ENTRANCE_START_STATE);
+    }
+
+    @Override
+    void createStateMachineTransitions() {
+        super.createStateMachineTransitions();
+        mStateMachine.addTransition(STATE_ENTRANCE_ON_PREPARED,
+                STATE_SET_ENTRANCE_START_STATE, EVT_ON_CREATEVIEW);
+    }
+
+    /**
+     * Sets the grid presenter.
+     */
+    public void setGridPresenter(VerticalGridPresenter gridPresenter) {
+        if (gridPresenter == null) {
+            throw new IllegalArgumentException("Grid presenter may not be null");
+        }
+        mGridPresenter = gridPresenter;
+        mGridPresenter.setOnItemViewSelectedListener(mViewSelectedListener);
+        if (mOnItemViewClickedListener != null) {
+            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        }
+    }
+
+    /**
+     * Returns the grid presenter.
+     */
+    public VerticalGridPresenter getGridPresenter() {
+        return mGridPresenter;
+    }
+
+    /**
+     * Sets the object adapter for the fragment.
+     */
+    public void setAdapter(ObjectAdapter adapter) {
+        mAdapter = adapter;
+        updateAdapter();
+    }
+
+    /**
+     * Returns the object adapter.
+     */
+    public ObjectAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    final private OnItemViewSelectedListener mViewSelectedListener =
+            new OnItemViewSelectedListener() {
+        @Override
+        public void onItemSelected(Presenter.ViewHolder itemViewHolder, Object item,
+                RowPresenter.ViewHolder rowViewHolder, Row row) {
+            int position = mGridViewHolder.getGridView().getSelectedPosition();
+            if (DEBUG) Log.v(TAG, "grid selected position " + position);
+            gridOnItemSelected(position);
+            if (mOnItemViewSelectedListener != null) {
+                mOnItemViewSelectedListener.onItemSelected(itemViewHolder, item,
+                        rowViewHolder, row);
+            }
+        }
+    };
+
+    final private OnChildLaidOutListener mChildLaidOutListener =
+            new OnChildLaidOutListener() {
+        @Override
+        public void onChildLaidOut(ViewGroup parent, View view, int position, long id) {
+            if (position == 0) {
+                showOrHideTitle();
+            }
+        }
+    };
+
+    /**
+     * Sets an item selection listener.
+     */
+    public void setOnItemViewSelectedListener(OnItemViewSelectedListener listener) {
+        mOnItemViewSelectedListener = listener;
+    }
+
+    void gridOnItemSelected(int position) {
+        if (position != mSelectedPosition) {
+            mSelectedPosition = position;
+            showOrHideTitle();
+        }
+    }
+
+    void showOrHideTitle() {
+        if (mGridViewHolder.getGridView().findViewHolderForAdapterPosition(mSelectedPosition)
+                == null) {
+            return;
+        }
+        if (!mGridViewHolder.getGridView().hasPreviousViewInSameRow(mSelectedPosition)) {
+            showTitle(true);
+        } else {
+            showTitle(false);
+        }
+    }
+
+    /**
+     * Sets an item clicked listener.
+     */
+    public void setOnItemViewClickedListener(OnItemViewClickedListener listener) {
+        mOnItemViewClickedListener = listener;
+        if (mGridPresenter != null) {
+            mGridPresenter.setOnItemViewClickedListener(mOnItemViewClickedListener);
+        }
+    }
+
+    /**
+     * Returns the item clicked listener.
+     */
+    public OnItemViewClickedListener getOnItemViewClickedListener() {
+        return mOnItemViewClickedListener;
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        ViewGroup root = (ViewGroup) inflater.inflate(R.layout.lb_vertical_grid_fragment,
+                container, false);
+        ViewGroup gridFrame = (ViewGroup) root.findViewById(R.id.grid_frame);
+        installTitleView(inflater, gridFrame, savedInstanceState);
+        getProgressBarManager().setRootView(root);
+
+        ViewGroup gridDock = (ViewGroup) root.findViewById(R.id.browse_grid_dock);
+        mGridViewHolder = mGridPresenter.onCreateViewHolder(gridDock);
+        gridDock.addView(mGridViewHolder.view);
+        mGridViewHolder.getGridView().setOnChildLaidOutListener(mChildLaidOutListener);
+
+        mSceneAfterEntranceTransition = TransitionHelper.createScene(gridDock, new Runnable() {
+            @Override
+            public void run() {
+                setEntranceTransitionState(true);
+            }
+        });
+
+        updateAdapter();
+        return root;
+    }
+
+    private void setupFocusSearchListener() {
+        BrowseFrameLayout browseFrameLayout = (BrowseFrameLayout) getView().findViewById(
+                R.id.grid_frame);
+        browseFrameLayout.setOnFocusSearchListener(getTitleHelper().getOnFocusSearchListener());
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        setupFocusSearchListener();
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        mGridViewHolder = null;
+    }
+
+    /**
+     * Sets the selected item position.
+     */
+    public void setSelectedPosition(int position) {
+        mSelectedPosition = position;
+        if(mGridViewHolder != null && mGridViewHolder.getGridView().getAdapter() != null) {
+            mGridViewHolder.getGridView().setSelectedPositionSmooth(position);
+        }
+    }
+
+    private void updateAdapter() {
+        if (mGridViewHolder != null) {
+            mGridPresenter.onBindViewHolder(mGridViewHolder, mAdapter);
+            if (mSelectedPosition != -1) {
+                mGridViewHolder.getGridView().setSelectedPosition(mSelectedPosition);
+            }
+        }
+    }
+
+    @Override
+    protected Object createEntranceTransition() {
+        return TransitionHelper.loadTransition(getContext(),
+                R.transition.lb_vertical_grid_entrance_transition);
+    }
+
+    @Override
+    protected void runEntranceTransition(Object entranceTransition) {
+        TransitionHelper.runTransition(mSceneAfterEntranceTransition, entranceTransition);
+    }
+
+    void setEntranceTransitionState(boolean afterTransition) {
+        mGridPresenter.setEntranceTransitionState(mGridViewHolder, afterTransition);
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/app/VideoFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/VideoFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/VideoFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/VideoFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/VideoFragmentGlueHost.java b/leanback/src/main/java/android/support/v17/leanback/app/VideoFragmentGlueHost.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/VideoFragmentGlueHost.java
rename to leanback/src/main/java/android/support/v17/leanback/app/VideoFragmentGlueHost.java
diff --git a/leanback/src/android/support/v17/leanback/app/VideoSupportFragment.java b/leanback/src/main/java/android/support/v17/leanback/app/VideoSupportFragment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/VideoSupportFragment.java
rename to leanback/src/main/java/android/support/v17/leanback/app/VideoSupportFragment.java
diff --git a/leanback/src/android/support/v17/leanback/app/VideoSupportFragmentGlueHost.java b/leanback/src/main/java/android/support/v17/leanback/app/VideoSupportFragmentGlueHost.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/VideoSupportFragmentGlueHost.java
rename to leanback/src/main/java/android/support/v17/leanback/app/VideoSupportFragmentGlueHost.java
diff --git a/leanback/src/android/support/v17/leanback/app/package-info.java b/leanback/src/main/java/android/support/v17/leanback/app/package-info.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/app/package-info.java
rename to leanback/src/main/java/android/support/v17/leanback/app/package-info.java
diff --git a/leanback/src/android/support/v17/leanback/database/CursorMapper.java b/leanback/src/main/java/android/support/v17/leanback/database/CursorMapper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/database/CursorMapper.java
rename to leanback/src/main/java/android/support/v17/leanback/database/CursorMapper.java
diff --git a/leanback/src/android/support/v17/leanback/graphics/BoundsRule.java b/leanback/src/main/java/android/support/v17/leanback/graphics/BoundsRule.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/graphics/BoundsRule.java
rename to leanback/src/main/java/android/support/v17/leanback/graphics/BoundsRule.java
diff --git a/leanback/src/android/support/v17/leanback/graphics/ColorFilterCache.java b/leanback/src/main/java/android/support/v17/leanback/graphics/ColorFilterCache.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/graphics/ColorFilterCache.java
rename to leanback/src/main/java/android/support/v17/leanback/graphics/ColorFilterCache.java
diff --git a/leanback/src/android/support/v17/leanback/graphics/ColorFilterDimmer.java b/leanback/src/main/java/android/support/v17/leanback/graphics/ColorFilterDimmer.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/graphics/ColorFilterDimmer.java
rename to leanback/src/main/java/android/support/v17/leanback/graphics/ColorFilterDimmer.java
diff --git a/leanback/src/android/support/v17/leanback/graphics/ColorOverlayDimmer.java b/leanback/src/main/java/android/support/v17/leanback/graphics/ColorOverlayDimmer.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/graphics/ColorOverlayDimmer.java
rename to leanback/src/main/java/android/support/v17/leanback/graphics/ColorOverlayDimmer.java
diff --git a/leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java b/leanback/src/main/java/android/support/v17/leanback/graphics/CompositeDrawable.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/graphics/CompositeDrawable.java
rename to leanback/src/main/java/android/support/v17/leanback/graphics/CompositeDrawable.java
diff --git a/leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java b/leanback/src/main/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
rename to leanback/src/main/java/android/support/v17/leanback/graphics/FitWidthBitmapDrawable.java
diff --git a/leanback/src/android/support/v17/leanback/media/MediaControllerAdapter.java b/leanback/src/main/java/android/support/v17/leanback/media/MediaControllerAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/MediaControllerAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/media/MediaControllerAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/media/MediaControllerGlue.java b/leanback/src/main/java/android/support/v17/leanback/media/MediaControllerGlue.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/MediaControllerGlue.java
rename to leanback/src/main/java/android/support/v17/leanback/media/MediaControllerGlue.java
diff --git a/leanback/src/android/support/v17/leanback/media/MediaPlayerAdapter.java b/leanback/src/main/java/android/support/v17/leanback/media/MediaPlayerAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/MediaPlayerAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/media/MediaPlayerAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java b/leanback/src/main/java/android/support/v17/leanback/media/MediaPlayerGlue.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/MediaPlayerGlue.java
rename to leanback/src/main/java/android/support/v17/leanback/media/MediaPlayerGlue.java
diff --git a/leanback/src/android/support/v17/leanback/media/PlaybackBannerControlGlue.java b/leanback/src/main/java/android/support/v17/leanback/media/PlaybackBannerControlGlue.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/PlaybackBannerControlGlue.java
rename to leanback/src/main/java/android/support/v17/leanback/media/PlaybackBannerControlGlue.java
diff --git a/leanback/src/android/support/v17/leanback/media/PlaybackBaseControlGlue.java b/leanback/src/main/java/android/support/v17/leanback/media/PlaybackBaseControlGlue.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/PlaybackBaseControlGlue.java
rename to leanback/src/main/java/android/support/v17/leanback/media/PlaybackBaseControlGlue.java
diff --git a/leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java b/leanback/src/main/java/android/support/v17/leanback/media/PlaybackControlGlue.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/PlaybackControlGlue.java
rename to leanback/src/main/java/android/support/v17/leanback/media/PlaybackControlGlue.java
diff --git a/leanback/src/android/support/v17/leanback/media/PlaybackGlue.java b/leanback/src/main/java/android/support/v17/leanback/media/PlaybackGlue.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/PlaybackGlue.java
rename to leanback/src/main/java/android/support/v17/leanback/media/PlaybackGlue.java
diff --git a/leanback/src/android/support/v17/leanback/media/PlaybackGlueHost.java b/leanback/src/main/java/android/support/v17/leanback/media/PlaybackGlueHost.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/PlaybackGlueHost.java
rename to leanback/src/main/java/android/support/v17/leanback/media/PlaybackGlueHost.java
diff --git a/leanback/src/android/support/v17/leanback/media/PlaybackTransportControlGlue.java b/leanback/src/main/java/android/support/v17/leanback/media/PlaybackTransportControlGlue.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/PlaybackTransportControlGlue.java
rename to leanback/src/main/java/android/support/v17/leanback/media/PlaybackTransportControlGlue.java
diff --git a/leanback/src/android/support/v17/leanback/media/PlayerAdapter.java b/leanback/src/main/java/android/support/v17/leanback/media/PlayerAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/PlayerAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/media/PlayerAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/media/SurfaceHolderGlueHost.java b/leanback/src/main/java/android/support/v17/leanback/media/SurfaceHolderGlueHost.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/media/SurfaceHolderGlueHost.java
rename to leanback/src/main/java/android/support/v17/leanback/media/SurfaceHolderGlueHost.java
diff --git a/leanback/src/android/support/v17/leanback/package-info.java b/leanback/src/main/java/android/support/v17/leanback/package-info.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/package-info.java
rename to leanback/src/main/java/android/support/v17/leanback/package-info.java
diff --git a/leanback/src/android/support/v17/leanback/system/Settings.java b/leanback/src/main/java/android/support/v17/leanback/system/Settings.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/system/Settings.java
rename to leanback/src/main/java/android/support/v17/leanback/system/Settings.java
diff --git a/leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java b/leanback/src/main/java/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/transition/LeanbackTransitionHelper.java
diff --git a/leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java b/leanback/src/main/java/android/support/v17/leanback/transition/ParallaxTransition.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/transition/ParallaxTransition.java
rename to leanback/src/main/java/android/support/v17/leanback/transition/ParallaxTransition.java
diff --git a/leanback/src/android/support/v17/leanback/transition/TransitionHelper.java b/leanback/src/main/java/android/support/v17/leanback/transition/TransitionHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/transition/TransitionHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/transition/TransitionHelper.java
diff --git a/leanback/src/android/support/v17/leanback/util/MathUtil.java b/leanback/src/main/java/android/support/v17/leanback/util/MathUtil.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/util/MathUtil.java
rename to leanback/src/main/java/android/support/v17/leanback/util/MathUtil.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/util/StateMachine.java b/leanback/src/main/java/android/support/v17/leanback/util/StateMachine.java
new file mode 100644
index 0000000..af801d1
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/util/StateMachine.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.util;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * State: each State has incoming Transitions and outgoing Transitions.
+ * When {@link State#mBranchStart} is true, all the outgoing Transitions may be triggered, when
+ * {@link State#mBranchStart} is false, only first outgoing Transition will be triggered.
+ * When {@link State#mBranchEnd} is true, all the incoming Transitions must be triggered for the
+ * State to run. When {@link State#mBranchEnd} is false, only need one incoming Transition triggered
+ * for the State to run.
+ * Transition: three types:
+ * 1. Event based transition, transition will be triggered when {@link #fireEvent(Event)} is called.
+ * 2. Auto transition, transition will be triggered when {@link Transition#mFromState} is executed.
+ * 3. Condiitonal Auto transition, transition will be triggered when {@link Transition#mFromState}
+ * is executed and {@link Transition#mCondition} passes.
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public final class StateMachine {
+
+    static final boolean DEBUG = false;
+    static final String TAG = "StateMachine";
+
+    /**
+     * No request on the State
+     */
+    public static final int STATUS_ZERO = 0;
+
+    /**
+     * Has been executed
+     */
+    public static final int STATUS_INVOKED = 1;
+
+    /**
+     * Used in Transition
+     */
+    public static class Event {
+        final String mName;
+
+        public Event(String name) {
+            mName = name;
+        }
+    }
+
+    /**
+     * Used in transition
+     */
+    public static class Condition {
+        final String mName;
+
+        public Condition(String name) {
+            mName = name;
+        }
+
+        /**
+         * @return True if can proceed and mark the transition INVOKED
+         */
+        public boolean canProceed() {
+            return true;
+        }
+    }
+
+    static class Transition {
+        final State mFromState;
+        final State mToState;
+        final Event mEvent;
+        final Condition mCondition;
+        int mState = STATUS_ZERO;
+
+        Transition(State fromState, State toState, Event event) {
+            if (event == null) {
+                throw new IllegalArgumentException();
+            }
+            mFromState = fromState;
+            mToState = toState;
+            mEvent = event;
+            mCondition = null;
+        }
+
+        Transition(State fromState, State toState) {
+            mFromState = fromState;
+            mToState = toState;
+            mEvent = null;
+            mCondition = null;
+        }
+
+        Transition(State fromState, State toState, Condition condition) {
+            if (condition == null) {
+                throw new IllegalArgumentException();
+            }
+            mFromState = fromState;
+            mToState = toState;
+            mEvent = null;
+            mCondition = condition;
+        }
+
+        @Override
+        public String toString() {
+            String signalName;
+            if (mEvent != null) {
+                signalName = mEvent.mName;
+            } else if (mCondition != null) {
+                signalName = mCondition.mName;
+            } else {
+                signalName = "auto";
+            }
+            return "[" + mFromState.mName + " -> " + mToState.mName + " <"
+                    + signalName + ">]";
+        }
+    }
+
+    /**
+     * @see StateMachine
+     */
+    public static class State {
+
+        final String mName;
+        final boolean mBranchStart;
+        final boolean mBranchEnd;
+        int mStatus = STATUS_ZERO;
+        int mInvokedOutTransitions = 0;
+        ArrayList<Transition> mIncomings;
+        ArrayList<Transition> mOutgoings;
+
+        @Override
+        public String toString() {
+            return "[" + mName + " " + mStatus + "]";
+        }
+
+        /**
+         * Create a State which is not branch start and a branch end.
+         */
+        public State(String name) {
+            this(name, false, true);
+        }
+
+        /**
+         * Create a State
+         * @param branchStart True if can run all out going transitions or false execute the first
+         *                    out going transition.
+         * @param branchEnd True if wait all incoming transitions executed or false
+         *                              only need one of the transition executed.
+         */
+        public State(String name, boolean branchStart, boolean branchEnd) {
+            mName = name;
+            mBranchStart = branchStart;
+            mBranchEnd = branchEnd;
+        }
+
+        void addIncoming(Transition t) {
+            if (mIncomings == null) {
+                mIncomings = new ArrayList();
+            }
+            mIncomings.add(t);
+        }
+
+        void addOutgoing(Transition t) {
+            if (mOutgoings == null) {
+                mOutgoings = new ArrayList();
+            }
+            mOutgoings.add(t);
+        }
+
+        /**
+         * Run State, Subclass may override.
+         */
+        public void run() {
+        }
+
+        final boolean checkPreCondition() {
+            if (mIncomings == null) {
+                return true;
+            }
+            if (mBranchEnd) {
+                for (Transition t: mIncomings) {
+                    if (t.mState != STATUS_INVOKED) {
+                        return false;
+                    }
+                }
+                return true;
+            } else {
+                for (Transition t: mIncomings) {
+                    if (t.mState == STATUS_INVOKED) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        }
+
+        /**
+         * @return True if the State has been executed.
+         */
+        final boolean runIfNeeded() {
+            if (mStatus != STATUS_INVOKED) {
+                if (checkPreCondition()) {
+                    if (DEBUG) {
+                        Log.d(TAG, "execute " + this);
+                    }
+                    mStatus = STATUS_INVOKED;
+                    run();
+                    signalAutoTransitionsAfterRun();
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        final void signalAutoTransitionsAfterRun() {
+            if (mOutgoings != null) {
+                for (Transition t: mOutgoings) {
+                    if (t.mEvent == null) {
+                        if (t.mCondition == null || t.mCondition.canProceed()) {
+                            if (DEBUG) {
+                                Log.d(TAG, "signal " + t);
+                            }
+                            mInvokedOutTransitions++;
+                            t.mState = STATUS_INVOKED;
+                            if (!mBranchStart) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Get status, return one of {@link #STATUS_ZERO}, {@link #STATUS_INVOKED}.
+         * @return Status of the State.
+         */
+        public final int getStatus() {
+            return mStatus;
+        }
+    }
+
+    final ArrayList<State> mStates = new ArrayList<State>();
+    final ArrayList<State> mFinishedStates = new ArrayList();
+    final ArrayList<State> mUnfinishedStates = new ArrayList();
+
+    public StateMachine() {
+    }
+
+    /**
+     * Add a State to StateMachine, ignore if it is already added.
+     * @param state The state to add.
+     */
+    public void addState(State state) {
+        if (!mStates.contains(state)) {
+            mStates.add(state);
+        }
+    }
+
+    /**
+     * Add event-triggered transition between two states.
+     * @param fromState The from state.
+     * @param toState The to state.
+     * @param event The event that needed to perform the transition.
+     */
+    public void addTransition(State fromState, State toState, Event event) {
+        Transition transition = new Transition(fromState, toState, event);
+        toState.addIncoming(transition);
+        fromState.addOutgoing(transition);
+    }
+
+    /**
+     * Add a conditional auto transition between two states.
+     * @param fromState The from state.
+     * @param toState The to state.
+     */
+    public void addTransition(State fromState, State toState, Condition condition) {
+        Transition transition = new Transition(fromState, toState, condition);
+        toState.addIncoming(transition);
+        fromState.addOutgoing(transition);
+    }
+
+    /**
+     * Add an auto transition between two states.
+     * @param fromState The from state to add.
+     * @param toState The to state to add.
+     */
+    public void addTransition(State fromState, State toState) {
+        Transition transition = new Transition(fromState, toState);
+        toState.addIncoming(transition);
+        fromState.addOutgoing(transition);
+    }
+
+    /**
+     * Start the state machine.
+     */
+    public void start() {
+        if (DEBUG) {
+            Log.d(TAG, "start");
+        }
+        mUnfinishedStates.addAll(mStates);
+        runUnfinishedStates();
+    }
+
+    void runUnfinishedStates() {
+        boolean changed;
+        do {
+            changed = false;
+            for (int i = mUnfinishedStates.size() - 1; i >= 0; i--) {
+                State state = mUnfinishedStates.get(i);
+                if (state.runIfNeeded()) {
+                    mUnfinishedStates.remove(i);
+                    mFinishedStates.add(state);
+                    changed = true;
+                }
+            }
+        } while (changed);
+    }
+
+    /**
+     * Find outgoing Transitions of invoked State whose Event matches, mark the Transition invoked.
+     */
+    public void fireEvent(Event event) {
+        for (int i = 0; i < mFinishedStates.size(); i++) {
+            State state = mFinishedStates.get(i);
+            if (state.mOutgoings != null) {
+                if (!state.mBranchStart && state.mInvokedOutTransitions > 0) {
+                    continue;
+                }
+                for (Transition t : state.mOutgoings) {
+                    if (t.mState != STATUS_INVOKED && t.mEvent == event) {
+                        if (DEBUG) {
+                            Log.d(TAG, "signal " + t);
+                        }
+                        t.mState = STATUS_INVOKED;
+                        state.mInvokedOutTransitions++;
+                        if (!state.mBranchStart) {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        runUnfinishedStates();
+    }
+
+    /**
+     * Reset status to orignal status
+     */
+    public void reset() {
+        if (DEBUG) {
+            Log.d(TAG, "reset");
+        }
+        mUnfinishedStates.clear();
+        mFinishedStates.clear();
+        for (State state: mStates) {
+            state.mStatus = STATUS_ZERO;
+            state.mInvokedOutTransitions = 0;
+            if (state.mOutgoings != null) {
+                for (Transition t: state.mOutgoings) {
+                    t.mState = STATUS_ZERO;
+                }
+            }
+        }
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/AbstractDetailsDescriptionPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/AbstractMediaItemPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/Action.java b/leanback/src/main/java/android/support/v17/leanback/widget/Action.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/Action.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/Action.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java b/leanback/src/main/java/android/support/v17/leanback/widget/ActionPresenterSelector.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ActionPresenterSelector.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ActionPresenterSelector.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ArrayObjectAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/ArrayObjectAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ArrayObjectAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ArrayObjectAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/BackgroundHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/BackgroundHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/BackgroundHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/BackgroundHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/BaseCardView.java b/leanback/src/main/java/android/support/v17/leanback/widget/BaseCardView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/BaseCardView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/BaseCardView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/BaseGridView.java b/leanback/src/main/java/android/support/v17/leanback/widget/BaseGridView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/BaseGridView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/BaseGridView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/BaseOnItemViewClickedListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/BaseOnItemViewSelectedListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/BaseOnItemViewSelectedListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/BaseOnItemViewSelectedListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/BaseOnItemViewSelectedListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/BrowseFrameLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/BrowseFrameLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/BrowseFrameLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/BrowseFrameLayout.java
diff --git a/leanback/src/android/support/v17/leanback/widget/BrowseRowsFrameLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/BrowseRowsFrameLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/BrowseRowsFrameLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/BrowseRowsFrameLayout.java
diff --git a/leanback/src/android/support/v17/leanback/widget/CheckableImageView.java b/leanback/src/main/java/android/support/v17/leanback/widget/CheckableImageView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/CheckableImageView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/CheckableImageView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ClassPresenterSelector.java b/leanback/src/main/java/android/support/v17/leanback/widget/ClassPresenterSelector.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ClassPresenterSelector.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ClassPresenterSelector.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ControlBar.java b/leanback/src/main/java/android/support/v17/leanback/widget/ControlBar.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ControlBar.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ControlBar.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ControlBarPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/ControlBarPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ControlBarPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ControlBarPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java b/leanback/src/main/java/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ControlButtonPresenterSelector.java
diff --git a/leanback/src/android/support/v17/leanback/widget/CursorObjectAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/CursorObjectAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/CursorObjectAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/CursorObjectAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewLogoPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java b/leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewRow.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DetailsOverviewRow.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewRow.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewRowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DetailsOverviewSharedElementHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DetailsParallax.java b/leanback/src/main/java/android/support/v17/leanback/widget/DetailsParallax.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DetailsParallax.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DetailsParallax.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DetailsParallaxDrawable.java b/leanback/src/main/java/android/support/v17/leanback/widget/DetailsParallaxDrawable.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DetailsParallaxDrawable.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DetailsParallaxDrawable.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DiffCallback.java b/leanback/src/main/java/android/support/v17/leanback/widget/DiffCallback.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DiffCallback.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DiffCallback.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DividerPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/DividerPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DividerPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DividerPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/DividerRow.java b/leanback/src/main/java/android/support/v17/leanback/widget/DividerRow.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/DividerRow.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/DividerRow.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FacetProvider.java b/leanback/src/main/java/android/support/v17/leanback/widget/FacetProvider.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FacetProvider.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FacetProvider.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FacetProviderAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/FacetProviderAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FacetProviderAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FacetProviderAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FocusHighlight.java b/leanback/src/main/java/android/support/v17/leanback/widget/FocusHighlight.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FocusHighlight.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FocusHighlight.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FocusHighlightHandler.java b/leanback/src/main/java/android/support/v17/leanback/widget/FocusHighlightHandler.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FocusHighlightHandler.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FocusHighlightHandler.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/FocusHighlightHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FocusHighlightHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FocusHighlightHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/ForegroundHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ForegroundHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ForegroundHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java b/leanback/src/main/java/android/support/v17/leanback/widget/FragmentAnimationProvider.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FragmentAnimationProvider.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FragmentAnimationProvider.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FullWidthDetailsOverviewRowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/FullWidthDetailsOverviewSharedElementHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/Grid.java b/leanback/src/main/java/android/support/v17/leanback/widget/Grid.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/Grid.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/Grid.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/widget/GridLayoutManager.java b/leanback/src/main/java/android/support/v17/leanback/widget/GridLayoutManager.java
new file mode 100644
index 0000000..ac26494
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -0,0 +1,3833 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import static android.support.v7.widget.RecyclerView.HORIZONTAL;
+import static android.support.v7.widget.RecyclerView.NO_ID;
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static android.support.v7.widget.RecyclerView.VERTICAL;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.os.TraceCompat;
+import android.support.v4.util.CircularIntArray;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.support.v7.widget.LinearSmoothScroller;
+import android.support.v7.widget.OrientationHelper;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Recycler;
+import android.support.v7.widget.RecyclerView.State;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseIntArray;
+import android.view.FocusFinder;
+import android.view.Gravity;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.animation.AccelerateDecelerateInterpolator;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+final class GridLayoutManager extends RecyclerView.LayoutManager {
+
+    /*
+     * LayoutParams for {@link HorizontalGridView} and {@link VerticalGridView}.
+     * The class currently does two internal jobs:
+     * - Saves optical bounds insets.
+     * - Caches focus align view center.
+     */
+    final static class LayoutParams extends RecyclerView.LayoutParams {
+
+        // For placement
+        int mLeftInset;
+        int mTopInset;
+        int mRightInset;
+        int mBottomInset;
+
+        // For alignment
+        private int mAlignX;
+        private int mAlignY;
+        private int[] mAlignMultiple;
+        private ItemAlignmentFacet mAlignmentFacet;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(RecyclerView.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+        }
+
+        int getAlignX() {
+            return mAlignX;
+        }
+
+        int getAlignY() {
+            return mAlignY;
+        }
+
+        int getOpticalLeft(View view) {
+            return view.getLeft() + mLeftInset;
+        }
+
+        int getOpticalTop(View view) {
+            return view.getTop() + mTopInset;
+        }
+
+        int getOpticalRight(View view) {
+            return view.getRight() - mRightInset;
+        }
+
+        int getOpticalBottom(View view) {
+            return view.getBottom() - mBottomInset;
+        }
+
+        int getOpticalWidth(View view) {
+            return view.getWidth() - mLeftInset - mRightInset;
+        }
+
+        int getOpticalHeight(View view) {
+            return view.getHeight() - mTopInset - mBottomInset;
+        }
+
+        int getOpticalLeftInset() {
+            return mLeftInset;
+        }
+
+        int getOpticalRightInset() {
+            return mRightInset;
+        }
+
+        int getOpticalTopInset() {
+            return mTopInset;
+        }
+
+        int getOpticalBottomInset() {
+            return mBottomInset;
+        }
+
+        void setAlignX(int alignX) {
+            mAlignX = alignX;
+        }
+
+        void setAlignY(int alignY) {
+            mAlignY = alignY;
+        }
+
+        void setItemAlignmentFacet(ItemAlignmentFacet facet) {
+            mAlignmentFacet = facet;
+        }
+
+        ItemAlignmentFacet getItemAlignmentFacet() {
+            return mAlignmentFacet;
+        }
+
+        void calculateItemAlignments(int orientation, View view) {
+            ItemAlignmentFacet.ItemAlignmentDef[] defs = mAlignmentFacet.getAlignmentDefs();
+            if (mAlignMultiple == null || mAlignMultiple.length != defs.length) {
+                mAlignMultiple = new int[defs.length];
+            }
+            for (int i = 0; i < defs.length; i++) {
+                mAlignMultiple[i] = ItemAlignmentFacetHelper
+                        .getAlignmentPosition(view, defs[i], orientation);
+            }
+            if (orientation == HORIZONTAL) {
+                mAlignX = mAlignMultiple[0];
+            } else {
+                mAlignY = mAlignMultiple[0];
+            }
+        }
+
+        int[] getAlignMultiple() {
+            return mAlignMultiple;
+        }
+
+        void setOpticalInsets(int leftInset, int topInset, int rightInset, int bottomInset) {
+            mLeftInset = leftInset;
+            mTopInset = topInset;
+            mRightInset = rightInset;
+            mBottomInset = bottomInset;
+        }
+
+    }
+
+    /**
+     * Base class which scrolls to selected view in onStop().
+     */
+    abstract class GridLinearSmoothScroller extends LinearSmoothScroller {
+        GridLinearSmoothScroller() {
+            super(mBaseGridView.getContext());
+        }
+
+        @Override
+        protected void onStop() {
+            mFlag |= PF_IN_ONSTOP_SMOOTHSCROLLER;
+            try {
+                onStopInternal();
+            } finally {
+                mFlag &= ~PF_IN_ONSTOP_SMOOTHSCROLLER;
+            }
+        }
+
+        protected void onStopInternal() {
+            // onTargetFound() may not be called if we hit the "wall" first or get cancelled.
+            View targetView = findViewByPosition(getTargetPosition());
+            if (targetView == null) {
+                if (getTargetPosition() >= 0) {
+                    // if smooth scroller is stopped without target, immediately jumps
+                    // to the target position.
+                    scrollToSelection(getTargetPosition(), 0, false, 0);
+                }
+                super.onStop();
+                return;
+            }
+            if (mFocusPosition != getTargetPosition()) {
+                // This should not happen since we cropped value in startPositionSmoothScroller()
+                mFocusPosition = getTargetPosition();
+            }
+            if (hasFocus()) {
+                mFlag |= PF_IN_SELECTION;
+                targetView.requestFocus();
+                mFlag &= ~PF_IN_SELECTION;
+            }
+            dispatchChildSelected();
+            dispatchChildSelectedAndPositioned();
+            super.onStop();
+        }
+
+        @Override
+        protected int calculateTimeForScrolling(int dx) {
+            int ms = super.calculateTimeForScrolling(dx);
+            if (mWindowAlignment.mainAxis().getSize() > 0) {
+                float minMs = (float) MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN
+                        / mWindowAlignment.mainAxis().getSize() * dx;
+                if (ms < minMs) {
+                    ms = (int) minMs;
+                }
+            }
+            return ms;
+        }
+
+        @Override
+        protected void onTargetFound(View targetView,
+                RecyclerView.State state, Action action) {
+            if (getScrollPosition(targetView, null, sTwoInts)) {
+                int dx, dy;
+                if (mOrientation == HORIZONTAL) {
+                    dx = sTwoInts[0];
+                    dy = sTwoInts[1];
+                } else {
+                    dx = sTwoInts[1];
+                    dy = sTwoInts[0];
+                }
+                final int distance = (int) Math.sqrt(dx * dx + dy * dy);
+                final int time = calculateTimeForDeceleration(distance);
+                action.update(dx, dy, time, mDecelerateInterpolator);
+            }
+        }
+    }
+
+    /**
+     * The SmoothScroller that remembers pending DPAD keys and consume pending keys
+     * during scroll.
+     */
+    final class PendingMoveSmoothScroller extends GridLinearSmoothScroller {
+        // -2 is a target position that LinearSmoothScroller can never find until
+        // consumePendingMovesXXX() sets real targetPosition.
+        final static int TARGET_UNDEFINED = -2;
+        // whether the grid is staggered.
+        private final boolean mStaggeredGrid;
+        // Number of pending movements on primary direction, negative if PREV_ITEM.
+        private int mPendingMoves;
+
+        PendingMoveSmoothScroller(int initialPendingMoves, boolean staggeredGrid) {
+            mPendingMoves = initialPendingMoves;
+            mStaggeredGrid = staggeredGrid;
+            setTargetPosition(TARGET_UNDEFINED);
+        }
+
+        void increasePendingMoves() {
+            if (mPendingMoves < mMaxPendingMoves) {
+                mPendingMoves++;
+            }
+        }
+
+        void decreasePendingMoves() {
+            if (mPendingMoves > -mMaxPendingMoves) {
+                mPendingMoves--;
+            }
+        }
+
+        /**
+         * Called before laid out an item when non-staggered grid can handle pending movements
+         * by skipping "mNumRows" per movement;  staggered grid will have to wait the item
+         * has been laid out in consumePendingMovesAfterLayout().
+         */
+        void consumePendingMovesBeforeLayout() {
+            if (mStaggeredGrid || mPendingMoves == 0) {
+                return;
+            }
+            View newSelected = null;
+            int startPos = mPendingMoves > 0 ? mFocusPosition + mNumRows :
+                    mFocusPosition - mNumRows;
+            for (int pos = startPos; mPendingMoves != 0;
+                    pos = mPendingMoves > 0 ? pos + mNumRows: pos - mNumRows) {
+                View v = findViewByPosition(pos);
+                if (v == null) {
+                    break;
+                }
+                if (!canScrollTo(v)) {
+                    continue;
+                }
+                newSelected = v;
+                mFocusPosition = pos;
+                mSubFocusPosition = 0;
+                if (mPendingMoves > 0) {
+                    mPendingMoves--;
+                } else {
+                    mPendingMoves++;
+                }
+            }
+            if (newSelected != null && hasFocus()) {
+                mFlag |= PF_IN_SELECTION;
+                newSelected.requestFocus();
+                mFlag &= ~PF_IN_SELECTION;
+            }
+        }
+
+        /**
+         * Called after laid out an item.  Staggered grid should find view on same
+         * Row and consume pending movements.
+         */
+        void consumePendingMovesAfterLayout() {
+            if (mStaggeredGrid && mPendingMoves != 0) {
+                // consume pending moves, focus to item on the same row.
+                mPendingMoves = processSelectionMoves(true, mPendingMoves);
+            }
+            if (mPendingMoves == 0 || (mPendingMoves > 0 && hasCreatedLastItem())
+                    || (mPendingMoves < 0 && hasCreatedFirstItem())) {
+                setTargetPosition(mFocusPosition);
+                stop();
+            }
+        }
+
+        @Override
+        protected void updateActionForInterimTarget(Action action) {
+            if (mPendingMoves == 0) {
+                return;
+            }
+            super.updateActionForInterimTarget(action);
+        }
+
+        @Override
+        public PointF computeScrollVectorForPosition(int targetPosition) {
+            if (mPendingMoves == 0) {
+                return null;
+            }
+            int direction = ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
+                    ? mPendingMoves > 0 : mPendingMoves < 0)
+                    ? -1 : 1;
+            if (mOrientation == HORIZONTAL) {
+                return new PointF(direction, 0);
+            } else {
+                return new PointF(0, direction);
+            }
+        }
+
+        @Override
+        protected void onStopInternal() {
+            super.onStopInternal();
+            // if we hit wall,  need clear the remaining pending moves.
+            mPendingMoves = 0;
+            mPendingMoveSmoothScroller = null;
+            View v = findViewByPosition(getTargetPosition());
+            if (v != null) scrollToView(v, true);
+        }
+    };
+
+    private static final String TAG = "GridLayoutManager";
+    static final boolean DEBUG = false;
+    static final boolean TRACE = false;
+
+    // maximum pending movement in one direction.
+    static final int DEFAULT_MAX_PENDING_MOVES = 10;
+    int mMaxPendingMoves = DEFAULT_MAX_PENDING_MOVES;
+    // minimal milliseconds to scroll window size in major direction,  we put a cap to prevent the
+    // effect smooth scrolling too over to bind an item view then drag the item view back.
+    final static int MIN_MS_SMOOTH_SCROLL_MAIN_SCREEN = 30;
+
+    String getTag() {
+        return TAG + ":" + mBaseGridView.getId();
+    }
+
+    final BaseGridView mBaseGridView;
+
+    /**
+     * Note on conventions in the presence of RTL layout directions:
+     * Many properties and method names reference entities related to the
+     * beginnings and ends of things.  In the presence of RTL flows,
+     * it may not be clear whether this is intended to reference a
+     * quantity that changes direction in RTL cases, or a quantity that
+     * does not.  Here are the conventions in use:
+     *
+     * start/end: coordinate quantities - do reverse
+     * (optical) left/right: coordinate quantities - do not reverse
+     * low/high: coordinate quantities - do not reverse
+     * min/max: coordinate quantities - do not reverse
+     * scroll offset - coordinate quantities - do not reverse
+     * first/last: positional indices - do not reverse
+     * front/end: positional indices - do not reverse
+     * prepend/append: related to positional indices - do not reverse
+     *
+     * Note that although quantities do not reverse in RTL flows, their
+     * relationship does.  In LTR flows, the first positional index is
+     * leftmost; in RTL flows, it is rightmost.  Thus, anywhere that
+     * positional quantities are mapped onto coordinate quantities,
+     * the flow must be checked and the logic reversed.
+     */
+
+    /**
+     * The orientation of a "row".
+     */
+    @RecyclerView.Orientation
+    int mOrientation = HORIZONTAL;
+    private OrientationHelper mOrientationHelper = OrientationHelper.createHorizontalHelper(this);
+
+    RecyclerView.State mState;
+    // Suppose currently showing 4, 5, 6, 7; removing 2,3,4 will make the layoutPosition to be
+    // 2(deleted), 3, 4, 5 in prelayout pass. So when we add item in prelayout, we must subtract 2
+    // from index of Grid.createItem.
+    int mPositionDeltaInPreLayout;
+    // Extra layout space needs to fill in prelayout pass. Note we apply the extra space to both
+    // appends and prepends due to the fact leanback is doing mario scrolling: removing items to
+    // the left of focused item might need extra layout on the right.
+    int mExtraLayoutSpaceInPreLayout;
+    // mPositionToRowInPostLayout and mDisappearingPositions are temp variables in post layout.
+    final SparseIntArray mPositionToRowInPostLayout = new SparseIntArray();
+    int[] mDisappearingPositions;
+
+    RecyclerView.Recycler mRecycler;
+
+    private static final Rect sTempRect = new Rect();
+
+    // 2 bits mask is for 3 STAGEs: 0, PF_STAGE_LAYOUT or PF_STAGE_SCROLL.
+    static final int PF_STAGE_MASK = 0x3;
+    static final int PF_STAGE_LAYOUT = 0x1;
+    static final int PF_STAGE_SCROLL = 0x2;
+
+    // Flag for "in fast relayout", determined by layoutInit() result.
+    static final int PF_FAST_RELAYOUT = 1 << 2;
+
+    // Flag for the selected item being updated in fast relayout.
+    static final int PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION = 1 << 3;
+    /**
+     * During full layout pass, when GridView had focus: onLayoutChildren will
+     * skip non-focusable child and adjust mFocusPosition.
+     */
+    static final int PF_IN_LAYOUT_SEARCH_FOCUS = 1 << 4;
+
+    // flag to prevent reentry if it's already processing selection request.
+    static final int PF_IN_SELECTION = 1 << 5;
+
+    // Represents whether child views are temporarily sliding out
+    static final int PF_SLIDING = 1 << 6;
+    static final int PF_LAYOUT_EATEN_IN_SLIDING = 1 << 7;
+
+    /**
+     * Force a full layout under certain situations.  E.g. Rows change, jump to invisible child.
+     */
+    static final int PF_FORCE_FULL_LAYOUT = 1 << 8;
+
+    /**
+     * True if layout is enabled.
+     */
+    static final int PF_LAYOUT_ENABLED = 1 << 9;
+
+    /**
+     * Flag controlling whether the current/next layout should
+     * be updating the secondary size of rows.
+     */
+    static final int PF_ROW_SECONDARY_SIZE_REFRESH = 1 << 10;
+
+    /**
+     *  Allow DPAD key to navigate out at the front of the View (where position = 0),
+     *  default is false.
+     */
+    static final int PF_FOCUS_OUT_FRONT = 1 << 11;
+
+    /**
+     * Allow DPAD key to navigate out at the end of the view, default is false.
+     */
+    static final int PF_FOCUS_OUT_END = 1 << 12;
+
+    static final int PF_FOCUS_OUT_MASKS = PF_FOCUS_OUT_FRONT | PF_FOCUS_OUT_END;
+
+    /**
+     *  Allow DPAD key to navigate out of second axis.
+     *  default is true.
+     */
+    static final int PF_FOCUS_OUT_SIDE_START = 1 << 13;
+
+    /**
+     * Allow DPAD key to navigate out of second axis.
+     */
+    static final int PF_FOCUS_OUT_SIDE_END = 1 << 14;
+
+    static final int PF_FOCUS_OUT_SIDE_MASKS = PF_FOCUS_OUT_SIDE_START | PF_FOCUS_OUT_SIDE_END;
+
+    /**
+     * True if focus search is disabled.
+     */
+    static final int PF_FOCUS_SEARCH_DISABLED = 1 << 15;
+
+    /**
+     * True if prune child,  might be disabled during transition.
+     */
+    static final int PF_PRUNE_CHILD = 1 << 16;
+
+    /**
+     * True if scroll content,  might be disabled during transition.
+     */
+    static final int PF_SCROLL_ENABLED = 1 << 17;
+
+    /**
+     * Set to true for RTL layout in horizontal orientation
+     */
+    static final int PF_REVERSE_FLOW_PRIMARY = 1 << 18;
+
+    /**
+     * Set to true for RTL layout in vertical orientation
+     */
+    static final int PF_REVERSE_FLOW_SECONDARY = 1 << 19;
+
+    static final int PF_REVERSE_FLOW_MASK = PF_REVERSE_FLOW_PRIMARY | PF_REVERSE_FLOW_SECONDARY;
+
+    /**
+     * flag to prevent calling stop() in onStop() which will lead to stack overflow crash
+     * TODO: fix RecyclerView.SmoothScroller#stop() instead
+     */
+    static final int PF_IN_ONSTOP_SMOOTHSCROLLER = 1 << 20;
+
+    int mFlag = PF_LAYOUT_ENABLED
+            | PF_FOCUS_OUT_SIDE_START | PF_FOCUS_OUT_SIDE_END
+            | PF_PRUNE_CHILD | PF_SCROLL_ENABLED;
+
+    private OnChildSelectedListener mChildSelectedListener = null;
+
+    private ArrayList<OnChildViewHolderSelectedListener> mChildViewHolderSelectedListeners = null;
+
+    OnChildLaidOutListener mChildLaidOutListener = null;
+
+    /**
+     * The focused position, it's not the currently visually aligned position
+     * but it is the final position that we intend to focus on. If there are
+     * multiple setSelection() called, mFocusPosition saves last value.
+     */
+    int mFocusPosition = NO_POSITION;
+
+    /**
+     * A view can have multiple alignment position,  this is the index of which
+     * alignment is used,  by default is 0.
+     */
+    int mSubFocusPosition = 0;
+
+    /**
+     * LinearSmoothScroller that consume pending DPAD movements.
+     */
+    PendingMoveSmoothScroller mPendingMoveSmoothScroller;
+
+    /**
+     * The offset to be applied to mFocusPosition, due to adapter change, on the next
+     * layout.  Set to Integer.MIN_VALUE means we should stop adding delta to mFocusPosition
+     * until next layout cycler.
+     * TODO:  This is somewhat duplication of RecyclerView getOldPosition() which is
+     * unfortunately cleared after prelayout.
+     */
+    private int mFocusPositionOffset = 0;
+
+    /**
+     * Extra pixels applied on primary direction.
+     */
+    private int mPrimaryScrollExtra;
+
+    /**
+     * override child visibility
+     */
+    @Visibility
+    int mChildVisibility;
+
+    /**
+     * Pixels that scrolled in secondary forward direction. Negative value means backward.
+     * Note that we treat secondary differently than main. For the main axis, update scroll min/max
+     * based on first/last item's view location. For second axis, we don't use item's view location.
+     * We are using the {@link #getRowSizeSecondary(int)} plus mScrollOffsetSecondary. see
+     * details in {@link #updateSecondaryScrollLimits()}.
+     */
+    int mScrollOffsetSecondary;
+
+    /**
+     * User-specified row height/column width.  Can be WRAP_CONTENT.
+     */
+    private int mRowSizeSecondaryRequested;
+
+    /**
+     * The fixed size of each grid item in the secondary direction. This corresponds to
+     * the row height, equal for all rows. Grid items may have variable length
+     * in the primary direction.
+     */
+    private int mFixedRowSizeSecondary;
+
+    /**
+     * Tracks the secondary size of each row.
+     */
+    private int[] mRowSizeSecondary;
+
+    /**
+     * The maximum measured size of the view.
+     */
+    private int mMaxSizeSecondary;
+
+    /**
+     * Margin between items.
+     */
+    private int mHorizontalSpacing;
+    /**
+     * Margin between items vertically.
+     */
+    private int mVerticalSpacing;
+    /**
+     * Margin in main direction.
+     */
+    private int mSpacingPrimary;
+    /**
+     * Margin in second direction.
+     */
+    private int mSpacingSecondary;
+    /**
+     * How to position child in secondary direction.
+     */
+    private int mGravity = Gravity.START | Gravity.TOP;
+    /**
+     * The number of rows in the grid.
+     */
+    int mNumRows;
+    /**
+     * Number of rows requested, can be 0 to be determined by parent size and
+     * rowHeight.
+     */
+    private int mNumRowsRequested = 1;
+
+    /**
+     * Saves grid information of each view.
+     */
+    Grid mGrid;
+
+    /**
+     * Focus Scroll strategy.
+     */
+    private int mFocusScrollStrategy = BaseGridView.FOCUS_SCROLL_ALIGNED;
+    /**
+     * Defines how item view is aligned in the window.
+     */
+    final WindowAlignment mWindowAlignment = new WindowAlignment();
+
+    /**
+     * Defines how item view is aligned.
+     */
+    private final ItemAlignment mItemAlignment = new ItemAlignment();
+
+    /**
+     * Dimensions of the view, width or height depending on orientation.
+     */
+    private int mSizePrimary;
+
+    /**
+     * Pixels of extra space for layout item (outside the widget)
+     */
+    private int mExtraLayoutSpace;
+
+    /**
+     * Temporary variable: an int array of length=2.
+     */
+    static int[] sTwoInts = new int[2];
+
+    /**
+     * Temporaries used for measuring.
+     */
+    private int[] mMeasuredDimension = new int[2];
+
+    final ViewsStateBundle mChildrenStates = new ViewsStateBundle();
+
+    /**
+     * Optional interface implemented by Adapter.
+     */
+    private FacetProviderAdapter mFacetProviderAdapter;
+
+    public GridLayoutManager(BaseGridView baseGridView) {
+        mBaseGridView = baseGridView;
+        mChildVisibility = -1;
+        // disable prefetch by default, prefetch causes regression on low power chipset
+        setItemPrefetchEnabled(false);
+    }
+
+    public void setOrientation(@RecyclerView.Orientation int orientation) {
+        if (orientation != HORIZONTAL && orientation != VERTICAL) {
+            if (DEBUG) Log.v(getTag(), "invalid orientation: " + orientation);
+            return;
+        }
+
+        mOrientation = orientation;
+        mOrientationHelper = OrientationHelper.createOrientationHelper(this, mOrientation);
+        mWindowAlignment.setOrientation(orientation);
+        mItemAlignment.setOrientation(orientation);
+        mFlag |= PF_FORCE_FULL_LAYOUT;
+    }
+
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        final int flags;
+        if (mOrientation == HORIZONTAL) {
+            flags = layoutDirection == View.LAYOUT_DIRECTION_RTL ? PF_REVERSE_FLOW_PRIMARY : 0;
+        } else {
+            flags = layoutDirection == View.LAYOUT_DIRECTION_RTL ? PF_REVERSE_FLOW_SECONDARY : 0;
+        }
+        if ((mFlag & PF_REVERSE_FLOW_MASK) == flags) {
+            return;
+        }
+        mFlag = (mFlag & ~PF_REVERSE_FLOW_MASK) | flags;
+        mFlag |= PF_FORCE_FULL_LAYOUT;
+        mWindowAlignment.horizontal.setReversedFlow(layoutDirection == View.LAYOUT_DIRECTION_RTL);
+    }
+
+    public int getFocusScrollStrategy() {
+        return mFocusScrollStrategy;
+    }
+
+    public void setFocusScrollStrategy(int focusScrollStrategy) {
+        mFocusScrollStrategy = focusScrollStrategy;
+    }
+
+    public void setWindowAlignment(int windowAlignment) {
+        mWindowAlignment.mainAxis().setWindowAlignment(windowAlignment);
+    }
+
+    public int getWindowAlignment() {
+        return mWindowAlignment.mainAxis().getWindowAlignment();
+    }
+
+    public void setWindowAlignmentOffset(int alignmentOffset) {
+        mWindowAlignment.mainAxis().setWindowAlignmentOffset(alignmentOffset);
+    }
+
+    public int getWindowAlignmentOffset() {
+        return mWindowAlignment.mainAxis().getWindowAlignmentOffset();
+    }
+
+    public void setWindowAlignmentOffsetPercent(float offsetPercent) {
+        mWindowAlignment.mainAxis().setWindowAlignmentOffsetPercent(offsetPercent);
+    }
+
+    public float getWindowAlignmentOffsetPercent() {
+        return mWindowAlignment.mainAxis().getWindowAlignmentOffsetPercent();
+    }
+
+    public void setItemAlignmentOffset(int alignmentOffset) {
+        mItemAlignment.mainAxis().setItemAlignmentOffset(alignmentOffset);
+        updateChildAlignments();
+    }
+
+    public int getItemAlignmentOffset() {
+        return mItemAlignment.mainAxis().getItemAlignmentOffset();
+    }
+
+    public void setItemAlignmentOffsetWithPadding(boolean withPadding) {
+        mItemAlignment.mainAxis().setItemAlignmentOffsetWithPadding(withPadding);
+        updateChildAlignments();
+    }
+
+    public boolean isItemAlignmentOffsetWithPadding() {
+        return mItemAlignment.mainAxis().isItemAlignmentOffsetWithPadding();
+    }
+
+    public void setItemAlignmentOffsetPercent(float offsetPercent) {
+        mItemAlignment.mainAxis().setItemAlignmentOffsetPercent(offsetPercent);
+        updateChildAlignments();
+    }
+
+    public float getItemAlignmentOffsetPercent() {
+        return mItemAlignment.mainAxis().getItemAlignmentOffsetPercent();
+    }
+
+    public void setItemAlignmentViewId(int viewId) {
+        mItemAlignment.mainAxis().setItemAlignmentViewId(viewId);
+        updateChildAlignments();
+    }
+
+    public int getItemAlignmentViewId() {
+        return mItemAlignment.mainAxis().getItemAlignmentViewId();
+    }
+
+    public void setFocusOutAllowed(boolean throughFront, boolean throughEnd) {
+        mFlag = (mFlag & ~PF_FOCUS_OUT_MASKS)
+                | (throughFront ? PF_FOCUS_OUT_FRONT : 0)
+                | (throughEnd ? PF_FOCUS_OUT_END : 0);
+    }
+
+    public void setFocusOutSideAllowed(boolean throughStart, boolean throughEnd) {
+        mFlag = (mFlag & ~PF_FOCUS_OUT_SIDE_MASKS)
+                | (throughStart ? PF_FOCUS_OUT_SIDE_START : 0)
+                | (throughEnd ? PF_FOCUS_OUT_SIDE_END : 0);
+    }
+
+    public void setNumRows(int numRows) {
+        if (numRows < 0) throw new IllegalArgumentException();
+        mNumRowsRequested = numRows;
+    }
+
+    /**
+     * Set the row height. May be WRAP_CONTENT, or a size in pixels.
+     */
+    public void setRowHeight(int height) {
+        if (height >= 0 || height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            mRowSizeSecondaryRequested = height;
+        } else {
+            throw new IllegalArgumentException("Invalid row height: " + height);
+        }
+    }
+
+    public void setItemSpacing(int space) {
+        mVerticalSpacing = mHorizontalSpacing = space;
+        mSpacingPrimary = mSpacingSecondary = space;
+    }
+
+    public void setVerticalSpacing(int space) {
+        if (mOrientation == VERTICAL) {
+            mSpacingPrimary = mVerticalSpacing = space;
+        } else {
+            mSpacingSecondary = mVerticalSpacing = space;
+        }
+    }
+
+    public void setHorizontalSpacing(int space) {
+        if (mOrientation == HORIZONTAL) {
+            mSpacingPrimary = mHorizontalSpacing = space;
+        } else {
+            mSpacingSecondary = mHorizontalSpacing = space;
+        }
+    }
+
+    public int getVerticalSpacing() {
+        return mVerticalSpacing;
+    }
+
+    public int getHorizontalSpacing() {
+        return mHorizontalSpacing;
+    }
+
+    public void setGravity(int gravity) {
+        mGravity = gravity;
+    }
+
+    protected boolean hasDoneFirstLayout() {
+        return mGrid != null;
+    }
+
+    public void setOnChildSelectedListener(OnChildSelectedListener listener) {
+        mChildSelectedListener = listener;
+    }
+
+    public void setOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) {
+        if (listener == null) {
+            mChildViewHolderSelectedListeners = null;
+            return;
+        }
+        if (mChildViewHolderSelectedListeners == null) {
+            mChildViewHolderSelectedListeners = new ArrayList<OnChildViewHolderSelectedListener>();
+        } else {
+            mChildViewHolderSelectedListeners.clear();
+        }
+        mChildViewHolderSelectedListeners.add(listener);
+    }
+
+    public void addOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener listener) {
+        if (mChildViewHolderSelectedListeners == null) {
+            mChildViewHolderSelectedListeners = new ArrayList<OnChildViewHolderSelectedListener>();
+        }
+        mChildViewHolderSelectedListeners.add(listener);
+    }
+
+    public void removeOnChildViewHolderSelectedListener(OnChildViewHolderSelectedListener
+            listener) {
+        if (mChildViewHolderSelectedListeners != null) {
+            mChildViewHolderSelectedListeners.remove(listener);
+        }
+    }
+
+    boolean hasOnChildViewHolderSelectedListener() {
+        return mChildViewHolderSelectedListeners != null
+                && mChildViewHolderSelectedListeners.size() > 0;
+    }
+
+    void fireOnChildViewHolderSelected(RecyclerView parent, RecyclerView.ViewHolder child,
+            int position, int subposition) {
+        if (mChildViewHolderSelectedListeners == null) {
+            return;
+        }
+        for (int i = mChildViewHolderSelectedListeners.size() - 1; i >= 0 ; i--) {
+            mChildViewHolderSelectedListeners.get(i).onChildViewHolderSelected(parent, child,
+                    position, subposition);
+        }
+    }
+
+    void fireOnChildViewHolderSelectedAndPositioned(RecyclerView parent, RecyclerView.ViewHolder
+            child, int position, int subposition) {
+        if (mChildViewHolderSelectedListeners == null) {
+            return;
+        }
+        for (int i = mChildViewHolderSelectedListeners.size() - 1; i >= 0 ; i--) {
+            mChildViewHolderSelectedListeners.get(i).onChildViewHolderSelectedAndPositioned(parent,
+                    child, position, subposition);
+        }
+    }
+
+    void setOnChildLaidOutListener(OnChildLaidOutListener listener) {
+        mChildLaidOutListener = listener;
+    }
+
+    private int getAdapterPositionByView(View view) {
+        if (view == null) {
+            return NO_POSITION;
+        }
+        LayoutParams params = (LayoutParams) view.getLayoutParams();
+        if (params == null || params.isItemRemoved()) {
+            // when item is removed, the position value can be any value.
+            return NO_POSITION;
+        }
+        return params.getViewAdapterPosition();
+    }
+
+    int getSubPositionByView(View view, View childView) {
+        if (view == null || childView == null) {
+            return 0;
+        }
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        final ItemAlignmentFacet facet = lp.getItemAlignmentFacet();
+        if (facet != null) {
+            final ItemAlignmentFacet.ItemAlignmentDef[] defs = facet.getAlignmentDefs();
+            if (defs.length > 1) {
+                while (childView != view) {
+                    int id = childView.getId();
+                    if (id != View.NO_ID) {
+                        for (int i = 1; i < defs.length; i++) {
+                            if (defs[i].getItemAlignmentFocusViewId() == id) {
+                                return i;
+                            }
+                        }
+                    }
+                    childView = (View) childView.getParent();
+                }
+            }
+        }
+        return 0;
+    }
+
+    private int getAdapterPositionByIndex(int index) {
+        return getAdapterPositionByView(getChildAt(index));
+    }
+
+    void dispatchChildSelected() {
+        if (mChildSelectedListener == null && !hasOnChildViewHolderSelectedListener()) {
+            return;
+        }
+
+        if (TRACE) TraceCompat.beginSection("onChildSelected");
+        View view = mFocusPosition == NO_POSITION ? null : findViewByPosition(mFocusPosition);
+        if (view != null) {
+            RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(view);
+            if (mChildSelectedListener != null) {
+                mChildSelectedListener.onChildSelected(mBaseGridView, view, mFocusPosition,
+                        vh == null? NO_ID: vh.getItemId());
+            }
+            fireOnChildViewHolderSelected(mBaseGridView, vh, mFocusPosition, mSubFocusPosition);
+        } else {
+            if (mChildSelectedListener != null) {
+                mChildSelectedListener.onChildSelected(mBaseGridView, null, NO_POSITION, NO_ID);
+            }
+            fireOnChildViewHolderSelected(mBaseGridView, null, NO_POSITION, 0);
+        }
+        if (TRACE) TraceCompat.endSection();
+
+        // Children may request layout when a child selection event occurs (such as a change of
+        // padding on the current and previously selected rows).
+        // If in layout, a child requesting layout may have been laid out before the selection
+        // callback.
+        // If it was not, the child will be laid out after the selection callback.
+        // If so, the layout request will be honoured though the view system will emit a double-
+        // layout warning.
+        // If not in layout, we may be scrolling in which case the child layout request will be
+        // eaten by recyclerview.  Post a requestLayout.
+        if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT && !mBaseGridView.isLayoutRequested()) {
+            int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (getChildAt(i).isLayoutRequested()) {
+                    forceRequestLayout();
+                    break;
+                }
+            }
+        }
+    }
+
+    private void dispatchChildSelectedAndPositioned() {
+        if (!hasOnChildViewHolderSelectedListener()) {
+            return;
+        }
+
+        if (TRACE) TraceCompat.beginSection("onChildSelectedAndPositioned");
+        View view = mFocusPosition == NO_POSITION ? null : findViewByPosition(mFocusPosition);
+        if (view != null) {
+            RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(view);
+            fireOnChildViewHolderSelectedAndPositioned(mBaseGridView, vh, mFocusPosition,
+                    mSubFocusPosition);
+        } else {
+            if (mChildSelectedListener != null) {
+                mChildSelectedListener.onChildSelected(mBaseGridView, null, NO_POSITION, NO_ID);
+            }
+            fireOnChildViewHolderSelectedAndPositioned(mBaseGridView, null, NO_POSITION, 0);
+        }
+        if (TRACE) TraceCompat.endSection();
+
+    }
+
+    @Override
+    public boolean canScrollHorizontally() {
+        // We can scroll horizontally if we have horizontal orientation, or if
+        // we are vertical and have more than one column.
+        return mOrientation == HORIZONTAL || mNumRows > 1;
+    }
+
+    @Override
+    public boolean canScrollVertically() {
+        // We can scroll vertically if we have vertical orientation, or if we
+        // are horizontal and have more than one row.
+        return mOrientation == VERTICAL || mNumRows > 1;
+    }
+
+    @Override
+    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    public RecyclerView.LayoutParams generateLayoutParams(Context context, AttributeSet attrs) {
+        return new LayoutParams(context, attrs);
+    }
+
+    @Override
+    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) lp);
+        } else if (lp instanceof RecyclerView.LayoutParams) {
+            return new LayoutParams((RecyclerView.LayoutParams) lp);
+        } else if (lp instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) lp);
+        } else {
+            return new LayoutParams(lp);
+        }
+    }
+
+    protected View getViewForPosition(int position) {
+        return mRecycler.getViewForPosition(position);
+    }
+
+    final int getOpticalLeft(View v) {
+        return ((LayoutParams) v.getLayoutParams()).getOpticalLeft(v);
+    }
+
+    final int getOpticalRight(View v) {
+        return ((LayoutParams) v.getLayoutParams()).getOpticalRight(v);
+    }
+
+    final int getOpticalTop(View v) {
+        return ((LayoutParams) v.getLayoutParams()).getOpticalTop(v);
+    }
+
+    final int getOpticalBottom(View v) {
+        return ((LayoutParams) v.getLayoutParams()).getOpticalBottom(v);
+    }
+
+    @Override
+    public int getDecoratedLeft(View child) {
+        return super.getDecoratedLeft(child) + ((LayoutParams) child.getLayoutParams()).mLeftInset;
+    }
+
+    @Override
+    public int getDecoratedTop(View child) {
+        return super.getDecoratedTop(child) + ((LayoutParams) child.getLayoutParams()).mTopInset;
+    }
+
+    @Override
+    public int getDecoratedRight(View child) {
+        return super.getDecoratedRight(child)
+                - ((LayoutParams) child.getLayoutParams()).mRightInset;
+    }
+
+    @Override
+    public int getDecoratedBottom(View child) {
+        return super.getDecoratedBottom(child)
+                - ((LayoutParams) child.getLayoutParams()).mBottomInset;
+    }
+
+    @Override
+    public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
+        super.getDecoratedBoundsWithMargins(view, outBounds);
+        LayoutParams params = ((LayoutParams) view.getLayoutParams());
+        outBounds.left += params.mLeftInset;
+        outBounds.top += params.mTopInset;
+        outBounds.right -= params.mRightInset;
+        outBounds.bottom -= params.mBottomInset;
+    }
+
+    int getViewMin(View v) {
+        return mOrientationHelper.getDecoratedStart(v);
+    }
+
+    int getViewMax(View v) {
+        return mOrientationHelper.getDecoratedEnd(v);
+    }
+
+    int getViewPrimarySize(View view) {
+        getDecoratedBoundsWithMargins(view, sTempRect);
+        return mOrientation == HORIZONTAL ? sTempRect.width() : sTempRect.height();
+    }
+
+    private int getViewCenter(View view) {
+        return (mOrientation == HORIZONTAL) ? getViewCenterX(view) : getViewCenterY(view);
+    }
+
+    private int getAdjustedViewCenter(View view) {
+        if (view.hasFocus()) {
+            View child = view.findFocus();
+            if (child != null && child != view) {
+                return getAdjustedPrimaryAlignedScrollDistance(getViewCenter(view), view, child);
+            }
+        }
+        return getViewCenter(view);
+    }
+
+    private int getViewCenterSecondary(View view) {
+        return (mOrientation == HORIZONTAL) ? getViewCenterY(view) : getViewCenterX(view);
+    }
+
+    private int getViewCenterX(View v) {
+        LayoutParams p = (LayoutParams) v.getLayoutParams();
+        return p.getOpticalLeft(v) + p.getAlignX();
+    }
+
+    private int getViewCenterY(View v) {
+        LayoutParams p = (LayoutParams) v.getLayoutParams();
+        return p.getOpticalTop(v) + p.getAlignY();
+    }
+
+    /**
+     * Save Recycler and State for convenience.  Must be paired with leaveContext().
+     */
+    private void saveContext(Recycler recycler, State state) {
+        if (mRecycler != null || mState != null) {
+            Log.e(TAG, "Recycler information was not released, bug!");
+        }
+        mRecycler = recycler;
+        mState = state;
+        mPositionDeltaInPreLayout = 0;
+        mExtraLayoutSpaceInPreLayout = 0;
+    }
+
+    /**
+     * Discard saved Recycler and State.
+     */
+    private void leaveContext() {
+        mRecycler = null;
+        mState = null;
+        mPositionDeltaInPreLayout = 0;
+        mExtraLayoutSpaceInPreLayout = 0;
+    }
+
+    /**
+     * Re-initialize data structures for a data change or handling invisible
+     * selection. The method tries its best to preserve position information so
+     * that staggered grid looks same before and after re-initialize.
+     * @return true if can fastRelayout()
+     */
+    private boolean layoutInit() {
+        final int newItemCount = mState.getItemCount();
+        if (newItemCount == 0) {
+            mFocusPosition = NO_POSITION;
+            mSubFocusPosition = 0;
+        } else if (mFocusPosition >= newItemCount) {
+            mFocusPosition = newItemCount - 1;
+            mSubFocusPosition = 0;
+        } else if (mFocusPosition == NO_POSITION && newItemCount > 0) {
+            // if focus position is never set before,  initialize it to 0
+            mFocusPosition = 0;
+            mSubFocusPosition = 0;
+        }
+        if (!mState.didStructureChange() && mGrid != null && mGrid.getFirstVisibleIndex() >= 0
+                && (mFlag & PF_FORCE_FULL_LAYOUT) == 0 && mGrid.getNumRows() == mNumRows) {
+            updateScrollController();
+            updateSecondaryScrollLimits();
+            mGrid.setSpacing(mSpacingPrimary);
+            return true;
+        } else {
+            mFlag &= ~PF_FORCE_FULL_LAYOUT;
+
+            if (mGrid == null || mNumRows != mGrid.getNumRows()
+                    || ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0) != mGrid.isReversedFlow()) {
+                mGrid = Grid.createGrid(mNumRows);
+                mGrid.setProvider(mGridProvider);
+                mGrid.setReversedFlow((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0);
+            }
+            initScrollController();
+            updateSecondaryScrollLimits();
+            mGrid.setSpacing(mSpacingPrimary);
+            detachAndScrapAttachedViews(mRecycler);
+            mGrid.resetVisibleIndex();
+            mWindowAlignment.mainAxis().invalidateScrollMin();
+            mWindowAlignment.mainAxis().invalidateScrollMax();
+            return false;
+        }
+    }
+
+    private int getRowSizeSecondary(int rowIndex) {
+        if (mFixedRowSizeSecondary != 0) {
+            return mFixedRowSizeSecondary;
+        }
+        if (mRowSizeSecondary == null) {
+            return 0;
+        }
+        return mRowSizeSecondary[rowIndex];
+    }
+
+    int getRowStartSecondary(int rowIndex) {
+        int start = 0;
+        // Iterate from left to right, which is a different index traversal
+        // in RTL flow
+        if ((mFlag & PF_REVERSE_FLOW_SECONDARY) != 0) {
+            for (int i = mNumRows-1; i > rowIndex; i--) {
+                start += getRowSizeSecondary(i) + mSpacingSecondary;
+            }
+        } else {
+            for (int i = 0; i < rowIndex; i++) {
+                start += getRowSizeSecondary(i) + mSpacingSecondary;
+            }
+        }
+        return start;
+    }
+
+    private int getSizeSecondary() {
+        int rightmostIndex = (mFlag & PF_REVERSE_FLOW_SECONDARY) != 0 ? 0 : mNumRows - 1;
+        return getRowStartSecondary(rightmostIndex) + getRowSizeSecondary(rightmostIndex);
+    }
+
+    int getDecoratedMeasuredWidthWithMargin(View v) {
+        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+        return getDecoratedMeasuredWidth(v) + lp.leftMargin + lp.rightMargin;
+    }
+
+    int getDecoratedMeasuredHeightWithMargin(View v) {
+        final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+        return getDecoratedMeasuredHeight(v) + lp.topMargin + lp.bottomMargin;
+    }
+
+    private void measureScrapChild(int position, int widthSpec, int heightSpec,
+            int[] measuredDimension) {
+        View view = mRecycler.getViewForPosition(position);
+        if (view != null) {
+            final LayoutParams p = (LayoutParams) view.getLayoutParams();
+            calculateItemDecorationsForChild(view, sTempRect);
+            int widthUsed = p.leftMargin + p.rightMargin + sTempRect.left + sTempRect.right;
+            int heightUsed = p.topMargin + p.bottomMargin + sTempRect.top + sTempRect.bottom;
+
+            int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
+                    getPaddingLeft() + getPaddingRight() + widthUsed, p.width);
+            int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
+                    getPaddingTop() + getPaddingBottom() + heightUsed, p.height);
+            view.measure(childWidthSpec, childHeightSpec);
+
+            measuredDimension[0] = getDecoratedMeasuredWidthWithMargin(view);
+            measuredDimension[1] = getDecoratedMeasuredHeightWithMargin(view);
+            mRecycler.recycleView(view);
+        }
+    }
+
+    private boolean processRowSizeSecondary(boolean measure) {
+        if (mFixedRowSizeSecondary != 0 || mRowSizeSecondary == null) {
+            return false;
+        }
+
+        if (TRACE) TraceCompat.beginSection("processRowSizeSecondary");
+        CircularIntArray[] rows = mGrid == null ? null : mGrid.getItemPositionsInRows();
+        boolean changed = false;
+        int scrapeChildSize = -1;
+
+        for (int rowIndex = 0; rowIndex < mNumRows; rowIndex++) {
+            CircularIntArray row = rows == null ? null : rows[rowIndex];
+            final int rowItemsPairCount = row == null ? 0 : row.size();
+            int rowSize = -1;
+            for (int rowItemPairIndex = 0; rowItemPairIndex < rowItemsPairCount;
+                    rowItemPairIndex += 2) {
+                final int rowIndexStart = row.get(rowItemPairIndex);
+                final int rowIndexEnd = row.get(rowItemPairIndex + 1);
+                for (int i = rowIndexStart; i <= rowIndexEnd; i++) {
+                    final View view = findViewByPosition(i - mPositionDeltaInPreLayout);
+                    if (view == null) {
+                        continue;
+                    }
+                    if (measure) {
+                        measureChild(view);
+                    }
+                    final int secondarySize = mOrientation == HORIZONTAL
+                            ? getDecoratedMeasuredHeightWithMargin(view)
+                            : getDecoratedMeasuredWidthWithMargin(view);
+                    if (secondarySize > rowSize) {
+                        rowSize = secondarySize;
+                    }
+                }
+            }
+
+            final int itemCount = mState.getItemCount();
+            if (!mBaseGridView.hasFixedSize() && measure && rowSize < 0 && itemCount > 0) {
+                if (scrapeChildSize < 0) {
+                    // measure a child that is close to mFocusPosition but not currently visible
+                    int position = mFocusPosition;
+                    if (position < 0) {
+                        position = 0;
+                    } else if (position >= itemCount) {
+                        position = itemCount - 1;
+                    }
+                    if (getChildCount() > 0) {
+                        int firstPos = mBaseGridView.getChildViewHolder(
+                                getChildAt(0)).getLayoutPosition();
+                        int lastPos = mBaseGridView.getChildViewHolder(
+                                getChildAt(getChildCount() - 1)).getLayoutPosition();
+                        // if mFocusPosition is between first and last, choose either
+                        // first - 1 or last + 1
+                        if (position >= firstPos && position <= lastPos) {
+                            position = (position - firstPos <= lastPos - position)
+                                    ? (firstPos - 1) : (lastPos + 1);
+                            // try the other value if the position is invalid. if both values are
+                            // invalid, skip measureScrapChild below.
+                            if (position < 0 && lastPos < itemCount - 1) {
+                                position = lastPos + 1;
+                            } else if (position >= itemCount && firstPos > 0) {
+                                position = firstPos - 1;
+                            }
+                        }
+                    }
+                    if (position >= 0 && position < itemCount) {
+                        measureScrapChild(position,
+                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+                                MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+                                mMeasuredDimension);
+                        scrapeChildSize = mOrientation == HORIZONTAL ? mMeasuredDimension[1] :
+                                mMeasuredDimension[0];
+                        if (DEBUG) {
+                            Log.v(TAG, "measured scrap child: " + mMeasuredDimension[0] + " "
+                                    + mMeasuredDimension[1]);
+                        }
+                    }
+                }
+                if (scrapeChildSize >= 0) {
+                    rowSize = scrapeChildSize;
+                }
+            }
+            if (rowSize < 0) {
+                rowSize = 0;
+            }
+            if (mRowSizeSecondary[rowIndex] != rowSize) {
+                if (DEBUG) {
+                    Log.v(getTag(), "row size secondary changed: " + mRowSizeSecondary[rowIndex]
+                            + ", " + rowSize);
+                }
+                mRowSizeSecondary[rowIndex] = rowSize;
+                changed = true;
+            }
+        }
+
+        if (TRACE) TraceCompat.endSection();
+        return changed;
+    }
+
+    /**
+     * Checks if we need to update row secondary sizes.
+     */
+    private void updateRowSecondarySizeRefresh() {
+        mFlag = (mFlag & ~PF_ROW_SECONDARY_SIZE_REFRESH)
+                | (processRowSizeSecondary(false) ? PF_ROW_SECONDARY_SIZE_REFRESH : 0);
+        if ((mFlag & PF_ROW_SECONDARY_SIZE_REFRESH) != 0) {
+            if (DEBUG) Log.v(getTag(), "mRowSecondarySizeRefresh now set");
+            forceRequestLayout();
+        }
+    }
+
+    private void forceRequestLayout() {
+        if (DEBUG) Log.v(getTag(), "forceRequestLayout");
+        // RecyclerView prevents us from requesting layout in many cases
+        // (during layout, during scroll, etc.)
+        // For secondary row size wrap_content support we currently need a
+        // second layout pass to update the measured size after having measured
+        // and added child views in layoutChildren.
+        // Force the second layout by posting a delayed runnable.
+        // TODO: investigate allowing a second layout pass,
+        // or move child add/measure logic to the measure phase.
+        ViewCompat.postOnAnimation(mBaseGridView, mRequestLayoutRunnable);
+    }
+
+    private final Runnable mRequestLayoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            if (DEBUG) Log.v(getTag(), "request Layout from runnable");
+            requestLayout();
+        }
+    };
+
+    @Override
+    public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) {
+        saveContext(recycler, state);
+
+        int sizePrimary, sizeSecondary, modeSecondary, paddingSecondary;
+        int measuredSizeSecondary;
+        if (mOrientation == HORIZONTAL) {
+            sizePrimary = MeasureSpec.getSize(widthSpec);
+            sizeSecondary = MeasureSpec.getSize(heightSpec);
+            modeSecondary = MeasureSpec.getMode(heightSpec);
+            paddingSecondary = getPaddingTop() + getPaddingBottom();
+        } else {
+            sizeSecondary = MeasureSpec.getSize(widthSpec);
+            sizePrimary = MeasureSpec.getSize(heightSpec);
+            modeSecondary = MeasureSpec.getMode(widthSpec);
+            paddingSecondary = getPaddingLeft() + getPaddingRight();
+        }
+        if (DEBUG) {
+            Log.v(getTag(), "onMeasure widthSpec " + Integer.toHexString(widthSpec)
+                    + " heightSpec " + Integer.toHexString(heightSpec)
+                    + " modeSecondary " + Integer.toHexString(modeSecondary)
+                    + " sizeSecondary " + sizeSecondary + " " + this);
+        }
+
+        mMaxSizeSecondary = sizeSecondary;
+
+        if (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT) {
+            mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
+            mFixedRowSizeSecondary = 0;
+
+            if (mRowSizeSecondary == null || mRowSizeSecondary.length != mNumRows) {
+                mRowSizeSecondary = new int[mNumRows];
+            }
+
+            if (mState.isPreLayout()) {
+                updatePositionDeltaInPreLayout();
+            }
+            // Measure all current children and update cached row height or column width
+            processRowSizeSecondary(true);
+
+            switch (modeSecondary) {
+                case MeasureSpec.UNSPECIFIED:
+                    measuredSizeSecondary = getSizeSecondary() + paddingSecondary;
+                    break;
+                case MeasureSpec.AT_MOST:
+                    measuredSizeSecondary = Math.min(getSizeSecondary() + paddingSecondary,
+                            mMaxSizeSecondary);
+                    break;
+                case MeasureSpec.EXACTLY:
+                    measuredSizeSecondary = mMaxSizeSecondary;
+                    break;
+                default:
+                    throw new IllegalStateException("wrong spec");
+            }
+
+        } else {
+            switch (modeSecondary) {
+                case MeasureSpec.UNSPECIFIED:
+                    mFixedRowSizeSecondary = mRowSizeSecondaryRequested == 0
+                            ? sizeSecondary - paddingSecondary : mRowSizeSecondaryRequested;
+                    mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
+                    measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mSpacingSecondary
+                            * (mNumRows - 1) + paddingSecondary;
+                    break;
+                case MeasureSpec.AT_MOST:
+                case MeasureSpec.EXACTLY:
+                    if (mNumRowsRequested == 0 && mRowSizeSecondaryRequested == 0) {
+                        mNumRows = 1;
+                        mFixedRowSizeSecondary = sizeSecondary - paddingSecondary;
+                    } else if (mNumRowsRequested == 0) {
+                        mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
+                        mNumRows = (sizeSecondary + mSpacingSecondary)
+                                / (mRowSizeSecondaryRequested + mSpacingSecondary);
+                    } else if (mRowSizeSecondaryRequested == 0) {
+                        mNumRows = mNumRowsRequested;
+                        mFixedRowSizeSecondary = (sizeSecondary - paddingSecondary
+                                - mSpacingSecondary * (mNumRows - 1)) / mNumRows;
+                    } else {
+                        mNumRows = mNumRowsRequested;
+                        mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
+                    }
+                    measuredSizeSecondary = sizeSecondary;
+                    if (modeSecondary == MeasureSpec.AT_MOST) {
+                        int childrenSize = mFixedRowSizeSecondary * mNumRows + mSpacingSecondary
+                                * (mNumRows - 1) + paddingSecondary;
+                        if (childrenSize < measuredSizeSecondary) {
+                            measuredSizeSecondary = childrenSize;
+                        }
+                    }
+                    break;
+                default:
+                    throw new IllegalStateException("wrong spec");
+            }
+        }
+        if (mOrientation == HORIZONTAL) {
+            setMeasuredDimension(sizePrimary, measuredSizeSecondary);
+        } else {
+            setMeasuredDimension(measuredSizeSecondary, sizePrimary);
+        }
+        if (DEBUG) {
+            Log.v(getTag(), "onMeasure sizePrimary " + sizePrimary
+                    + " measuredSizeSecondary " + measuredSizeSecondary
+                    + " mFixedRowSizeSecondary " + mFixedRowSizeSecondary
+                    + " mNumRows " + mNumRows);
+        }
+        leaveContext();
+    }
+
+    void measureChild(View child) {
+        if (TRACE) TraceCompat.beginSection("measureChild");
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        calculateItemDecorationsForChild(child, sTempRect);
+        int widthUsed = lp.leftMargin + lp.rightMargin + sTempRect.left + sTempRect.right;
+        int heightUsed = lp.topMargin + lp.bottomMargin + sTempRect.top + sTempRect.bottom;
+
+        final int secondarySpec =
+                (mRowSizeSecondaryRequested == ViewGroup.LayoutParams.WRAP_CONTENT)
+                        ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+                        : MeasureSpec.makeMeasureSpec(mFixedRowSizeSecondary, MeasureSpec.EXACTLY);
+        int widthSpec, heightSpec;
+
+        if (mOrientation == HORIZONTAL) {
+            widthSpec = ViewGroup.getChildMeasureSpec(
+                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), widthUsed, lp.width);
+            heightSpec = ViewGroup.getChildMeasureSpec(secondarySpec, heightUsed, lp.height);
+        } else {
+            heightSpec = ViewGroup.getChildMeasureSpec(
+                    MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), heightUsed, lp.height);
+            widthSpec = ViewGroup.getChildMeasureSpec(secondarySpec, widthUsed, lp.width);
+        }
+        child.measure(widthSpec, heightSpec);
+        if (DEBUG) {
+            Log.v(getTag(), "measureChild secondarySpec " + Integer.toHexString(secondarySpec)
+                    + " widthSpec " + Integer.toHexString(widthSpec)
+                    + " heightSpec " + Integer.toHexString(heightSpec)
+                    + " measuredWidth " + child.getMeasuredWidth()
+                    + " measuredHeight " + child.getMeasuredHeight());
+        }
+        if (DEBUG) Log.v(getTag(), "child lp width " + lp.width + " height " + lp.height);
+        if (TRACE) TraceCompat.endSection();
+    }
+
+    /**
+     * Get facet from the ViewHolder or the viewType.
+     */
+    <E> E getFacet(RecyclerView.ViewHolder vh, Class<? extends E> facetClass) {
+        E facet = null;
+        if (vh instanceof FacetProvider) {
+            facet = (E) ((FacetProvider) vh).getFacet(facetClass);
+        }
+        if (facet == null && mFacetProviderAdapter != null) {
+            FacetProvider p = mFacetProviderAdapter.getFacetProvider(vh.getItemViewType());
+            if (p != null) {
+                facet = (E) p.getFacet(facetClass);
+            }
+        }
+        return facet;
+    }
+
+    private Grid.Provider mGridProvider = new Grid.Provider() {
+
+        @Override
+        public int getMinIndex() {
+            return mPositionDeltaInPreLayout;
+        }
+
+        @Override
+        public int getCount() {
+            return mState.getItemCount() + mPositionDeltaInPreLayout;
+        }
+
+        @Override
+        public int createItem(int index, boolean append, Object[] item, boolean disappearingItem) {
+            if (TRACE) TraceCompat.beginSection("createItem");
+            if (TRACE) TraceCompat.beginSection("getview");
+            View v = getViewForPosition(index - mPositionDeltaInPreLayout);
+            if (TRACE) TraceCompat.endSection();
+            LayoutParams lp = (LayoutParams) v.getLayoutParams();
+            RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(v);
+            lp.setItemAlignmentFacet((ItemAlignmentFacet)getFacet(vh, ItemAlignmentFacet.class));
+            // See recyclerView docs:  we don't need re-add scraped view if it was removed.
+            if (!lp.isItemRemoved()) {
+                if (TRACE) TraceCompat.beginSection("addView");
+                if (disappearingItem) {
+                    if (append) {
+                        addDisappearingView(v);
+                    } else {
+                        addDisappearingView(v, 0);
+                    }
+                } else {
+                    if (append) {
+                        addView(v);
+                    } else {
+                        addView(v, 0);
+                    }
+                }
+                if (TRACE) TraceCompat.endSection();
+                if (mChildVisibility != -1) {
+                    v.setVisibility(mChildVisibility);
+                }
+
+                if (mPendingMoveSmoothScroller != null) {
+                    mPendingMoveSmoothScroller.consumePendingMovesBeforeLayout();
+                }
+                int subindex = getSubPositionByView(v, v.findFocus());
+                if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT) {
+                    // when we are appending item during scroll pass and the item's position
+                    // matches the mFocusPosition,  we should signal a childSelected event.
+                    // However if we are still running PendingMoveSmoothScroller,  we defer and
+                    // signal the event in PendingMoveSmoothScroller.onStop().  This can
+                    // avoid lots of childSelected events during a long smooth scrolling and
+                    // increase performance.
+                    if (index == mFocusPosition && subindex == mSubFocusPosition
+                            && mPendingMoveSmoothScroller == null) {
+                        dispatchChildSelected();
+                    }
+                } else if ((mFlag & PF_FAST_RELAYOUT) == 0) {
+                    // fastRelayout will dispatch event at end of onLayoutChildren().
+                    // For full layout, two situations here:
+                    // 1. mInLayoutSearchFocus is false, dispatchChildSelected() at mFocusPosition.
+                    // 2. mInLayoutSearchFocus is true:  dispatchChildSelected() on first child
+                    //    equal to or after mFocusPosition that can take focus.
+                    if ((mFlag & PF_IN_LAYOUT_SEARCH_FOCUS) == 0 && index == mFocusPosition
+                            && subindex == mSubFocusPosition) {
+                        dispatchChildSelected();
+                    } else if ((mFlag & PF_IN_LAYOUT_SEARCH_FOCUS) != 0 && index >= mFocusPosition
+                            && v.hasFocusable()) {
+                        mFocusPosition = index;
+                        mSubFocusPosition = subindex;
+                        mFlag &= ~PF_IN_LAYOUT_SEARCH_FOCUS;
+                        dispatchChildSelected();
+                    }
+                }
+                measureChild(v);
+            }
+            item[0] = v;
+            return mOrientation == HORIZONTAL ? getDecoratedMeasuredWidthWithMargin(v)
+                    : getDecoratedMeasuredHeightWithMargin(v);
+        }
+
+        @Override
+        public void addItem(Object item, int index, int length, int rowIndex, int edge) {
+            View v = (View) item;
+            int start, end;
+            if (edge == Integer.MIN_VALUE || edge == Integer.MAX_VALUE) {
+                edge = !mGrid.isReversedFlow() ? mWindowAlignment.mainAxis().getPaddingMin()
+                        : mWindowAlignment.mainAxis().getSize()
+                                - mWindowAlignment.mainAxis().getPaddingMax();
+            }
+            boolean edgeIsMin = !mGrid.isReversedFlow();
+            if (edgeIsMin) {
+                start = edge;
+                end = edge + length;
+            } else {
+                start = edge - length;
+                end = edge;
+            }
+            int startSecondary = getRowStartSecondary(rowIndex)
+                    + mWindowAlignment.secondAxis().getPaddingMin() - mScrollOffsetSecondary;
+            mChildrenStates.loadView(v, index);
+            layoutChild(rowIndex, v, start, end, startSecondary);
+            if (DEBUG) {
+                Log.d(getTag(), "addView " + index + " " + v);
+            }
+            if (TRACE) TraceCompat.endSection();
+
+            if (!mState.isPreLayout()) {
+                updateScrollLimits();
+            }
+            if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT && mPendingMoveSmoothScroller != null) {
+                mPendingMoveSmoothScroller.consumePendingMovesAfterLayout();
+            }
+            if (mChildLaidOutListener != null) {
+                RecyclerView.ViewHolder vh = mBaseGridView.getChildViewHolder(v);
+                mChildLaidOutListener.onChildLaidOut(mBaseGridView, v, index,
+                        vh == null ? NO_ID : vh.getItemId());
+            }
+        }
+
+        @Override
+        public void removeItem(int index) {
+            if (TRACE) TraceCompat.beginSection("removeItem");
+            View v = findViewByPosition(index - mPositionDeltaInPreLayout);
+            if ((mFlag & PF_STAGE_MASK) == PF_STAGE_LAYOUT) {
+                detachAndScrapView(v, mRecycler);
+            } else {
+                removeAndRecycleView(v, mRecycler);
+            }
+            if (TRACE) TraceCompat.endSection();
+        }
+
+        @Override
+        public int getEdge(int index) {
+            View v = findViewByPosition(index - mPositionDeltaInPreLayout);
+            return (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0 ? getViewMax(v) : getViewMin(v);
+        }
+
+        @Override
+        public int getSize(int index) {
+            return getViewPrimarySize(findViewByPosition(index - mPositionDeltaInPreLayout));
+        }
+    };
+
+    void layoutChild(int rowIndex, View v, int start, int end, int startSecondary) {
+        if (TRACE) TraceCompat.beginSection("layoutChild");
+        int sizeSecondary = mOrientation == HORIZONTAL ? getDecoratedMeasuredHeightWithMargin(v)
+                : getDecoratedMeasuredWidthWithMargin(v);
+        if (mFixedRowSizeSecondary > 0) {
+            sizeSecondary = Math.min(sizeSecondary, mFixedRowSizeSecondary);
+        }
+        final int verticalGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
+        final int horizontalGravity = (mFlag & PF_REVERSE_FLOW_MASK) != 0
+                ? 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)) {
+            // do nothing
+        } 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)) {
+            startSecondary += (getRowSizeSecondary(rowIndex) - sizeSecondary) / 2;
+        }
+        int left, top, right, bottom;
+        if (mOrientation == HORIZONTAL) {
+            left = start;
+            top = startSecondary;
+            right = end;
+            bottom = startSecondary + sizeSecondary;
+        } else {
+            top = start;
+            left = startSecondary;
+            bottom = end;
+            right = startSecondary + sizeSecondary;
+        }
+        LayoutParams params = (LayoutParams) v.getLayoutParams();
+        layoutDecoratedWithMargins(v, left, top, right, bottom);
+        // Now super.getDecoratedBoundsWithMargins() includes the extra space for optical bounds,
+        // subtracting it from value passed in layoutDecoratedWithMargins(), we can get the optical
+        // bounds insets.
+        super.getDecoratedBoundsWithMargins(v, sTempRect);
+        params.setOpticalInsets(left - sTempRect.left, top - sTempRect.top,
+                sTempRect.right - right, sTempRect.bottom - bottom);
+        updateChildAlignments(v);
+        if (TRACE) TraceCompat.endSection();
+    }
+
+    private void updateChildAlignments(View v) {
+        final LayoutParams p = (LayoutParams) v.getLayoutParams();
+        if (p.getItemAlignmentFacet() == null) {
+            // Fallback to global settings on grid view
+            p.setAlignX(mItemAlignment.horizontal.getAlignmentPosition(v));
+            p.setAlignY(mItemAlignment.vertical.getAlignmentPosition(v));
+        } else {
+            // Use ItemAlignmentFacet defined on specific ViewHolder
+            p.calculateItemAlignments(mOrientation, v);
+            if (mOrientation == HORIZONTAL) {
+                p.setAlignY(mItemAlignment.vertical.getAlignmentPosition(v));
+            } else {
+                p.setAlignX(mItemAlignment.horizontal.getAlignmentPosition(v));
+            }
+        }
+    }
+
+    private void updateChildAlignments() {
+        for (int i = 0, c = getChildCount(); i < c; i++) {
+            updateChildAlignments(getChildAt(i));
+        }
+    }
+
+    void setExtraLayoutSpace(int extraLayoutSpace) {
+        if (mExtraLayoutSpace == extraLayoutSpace) {
+            return;
+        } else if (mExtraLayoutSpace < 0) {
+            throw new IllegalArgumentException("ExtraLayoutSpace must >= 0");
+        }
+        mExtraLayoutSpace = extraLayoutSpace;
+        requestLayout();
+    }
+
+    int getExtraLayoutSpace() {
+        return mExtraLayoutSpace;
+    }
+
+    private void removeInvisibleViewsAtEnd() {
+        if ((mFlag & (PF_PRUNE_CHILD | PF_SLIDING)) == PF_PRUNE_CHILD) {
+            mGrid.removeInvisibleItemsAtEnd(mFocusPosition, (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
+                    ? -mExtraLayoutSpace : mSizePrimary + mExtraLayoutSpace);
+        }
+    }
+
+    private void removeInvisibleViewsAtFront() {
+        if ((mFlag & (PF_PRUNE_CHILD | PF_SLIDING)) == PF_PRUNE_CHILD) {
+            mGrid.removeInvisibleItemsAtFront(mFocusPosition, (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
+                    ? mSizePrimary + mExtraLayoutSpace : -mExtraLayoutSpace);
+        }
+    }
+
+    private boolean appendOneColumnVisibleItems() {
+        return mGrid.appendOneColumnVisibleItems();
+    }
+
+    void slideIn() {
+        if ((mFlag & PF_SLIDING) != 0) {
+            mFlag &= ~PF_SLIDING;
+            if (mFocusPosition >= 0) {
+                scrollToSelection(mFocusPosition, mSubFocusPosition, true, mPrimaryScrollExtra);
+            } else {
+                mFlag &= ~PF_LAYOUT_EATEN_IN_SLIDING;
+                requestLayout();
+            }
+            if ((mFlag & PF_LAYOUT_EATEN_IN_SLIDING) != 0) {
+                mFlag &= ~PF_LAYOUT_EATEN_IN_SLIDING;
+                if (mBaseGridView.getScrollState() != SCROLL_STATE_IDLE || isSmoothScrolling()) {
+                    mBaseGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+                        @Override
+                        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                            if (newState == SCROLL_STATE_IDLE) {
+                                mBaseGridView.removeOnScrollListener(this);
+                                requestLayout();
+                            }
+                        }
+                    });
+                } else {
+                    requestLayout();
+                }
+            }
+        }
+    }
+
+    int getSlideOutDistance() {
+        int distance;
+        if (mOrientation == VERTICAL) {
+            distance = -getHeight();
+            if (getChildCount() > 0) {
+                int top = getChildAt(0).getTop();
+                if (top < 0) {
+                    // scroll more if first child is above top edge
+                    distance = distance + top;
+                }
+            }
+        } else {
+            if ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0) {
+                distance = getWidth();
+                if (getChildCount() > 0) {
+                    int start = getChildAt(0).getRight();
+                    if (start > distance) {
+                        // scroll more if first child is outside right edge
+                        distance = start;
+                    }
+                }
+            } else {
+                distance = -getWidth();
+                if (getChildCount() > 0) {
+                    int start = getChildAt(0).getLeft();
+                    if (start < 0) {
+                        // scroll more if first child is out side left edge
+                        distance = distance + start;
+                    }
+                }
+            }
+        }
+        return distance;
+    }
+
+    boolean isSlidingChildViews() {
+        return (mFlag & PF_SLIDING) != 0;
+    }
+
+    /**
+     * Temporarily slide out child and block layout and scroll requests.
+     */
+    void slideOut() {
+        if ((mFlag & PF_SLIDING) != 0) {
+            return;
+        }
+        mFlag |= PF_SLIDING;
+        if (getChildCount() == 0) {
+            return;
+        }
+        if (mOrientation == VERTICAL) {
+            mBaseGridView.smoothScrollBy(0, getSlideOutDistance(),
+                    new AccelerateDecelerateInterpolator());
+        } else {
+            mBaseGridView.smoothScrollBy(getSlideOutDistance(), 0,
+                    new AccelerateDecelerateInterpolator());
+        }
+    }
+
+    private boolean prependOneColumnVisibleItems() {
+        return mGrid.prependOneColumnVisibleItems();
+    }
+
+    private void appendVisibleItems() {
+        mGrid.appendVisibleItems((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
+                ? -mExtraLayoutSpace - mExtraLayoutSpaceInPreLayout
+                : mSizePrimary + mExtraLayoutSpace + mExtraLayoutSpaceInPreLayout);
+    }
+
+    private void prependVisibleItems() {
+        mGrid.prependVisibleItems((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
+                ? mSizePrimary + mExtraLayoutSpace + mExtraLayoutSpaceInPreLayout
+                : -mExtraLayoutSpace - mExtraLayoutSpaceInPreLayout);
+    }
+
+    /**
+     * Fast layout when there is no structure change, adapter change, etc.
+     * It will layout all views was layout requested or updated, until hit a view
+     * with different size,  then it break and detachAndScrap all views after that.
+     */
+    private void fastRelayout() {
+        boolean invalidateAfter = false;
+        final int childCount = getChildCount();
+        int position = mGrid.getFirstVisibleIndex();
+        int index = 0;
+        mFlag &= ~PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION;
+        for (; index < childCount; index++, position++) {
+            View view = getChildAt(index);
+            // We don't hit fastRelayout() if State.didStructure() is true, but prelayout may add
+            // extra views and invalidate existing Grid position. Also the prelayout calling
+            // getViewForPosotion() may retrieve item from cache with FLAG_INVALID. The adapter
+            // postion will be -1 for this case. Either case, we should invalidate after this item
+            // and call getViewForPosition() again to rebind.
+            if (position != getAdapterPositionByView(view)) {
+                invalidateAfter = true;
+                break;
+            }
+            Grid.Location location = mGrid.getLocation(position);
+            if (location == null) {
+                invalidateAfter = true;
+                break;
+            }
+
+            int startSecondary = getRowStartSecondary(location.row)
+                    + mWindowAlignment.secondAxis().getPaddingMin() - mScrollOffsetSecondary;
+            int primarySize, end;
+            int start = getViewMin(view);
+            int oldPrimarySize = getViewPrimarySize(view);
+
+            LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            if (lp.viewNeedsUpdate()) {
+                mFlag |= PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION;
+                detachAndScrapView(view, mRecycler);
+                view = getViewForPosition(position);
+                addView(view, index);
+            }
+
+            measureChild(view);
+            if (mOrientation == HORIZONTAL) {
+                primarySize = getDecoratedMeasuredWidthWithMargin(view);
+                end = start + primarySize;
+            } else {
+                primarySize = getDecoratedMeasuredHeightWithMargin(view);
+                end = start + primarySize;
+            }
+            layoutChild(location.row, view, start, end, startSecondary);
+            if (oldPrimarySize != primarySize) {
+                // size changed invalidate remaining Locations
+                if (DEBUG) Log.d(getTag(), "fastRelayout: view size changed at " + position);
+                invalidateAfter = true;
+                break;
+            }
+        }
+        if (invalidateAfter) {
+            final int savedLastPos = mGrid.getLastVisibleIndex();
+            for (int i = childCount - 1; i >= index; i--) {
+                View v = getChildAt(i);
+                detachAndScrapView(v, mRecycler);
+            }
+            mGrid.invalidateItemsAfter(position);
+            if ((mFlag & PF_PRUNE_CHILD) != 0) {
+                // in regular prune child mode, we just append items up to edge limit
+                appendVisibleItems();
+                if (mFocusPosition >= 0 && mFocusPosition <= savedLastPos) {
+                    // make sure add focus view back:  the view might be outside edge limit
+                    // when there is delta in onLayoutChildren().
+                    while (mGrid.getLastVisibleIndex() < mFocusPosition) {
+                        mGrid.appendOneColumnVisibleItems();
+                    }
+                }
+            } else {
+                // prune disabled(e.g. in RowsFragment transition): append all removed items
+                while (mGrid.appendOneColumnVisibleItems()
+                        && mGrid.getLastVisibleIndex() < savedLastPos);
+            }
+        }
+        updateScrollLimits();
+        updateSecondaryScrollLimits();
+    }
+
+    @Override
+    public void removeAndRecycleAllViews(RecyclerView.Recycler recycler) {
+        if (TRACE) TraceCompat.beginSection("removeAndRecycleAllViews");
+        if (DEBUG) Log.v(TAG, "removeAndRecycleAllViews " + getChildCount());
+        for (int i = getChildCount() - 1; i >= 0; i--) {
+            removeAndRecycleViewAt(i, recycler);
+        }
+        if (TRACE) TraceCompat.endSection();
+    }
+
+    // called by onLayoutChildren, either focus to FocusPosition or declare focusViewAvailable
+    // and scroll to the view if framework focus on it.
+    private void focusToViewInLayout(boolean hadFocus, boolean alignToView, int extraDelta,
+            int extraDeltaSecondary) {
+        View focusView = findViewByPosition(mFocusPosition);
+        if (focusView != null && alignToView) {
+            scrollToView(focusView, false, extraDelta, extraDeltaSecondary);
+        }
+        if (focusView != null && hadFocus && !focusView.hasFocus()) {
+            focusView.requestFocus();
+        } else if (!hadFocus && !mBaseGridView.hasFocus()) {
+            if (focusView != null && focusView.hasFocusable()) {
+                mBaseGridView.focusableViewAvailable(focusView);
+            } else {
+                for (int i = 0, count = getChildCount(); i < count; i++) {
+                    focusView = getChildAt(i);
+                    if (focusView != null && focusView.hasFocusable()) {
+                        mBaseGridView.focusableViewAvailable(focusView);
+                        break;
+                    }
+                }
+            }
+            // focusViewAvailable() might focus to the view, scroll to it if that is the case.
+            if (alignToView && focusView != null && focusView.hasFocus()) {
+                scrollToView(focusView, false, extraDelta, extraDeltaSecondary);
+            }
+        }
+    }
+
+    @VisibleForTesting
+    public static class OnLayoutCompleteListener {
+        public void onLayoutCompleted(RecyclerView.State state) {
+        }
+    }
+
+    @VisibleForTesting
+    OnLayoutCompleteListener mLayoutCompleteListener;
+
+    @Override
+    public void onLayoutCompleted(State state) {
+        if (mLayoutCompleteListener != null) {
+            mLayoutCompleteListener.onLayoutCompleted(state);
+        }
+    }
+
+    @Override
+    public boolean supportsPredictiveItemAnimations() {
+        return true;
+    }
+
+    void updatePositionToRowMapInPostLayout() {
+        mPositionToRowInPostLayout.clear();
+        final int childCount = getChildCount();
+        for (int i = 0;  i < childCount; i++) {
+            // Grid still maps to old positions at this point, use old position to get row infor
+            int position = mBaseGridView.getChildViewHolder(getChildAt(i)).getOldPosition();
+            if (position >= 0) {
+                Grid.Location loc = mGrid.getLocation(position);
+                if (loc != null) {
+                    mPositionToRowInPostLayout.put(position, loc.row);
+                }
+            }
+        }
+    }
+
+    void fillScrapViewsInPostLayout() {
+        List<RecyclerView.ViewHolder> scrapList = mRecycler.getScrapList();
+        final int scrapSize = scrapList.size();
+        if (scrapSize == 0) {
+            return;
+        }
+        // initialize the int array or re-allocate the array.
+        if (mDisappearingPositions == null  || scrapSize > mDisappearingPositions.length) {
+            int length = mDisappearingPositions == null ? 16 : mDisappearingPositions.length;
+            while (length < scrapSize) {
+                length = length << 1;
+            }
+            mDisappearingPositions = new int[length];
+        }
+        int totalItems = 0;
+        for (int i = 0; i < scrapSize; i++) {
+            int pos = scrapList.get(i).getAdapterPosition();
+            if (pos >= 0) {
+                mDisappearingPositions[totalItems++] = pos;
+            }
+        }
+        // totalItems now has the length of disappearing items
+        if (totalItems > 0) {
+            Arrays.sort(mDisappearingPositions, 0, totalItems);
+            mGrid.fillDisappearingItems(mDisappearingPositions, totalItems,
+                    mPositionToRowInPostLayout);
+        }
+        mPositionToRowInPostLayout.clear();
+    }
+
+    // in prelayout, first child's getViewPosition can be smaller than old adapter position
+    // if there were items removed before first visible index. For example:
+    // visible items are 3, 4, 5, 6, deleting 1, 2, 3 from adapter; the view position in
+    // prelayout are not 3(deleted), 4, 5, 6. Instead it's 1(deleted), 2, 3, 4.
+    // So there is a delta (2 in this case) between last cached position and prelayout position.
+    void updatePositionDeltaInPreLayout() {
+        if (getChildCount() > 0) {
+            View view = getChildAt(0);
+            LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            mPositionDeltaInPreLayout = mGrid.getFirstVisibleIndex()
+                    - lp.getViewLayoutPosition();
+        } else {
+            mPositionDeltaInPreLayout = 0;
+        }
+    }
+
+    // Lays out items based on the current scroll position
+    @Override
+    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        if (DEBUG) {
+            Log.v(getTag(), "layoutChildren start numRows " + mNumRows
+                    + " inPreLayout " + state.isPreLayout()
+                    + " didStructureChange " + state.didStructureChange()
+                    + " mForceFullLayout " + ((mFlag & PF_FORCE_FULL_LAYOUT) != 0));
+            Log.v(getTag(), "width " + getWidth() + " height " + getHeight());
+        }
+
+        if (mNumRows == 0) {
+            // haven't done measure yet
+            return;
+        }
+        final int itemCount = state.getItemCount();
+        if (itemCount < 0) {
+            return;
+        }
+
+        if ((mFlag & PF_SLIDING) != 0) {
+            // if there is already children, delay the layout process until slideIn(), if it's
+            // first time layout children: scroll them offscreen at end of onLayoutChildren()
+            if (getChildCount() > 0) {
+                mFlag |= PF_LAYOUT_EATEN_IN_SLIDING;
+                return;
+            }
+        }
+        if ((mFlag & PF_LAYOUT_ENABLED) == 0) {
+            discardLayoutInfo();
+            removeAndRecycleAllViews(recycler);
+            return;
+        }
+        mFlag = (mFlag & ~PF_STAGE_MASK) | PF_STAGE_LAYOUT;
+
+        saveContext(recycler, state);
+        if (state.isPreLayout()) {
+            updatePositionDeltaInPreLayout();
+            int childCount = getChildCount();
+            if (mGrid != null && childCount > 0) {
+                int minChangedEdge = Integer.MAX_VALUE;
+                int maxChangeEdge = Integer.MIN_VALUE;
+                int minOldAdapterPosition = mBaseGridView.getChildViewHolder(
+                        getChildAt(0)).getOldPosition();
+                int maxOldAdapterPosition = mBaseGridView.getChildViewHolder(
+                        getChildAt(childCount - 1)).getOldPosition();
+                for (int i = 0; i < childCount; i++) {
+                    View view = getChildAt(i);
+                    LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                    int newAdapterPosition = mBaseGridView.getChildAdapterPosition(view);
+                    // if either of following happening
+                    // 1. item itself has changed or layout parameter changed
+                    // 2. item is losing focus
+                    // 3. item is gaining focus
+                    // 4. item is moved out of old adapter position range.
+                    if (lp.isItemChanged() || lp.isItemRemoved() || view.isLayoutRequested()
+                            || (!view.hasFocus() && mFocusPosition == lp.getViewAdapterPosition())
+                            || (view.hasFocus() && mFocusPosition != lp.getViewAdapterPosition())
+                            || newAdapterPosition < minOldAdapterPosition
+                            || newAdapterPosition > maxOldAdapterPosition) {
+                        minChangedEdge = Math.min(minChangedEdge, getViewMin(view));
+                        maxChangeEdge = Math.max(maxChangeEdge, getViewMax(view));
+                    }
+                }
+                if (maxChangeEdge > minChangedEdge) {
+                    mExtraLayoutSpaceInPreLayout = maxChangeEdge - minChangedEdge;
+                }
+                // append items for mExtraLayoutSpaceInPreLayout
+                appendVisibleItems();
+                prependVisibleItems();
+            }
+            mFlag &= ~PF_STAGE_MASK;
+            leaveContext();
+            if (DEBUG) Log.v(getTag(), "layoutChildren end");
+            return;
+        }
+
+        // save all view's row information before detach all views
+        if (state.willRunPredictiveAnimations()) {
+            updatePositionToRowMapInPostLayout();
+        }
+        // check if we need align to mFocusPosition, this is usually true unless in smoothScrolling
+        final boolean scrollToFocus = !isSmoothScrolling()
+                && mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_ALIGNED;
+        if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE) {
+            mFocusPosition = mFocusPosition + mFocusPositionOffset;
+            mSubFocusPosition = 0;
+        }
+        mFocusPositionOffset = 0;
+
+        View savedFocusView = findViewByPosition(mFocusPosition);
+        int savedFocusPos = mFocusPosition;
+        int savedSubFocusPos = mSubFocusPosition;
+        boolean hadFocus = mBaseGridView.hasFocus();
+        final int firstVisibleIndex = mGrid != null ? mGrid.getFirstVisibleIndex() : NO_POSITION;
+        final int lastVisibleIndex = mGrid != null ? mGrid.getLastVisibleIndex() : NO_POSITION;
+        final int deltaPrimary;
+        final int deltaSecondary;
+        if (mOrientation == HORIZONTAL) {
+            deltaPrimary = state.getRemainingScrollHorizontal();
+            deltaSecondary = state.getRemainingScrollVertical();
+        } else {
+            deltaSecondary = state.getRemainingScrollHorizontal();
+            deltaPrimary = state.getRemainingScrollVertical();
+        }
+        if (layoutInit()) {
+            mFlag |= PF_FAST_RELAYOUT;
+            // If grid view is empty, we will start from mFocusPosition
+            mGrid.setStart(mFocusPosition);
+            fastRelayout();
+        } else {
+            mFlag &= ~PF_FAST_RELAYOUT;
+            // layoutInit() has detached all views, so start from scratch
+            mFlag = (mFlag & ~PF_IN_LAYOUT_SEARCH_FOCUS)
+                    | (hadFocus ? PF_IN_LAYOUT_SEARCH_FOCUS : 0);
+            int startFromPosition, endPos;
+            if (scrollToFocus && (firstVisibleIndex < 0 || mFocusPosition > lastVisibleIndex
+                    || mFocusPosition < firstVisibleIndex)) {
+                startFromPosition = endPos = mFocusPosition;
+            } else {
+                startFromPosition = firstVisibleIndex;
+                endPos = lastVisibleIndex;
+            }
+            mGrid.setStart(startFromPosition);
+            if (endPos != NO_POSITION) {
+                while (appendOneColumnVisibleItems() && findViewByPosition(endPos) == null) {
+                    // continuously append items until endPos
+                }
+            }
+        }
+        // multiple rounds: scrollToView of first round may drag first/last child into
+        // "visible window" and we update scrollMin/scrollMax then run second scrollToView
+        // we must do this for fastRelayout() for the append item case
+        int oldFirstVisible;
+        int oldLastVisible;
+        do {
+            updateScrollLimits();
+            oldFirstVisible = mGrid.getFirstVisibleIndex();
+            oldLastVisible = mGrid.getLastVisibleIndex();
+            focusToViewInLayout(hadFocus, scrollToFocus, -deltaPrimary, -deltaSecondary);
+            appendVisibleItems();
+            prependVisibleItems();
+            // b/67370222: do not removeInvisibleViewsAtFront/End() in the loop, otherwise
+            // loop may bounce between scroll forward and scroll backward forever. Example:
+            // Assuming there are 19 items, child#18 and child#19 are both in RV, we are
+            // trying to focus to child#18 and there are 200px remaining scroll distance.
+            //   1  focusToViewInLayout() tries scroll forward 50 px to align focused child#18 on
+            //      right edge, but there to compensate remaining scroll 200px, also scroll
+            //      backward 200px, 150px pushes last child#19 out side of right edge.
+            //   2  removeInvisibleViewsAtEnd() remove last child#19, updateScrollLimits()
+            //      invalidates scroll max
+            //   3  In next iteration, when scroll max/min is unknown, focusToViewInLayout() will
+            //      align focused child#18 at center of screen.
+            //   4  Because #18 is aligned at center, appendVisibleItems() will fill child#19 to
+            //      the right.
+            //   5  (back to 1 and loop forever)
+        } while (mGrid.getFirstVisibleIndex() != oldFirstVisible
+                || mGrid.getLastVisibleIndex() != oldLastVisible);
+        removeInvisibleViewsAtFront();
+        removeInvisibleViewsAtEnd();
+
+        if (state.willRunPredictiveAnimations()) {
+            fillScrapViewsInPostLayout();
+        }
+
+        if (DEBUG) {
+            StringWriter sw = new StringWriter();
+            PrintWriter pw = new PrintWriter(sw);
+            mGrid.debugPrint(pw);
+            Log.d(getTag(), sw.toString());
+        }
+
+        if ((mFlag & PF_ROW_SECONDARY_SIZE_REFRESH) != 0) {
+            mFlag &= ~PF_ROW_SECONDARY_SIZE_REFRESH;
+        } else {
+            updateRowSecondarySizeRefresh();
+        }
+
+        // For fastRelayout, only dispatch event when focus position changes or selected item
+        // being updated.
+        if ((mFlag & PF_FAST_RELAYOUT) != 0 && (mFocusPosition != savedFocusPos || mSubFocusPosition
+                != savedSubFocusPos || findViewByPosition(mFocusPosition) != savedFocusView
+                || (mFlag & PF_FAST_RELAYOUT_UPDATED_SELECTED_POSITION) != 0)) {
+            dispatchChildSelected();
+        } else if ((mFlag & (PF_FAST_RELAYOUT | PF_IN_LAYOUT_SEARCH_FOCUS))
+                == PF_IN_LAYOUT_SEARCH_FOCUS) {
+            // For full layout we dispatchChildSelected() in createItem() unless searched all
+            // children and found none is focusable then dispatchChildSelected() here.
+            dispatchChildSelected();
+        }
+        dispatchChildSelectedAndPositioned();
+        if ((mFlag & PF_SLIDING) != 0) {
+            scrollDirectionPrimary(getSlideOutDistance());
+        }
+
+        mFlag &= ~PF_STAGE_MASK;
+        leaveContext();
+        if (DEBUG) Log.v(getTag(), "layoutChildren end");
+    }
+
+    private void offsetChildrenSecondary(int increment) {
+        final int childCount = getChildCount();
+        if (mOrientation == HORIZONTAL) {
+            for (int i = 0; i < childCount; i++) {
+                getChildAt(i).offsetTopAndBottom(increment);
+            }
+        } else {
+            for (int i = 0; i < childCount; i++) {
+                getChildAt(i).offsetLeftAndRight(increment);
+            }
+        }
+    }
+
+    private void offsetChildrenPrimary(int increment) {
+        final int childCount = getChildCount();
+        if (mOrientation == VERTICAL) {
+            for (int i = 0; i < childCount; i++) {
+                getChildAt(i).offsetTopAndBottom(increment);
+            }
+        } else {
+            for (int i = 0; i < childCount; i++) {
+                getChildAt(i).offsetLeftAndRight(increment);
+            }
+        }
+    }
+
+    @Override
+    public int scrollHorizontallyBy(int dx, Recycler recycler, RecyclerView.State state) {
+        if (DEBUG) Log.v(getTag(), "scrollHorizontallyBy " + dx);
+        if ((mFlag & PF_LAYOUT_ENABLED) == 0 || !hasDoneFirstLayout()) {
+            return 0;
+        }
+        saveContext(recycler, state);
+        mFlag = (mFlag & ~PF_STAGE_MASK) | PF_STAGE_SCROLL;
+        int result;
+        if (mOrientation == HORIZONTAL) {
+            result = scrollDirectionPrimary(dx);
+        } else {
+            result = scrollDirectionSecondary(dx);
+        }
+        leaveContext();
+        mFlag &= ~PF_STAGE_MASK;
+        return result;
+    }
+
+    @Override
+    public int scrollVerticallyBy(int dy, Recycler recycler, RecyclerView.State state) {
+        if (DEBUG) Log.v(getTag(), "scrollVerticallyBy " + dy);
+        if ((mFlag & PF_LAYOUT_ENABLED) == 0 || !hasDoneFirstLayout()) {
+            return 0;
+        }
+        mFlag = (mFlag & ~PF_STAGE_MASK) | PF_STAGE_SCROLL;
+        saveContext(recycler, state);
+        int result;
+        if (mOrientation == VERTICAL) {
+            result = scrollDirectionPrimary(dy);
+        } else {
+            result = scrollDirectionSecondary(dy);
+        }
+        leaveContext();
+        mFlag &= ~PF_STAGE_MASK;
+        return result;
+    }
+
+    // scroll in main direction may add/prune views
+    private int scrollDirectionPrimary(int da) {
+        if (TRACE) TraceCompat.beginSection("scrollPrimary");
+        // We apply the cap of maxScroll/minScroll to the delta, except for two cases:
+        // 1. when children are in sliding out mode
+        // 2. During onLayoutChildren(), it may compensate the remaining scroll delta,
+        //    we should honor the request regardless if it goes over minScroll / maxScroll.
+        //    (see b/64931938 testScrollAndRemove and testScrollAndRemoveSample1)
+        if ((mFlag & PF_SLIDING) == 0 && (mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT) {
+            if (da > 0) {
+                if (!mWindowAlignment.mainAxis().isMaxUnknown()) {
+                    int maxScroll = mWindowAlignment.mainAxis().getMaxScroll();
+                    if (da > maxScroll) {
+                        da = maxScroll;
+                    }
+                }
+            } else if (da < 0) {
+                if (!mWindowAlignment.mainAxis().isMinUnknown()) {
+                    int minScroll = mWindowAlignment.mainAxis().getMinScroll();
+                    if (da < minScroll) {
+                        da = minScroll;
+                    }
+                }
+            }
+        }
+        if (da == 0) {
+            if (TRACE) TraceCompat.endSection();
+            return 0;
+        }
+        offsetChildrenPrimary(-da);
+        if ((mFlag & PF_STAGE_MASK) == PF_STAGE_LAYOUT) {
+            updateScrollLimits();
+            if (TRACE) TraceCompat.endSection();
+            return da;
+        }
+
+        int childCount = getChildCount();
+        boolean updated;
+
+        if ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0 ? da > 0 : da < 0) {
+            prependVisibleItems();
+        } else {
+            appendVisibleItems();
+        }
+        updated = getChildCount() > childCount;
+        childCount = getChildCount();
+
+        if (TRACE) TraceCompat.beginSection("remove");
+        if ((mFlag & PF_REVERSE_FLOW_PRIMARY) != 0 ? da > 0 : da < 0) {
+            removeInvisibleViewsAtEnd();
+        } else {
+            removeInvisibleViewsAtFront();
+        }
+        if (TRACE) TraceCompat.endSection();
+        updated |= getChildCount() < childCount;
+        if (updated) {
+            updateRowSecondarySizeRefresh();
+        }
+
+        mBaseGridView.invalidate();
+        updateScrollLimits();
+        if (TRACE) TraceCompat.endSection();
+        return da;
+    }
+
+    // scroll in second direction will not add/prune views
+    private int scrollDirectionSecondary(int dy) {
+        if (dy == 0) {
+            return 0;
+        }
+        offsetChildrenSecondary(-dy);
+        mScrollOffsetSecondary += dy;
+        updateSecondaryScrollLimits();
+        mBaseGridView.invalidate();
+        return dy;
+    }
+
+    @Override
+    public void collectAdjacentPrefetchPositions(int dx, int dy, State state,
+            LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        try {
+            saveContext(null, state);
+            int da = (mOrientation == HORIZONTAL) ? dx : dy;
+            if (getChildCount() == 0 || da == 0) {
+                // can't support this scroll, so don't bother prefetching
+                return;
+            }
+
+            int fromLimit = da < 0
+                    ? -mExtraLayoutSpace
+                    : mSizePrimary + mExtraLayoutSpace;
+            mGrid.collectAdjacentPrefetchPositions(fromLimit, da, layoutPrefetchRegistry);
+        } finally {
+            leaveContext();
+        }
+    }
+
+    @Override
+    public void collectInitialPrefetchPositions(int adapterItemCount,
+            LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        int numToPrefetch = mBaseGridView.mInitialPrefetchItemCount;
+        if (adapterItemCount != 0 && numToPrefetch != 0) {
+            // prefetch items centered around mFocusPosition
+            int initialPos = Math.max(0, Math.min(mFocusPosition - (numToPrefetch - 1)/ 2,
+                    adapterItemCount - numToPrefetch));
+            for (int i = initialPos; i < adapterItemCount && i < initialPos + numToPrefetch; i++) {
+                layoutPrefetchRegistry.addPosition(i, 0);
+            }
+        }
+    }
+
+    void updateScrollLimits() {
+        if (mState.getItemCount() == 0) {
+            return;
+        }
+        int highVisiblePos, lowVisiblePos;
+        int highMaxPos, lowMinPos;
+        if ((mFlag & PF_REVERSE_FLOW_PRIMARY) == 0) {
+            highVisiblePos = mGrid.getLastVisibleIndex();
+            highMaxPos = mState.getItemCount() - 1;
+            lowVisiblePos = mGrid.getFirstVisibleIndex();
+            lowMinPos = 0;
+        } else {
+            highVisiblePos = mGrid.getFirstVisibleIndex();
+            highMaxPos = 0;
+            lowVisiblePos = mGrid.getLastVisibleIndex();
+            lowMinPos = mState.getItemCount() - 1;
+        }
+        if (highVisiblePos < 0 || lowVisiblePos < 0) {
+            return;
+        }
+        final boolean highAvailable = highVisiblePos == highMaxPos;
+        final boolean lowAvailable = lowVisiblePos == lowMinPos;
+        if (!highAvailable && mWindowAlignment.mainAxis().isMaxUnknown()
+                && !lowAvailable && mWindowAlignment.mainAxis().isMinUnknown()) {
+            return;
+        }
+        int maxEdge, maxViewCenter;
+        if (highAvailable) {
+            maxEdge = mGrid.findRowMax(true, sTwoInts);
+            View maxChild = findViewByPosition(sTwoInts[1]);
+            maxViewCenter = getViewCenter(maxChild);
+            final LayoutParams lp = (LayoutParams) maxChild.getLayoutParams();
+            int[] multipleAligns = lp.getAlignMultiple();
+            if (multipleAligns != null && multipleAligns.length > 0) {
+                maxViewCenter += multipleAligns[multipleAligns.length - 1] - multipleAligns[0];
+            }
+        } else {
+            maxEdge = Integer.MAX_VALUE;
+            maxViewCenter = Integer.MAX_VALUE;
+        }
+        int minEdge, minViewCenter;
+        if (lowAvailable) {
+            minEdge = mGrid.findRowMin(false, sTwoInts);
+            View minChild = findViewByPosition(sTwoInts[1]);
+            minViewCenter = getViewCenter(minChild);
+        } else {
+            minEdge = Integer.MIN_VALUE;
+            minViewCenter = Integer.MIN_VALUE;
+        }
+        mWindowAlignment.mainAxis().updateMinMax(minEdge, maxEdge, minViewCenter, maxViewCenter);
+    }
+
+    /**
+     * Update secondary axis's scroll min/max, should be updated in
+     * {@link #scrollDirectionSecondary(int)}.
+     */
+    private void updateSecondaryScrollLimits() {
+        WindowAlignment.Axis secondAxis = mWindowAlignment.secondAxis();
+        int minEdge = secondAxis.getPaddingMin() - mScrollOffsetSecondary;
+        int maxEdge = minEdge + getSizeSecondary();
+        secondAxis.updateMinMax(minEdge, maxEdge, minEdge, maxEdge);
+    }
+
+    private void initScrollController() {
+        mWindowAlignment.reset();
+        mWindowAlignment.horizontal.setSize(getWidth());
+        mWindowAlignment.vertical.setSize(getHeight());
+        mWindowAlignment.horizontal.setPadding(getPaddingLeft(), getPaddingRight());
+        mWindowAlignment.vertical.setPadding(getPaddingTop(), getPaddingBottom());
+        mSizePrimary = mWindowAlignment.mainAxis().getSize();
+        mScrollOffsetSecondary = 0;
+
+        if (DEBUG) {
+            Log.v(getTag(), "initScrollController mSizePrimary " + mSizePrimary
+                    + " mWindowAlignment " + mWindowAlignment);
+        }
+    }
+
+    private void updateScrollController() {
+        mWindowAlignment.horizontal.setSize(getWidth());
+        mWindowAlignment.vertical.setSize(getHeight());
+        mWindowAlignment.horizontal.setPadding(getPaddingLeft(), getPaddingRight());
+        mWindowAlignment.vertical.setPadding(getPaddingTop(), getPaddingBottom());
+        mSizePrimary = mWindowAlignment.mainAxis().getSize();
+
+        if (DEBUG) {
+            Log.v(getTag(), "updateScrollController mSizePrimary " + mSizePrimary
+                    + " mWindowAlignment " + mWindowAlignment);
+        }
+    }
+
+    @Override
+    public void scrollToPosition(int position) {
+        setSelection(position, 0, false, 0);
+    }
+
+    @Override
+    public void smoothScrollToPosition(RecyclerView recyclerView, State state,
+            int position) {
+        setSelection(position, 0, true, 0);
+    }
+
+    public void setSelection(int position,
+            int primaryScrollExtra) {
+        setSelection(position, 0, false, primaryScrollExtra);
+    }
+
+    public void setSelectionSmooth(int position) {
+        setSelection(position, 0, true, 0);
+    }
+
+    public void setSelectionWithSub(int position, int subposition,
+            int primaryScrollExtra) {
+        setSelection(position, subposition, false, primaryScrollExtra);
+    }
+
+    public void setSelectionSmoothWithSub(int position, int subposition) {
+        setSelection(position, subposition, true, 0);
+    }
+
+    public int getSelection() {
+        return mFocusPosition;
+    }
+
+    public int getSubSelection() {
+        return mSubFocusPosition;
+    }
+
+    public void setSelection(int position, int subposition, boolean smooth,
+            int primaryScrollExtra) {
+        if ((mFocusPosition != position && position != NO_POSITION)
+                || subposition != mSubFocusPosition || primaryScrollExtra != mPrimaryScrollExtra) {
+            scrollToSelection(position, subposition, smooth, primaryScrollExtra);
+        }
+    }
+
+    void scrollToSelection(int position, int subposition,
+            boolean smooth, int primaryScrollExtra) {
+        if (TRACE) TraceCompat.beginSection("scrollToSelection");
+        mPrimaryScrollExtra = primaryScrollExtra;
+
+        View view = findViewByPosition(position);
+        // scrollToView() is based on Adapter position. Only call scrollToView() when item
+        // is still valid and no layout is requested, otherwise defer to next layout pass.
+        // If it is still in smoothScrolling, we should either update smoothScroller or initiate
+        // a layout.
+        final boolean notSmoothScrolling = !isSmoothScrolling()
+                || (mFlag & PF_IN_ONSTOP_SMOOTHSCROLLER) != 0;
+        if (notSmoothScrolling && !mBaseGridView.isLayoutRequested()
+                && view != null && getAdapterPositionByView(view) == position) {
+            mFlag |= PF_IN_SELECTION;
+            scrollToView(view, smooth);
+            mFlag &= ~PF_IN_SELECTION;
+        } else {
+            if ((mFlag & PF_LAYOUT_ENABLED) == 0 || (mFlag & PF_SLIDING) != 0) {
+                mFocusPosition = position;
+                mSubFocusPosition = subposition;
+                mFocusPositionOffset = Integer.MIN_VALUE;
+                return;
+            }
+            if (smooth) {
+                mFocusPosition = position;
+                mSubFocusPosition = subposition;
+                mFocusPositionOffset = Integer.MIN_VALUE;
+                if (!hasDoneFirstLayout()) {
+                    Log.w(getTag(), "setSelectionSmooth should "
+                            + "not be called before first layout pass");
+                    return;
+                }
+                position = startPositionSmoothScroller(position);
+                if (position != mFocusPosition) {
+                    // gets cropped by adapter size
+                    mFocusPosition = position;
+                    mSubFocusPosition = 0;
+                }
+            } else {
+                // stopScroll might change mFocusPosition, so call it before assign value to
+                // mFocusPosition
+                if (!notSmoothScrolling) {
+                    mBaseGridView.stopScroll();
+                }
+                mFocusPosition = position;
+                mSubFocusPosition = subposition;
+                mFocusPositionOffset = Integer.MIN_VALUE;
+                mFlag |= PF_FORCE_FULL_LAYOUT;
+                requestLayout();
+            }
+        }
+        if (TRACE) TraceCompat.endSection();
+    }
+
+    int startPositionSmoothScroller(int position) {
+        LinearSmoothScroller linearSmoothScroller = new GridLinearSmoothScroller() {
+            @Override
+            public PointF computeScrollVectorForPosition(int targetPosition) {
+                if (getChildCount() == 0) {
+                    return null;
+                }
+                final int firstChildPos = getPosition(getChildAt(0));
+                // TODO We should be able to deduce direction from bounds of current and target
+                // focus, rather than making assumptions about positions and directionality
+                final boolean isStart = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0
+                        ? targetPosition > firstChildPos
+                        : targetPosition < firstChildPos;
+                final int direction = isStart ? -1 : 1;
+                if (mOrientation == HORIZONTAL) {
+                    return new PointF(direction, 0);
+                } else {
+                    return new PointF(0, direction);
+                }
+            }
+
+        };
+        linearSmoothScroller.setTargetPosition(position);
+        startSmoothScroll(linearSmoothScroller);
+        return linearSmoothScroller.getTargetPosition();
+    }
+
+    private void processPendingMovement(boolean forward) {
+        if (forward ? hasCreatedLastItem() : hasCreatedFirstItem()) {
+            return;
+        }
+        if (mPendingMoveSmoothScroller == null) {
+            // Stop existing scroller and create a new PendingMoveSmoothScroller.
+            mBaseGridView.stopScroll();
+            PendingMoveSmoothScroller linearSmoothScroller = new PendingMoveSmoothScroller(
+                    forward ? 1 : -1, mNumRows > 1);
+            mFocusPositionOffset = 0;
+            startSmoothScroll(linearSmoothScroller);
+            if (linearSmoothScroller.isRunning()) {
+                mPendingMoveSmoothScroller = linearSmoothScroller;
+            }
+        } else {
+            if (forward) {
+                mPendingMoveSmoothScroller.increasePendingMoves();
+            } else {
+                mPendingMoveSmoothScroller.decreasePendingMoves();
+            }
+        }
+    }
+
+    @Override
+    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
+        if (DEBUG) Log.v(getTag(), "onItemsAdded positionStart "
+                + positionStart + " itemCount " + itemCount);
+        if (mFocusPosition != NO_POSITION && mGrid != null && mGrid.getFirstVisibleIndex() >= 0
+                && mFocusPositionOffset != Integer.MIN_VALUE) {
+            int pos = mFocusPosition + mFocusPositionOffset;
+            if (positionStart <= pos) {
+                mFocusPositionOffset += itemCount;
+            }
+        }
+        mChildrenStates.clear();
+    }
+
+    @Override
+    public void onItemsChanged(RecyclerView recyclerView) {
+        if (DEBUG) Log.v(getTag(), "onItemsChanged");
+        mFocusPositionOffset = 0;
+        mChildrenStates.clear();
+    }
+
+    @Override
+    public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
+        if (DEBUG) Log.v(getTag(), "onItemsRemoved positionStart "
+                + positionStart + " itemCount " + itemCount);
+        if (mFocusPosition != NO_POSITION  && mGrid != null && mGrid.getFirstVisibleIndex() >= 0
+                && mFocusPositionOffset != Integer.MIN_VALUE) {
+            int pos = mFocusPosition + mFocusPositionOffset;
+            if (positionStart <= pos) {
+                if (positionStart + itemCount > pos) {
+                    // stop updating offset after the focus item was removed
+                    mFocusPositionOffset += positionStart - pos;
+                    mFocusPosition += mFocusPositionOffset;
+                    mFocusPositionOffset = Integer.MIN_VALUE;
+                } else {
+                    mFocusPositionOffset -= itemCount;
+                }
+            }
+        }
+        mChildrenStates.clear();
+    }
+
+    @Override
+    public void onItemsMoved(RecyclerView recyclerView, int fromPosition, int toPosition,
+            int itemCount) {
+        if (DEBUG) Log.v(getTag(), "onItemsMoved fromPosition "
+                + fromPosition + " toPosition " + toPosition);
+        if (mFocusPosition != NO_POSITION && mFocusPositionOffset != Integer.MIN_VALUE) {
+            int pos = mFocusPosition + mFocusPositionOffset;
+            if (fromPosition <= pos && pos < fromPosition + itemCount) {
+                // moved items include focused position
+                mFocusPositionOffset += toPosition - fromPosition;
+            } else if (fromPosition < pos && toPosition > pos - itemCount) {
+                // move items before focus position to after focused position
+                mFocusPositionOffset -= itemCount;
+            } else if (fromPosition > pos && toPosition < pos) {
+                // move items after focus position to before focused position
+                mFocusPositionOffset += itemCount;
+            }
+        }
+        mChildrenStates.clear();
+    }
+
+    @Override
+    public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) {
+        if (DEBUG) Log.v(getTag(), "onItemsUpdated positionStart "
+                + positionStart + " itemCount " + itemCount);
+        for (int i = positionStart, end = positionStart + itemCount; i < end; i++) {
+            mChildrenStates.remove(i);
+        }
+    }
+
+    @Override
+    public boolean onRequestChildFocus(RecyclerView parent, View child, View focused) {
+        if ((mFlag & PF_FOCUS_SEARCH_DISABLED) != 0) {
+            return true;
+        }
+        if (getAdapterPositionByView(child) == NO_POSITION) {
+            // This is could be the last view in DISAPPEARING animation.
+            return true;
+        }
+        if ((mFlag & (PF_STAGE_MASK | PF_IN_SELECTION)) == 0) {
+            scrollToView(child, focused, true);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean requestChildRectangleOnScreen(RecyclerView parent, View view, Rect rect,
+            boolean immediate) {
+        if (DEBUG) Log.v(getTag(), "requestChildRectangleOnScreen " + view + " " + rect);
+        return false;
+    }
+
+    public void getViewSelectedOffsets(View view, int[] offsets) {
+        if (mOrientation == HORIZONTAL) {
+            offsets[0] = getPrimaryAlignedScrollDistance(view);
+            offsets[1] = getSecondaryScrollDistance(view);
+        } else {
+            offsets[1] = getPrimaryAlignedScrollDistance(view);
+            offsets[0] = getSecondaryScrollDistance(view);
+        }
+    }
+
+    /**
+     * Return the scroll delta on primary direction to make the view selected. If the return value
+     * is 0, there is no need to scroll.
+     */
+    private int getPrimaryAlignedScrollDistance(View view) {
+        return mWindowAlignment.mainAxis().getScroll(getViewCenter(view));
+    }
+
+    /**
+     * Get adjusted primary position for a given childView (if there is multiple ItemAlignment
+     * defined on the view).
+     */
+    private int getAdjustedPrimaryAlignedScrollDistance(int scrollPrimary, View view,
+            View childView) {
+        int subindex = getSubPositionByView(view, childView);
+        if (subindex != 0) {
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            scrollPrimary += lp.getAlignMultiple()[subindex] - lp.getAlignMultiple()[0];
+        }
+        return scrollPrimary;
+    }
+
+    private int getSecondaryScrollDistance(View view) {
+        int viewCenterSecondary = getViewCenterSecondary(view);
+        return mWindowAlignment.secondAxis().getScroll(viewCenterSecondary);
+    }
+
+    /**
+     * Scroll to a given child view and change mFocusPosition. Ignored when in slideOut() state.
+     */
+    void scrollToView(View view, boolean smooth) {
+        scrollToView(view, view == null ? null : view.findFocus(), smooth);
+    }
+
+    void scrollToView(View view, boolean smooth, int extraDelta, int extraDeltaSecondary) {
+        scrollToView(view, view == null ? null : view.findFocus(), smooth, extraDelta,
+                extraDeltaSecondary);
+    }
+
+    private void scrollToView(View view, View childView, boolean smooth) {
+        scrollToView(view, childView, smooth, 0, 0);
+    }
+    /**
+     * Scroll to a given child view and change mFocusPosition. Ignored when in slideOut() state.
+     */
+    private void scrollToView(View view, View childView, boolean smooth, int extraDelta,
+            int extraDeltaSecondary) {
+        if ((mFlag & PF_SLIDING) != 0) {
+            return;
+        }
+        int newFocusPosition = getAdapterPositionByView(view);
+        int newSubFocusPosition = getSubPositionByView(view, childView);
+        if (newFocusPosition != mFocusPosition || newSubFocusPosition != mSubFocusPosition) {
+            mFocusPosition = newFocusPosition;
+            mSubFocusPosition = newSubFocusPosition;
+            mFocusPositionOffset = 0;
+            if ((mFlag & PF_STAGE_MASK) != PF_STAGE_LAYOUT) {
+                dispatchChildSelected();
+            }
+            if (mBaseGridView.isChildrenDrawingOrderEnabledInternal()) {
+                mBaseGridView.invalidate();
+            }
+        }
+        if (view == null) {
+            return;
+        }
+        if (!view.hasFocus() && mBaseGridView.hasFocus()) {
+            // transfer focus to the child if it does not have focus yet (e.g. triggered
+            // by setSelection())
+            view.requestFocus();
+        }
+        if ((mFlag & PF_SCROLL_ENABLED) == 0 && smooth) {
+            return;
+        }
+        if (getScrollPosition(view, childView, sTwoInts)
+                || extraDelta != 0 || extraDeltaSecondary != 0) {
+            scrollGrid(sTwoInts[0] + extraDelta, sTwoInts[1] + extraDeltaSecondary, smooth);
+        }
+    }
+
+    boolean getScrollPosition(View view, View childView, int[] deltas) {
+        switch (mFocusScrollStrategy) {
+            case BaseGridView.FOCUS_SCROLL_ALIGNED:
+            default:
+                return getAlignedPosition(view, childView, deltas);
+            case BaseGridView.FOCUS_SCROLL_ITEM:
+            case BaseGridView.FOCUS_SCROLL_PAGE:
+                return getNoneAlignedPosition(view, deltas);
+        }
+    }
+
+    private boolean getNoneAlignedPosition(View view, int[] deltas) {
+        int pos = getAdapterPositionByView(view);
+        int viewMin = getViewMin(view);
+        int viewMax = getViewMax(view);
+        // we either align "firstView" to left/top padding edge
+        // or align "lastView" to right/bottom padding edge
+        View firstView = null;
+        View lastView = null;
+        int paddingMin = mWindowAlignment.mainAxis().getPaddingMin();
+        int clientSize = mWindowAlignment.mainAxis().getClientSize();
+        final int row = mGrid.getRowIndex(pos);
+        if (viewMin < paddingMin) {
+            // view enters low padding area:
+            firstView = view;
+            if (mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_PAGE) {
+                // scroll one "page" left/top,
+                // align first visible item of the "page" at the low padding edge.
+                while (prependOneColumnVisibleItems()) {
+                    CircularIntArray positions =
+                            mGrid.getItemPositionsInRows(mGrid.getFirstVisibleIndex(), pos)[row];
+                    firstView = findViewByPosition(positions.get(0));
+                    if (viewMax - getViewMin(firstView) > clientSize) {
+                        if (positions.size() > 2) {
+                            firstView = findViewByPosition(positions.get(2));
+                        }
+                        break;
+                    }
+                }
+            }
+        } else if (viewMax > clientSize + paddingMin) {
+            // view enters high padding area:
+            if (mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_PAGE) {
+                // scroll whole one page right/bottom, align view at the low padding edge.
+                firstView = view;
+                do {
+                    CircularIntArray positions =
+                            mGrid.getItemPositionsInRows(pos, mGrid.getLastVisibleIndex())[row];
+                    lastView = findViewByPosition(positions.get(positions.size() - 1));
+                    if (getViewMax(lastView) - viewMin > clientSize) {
+                        lastView = null;
+                        break;
+                    }
+                } while (appendOneColumnVisibleItems());
+                if (lastView != null) {
+                    // however if we reached end,  we should align last view.
+                    firstView = null;
+                }
+            } else {
+                lastView = view;
+            }
+        }
+        int scrollPrimary = 0;
+        int scrollSecondary = 0;
+        if (firstView != null) {
+            scrollPrimary = getViewMin(firstView) - paddingMin;
+        } else if (lastView != null) {
+            scrollPrimary = getViewMax(lastView) - (paddingMin + clientSize);
+        }
+        View secondaryAlignedView;
+        if (firstView != null) {
+            secondaryAlignedView = firstView;
+        } else if (lastView != null) {
+            secondaryAlignedView = lastView;
+        } else {
+            secondaryAlignedView = view;
+        }
+        scrollSecondary = getSecondaryScrollDistance(secondaryAlignedView);
+        if (scrollPrimary != 0 || scrollSecondary != 0) {
+            deltas[0] = scrollPrimary;
+            deltas[1] = scrollSecondary;
+            return true;
+        }
+        return false;
+    }
+
+    private boolean getAlignedPosition(View view, View childView, int[] deltas) {
+        int scrollPrimary = getPrimaryAlignedScrollDistance(view);
+        if (childView != null) {
+            scrollPrimary = getAdjustedPrimaryAlignedScrollDistance(scrollPrimary, view, childView);
+        }
+        int scrollSecondary = getSecondaryScrollDistance(view);
+        if (DEBUG) {
+            Log.v(getTag(), "getAlignedPosition " + scrollPrimary + " " + scrollSecondary
+                    + " " + mPrimaryScrollExtra + " " + mWindowAlignment);
+        }
+        scrollPrimary += mPrimaryScrollExtra;
+        if (scrollPrimary != 0 || scrollSecondary != 0) {
+            deltas[0] = scrollPrimary;
+            deltas[1] = scrollSecondary;
+            return true;
+        } else {
+            deltas[0] = 0;
+            deltas[1] = 0;
+        }
+        return false;
+    }
+
+    private void scrollGrid(int scrollPrimary, int scrollSecondary, boolean smooth) {
+        if ((mFlag & PF_STAGE_MASK) == PF_STAGE_LAYOUT) {
+            scrollDirectionPrimary(scrollPrimary);
+            scrollDirectionSecondary(scrollSecondary);
+        } else {
+            int scrollX;
+            int scrollY;
+            if (mOrientation == HORIZONTAL) {
+                scrollX = scrollPrimary;
+                scrollY = scrollSecondary;
+            } else {
+                scrollX = scrollSecondary;
+                scrollY = scrollPrimary;
+            }
+            if (smooth) {
+                mBaseGridView.smoothScrollBy(scrollX, scrollY);
+            } else {
+                mBaseGridView.scrollBy(scrollX, scrollY);
+                dispatchChildSelectedAndPositioned();
+            }
+        }
+    }
+
+    public void setPruneChild(boolean pruneChild) {
+        if (((mFlag & PF_PRUNE_CHILD) != 0) != pruneChild) {
+            mFlag = (mFlag & ~PF_PRUNE_CHILD) | (pruneChild ? PF_PRUNE_CHILD : 0);
+            if (pruneChild) {
+                requestLayout();
+            }
+        }
+    }
+
+    public boolean getPruneChild() {
+        return (mFlag & PF_PRUNE_CHILD) != 0;
+    }
+
+    public void setScrollEnabled(boolean scrollEnabled) {
+        if (((mFlag & PF_SCROLL_ENABLED) != 0) != scrollEnabled) {
+            mFlag = (mFlag & ~PF_SCROLL_ENABLED) | (scrollEnabled ? PF_SCROLL_ENABLED : 0);
+            if (((mFlag & PF_SCROLL_ENABLED) != 0)
+                    && mFocusScrollStrategy == BaseGridView.FOCUS_SCROLL_ALIGNED
+                    && mFocusPosition != NO_POSITION) {
+                scrollToSelection(mFocusPosition, mSubFocusPosition,
+                        true, mPrimaryScrollExtra);
+            }
+        }
+    }
+
+    public boolean isScrollEnabled() {
+        return (mFlag & PF_SCROLL_ENABLED) != 0;
+    }
+
+    private int findImmediateChildIndex(View view) {
+        if (mBaseGridView != null && view != mBaseGridView) {
+            view = findContainingItemView(view);
+            if (view != null) {
+                for (int i = 0, count = getChildCount(); i < count; i++) {
+                    if (getChildAt(i) == view) {
+                        return i;
+                    }
+                }
+            }
+        }
+        return NO_POSITION;
+    }
+
+    void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+        if (gainFocus) {
+            // if gridview.requestFocus() is called, select first focusable child.
+            for (int i = mFocusPosition; ;i++) {
+                View view = findViewByPosition(i);
+                if (view == null) {
+                    break;
+                }
+                if (view.getVisibility() == View.VISIBLE && view.hasFocusable()) {
+                    view.requestFocus();
+                    break;
+                }
+            }
+        }
+    }
+
+    void setFocusSearchDisabled(boolean disabled) {
+        mFlag = (mFlag & ~PF_FOCUS_SEARCH_DISABLED) | (disabled ? PF_FOCUS_SEARCH_DISABLED : 0);
+    }
+
+    boolean isFocusSearchDisabled() {
+        return (mFlag & PF_FOCUS_SEARCH_DISABLED) != 0;
+    }
+
+    @Override
+    public View onInterceptFocusSearch(View focused, int direction) {
+        if ((mFlag & PF_FOCUS_SEARCH_DISABLED) != 0) {
+            return focused;
+        }
+
+        final FocusFinder ff = FocusFinder.getInstance();
+        View result = null;
+        if (direction == View.FOCUS_FORWARD || direction == View.FOCUS_BACKWARD) {
+            // convert direction to absolute direction and see if we have a view there and if not
+            // tell LayoutManager to add if it can.
+            if (canScrollVertically()) {
+                final int absDir =
+                        direction == View.FOCUS_FORWARD ? View.FOCUS_DOWN : View.FOCUS_UP;
+                result = ff.findNextFocus(mBaseGridView, focused, absDir);
+            }
+            if (canScrollHorizontally()) {
+                boolean rtl = getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL;
+                final int absDir = (direction == View.FOCUS_FORWARD) ^ rtl
+                        ? View.FOCUS_RIGHT : View.FOCUS_LEFT;
+                result = ff.findNextFocus(mBaseGridView, focused, absDir);
+            }
+        } else {
+            result = ff.findNextFocus(mBaseGridView, focused, direction);
+        }
+        if (result != null) {
+            return result;
+        }
+
+        if (mBaseGridView.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS) {
+            return mBaseGridView.getParent().focusSearch(focused, direction);
+        }
+
+        if (DEBUG) Log.v(getTag(), "regular focusSearch failed direction " + direction);
+        int movement = getMovement(direction);
+        final boolean isScroll = mBaseGridView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE;
+        if (movement == NEXT_ITEM) {
+            if (isScroll || (mFlag & PF_FOCUS_OUT_END) == 0) {
+                result = focused;
+            }
+            if ((mFlag & PF_SCROLL_ENABLED) != 0 && !hasCreatedLastItem()) {
+                processPendingMovement(true);
+                result = focused;
+            }
+        } else if (movement == PREV_ITEM) {
+            if (isScroll || (mFlag & PF_FOCUS_OUT_FRONT) == 0) {
+                result = focused;
+            }
+            if ((mFlag & PF_SCROLL_ENABLED) != 0 && !hasCreatedFirstItem()) {
+                processPendingMovement(false);
+                result = focused;
+            }
+        } else if (movement == NEXT_ROW) {
+            if (isScroll || (mFlag & PF_FOCUS_OUT_SIDE_END) == 0) {
+                result = focused;
+            }
+        } else if (movement == PREV_ROW) {
+            if (isScroll || (mFlag & PF_FOCUS_OUT_SIDE_START) == 0) {
+                result = focused;
+            }
+        }
+        if (result != null) {
+            return result;
+        }
+
+        if (DEBUG) Log.v(getTag(), "now focusSearch in parent");
+        result = mBaseGridView.getParent().focusSearch(focused, direction);
+        if (result != null) {
+            return result;
+        }
+        return focused != null ? focused : mBaseGridView;
+    }
+
+    boolean hasPreviousViewInSameRow(int pos) {
+        if (mGrid == null || pos == NO_POSITION || mGrid.getFirstVisibleIndex() < 0) {
+            return false;
+        }
+        if (mGrid.getFirstVisibleIndex() > 0) {
+            return true;
+        }
+        final int focusedRow = mGrid.getLocation(pos).row;
+        for (int i = getChildCount() - 1; i >= 0; i--) {
+            int position = getAdapterPositionByIndex(i);
+            Grid.Location loc = mGrid.getLocation(position);
+            if (loc != null && loc.row == focusedRow) {
+                if (position < pos) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onAddFocusables(RecyclerView recyclerView,
+            ArrayList<View> views, int direction, int focusableMode) {
+        if ((mFlag & PF_FOCUS_SEARCH_DISABLED) != 0) {
+            return true;
+        }
+        // If this viewgroup or one of its children currently has focus then we
+        // consider our children for focus searching in main direction on the same row.
+        // If this viewgroup has no focus and using focus align, we want the system
+        // to ignore our children and pass focus to the viewgroup, which will pass
+        // focus on to its children appropriately.
+        // If this viewgroup has no focus and not using focus align, we want to
+        // consider the child that does not overlap with padding area.
+        if (recyclerView.hasFocus()) {
+            if (mPendingMoveSmoothScroller != null) {
+                // don't find next focusable if has pending movement.
+                return true;
+            }
+            final int movement = getMovement(direction);
+            final View focused = recyclerView.findFocus();
+            final int focusedIndex = findImmediateChildIndex(focused);
+            final int focusedPos = getAdapterPositionByIndex(focusedIndex);
+            // Even if focusedPos != NO_POSITION, findViewByPosition could return null if the view
+            // is ignored or getLayoutPosition does not match the adapter position of focused view.
+            final View immediateFocusedChild = (focusedPos == NO_POSITION) ? null
+                    : findViewByPosition(focusedPos);
+            // Add focusables of focused item.
+            if (immediateFocusedChild != null) {
+                immediateFocusedChild.addFocusables(views,  direction, focusableMode);
+            }
+            if (mGrid == null || getChildCount() == 0) {
+                // no grid information, or no child, bail out.
+                return true;
+            }
+            if ((movement == NEXT_ROW || movement == PREV_ROW) && mGrid.getNumRows() <= 1) {
+                // For single row, cannot navigate to previous/next row.
+                return true;
+            }
+            // Add focusables of neighbor depending on the focus search direction.
+            final int focusedRow = mGrid != null && immediateFocusedChild != null
+                    ? mGrid.getLocation(focusedPos).row : NO_POSITION;
+            final int focusableCount = views.size();
+            int inc = movement == NEXT_ITEM || movement == NEXT_ROW ? 1 : -1;
+            int loop_end = inc > 0 ? getChildCount() - 1 : 0;
+            int loop_start;
+            if (focusedIndex == NO_POSITION) {
+                loop_start = inc > 0 ? 0 : getChildCount() - 1;
+            } else {
+                loop_start = focusedIndex + inc;
+            }
+            for (int i = loop_start; inc > 0 ? i <= loop_end : i >= loop_end; i += inc) {
+                final View child = getChildAt(i);
+                if (child.getVisibility() != View.VISIBLE || !child.hasFocusable()) {
+                    continue;
+                }
+                // if there wasn't any focused item, add the very first focusable
+                // items and stop.
+                if (immediateFocusedChild == null) {
+                    child.addFocusables(views,  direction, focusableMode);
+                    if (views.size() > focusableCount) {
+                        break;
+                    }
+                    continue;
+                }
+                int position = getAdapterPositionByIndex(i);
+                Grid.Location loc = mGrid.getLocation(position);
+                if (loc == null) {
+                    continue;
+                }
+                if (movement == NEXT_ITEM) {
+                    // Add first focusable item on the same row
+                    if (loc.row == focusedRow && position > focusedPos) {
+                        child.addFocusables(views,  direction, focusableMode);
+                        if (views.size() > focusableCount) {
+                            break;
+                        }
+                    }
+                } else if (movement == PREV_ITEM) {
+                    // Add first focusable item on the same row
+                    if (loc.row == focusedRow && position < focusedPos) {
+                        child.addFocusables(views,  direction, focusableMode);
+                        if (views.size() > focusableCount) {
+                            break;
+                        }
+                    }
+                } else if (movement == NEXT_ROW) {
+                    // Add all focusable items after this item whose row index is bigger
+                    if (loc.row == focusedRow) {
+                        continue;
+                    } else if (loc.row < focusedRow) {
+                        break;
+                    }
+                    child.addFocusables(views,  direction, focusableMode);
+                } else if (movement == PREV_ROW) {
+                    // Add all focusable items before this item whose row index is smaller
+                    if (loc.row == focusedRow) {
+                        continue;
+                    } else if (loc.row > focusedRow) {
+                        break;
+                    }
+                    child.addFocusables(views,  direction, focusableMode);
+                }
+            }
+        } else {
+            int focusableCount = views.size();
+            if (mFocusScrollStrategy != BaseGridView.FOCUS_SCROLL_ALIGNED) {
+                // adding views not overlapping padding area to avoid scrolling in gaining focus
+                int left = mWindowAlignment.mainAxis().getPaddingMin();
+                int right = mWindowAlignment.mainAxis().getClientSize() + left;
+                for (int i = 0, count = getChildCount(); i < count; i++) {
+                    View child = getChildAt(i);
+                    if (child.getVisibility() == View.VISIBLE) {
+                        if (getViewMin(child) >= left && getViewMax(child) <= right) {
+                            child.addFocusables(views, direction, focusableMode);
+                        }
+                    }
+                }
+                // if we cannot find any, then just add all children.
+                if (views.size() == focusableCount) {
+                    for (int i = 0, count = getChildCount(); i < count; i++) {
+                        View child = getChildAt(i);
+                        if (child.getVisibility() == View.VISIBLE) {
+                            child.addFocusables(views, direction, focusableMode);
+                        }
+                    }
+                }
+            } else {
+                View view = findViewByPosition(mFocusPosition);
+                if (view != null) {
+                    view.addFocusables(views, direction, focusableMode);
+                }
+            }
+            // if still cannot find any, fall through and add itself
+            if (views.size() != focusableCount) {
+                return true;
+            }
+            if (recyclerView.isFocusable()) {
+                views.add(recyclerView);
+            }
+        }
+        return true;
+    }
+
+    boolean hasCreatedLastItem() {
+        int count = getItemCount();
+        return count == 0 || mBaseGridView.findViewHolderForAdapterPosition(count - 1) != null;
+    }
+
+    boolean hasCreatedFirstItem() {
+        int count = getItemCount();
+        return count == 0 || mBaseGridView.findViewHolderForAdapterPosition(0) != null;
+    }
+
+    boolean isItemFullyVisible(int pos) {
+        RecyclerView.ViewHolder vh = mBaseGridView.findViewHolderForAdapterPosition(pos);
+        if (vh == null) {
+            return false;
+        }
+        return vh.itemView.getLeft() >= 0 && vh.itemView.getRight() < mBaseGridView.getWidth()
+                && vh.itemView.getTop() >= 0 && vh.itemView.getBottom() < mBaseGridView.getHeight();
+    }
+
+    boolean canScrollTo(View view) {
+        return view.getVisibility() == View.VISIBLE && (!hasFocus() || view.hasFocusable());
+    }
+
+    boolean gridOnRequestFocusInDescendants(RecyclerView recyclerView, int direction,
+            Rect previouslyFocusedRect) {
+        switch (mFocusScrollStrategy) {
+            case BaseGridView.FOCUS_SCROLL_ALIGNED:
+            default:
+                return gridOnRequestFocusInDescendantsAligned(recyclerView,
+                        direction, previouslyFocusedRect);
+            case BaseGridView.FOCUS_SCROLL_PAGE:
+            case BaseGridView.FOCUS_SCROLL_ITEM:
+                return gridOnRequestFocusInDescendantsUnaligned(recyclerView,
+                        direction, previouslyFocusedRect);
+        }
+    }
+
+    private boolean gridOnRequestFocusInDescendantsAligned(RecyclerView recyclerView,
+            int direction, Rect previouslyFocusedRect) {
+        View view = findViewByPosition(mFocusPosition);
+        if (view != null) {
+            boolean result = view.requestFocus(direction, previouslyFocusedRect);
+            if (!result && DEBUG) {
+                Log.w(getTag(), "failed to request focus on " + view);
+            }
+            return result;
+        }
+        return false;
+    }
+
+    private boolean gridOnRequestFocusInDescendantsUnaligned(RecyclerView recyclerView,
+            int direction, Rect previouslyFocusedRect) {
+        // focus to view not overlapping padding area to avoid scrolling in gaining focus
+        int index;
+        int increment;
+        int end;
+        int count = getChildCount();
+        if ((direction & View.FOCUS_FORWARD) != 0) {
+            index = 0;
+            increment = 1;
+            end = count;
+        } else {
+            index = count - 1;
+            increment = -1;
+            end = -1;
+        }
+        int left = mWindowAlignment.mainAxis().getPaddingMin();
+        int right = mWindowAlignment.mainAxis().getClientSize() + left;
+        for (int i = index; i != end; i += increment) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == View.VISIBLE) {
+                if (getViewMin(child) >= left && getViewMax(child) <= right) {
+                    if (child.requestFocus(direction, previouslyFocusedRect)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    private final static int PREV_ITEM = 0;
+    private final static int NEXT_ITEM = 1;
+    private final static int PREV_ROW = 2;
+    private final static int NEXT_ROW = 3;
+
+    private int getMovement(int direction) {
+        int movement = View.FOCUS_LEFT;
+
+        if (mOrientation == HORIZONTAL) {
+            switch(direction) {
+                case View.FOCUS_LEFT:
+                    movement = (mFlag & PF_REVERSE_FLOW_PRIMARY) == 0 ? PREV_ITEM : NEXT_ITEM;
+                    break;
+                case View.FOCUS_RIGHT:
+                    movement = (mFlag & PF_REVERSE_FLOW_PRIMARY) == 0 ? NEXT_ITEM : PREV_ITEM;
+                    break;
+                case View.FOCUS_UP:
+                    movement = PREV_ROW;
+                    break;
+                case View.FOCUS_DOWN:
+                    movement = NEXT_ROW;
+                    break;
+            }
+        } else if (mOrientation == VERTICAL) {
+            switch(direction) {
+                case View.FOCUS_LEFT:
+                    movement = (mFlag & PF_REVERSE_FLOW_SECONDARY) == 0 ? PREV_ROW : NEXT_ROW;
+                    break;
+                case View.FOCUS_RIGHT:
+                    movement = (mFlag & PF_REVERSE_FLOW_SECONDARY) == 0 ? NEXT_ROW : PREV_ROW;
+                    break;
+                case View.FOCUS_UP:
+                    movement = PREV_ITEM;
+                    break;
+                case View.FOCUS_DOWN:
+                    movement = NEXT_ITEM;
+                    break;
+            }
+        }
+
+        return movement;
+    }
+
+    int getChildDrawingOrder(RecyclerView recyclerView, int childCount, int i) {
+        View view = findViewByPosition(mFocusPosition);
+        if (view == null) {
+            return i;
+        }
+        int focusIndex = recyclerView.indexOfChild(view);
+        // supposely 0 1 2 3 4 5 6 7 8 9, 4 is the center item
+        // drawing order is 0 1 2 3 9 8 7 6 5 4
+        if (i < focusIndex) {
+            return i;
+        } else if (i < childCount - 1) {
+            return focusIndex + childCount - 1 - i;
+        } else {
+            return focusIndex;
+        }
+    }
+
+    @Override
+    public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
+            RecyclerView.Adapter newAdapter) {
+        if (DEBUG) Log.v(getTag(), "onAdapterChanged to " + newAdapter);
+        if (oldAdapter != null) {
+            discardLayoutInfo();
+            mFocusPosition = NO_POSITION;
+            mFocusPositionOffset = 0;
+            mChildrenStates.clear();
+        }
+        if (newAdapter instanceof FacetProviderAdapter) {
+            mFacetProviderAdapter = (FacetProviderAdapter) newAdapter;
+        } else {
+            mFacetProviderAdapter = null;
+        }
+        super.onAdapterChanged(oldAdapter, newAdapter);
+    }
+
+    private void discardLayoutInfo() {
+        mGrid = null;
+        mRowSizeSecondary = null;
+        mFlag &= ~PF_ROW_SECONDARY_SIZE_REFRESH;
+    }
+
+    public void setLayoutEnabled(boolean layoutEnabled) {
+        if (((mFlag & PF_LAYOUT_ENABLED) != 0) != layoutEnabled) {
+            mFlag = (mFlag & ~PF_LAYOUT_ENABLED) | (layoutEnabled ? PF_LAYOUT_ENABLED : 0);
+            requestLayout();
+        }
+    }
+
+    void setChildrenVisibility(int visibility) {
+        mChildVisibility = visibility;
+        if (mChildVisibility != -1) {
+            int count = getChildCount();
+            for (int i= 0; i < count; i++) {
+                getChildAt(i).setVisibility(mChildVisibility);
+            }
+        }
+    }
+
+    final static class SavedState implements Parcelable {
+
+        int index; // index inside adapter of the current view
+        Bundle childStates = Bundle.EMPTY;
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(index);
+            out.writeBundle(childStates);
+        }
+
+        @SuppressWarnings("hiding")
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+                    @Override
+                    public SavedState createFromParcel(Parcel in) {
+                        return new SavedState(in);
+                    }
+
+                    @Override
+                    public SavedState[] newArray(int size) {
+                        return new SavedState[size];
+                    }
+                };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        SavedState(Parcel in) {
+            index = in.readInt();
+            childStates = in.readBundle(GridLayoutManager.class.getClassLoader());
+        }
+
+        SavedState() {
+        }
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        if (DEBUG) Log.v(getTag(), "onSaveInstanceState getSelection() " + getSelection());
+        SavedState ss = new SavedState();
+        // save selected index
+        ss.index = getSelection();
+        // save offscreen child (state when they are recycled)
+        Bundle bundle = mChildrenStates.saveAsBundle();
+        // save views currently is on screen (TODO save cached views)
+        for (int i = 0, count = getChildCount(); i < count; i++) {
+            View view = getChildAt(i);
+            int position = getAdapterPositionByView(view);
+            if (position != NO_POSITION) {
+                bundle = mChildrenStates.saveOnScreenView(bundle, view, position);
+            }
+        }
+        ss.childStates = bundle;
+        return ss;
+    }
+
+    void onChildRecycled(RecyclerView.ViewHolder holder) {
+        final int position = holder.getAdapterPosition();
+        if (position != NO_POSITION) {
+            mChildrenStates.saveOffscreenView(holder.itemView, position);
+        }
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (!(state instanceof SavedState)) {
+            return;
+        }
+        SavedState loadingState = (SavedState)state;
+        mFocusPosition = loadingState.index;
+        mFocusPositionOffset = 0;
+        mChildrenStates.loadFromBundle(loadingState.childStates);
+        mFlag |= PF_FORCE_FULL_LAYOUT;
+        requestLayout();
+        if (DEBUG) Log.v(getTag(), "onRestoreInstanceState mFocusPosition " + mFocusPosition);
+    }
+
+    @Override
+    public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        if (mOrientation == HORIZONTAL && mGrid != null) {
+            return mGrid.getNumRows();
+        }
+        return super.getRowCountForAccessibility(recycler, state);
+    }
+
+    @Override
+    public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        if (mOrientation == VERTICAL && mGrid != null) {
+            return mGrid.getNumRows();
+        }
+        return super.getColumnCountForAccessibility(recycler, state);
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
+            RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
+        ViewGroup.LayoutParams lp = host.getLayoutParams();
+        if (mGrid == null || !(lp instanceof LayoutParams)) {
+            return;
+        }
+        LayoutParams glp = (LayoutParams) lp;
+        int position = glp.getViewAdapterPosition();
+        int rowIndex = position >= 0 ? mGrid.getRowIndex(position) : -1;
+        if (rowIndex < 0) {
+            return;
+        }
+        int guessSpanIndex = position / mGrid.getNumRows();
+        if (mOrientation == HORIZONTAL) {
+            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
+                    rowIndex, 1, guessSpanIndex, 1, false, false));
+        } else {
+            info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(
+                    guessSpanIndex, 1, rowIndex, 1, false, false));
+        }
+    }
+
+    /*
+     * Leanback widget is different than the default implementation because the "scroll" is driven
+     * by selection change.
+     */
+    @Override
+    public boolean performAccessibilityAction(Recycler recycler, State state, int action,
+            Bundle args) {
+        saveContext(recycler, state);
+        int translatedAction = action;
+        boolean reverseFlowPrimary = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0;
+        if (Build.VERSION.SDK_INT >= 23) {
+            if (mOrientation == HORIZONTAL) {
+                if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                        .ACTION_SCROLL_LEFT.getId()) {
+                    translatedAction = reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD :
+                            AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
+                } else if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                        .ACTION_SCROLL_RIGHT.getId()) {
+                    translatedAction = reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD :
+                            AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
+                }
+            } else { // VERTICAL layout
+                if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP
+                        .getId()) {
+                    translatedAction = AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
+                } else if (action == AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                        .ACTION_SCROLL_DOWN.getId()) {
+                    translatedAction = AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
+                }
+            }
+        }
+        switch (translatedAction) {
+            case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD:
+                processPendingMovement(false);
+                processSelectionMoves(false, -1);
+                break;
+            case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD:
+                processPendingMovement(true);
+                processSelectionMoves(false, 1);
+                break;
+        }
+        leaveContext();
+        return true;
+    }
+
+    /*
+     * Move mFocusPosition multiple steps on the same row in main direction.
+     * Stops when moves are all consumed or reach first/last visible item.
+     * Returning remaining moves.
+     */
+    int processSelectionMoves(boolean preventScroll, int moves) {
+        if (mGrid == null) {
+            return moves;
+        }
+        int focusPosition = mFocusPosition;
+        int focusedRow = focusPosition != NO_POSITION
+                ? mGrid.getRowIndex(focusPosition) : NO_POSITION;
+        View newSelected = null;
+        for (int i = 0, count = getChildCount(); i < count && moves != 0; i++) {
+            int index = moves > 0 ? i : count - 1 - i;
+            final View child = getChildAt(index);
+            if (!canScrollTo(child)) {
+                continue;
+            }
+            int position = getAdapterPositionByIndex(index);
+            int rowIndex = mGrid.getRowIndex(position);
+            if (focusedRow == NO_POSITION) {
+                focusPosition = position;
+                newSelected = child;
+                focusedRow = rowIndex;
+            } else if (rowIndex == focusedRow) {
+                if ((moves > 0 && position > focusPosition)
+                        || (moves < 0 && position < focusPosition)) {
+                    focusPosition = position;
+                    newSelected = child;
+                    if (moves > 0) {
+                        moves--;
+                    } else {
+                        moves++;
+                    }
+                }
+            }
+        }
+        if (newSelected != null) {
+            if (preventScroll) {
+                if (hasFocus()) {
+                    mFlag |= PF_IN_SELECTION;
+                    newSelected.requestFocus();
+                    mFlag &= ~PF_IN_SELECTION;
+                }
+                mFocusPosition = focusPosition;
+                mSubFocusPosition = 0;
+            } else {
+                scrollToView(newSelected, true);
+            }
+        }
+        return moves;
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(Recycler recycler, State state,
+            AccessibilityNodeInfoCompat info) {
+        saveContext(recycler, state);
+        int count = state.getItemCount();
+        boolean reverseFlowPrimary = (mFlag & PF_REVERSE_FLOW_PRIMARY) != 0;
+        if (count > 1 && !isItemFullyVisible(0)) {
+            if (Build.VERSION.SDK_INT >= 23) {
+                if (mOrientation == HORIZONTAL) {
+                    info.addAction(reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_RIGHT :
+                            AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_LEFT);
+                } else {
+                    info.addAction(
+                            AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP);
+                }
+            } else {
+                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD);
+            }
+            info.setScrollable(true);
+        }
+        if (count > 1 && !isItemFullyVisible(count - 1)) {
+            if (Build.VERSION.SDK_INT >= 23) {
+                if (mOrientation == HORIZONTAL) {
+                    info.addAction(reverseFlowPrimary
+                            ? AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_LEFT :
+                            AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_RIGHT);
+                } else {
+                    info.addAction(AccessibilityNodeInfoCompat.AccessibilityActionCompat
+                                    .ACTION_SCROLL_DOWN);
+                }
+            } else {
+                info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD);
+            }
+            info.setScrollable(true);
+        }
+        final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo =
+                AccessibilityNodeInfoCompat.CollectionInfoCompat
+                        .obtain(getRowCountForAccessibility(recycler, state),
+                                getColumnCountForAccessibility(recycler, state),
+                                isLayoutHierarchical(recycler, state),
+                                getSelectionModeForAccessibility(recycler, state));
+        info.setCollectionInfo(collectionInfo);
+        leaveContext();
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidanceStylingRelativeLayout.java
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidanceStylist.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidanceStylist.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidanceStylist.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/widget/GuidedAction.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedAction.java
new file mode 100644
index 0000000..c057673
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedAction.java
@@ -0,0 +1,956 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.content.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.text.InputType;
+
+import java.util.List;
+
+/**
+ * A data class which represents an action within a {@link
+ * android.support.v17.leanback.app.GuidedStepFragment}. GuidedActions contain at minimum a title
+ * and a description, and typically also an icon.
+ * <p>
+ * A GuidedAction typically represents a single action a user may take, but may also represent a
+ * possible choice out of a group of mutually exclusive choices (similar to radio buttons), or an
+ * information-only label (in which case the item cannot be clicked).
+ * <p>
+ * GuidedActions may optionally be checked. They may also indicate that they will request further
+ * user input on selection, in which case they will be displayed with a chevron indicator.
+ * <p>
+ * GuidedAction recommends to use {@link Builder}. When application subclass GuidedAction, it
+ * can subclass {@link BuilderBase}, implement its own builder() method where it should
+ * call {@link BuilderBase#applyValues(GuidedAction)}.
+ */
+public class GuidedAction extends Action {
+
+    private static final String TAG = "GuidedAction";
+
+    /**
+     * Special check set Id that is neither checkbox nor radio.
+     */
+    public static final int NO_CHECK_SET = 0;
+    /**
+     * Default checkset Id for radio.
+     */
+    public static final int DEFAULT_CHECK_SET_ID = 1;
+    /**
+     * Checkset Id for checkbox.
+     */
+    public static final int CHECKBOX_CHECK_SET_ID = -1;
+
+    /**
+     * When finishing editing, goes to next action.
+     */
+    public static final long ACTION_ID_NEXT = -2;
+    /**
+     * When finishing editing, stay on current action.
+     */
+    public static final long ACTION_ID_CURRENT = -3;
+
+    /**
+     * Id of standard OK action.
+     */
+    public static final long ACTION_ID_OK = -4;
+
+    /**
+     * Id of standard Cancel action.
+     */
+    public static final long ACTION_ID_CANCEL = -5;
+
+    /**
+     * Id of standard Finish action.
+     */
+    public static final long ACTION_ID_FINISH = -6;
+
+    /**
+     * Id of standard Finish action.
+     */
+    public static final long ACTION_ID_CONTINUE = -7;
+
+    /**
+     * Id of standard Yes action.
+     */
+    public static final long ACTION_ID_YES = -8;
+
+    /**
+     * Id of standard No action.
+     */
+    public static final long ACTION_ID_NO = -9;
+
+    static final int EDITING_NONE = 0;
+    static final int EDITING_TITLE = 1;
+    static final int EDITING_DESCRIPTION = 2;
+    static final int EDITING_ACTIVATOR_VIEW = 3;
+
+    /**
+     * Base builder class to build a {@link GuidedAction} object.  When subclass GuidedAction, you
+     * can override this BuilderBase class, implements your build() method which should call
+     * {@link #applyValues(GuidedAction)}.  When using GuidedAction directly, use {@link Builder}.
+     */
+    public abstract static class BuilderBase<B extends BuilderBase> {
+        private Context mContext;
+        private long mId;
+        private CharSequence mTitle;
+        private CharSequence mEditTitle;
+        private CharSequence mDescription;
+        private CharSequence mEditDescription;
+        private Drawable mIcon;
+        /**
+         * The mActionFlags holds various action states such as whether title or description are
+         * editable, or the action is focusable.
+         *
+         */
+        private int mActionFlags;
+
+        private int mEditable = EDITING_NONE;
+        private int mInputType = InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
+        private int mDescriptionInputType = InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
+        private int mEditInputType = InputType.TYPE_CLASS_TEXT;
+        private int mDescriptionEditInputType = InputType.TYPE_CLASS_TEXT;
+        private int mCheckSetId = NO_CHECK_SET;
+        private List<GuidedAction> mSubActions;
+        private Intent mIntent;
+
+        /**
+         * Creates a BuilderBase for GuidedAction or its subclass.
+         * @param context Context object used to build the GuidedAction.
+         */
+        public BuilderBase(Context context) {
+            mContext = context;
+            mActionFlags = PF_ENABLED | PF_FOCUSABLE | PF_AUTORESTORE;
+        }
+
+        /**
+         * Returns Context of this Builder.
+         * @return Context of this Builder.
+         */
+        public Context getContext() {
+            return mContext;
+        }
+
+        private void setFlags(int flag, int mask) {
+            mActionFlags = (mActionFlags & ~mask) | (flag & mask);
+        }
+
+        /**
+         * Subclass of BuilderBase should call this function to apply values.
+         * @param action GuidedAction to apply BuilderBase values.
+         */
+        protected final void applyValues(GuidedAction action) {
+            // Base Action values
+            action.setId(mId);
+            action.setLabel1(mTitle);
+            action.setEditTitle(mEditTitle);
+            action.setLabel2(mDescription);
+            action.setEditDescription(mEditDescription);
+            action.setIcon(mIcon);
+
+            // Subclass values
+            action.mIntent = mIntent;
+            action.mEditable = mEditable;
+            action.mInputType = mInputType;
+            action.mDescriptionInputType = mDescriptionInputType;
+            action.mEditInputType = mEditInputType;
+            action.mDescriptionEditInputType = mDescriptionEditInputType;
+            action.mActionFlags = mActionFlags;
+            action.mCheckSetId = mCheckSetId;
+            action.mSubActions = mSubActions;
+        }
+
+        /**
+         * Construct a clickable action with associated id and auto assign pre-defined title for the
+         * action. If the id is not supported, the method simply does nothing.
+         * @param id One of {@link GuidedAction#ACTION_ID_OK} {@link GuidedAction#ACTION_ID_CANCEL}
+         * {@link GuidedAction#ACTION_ID_FINISH} {@link GuidedAction#ACTION_ID_CONTINUE}
+         * {@link GuidedAction#ACTION_ID_YES} {@link GuidedAction#ACTION_ID_NO}.
+         * @return The same BuilderBase object.
+         */
+        public B clickAction(long id) {
+            if (id == ACTION_ID_OK) {
+                mId = ACTION_ID_OK;
+                mTitle = mContext.getString(android.R.string.ok);
+            } else if (id == ACTION_ID_CANCEL) {
+                mId = ACTION_ID_CANCEL;
+                mTitle = mContext.getString(android.R.string.cancel);
+            } else if (id == ACTION_ID_FINISH) {
+                mId = ACTION_ID_FINISH;
+                mTitle = mContext.getString(R.string.lb_guidedaction_finish_title);
+            } else if (id == ACTION_ID_CONTINUE) {
+                mId = ACTION_ID_CONTINUE;
+                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.ok);
+            } else if (id == ACTION_ID_NO) {
+                mId = ACTION_ID_NO;
+                mTitle = mContext.getString(android.R.string.cancel);
+            }
+            return (B) this;
+        }
+
+        /**
+         * Sets the ID associated with this action.  The ID can be any value the client wishes;
+         * it is typically used to determine what to do when an action is clicked.
+         * @param id The ID to associate with this action.
+         */
+        public B id(long id) {
+            mId = id;
+            return (B) this;
+        }
+
+        /**
+         * Sets the title for this action.  The title is typically a short string indicating the
+         * action to be taken on click, e.g. "Continue" or "Cancel".
+         * @param title The title for this action.
+         */
+        public B title(CharSequence title) {
+            mTitle = title;
+            return (B) this;
+        }
+
+        /**
+         * Sets the title for this action.  The title is typically a short string indicating the
+         * action to be taken on click, e.g. "Continue" or "Cancel".
+         * @param titleResourceId The resource id of title for this action.
+         */
+        public B title(@StringRes int titleResourceId) {
+            mTitle = getContext().getString(titleResourceId);
+            return (B) this;
+        }
+
+        /**
+         * Sets the optional title text to edit.  When TextView is activated, the edit title
+         * replaces the string of title.
+         * @param editTitle The optional title text to edit when TextView is activated.
+         */
+        public B editTitle(CharSequence editTitle) {
+            mEditTitle = editTitle;
+            return (B) this;
+        }
+
+        /**
+         * Sets the optional title text to edit.  When TextView is activated, the edit title
+         * replaces the string of title.
+         * @param editTitleResourceId String resource id of the optional title text to edit when
+         * TextView is activated.
+         */
+        public B editTitle(@StringRes int editTitleResourceId) {
+            mEditTitle = getContext().getString(editTitleResourceId);
+            return (B) this;
+        }
+
+        /**
+         * Sets the description for this action.  The description is typically a longer string
+         * providing extra information on what the action will do.
+         * @param description The description for this action.
+         */
+        public B description(CharSequence description) {
+            mDescription = description;
+            return (B) this;
+        }
+
+        /**
+         * Sets the description for this action.  The description is typically a longer string
+         * providing extra information on what the action will do.
+         * @param descriptionResourceId String resource id of the description for this action.
+         */
+        public B description(@StringRes int descriptionResourceId) {
+            mDescription = getContext().getString(descriptionResourceId);
+            return (B) this;
+        }
+
+        /**
+         * Sets the optional description text to edit.  When TextView is activated, the edit
+         * description replaces the string of description.
+         * @param description The description to edit for this action.
+         */
+        public B editDescription(CharSequence description) {
+            mEditDescription = description;
+            return (B) this;
+        }
+
+        /**
+         * Sets the optional description text to edit.  When TextView is activated, the edit
+         * description replaces the string of description.
+         * @param descriptionResourceId String resource id of the description to edit for this
+         * action.
+         */
+        public B editDescription(@StringRes int descriptionResourceId) {
+            mEditDescription = getContext().getString(descriptionResourceId);
+            return (B) this;
+        }
+
+        /**
+         * Sets the intent associated with this action.  Clients would typically fire this intent
+         * directly when the action is clicked.
+         * @param intent The intent associated with this action.
+         */
+        public B intent(Intent intent) {
+            mIntent = intent;
+            return (B) this;
+        }
+
+        /**
+         * Sets the action's icon drawable.
+         * @param icon The drawable for the icon associated with this action.
+         */
+        public B icon(Drawable icon) {
+            mIcon = icon;
+            return (B) this;
+        }
+
+        /**
+         * Sets the action's icon drawable by retrieving it by resource ID from the specified
+         * context. This is a convenience function that simply looks up the drawable and calls
+         * {@link #icon(Drawable)}.
+         * @param iconResourceId The resource ID for the icon associated with this action.
+         * @param context The context whose resource ID should be retrieved.
+         * @deprecated Use {@link #icon(int)}.
+         */
+        @Deprecated
+        public B iconResourceId(@DrawableRes int iconResourceId, Context context) {
+            return icon(ContextCompat.getDrawable(context, iconResourceId));
+        }
+
+        /**
+         * Sets the action's icon drawable by retrieving it by resource ID from Builder's
+         * context. This is a convenience function that simply looks up the drawable and calls
+         * {@link #icon(Drawable)}.
+         * @param iconResourceId The resource ID for the icon associated with this action.
+         */
+        public B icon(@DrawableRes int iconResourceId) {
+            return icon(ContextCompat.getDrawable(getContext(), iconResourceId));
+        }
+
+        /**
+         * Indicates whether this action title is editable. Note: Editable actions cannot also be
+         * checked, or belong to a check set.
+         * @param editable Whether this action is editable.
+         */
+        public B editable(boolean editable) {
+            if (!editable) {
+                if (mEditable == EDITING_TITLE) {
+                    mEditable = EDITING_NONE;
+                }
+                return (B) this;
+            }
+            mEditable = EDITING_TITLE;
+            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
+                throw new IllegalArgumentException("Editable actions cannot also be checked");
+            }
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether this action's description is editable
+         * @param editable Whether this action description is editable.
+         */
+        public B descriptionEditable(boolean editable) {
+            if (!editable) {
+                if (mEditable == EDITING_DESCRIPTION) {
+                    mEditable = EDITING_NONE;
+                }
+                return (B) this;
+            }
+            mEditable = EDITING_DESCRIPTION;
+            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
+                throw new IllegalArgumentException("Editable actions cannot also be checked");
+            }
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether this action has a view can be activated to edit, e.g. a DatePicker.
+         * @param editable Whether this action has view can be activated to edit.
+         */
+        public B hasEditableActivatorView(boolean editable) {
+            if (!editable) {
+                if (mEditable == EDITING_ACTIVATOR_VIEW) {
+                    mEditable = EDITING_NONE;
+                }
+                return (B) this;
+            }
+            mEditable = EDITING_ACTIVATOR_VIEW;
+            if (isChecked() || mCheckSetId != NO_CHECK_SET) {
+                throw new IllegalArgumentException("Editable actions cannot also be checked");
+            }
+            return (B) this;
+        }
+
+        /**
+         * Sets {@link InputType} of this action title not in editing.
+         *
+         * @param inputType InputType for the action title not in editing.
+         */
+        public B inputType(int inputType) {
+            mInputType = inputType;
+            return (B) this;
+        }
+
+        /**
+         * Sets {@link InputType} of this action description not in editing.
+         *
+         * @param inputType InputType for the action description not in editing.
+         */
+        public B descriptionInputType(int inputType) {
+            mDescriptionInputType = inputType;
+            return (B) this;
+        }
+
+
+        /**
+         * Sets {@link InputType} of this action title in editing.
+         *
+         * @param inputType InputType for the action title in editing.
+         */
+        public B editInputType(int inputType) {
+            mEditInputType = inputType;
+            return (B) this;
+        }
+
+        /**
+         * Sets {@link InputType} of this action description in editing.
+         *
+         * @param inputType InputType for the action description in editing.
+         */
+        public B descriptionEditInputType(int inputType) {
+            mDescriptionEditInputType = inputType;
+            return (B) this;
+        }
+
+
+        private boolean isChecked() {
+            return (mActionFlags & PF_CHECKED) == PF_CHECKED;
+        }
+        /**
+         * Indicates whether this action is initially checked.
+         * @param checked Whether this action is checked.
+         */
+        public B checked(boolean checked) {
+            setFlags(checked ? PF_CHECKED : 0, PF_CHECKED);
+            if (mEditable != EDITING_NONE) {
+                throw new IllegalArgumentException("Editable actions cannot also be checked");
+            }
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether this action is part of a single-select group similar to radio buttons
+         * or this action is a checkbox. When one item in a check set is checked, all others with
+         * the same check set ID will be checked automatically.
+         * @param checkSetId The check set ID, or {@link GuidedAction#NO_CHECK_SET} to indicate not
+         * radio or checkbox, or {@link GuidedAction#CHECKBOX_CHECK_SET_ID} to indicate a checkbox.
+         */
+        public B checkSetId(int checkSetId) {
+            mCheckSetId = checkSetId;
+            if (mEditable != EDITING_NONE) {
+                throw new IllegalArgumentException("Editable actions cannot also be in check sets");
+            }
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether the title and description are long, and should be displayed
+         * appropriately.
+         * @param multilineDescription Whether this action has a multiline description.
+         */
+        public B multilineDescription(boolean multilineDescription) {
+            setFlags(multilineDescription ? PF_MULTI_LINE_DESCRIPTION : 0,
+                PF_MULTI_LINE_DESCRIPTION);
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether this action has a next state and should display a chevron.
+         * @param hasNext Whether this action has a next state.
+         */
+        public B hasNext(boolean hasNext) {
+            setFlags(hasNext ? PF_HAS_NEXT : 0, PF_HAS_NEXT);
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether this action is for information purposes only and cannot be clicked.
+         * @param infoOnly Whether this action has a next state.
+         */
+        public B infoOnly(boolean infoOnly) {
+            setFlags(infoOnly ? PF_INFO_ONLY : 0, PF_INFO_ONLY);
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether this action is enabled.  If not enabled, an action cannot be clicked.
+         * @param enabled Whether the action is enabled.
+         */
+        public B enabled(boolean enabled) {
+            setFlags(enabled ? PF_ENABLED : 0, PF_ENABLED);
+            return (B) this;
+        }
+
+        /**
+         * Indicates whether this action can take focus.
+         * @param focusable
+         * @return The same BuilderBase object.
+         */
+        public B focusable(boolean focusable) {
+            setFlags(focusable ? PF_FOCUSABLE : 0, PF_FOCUSABLE);
+            return (B) this;
+        }
+
+        /**
+         * Sets sub actions list.
+         * @param subActions
+         * @return The same BuilderBase object.
+         */
+        public B subActions(List<GuidedAction> subActions) {
+            mSubActions = subActions;
+            return (B) this;
+        }
+
+        /**
+         * Explicitly sets auto restore feature on the GuidedAction.  It's by default true.
+         * @param autoSaveRestoreEnabled True if turn on auto save/restore of GuidedAction content,
+         *                                false otherwise.
+         * @return The same BuilderBase object.
+         * @see GuidedAction#isAutoSaveRestoreEnabled()
+         */
+        public B autoSaveRestoreEnabled(boolean autoSaveRestoreEnabled) {
+            setFlags(autoSaveRestoreEnabled ? PF_AUTORESTORE : 0, PF_AUTORESTORE);
+            return (B) this;
+        }
+
+    }
+
+    /**
+     * Builds a {@link GuidedAction} object.
+     */
+    public static class Builder extends BuilderBase<Builder> {
+
+        /**
+         * @deprecated Use {@link GuidedAction.Builder#GuidedAction.Builder(Context)}.
+         */
+        @Deprecated
+        public Builder() {
+            super(null);
+        }
+
+        /**
+         * Creates a Builder for GuidedAction.
+         * @param context Context to build GuidedAction.
+         */
+        public Builder(Context context) {
+            super(context);
+        }
+
+        /**
+         * Builds the GuidedAction corresponding to this Builder.
+         * @return The GuidedAction as configured through this Builder.
+         */
+        public GuidedAction build() {
+            GuidedAction action = new GuidedAction();
+            applyValues(action);
+            return action;
+        }
+
+    }
+
+    static final int PF_CHECKED = 0x00000001;
+    static final int PF_MULTI_LINE_DESCRIPTION = 0x00000002;
+    static final int PF_HAS_NEXT = 0x00000004;
+    static final int PF_INFO_ONLY = 0x00000008;
+    static final int PF_ENABLED = 0x00000010;
+    static final int PF_FOCUSABLE = 0x00000020;
+    static final int PF_AUTORESTORE = 0x00000040;
+    int mActionFlags;
+
+    private CharSequence mEditTitle;
+    private CharSequence mEditDescription;
+    int mEditable;
+    int mInputType;
+    int mDescriptionInputType;
+    int mEditInputType;
+    int mDescriptionEditInputType;
+
+    int mCheckSetId;
+
+    List<GuidedAction> mSubActions;
+
+    Intent mIntent;
+
+    protected GuidedAction() {
+        super(0);
+    }
+
+    private void setFlags(int flag, int mask) {
+        mActionFlags = (mActionFlags & ~mask) | (flag & mask);
+    }
+
+    /**
+     * Returns the title of this action.
+     * @return The title set when this action was built.
+     */
+    public CharSequence getTitle() {
+        return getLabel1();
+    }
+
+    /**
+     * Sets the title of this action.
+     * @param title The title set when this action was built.
+     */
+    public void setTitle(CharSequence title) {
+        setLabel1(title);
+    }
+
+    /**
+     * Returns the optional title text to edit.  When not null, it is being edited instead of
+     * {@link #getTitle()}.
+     * @return Optional title text to edit instead of {@link #getTitle()}.
+     */
+    public CharSequence getEditTitle() {
+        return mEditTitle;
+    }
+
+    /**
+     * Sets the optional title text to edit instead of {@link #setTitle(CharSequence)}.
+     * @param editTitle Optional title text to edit instead of {@link #setTitle(CharSequence)}.
+     */
+    public void setEditTitle(CharSequence editTitle) {
+        mEditTitle = editTitle;
+    }
+
+    /**
+     * Returns the optional description text to edit.  When not null, it is being edited instead of
+     * {@link #getDescription()}.
+     * @return Optional description text to edit instead of {@link #getDescription()}.
+     */
+    public CharSequence getEditDescription() {
+        return mEditDescription;
+    }
+
+    /**
+     * Sets the optional description text to edit instead of {@link #setDescription(CharSequence)}.
+     * @param editDescription Optional description text to edit instead of
+     * {@link #setDescription(CharSequence)}.
+     */
+    public void setEditDescription(CharSequence editDescription) {
+        mEditDescription = editDescription;
+    }
+
+    /**
+     * Returns true if {@link #getEditTitle()} is not null.  When true, the {@link #getEditTitle()}
+     * is being edited instead of {@link #getTitle()}.
+     * @return true if {@link #getEditTitle()} is not null.
+     */
+    public boolean isEditTitleUsed() {
+        return mEditTitle != null;
+    }
+
+    /**
+     * Returns the description of this action.
+     * @return The description of this action.
+     */
+    public CharSequence getDescription() {
+        return getLabel2();
+    }
+
+    /**
+     * Sets the description of this action.
+     * @param description The description of the action.
+     */
+    public void setDescription(CharSequence description) {
+        setLabel2(description);
+    }
+
+    /**
+     * Returns the intent associated with this action.
+     * @return The intent set when this action was built.
+     */
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    /**
+     * Sets the intent of this action.
+     * @param intent New intent to set on this action.
+     */
+    public void setIntent(Intent intent) {
+        mIntent = intent;
+    }
+
+    /**
+     * Returns whether this action title is editable.
+     * @return true if the action title is editable, false otherwise.
+     */
+    public boolean isEditable() {
+        return mEditable == EDITING_TITLE;
+    }
+
+    /**
+     * Returns whether this action description is editable.
+     * @return true if the action description is editable, false otherwise.
+     */
+    public boolean isDescriptionEditable() {
+        return mEditable == EDITING_DESCRIPTION;
+    }
+
+    /**
+     * Returns if this action has editable title or editable description.
+     * @return True if this action has editable title or editable description, false otherwise.
+     */
+    public boolean hasTextEditable() {
+        return mEditable == EDITING_TITLE || mEditable == EDITING_DESCRIPTION;
+    }
+
+    /**
+     * Returns whether this action can be activated to edit, e.g. a DatePicker.
+     * @return true if the action can be activated to edit.
+     */
+    public boolean hasEditableActivatorView() {
+        return mEditable == EDITING_ACTIVATOR_VIEW;
+    }
+
+    /**
+     * Returns InputType of action title in editing; only valid when {@link #isEditable()} is true.
+     * @return InputType of action title in editing.
+     */
+    public int getEditInputType() {
+        return mEditInputType;
+    }
+
+    /**
+     * Returns InputType of action description in editing; only valid when
+     * {@link #isDescriptionEditable()} is true.
+     * @return InputType of action description in editing.
+     */
+    public int getDescriptionEditInputType() {
+        return mDescriptionEditInputType;
+    }
+
+    /**
+     * Returns InputType of action title not in editing.
+     * @return InputType of action title not in editing.
+     */
+    public int getInputType() {
+        return mInputType;
+    }
+
+    /**
+     * Returns InputType of action description not in editing.
+     * @return InputType of action description not in editing.
+     */
+    public int getDescriptionInputType() {
+        return mDescriptionInputType;
+    }
+
+    /**
+     * Returns whether this action is checked.
+     * @return true if the action is currently checked, false otherwise.
+     */
+    public boolean isChecked() {
+        return (mActionFlags & PF_CHECKED) == PF_CHECKED;
+    }
+
+    /**
+     * Sets whether this action is checked.
+     * @param checked Whether this action should be checked.
+     */
+    public void setChecked(boolean checked) {
+        setFlags(checked ? PF_CHECKED : 0, PF_CHECKED);
+    }
+
+    /**
+     * Returns the check set id this action is a part of. All actions in the same list with the same
+     * check set id are considered linked. When one of the actions within that set is selected, that
+     * action becomes checked, while all the other actions become unchecked.
+     *
+     * @return an integer representing the check set this action is a part of, or
+     *         {@link #CHECKBOX_CHECK_SET_ID} if this is a checkbox, or {@link #NO_CHECK_SET} if
+     *         this action is not a checkbox or radiobutton.
+     */
+    public int getCheckSetId() {
+        return mCheckSetId;
+    }
+
+    /**
+     * Returns whether this action is has a multiline description.
+     * @return true if the action was constructed as having a multiline description, false
+     * otherwise.
+     */
+    public boolean hasMultilineDescription() {
+        return (mActionFlags & PF_MULTI_LINE_DESCRIPTION) == PF_MULTI_LINE_DESCRIPTION;
+    }
+
+    /**
+     * Returns whether this action is enabled.
+     * @return true if the action is currently enabled, false otherwise.
+     */
+    public boolean isEnabled() {
+        return (mActionFlags & PF_ENABLED) == PF_ENABLED;
+    }
+
+    /**
+     * Sets whether this action is enabled.
+     * @param enabled Whether this action should be enabled.
+     */
+    public void setEnabled(boolean enabled) {
+        setFlags(enabled ? PF_ENABLED : 0, PF_ENABLED);
+    }
+
+    /**
+     * Returns whether this action is focusable.
+     * @return true if the action is currently focusable, false otherwise.
+     */
+    public boolean isFocusable() {
+        return (mActionFlags & PF_FOCUSABLE) == PF_FOCUSABLE;
+    }
+
+    /**
+     * Sets whether this action is focusable.
+     * @param focusable Whether this action should be focusable.
+     */
+    public void setFocusable(boolean focusable) {
+        setFlags(focusable ? PF_FOCUSABLE : 0, PF_FOCUSABLE);
+    }
+
+    /**
+     * Returns whether this action will request further user input when selected, such as showing
+     * another GuidedStepFragment or launching a new activity. Configured during construction.
+     * @return true if the action will request further user input when selected, false otherwise.
+     */
+    public boolean hasNext() {
+        return (mActionFlags & PF_HAS_NEXT) == PF_HAS_NEXT;
+    }
+
+    /**
+     * Returns whether the action will only display information and is thus not clickable. If both
+     * this and {@link #hasNext()} are true, infoOnly takes precedence. The default is false. For
+     * example, this might represent e.g. the amount of storage a document uses, or the cost of an
+     * app.
+     * @return true if will only display information, false otherwise.
+     */
+    public boolean infoOnly() {
+        return (mActionFlags & PF_INFO_ONLY) == PF_INFO_ONLY;
+    }
+
+    /**
+     * Change sub actions list.
+     * @param actions Sub actions list to set on this action.  Sets null to disable sub actions.
+     */
+    public void setSubActions(List<GuidedAction> actions) {
+        mSubActions = actions;
+    }
+
+    /**
+     * @return List of sub actions or null if sub actions list is not enabled.
+     */
+    public List<GuidedAction> getSubActions() {
+        return mSubActions;
+    }
+
+    /**
+     * @return True if has sub actions list, even it's currently empty.
+     */
+    public boolean hasSubActions() {
+        return mSubActions != null;
+    }
+
+    /**
+     * Returns true if Action will be saved to instanceState and restored later, false otherwise.
+     * The default value is true.  When isAutoSaveRestoreEnabled() is true and {@link #getId()} is
+     * not {@link #NO_ID}:
+     * <li>{@link #isEditable()} is true: save text of {@link #getTitle()}</li>
+     * <li>{@link #isDescriptionEditable()} is true: save text of {@link #getDescription()}</li>
+     * <li>{@link #getCheckSetId()} is not {@link #NO_CHECK_SET}: save {@link #isChecked()}}</li>
+     * <li>{@link GuidedDatePickerAction} will be saved</li>
+     * App may explicitly disable auto restore and handle by itself. App should override Fragment
+     * onSaveInstanceState() and onCreateActions()
+     * @return True if Action will be saved to instanceState and restored later, false otherwise.
+     */
+    public final boolean isAutoSaveRestoreEnabled() {
+        return (mActionFlags & PF_AUTORESTORE) == PF_AUTORESTORE;
+    }
+
+    /**
+     * Save action into a bundle using a given key. When isAutoRestoreEna() is true:
+     * <li>{@link #isEditable()} is true: save text of {@link #getTitle()}</li>
+     * <li>{@link #isDescriptionEditable()} is true: save text of {@link #getDescription()}</li>
+     * <li>{@link #getCheckSetId()} is not {@link #NO_CHECK_SET}: save {@link #isChecked()}}</li>
+     * <li>{@link GuidedDatePickerAction} will be saved</li>
+     * Subclass may override this method.
+     * @param bundle  Bundle to save the Action.
+     * @param key Key used to save the Action.
+     */
+    public void onSaveInstanceState(Bundle bundle, String key) {
+        if (needAutoSaveTitle() && getTitle() != null) {
+            bundle.putString(key, getTitle().toString());
+        } else if (needAutoSaveDescription() && getDescription() != null) {
+            bundle.putString(key, getDescription().toString());
+        } else if (getCheckSetId() != NO_CHECK_SET) {
+            bundle.putBoolean(key, isChecked());
+        }
+    }
+
+    /**
+     * Restore action from a bundle using a given key. When isAutoRestore() is true:
+     * <li>{@link #isEditable()} is true: save text of {@link #getTitle()}</li>
+     * <li>{@link #isDescriptionEditable()} is true: save text of {@link #getDescription()}</li>
+     * <li>{@link #getCheckSetId()} is not {@link #NO_CHECK_SET}: save {@link #isChecked()}}</li>
+     * <li>{@link GuidedDatePickerAction} will be saved</li>
+     * Subclass may override this method.
+     * @param bundle  Bundle to restore the Action from.
+     * @param key Key used to restore the Action.
+     */
+    public void onRestoreInstanceState(Bundle bundle, String key) {
+        if (needAutoSaveTitle()) {
+            String title = bundle.getString(key);
+            if (title != null) {
+                setTitle(title);
+            }
+        } else if (needAutoSaveDescription()) {
+            String description = bundle.getString(key);
+            if (description != null) {
+                setDescription(description);
+            }
+        } else if (getCheckSetId() != NO_CHECK_SET) {
+            setChecked(bundle.getBoolean(key, isChecked()));
+        }
+    }
+
+    static boolean isPasswordVariant(int inputType) {
+        final int variation = inputType & InputType.TYPE_MASK_VARIATION;
+        return variation == InputType.TYPE_TEXT_VARIATION_PASSWORD
+                || variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+                || variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD;
+    }
+
+    final boolean needAutoSaveTitle() {
+        return isEditable() && !isPasswordVariant(getEditInputType());
+    }
+
+    final boolean needAutoSaveDescription() {
+        return isDescriptionEditable() && !isPasswordVariant(getDescriptionEditInputType());
+    }
+
+}
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidedActionAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionAdapterGroup.java
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionDiffCallback.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionDiffCallback.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidedActionDiffCallback.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionDiffCallback.java
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionEditText.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidedActionEditText.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionEditText.java
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionItemContainer.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionItemContainer.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidedActionItemContainer.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionItemContainer.java
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedActionsRelativeLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionsRelativeLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidedActionsRelativeLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionsRelativeLayout.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionsStylist.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionsStylist.java
new file mode 100644
index 0000000..00d598f
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedActionsStylist.java
@@ -0,0 +1,1523 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_ACTIVATOR_VIEW;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_DESCRIPTION;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_NONE;
+import static android.support.v17.leanback.widget.GuidedAction.EDITING_TITLE;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build.VERSION;
+import android.support.annotation.CallSuper;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.transition.TransitionEpicenterCallback;
+import android.support.v17.leanback.transition.TransitionHelper;
+import android.support.v17.leanback.transition.TransitionListener;
+import android.support.v17.leanback.widget.GuidedActionAdapter.EditListener;
+import android.support.v17.leanback.widget.picker.DatePicker;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.RecyclerView;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.AccessibilityDelegate;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Checkable;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * GuidedActionsStylist is used within a {@link android.support.v17.leanback.app.GuidedStepFragment}
+ * to supply the right-side panel where users can take actions. It consists of a container for the
+ * list of actions, and a stationary selector view that indicates visually the location of focus.
+ * GuidedActionsStylist has two different layouts: default is for normal actions including text,
+ * radio, checkbox, DatePicker, etc, the other when {@link #setAsButtonActions()} is called is
+ * recommended for button actions such as "yes", "no".
+ * <p>
+ * Many aspects of the base GuidedActionsStylist can be customized through theming; see the
+ * theme attributes below. Note that these attributes are not set on individual elements in layout
+ * XML, but instead would be set in a custom theme. See
+ * <a href="http://developer.android.com/guide/topics/ui/themes.html">Styles and Themes</a>
+ * for more information.
+ * <p>
+ * If these hooks are insufficient, this class may also be subclassed. Subclasses may wish to
+ * override the {@link #onProvideLayoutId} method to change the layout used to display the
+ * list container and selector; override {@link #onProvideItemLayoutId(int)} and
+ * {@link #getItemViewType(GuidedAction)} method to change the layout used to display each action.
+ * <p>
+ * To support a "click to activate" view similar to DatePicker, app needs:
+ * <li> Override {@link #onProvideItemLayoutId(int)} and {@link #getItemViewType(GuidedAction)},
+ * provides a layout id for the action.
+ * <li> The layout must include a widget with id "guidedactions_activator_item", the widget is
+ * toggled edit mode by {@link View#setActivated(boolean)}.
+ * <li> Override {@link #onBindActivatorView(ViewHolder, GuidedAction)} to populate values into View.
+ * <li> Override {@link #onUpdateActivatorView(ViewHolder, GuidedAction)} to update action.
+ * <p>
+ * Note: If an alternate list layout is provided, the following view IDs must be supplied:
+ * <ul>
+ * <li>{@link android.support.v17.leanback.R.id#guidedactions_list}</li>
+ * </ul><p>
+ * These view IDs must be present in order for the stylist to function. The list ID must correspond
+ * to a {@link VerticalGridView} or subclass.
+ * <p>
+ * If an alternate item layout is provided, the following view IDs should be used to refer to base
+ * elements:
+ * <ul>
+ * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_content}</li>
+ * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_title}</li>
+ * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_description}</li>
+ * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_icon}</li>
+ * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_checkmark}</li>
+ * <li>{@link android.support.v17.leanback.R.id#guidedactions_item_chevron}</li>
+ * </ul><p>
+ * These view IDs are allowed to be missing, in which case the corresponding views in {@link
+ * GuidedActionsStylist.ViewHolder} will be null.
+ * <p>
+ * In order to support editable actions, the view associated with guidedactions_item_title should
+ * be a subclass of {@link android.widget.EditText}, and should satisfy the {@link
+ * ImeKeyMonitor} interface.
+ *
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeAppearingAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedStepImeDisappearingAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsSelectorDrawable
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionsListStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedSubActionsListStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedButtonActionsListStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContainerStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemCheckmarkStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemIconStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemContentStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemTitleStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemDescriptionStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionItemChevronStyle
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionPressedAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionUnpressedAnimation
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionEnabledChevronAlpha
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDisabledChevronAlpha
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMinLines
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionTitleMaxLines
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionDescriptionMinLines
+ * @attr ref android.support.v17.leanback.R.styleable#LeanbackGuidedStepTheme_guidedActionVerticalPadding
+ * @see android.R.styleable#Theme_listChoiceIndicatorSingle
+ * @see android.R.styleable#Theme_listChoiceIndicatorMultiple
+ * @see android.support.v17.leanback.app.GuidedStepFragment
+ * @see GuidedAction
+ */
+public class GuidedActionsStylist implements FragmentAnimationProvider {
+
+    /**
+     * Default viewType that associated with default layout Id for the action item.
+     * @see #getItemViewType(GuidedAction)
+     * @see #onProvideItemLayoutId(int)
+     * @see #onCreateViewHolder(ViewGroup, int)
+     */
+    public static final int VIEW_TYPE_DEFAULT = 0;
+
+    /**
+     * ViewType for DatePicker.
+     */
+    public static final int VIEW_TYPE_DATE_PICKER = 1;
+
+    final static ItemAlignmentFacet sGuidedActionItemAlignFacet;
+
+    static {
+        sGuidedActionItemAlignFacet = new ItemAlignmentFacet();
+        ItemAlignmentFacet.ItemAlignmentDef alignedDef = new ItemAlignmentFacet.ItemAlignmentDef();
+        alignedDef.setItemAlignmentViewId(R.id.guidedactions_item_title);
+        alignedDef.setAlignedToTextViewBaseline(true);
+        alignedDef.setItemAlignmentOffset(0);
+        alignedDef.setItemAlignmentOffsetWithPadding(true);
+        alignedDef.setItemAlignmentOffsetPercent(0);
+        sGuidedActionItemAlignFacet.setAlignmentDefs(new ItemAlignmentFacet.ItemAlignmentDef[]{alignedDef});
+    }
+
+    /**
+     * ViewHolder caches information about the action item layouts' subviews. Subclasses of {@link
+     * GuidedActionsStylist} may also wish to subclass this in order to add fields.
+     * @see GuidedAction
+     */
+    public static class ViewHolder extends RecyclerView.ViewHolder implements FacetProvider {
+
+        GuidedAction mAction;
+        private View mContentView;
+        TextView mTitleView;
+        TextView mDescriptionView;
+        View mActivatorView;
+        ImageView mIconView;
+        ImageView mCheckmarkView;
+        ImageView mChevronView;
+        int mEditingMode = EDITING_NONE;
+        private final boolean mIsSubAction;
+        Animator mPressAnimator;
+
+        final AccessibilityDelegate mDelegate = new AccessibilityDelegate() {
+            @Override
+            public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
+                super.onInitializeAccessibilityEvent(host, event);
+                event.setChecked(mAction != null && mAction.isChecked());
+            }
+
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.setCheckable(
+                        mAction != null && mAction.getCheckSetId() != GuidedAction.NO_CHECK_SET);
+                info.setChecked(mAction != null && mAction.isChecked());
+            }
+        };
+
+        /**
+         * Constructs an ViewHolder and caches the relevant subviews.
+         */
+        public ViewHolder(View v) {
+            this(v, false);
+        }
+
+        /**
+         * Constructs an ViewHolder for sub action and caches the relevant subviews.
+         */
+        public ViewHolder(View v, boolean isSubAction) {
+            super(v);
+
+            mContentView = v.findViewById(R.id.guidedactions_item_content);
+            mTitleView = (TextView) v.findViewById(R.id.guidedactions_item_title);
+            mActivatorView = v.findViewById(R.id.guidedactions_activator_item);
+            mDescriptionView = (TextView) v.findViewById(R.id.guidedactions_item_description);
+            mIconView = (ImageView) v.findViewById(R.id.guidedactions_item_icon);
+            mCheckmarkView = (ImageView) v.findViewById(R.id.guidedactions_item_checkmark);
+            mChevronView = (ImageView) v.findViewById(R.id.guidedactions_item_chevron);
+            mIsSubAction = isSubAction;
+
+            v.setAccessibilityDelegate(mDelegate);
+        }
+
+        /**
+         * Returns the content view within this view holder's view, where title and description are
+         * shown.
+         */
+        public View getContentView() {
+            return mContentView;
+        }
+
+        /**
+         * Returns the title view within this view holder's view.
+         */
+        public TextView getTitleView() {
+            return mTitleView;
+        }
+
+        /**
+         * Convenience method to return an editable version of the title, if possible,
+         * or null if the title view isn't an EditText.
+         */
+        public EditText getEditableTitleView() {
+            return (mTitleView instanceof EditText) ? (EditText)mTitleView : null;
+        }
+
+        /**
+         * Returns the description view within this view holder's view.
+         */
+        public TextView getDescriptionView() {
+            return mDescriptionView;
+        }
+
+        /**
+         * Convenience method to return an editable version of the description, if possible,
+         * or null if the description view isn't an EditText.
+         */
+        public EditText getEditableDescriptionView() {
+            return (mDescriptionView instanceof EditText) ? (EditText)mDescriptionView : null;
+        }
+
+        /**
+         * Returns the icon view within this view holder's view.
+         */
+        public ImageView getIconView() {
+            return mIconView;
+        }
+
+        /**
+         * Returns the checkmark view within this view holder's view.
+         */
+        public ImageView getCheckmarkView() {
+            return mCheckmarkView;
+        }
+
+        /**
+         * Returns the chevron view within this view holder's view.
+         */
+        public ImageView getChevronView() {
+            return mChevronView;
+        }
+
+        /**
+         * Returns true if in editing title, description, or activator View, false otherwise.
+         */
+        public boolean isInEditing() {
+            return mEditingMode != EDITING_NONE;
+        }
+
+        /**
+         * Returns true if in editing title, description, so IME would be open.
+         * @return True if in editing title, description, so IME would be open, false otherwise.
+         */
+        public boolean isInEditingText() {
+            return mEditingMode == EDITING_TITLE || mEditingMode == EDITING_DESCRIPTION;
+        }
+
+        /**
+         * Returns true if the TextView is in editing title, false otherwise.
+         */
+        public boolean isInEditingTitle() {
+            return mEditingMode == EDITING_TITLE;
+        }
+
+        /**
+         * Returns true if the TextView is in editing description, false otherwise.
+         */
+        public boolean isInEditingDescription() {
+            return mEditingMode == EDITING_DESCRIPTION;
+        }
+
+        /**
+         * Returns true if is in editing activator view with id guidedactions_activator_item, false
+         * otherwise.
+         */
+        public boolean isInEditingActivatorView() {
+            return mEditingMode == EDITING_ACTIVATOR_VIEW;
+        }
+
+        /**
+         * @return Current editing title view or description view or activator view or null if not
+         * in editing.
+         */
+        public View getEditingView() {
+            switch(mEditingMode) {
+            case EDITING_TITLE:
+                return mTitleView;
+            case EDITING_DESCRIPTION:
+                return mDescriptionView;
+            case EDITING_ACTIVATOR_VIEW:
+                return mActivatorView;
+            case EDITING_NONE:
+            default:
+                return null;
+            }
+        }
+
+        /**
+         * @return True if bound action is inside {@link GuidedAction#getSubActions()}, false
+         * otherwise.
+         */
+        public boolean isSubAction() {
+            return mIsSubAction;
+        }
+
+        /**
+         * @return Currently bound action.
+         */
+        public GuidedAction getAction() {
+            return mAction;
+        }
+
+        void setActivated(boolean activated) {
+            mActivatorView.setActivated(activated);
+            if (itemView instanceof GuidedActionItemContainer) {
+                ((GuidedActionItemContainer) itemView).setFocusOutAllowed(!activated);
+            }
+        }
+
+        @Override
+        public Object getFacet(Class<?> facetClass) {
+            if (facetClass == ItemAlignmentFacet.class) {
+                return sGuidedActionItemAlignFacet;
+            }
+            return null;
+        }
+
+        void press(boolean pressed) {
+            if (mPressAnimator != null) {
+                mPressAnimator.cancel();
+                mPressAnimator = null;
+            }
+            final int themeAttrId = pressed ? R.attr.guidedActionPressedAnimation :
+                    R.attr.guidedActionUnpressedAnimation;
+            Context ctx = itemView.getContext();
+            TypedValue typedValue = new TypedValue();
+            if (ctx.getTheme().resolveAttribute(themeAttrId, typedValue, true)) {
+                mPressAnimator = AnimatorInflater.loadAnimator(ctx, typedValue.resourceId);
+                mPressAnimator.setTarget(itemView);
+                mPressAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mPressAnimator = null;
+                    }
+                });
+                mPressAnimator.start();
+            }
+        }
+    }
+
+    private static final String TAG = "GuidedActionsStylist";
+
+    ViewGroup mMainView;
+    private VerticalGridView mActionsGridView;
+    VerticalGridView mSubActionsGridView;
+    private View mSubActionsBackground;
+    private View mBgView;
+    private View mContentView;
+    private boolean mButtonActions;
+
+    // Cached values from resources
+    private float mEnabledTextAlpha;
+    private float mDisabledTextAlpha;
+    private float mEnabledDescriptionAlpha;
+    private float mDisabledDescriptionAlpha;
+    private float mEnabledChevronAlpha;
+    private float mDisabledChevronAlpha;
+    private int mTitleMinLines;
+    private int mTitleMaxLines;
+    private int mDescriptionMinLines;
+    private int mVerticalPadding;
+    private int mDisplayHeight;
+
+    private EditListener mEditListener;
+
+    private GuidedAction mExpandedAction = null;
+    Object mExpandTransition;
+    private boolean mBackToCollapseSubActions = true;
+    private boolean mBackToCollapseActivatorView = true;
+
+    private float mKeyLinePercent;
+
+    /**
+     * Creates a view appropriate for displaying a list of GuidedActions, using the provided
+     * inflater and container.
+     * <p>
+     * <i>Note: Does not actually add the created view to the container; the caller should do
+     * this.</i>
+     * @param inflater The layout inflater to be used when constructing the view.
+     * @param container The view group to be passed in the call to
+     * <code>LayoutInflater.inflate</code>.
+     * @return The view to be added to the caller's view hierarchy.
+     */
+    public View onCreateView(LayoutInflater inflater, final ViewGroup container) {
+        TypedArray ta = inflater.getContext().getTheme().obtainStyledAttributes(
+                R.styleable.LeanbackGuidedStepTheme);
+        float keylinePercent = ta.getFloat(R.styleable.LeanbackGuidedStepTheme_guidedStepKeyline,
+                40);
+        mMainView = (ViewGroup) inflater.inflate(onProvideLayoutId(), container, false);
+        mContentView = mMainView.findViewById(mButtonActions ? R.id.guidedactions_content2 :
+                R.id.guidedactions_content);
+        mBgView = mMainView.findViewById(mButtonActions ? R.id.guidedactions_list_background2 :
+                R.id.guidedactions_list_background);
+        if (mMainView instanceof VerticalGridView) {
+            mActionsGridView = (VerticalGridView) mMainView;
+        } else {
+            mActionsGridView = (VerticalGridView) mMainView.findViewById(mButtonActions
+                    ? R.id.guidedactions_list2 : R.id.guidedactions_list);
+            if (mActionsGridView == null) {
+                throw new IllegalStateException("No ListView exists.");
+            }
+            mActionsGridView.setWindowAlignmentOffsetPercent(keylinePercent);
+            mActionsGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_NO_EDGE);
+            if (!mButtonActions) {
+                mSubActionsGridView = (VerticalGridView) mMainView.findViewById(
+                        R.id.guidedactions_sub_list);
+                mSubActionsBackground = mMainView.findViewById(
+                        R.id.guidedactions_sub_list_background);
+            }
+        }
+        mActionsGridView.setFocusable(false);
+        mActionsGridView.setFocusableInTouchMode(false);
+
+        // Cache widths, chevron alpha values, max and min text lines, etc
+        Context ctx = mMainView.getContext();
+        TypedValue val = new TypedValue();
+        mEnabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionEnabledChevronAlpha);
+        mDisabledChevronAlpha = getFloat(ctx, val, R.attr.guidedActionDisabledChevronAlpha);
+        mTitleMinLines = getInteger(ctx, val, R.attr.guidedActionTitleMinLines);
+        mTitleMaxLines = getInteger(ctx, val, R.attr.guidedActionTitleMaxLines);
+        mDescriptionMinLines = getInteger(ctx, val, R.attr.guidedActionDescriptionMinLines);
+        mVerticalPadding = getDimension(ctx, val, R.attr.guidedActionVerticalPadding);
+        mDisplayHeight = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
+                .getDefaultDisplay().getHeight();
+
+        mEnabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_unselected_text_alpha));
+        mDisabledTextAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_disabled_text_alpha));
+        mEnabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_unselected_description_text_alpha));
+        mDisabledDescriptionAlpha = Float.valueOf(ctx.getResources().getString(R.string
+                .lb_guidedactions_item_disabled_description_text_alpha));
+
+        mKeyLinePercent = GuidanceStylingRelativeLayout.getKeyLinePercent(ctx);
+        if (mContentView instanceof GuidedActionsRelativeLayout) {
+            ((GuidedActionsRelativeLayout) mContentView).setInterceptKeyEventListener(
+                    new GuidedActionsRelativeLayout.InterceptKeyEventListener() {
+                        @Override
+                        public boolean onInterceptKeyEvent(KeyEvent event) {
+                            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
+                                    && event.getAction() == KeyEvent.ACTION_UP
+                                    && mExpandedAction != null) {
+                                if ((mExpandedAction.hasSubActions()
+                                        && isBackKeyToCollapseSubActions())
+                                        || (mExpandedAction.hasEditableActivatorView()
+                                        && isBackKeyToCollapseActivatorView())) {
+                                    collapseAction(true);
+                                    return true;
+                                }
+                            }
+                            return false;
+                        }
+                    }
+            );
+        }
+        return mMainView;
+    }
+
+    /**
+     * Choose the layout resource for button actions in {@link #onProvideLayoutId()}.
+     */
+    public void setAsButtonActions() {
+        if (mMainView != null) {
+            throw new IllegalStateException("setAsButtonActions() must be called before creating "
+                    + "views");
+        }
+        mButtonActions = true;
+    }
+
+    /**
+     * Returns true if it is button actions list, false for normal actions list.
+     * @return True if it is button actions list, false for normal actions list.
+     */
+    public boolean isButtonActions() {
+        return mButtonActions;
+    }
+
+    /**
+     * Called when destroy the View created by GuidedActionsStylist.
+     */
+    public void onDestroyView() {
+        mExpandedAction = null;
+        mExpandTransition = null;
+        mActionsGridView = null;
+        mSubActionsGridView = null;
+        mSubActionsBackground = null;
+        mContentView = null;
+        mBgView = null;
+        mMainView = null;
+    }
+
+    /**
+     * Returns the VerticalGridView that displays the list of GuidedActions.
+     * @return The VerticalGridView for this presenter.
+     */
+    public VerticalGridView getActionsGridView() {
+        return mActionsGridView;
+    }
+
+    /**
+     * Returns the VerticalGridView that displays the sub actions list of an expanded action.
+     * @return The VerticalGridView that displays the sub actions list of an expanded action.
+     */
+    public VerticalGridView getSubActionsGridView() {
+        return mSubActionsGridView;
+    }
+
+    /**
+     * Provides the resource ID of the layout defining the host view for the list of guided actions.
+     * Subclasses may override to provide their own customized layouts. The base implementation
+     * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions} or
+     * {@link android.support.v17.leanback.R.layout#lb_guidedbuttonactions} if
+     * {@link #isButtonActions()} is true. If overridden, the substituted layout should contain
+     * matching IDs for any views that should be managed by the base class; this can be achieved by
+     * starting with a copy of the base layout file.
+     *
+     * @return The resource ID of the layout to be inflated to define the host view for the list of
+     *         GuidedActions.
+     */
+    public int onProvideLayoutId() {
+        return mButtonActions ? R.layout.lb_guidedbuttonactions : R.layout.lb_guidedactions;
+    }
+
+    /**
+     * Return view type of action, each different type can have differently associated layout Id.
+     * Default implementation returns {@link #VIEW_TYPE_DEFAULT}.
+     * @param action  The action object.
+     * @return View type that used in {@link #onProvideItemLayoutId(int)}.
+     */
+    public int getItemViewType(GuidedAction action) {
+        if (action instanceof GuidedDatePickerAction) {
+            return VIEW_TYPE_DATE_PICKER;
+        }
+        return VIEW_TYPE_DEFAULT;
+    }
+
+    /**
+     * Provides the resource ID of the layout defining the view for an individual guided actions.
+     * Subclasses may override to provide their own customized layouts. The base implementation
+     * returns {@link android.support.v17.leanback.R.layout#lb_guidedactions_item}. If overridden,
+     * the substituted layout should contain matching IDs for any views that should be managed by
+     * the base class; this can be achieved by starting with a copy of the base layout file. Note
+     * that in order for the item to support editing, the title view should both subclass {@link
+     * android.widget.EditText} and implement {@link ImeKeyMonitor}; see {@link
+     * GuidedActionEditText}.  To support different types of Layouts, override {@link
+     * #onProvideItemLayoutId(int)}.
+     * @return The resource ID of the layout to be inflated to define the view to display an
+     * individual GuidedAction.
+     */
+    public int onProvideItemLayoutId() {
+        return R.layout.lb_guidedactions_item;
+    }
+
+    /**
+     * Provides the resource ID of the layout defining the view for an individual guided actions.
+     * Subclasses may override to provide their own customized layouts. The base implementation
+     * supports:
+     * <li>{@link android.support.v17.leanback.R.layout#lb_guidedactions_item}
+     * <li>{{@link android.support.v17.leanback.R.layout#lb_guidedactions_datepicker_item}. If
+     * overridden, the substituted layout should contain matching IDs for any views that should be
+     * managed by the base class; this can be achieved by starting with a copy of the base layout
+     * file. Note that in order for the item to support editing, the title view should both subclass
+     * {@link android.widget.EditText} and implement {@link ImeKeyMonitor}; see
+     * {@link GuidedActionEditText}.
+     *
+     * @param viewType View type returned by {@link #getItemViewType(GuidedAction)}
+     * @return The resource ID of the layout to be inflated to define the view to display an
+     *         individual GuidedAction.
+     */
+    public int onProvideItemLayoutId(int viewType) {
+        if (viewType == VIEW_TYPE_DEFAULT) {
+            return onProvideItemLayoutId();
+        } else if (viewType == VIEW_TYPE_DATE_PICKER) {
+            return R.layout.lb_guidedactions_datepicker_item;
+        } else {
+            throw new RuntimeException("ViewType " + viewType
+                    + " not supported in GuidedActionsStylist");
+        }
+    }
+
+    /**
+     * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
+     * may choose to return a subclass of ViewHolder.  To support different view types, override
+     * {@link #onCreateViewHolder(ViewGroup, int)}
+     * <p>
+     * <i>Note: Should not actually add the created view to the parent; the caller will do
+     * this.</i>
+     * @param parent The view group to be used as the parent of the new view.
+     * @return The view to be added to the caller's view hierarchy.
+     */
+    public ViewHolder onCreateViewHolder(ViewGroup parent) {
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+        View v = inflater.inflate(onProvideItemLayoutId(), parent, false);
+        return new ViewHolder(v, parent == mSubActionsGridView);
+    }
+
+    /**
+     * Constructs a {@link ViewHolder} capable of representing {@link GuidedAction}s. Subclasses
+     * may choose to return a subclass of ViewHolder.
+     * <p>
+     * <i>Note: Should not actually add the created view to the parent; the caller will do
+     * this.</i>
+     * @param parent The view group to be used as the parent of the new view.
+     * @param viewType The viewType returned by {@link #getItemViewType(GuidedAction)}
+     * @return The view to be added to the caller's view hierarchy.
+     */
+    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (viewType == VIEW_TYPE_DEFAULT) {
+            return onCreateViewHolder(parent);
+        }
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+        View v = inflater.inflate(onProvideItemLayoutId(viewType), parent, false);
+        return new ViewHolder(v, parent == mSubActionsGridView);
+    }
+
+    /**
+     * Binds a {@link ViewHolder} to a particular {@link GuidedAction}.
+     * @param vh The view holder to be associated with the given action.
+     * @param action The guided action to be displayed by the view holder's view.
+     * @return The view to be added to the caller's view hierarchy.
+     */
+    public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
+        vh.mAction = action;
+        if (vh.mTitleView != null) {
+            vh.mTitleView.setInputType(action.getInputType());
+            vh.mTitleView.setText(action.getTitle());
+            vh.mTitleView.setAlpha(action.isEnabled() ? mEnabledTextAlpha : mDisabledTextAlpha);
+            vh.mTitleView.setFocusable(false);
+            vh.mTitleView.setClickable(false);
+            vh.mTitleView.setLongClickable(false);
+        }
+        if (vh.mDescriptionView != null) {
+            vh.mDescriptionView.setInputType(action.getDescriptionInputType());
+            vh.mDescriptionView.setText(action.getDescription());
+            vh.mDescriptionView.setVisibility(TextUtils.isEmpty(action.getDescription())
+                    ? View.GONE : View.VISIBLE);
+            vh.mDescriptionView.setAlpha(action.isEnabled() ? mEnabledDescriptionAlpha :
+                mDisabledDescriptionAlpha);
+            vh.mDescriptionView.setFocusable(false);
+            vh.mDescriptionView.setClickable(false);
+            vh.mDescriptionView.setLongClickable(false);
+        }
+        // Clients might want the check mark view to be gone entirely, in which case, ignore it.
+        if (vh.mCheckmarkView != null) {
+            onBindCheckMarkView(vh, action);
+        }
+        setIcon(vh.mIconView, action);
+
+        if (action.hasMultilineDescription()) {
+            if (vh.mTitleView != null) {
+                setMaxLines(vh.mTitleView, mTitleMaxLines);
+                vh.mTitleView.setInputType(
+                        vh.mTitleView.getInputType() | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
+                if (vh.mDescriptionView != null) {
+                    vh.mDescriptionView.setInputType(vh.mDescriptionView.getInputType()
+                            | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
+                    vh.mDescriptionView.setMaxHeight(getDescriptionMaxHeight(
+                            vh.itemView.getContext(), vh.mTitleView));
+                }
+            }
+        } else {
+            if (vh.mTitleView != null) {
+                setMaxLines(vh.mTitleView, mTitleMinLines);
+            }
+            if (vh.mDescriptionView != null) {
+                setMaxLines(vh.mDescriptionView, mDescriptionMinLines);
+            }
+        }
+        if (vh.mActivatorView != null) {
+            onBindActivatorView(vh, action);
+        }
+        setEditingMode(vh, false /*editing*/, false /*withTransition*/);
+        if (action.isFocusable()) {
+            vh.itemView.setFocusable(true);
+            ((ViewGroup) vh.itemView).setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        } else {
+            vh.itemView.setFocusable(false);
+            ((ViewGroup) vh.itemView).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        }
+        setupImeOptions(vh, action);
+
+        updateChevronAndVisibility(vh);
+    }
+
+    /**
+     * Switches action to edit mode and pops up the keyboard.
+     */
+    public void openInEditMode(GuidedAction action) {
+        final GuidedActionAdapter guidedActionAdapter =
+                (GuidedActionAdapter) getActionsGridView().getAdapter();
+        int actionIndex = guidedActionAdapter.getActions().indexOf(action);
+        if (actionIndex < 0 || !action.isEditable()) {
+            return;
+        }
+
+        getActionsGridView().setSelectedPosition(actionIndex, new ViewHolderTask() {
+            @Override
+            public void run(RecyclerView.ViewHolder viewHolder) {
+                ViewHolder vh = (ViewHolder) viewHolder;
+                guidedActionAdapter.mGroup.openIme(guidedActionAdapter, vh);
+            }
+        });
+    }
+
+    private static void setMaxLines(TextView view, int maxLines) {
+        // setSingleLine must be called before setMaxLines because it resets maximum to
+        // Integer.MAX_VALUE.
+        if (maxLines == 1) {
+            view.setSingleLine(true);
+        } else {
+            view.setSingleLine(false);
+            view.setMaxLines(maxLines);
+        }
+    }
+
+    /**
+     * Called by {@link #onBindViewHolder(ViewHolder, GuidedAction)} to setup IME options.  Default
+     * implementation assigns {@link EditorInfo#IME_ACTION_DONE}.  Subclass may override.
+     * @param vh The view holder to be associated with the given action.
+     * @param action The guided action to be displayed by the view holder's view.
+     */
+    protected void setupImeOptions(ViewHolder vh, GuidedAction action) {
+        setupNextImeOptions(vh.getEditableTitleView());
+        setupNextImeOptions(vh.getEditableDescriptionView());
+    }
+
+    private void setupNextImeOptions(EditText edit) {
+        if (edit != null) {
+            edit.setImeOptions(EditorInfo.IME_ACTION_NEXT);
+        }
+    }
+
+    /**
+     * @deprecated This method is for internal library use only and should not
+     *             be called directly.
+     */
+    @Deprecated
+    public void setEditingMode(ViewHolder vh, GuidedAction action, boolean editing) {
+        if (editing != vh.isInEditing() && isInExpandTransition()) {
+            onEditingModeChange(vh, action, editing);
+        }
+    }
+
+    void setEditingMode(ViewHolder vh, boolean editing) {
+        setEditingMode(vh, editing, true /*withTransition*/);
+    }
+
+    void setEditingMode(ViewHolder vh, boolean editing, boolean withTransition) {
+        if (editing != vh.isInEditing() && !isInExpandTransition()) {
+            onEditingModeChange(vh, editing, withTransition);
+        }
+    }
+
+    /**
+     * @deprecated Use {@link #onEditingModeChange(ViewHolder, boolean, boolean)}.
+     */
+    @Deprecated
+    protected void onEditingModeChange(ViewHolder vh, GuidedAction action, boolean editing) {
+    }
+
+    /**
+     * Called when editing mode of an ViewHolder is changed.  Subclass must call
+     * <code>super.onEditingModeChange(vh,editing,withTransition)</code>.
+     *
+     * @param vh                ViewHolder to change editing mode.
+     * @param editing           True to enable editing, false to stop editing
+     * @param withTransition    True to run expand transiiton, false otherwise.
+     */
+    @CallSuper
+    protected void onEditingModeChange(ViewHolder vh, boolean editing, boolean withTransition) {
+        GuidedAction action = vh.getAction();
+        TextView titleView = vh.getTitleView();
+        TextView descriptionView = vh.getDescriptionView();
+        if (editing) {
+            CharSequence editTitle = action.getEditTitle();
+            if (titleView != null && editTitle != null) {
+                titleView.setText(editTitle);
+            }
+            CharSequence editDescription = action.getEditDescription();
+            if (descriptionView != null && editDescription != null) {
+                descriptionView.setText(editDescription);
+            }
+            if (action.isDescriptionEditable()) {
+                if (descriptionView != null) {
+                    descriptionView.setVisibility(View.VISIBLE);
+                    descriptionView.setInputType(action.getDescriptionEditInputType());
+                }
+                vh.mEditingMode = EDITING_DESCRIPTION;
+            } else if (action.isEditable()){
+                if (titleView != null) {
+                    titleView.setInputType(action.getEditInputType());
+                }
+                vh.mEditingMode = EDITING_TITLE;
+            } else if (vh.mActivatorView != null) {
+                onEditActivatorView(vh, editing, withTransition);
+                vh.mEditingMode = EDITING_ACTIVATOR_VIEW;
+            }
+        } else {
+            if (titleView != null) {
+                titleView.setText(action.getTitle());
+            }
+            if (descriptionView != null) {
+                descriptionView.setText(action.getDescription());
+            }
+            if (vh.mEditingMode == EDITING_DESCRIPTION) {
+                if (descriptionView != null) {
+                    descriptionView.setVisibility(TextUtils.isEmpty(action.getDescription())
+                            ? View.GONE : View.VISIBLE);
+                    descriptionView.setInputType(action.getDescriptionInputType());
+                }
+            } else if (vh.mEditingMode == EDITING_TITLE) {
+                if (titleView != null) {
+                    titleView.setInputType(action.getInputType());
+                }
+            } else if (vh.mEditingMode == EDITING_ACTIVATOR_VIEW) {
+                if (vh.mActivatorView != null) {
+                    onEditActivatorView(vh, editing, withTransition);
+                }
+            }
+            vh.mEditingMode = EDITING_NONE;
+        }
+        // call deprecated method for backward compatible
+        onEditingModeChange(vh, action, editing);
+    }
+
+    /**
+     * Animates the view holder's view (or subviews thereof) when the action has had its focus
+     * state changed.
+     * @param vh The view holder associated with the relevant action.
+     * @param focused True if the action has become focused, false if it has lost focus.
+     */
+    public void onAnimateItemFocused(ViewHolder vh, boolean focused) {
+        // No animations for this, currently, because the animation is done on
+        // mSelectorView
+    }
+
+    /**
+     * Animates the view holder's view (or subviews thereof) when the action has had its press
+     * state changed.
+     * @param vh The view holder associated with the relevant action.
+     * @param pressed True if the action has been pressed, false if it has been unpressed.
+     */
+    public void onAnimateItemPressed(ViewHolder vh, boolean pressed) {
+        vh.press(pressed);
+    }
+
+    /**
+     * Resets the view holder's view to unpressed state.
+     * @param vh The view holder associated with the relevant action.
+     */
+    public void onAnimateItemPressedCancelled(ViewHolder vh) {
+        vh.press(false);
+    }
+
+    /**
+     * Animates the view holder's view (or subviews thereof) when the action has had its check state
+     * changed. Default implementation calls setChecked() if {@link ViewHolder#getCheckmarkView()}
+     * is instance of {@link Checkable}.
+     *
+     * @param vh The view holder associated with the relevant action.
+     * @param checked True if the action has become checked, false if it has become unchecked.
+     * @see #onBindCheckMarkView(ViewHolder, GuidedAction)
+     */
+    public void onAnimateItemChecked(ViewHolder vh, boolean checked) {
+        if (vh.mCheckmarkView instanceof Checkable) {
+            ((Checkable) vh.mCheckmarkView).setChecked(checked);
+        }
+    }
+
+    /**
+     * Sets states of check mark view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}
+     * when action's checkset Id is other than {@link GuidedAction#NO_CHECK_SET}. Default
+     * implementation assigns drawable loaded from theme attribute
+     * {@link android.R.attr#listChoiceIndicatorMultiple} for checkbox or
+     * {@link android.R.attr#listChoiceIndicatorSingle} for radio button. Subclass rarely needs
+     * override the method, instead app can provide its own drawable that supports transition
+     * animations, change theme attributes {@link android.R.attr#listChoiceIndicatorMultiple} and
+     * {@link android.R.attr#listChoiceIndicatorSingle} in {android.support.v17.leanback.R.
+     * styleable#LeanbackGuidedStepTheme}.
+     *
+     * @param vh The view holder associated with the relevant action.
+     * @param action The GuidedAction object to bind to.
+     * @see #onAnimateItemChecked(ViewHolder, boolean)
+     */
+    public void onBindCheckMarkView(ViewHolder vh, GuidedAction action) {
+        if (action.getCheckSetId() != GuidedAction.NO_CHECK_SET) {
+            vh.mCheckmarkView.setVisibility(View.VISIBLE);
+            int attrId = action.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID
+                    ? android.R.attr.listChoiceIndicatorMultiple
+                    : android.R.attr.listChoiceIndicatorSingle;
+            final Context context = vh.mCheckmarkView.getContext();
+            Drawable drawable = null;
+            TypedValue typedValue = new TypedValue();
+            if (context.getTheme().resolveAttribute(attrId, typedValue, true)) {
+                drawable = ContextCompat.getDrawable(context, typedValue.resourceId);
+            }
+            vh.mCheckmarkView.setImageDrawable(drawable);
+            if (vh.mCheckmarkView instanceof Checkable) {
+                ((Checkable) vh.mCheckmarkView).setChecked(action.isChecked());
+            }
+        } else {
+            vh.mCheckmarkView.setVisibility(View.GONE);
+        }
+    }
+
+    /**
+     * Performs binding activator view value to action.  Default implementation supports
+     * GuidedDatePickerAction, subclass may override to add support of other views.
+     * @param vh ViewHolder of activator view.
+     * @param action GuidedAction to bind.
+     */
+    public void onBindActivatorView(ViewHolder vh, GuidedAction action) {
+        if (action instanceof GuidedDatePickerAction) {
+            GuidedDatePickerAction dateAction = (GuidedDatePickerAction) action;
+            DatePicker dateView = (DatePicker) vh.mActivatorView;
+            dateView.setDatePickerFormat(dateAction.getDatePickerFormat());
+            if (dateAction.getMinDate() != Long.MIN_VALUE) {
+                dateView.setMinDate(dateAction.getMinDate());
+            }
+            if (dateAction.getMaxDate() != Long.MAX_VALUE) {
+                dateView.setMaxDate(dateAction.getMaxDate());
+            }
+            Calendar c = Calendar.getInstance();
+            c.setTimeInMillis(dateAction.getDate());
+            dateView.updateDate(c.get(Calendar.YEAR), c.get(Calendar.MONTH),
+                    c.get(Calendar.DAY_OF_MONTH), false);
+        }
+    }
+
+    /**
+     * Performs updating GuidedAction from activator view.  Default implementation supports
+     * GuidedDatePickerAction, subclass may override to add support of other views.
+     * @param vh ViewHolder of activator view.
+     * @param action GuidedAction to update.
+     * @return True if value has been updated, false otherwise.
+     */
+    public boolean onUpdateActivatorView(ViewHolder vh, GuidedAction action) {
+        if (action instanceof GuidedDatePickerAction) {
+            GuidedDatePickerAction dateAction = (GuidedDatePickerAction) action;
+            DatePicker dateView = (DatePicker) vh.mActivatorView;
+            if (dateAction.getDate() != dateView.getDate()) {
+                dateAction.setDate(dateView.getDate());
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sets listener for reporting view being edited.
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public void setEditListener(EditListener listener) {
+        mEditListener = listener;
+    }
+
+    void onEditActivatorView(final ViewHolder vh, boolean editing, final boolean withTransition) {
+        if (editing) {
+            startExpanded(vh, withTransition);
+            vh.itemView.setFocusable(false);
+            vh.mActivatorView.requestFocus();
+            vh.mActivatorView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (!isInExpandTransition()) {
+                        ((GuidedActionAdapter) getActionsGridView().getAdapter())
+                                .performOnActionClick(vh);
+                    }
+                }
+            });
+        } else {
+            if (onUpdateActivatorView(vh, vh.getAction())) {
+                if (mEditListener != null) {
+                    mEditListener.onGuidedActionEditedAndProceed(vh.getAction());
+                }
+            }
+            vh.itemView.setFocusable(true);
+            vh.itemView.requestFocus();
+            startExpanded(null, withTransition);
+            vh.mActivatorView.setOnClickListener(null);
+            vh.mActivatorView.setClickable(false);
+        }
+    }
+
+    /**
+     * Sets states of chevron view, called by {@link #onBindViewHolder(ViewHolder, GuidedAction)}.
+     * Subclass may override.
+     *
+     * @param vh The view holder associated with the relevant action.
+     * @param action The GuidedAction object to bind to.
+     */
+    public void onBindChevronView(ViewHolder vh, GuidedAction action) {
+        final boolean hasNext = action.hasNext();
+        final boolean hasSubActions = action.hasSubActions();
+        if (hasNext || hasSubActions) {
+            vh.mChevronView.setVisibility(View.VISIBLE);
+            vh.mChevronView.setAlpha(action.isEnabled() ? mEnabledChevronAlpha :
+                    mDisabledChevronAlpha);
+            if (hasNext) {
+                float r = mMainView != null
+                        && mMainView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? 180f : 0f;
+                vh.mChevronView.setRotation(r);
+            } else if (action == mExpandedAction) {
+                vh.mChevronView.setRotation(270);
+            } else {
+                vh.mChevronView.setRotation(90);
+            }
+        } else {
+            vh.mChevronView.setVisibility(View.GONE);
+
+        }
+    }
+
+    /**
+     * Expands or collapse the sub actions list view with transition animation
+     * @param avh When not null, fill sub actions list of this ViewHolder into sub actions list and
+     * hide the other items in main list.  When null, collapse the sub actions list.
+     * @deprecated use {@link #expandAction(GuidedAction, boolean)} and
+     * {@link #collapseAction(boolean)}
+     */
+    @Deprecated
+    public void setExpandedViewHolder(ViewHolder avh) {
+        expandAction(avh == null ? null : avh.getAction(), isExpandTransitionSupported());
+    }
+
+    /**
+     * Returns true if it is running an expanding or collapsing transition, false otherwise.
+     * @return True if it is running an expanding or collapsing transition, false otherwise.
+     */
+    public boolean isInExpandTransition() {
+        return mExpandTransition != null;
+    }
+
+    /**
+     * Returns if expand/collapse animation is supported.  When this method returns true,
+     * {@link #startExpandedTransition(ViewHolder)} will be used.  When this method returns false,
+     * {@link #onUpdateExpandedViewHolder(ViewHolder)} will be called.
+     * @return True if it is running an expanding or collapsing transition, false otherwise.
+     */
+    public boolean isExpandTransitionSupported() {
+        return VERSION.SDK_INT >= 21;
+    }
+
+    /**
+     * Start transition to expand or collapse GuidedActionStylist.
+     * @param avh When not null, the GuidedActionStylist expands the sub actions of avh.  When null
+     * the GuidedActionStylist will collapse sub actions.
+     * @deprecated use {@link #expandAction(GuidedAction, boolean)} and
+     * {@link #collapseAction(boolean)}
+     */
+    @Deprecated
+    public void startExpandedTransition(ViewHolder avh) {
+        expandAction(avh == null ? null : avh.getAction(), isExpandTransitionSupported());
+    }
+
+    /**
+     * Enable or disable using BACK key to collapse sub actions list. Default is enabled.
+     *
+     * @param backToCollapse True to enable using BACK key to collapse sub actions list, false
+     *                       to disable.
+     * @see GuidedAction#hasSubActions
+     * @see GuidedAction#getSubActions
+     */
+    public final void setBackKeyToCollapseSubActions(boolean backToCollapse) {
+        mBackToCollapseSubActions = backToCollapse;
+    }
+
+    /**
+     * @return True if using BACK key to collapse sub actions list, false otherwise. Default value
+     * is true.
+     *
+     * @see GuidedAction#hasSubActions
+     * @see GuidedAction#getSubActions
+     */
+    public final boolean isBackKeyToCollapseSubActions() {
+        return mBackToCollapseSubActions;
+    }
+
+    /**
+     * Enable or disable using BACK key to collapse {@link GuidedAction} with editable activator
+     * view. Default is enabled.
+     *
+     * @param backToCollapse True to enable using BACK key to collapse {@link GuidedAction} with
+     *                       editable activator view.
+     * @see GuidedAction#hasEditableActivatorView
+     */
+    public final void setBackKeyToCollapseActivatorView(boolean backToCollapse) {
+        mBackToCollapseActivatorView = backToCollapse;
+    }
+
+    /**
+     * @return True if using BACK key to collapse {@link GuidedAction} with editable activator
+     * view, false otherwise. Default value is true.
+     *
+     * @see GuidedAction#hasEditableActivatorView
+     */
+    public final boolean isBackKeyToCollapseActivatorView() {
+        return mBackToCollapseActivatorView;
+    }
+
+    /**
+     * Expand an action. Do nothing if it is in animation or there is action expanded.
+     *
+     * @param action         Action to expand.
+     * @param withTransition True to run transition animation, false otherwsie.
+     */
+    public void expandAction(GuidedAction action, final boolean withTransition) {
+        if (isInExpandTransition() || mExpandedAction != null) {
+            return;
+        }
+        int actionPosition =
+                ((GuidedActionAdapter) getActionsGridView().getAdapter()).indexOf(action);
+        if (actionPosition < 0) {
+            return;
+        }
+        boolean runTransition = isExpandTransitionSupported() && withTransition;
+        if (!runTransition) {
+            getActionsGridView().setSelectedPosition(actionPosition,
+                    new ViewHolderTask() {
+                        @Override
+                        public void run(RecyclerView.ViewHolder vh) {
+                            GuidedActionsStylist.ViewHolder avh =
+                                    (GuidedActionsStylist.ViewHolder)vh;
+                            if (avh.getAction().hasEditableActivatorView()) {
+                                setEditingMode(avh, true /*editing*/, false /*withTransition*/);
+                            } else {
+                                onUpdateExpandedViewHolder(avh);
+                            }
+                        }
+                    });
+            if (action.hasSubActions()) {
+                onUpdateSubActionsGridView(action, true);
+            }
+        } else {
+            getActionsGridView().setSelectedPosition(actionPosition,
+                    new ViewHolderTask() {
+                        @Override
+                        public void run(RecyclerView.ViewHolder vh) {
+                            GuidedActionsStylist.ViewHolder avh =
+                                    (GuidedActionsStylist.ViewHolder)vh;
+                            if (avh.getAction().hasEditableActivatorView()) {
+                                setEditingMode(avh, true /*editing*/, true /*withTransition*/);
+                            } else {
+                                startExpanded(avh, true);
+                            }
+                        }
+                    });
+        }
+
+    }
+
+    /**
+     * Collapse expanded action. Do nothing if it is in animation or there is no action expanded.
+     *
+     * @param withTransition True to run transition animation, false otherwsie.
+     */
+    public void collapseAction(boolean withTransition) {
+        if (isInExpandTransition() || mExpandedAction == null) {
+            return;
+        }
+        boolean runTransition = isExpandTransitionSupported() && withTransition;
+        int actionPosition =
+                ((GuidedActionAdapter) getActionsGridView().getAdapter()).indexOf(mExpandedAction);
+        if (actionPosition < 0) {
+            return;
+        }
+        if (mExpandedAction.hasEditableActivatorView()) {
+            setEditingMode(
+                    ((ViewHolder) getActionsGridView().findViewHolderForPosition(actionPosition)),
+                    false /*editing*/,
+                    runTransition);
+        } else {
+            startExpanded(null, runTransition);
+        }
+    }
+
+    int getKeyLine() {
+        return (int) (mKeyLinePercent * mActionsGridView.getHeight() / 100);
+    }
+
+    /**
+     * Internal method with assumption we already scroll to the new ViewHolder or is currently
+     * expanded.
+     */
+    void startExpanded(ViewHolder avh, final boolean withTransition) {
+        ViewHolder focusAvh = null; // expand / collapse view holder
+        final int count = mActionsGridView.getChildCount();
+        for (int i = 0; i < count; i++) {
+            ViewHolder vh = (ViewHolder) mActionsGridView
+                    .getChildViewHolder(mActionsGridView.getChildAt(i));
+            if (avh == null && vh.itemView.getVisibility() == View.VISIBLE) {
+                // going to collapse this one.
+                focusAvh = vh;
+                break;
+            } else if (avh != null && vh.getAction() == avh.getAction()) {
+                // going to expand this one.
+                focusAvh = vh;
+                break;
+            }
+        }
+        if (focusAvh == null) {
+            // huh?
+            return;
+        }
+        boolean isExpand = avh != null;
+        boolean isSubActionTransition = focusAvh.getAction().hasSubActions();
+        if (withTransition) {
+            Object set = TransitionHelper.createTransitionSet(false);
+            float slideDistance = isSubActionTransition ? focusAvh.itemView.getHeight()
+                    : focusAvh.itemView.getHeight() * 0.5f;
+            Object slideAndFade = TransitionHelper.createFadeAndShortSlide(
+                    Gravity.TOP | Gravity.BOTTOM,
+                    slideDistance);
+            TransitionHelper.setEpicenterCallback(slideAndFade, new TransitionEpicenterCallback() {
+                Rect mRect = new Rect();
+                @Override
+                public Rect onGetEpicenter(Object transition) {
+                    int centerY = getKeyLine();
+                    int centerX = 0;
+                    mRect.set(centerX, centerY, centerX, centerY);
+                    return mRect;
+                }
+            });
+            Object changeFocusItemTransform = TransitionHelper.createChangeTransform();
+            Object changeFocusItemBounds = TransitionHelper.createChangeBounds(false);
+            Object fade = TransitionHelper.createFadeTransition(TransitionHelper.FADE_IN
+                    | TransitionHelper.FADE_OUT);
+            Object changeGridBounds = TransitionHelper.createChangeBounds(false);
+            if (avh == null) {
+                TransitionHelper.setStartDelay(slideAndFade, 150);
+                TransitionHelper.setStartDelay(changeFocusItemTransform, 100);
+                TransitionHelper.setStartDelay(changeFocusItemBounds, 100);
+                TransitionHelper.setStartDelay(changeGridBounds, 100);
+            } else {
+                TransitionHelper.setStartDelay(fade, 100);
+                TransitionHelper.setStartDelay(changeGridBounds, 50);
+                TransitionHelper.setStartDelay(changeFocusItemTransform, 50);
+                TransitionHelper.setStartDelay(changeFocusItemBounds, 50);
+            }
+            for (int i = 0; i < count; i++) {
+                ViewHolder vh = (ViewHolder) mActionsGridView
+                        .getChildViewHolder(mActionsGridView.getChildAt(i));
+                if (vh == focusAvh) {
+                    // going to expand/collapse this one.
+                    if (isSubActionTransition) {
+                        TransitionHelper.include(changeFocusItemTransform, vh.itemView);
+                        TransitionHelper.include(changeFocusItemBounds, vh.itemView);
+                    }
+                } else {
+                    // going to slide this item to top / bottom.
+                    TransitionHelper.include(slideAndFade, vh.itemView);
+                    TransitionHelper.exclude(fade, vh.itemView, true);
+                }
+            }
+            TransitionHelper.include(changeGridBounds, mSubActionsGridView);
+            TransitionHelper.include(changeGridBounds, mSubActionsBackground);
+            TransitionHelper.addTransition(set, slideAndFade);
+            // note that we don't run ChangeBounds for activating view due to the rounding problem
+            // of multiple level views ChangeBounds animation causing vertical jittering.
+            if (isSubActionTransition) {
+                TransitionHelper.addTransition(set, changeFocusItemTransform);
+                TransitionHelper.addTransition(set, changeFocusItemBounds);
+            }
+            TransitionHelper.addTransition(set, fade);
+            TransitionHelper.addTransition(set, changeGridBounds);
+            mExpandTransition = set;
+            TransitionHelper.addTransitionListener(mExpandTransition, new TransitionListener() {
+                @Override
+                public void onTransitionEnd(Object transition) {
+                    mExpandTransition = null;
+                }
+            });
+            if (isExpand && isSubActionTransition) {
+                // To expand sub actions, move original position of sub actions to bottom of item
+                int startY = avh.itemView.getBottom();
+                mSubActionsGridView.offsetTopAndBottom(startY - mSubActionsGridView.getTop());
+                mSubActionsBackground.offsetTopAndBottom(startY - mSubActionsBackground.getTop());
+            }
+            TransitionHelper.beginDelayedTransition(mMainView, mExpandTransition);
+        }
+        onUpdateExpandedViewHolder(avh);
+        if (isSubActionTransition) {
+            onUpdateSubActionsGridView(focusAvh.getAction(), isExpand);
+        }
+    }
+
+    /**
+     * @return True if sub actions list is expanded.
+     */
+    public boolean isSubActionsExpanded() {
+        return mExpandedAction != null && mExpandedAction.hasSubActions();
+    }
+
+    /**
+     * @return True if there is {@link #getExpandedAction()} is not null, false otherwise.
+     */
+    public boolean isExpanded() {
+        return mExpandedAction != null;
+    }
+
+    /**
+     * @return Current expanded GuidedAction or null if not expanded.
+     */
+    public GuidedAction getExpandedAction() {
+        return mExpandedAction;
+    }
+
+    /**
+     * Expand or collapse GuidedActionStylist.
+     * @param avh When not null, the GuidedActionStylist expands the sub actions of avh.  When null
+     * the GuidedActionStylist will collapse sub actions.
+     */
+    public void onUpdateExpandedViewHolder(ViewHolder avh) {
+
+        // Note about setting the prune child flag back & forth here: without this, the actions that
+        // go off the screen from the top or bottom become invisible forever. This is because once
+        // an action is expanded, it takes more space which in turn kicks out some other actions
+        // off of the screen. Once, this action is collapsed (after the second click) and the
+        // visibility flag is set back to true for all existing actions,
+        // the off-the-screen actions are pruned from the view, thus
+        // could not be accessed, had we not disabled pruning prior to this.
+        if (avh == null) {
+            mExpandedAction = null;
+            mActionsGridView.setPruneChild(true);
+        } else if (avh.getAction() != mExpandedAction) {
+            mExpandedAction = avh.getAction();
+            mActionsGridView.setPruneChild(false);
+        }
+        // In expanding mode, notifyItemChange on expanded item will reset the translationY by
+        // the default ItemAnimator.  So disable ItemAnimation in expanding mode.
+        mActionsGridView.setAnimateChildLayout(false);
+        final int count = mActionsGridView.getChildCount();
+        for (int i = 0; i < count; i++) {
+            ViewHolder vh = (ViewHolder) mActionsGridView
+                    .getChildViewHolder(mActionsGridView.getChildAt(i));
+            updateChevronAndVisibility(vh);
+        }
+    }
+
+    void onUpdateSubActionsGridView(GuidedAction action, boolean expand) {
+        if (mSubActionsGridView != null) {
+            ViewGroup.MarginLayoutParams lp =
+                    (ViewGroup.MarginLayoutParams) mSubActionsGridView.getLayoutParams();
+            GuidedActionAdapter adapter = (GuidedActionAdapter) mSubActionsGridView.getAdapter();
+            if (expand) {
+                // set to negative value so GuidedActionRelativeLayout will override with
+                // keyLine percentage.
+                lp.topMargin = -2;
+                lp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+                mSubActionsGridView.setLayoutParams(lp);
+                mSubActionsGridView.setVisibility(View.VISIBLE);
+                mSubActionsBackground.setVisibility(View.VISIBLE);
+                mSubActionsGridView.requestFocus();
+                adapter.setActions(action.getSubActions());
+            } else {
+                // set to explicit value, which will disable the keyLine percentage calculation
+                // in GuidedRelativeLayout.
+                int actionPosition = ((GuidedActionAdapter) mActionsGridView.getAdapter())
+                        .indexOf(action);
+                lp.topMargin = mActionsGridView.getLayoutManager()
+                        .findViewByPosition(actionPosition).getBottom();
+                lp.height = 0;
+                mSubActionsGridView.setVisibility(View.INVISIBLE);
+                mSubActionsBackground.setVisibility(View.INVISIBLE);
+                mSubActionsGridView.setLayoutParams(lp);
+                adapter.setActions(Collections.EMPTY_LIST);
+                mActionsGridView.requestFocus();
+            }
+        }
+    }
+
+    private void updateChevronAndVisibility(ViewHolder vh) {
+        if (!vh.isSubAction()) {
+            if (mExpandedAction == null) {
+                vh.itemView.setVisibility(View.VISIBLE);
+                vh.itemView.setTranslationY(0);
+                if (vh.mActivatorView != null) {
+                    vh.setActivated(false);
+                }
+            } else if (vh.getAction() == mExpandedAction) {
+                vh.itemView.setVisibility(View.VISIBLE);
+                if (vh.getAction().hasSubActions()) {
+                    vh.itemView.setTranslationY(getKeyLine() - vh.itemView.getBottom());
+                } else if (vh.mActivatorView != null) {
+                    vh.itemView.setTranslationY(0);
+                    vh.setActivated(true);
+                }
+            } else {
+                vh.itemView.setVisibility(View.INVISIBLE);
+                vh.itemView.setTranslationY(0);
+            }
+        }
+        if (vh.mChevronView != null) {
+            onBindChevronView(vh, vh.getAction());
+        }
+    }
+
+    /*
+     * ==========================================
+     * FragmentAnimationProvider overrides
+     * ==========================================
+     */
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onImeAppearing(@NonNull List<Animator> animators) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onImeDisappearing(@NonNull List<Animator> animators) {
+    }
+
+    /*
+     * ==========================================
+     * Private methods
+     * ==========================================
+     */
+
+    private float getFloat(Context ctx, TypedValue typedValue, int attrId) {
+        ctx.getTheme().resolveAttribute(attrId, typedValue, true);
+        // Android resources don't have a native float type, so we have to use strings.
+        return Float.valueOf(ctx.getResources().getString(typedValue.resourceId));
+    }
+
+    private int getInteger(Context ctx, TypedValue typedValue, int attrId) {
+        ctx.getTheme().resolveAttribute(attrId, typedValue, true);
+        return ctx.getResources().getInteger(typedValue.resourceId);
+    }
+
+    private int getDimension(Context ctx, TypedValue typedValue, int attrId) {
+        ctx.getTheme().resolveAttribute(attrId, typedValue, true);
+        return ctx.getResources().getDimensionPixelSize(typedValue.resourceId);
+    }
+
+    private boolean setIcon(final ImageView iconView, GuidedAction action) {
+        Drawable icon = null;
+        if (iconView != null) {
+            icon = action.getIcon();
+            if (icon != null) {
+                // setImageDrawable resets the drawable's level unless we set the view level first.
+                iconView.setImageLevel(icon.getLevel());
+                iconView.setImageDrawable(icon);
+                iconView.setVisibility(View.VISIBLE);
+            } else {
+                iconView.setVisibility(View.GONE);
+            }
+        }
+        return icon != null;
+    }
+
+    /**
+     * @return the max height in pixels the description can be such that the
+     *         action nicely takes up the entire screen.
+     */
+    private int getDescriptionMaxHeight(Context context, TextView title) {
+        // The 2 multiplier on the title height calculation is a
+        // conservative estimate for font padding which can not be
+        // calculated at this stage since the view hasn't been rendered yet.
+        return (int)(mDisplayHeight - 2*mVerticalPadding - 2*mTitleMaxLines*title.getLineHeight());
+    }
+
+}
diff --git a/leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java b/leanback/src/main/java/android/support/v17/leanback/widget/GuidedDatePickerAction.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/GuidedDatePickerAction.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/GuidedDatePickerAction.java
diff --git a/leanback/src/android/support/v17/leanback/widget/HeaderItem.java b/leanback/src/main/java/android/support/v17/leanback/widget/HeaderItem.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/HeaderItem.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/HeaderItem.java
diff --git a/leanback/src/android/support/v17/leanback/widget/HorizontalGridView.java b/leanback/src/main/java/android/support/v17/leanback/widget/HorizontalGridView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/HorizontalGridView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/HorizontalGridView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java b/leanback/src/main/java/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/HorizontalHoverCardSwitcher.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ImageCardView.java b/leanback/src/main/java/android/support/v17/leanback/widget/ImageCardView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ImageCardView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ImageCardView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java b/leanback/src/main/java/android/support/v17/leanback/widget/ImeKeyMonitor.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ImeKeyMonitor.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ImeKeyMonitor.java
diff --git a/leanback/src/android/support/v17/leanback/widget/InvisibleRowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/InvisibleRowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/InvisibleRowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/InvisibleRowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ItemAlignment.java b/leanback/src/main/java/android/support/v17/leanback/widget/ItemAlignment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ItemAlignment.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ItemAlignment.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacet.java b/leanback/src/main/java/android/support/v17/leanback/widget/ItemAlignmentFacet.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacet.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ItemAlignmentFacet.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ItemAlignmentFacetHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/ItemBridgeAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ItemBridgeAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java b/leanback/src/main/java/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ItemBridgeAdapterShadowOverlayWrapper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ListRow.java b/leanback/src/main/java/android/support/v17/leanback/widget/ListRow.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ListRow.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ListRow.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ListRowHoverCardView.java b/leanback/src/main/java/android/support/v17/leanback/widget/ListRowHoverCardView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ListRowHoverCardView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ListRowHoverCardView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/ListRowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ListRowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ListRowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ListRowView.java b/leanback/src/main/java/android/support/v17/leanback/widget/ListRowView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ListRowView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ListRowView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/MediaItemActionPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/MediaItemActionPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/MediaItemActionPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/MediaItemActionPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/MediaNowPlayingView.java b/leanback/src/main/java/android/support/v17/leanback/widget/MediaNowPlayingView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/MediaNowPlayingView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/MediaNowPlayingView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/MediaRowFocusView.java b/leanback/src/main/java/android/support/v17/leanback/widget/MediaRowFocusView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/MediaRowFocusView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/MediaRowFocusView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/MultiActionsProvider.java b/leanback/src/main/java/android/support/v17/leanback/widget/MultiActionsProvider.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/MultiActionsProvider.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/MultiActionsProvider.java
diff --git a/leanback/src/android/support/v17/leanback/widget/NonOverlappingFrameLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingFrameLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/NonOverlappingFrameLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingFrameLayout.java
diff --git a/leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingLinearLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingLinearLayout.java
diff --git a/leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java b/leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingLinearLayoutWithForeground.java
diff --git a/leanback/src/android/support/v17/leanback/widget/NonOverlappingRelativeLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingRelativeLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/NonOverlappingRelativeLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingRelativeLayout.java
diff --git a/leanback/src/android/support/v17/leanback/widget/NonOverlappingView.java b/leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/NonOverlappingView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/NonOverlappingView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ObjectAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/ObjectAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ObjectAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ObjectAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/OnActionClickedListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/OnActionClickedListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/OnActionClickedListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/OnActionClickedListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/OnChildLaidOutListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/OnChildLaidOutListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/OnChildLaidOutListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/OnChildLaidOutListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/OnChildSelectedListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/OnChildSelectedListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/OnChildSelectedListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/OnChildSelectedListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/OnChildViewHolderSelectedListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/OnItemViewClickedListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/OnItemViewClickedListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/OnItemViewClickedListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/OnItemViewClickedListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/OnItemViewSelectedListener.java b/leanback/src/main/java/android/support/v17/leanback/widget/OnItemViewSelectedListener.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/OnItemViewSelectedListener.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/OnItemViewSelectedListener.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PageRow.java b/leanback/src/main/java/android/support/v17/leanback/widget/PageRow.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PageRow.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PageRow.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PagingIndicator.java b/leanback/src/main/java/android/support/v17/leanback/widget/PagingIndicator.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PagingIndicator.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PagingIndicator.java
diff --git a/leanback/src/android/support/v17/leanback/widget/Parallax.java b/leanback/src/main/java/android/support/v17/leanback/widget/Parallax.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/Parallax.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/Parallax.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java b/leanback/src/main/java/android/support/v17/leanback/widget/ParallaxEffect.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ParallaxEffect.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ParallaxEffect.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java b/leanback/src/main/java/android/support/v17/leanback/widget/ParallaxTarget.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ParallaxTarget.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ParallaxTarget.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PersistentFocusWrapper.java b/leanback/src/main/java/android/support/v17/leanback/widget/PersistentFocusWrapper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PersistentFocusWrapper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PersistentFocusWrapper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsPresenter.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsRow.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsRow.java
new file mode 100644
index 0000000..19358ec
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsRow.java
@@ -0,0 +1,1083 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.support.v17.leanback.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.util.MathUtil;
+import android.util.TypedValue;
+import android.view.KeyEvent;
+
+/**
+ * A {@link Row} of playback controls to be displayed by a {@link PlaybackControlsRowPresenter}.
+ *
+ * This row consists of some optional item detail, a series of primary actions,
+ * and an optional series of secondary actions.
+ *
+ * <p>
+ * Controls are specified via an {@link ObjectAdapter} containing one or more
+ * {@link Action}s.
+ * </p>
+ * <p>
+ * Adapters should have their {@link PresenterSelector} set to an instance of
+ * {@link ControlButtonPresenterSelector}.
+ * </p>
+ */
+public class PlaybackControlsRow extends Row {
+
+    /**
+     * Listener for progress or duration change.
+     */
+    public static class OnPlaybackProgressCallback {
+        /**
+         * Called when {@link PlaybackControlsRow#getCurrentPosition()} changed.
+         * @param row The PlaybackControlsRow that current time changed.
+         * @param currentTimeMs Current time in milliseconds.
+         */
+        public void onCurrentPositionChanged(PlaybackControlsRow row, long currentTimeMs) {
+        }
+
+        /**
+         * Called when {@link PlaybackControlsRow#getDuration()} changed.
+         * @param row The PlaybackControlsRow that total time changed.
+         * @param totalTime Total time in milliseconds.
+         */
+        public void onDurationChanged(PlaybackControlsRow row, long totalTime) {
+        }
+
+        /**
+         * Called when {@link PlaybackControlsRow#getBufferedPosition()} changed.
+         * @param row The PlaybackControlsRow that buffered progress changed.
+         * @param bufferedProgressMs Buffered time in milliseconds.
+         */
+        public void onBufferedPositionChanged(PlaybackControlsRow row, long bufferedProgressMs) {
+        }
+    }
+
+    /**
+     * Base class for an action comprised of a series of icons.
+     */
+    public static abstract class MultiAction extends Action {
+        private int mIndex;
+        private Drawable[] mDrawables;
+        private String[] mLabels;
+        private String[] mLabels2;
+
+        /**
+         * Constructor
+         * @param id The id of the Action.
+         */
+        public MultiAction(int id) {
+            super(id);
+        }
+
+        /**
+         * Sets the array of drawables.  The size of the array defines the range
+         * of valid indices for this action.
+         */
+        public void setDrawables(Drawable[] drawables) {
+            mDrawables = drawables;
+            setIndex(0);
+        }
+
+        /**
+         * Sets the array of strings used as labels.  The size of the array defines the range
+         * of valid indices for this action.  The labels are used to define the accessibility
+         * content description unless secondary labels are provided.
+         */
+        public void setLabels(String[] labels) {
+            mLabels = labels;
+            setIndex(0);
+        }
+
+        /**
+         * Sets the array of strings used as secondary labels.  These labels are used
+         * in place of the primary labels for accessibility content description only.
+         */
+        public void setSecondaryLabels(String[] labels) {
+            mLabels2 = labels;
+            setIndex(0);
+        }
+
+        /**
+         * Returns the number of actions.
+         */
+        public int getActionCount() {
+            if (mDrawables != null) {
+                return mDrawables.length;
+            }
+            if (mLabels != null) {
+                return mLabels.length;
+            }
+            return 0;
+        }
+
+        /**
+         * Returns the drawable at the given index.
+         */
+        public Drawable getDrawable(int index) {
+            return mDrawables == null ? null : mDrawables[index];
+        }
+
+        /**
+         * Returns the label at the given index.
+         */
+        public String getLabel(int index) {
+            return mLabels == null ? null : mLabels[index];
+        }
+
+        /**
+         * Returns the secondary label at the given index.
+         */
+        public String getSecondaryLabel(int index) {
+            return mLabels2 == null ? null : mLabels2[index];
+        }
+
+        /**
+         * Increments the index, wrapping to zero once the end is reached.
+         */
+        public void nextIndex() {
+            setIndex(mIndex < getActionCount() - 1 ? mIndex + 1 : 0);
+        }
+
+        /**
+         * Sets the current index.
+         */
+        public void setIndex(int index) {
+            mIndex = index;
+            if (mDrawables != null) {
+                setIcon(mDrawables[mIndex]);
+            }
+            if (mLabels != null) {
+                setLabel1(mLabels[mIndex]);
+            }
+            if (mLabels2 != null) {
+                setLabel2(mLabels2[mIndex]);
+            }
+        }
+
+        /**
+         * Returns the current index.
+         */
+        public int getIndex() {
+            return mIndex;
+        }
+    }
+
+    /**
+     * An action displaying icons for play and pause.
+     */
+    public static class PlayPauseAction extends MultiAction {
+        /**
+         * Action index for the play icon.
+         * @deprecated Use {@link #INDEX_PLAY}
+         */
+        @Deprecated
+        public static final int PLAY = 0;
+
+        /**
+         * Action index for the pause icon.
+         * @deprecated Use {@link #INDEX_PAUSE}
+         */
+        @Deprecated
+        public static final int PAUSE = 1;
+
+        /**
+         * Action index for the play icon.
+         */
+        public static final int INDEX_PLAY = 0;
+
+        /**
+         * Action index for the pause icon.
+         */
+        public static final int INDEX_PAUSE = 1;
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public PlayPauseAction(Context context) {
+            super(R.id.lb_control_play_pause);
+            Drawable[] drawables = new Drawable[2];
+            drawables[INDEX_PLAY] = getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_play);
+            drawables[INDEX_PAUSE] = getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_pause);
+            setDrawables(drawables);
+
+            String[] labels = new String[drawables.length];
+            labels[INDEX_PLAY] = context.getString(R.string.lb_playback_controls_play);
+            labels[INDEX_PAUSE] = context.getString(R.string.lb_playback_controls_pause);
+            setLabels(labels);
+            addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+            addKeyCode(KeyEvent.KEYCODE_MEDIA_PLAY);
+            addKeyCode(KeyEvent.KEYCODE_MEDIA_PAUSE);
+        }
+    }
+
+    /**
+     * An action displaying an icon for fast forward.
+     */
+    public static class FastForwardAction extends MultiAction {
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public FastForwardAction(Context context) {
+            this(context, 1);
+        }
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         * @param numSpeeds Number of supported fast forward speeds.
+         */
+        public FastForwardAction(Context context, int numSpeeds) {
+            super(R.id.lb_control_fast_forward);
+
+            if (numSpeeds < 1) {
+                throw new IllegalArgumentException("numSpeeds must be > 0");
+            }
+            Drawable[] drawables = new Drawable[numSpeeds + 1];
+            drawables[0] = getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_fast_forward);
+            setDrawables(drawables);
+
+            String[] labels = new String[getActionCount()];
+            labels[0] = context.getString(R.string.lb_playback_controls_fast_forward);
+
+            String[] labels2 = new String[getActionCount()];
+            labels2[0] = labels[0];
+
+            for (int i = 1; i <= numSpeeds; i++) {
+                int multiplier = i + 1;
+                labels[i] = context.getResources().getString(
+                        R.string.lb_control_display_fast_forward_multiplier, multiplier);
+                labels2[i] = context.getResources().getString(
+                        R.string.lb_playback_controls_fast_forward_multiplier, multiplier);
+            }
+            setLabels(labels);
+            setSecondaryLabels(labels2);
+            addKeyCode(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
+        }
+    }
+
+    /**
+     * An action displaying an icon for rewind.
+     */
+    public static class RewindAction extends MultiAction {
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public RewindAction(Context context) {
+            this(context, 1);
+        }
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         * @param numSpeeds Number of supported fast forward speeds.
+         */
+        public RewindAction(Context context, int numSpeeds) {
+            super(R.id.lb_control_fast_rewind);
+
+            if (numSpeeds < 1) {
+                throw new IllegalArgumentException("numSpeeds must be > 0");
+            }
+            Drawable[] drawables = new Drawable[numSpeeds + 1];
+            drawables[0] = getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_rewind);
+            setDrawables(drawables);
+
+            String[] labels = new String[getActionCount()];
+            labels[0] = context.getString(R.string.lb_playback_controls_rewind);
+
+            String[] labels2 = new String[getActionCount()];
+            labels2[0] = labels[0];
+
+            for (int i = 1; i <= numSpeeds; i++) {
+                int multiplier = i + 1;
+                labels[i] = labels[i] = context.getResources().getString(
+                        R.string.lb_control_display_rewind_multiplier, multiplier);
+                labels2[i] = context.getResources().getString(
+                        R.string.lb_playback_controls_rewind_multiplier, multiplier);
+            }
+            setLabels(labels);
+            setSecondaryLabels(labels2);
+            addKeyCode(KeyEvent.KEYCODE_MEDIA_REWIND);
+        }
+    }
+
+    /**
+     * An action displaying an icon for skip next.
+     */
+    public static class SkipNextAction extends Action {
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public SkipNextAction(Context context) {
+            super(R.id.lb_control_skip_next);
+            setIcon(getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_skip_next));
+            setLabel1(context.getString(R.string.lb_playback_controls_skip_next));
+            addKeyCode(KeyEvent.KEYCODE_MEDIA_NEXT);
+        }
+    }
+
+    /**
+     * An action displaying an icon for skip previous.
+     */
+    public static class SkipPreviousAction extends Action {
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public SkipPreviousAction(Context context) {
+            super(R.id.lb_control_skip_previous);
+            setIcon(getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_skip_previous));
+            setLabel1(context.getString(R.string.lb_playback_controls_skip_previous));
+            addKeyCode(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+        }
+    }
+
+    /**
+     * An action displaying an icon for picture-in-picture.
+     */
+    public static class PictureInPictureAction extends Action {
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public PictureInPictureAction(Context context) {
+            super(R.id.lb_control_picture_in_picture);
+            setIcon(getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_picture_in_picture));
+            setLabel1(context.getString(R.string.lb_playback_controls_picture_in_picture));
+            addKeyCode(KeyEvent.KEYCODE_WINDOW);
+        }
+    }
+
+    /**
+     * An action displaying an icon for "more actions".
+     */
+    public static class MoreActions extends Action {
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public MoreActions(Context context) {
+            super(R.id.lb_control_more_actions);
+            setIcon(context.getResources().getDrawable(R.drawable.lb_ic_more));
+            setLabel1(context.getString(R.string.lb_playback_controls_more_actions));
+        }
+    }
+
+    /**
+     * A base class for displaying a thumbs action.
+     */
+    public static abstract class ThumbsAction extends MultiAction {
+        /**
+         * Action index for the solid thumb icon.
+         * @deprecated Use {@link #INDEX_SOLID}
+         */
+        @Deprecated
+        public static final int SOLID = 0;
+
+        /**
+         * Action index for the outline thumb icon.
+         * @deprecated Use {@link #INDEX_OUTLINE}
+         */
+        @Deprecated
+        public static final int OUTLINE = 1;
+
+        /**
+         * Action index for the solid thumb icon.
+         */
+        public static final int INDEX_SOLID = 0;
+
+        /**
+         * Action index for the outline thumb icon.
+         */
+        public static final int INDEX_OUTLINE = 1;
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public ThumbsAction(int id, Context context, int solidIconIndex, int outlineIconIndex) {
+            super(id);
+            Drawable[] drawables = new Drawable[2];
+            drawables[INDEX_SOLID] = getStyledDrawable(context, solidIconIndex);
+            drawables[INDEX_OUTLINE] = getStyledDrawable(context, outlineIconIndex);
+            setDrawables(drawables);
+        }
+    }
+
+    /**
+     * An action displaying an icon for thumbs up.
+     */
+    public static class ThumbsUpAction extends ThumbsAction {
+        public ThumbsUpAction(Context context) {
+            super(R.id.lb_control_thumbs_up, context,
+                    R.styleable.lbPlaybackControlsActionIcons_thumb_up,
+                    R.styleable.lbPlaybackControlsActionIcons_thumb_up_outline);
+            String[] labels = new String[getActionCount()];
+            labels[INDEX_SOLID] = context.getString(R.string.lb_playback_controls_thumb_up);
+            labels[INDEX_OUTLINE] = context.getString(
+                    R.string.lb_playback_controls_thumb_up_outline);
+            setLabels(labels);
+        }
+    }
+
+    /**
+     * An action displaying an icon for thumbs down.
+     */
+    public static class ThumbsDownAction extends ThumbsAction {
+        public ThumbsDownAction(Context context) {
+            super(R.id.lb_control_thumbs_down, context,
+                    R.styleable.lbPlaybackControlsActionIcons_thumb_down,
+                    R.styleable.lbPlaybackControlsActionIcons_thumb_down_outline);
+            String[] labels = new String[getActionCount()];
+            labels[INDEX_SOLID] = context.getString(R.string.lb_playback_controls_thumb_down);
+            labels[INDEX_OUTLINE] = context.getString(
+                    R.string.lb_playback_controls_thumb_down_outline);
+            setLabels(labels);
+        }
+    }
+
+    /**
+     * An action for displaying three repeat states: none, one, or all.
+     */
+    public static class RepeatAction extends MultiAction {
+        /**
+         * Action index for the repeat-none icon.
+         * @deprecated Use {@link #INDEX_NONE}
+         */
+        @Deprecated
+        public static final int NONE = 0;
+
+        /**
+         * Action index for the repeat-all icon.
+         * @deprecated Use {@link #INDEX_ALL}
+         */
+        @Deprecated
+        public static final int ALL = 1;
+
+        /**
+         * Action index for the repeat-one icon.
+         * @deprecated Use {@link #INDEX_ONE}
+         */
+        @Deprecated
+        public static final int ONE = 2;
+
+        /**
+         * Action index for the repeat-none icon.
+         */
+        public static final int INDEX_NONE = 0;
+
+        /**
+         * Action index for the repeat-all icon.
+         */
+        public static final int INDEX_ALL = 1;
+
+        /**
+         * Action index for the repeat-one icon.
+         */
+        public static final int INDEX_ONE = 2;
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public RepeatAction(Context context) {
+            this(context, getIconHighlightColor(context));
+        }
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources
+         * @param highlightColor Color to display the repeat-all and repeat0one icons.
+         */
+        public RepeatAction(Context context, int highlightColor) {
+            this(context, highlightColor, highlightColor);
+        }
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources
+         * @param repeatAllColor Color to display the repeat-all icon.
+         * @param repeatOneColor Color to display the repeat-one icon.
+         */
+        public RepeatAction(Context context, int repeatAllColor, int repeatOneColor) {
+            super(R.id.lb_control_repeat);
+            Drawable[] drawables = new Drawable[3];
+            BitmapDrawable repeatDrawable = (BitmapDrawable) getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_repeat);
+            BitmapDrawable repeatOneDrawable = (BitmapDrawable) getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_repeat_one);
+            drawables[INDEX_NONE] = repeatDrawable;
+            drawables[INDEX_ALL] = repeatDrawable == null ? null
+                    : new BitmapDrawable(context.getResources(),
+                            createBitmap(repeatDrawable.getBitmap(), repeatAllColor));
+            drawables[INDEX_ONE] = repeatOneDrawable == null ? null
+                    : new BitmapDrawable(context.getResources(),
+                            createBitmap(repeatOneDrawable.getBitmap(), repeatOneColor));
+            setDrawables(drawables);
+
+            String[] labels = new String[drawables.length];
+            // Note, labels denote the action taken when clicked
+            labels[INDEX_NONE] = context.getString(R.string.lb_playback_controls_repeat_all);
+            labels[INDEX_ALL] = context.getString(R.string.lb_playback_controls_repeat_one);
+            labels[INDEX_ONE] = context.getString(R.string.lb_playback_controls_repeat_none);
+            setLabels(labels);
+        }
+    }
+
+    /**
+     * An action for displaying a shuffle icon.
+     */
+    public static class ShuffleAction extends MultiAction {
+        /**
+         * Action index for shuffle is off.
+         * @deprecated Use {@link #INDEX_OFF}
+         */
+        @Deprecated
+        public static final int OFF = 0;
+
+        /**
+         * Action index for shuffle is on.
+         * @deprecated Use {@link #INDEX_ON}
+         */
+        @Deprecated
+        public static final int ON = 1;
+
+        /**
+         * Action index for shuffle is off
+         */
+        public static final int INDEX_OFF = 0;
+
+        /**
+         * Action index for shuffle is on.
+         */
+        public static final int INDEX_ON = 1;
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public ShuffleAction(Context context) {
+            this(context, getIconHighlightColor(context));
+        }
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         * @param highlightColor Color for the highlighted icon state.
+         */
+        public ShuffleAction(Context context, int highlightColor) {
+            super(R.id.lb_control_shuffle);
+            BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_shuffle);
+            Drawable[] drawables = new Drawable[2];
+            drawables[INDEX_OFF] = uncoloredDrawable;
+            drawables[INDEX_ON] = new BitmapDrawable(context.getResources(),
+                    createBitmap(uncoloredDrawable.getBitmap(), highlightColor));
+            setDrawables(drawables);
+
+            String[] labels = new String[drawables.length];
+            labels[INDEX_OFF] = context.getString(R.string.lb_playback_controls_shuffle_enable);
+            labels[INDEX_ON] = context.getString(R.string.lb_playback_controls_shuffle_disable);
+            setLabels(labels);
+        }
+    }
+
+    /**
+     * An action for displaying a HQ (High Quality) icon.
+     */
+    public static class HighQualityAction extends MultiAction {
+        /**
+         * Action index for high quality is off.
+         * @deprecated Use {@link #INDEX_OFF}
+         */
+        @Deprecated
+        public static final int OFF = 0;
+
+        /**
+         * Action index for high quality is on.
+         * @deprecated Use {@link #INDEX_ON}
+         */
+        @Deprecated
+        public static final int ON = 1;
+
+        /**
+         * Action index for high quality is off.
+         */
+        public static final int INDEX_OFF = 0;
+
+        /**
+         * Action index for high quality is on.
+         */
+        public static final int INDEX_ON = 1;
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public HighQualityAction(Context context) {
+            this(context, getIconHighlightColor(context));
+        }
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         * @param highlightColor Color for the highlighted icon state.
+         */
+        public HighQualityAction(Context context, int highlightColor) {
+            super(R.id.lb_control_high_quality);
+            BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_high_quality);
+            Drawable[] drawables = new Drawable[2];
+            drawables[INDEX_OFF] = uncoloredDrawable;
+            drawables[INDEX_ON] = new BitmapDrawable(context.getResources(),
+                    createBitmap(uncoloredDrawable.getBitmap(), highlightColor));
+            setDrawables(drawables);
+
+            String[] labels = new String[drawables.length];
+            labels[INDEX_OFF] = context.getString(
+                    R.string.lb_playback_controls_high_quality_enable);
+            labels[INDEX_ON] = context.getString(
+                    R.string.lb_playback_controls_high_quality_disable);
+            setLabels(labels);
+        }
+    }
+
+    /**
+     * An action for displaying a CC (Closed Captioning) icon.
+     */
+    public static class ClosedCaptioningAction extends MultiAction {
+        /**
+         * Action index for closed caption is off.
+         * @deprecated Use {@link #INDEX_OFF}
+         */
+        @Deprecated
+        public static final int OFF = 0;
+
+        /**
+         * Action index for closed caption is on.
+         * @deprecated Use {@link #INDEX_ON}
+         */
+        @Deprecated
+        public static final int ON = 1;
+
+        /**
+         * Action index for closed caption is off.
+         */
+        public static final int INDEX_OFF = 0;
+
+        /**
+         * Action index for closed caption is on.
+         */
+        public static final int INDEX_ON = 1;
+
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         */
+        public ClosedCaptioningAction(Context context) {
+            this(context, getIconHighlightColor(context));
+        }
+
+        /**
+         * Constructor
+         * @param context Context used for loading resources.
+         * @param highlightColor Color for the highlighted icon state.
+         */
+        public ClosedCaptioningAction(Context context, int highlightColor) {
+            super(R.id.lb_control_closed_captioning);
+            BitmapDrawable uncoloredDrawable = (BitmapDrawable) getStyledDrawable(context,
+                    R.styleable.lbPlaybackControlsActionIcons_closed_captioning);
+            Drawable[] drawables = new Drawable[2];
+            drawables[INDEX_OFF] = uncoloredDrawable;
+            drawables[INDEX_ON] = new BitmapDrawable(context.getResources(),
+                    createBitmap(uncoloredDrawable.getBitmap(), highlightColor));
+            setDrawables(drawables);
+
+            String[] labels = new String[drawables.length];
+            labels[INDEX_OFF] = context.getString(
+                    R.string.lb_playback_controls_closed_captioning_enable);
+            labels[INDEX_ON] = context.getString(
+                    R.string.lb_playback_controls_closed_captioning_disable);
+            setLabels(labels);
+        }
+    }
+
+    static Bitmap createBitmap(Bitmap bitmap, int color) {
+        Bitmap dst = bitmap.copy(bitmap.getConfig(), true);
+        Canvas canvas = new Canvas(dst);
+        Paint paint = new Paint();
+        paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
+        canvas.drawBitmap(bitmap, 0, 0, paint);
+        return dst;
+    }
+
+    static int getIconHighlightColor(Context context) {
+        TypedValue outValue = new TypedValue();
+        if (context.getTheme().resolveAttribute(R.attr.playbackControlsIconHighlightColor,
+                outValue, true)) {
+            return outValue.data;
+        }
+        return context.getResources().getColor(R.color.lb_playback_icon_highlight_no_theme);
+    }
+
+    static Drawable getStyledDrawable(Context context, int index) {
+        TypedValue outValue = new TypedValue();
+        if (!context.getTheme().resolveAttribute(
+                R.attr.playbackControlsActionIcons, outValue, false)) {
+            return null;
+        }
+        TypedArray array = context.getTheme().obtainStyledAttributes(outValue.data,
+                R.styleable.lbPlaybackControlsActionIcons);
+        Drawable drawable = array.getDrawable(index);
+        array.recycle();
+        return drawable;
+    }
+
+    private Object mItem;
+    private Drawable mImageDrawable;
+    private ObjectAdapter mPrimaryActionsAdapter;
+    private ObjectAdapter mSecondaryActionsAdapter;
+    private long mTotalTimeMs;
+    private long mCurrentTimeMs;
+    private long mBufferedProgressMs;
+    private OnPlaybackProgressCallback mListener;
+
+    /**
+     * Constructor for a PlaybackControlsRow that displays some details from
+     * the given item.
+     *
+     * @param item The main item for the row.
+     */
+    public PlaybackControlsRow(Object item) {
+        mItem = item;
+    }
+
+    /**
+     * Constructor for a PlaybackControlsRow that has no item details.
+     */
+    public PlaybackControlsRow() {
+    }
+
+    /**
+     * Returns the main item for the details page.
+     */
+    public final Object getItem() {
+        return mItem;
+    }
+
+    /**
+     * Sets a {link @Drawable} image for this row.
+     * <p>If set after the row has been bound to a view, the adapter must be notified that
+     * this row has changed.</p>
+     *
+     * @param drawable The drawable to set.
+     */
+    public final void setImageDrawable(Drawable drawable) {
+        mImageDrawable = drawable;
+    }
+
+    /**
+     * Sets a {@link Bitmap} for this row.
+     * <p>If set after the row has been bound to a view, the adapter must be notified that
+     * this row has changed.</p>
+     *
+     * @param context The context to retrieve display metrics from.
+     * @param bm The bitmap to set.
+     */
+    public final void setImageBitmap(Context context, Bitmap bm) {
+        mImageDrawable = new BitmapDrawable(context.getResources(), bm);
+    }
+
+    /**
+     * Returns the image {@link Drawable} of this row.
+     *
+     * @return The overview's image drawable, or null if no drawable has been
+     *         assigned.
+     */
+    public final Drawable getImageDrawable() {
+        return mImageDrawable;
+    }
+
+    /**
+     * Sets the primary actions {@link ObjectAdapter}.
+     * <p>If set after the row has been bound to a view, the adapter must be notified that
+     * this row has changed.</p>
+     */
+    public final void setPrimaryActionsAdapter(ObjectAdapter adapter) {
+        mPrimaryActionsAdapter = adapter;
+    }
+
+    /**
+     * Sets the secondary actions {@link ObjectAdapter}.
+     * <p>If set after the row has been bound to a view, the adapter must be notified that
+     * this row has changed.</p>
+     */
+    public final void setSecondaryActionsAdapter(ObjectAdapter adapter) {
+        mSecondaryActionsAdapter = adapter;
+    }
+
+    /**
+     * Returns the primary actions {@link ObjectAdapter}.
+     */
+    public final ObjectAdapter getPrimaryActionsAdapter() {
+        return mPrimaryActionsAdapter;
+    }
+
+    /**
+     * Returns the secondary actions {@link ObjectAdapter}.
+     */
+    public final ObjectAdapter getSecondaryActionsAdapter() {
+        return mSecondaryActionsAdapter;
+    }
+
+    /**
+     * Sets the total time in milliseconds for the playback controls row.
+     * <p>If set after the row has been bound to a view, the adapter must be notified that
+     * this row has changed.</p>
+     * @deprecated Use {@link #setDuration(long)}
+     */
+    @Deprecated
+    public void setTotalTime(int ms) {
+        setDuration((long) ms);
+    }
+
+    /**
+     * Sets the total time in milliseconds (long type) for the playback controls row.
+     * @param ms Total time in milliseconds of long type.
+     * @deprecated Use {@link #setDuration(long)}
+     */
+    @Deprecated
+    public void setTotalTimeLong(long ms) {
+        setDuration(ms);
+    }
+
+    /**
+     * Sets the total time in milliseconds (long type) for the playback controls row.
+     * If this row is bound to a view, the view will automatically
+     * be updated to reflect the new value.
+     * @param ms Total time in milliseconds of long type.
+     */
+    public void setDuration(long ms) {
+        if (mTotalTimeMs != ms) {
+            mTotalTimeMs = ms;
+            if (mListener != null) {
+                mListener.onDurationChanged(this, mTotalTimeMs);
+            }
+        }
+    }
+
+    /**
+     * Returns the total time in milliseconds for the playback controls row.
+     * @throws ArithmeticException If total time in milliseconds overflows int.
+     * @deprecated use {@link #getDuration()}
+     */
+    @Deprecated
+    public int getTotalTime() {
+        return MathUtil.safeLongToInt(getTotalTimeLong());
+    }
+
+    /**
+     * Returns the total time in milliseconds of long type for the playback controls row.
+     * @deprecated use {@link #getDuration()}
+     */
+    @Deprecated
+    public long getTotalTimeLong() {
+        return mTotalTimeMs;
+    }
+
+    /**
+     * Returns duration in milliseconds.
+     * @return Duration in milliseconds.
+     */
+    public long getDuration() {
+        return mTotalTimeMs;
+    }
+
+    /**
+     * Sets the current time in milliseconds for the playback controls row.
+     * If this row is bound to a view, the view will automatically
+     * be updated to reflect the new value.
+     * @deprecated use {@link #setCurrentPosition(long)}
+     */
+    @Deprecated
+    public void setCurrentTime(int ms) {
+        setCurrentTimeLong((long) ms);
+    }
+
+    /**
+     * Sets the current time in milliseconds for playback controls row in long type.
+     * @param ms Current time in milliseconds of long type.
+     * @deprecated use {@link #setCurrentPosition(long)}
+     */
+    @Deprecated
+    public void setCurrentTimeLong(long ms) {
+        setCurrentPosition(ms);
+    }
+
+    /**
+     * Sets the current time in milliseconds for the playback controls row.
+     * If this row is bound to a view, the view will automatically
+     * be updated to reflect the new value.
+     * @param ms Current time in milliseconds of long type.
+     */
+    public void setCurrentPosition(long ms) {
+        if (mCurrentTimeMs != ms) {
+            mCurrentTimeMs = ms;
+            if (mListener != null) {
+                mListener.onCurrentPositionChanged(this, mCurrentTimeMs);
+            }
+        }
+    }
+
+    /**
+     * Returns the current time in milliseconds for the playback controls row.
+     * @throws ArithmeticException If current time in milliseconds overflows int.
+     * @deprecated Use {@link #getCurrentPosition()}
+     */
+    @Deprecated
+    public int getCurrentTime() {
+        return MathUtil.safeLongToInt(getCurrentTimeLong());
+    }
+
+    /**
+     * Returns the current time in milliseconds of long type for playback controls row.
+     * @deprecated Use {@link #getCurrentPosition()}
+     */
+    @Deprecated
+    public long getCurrentTimeLong() {
+        return mCurrentTimeMs;
+    }
+
+    /**
+     * Returns the current time in milliseconds of long type for playback controls row.
+     */
+    public long getCurrentPosition() {
+        return mCurrentTimeMs;
+    }
+
+    /**
+     * Sets the buffered progress for the playback controls row.
+     * If this row is bound to a view, the view will automatically
+     * be updated to reflect the new value.
+     * @deprecated Use {@link #setBufferedPosition(long)}
+     */
+    @Deprecated
+    public void setBufferedProgress(int ms) {
+        setBufferedPosition((long) ms);
+    }
+
+    /**
+     * Sets the buffered progress for the playback controls row.
+     * @param ms Buffered progress in milliseconds of long type.
+     * @deprecated Use {@link #setBufferedPosition(long)}
+     */
+    @Deprecated
+    public void setBufferedProgressLong(long ms) {
+        setBufferedPosition(ms);
+    }
+
+    /**
+     * Sets the buffered progress for the playback controls row.
+     * @param ms Buffered progress in milliseconds of long type.
+     */
+    public void setBufferedPosition(long ms) {
+        if (mBufferedProgressMs != ms) {
+            mBufferedProgressMs = ms;
+            if (mListener != null) {
+                mListener.onBufferedPositionChanged(this, mBufferedProgressMs);
+            }
+        }
+    }
+    /**
+     * Returns the buffered progress for the playback controls row.
+     * @throws ArithmeticException If buffered progress in milliseconds overflows int.
+     * @deprecated Use {@link #getBufferedPosition()}
+     */
+    @Deprecated
+    public int getBufferedProgress() {
+        return MathUtil.safeLongToInt(getBufferedPosition());
+    }
+
+    /**
+     * Returns the buffered progress of long type for the playback controls row.
+     * @deprecated Use {@link #getBufferedPosition()}
+     */
+    @Deprecated
+    public long getBufferedProgressLong() {
+        return mBufferedProgressMs;
+    }
+
+    /**
+     * Returns the buffered progress of long type for the playback controls row.
+     */
+    public long getBufferedPosition() {
+        return mBufferedProgressMs;
+    }
+
+    /**
+     * Returns the Action associated with the given keycode, or null if no associated action exists.
+     * Searches the primary adapter first, then the secondary adapter.
+     */
+    public Action getActionForKeyCode(int keyCode) {
+        Action action = getActionForKeyCode(getPrimaryActionsAdapter(), keyCode);
+        if (action != null) {
+            return action;
+        }
+        return getActionForKeyCode(getSecondaryActionsAdapter(), keyCode);
+    }
+
+    /**
+     * Returns the Action associated with the given keycode, or null if no associated action exists.
+     */
+    public Action getActionForKeyCode(ObjectAdapter adapter, int keyCode) {
+        if (adapter != mPrimaryActionsAdapter && adapter != mSecondaryActionsAdapter) {
+            throw new IllegalArgumentException("Invalid adapter");
+        }
+        for (int i = 0; i < adapter.size(); i++) {
+            Action action = (Action) adapter.get(i);
+            if (action.respondsToKeyCode(keyCode)) {
+                return action;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets a listener to be called when the playback state changes.
+     */
+    public void setOnPlaybackProgressChangedListener(OnPlaybackProgressCallback listener) {
+        mListener = listener;
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsRowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowView.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsRowView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackControlsRowView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackControlsRowView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackRowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackRowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackRowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackRowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackSeekDataProvider.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackSeekDataProvider.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackSeekDataProvider.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackSeekDataProvider.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackSeekUi.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackSeekUi.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackSeekUi.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackSeekUi.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackTransportRowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowView.java b/leanback/src/main/java/android/support/v17/leanback/widget/PlaybackTransportRowView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PlaybackTransportRowView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PlaybackTransportRowView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/Presenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/Presenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/Presenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/Presenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PresenterSelector.java b/leanback/src/main/java/android/support/v17/leanback/widget/PresenterSelector.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PresenterSelector.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PresenterSelector.java
diff --git a/leanback/src/android/support/v17/leanback/widget/PresenterSwitcher.java b/leanback/src/main/java/android/support/v17/leanback/widget/PresenterSwitcher.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/PresenterSwitcher.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/PresenterSwitcher.java
diff --git a/leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java b/leanback/src/main/java/android/support/v17/leanback/widget/RecyclerViewParallax.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/RecyclerViewParallax.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/RecyclerViewParallax.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ResizingTextView.java b/leanback/src/main/java/android/support/v17/leanback/widget/ResizingTextView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ResizingTextView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ResizingTextView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/RoundedRectHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/RoundedRectHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/RoundedRectHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/Row.java b/leanback/src/main/java/android/support/v17/leanback/widget/Row.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/Row.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/Row.java
diff --git a/leanback/src/android/support/v17/leanback/widget/RowContainerView.java b/leanback/src/main/java/android/support/v17/leanback/widget/RowContainerView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/RowContainerView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/RowContainerView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/RowHeaderPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/RowHeaderPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/RowHeaderPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/RowHeaderView.java b/leanback/src/main/java/android/support/v17/leanback/widget/RowHeaderView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/RowHeaderView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/RowHeaderView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/RowPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/RowPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/RowPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/RowPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ScaleFrameLayout.java b/leanback/src/main/java/android/support/v17/leanback/widget/ScaleFrameLayout.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ScaleFrameLayout.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ScaleFrameLayout.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SearchBar.java b/leanback/src/main/java/android/support/v17/leanback/widget/SearchBar.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SearchBar.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SearchBar.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SearchEditText.java b/leanback/src/main/java/android/support/v17/leanback/widget/SearchEditText.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SearchEditText.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SearchEditText.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/widget/SearchOrbView.java b/leanback/src/main/java/android/support/v17/leanback/widget/SearchOrbView.java
new file mode 100644
index 0000000..4f9492d
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/widget/SearchOrbView.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v17.leanback.widget;
+
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.support.annotation.ColorInt;
+import android.support.v17.leanback.R;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+/**
+ * <p>A widget that draws a search affordance, represented by a round background and an icon.</p>
+ *
+ * The background color and icon can be customized.
+ */
+public class SearchOrbView extends FrameLayout implements View.OnClickListener {
+    private OnClickListener mListener;
+    private View mRootView;
+    private View mSearchOrbView;
+    private ImageView mIcon;
+    private Drawable mIconDrawable;
+    private Colors mColors;
+    private final float mFocusedZoom;
+    private final int mPulseDurationMs;
+    private final int mScaleDurationMs;
+    private final float mUnfocusedZ;
+    private final float mFocusedZ;
+    private ValueAnimator mColorAnimator;
+    private boolean mColorAnimationEnabled;
+    private boolean mAttachedToWindow;
+
+    /**
+     * A set of colors used to display the search orb.
+     */
+    public static class Colors {
+        private static final float BRIGHTNESS_ALPHA = 0.15f;
+
+        /**
+         * Constructs a color set using the given color for the search orb.
+         * Other colors are provided by the framework.
+         *
+         * @param color The main search orb color.
+         */
+        public Colors(@ColorInt int color) {
+            this(color, color);
+        }
+
+        /**
+         * Constructs a color set using the given colors for the search orb.
+         * Other colors are provided by the framework.
+         *
+         * @param color The main search orb color.
+         * @param brightColor A brighter version of the search orb used for animation.
+         */
+        public Colors(@ColorInt int color, @ColorInt int brightColor) {
+            this(color, brightColor, Color.TRANSPARENT);
+        }
+
+        /**
+         * Constructs a color set using the given colors.
+         *
+         * @param color The main search orb color.
+         * @param brightColor A brighter version of the search orb used for animation.
+         * @param iconColor A color used to tint the search orb icon.
+         */
+        public Colors(@ColorInt int color, @ColorInt int brightColor, @ColorInt int iconColor) {
+            this.color = color;
+            this.brightColor = brightColor == color ? getBrightColor(color) : brightColor;
+            this.iconColor = iconColor;
+        }
+
+        /**
+         * The main color of the search orb.
+         */
+        @ColorInt
+        public int color;
+
+        /**
+         * A brighter version of the search orb used for animation.
+         */
+        @ColorInt
+        public int brightColor;
+
+        /**
+         * A color used to tint the search orb icon.
+         */
+        @ColorInt
+        public int iconColor;
+
+        /**
+         * Computes a default brighter version of the given color.
+         */
+        public static int getBrightColor(int color) {
+            final float brightnessValue = 0xff * BRIGHTNESS_ALPHA;
+            int red = (int)(Color.red(color) * (1 - BRIGHTNESS_ALPHA) + brightnessValue);
+            int green = (int)(Color.green(color) * (1 - BRIGHTNESS_ALPHA) + brightnessValue);
+            int blue = (int)(Color.blue(color) * (1 - BRIGHTNESS_ALPHA) + brightnessValue);
+            int alpha = (int)(Color.alpha(color) * (1 - BRIGHTNESS_ALPHA) + brightnessValue);
+            return Color.argb(alpha, red, green, blue);
+        }
+    }
+
+    private final ArgbEvaluator mColorEvaluator = new ArgbEvaluator();
+
+    private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animator) {
+            Integer color = (Integer) animator.getAnimatedValue();
+            setOrbViewColor(color.intValue());
+        }
+    };
+
+    private ValueAnimator mShadowFocusAnimator;
+
+    private final ValueAnimator.AnimatorUpdateListener mFocusUpdateListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            setSearchOrbZ(animation.getAnimatedFraction());
+        }
+    };
+
+    void setSearchOrbZ(float fraction) {
+        ShadowHelper.getInstance().setZ(mSearchOrbView,
+                mUnfocusedZ + fraction * (mFocusedZ - mUnfocusedZ));
+    }
+
+    public SearchOrbView(Context context) {
+        this(context, null);
+    }
+
+    public SearchOrbView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.searchOrbViewStyle);
+    }
+
+    public SearchOrbView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        final Resources res = context.getResources();
+
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        mRootView = inflater.inflate(getLayoutResourceId(), this, true);
+        mSearchOrbView = mRootView.findViewById(R.id.search_orb);
+        mIcon = (ImageView) mRootView.findViewById(R.id.icon);
+
+        mFocusedZoom = context.getResources().getFraction(
+                R.fraction.lb_search_orb_focused_zoom, 1, 1);
+        mPulseDurationMs = context.getResources().getInteger(
+                R.integer.lb_search_orb_pulse_duration_ms);
+        mScaleDurationMs = context.getResources().getInteger(
+                R.integer.lb_search_orb_scale_duration_ms);
+        mFocusedZ = context.getResources().getDimensionPixelSize(
+                R.dimen.lb_search_orb_focused_z);
+        mUnfocusedZ = context.getResources().getDimensionPixelSize(
+                R.dimen.lb_search_orb_unfocused_z);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.lbSearchOrbView,
+                defStyleAttr, 0);
+
+        Drawable img = a.getDrawable(R.styleable.lbSearchOrbView_searchOrbIcon);
+        if (img == null) {
+            img = res.getDrawable(R.drawable.lb_ic_in_app_search);
+        }
+        setOrbIcon(img);
+
+        int defColor = res.getColor(R.color.lb_default_search_color);
+        int color = a.getColor(R.styleable.lbSearchOrbView_searchOrbColor, defColor);
+        int brightColor = a.getColor(
+                R.styleable.lbSearchOrbView_searchOrbBrightColor, color);
+        int iconColor = a.getColor(R.styleable.lbSearchOrbView_searchOrbIconColor, Color.TRANSPARENT);
+        setOrbColors(new Colors(color, brightColor, iconColor));
+        a.recycle();
+
+        setFocusable(true);
+        setClipChildren(false);
+        setOnClickListener(this);
+        setSoundEffectsEnabled(false);
+        setSearchOrbZ(0);
+
+        // Icon has no background, but must be on top of the search orb view
+        ShadowHelper.getInstance().setZ(mIcon, mFocusedZ);
+    }
+
+    int getLayoutResourceId() {
+        return R.layout.lb_search_orb;
+    }
+
+    void scaleOrbViewOnly(float scale) {
+        mSearchOrbView.setScaleX(scale);
+        mSearchOrbView.setScaleY(scale);
+    }
+
+    float getFocusedZoom() {
+        return mFocusedZoom;
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (null != mListener) {
+            mListener.onClick(view);
+        }
+    }
+
+    private void startShadowFocusAnimation(boolean gainFocus, int duration) {
+        if (mShadowFocusAnimator == null) {
+            mShadowFocusAnimator = ValueAnimator.ofFloat(0f, 1f);
+            mShadowFocusAnimator.addUpdateListener(mFocusUpdateListener);
+        }
+        if (gainFocus) {
+            mShadowFocusAnimator.start();
+        } else {
+            mShadowFocusAnimator.reverse();
+        }
+        mShadowFocusAnimator.setDuration(duration);
+    }
+
+    @Override
+    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        animateOnFocus(gainFocus);
+    }
+
+    void animateOnFocus(boolean hasFocus) {
+        final float zoom = hasFocus ? mFocusedZoom : 1f;
+        mRootView.animate().scaleX(zoom).scaleY(zoom).setDuration(mScaleDurationMs).start();
+        startShadowFocusAnimation(hasFocus, mScaleDurationMs);
+        enableOrbColorAnimation(hasFocus);
+    }
+
+    /**
+     * Sets the orb icon.
+     * @param icon the drawable to be used as the icon
+     */
+    public void setOrbIcon(Drawable icon) {
+        mIconDrawable = icon;
+        mIcon.setImageDrawable(mIconDrawable);
+    }
+
+    /**
+     * Returns the orb icon
+     * @return the drawable used as the icon
+     */
+    public Drawable getOrbIcon() {
+        return mIconDrawable;
+    }
+
+    /**
+     * Sets the on click listener for the orb.
+     * @param listener The listener.
+     */
+    public void setOnOrbClickedListener(OnClickListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Sets the background color of the search orb.
+     * Other colors will be provided by the framework.
+     *
+     * @param color the RGBA color
+     */
+    public void setOrbColor(int color) {
+        setOrbColors(new Colors(color, color, Color.TRANSPARENT));
+    }
+
+    /**
+     * Sets the search orb colors.
+     * Other colors are provided by the framework.
+     * @deprecated Use {@link #setOrbColors(Colors)} instead.
+     */
+    @Deprecated
+    public void setOrbColor(@ColorInt int color, @ColorInt int brightColor) {
+        setOrbColors(new Colors(color, brightColor, Color.TRANSPARENT));
+    }
+
+    /**
+     * Returns the orb color
+     * @return the RGBA color
+     */
+    @ColorInt
+    public int getOrbColor() {
+        return mColors.color;
+    }
+
+    /**
+     * Sets the {@link Colors} used to display the search orb.
+     */
+    public void setOrbColors(Colors colors) {
+        mColors = colors;
+        mIcon.setColorFilter(mColors.iconColor);
+
+        if (mColorAnimator == null) {
+            setOrbViewColor(mColors.color);
+        } else {
+            enableOrbColorAnimation(true);
+        }
+    }
+
+    /**
+     * Returns the {@link Colors} used to display the search orb.
+     */
+    public Colors getOrbColors() {
+        return mColors;
+    }
+
+    /**
+     * Enables or disables the orb color animation.
+     *
+     * <p>
+     * Orb color animation is handled automatically when the orb is focused/unfocused,
+     * however, an app may choose to override the current animation state, for example
+     * when an activity is paused.
+     * </p>
+     */
+    public void enableOrbColorAnimation(boolean enable) {
+        mColorAnimationEnabled = enable;
+        updateColorAnimator();
+    }
+
+    private void updateColorAnimator() {
+        if (mColorAnimator != null) {
+            mColorAnimator.end();
+            mColorAnimator = null;
+        }
+        if (mColorAnimationEnabled && mAttachedToWindow) {
+            // TODO: set interpolator (material if available)
+            mColorAnimator = ValueAnimator.ofObject(mColorEvaluator,
+                    mColors.color, mColors.brightColor, mColors.color);
+            mColorAnimator.setRepeatCount(ValueAnimator.INFINITE);
+            mColorAnimator.setDuration(mPulseDurationMs * 2);
+            mColorAnimator.addUpdateListener(mUpdateListener);
+            mColorAnimator.start();
+        }
+    }
+
+    void setOrbViewColor(int color) {
+        if (mSearchOrbView.getBackground() instanceof GradientDrawable) {
+            ((GradientDrawable) mSearchOrbView.getBackground()).setColor(color);
+        }
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mAttachedToWindow = true;
+        updateColorAnimator();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        mAttachedToWindow = false;
+        // Must stop infinite animation to prevent activity leak
+        updateColorAnimator();
+        super.onDetachedFromWindow();
+    }
+}
diff --git a/leanback/src/android/support/v17/leanback/widget/SectionRow.java b/leanback/src/main/java/android/support/v17/leanback/widget/SectionRow.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SectionRow.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SectionRow.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SeekBar.java b/leanback/src/main/java/android/support/v17/leanback/widget/SeekBar.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SeekBar.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SeekBar.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ShadowHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/ShadowHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ShadowHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ShadowHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java b/leanback/src/main/java/android/support/v17/leanback/widget/ShadowOverlayContainer.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ShadowOverlayContainer.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ShadowOverlayContainer.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/ShadowOverlayHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ShadowOverlayHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ShadowOverlayHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SinglePresenterSelector.java b/leanback/src/main/java/android/support/v17/leanback/widget/SinglePresenterSelector.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SinglePresenterSelector.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SinglePresenterSelector.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SingleRow.java b/leanback/src/main/java/android/support/v17/leanback/widget/SingleRow.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SingleRow.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SingleRow.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SparseArrayObjectAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/SparseArrayObjectAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SparseArrayObjectAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SparseArrayObjectAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SpeechOrbView.java b/leanback/src/main/java/android/support/v17/leanback/widget/SpeechOrbView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SpeechOrbView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SpeechOrbView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/SpeechRecognitionCallback.java b/leanback/src/main/java/android/support/v17/leanback/widget/SpeechRecognitionCallback.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/SpeechRecognitionCallback.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/SpeechRecognitionCallback.java
diff --git a/leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java b/leanback/src/main/java/android/support/v17/leanback/widget/StaggeredGrid.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/StaggeredGrid.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/StaggeredGrid.java
diff --git a/leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java b/leanback/src/main/java/android/support/v17/leanback/widget/StaggeredGridDefault.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/StaggeredGridDefault.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/StaggeredGridDefault.java
diff --git a/leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/StaticShadowHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/StaticShadowHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/StaticShadowHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/StreamingTextView.java b/leanback/src/main/java/android/support/v17/leanback/widget/StreamingTextView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/StreamingTextView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/StreamingTextView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ThumbsBar.java b/leanback/src/main/java/android/support/v17/leanback/widget/ThumbsBar.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ThumbsBar.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ThumbsBar.java
diff --git a/leanback/src/android/support/v17/leanback/widget/TitleHelper.java b/leanback/src/main/java/android/support/v17/leanback/widget/TitleHelper.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/TitleHelper.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/TitleHelper.java
diff --git a/leanback/src/android/support/v17/leanback/widget/TitleView.java b/leanback/src/main/java/android/support/v17/leanback/widget/TitleView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/TitleView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/TitleView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/TitleViewAdapter.java b/leanback/src/main/java/android/support/v17/leanback/widget/TitleViewAdapter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/TitleViewAdapter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/TitleViewAdapter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/Util.java b/leanback/src/main/java/android/support/v17/leanback/widget/Util.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/Util.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/Util.java
diff --git a/leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java b/leanback/src/main/java/android/support/v17/leanback/widget/VerticalGridPresenter.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/VerticalGridPresenter.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/VerticalGridPresenter.java
diff --git a/leanback/src/android/support/v17/leanback/widget/VerticalGridView.java b/leanback/src/main/java/android/support/v17/leanback/widget/VerticalGridView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/VerticalGridView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/VerticalGridView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/VideoSurfaceView.java b/leanback/src/main/java/android/support/v17/leanback/widget/VideoSurfaceView.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/VideoSurfaceView.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/VideoSurfaceView.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ViewHolderTask.java b/leanback/src/main/java/android/support/v17/leanback/widget/ViewHolderTask.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ViewHolderTask.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ViewHolderTask.java
diff --git a/leanback/src/android/support/v17/leanback/widget/ViewsStateBundle.java b/leanback/src/main/java/android/support/v17/leanback/widget/ViewsStateBundle.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/ViewsStateBundle.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/ViewsStateBundle.java
diff --git a/leanback/src/android/support/v17/leanback/widget/Visibility.java b/leanback/src/main/java/android/support/v17/leanback/widget/Visibility.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/Visibility.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/Visibility.java
diff --git a/leanback/src/android/support/v17/leanback/widget/WindowAlignment.java b/leanback/src/main/java/android/support/v17/leanback/widget/WindowAlignment.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/WindowAlignment.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/WindowAlignment.java
diff --git a/leanback/src/android/support/v17/leanback/widget/package-info.java b/leanback/src/main/java/android/support/v17/leanback/widget/package-info.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/package-info.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/package-info.java
diff --git a/leanback/src/main/java/android/support/v17/leanback/widget/picker/DatePicker.java b/leanback/src/main/java/android/support/v17/leanback/widget/picker/DatePicker.java
new file mode 100644
index 0000000..2925306
--- /dev/null
+++ b/leanback/src/main/java/android/support/v17/leanback/widget/picker/DatePicker.java
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.support.v17.leanback.widget.picker;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.annotation.RestrictTo;
+import android.support.v17.leanback.R;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * {@link DatePicker} is a directly subclass of {@link Picker}.
+ * This class is a widget for selecting a date. The date can be selected by a
+ * year, month, and day Columns. The "minDate" and "maxDate" from which dates to be selected
+ * can be customized.  The columns can be customized by attribute "datePickerFormat" or
+ * {@link #setDatePickerFormat(String)}.
+ *
+ * @attr ref R.styleable#lbDatePicker_android_maxDate
+ * @attr ref R.styleable#lbDatePicker_android_minDate
+ * @attr ref R.styleable#lbDatePicker_datePickerFormat
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class DatePicker extends Picker {
+
+    static final String LOG_TAG = "DatePicker";
+
+    private String mDatePickerFormat;
+    PickerColumn mMonthColumn;
+    PickerColumn mDayColumn;
+    PickerColumn mYearColumn;
+    int mColMonthIndex;
+    int mColDayIndex;
+    int mColYearIndex;
+
+    final static String DATE_FORMAT = "MM/dd/yyyy";
+    final DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
+    PickerUtility.DateConstant mConstant;
+
+    Calendar mMinDate;
+    Calendar mMaxDate;
+    Calendar mCurrentDate;
+    Calendar mTempDate;
+
+    public DatePicker(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DatePicker(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+
+        updateCurrentLocale();
+
+        final TypedArray attributesArray = context.obtainStyledAttributes(attrs,
+                R.styleable.lbDatePicker);
+        String minDate = attributesArray.getString(R.styleable.lbDatePicker_android_minDate);
+        String maxDate = attributesArray.getString(R.styleable.lbDatePicker_android_maxDate);
+        mTempDate.clear();
+        if (!TextUtils.isEmpty(minDate)) {
+            if (!parseDate(minDate, mTempDate)) {
+                mTempDate.set(1900, 0, 1);
+            }
+        } else {
+            mTempDate.set(1900, 0, 1);
+        }
+        mMinDate.setTimeInMillis(mTempDate.getTimeInMillis());
+
+        mTempDate.clear();
+        if (!TextUtils.isEmpty(maxDate)) {
+            if (!parseDate(maxDate, mTempDate)) {
+                mTempDate.set(2100, 0, 1);
+            }
+        } else {
+            mTempDate.set(2100, 0, 1);
+        }
+        mMaxDate.setTimeInMillis(mTempDate.getTimeInMillis());
+
+        String datePickerFormat = attributesArray
+                .getString(R.styleable.lbDatePicker_datePickerFormat);
+        if (TextUtils.isEmpty(datePickerFormat)) {
+            datePickerFormat = new String(
+                    android.text.format.DateFormat.getDateFormatOrder(context));
+        }
+        setDatePickerFormat(datePickerFormat);
+    }
+
+    private boolean parseDate(String date, Calendar outDate) {
+        try {
+            outDate.setTime(mDateFormat.parse(date));
+            return true;
+        } catch (ParseException e) {
+            Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
+            return false;
+        }
+    }
+
+    /**
+     * Returns the best localized representation of the date for the given date format and the
+     * current locale.
+     *
+     * @param datePickerFormat The date format skeleton (e.g. "dMy") used to gather the
+     *                         appropriate representation of the date in the current locale.
+     *
+     * @return The best localized representation of the date for the given date format
+     */
+    String getBestYearMonthDayPattern(String datePickerFormat) {
+        final String yearPattern;
+        if (PickerUtility.SUPPORTS_BEST_DATE_TIME_PATTERN) {
+            yearPattern = android.text.format.DateFormat.getBestDateTimePattern(mConstant.locale,
+                    datePickerFormat);
+        } else {
+            final java.text.DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(
+                    getContext());
+            if (dateFormat instanceof SimpleDateFormat) {
+                yearPattern = ((SimpleDateFormat) dateFormat).toLocalizedPattern();
+            } else {
+                yearPattern = DATE_FORMAT;
+            }
+        }
+        return TextUtils.isEmpty(yearPattern) ? DATE_FORMAT : yearPattern;
+    }
+
+    /**
+     * Extracts the separators used to separate date fields (including before the first and after
+     * the last date field). The separators can vary based on the individual locale date format,
+     * defined in the Unicode CLDR and cannot be supposed to be "/".
+     *
+     * See http://unicode.org/cldr/trac/browser/trunk/common/main
+     *
+     * For example, for Croatian in dMy format, the best localized representation is "d. M. y". This
+     * method returns {"", ".", ".", "."}, where the first separator indicates nothing needs to be
+     * displayed to the left of the day field, "." needs to be displayed tos the right of the day
+     * field, and so forth.
+     *
+     * @return The ArrayList of separators to populate between the actual date fields in the
+     * DatePicker.
+     */
+    List<CharSequence> extractSeparators() {
+        // Obtain the time format string per the current locale (e.g. h:mm a)
+        String hmaPattern = getBestYearMonthDayPattern(mDatePickerFormat);
+
+        List<CharSequence> separators = new ArrayList<>();
+        StringBuilder sb = new StringBuilder();
+        char lastChar = '\0';
+        // See http://www.unicode.org/reports/tr35/tr35-dates.html for date formats
+        final char[] dateFormats = {'Y', 'y', 'M', 'm', 'D', 'd'};
+        boolean processingQuote = false;
+        for (int i = 0; i < hmaPattern.length(); i++) {
+            char c = hmaPattern.charAt(i);
+            if (c == ' ') {
+                continue;
+            }
+            if (c == '\'') {
+                if (!processingQuote) {
+                    sb.setLength(0);
+                    processingQuote = true;
+                } else {
+                    processingQuote = false;
+                }
+                continue;
+            }
+            if (processingQuote) {
+                sb.append(c);
+            } else {
+                if (isAnyOf(c, dateFormats)) {
+                    if (c != lastChar) {
+                        separators.add(sb.toString());
+                        sb.setLength(0);
+                    }
+                } else {
+                    sb.append(c);
+                }
+            }
+            lastChar = c;
+        }
+        separators.add(sb.toString());
+        return separators;
+    }
+
+    private static boolean isAnyOf(char c, char[] any) {
+        for (int i = 0; i < any.length; i++) {
+            if (c == any[i]) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Changes format of showing dates.  For example "YMD".
+     * @param datePickerFormat Format of showing dates.
+     */
+    public void setDatePickerFormat(String datePickerFormat) {
+        if (TextUtils.isEmpty(datePickerFormat)) {
+            datePickerFormat = new String(
+                    android.text.format.DateFormat.getDateFormatOrder(getContext()));
+        }
+        if (TextUtils.equals(mDatePickerFormat, datePickerFormat)) {
+            return;
+        }
+        mDatePickerFormat = datePickerFormat;
+        List<CharSequence> separators = extractSeparators();
+        if (separators.size() != (datePickerFormat.length() + 1)) {
+            throw new IllegalStateException("Separators size: " + separators.size() + " must equal"
+                    + " the size of datePickerFormat: " + datePickerFormat.length() + " + 1");
+        }
+        setSeparators(separators);
+        mYearColumn = mMonthColumn = mDayColumn = null;
+        mColYearIndex = mColDayIndex = mColMonthIndex = -1;
+        String dateFieldsPattern = datePickerFormat.toUpperCase();
+        ArrayList<PickerColumn> columns = new ArrayList<PickerColumn>(3);
+        for (int i = 0; i < dateFieldsPattern.length(); i++) {
+            switch (dateFieldsPattern.charAt(i)) {
+            case 'Y':
+                if (mYearColumn != null) {
+                    throw new IllegalArgumentException("datePicker format error");
+                }
+                columns.add(mYearColumn = new PickerColumn());
+                mColYearIndex = i;
+                mYearColumn.setLabelFormat("%d");
+                break;
+            case 'M':
+                if (mMonthColumn != null) {
+                    throw new IllegalArgumentException("datePicker format error");
+                }
+                columns.add(mMonthColumn = new PickerColumn());
+                mMonthColumn.setStaticLabels(mConstant.months);
+                mColMonthIndex = i;
+                break;
+            case 'D':
+                if (mDayColumn != null) {
+                    throw new IllegalArgumentException("datePicker format error");
+                }
+                columns.add(mDayColumn = new PickerColumn());
+                mDayColumn.setLabelFormat("%02d");
+                mColDayIndex = i;
+                break;
+            default:
+                throw new IllegalArgumentException("datePicker format error");
+            }
+        }
+        setColumns(columns);
+        updateSpinners(false);
+    }
+
+    /**
+     * Get format of showing dates.  For example "YMD".  Default value is from
+     * {@link android.text.format.DateFormat#getDateFormatOrder(Context)}.
+     * @return Format of showing dates.
+     */
+    public String getDatePickerFormat() {
+        return mDatePickerFormat;
+    }
+
+    private void updateCurrentLocale() {
+        mConstant = PickerUtility.getDateConstantInstance(Locale.getDefault(),
+                getContext().getResources());
+        mTempDate = PickerUtility.getCalendarForLocale(mTempDate, mConstant.locale);
+        mMinDate = PickerUtility.getCalendarForLocale(mMinDate, mConstant.locale);
+        mMaxDate = PickerUtility.getCalendarForLocale(mMaxDate, mConstant.locale);
+        mCurrentDate = PickerUtility.getCalendarForLocale(mCurrentDate, mConstant.locale);
+
+        if (mMonthColumn != null) {
+            mMonthColumn.setStaticLabels(mConstant.months);
+            setColumnAt(mColMonthIndex, mMonthColumn);
+        }
+    }
+
+    @Override
+    public final void onColumnValueChanged(int column, int newVal) {
+        mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
+        // take care of wrapping of days and months to update greater fields
+        int oldVal = getColumnAt(column).getCurrentValue();
+        if (column == mColDayIndex) {
+            mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
+        } else if (column == mColMonthIndex) {
+            mTempDate.add(Calendar.MONTH, newVal - oldVal);
+        } else if (column == mColYearIndex) {
+            mTempDate.add(Calendar.YEAR, newVal - oldVal);
+        } else {
+            throw new IllegalArgumentException();
+        }
+        setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
+                mTempDate.get(Calendar.DAY_OF_MONTH));
+        updateSpinners(false);
+    }
+
+
+    /**
+     * Sets the minimal date supported by this {@link DatePicker} in
+     * milliseconds since January 1, 1970 00:00:00 in
+     * {@link TimeZone#getDefault()} time zone.
+     *
+     * @param minDate The minimal supported date.
+     */
+    public void setMinDate(long minDate) {
+        mTempDate.setTimeInMillis(minDate);
+        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
+                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
+            return;
+        }
+        mMinDate.setTimeInMillis(minDate);
+        if (mCurrentDate.before(mMinDate)) {
+            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
+        }
+        updateSpinners(false);
+    }
+
+
+    /**
+     * Gets the minimal date supported by this {@link DatePicker} in
+     * milliseconds since January 1, 1970 00:00:00 in
+     * {@link TimeZone#getDefault()} time zone.
+     * <p>
+     * Note: The default minimal date is 01/01/1900.
+     * <p>
+     *
+     * @return The minimal supported date.
+     */
+    public long getMinDate() {
+        return mMinDate.getTimeInMillis();
+    }
+
+    /**
+     * Sets the maximal date supported by this {@link DatePicker} in
+     * milliseconds since January 1, 1970 00:00:00 in
+     * {@link TimeZone#getDefault()} time zone.
+     *
+     * @param maxDate The maximal supported date.
+     */
+    public void setMaxDate(long maxDate) {
+        mTempDate.setTimeInMillis(maxDate);
+        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
+                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
+            return;
+        }
+        mMaxDate.setTimeInMillis(maxDate);
+        if (mCurrentDate.after(mMaxDate)) {
+            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+        }
+        updateSpinners(false);
+    }
+
+    /**
+     * Gets the maximal date supported by this {@link DatePicker} in
+     * milliseconds since January 1, 1970 00:00:00 in
+     * {@link TimeZone#getDefault()} time zone.
+     * <p>
+     * Note: The default maximal date is 12/31/2100.
+     * <p>
+     *
+     * @return The maximal supported date.
+     */
+    public long getMaxDate() {
+        return mMaxDate.getTimeInMillis();
+    }
+
+    /**
+     * Gets current date value in milliseconds since January 1, 1970 00:00:00 in
+     * {@link TimeZone#getDefault()} time zone.
+     *
+     * @return Current date values.
+     */
+    public long getDate() {
+        return mCurrentDate.getTimeInMillis();
+    }
+
+    private void setDate(int year, int month, int dayOfMonth) {
+        mCurrentDate.set(year, month, dayOfMonth);
+        if (mCurrentDate.before(mMinDate)) {
+            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
+        } else if (mCurrentDate.after(mMaxDate)) {
+            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+        }
+    }
+
+    /**
+     * Update the current date.
+     *
+     * @param year The year.
+     * @param month The month which is <strong>starting from zero</strong>.
+     * @param dayOfMonth The day of the month.
+     * @param animation True to run animation to scroll the column.
+     */
+    public void updateDate(int year, int month, int dayOfMonth, boolean animation) {
+        if (!isNewDate(year, month, dayOfMonth)) {
+            return;
+        }
+        setDate(year, month, dayOfMonth);
+        updateSpinners(animation);
+    }
+
+    private boolean isNewDate(int year, int month, int dayOfMonth) {
+        return (mCurrentDate.get(Calendar.YEAR) != year
+                || mCurrentDate.get(Calendar.MONTH) != dayOfMonth
+                || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month);
+    }
+
+    private static boolean updateMin(PickerColumn column, int value) {
+        if (value != column.getMinValue()) {
+            column.setMinValue(value);
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean updateMax(PickerColumn column, int value) {
+        if (value != column.getMaxValue()) {
+            column.setMaxValue(value);
+            return true;
+        }
+        return false;
+    }
+
+    private static final int[] DATE_FIELDS = {Calendar.DAY_OF_MONTH, Calendar.MONTH, Calendar.YEAR};
+
+    // Following implementation always keeps up-to-date date ranges (min & max values) no matter
+    // what the currently selected date is. This prevents the constant updating of date values while
+    // scrolling vertically and thus fixes the animation jumps that used to happen when we reached
+    // the endpoint date field values since the adapter values do not change while scrolling up
+    // & down across a single field.
+    void updateSpinnersImpl(boolean animation) {
+        // set the spinner ranges respecting the min and max dates
+        int dateFieldIndices[] = {mColDayIndex, mColMonthIndex, mColYearIndex};
+
+        boolean allLargerDateFieldsHaveBeenEqualToMinDate = true;
+        boolean allLargerDateFieldsHaveBeenEqualToMaxDate = true;
+        for(int i = DATE_FIELDS.length - 1; i >= 0; i--) {
+            boolean dateFieldChanged = false;
+            if (dateFieldIndices[i] < 0)
+                continue;
+
+            int currField = DATE_FIELDS[i];
+            PickerColumn currPickerColumn = getColumnAt(dateFieldIndices[i]);
+
+            if (allLargerDateFieldsHaveBeenEqualToMinDate) {
+                dateFieldChanged |= updateMin(currPickerColumn,
+                        mMinDate.get(currField));
+            } else {
+                dateFieldChanged |= updateMin(currPickerColumn,
+                        mCurrentDate.getActualMinimum(currField));
+            }
+
+            if (allLargerDateFieldsHaveBeenEqualToMaxDate) {
+                dateFieldChanged |= updateMax(currPickerColumn,
+                        mMaxDate.get(currField));
+            } else {
+                dateFieldChanged |= updateMax(currPickerColumn,
+                        mCurrentDate.getActualMaximum(currField));
+            }
+
+            allLargerDateFieldsHaveBeenEqualToMinDate &=
+                    (mCurrentDate.get(currField) == mMinDate.get(currField));
+            allLargerDateFieldsHaveBeenEqualToMaxDate &=
+                    (mCurrentDate.get(currField) == mMaxDate.get(currField));
+
+            if (dateFieldChanged) {
+                setColumnAt(dateFieldIndices[i], currPickerColumn);
+            }
+            setColumnValue(dateFieldIndices[i], mCurrentDate.get(currField), animation);
+        }
+    }
+
+    private void updateSpinners(final boolean animation) {
+        // update range in a post call.  The reason is that RV does not allow notifyDataSetChange()
+        // in scroll pass.  UpdateSpinner can be called in a scroll pass, UpdateSpinner() may
+        // notifyDataSetChange to update the range.
+        post(new Runnable() {
+            @Override
+            public void run() {
+                updateSpinnersImpl(animation);
+            }
+        });
+    }
+}
\ No newline at end of file
diff --git a/leanback/src/android/support/v17/leanback/widget/picker/Picker.java b/leanback/src/main/java/android/support/v17/leanback/widget/picker/Picker.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/picker/Picker.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/picker/Picker.java
diff --git a/leanback/src/android/support/v17/leanback/widget/picker/PickerColumn.java b/leanback/src/main/java/android/support/v17/leanback/widget/picker/PickerColumn.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/picker/PickerColumn.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/picker/PickerColumn.java
diff --git a/leanback/src/android/support/v17/leanback/widget/picker/PickerUtility.java b/leanback/src/main/java/android/support/v17/leanback/widget/picker/PickerUtility.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/picker/PickerUtility.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/picker/PickerUtility.java
diff --git a/leanback/src/android/support/v17/leanback/widget/picker/TimePicker.java b/leanback/src/main/java/android/support/v17/leanback/widget/picker/TimePicker.java
similarity index 100%
rename from leanback/src/android/support/v17/leanback/widget/picker/TimePicker.java
rename to leanback/src/main/java/android/support/v17/leanback/widget/picker/TimePicker.java
diff --git a/leanback/res/anim/lb_decelerator_2.xml b/leanback/src/main/res/anim/lb_decelerator_2.xml
similarity index 100%
rename from leanback/res/anim/lb_decelerator_2.xml
rename to leanback/src/main/res/anim/lb_decelerator_2.xml
diff --git a/leanback/res/anim/lb_decelerator_4.xml b/leanback/src/main/res/anim/lb_decelerator_4.xml
similarity index 100%
rename from leanback/res/anim/lb_decelerator_4.xml
rename to leanback/src/main/res/anim/lb_decelerator_4.xml
diff --git a/leanback/res/animator-v21/lb_onboarding_description_enter.xml b/leanback/src/main/res/animator-v21/lb_onboarding_description_enter.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_onboarding_description_enter.xml
rename to leanback/src/main/res/animator-v21/lb_onboarding_description_enter.xml
diff --git a/leanback/res/animator-v21/lb_onboarding_logo_enter.xml b/leanback/src/main/res/animator-v21/lb_onboarding_logo_enter.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_onboarding_logo_enter.xml
rename to leanback/src/main/res/animator-v21/lb_onboarding_logo_enter.xml
diff --git a/leanback/res/animator-v21/lb_onboarding_logo_exit.xml b/leanback/src/main/res/animator-v21/lb_onboarding_logo_exit.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_onboarding_logo_exit.xml
rename to leanback/src/main/res/animator-v21/lb_onboarding_logo_exit.xml
diff --git a/leanback/res/animator-v21/lb_onboarding_page_indicator_enter.xml b/leanback/src/main/res/animator-v21/lb_onboarding_page_indicator_enter.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_onboarding_page_indicator_enter.xml
rename to leanback/src/main/res/animator-v21/lb_onboarding_page_indicator_enter.xml
diff --git a/leanback/res/animator-v21/lb_onboarding_title_enter.xml b/leanback/src/main/res/animator-v21/lb_onboarding_title_enter.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_onboarding_title_enter.xml
rename to leanback/src/main/res/animator-v21/lb_onboarding_title_enter.xml
diff --git a/leanback/res/animator-v21/lb_playback_bg_fade_in.xml b/leanback/src/main/res/animator-v21/lb_playback_bg_fade_in.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_playback_bg_fade_in.xml
rename to leanback/src/main/res/animator-v21/lb_playback_bg_fade_in.xml
diff --git a/leanback/res/animator-v21/lb_playback_bg_fade_out.xml b/leanback/src/main/res/animator-v21/lb_playback_bg_fade_out.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_playback_bg_fade_out.xml
rename to leanback/src/main/res/animator-v21/lb_playback_bg_fade_out.xml
diff --git a/leanback/res/animator-v21/lb_playback_description_fade_out.xml b/leanback/src/main/res/animator-v21/lb_playback_description_fade_out.xml
similarity index 100%
rename from leanback/res/animator-v21/lb_playback_description_fade_out.xml
rename to leanback/src/main/res/animator-v21/lb_playback_description_fade_out.xml
diff --git a/leanback/res/animator/lb_guidedactions_item_pressed.xml b/leanback/src/main/res/animator/lb_guidedactions_item_pressed.xml
similarity index 100%
rename from leanback/res/animator/lb_guidedactions_item_pressed.xml
rename to leanback/src/main/res/animator/lb_guidedactions_item_pressed.xml
diff --git a/leanback/res/animator/lb_guidedactions_item_unpressed.xml b/leanback/src/main/res/animator/lb_guidedactions_item_unpressed.xml
similarity index 100%
rename from leanback/res/animator/lb_guidedactions_item_unpressed.xml
rename to leanback/src/main/res/animator/lb_guidedactions_item_unpressed.xml
diff --git a/leanback/res/animator/lb_guidedstep_slide_down.xml b/leanback/src/main/res/animator/lb_guidedstep_slide_down.xml
similarity index 100%
rename from leanback/res/animator/lb_guidedstep_slide_down.xml
rename to leanback/src/main/res/animator/lb_guidedstep_slide_down.xml
diff --git a/leanback/res/animator/lb_guidedstep_slide_up.xml b/leanback/src/main/res/animator/lb_guidedstep_slide_up.xml
similarity index 100%
rename from leanback/res/animator/lb_guidedstep_slide_up.xml
rename to leanback/src/main/res/animator/lb_guidedstep_slide_up.xml
diff --git a/leanback/res/animator/lb_onboarding_description_enter.xml b/leanback/src/main/res/animator/lb_onboarding_description_enter.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_description_enter.xml
rename to leanback/src/main/res/animator/lb_onboarding_description_enter.xml
diff --git a/leanback/res/animator/lb_onboarding_logo_enter.xml b/leanback/src/main/res/animator/lb_onboarding_logo_enter.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_logo_enter.xml
rename to leanback/src/main/res/animator/lb_onboarding_logo_enter.xml
diff --git a/leanback/res/animator/lb_onboarding_logo_exit.xml b/leanback/src/main/res/animator/lb_onboarding_logo_exit.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_logo_exit.xml
rename to leanback/src/main/res/animator/lb_onboarding_logo_exit.xml
diff --git a/leanback/res/animator/lb_onboarding_page_indicator_enter.xml b/leanback/src/main/res/animator/lb_onboarding_page_indicator_enter.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_page_indicator_enter.xml
rename to leanback/src/main/res/animator/lb_onboarding_page_indicator_enter.xml
diff --git a/leanback/res/animator/lb_onboarding_page_indicator_fade_in.xml b/leanback/src/main/res/animator/lb_onboarding_page_indicator_fade_in.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_page_indicator_fade_in.xml
rename to leanback/src/main/res/animator/lb_onboarding_page_indicator_fade_in.xml
diff --git a/leanback/res/animator/lb_onboarding_page_indicator_fade_out.xml b/leanback/src/main/res/animator/lb_onboarding_page_indicator_fade_out.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_page_indicator_fade_out.xml
rename to leanback/src/main/res/animator/lb_onboarding_page_indicator_fade_out.xml
diff --git a/leanback/res/animator/lb_onboarding_start_button_fade_in.xml b/leanback/src/main/res/animator/lb_onboarding_start_button_fade_in.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_start_button_fade_in.xml
rename to leanback/src/main/res/animator/lb_onboarding_start_button_fade_in.xml
diff --git a/leanback/res/animator/lb_onboarding_start_button_fade_out.xml b/leanback/src/main/res/animator/lb_onboarding_start_button_fade_out.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_start_button_fade_out.xml
rename to leanback/src/main/res/animator/lb_onboarding_start_button_fade_out.xml
diff --git a/leanback/res/animator/lb_onboarding_title_enter.xml b/leanback/src/main/res/animator/lb_onboarding_title_enter.xml
similarity index 100%
rename from leanback/res/animator/lb_onboarding_title_enter.xml
rename to leanback/src/main/res/animator/lb_onboarding_title_enter.xml
diff --git a/leanback/res/animator/lb_playback_bg_fade_in.xml b/leanback/src/main/res/animator/lb_playback_bg_fade_in.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_bg_fade_in.xml
rename to leanback/src/main/res/animator/lb_playback_bg_fade_in.xml
diff --git a/leanback/res/animator/lb_playback_bg_fade_out.xml b/leanback/src/main/res/animator/lb_playback_bg_fade_out.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_bg_fade_out.xml
rename to leanback/src/main/res/animator/lb_playback_bg_fade_out.xml
diff --git a/leanback/res/animator/lb_playback_controls_fade_in.xml b/leanback/src/main/res/animator/lb_playback_controls_fade_in.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_controls_fade_in.xml
rename to leanback/src/main/res/animator/lb_playback_controls_fade_in.xml
diff --git a/leanback/res/animator/lb_playback_controls_fade_out.xml b/leanback/src/main/res/animator/lb_playback_controls_fade_out.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_controls_fade_out.xml
rename to leanback/src/main/res/animator/lb_playback_controls_fade_out.xml
diff --git a/leanback/res/animator/lb_playback_description_fade_in.xml b/leanback/src/main/res/animator/lb_playback_description_fade_in.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_description_fade_in.xml
rename to leanback/src/main/res/animator/lb_playback_description_fade_in.xml
diff --git a/leanback/res/animator/lb_playback_description_fade_out.xml b/leanback/src/main/res/animator/lb_playback_description_fade_out.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_description_fade_out.xml
rename to leanback/src/main/res/animator/lb_playback_description_fade_out.xml
diff --git a/leanback/res/animator/lb_playback_rows_fade_in.xml b/leanback/src/main/res/animator/lb_playback_rows_fade_in.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_rows_fade_in.xml
rename to leanback/src/main/res/animator/lb_playback_rows_fade_in.xml
diff --git a/leanback/res/animator/lb_playback_rows_fade_out.xml b/leanback/src/main/res/animator/lb_playback_rows_fade_out.xml
similarity index 100%
rename from leanback/res/animator/lb_playback_rows_fade_out.xml
rename to leanback/src/main/res/animator/lb_playback_rows_fade_out.xml
diff --git a/leanback/res/drawable-hdpi/lb_action_bg_focused.9.png b/leanback/src/main/res/drawable-hdpi/lb_action_bg_focused.9.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_action_bg_focused.9.png
rename to leanback/src/main/res/drawable-hdpi/lb_action_bg_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_ic_actions_right_arrow.png b/leanback/src/main/res/drawable-hdpi/lb_ic_actions_right_arrow.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_ic_actions_right_arrow.png
rename to leanback/src/main/res/drawable-hdpi/lb_ic_actions_right_arrow.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_ic_in_app_search.png b/leanback/src/main/res/drawable-hdpi/lb_ic_in_app_search.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_ic_in_app_search.png
rename to leanback/src/main/res/drawable-hdpi/lb_ic_in_app_search.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_ic_sad_cloud.png b/leanback/src/main/res/drawable-hdpi/lb_ic_sad_cloud.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_ic_sad_cloud.png
rename to leanback/src/main/res/drawable-hdpi/lb_ic_sad_cloud.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_ic_search_mic.png b/leanback/src/main/res/drawable-hdpi/lb_ic_search_mic.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_ic_search_mic.png
rename to leanback/src/main/res/drawable-hdpi/lb_ic_search_mic.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_ic_search_mic_out.png b/leanback/src/main/res/drawable-hdpi/lb_ic_search_mic_out.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_ic_search_mic_out.png
rename to leanback/src/main/res/drawable-hdpi/lb_ic_search_mic_out.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_in_app_search_bg.9.png b/leanback/src/main/res/drawable-hdpi/lb_in_app_search_bg.9.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_in_app_search_bg.9.png
rename to leanback/src/main/res/drawable-hdpi/lb_in_app_search_bg.9.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_in_app_search_shadow_focused.9.png b/leanback/src/main/res/drawable-hdpi/lb_in_app_search_shadow_focused.9.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_in_app_search_shadow_focused.9.png
rename to leanback/src/main/res/drawable-hdpi/lb_in_app_search_shadow_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-hdpi/lb_in_app_search_shadow_normal.9.png b/leanback/src/main/res/drawable-hdpi/lb_in_app_search_shadow_normal.9.png
similarity index 100%
rename from leanback/res/drawable-hdpi/lb_in_app_search_shadow_normal.9.png
rename to leanback/src/main/res/drawable-hdpi/lb_in_app_search_shadow_normal.9.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_action_bg_focused.9.png b/leanback/src/main/res/drawable-mdpi/lb_action_bg_focused.9.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_action_bg_focused.9.png
rename to leanback/src/main/res/drawable-mdpi/lb_action_bg_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_ic_actions_right_arrow.png b/leanback/src/main/res/drawable-mdpi/lb_ic_actions_right_arrow.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_ic_actions_right_arrow.png
rename to leanback/src/main/res/drawable-mdpi/lb_ic_actions_right_arrow.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_ic_in_app_search.png b/leanback/src/main/res/drawable-mdpi/lb_ic_in_app_search.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_ic_in_app_search.png
rename to leanback/src/main/res/drawable-mdpi/lb_ic_in_app_search.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_ic_sad_cloud.png b/leanback/src/main/res/drawable-mdpi/lb_ic_sad_cloud.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_ic_sad_cloud.png
rename to leanback/src/main/res/drawable-mdpi/lb_ic_sad_cloud.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_ic_search_mic.png b/leanback/src/main/res/drawable-mdpi/lb_ic_search_mic.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_ic_search_mic.png
rename to leanback/src/main/res/drawable-mdpi/lb_ic_search_mic.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_ic_search_mic_out.png b/leanback/src/main/res/drawable-mdpi/lb_ic_search_mic_out.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_ic_search_mic_out.png
rename to leanback/src/main/res/drawable-mdpi/lb_ic_search_mic_out.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_in_app_search_bg.9.png b/leanback/src/main/res/drawable-mdpi/lb_in_app_search_bg.9.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_in_app_search_bg.9.png
rename to leanback/src/main/res/drawable-mdpi/lb_in_app_search_bg.9.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_in_app_search_shadow_focused.9.png b/leanback/src/main/res/drawable-mdpi/lb_in_app_search_shadow_focused.9.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_in_app_search_shadow_focused.9.png
rename to leanback/src/main/res/drawable-mdpi/lb_in_app_search_shadow_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-mdpi/lb_in_app_search_shadow_normal.9.png b/leanback/src/main/res/drawable-mdpi/lb_in_app_search_shadow_normal.9.png
similarity index 100%
rename from leanback/res/drawable-mdpi/lb_in_app_search_shadow_normal.9.png
rename to leanback/src/main/res/drawable-mdpi/lb_in_app_search_shadow_normal.9.png
Binary files differ
diff --git a/leanback/res/drawable-v21/lb_action_bg.xml b/leanback/src/main/res/drawable-v21/lb_action_bg.xml
similarity index 100%
rename from leanback/res/drawable-v21/lb_action_bg.xml
rename to leanback/src/main/res/drawable-v21/lb_action_bg.xml
diff --git a/leanback/res/drawable-v21/lb_card_foreground.xml b/leanback/src/main/res/drawable-v21/lb_card_foreground.xml
similarity index 100%
rename from leanback/res/drawable-v21/lb_card_foreground.xml
rename to leanback/src/main/res/drawable-v21/lb_card_foreground.xml
diff --git a/leanback/res/drawable-v21/lb_control_button_primary.xml b/leanback/src/main/res/drawable-v21/lb_control_button_primary.xml
similarity index 100%
rename from leanback/res/drawable-v21/lb_control_button_primary.xml
rename to leanback/src/main/res/drawable-v21/lb_control_button_primary.xml
diff --git a/leanback/res/drawable-v21/lb_control_button_secondary.xml b/leanback/src/main/res/drawable-v21/lb_control_button_secondary.xml
similarity index 100%
rename from leanback/res/drawable-v21/lb_control_button_secondary.xml
rename to leanback/src/main/res/drawable-v21/lb_control_button_secondary.xml
diff --git a/leanback/res/drawable-v21/lb_selectable_item_rounded_rect.xml b/leanback/src/main/res/drawable-v21/lb_selectable_item_rounded_rect.xml
similarity index 100%
rename from leanback/res/drawable-v21/lb_selectable_item_rounded_rect.xml
rename to leanback/src/main/res/drawable-v21/lb_selectable_item_rounded_rect.xml
diff --git a/leanback/res/drawable-xhdpi/lb_action_bg_focused.9.png b/leanback/src/main/res/drawable-xhdpi/lb_action_bg_focused.9.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_action_bg_focused.9.png
rename to leanback/src/main/res/drawable-xhdpi/lb_action_bg_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_card_shadow_focused.9.png b/leanback/src/main/res/drawable-xhdpi/lb_card_shadow_focused.9.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_card_shadow_focused.9.png
rename to leanback/src/main/res/drawable-xhdpi/lb_card_shadow_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_card_shadow_normal.9.png b/leanback/src/main/res/drawable-xhdpi/lb_card_shadow_normal.9.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_card_shadow_normal.9.png
rename to leanback/src/main/res/drawable-xhdpi/lb_card_shadow_normal.9.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_actions_right_arrow.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_actions_right_arrow.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_actions_right_arrow.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_actions_right_arrow.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_cc.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_cc.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_cc.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_cc.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_fast_forward.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_fast_forward.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_fast_forward.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_fast_forward.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_fast_rewind.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_fast_rewind.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_fast_rewind.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_fast_rewind.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_guidedactions_item_chevron.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_guidedactions_item_chevron.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_guidedactions_item_chevron.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_guidedactions_item_chevron.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_hq.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_hq.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_hq.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_hq.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_in_app_search.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_in_app_search.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_in_app_search.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_in_app_search.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_loop.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_loop.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_loop.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_loop.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_loop_one.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_loop_one.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_loop_one.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_loop_one.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_more.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_more.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_more.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_more.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_nav_arrow.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_nav_arrow.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_nav_arrow.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_nav_arrow.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_pause.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_pause.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_pause.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_pause.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_pip.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_pip.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_pip.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_pip.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_play.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_play.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_play.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_play.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_play_fit.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_play_fit.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_play_fit.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_play_fit.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_playback_loop.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_playback_loop.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_playback_loop.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_playback_loop.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_replay.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_replay.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_replay.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_replay.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_sad_cloud.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_sad_cloud.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_sad_cloud.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_sad_cloud.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_search_mic.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_search_mic.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_search_mic.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_search_mic.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_search_mic_out.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_search_mic_out.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_search_mic_out.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_search_mic_out.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_shuffle.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_shuffle.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_shuffle.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_shuffle.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_skip_next.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_skip_next.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_skip_next.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_skip_next.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_skip_previous.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_skip_previous.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_skip_previous.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_skip_previous.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_stop.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_stop.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_stop.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_stop.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_thumb_down.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_down.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_thumb_down.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_down.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_thumb_down_outline.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_down_outline.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_thumb_down_outline.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_down_outline.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_thumb_up.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_up.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_thumb_up.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_up.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_ic_thumb_up_outline.png b/leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_up_outline.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_ic_thumb_up_outline.png
rename to leanback/src/main/res/drawable-xhdpi/lb_ic_thumb_up_outline.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_in_app_search_bg.9.png b/leanback/src/main/res/drawable-xhdpi/lb_in_app_search_bg.9.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_in_app_search_bg.9.png
rename to leanback/src/main/res/drawable-xhdpi/lb_in_app_search_bg.9.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_in_app_search_shadow_focused.9.png b/leanback/src/main/res/drawable-xhdpi/lb_in_app_search_shadow_focused.9.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_in_app_search_shadow_focused.9.png
rename to leanback/src/main/res/drawable-xhdpi/lb_in_app_search_shadow_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_in_app_search_shadow_normal.9.png b/leanback/src/main/res/drawable-xhdpi/lb_in_app_search_shadow_normal.9.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_in_app_search_shadow_normal.9.png
rename to leanback/src/main/res/drawable-xhdpi/lb_in_app_search_shadow_normal.9.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_text_dot_one.png b/leanback/src/main/res/drawable-xhdpi/lb_text_dot_one.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_text_dot_one.png
rename to leanback/src/main/res/drawable-xhdpi/lb_text_dot_one.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_text_dot_one_small.png b/leanback/src/main/res/drawable-xhdpi/lb_text_dot_one_small.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_text_dot_one_small.png
rename to leanback/src/main/res/drawable-xhdpi/lb_text_dot_one_small.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_text_dot_two.png b/leanback/src/main/res/drawable-xhdpi/lb_text_dot_two.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_text_dot_two.png
rename to leanback/src/main/res/drawable-xhdpi/lb_text_dot_two.png
Binary files differ
diff --git a/leanback/res/drawable-xhdpi/lb_text_dot_two_small.png b/leanback/src/main/res/drawable-xhdpi/lb_text_dot_two_small.png
similarity index 100%
rename from leanback/res/drawable-xhdpi/lb_text_dot_two_small.png
rename to leanback/src/main/res/drawable-xhdpi/lb_text_dot_two_small.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_action_bg_focused.9.png b/leanback/src/main/res/drawable-xxhdpi/lb_action_bg_focused.9.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_action_bg_focused.9.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_action_bg_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_ic_actions_right_arrow.png b/leanback/src/main/res/drawable-xxhdpi/lb_ic_actions_right_arrow.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_ic_actions_right_arrow.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_ic_actions_right_arrow.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_ic_in_app_search.png b/leanback/src/main/res/drawable-xxhdpi/lb_ic_in_app_search.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_ic_in_app_search.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_ic_in_app_search.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_ic_sad_cloud.png b/leanback/src/main/res/drawable-xxhdpi/lb_ic_sad_cloud.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_ic_sad_cloud.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_ic_sad_cloud.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_ic_search_mic.png b/leanback/src/main/res/drawable-xxhdpi/lb_ic_search_mic.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_ic_search_mic.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_ic_search_mic.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_ic_search_mic_out.png b/leanback/src/main/res/drawable-xxhdpi/lb_ic_search_mic_out.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_ic_search_mic_out.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_ic_search_mic_out.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_in_app_search_bg.9.png b/leanback/src/main/res/drawable-xxhdpi/lb_in_app_search_bg.9.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_in_app_search_bg.9.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_in_app_search_bg.9.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_in_app_search_shadow_focused.9.png b/leanback/src/main/res/drawable-xxhdpi/lb_in_app_search_shadow_focused.9.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_in_app_search_shadow_focused.9.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_in_app_search_shadow_focused.9.png
Binary files differ
diff --git a/leanback/res/drawable-xxhdpi/lb_in_app_search_shadow_normal.9.png b/leanback/src/main/res/drawable-xxhdpi/lb_in_app_search_shadow_normal.9.png
similarity index 100%
rename from leanback/res/drawable-xxhdpi/lb_in_app_search_shadow_normal.9.png
rename to leanback/src/main/res/drawable-xxhdpi/lb_in_app_search_shadow_normal.9.png
Binary files differ
diff --git a/leanback/res/drawable/lb_background.xml b/leanback/src/main/res/drawable/lb_background.xml
similarity index 100%
rename from leanback/res/drawable/lb_background.xml
rename to leanback/src/main/res/drawable/lb_background.xml
diff --git a/leanback/res/drawable/lb_card_foreground.xml b/leanback/src/main/res/drawable/lb_card_foreground.xml
similarity index 100%
rename from leanback/res/drawable/lb_card_foreground.xml
rename to leanback/src/main/res/drawable/lb_card_foreground.xml
diff --git a/leanback/res/drawable/lb_control_button_primary.xml b/leanback/src/main/res/drawable/lb_control_button_primary.xml
similarity index 100%
rename from leanback/res/drawable/lb_control_button_primary.xml
rename to leanback/src/main/res/drawable/lb_control_button_primary.xml
diff --git a/leanback/res/drawable/lb_control_button_secondary.xml b/leanback/src/main/res/drawable/lb_control_button_secondary.xml
similarity index 100%
rename from leanback/res/drawable/lb_control_button_secondary.xml
rename to leanback/src/main/res/drawable/lb_control_button_secondary.xml
diff --git a/leanback/res/drawable/lb_headers_right_fading.xml b/leanback/src/main/res/drawable/lb_headers_right_fading.xml
similarity index 100%
rename from leanback/res/drawable/lb_headers_right_fading.xml
rename to leanback/src/main/res/drawable/lb_headers_right_fading.xml
diff --git a/leanback/res/drawable/lb_onboarding_start_button_background.xml b/leanback/src/main/res/drawable/lb_onboarding_start_button_background.xml
similarity index 100%
rename from leanback/res/drawable/lb_onboarding_start_button_background.xml
rename to leanback/src/main/res/drawable/lb_onboarding_start_button_background.xml
diff --git a/leanback/res/drawable/lb_playback_now_playing_bar.xml b/leanback/src/main/res/drawable/lb_playback_now_playing_bar.xml
similarity index 100%
rename from leanback/res/drawable/lb_playback_now_playing_bar.xml
rename to leanback/src/main/res/drawable/lb_playback_now_playing_bar.xml
diff --git a/leanback/res/drawable/lb_playback_progress_bar.xml b/leanback/src/main/res/drawable/lb_playback_progress_bar.xml
similarity index 100%
rename from leanback/res/drawable/lb_playback_progress_bar.xml
rename to leanback/src/main/res/drawable/lb_playback_progress_bar.xml
diff --git a/leanback/res/drawable/lb_search_orb.xml b/leanback/src/main/res/drawable/lb_search_orb.xml
similarity index 100%
rename from leanback/res/drawable/lb_search_orb.xml
rename to leanback/src/main/res/drawable/lb_search_orb.xml
diff --git a/leanback/res/drawable/lb_speech_orb.xml b/leanback/src/main/res/drawable/lb_speech_orb.xml
similarity index 100%
rename from leanback/res/drawable/lb_speech_orb.xml
rename to leanback/src/main/res/drawable/lb_speech_orb.xml
diff --git a/leanback/res/layout/lb_action_1_line.xml b/leanback/src/main/res/layout/lb_action_1_line.xml
similarity index 100%
rename from leanback/res/layout/lb_action_1_line.xml
rename to leanback/src/main/res/layout/lb_action_1_line.xml
diff --git a/leanback/res/layout/lb_action_2_lines.xml b/leanback/src/main/res/layout/lb_action_2_lines.xml
similarity index 100%
rename from leanback/res/layout/lb_action_2_lines.xml
rename to leanback/src/main/res/layout/lb_action_2_lines.xml
diff --git a/leanback/res/layout/lb_background_window.xml b/leanback/src/main/res/layout/lb_background_window.xml
similarity index 100%
rename from leanback/res/layout/lb_background_window.xml
rename to leanback/src/main/res/layout/lb_background_window.xml
diff --git a/leanback/res/layout/lb_browse_fragment.xml b/leanback/src/main/res/layout/lb_browse_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_browse_fragment.xml
rename to leanback/src/main/res/layout/lb_browse_fragment.xml
diff --git a/leanback/res/layout/lb_browse_title.xml b/leanback/src/main/res/layout/lb_browse_title.xml
similarity index 100%
rename from leanback/res/layout/lb_browse_title.xml
rename to leanback/src/main/res/layout/lb_browse_title.xml
diff --git a/leanback/res/layout/lb_control_bar.xml b/leanback/src/main/res/layout/lb_control_bar.xml
similarity index 100%
rename from leanback/res/layout/lb_control_bar.xml
rename to leanback/src/main/res/layout/lb_control_bar.xml
diff --git a/leanback/res/layout/lb_control_button_primary.xml b/leanback/src/main/res/layout/lb_control_button_primary.xml
similarity index 100%
rename from leanback/res/layout/lb_control_button_primary.xml
rename to leanback/src/main/res/layout/lb_control_button_primary.xml
diff --git a/leanback/res/layout/lb_control_button_secondary.xml b/leanback/src/main/res/layout/lb_control_button_secondary.xml
similarity index 100%
rename from leanback/res/layout/lb_control_button_secondary.xml
rename to leanback/src/main/res/layout/lb_control_button_secondary.xml
diff --git a/leanback/res/layout/lb_details_description.xml b/leanback/src/main/res/layout/lb_details_description.xml
similarity index 100%
rename from leanback/res/layout/lb_details_description.xml
rename to leanback/src/main/res/layout/lb_details_description.xml
diff --git a/leanback/res/layout/lb_details_fragment.xml b/leanback/src/main/res/layout/lb_details_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_details_fragment.xml
rename to leanback/src/main/res/layout/lb_details_fragment.xml
diff --git a/leanback/res/layout/lb_details_overview.xml b/leanback/src/main/res/layout/lb_details_overview.xml
similarity index 100%
rename from leanback/res/layout/lb_details_overview.xml
rename to leanback/src/main/res/layout/lb_details_overview.xml
diff --git a/leanback/res/layout/lb_divider.xml b/leanback/src/main/res/layout/lb_divider.xml
similarity index 100%
rename from leanback/res/layout/lb_divider.xml
rename to leanback/src/main/res/layout/lb_divider.xml
diff --git a/leanback/res/layout/lb_error_fragment.xml b/leanback/src/main/res/layout/lb_error_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_error_fragment.xml
rename to leanback/src/main/res/layout/lb_error_fragment.xml
diff --git a/leanback/res/layout/lb_fullwidth_details_overview.xml b/leanback/src/main/res/layout/lb_fullwidth_details_overview.xml
similarity index 100%
rename from leanback/res/layout/lb_fullwidth_details_overview.xml
rename to leanback/src/main/res/layout/lb_fullwidth_details_overview.xml
diff --git a/leanback/res/layout/lb_fullwidth_details_overview_logo.xml b/leanback/src/main/res/layout/lb_fullwidth_details_overview_logo.xml
similarity index 100%
rename from leanback/res/layout/lb_fullwidth_details_overview_logo.xml
rename to leanback/src/main/res/layout/lb_fullwidth_details_overview_logo.xml
diff --git a/leanback/res/layout/lb_guidance.xml b/leanback/src/main/res/layout/lb_guidance.xml
similarity index 100%
rename from leanback/res/layout/lb_guidance.xml
rename to leanback/src/main/res/layout/lb_guidance.xml
diff --git a/leanback/res/layout/lb_guidedactions.xml b/leanback/src/main/res/layout/lb_guidedactions.xml
similarity index 100%
rename from leanback/res/layout/lb_guidedactions.xml
rename to leanback/src/main/res/layout/lb_guidedactions.xml
diff --git a/leanback/res/layout/lb_guidedactions_datepicker_item.xml b/leanback/src/main/res/layout/lb_guidedactions_datepicker_item.xml
similarity index 100%
rename from leanback/res/layout/lb_guidedactions_datepicker_item.xml
rename to leanback/src/main/res/layout/lb_guidedactions_datepicker_item.xml
diff --git a/leanback/res/layout/lb_guidedactions_item.xml b/leanback/src/main/res/layout/lb_guidedactions_item.xml
similarity index 100%
rename from leanback/res/layout/lb_guidedactions_item.xml
rename to leanback/src/main/res/layout/lb_guidedactions_item.xml
diff --git a/leanback/res/layout/lb_guidedbuttonactions.xml b/leanback/src/main/res/layout/lb_guidedbuttonactions.xml
similarity index 100%
rename from leanback/res/layout/lb_guidedbuttonactions.xml
rename to leanback/src/main/res/layout/lb_guidedbuttonactions.xml
diff --git a/leanback/res/layout/lb_guidedstep_background.xml b/leanback/src/main/res/layout/lb_guidedstep_background.xml
similarity index 100%
rename from leanback/res/layout/lb_guidedstep_background.xml
rename to leanback/src/main/res/layout/lb_guidedstep_background.xml
diff --git a/leanback/res/layout/lb_guidedstep_fragment.xml b/leanback/src/main/res/layout/lb_guidedstep_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_guidedstep_fragment.xml
rename to leanback/src/main/res/layout/lb_guidedstep_fragment.xml
diff --git a/leanback/res/layout/lb_header.xml b/leanback/src/main/res/layout/lb_header.xml
similarity index 100%
rename from leanback/res/layout/lb_header.xml
rename to leanback/src/main/res/layout/lb_header.xml
diff --git a/leanback/res/layout/lb_headers_fragment.xml b/leanback/src/main/res/layout/lb_headers_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_headers_fragment.xml
rename to leanback/src/main/res/layout/lb_headers_fragment.xml
diff --git a/leanback/res/layout/lb_image_card_view.xml b/leanback/src/main/res/layout/lb_image_card_view.xml
similarity index 100%
rename from leanback/res/layout/lb_image_card_view.xml
rename to leanback/src/main/res/layout/lb_image_card_view.xml
diff --git a/leanback/res/layout/lb_image_card_view_themed_badge_left.xml b/leanback/src/main/res/layout/lb_image_card_view_themed_badge_left.xml
similarity index 100%
rename from leanback/res/layout/lb_image_card_view_themed_badge_left.xml
rename to leanback/src/main/res/layout/lb_image_card_view_themed_badge_left.xml
diff --git a/leanback/res/layout/lb_image_card_view_themed_badge_right.xml b/leanback/src/main/res/layout/lb_image_card_view_themed_badge_right.xml
similarity index 100%
rename from leanback/res/layout/lb_image_card_view_themed_badge_right.xml
rename to leanback/src/main/res/layout/lb_image_card_view_themed_badge_right.xml
diff --git a/leanback/res/layout/lb_image_card_view_themed_content.xml b/leanback/src/main/res/layout/lb_image_card_view_themed_content.xml
similarity index 100%
rename from leanback/res/layout/lb_image_card_view_themed_content.xml
rename to leanback/src/main/res/layout/lb_image_card_view_themed_content.xml
diff --git a/leanback/res/layout/lb_image_card_view_themed_title.xml b/leanback/src/main/res/layout/lb_image_card_view_themed_title.xml
similarity index 100%
rename from leanback/res/layout/lb_image_card_view_themed_title.xml
rename to leanback/src/main/res/layout/lb_image_card_view_themed_title.xml
diff --git a/leanback/res/layout/lb_list_row.xml b/leanback/src/main/res/layout/lb_list_row.xml
similarity index 100%
rename from leanback/res/layout/lb_list_row.xml
rename to leanback/src/main/res/layout/lb_list_row.xml
diff --git a/leanback/res/layout/lb_list_row_hovercard.xml b/leanback/src/main/res/layout/lb_list_row_hovercard.xml
similarity index 100%
rename from leanback/res/layout/lb_list_row_hovercard.xml
rename to leanback/src/main/res/layout/lb_list_row_hovercard.xml
diff --git a/leanback/res/layout/lb_media_item_number_view_flipper.xml b/leanback/src/main/res/layout/lb_media_item_number_view_flipper.xml
similarity index 100%
rename from leanback/res/layout/lb_media_item_number_view_flipper.xml
rename to leanback/src/main/res/layout/lb_media_item_number_view_flipper.xml
diff --git a/leanback/res/layout/lb_media_list_header.xml b/leanback/src/main/res/layout/lb_media_list_header.xml
similarity index 100%
rename from leanback/res/layout/lb_media_list_header.xml
rename to leanback/src/main/res/layout/lb_media_list_header.xml
diff --git a/leanback/res/layout/lb_onboarding_fragment.xml b/leanback/src/main/res/layout/lb_onboarding_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_onboarding_fragment.xml
rename to leanback/src/main/res/layout/lb_onboarding_fragment.xml
diff --git a/leanback/res/layout/lb_picker.xml b/leanback/src/main/res/layout/lb_picker.xml
similarity index 100%
rename from leanback/res/layout/lb_picker.xml
rename to leanback/src/main/res/layout/lb_picker.xml
diff --git a/leanback/res/layout/lb_picker_column.xml b/leanback/src/main/res/layout/lb_picker_column.xml
similarity index 100%
rename from leanback/res/layout/lb_picker_column.xml
rename to leanback/src/main/res/layout/lb_picker_column.xml
diff --git a/leanback/res/layout/lb_picker_item.xml b/leanback/src/main/res/layout/lb_picker_item.xml
similarity index 100%
rename from leanback/res/layout/lb_picker_item.xml
rename to leanback/src/main/res/layout/lb_picker_item.xml
diff --git a/leanback/res/layout/lb_picker_separator.xml b/leanback/src/main/res/layout/lb_picker_separator.xml
similarity index 100%
rename from leanback/res/layout/lb_picker_separator.xml
rename to leanback/src/main/res/layout/lb_picker_separator.xml
diff --git a/leanback/res/layout/lb_playback_controls.xml b/leanback/src/main/res/layout/lb_playback_controls.xml
similarity index 100%
rename from leanback/res/layout/lb_playback_controls.xml
rename to leanback/src/main/res/layout/lb_playback_controls.xml
diff --git a/leanback/res/layout/lb_playback_controls_row.xml b/leanback/src/main/res/layout/lb_playback_controls_row.xml
similarity index 100%
rename from leanback/res/layout/lb_playback_controls_row.xml
rename to leanback/src/main/res/layout/lb_playback_controls_row.xml
diff --git a/leanback/res/layout/lb_playback_fragment.xml b/leanback/src/main/res/layout/lb_playback_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_playback_fragment.xml
rename to leanback/src/main/res/layout/lb_playback_fragment.xml
diff --git a/leanback/res/layout/lb_playback_now_playing_bars.xml b/leanback/src/main/res/layout/lb_playback_now_playing_bars.xml
similarity index 100%
rename from leanback/res/layout/lb_playback_now_playing_bars.xml
rename to leanback/src/main/res/layout/lb_playback_now_playing_bars.xml
diff --git a/leanback/res/layout/lb_playback_transport_controls.xml b/leanback/src/main/res/layout/lb_playback_transport_controls.xml
similarity index 100%
rename from leanback/res/layout/lb_playback_transport_controls.xml
rename to leanback/src/main/res/layout/lb_playback_transport_controls.xml
diff --git a/leanback/res/layout/lb_playback_transport_controls_row.xml b/leanback/src/main/res/layout/lb_playback_transport_controls_row.xml
similarity index 100%
rename from leanback/res/layout/lb_playback_transport_controls_row.xml
rename to leanback/src/main/res/layout/lb_playback_transport_controls_row.xml
diff --git a/leanback/res/layout/lb_row_container.xml b/leanback/src/main/res/layout/lb_row_container.xml
similarity index 100%
rename from leanback/res/layout/lb_row_container.xml
rename to leanback/src/main/res/layout/lb_row_container.xml
diff --git a/leanback/res/layout/lb_row_header.xml b/leanback/src/main/res/layout/lb_row_header.xml
similarity index 100%
rename from leanback/res/layout/lb_row_header.xml
rename to leanback/src/main/res/layout/lb_row_header.xml
diff --git a/leanback/res/layout/lb_row_media_item.xml b/leanback/src/main/res/layout/lb_row_media_item.xml
similarity index 100%
rename from leanback/res/layout/lb_row_media_item.xml
rename to leanback/src/main/res/layout/lb_row_media_item.xml
diff --git a/leanback/res/layout/lb_row_media_item_action.xml b/leanback/src/main/res/layout/lb_row_media_item_action.xml
similarity index 100%
rename from leanback/res/layout/lb_row_media_item_action.xml
rename to leanback/src/main/res/layout/lb_row_media_item_action.xml
diff --git a/leanback/res/layout/lb_rows_fragment.xml b/leanback/src/main/res/layout/lb_rows_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_rows_fragment.xml
rename to leanback/src/main/res/layout/lb_rows_fragment.xml
diff --git a/leanback/res/layout/lb_search_bar.xml b/leanback/src/main/res/layout/lb_search_bar.xml
similarity index 100%
rename from leanback/res/layout/lb_search_bar.xml
rename to leanback/src/main/res/layout/lb_search_bar.xml
diff --git a/leanback/res/layout/lb_search_fragment.xml b/leanback/src/main/res/layout/lb_search_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_search_fragment.xml
rename to leanback/src/main/res/layout/lb_search_fragment.xml
diff --git a/leanback/res/layout/lb_search_orb.xml b/leanback/src/main/res/layout/lb_search_orb.xml
similarity index 100%
rename from leanback/res/layout/lb_search_orb.xml
rename to leanback/src/main/res/layout/lb_search_orb.xml
diff --git a/leanback/res/layout/lb_section_header.xml b/leanback/src/main/res/layout/lb_section_header.xml
similarity index 100%
rename from leanback/res/layout/lb_section_header.xml
rename to leanback/src/main/res/layout/lb_section_header.xml
diff --git a/leanback/res/layout/lb_shadow.xml b/leanback/src/main/res/layout/lb_shadow.xml
similarity index 100%
rename from leanback/res/layout/lb_shadow.xml
rename to leanback/src/main/res/layout/lb_shadow.xml
diff --git a/leanback/res/layout/lb_speech_orb.xml b/leanback/src/main/res/layout/lb_speech_orb.xml
similarity index 100%
rename from leanback/res/layout/lb_speech_orb.xml
rename to leanback/src/main/res/layout/lb_speech_orb.xml
diff --git a/leanback/res/layout/lb_title_view.xml b/leanback/src/main/res/layout/lb_title_view.xml
similarity index 100%
rename from leanback/res/layout/lb_title_view.xml
rename to leanback/src/main/res/layout/lb_title_view.xml
diff --git a/leanback/res/layout/lb_vertical_grid.xml b/leanback/src/main/res/layout/lb_vertical_grid.xml
similarity index 100%
rename from leanback/res/layout/lb_vertical_grid.xml
rename to leanback/src/main/res/layout/lb_vertical_grid.xml
diff --git a/leanback/res/layout/lb_vertical_grid_fragment.xml b/leanback/src/main/res/layout/lb_vertical_grid_fragment.xml
similarity index 100%
rename from leanback/res/layout/lb_vertical_grid_fragment.xml
rename to leanback/src/main/res/layout/lb_vertical_grid_fragment.xml
diff --git a/leanback/res/layout/lb_video_surface.xml b/leanback/src/main/res/layout/lb_video_surface.xml
similarity index 100%
rename from leanback/res/layout/lb_video_surface.xml
rename to leanback/src/main/res/layout/lb_video_surface.xml
diff --git a/leanback/res/layout/video_surface_fragment.xml b/leanback/src/main/res/layout/video_surface_fragment.xml
similarity index 100%
rename from leanback/res/layout/video_surface_fragment.xml
rename to leanback/src/main/res/layout/video_surface_fragment.xml
diff --git a/leanback/res/raw/lb_voice_failure.ogg b/leanback/src/main/res/raw/lb_voice_failure.ogg
similarity index 100%
rename from leanback/res/raw/lb_voice_failure.ogg
rename to leanback/src/main/res/raw/lb_voice_failure.ogg
Binary files differ
diff --git a/leanback/res/raw/lb_voice_no_input.ogg b/leanback/src/main/res/raw/lb_voice_no_input.ogg
similarity index 100%
rename from leanback/res/raw/lb_voice_no_input.ogg
rename to leanback/src/main/res/raw/lb_voice_no_input.ogg
Binary files differ
diff --git a/leanback/res/raw/lb_voice_open.ogg b/leanback/src/main/res/raw/lb_voice_open.ogg
similarity index 100%
rename from leanback/res/raw/lb_voice_open.ogg
rename to leanback/src/main/res/raw/lb_voice_open.ogg
Binary files differ
diff --git a/leanback/res/raw/lb_voice_success.ogg b/leanback/src/main/res/raw/lb_voice_success.ogg
similarity index 100%
rename from leanback/res/raw/lb_voice_success.ogg
rename to leanback/src/main/res/raw/lb_voice_success.ogg
Binary files differ
diff --git a/leanback/res/transition-v19/lb_browse_headers_in.xml b/leanback/src/main/res/transition-v19/lb_browse_headers_in.xml
similarity index 100%
rename from leanback/res/transition-v19/lb_browse_headers_in.xml
rename to leanback/src/main/res/transition-v19/lb_browse_headers_in.xml
diff --git a/leanback/res/transition-v19/lb_browse_headers_out.xml b/leanback/src/main/res/transition-v19/lb_browse_headers_out.xml
similarity index 100%
rename from leanback/res/transition-v19/lb_browse_headers_out.xml
rename to leanback/src/main/res/transition-v19/lb_browse_headers_out.xml
diff --git a/leanback/res/transition-v21/lb_browse_enter_transition.xml b/leanback/src/main/res/transition-v21/lb_browse_enter_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_browse_enter_transition.xml
rename to leanback/src/main/res/transition-v21/lb_browse_enter_transition.xml
diff --git a/leanback/res/transition-v21/lb_browse_entrance_transition.xml b/leanback/src/main/res/transition-v21/lb_browse_entrance_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_browse_entrance_transition.xml
rename to leanback/src/main/res/transition-v21/lb_browse_entrance_transition.xml
diff --git a/leanback/res/transition-v21/lb_browse_headers_in.xml b/leanback/src/main/res/transition-v21/lb_browse_headers_in.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_browse_headers_in.xml
rename to leanback/src/main/res/transition-v21/lb_browse_headers_in.xml
diff --git a/leanback/res/transition-v21/lb_browse_headers_out.xml b/leanback/src/main/res/transition-v21/lb_browse_headers_out.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_browse_headers_out.xml
rename to leanback/src/main/res/transition-v21/lb_browse_headers_out.xml
diff --git a/leanback/res/transition-v21/lb_browse_return_transition.xml b/leanback/src/main/res/transition-v21/lb_browse_return_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_browse_return_transition.xml
rename to leanback/src/main/res/transition-v21/lb_browse_return_transition.xml
diff --git a/leanback/res/transition-v21/lb_details_enter_transition.xml b/leanback/src/main/res/transition-v21/lb_details_enter_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_details_enter_transition.xml
rename to leanback/src/main/res/transition-v21/lb_details_enter_transition.xml
diff --git a/leanback/res/transition-v21/lb_details_return_transition.xml b/leanback/src/main/res/transition-v21/lb_details_return_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_details_return_transition.xml
rename to leanback/src/main/res/transition-v21/lb_details_return_transition.xml
diff --git a/leanback/res/transition-v21/lb_enter_transition.xml b/leanback/src/main/res/transition-v21/lb_enter_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_enter_transition.xml
rename to leanback/src/main/res/transition-v21/lb_enter_transition.xml
diff --git a/leanback/res/transition-v21/lb_guidedstep_activity_enter.xml b/leanback/src/main/res/transition-v21/lb_guidedstep_activity_enter.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_guidedstep_activity_enter.xml
rename to leanback/src/main/res/transition-v21/lb_guidedstep_activity_enter.xml
diff --git a/leanback/res/transition-v21/lb_guidedstep_activity_enter_bottom.xml b/leanback/src/main/res/transition-v21/lb_guidedstep_activity_enter_bottom.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_guidedstep_activity_enter_bottom.xml
rename to leanback/src/main/res/transition-v21/lb_guidedstep_activity_enter_bottom.xml
diff --git a/leanback/res/transition-v21/lb_return_transition.xml b/leanback/src/main/res/transition-v21/lb_return_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_return_transition.xml
rename to leanback/src/main/res/transition-v21/lb_return_transition.xml
diff --git a/leanback/res/transition-v21/lb_shared_element_enter_transition.xml b/leanback/src/main/res/transition-v21/lb_shared_element_enter_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_shared_element_enter_transition.xml
rename to leanback/src/main/res/transition-v21/lb_shared_element_enter_transition.xml
diff --git a/leanback/res/transition-v21/lb_shared_element_return_transition.xml b/leanback/src/main/res/transition-v21/lb_shared_element_return_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_shared_element_return_transition.xml
rename to leanback/src/main/res/transition-v21/lb_shared_element_return_transition.xml
diff --git a/leanback/res/transition-v21/lb_title_in.xml b/leanback/src/main/res/transition-v21/lb_title_in.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_title_in.xml
rename to leanback/src/main/res/transition-v21/lb_title_in.xml
diff --git a/leanback/res/transition-v21/lb_title_out.xml b/leanback/src/main/res/transition-v21/lb_title_out.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_title_out.xml
rename to leanback/src/main/res/transition-v21/lb_title_out.xml
diff --git a/leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml b/leanback/src/main/res/transition-v21/lb_vertical_grid_enter_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_vertical_grid_enter_transition.xml
rename to leanback/src/main/res/transition-v21/lb_vertical_grid_enter_transition.xml
diff --git a/leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml b/leanback/src/main/res/transition-v21/lb_vertical_grid_entrance_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_vertical_grid_entrance_transition.xml
rename to leanback/src/main/res/transition-v21/lb_vertical_grid_entrance_transition.xml
diff --git a/leanback/res/transition-v21/lb_vertical_grid_return_transition.xml b/leanback/src/main/res/transition-v21/lb_vertical_grid_return_transition.xml
similarity index 100%
rename from leanback/res/transition-v21/lb_vertical_grid_return_transition.xml
rename to leanback/src/main/res/transition-v21/lb_vertical_grid_return_transition.xml
diff --git a/leanback/res/values-af/strings.xml b/leanback/src/main/res/values-af/strings.xml
similarity index 100%
rename from leanback/res/values-af/strings.xml
rename to leanback/src/main/res/values-af/strings.xml
diff --git a/leanback/res/values-am/strings.xml b/leanback/src/main/res/values-am/strings.xml
similarity index 100%
rename from leanback/res/values-am/strings.xml
rename to leanback/src/main/res/values-am/strings.xml
diff --git a/leanback/res/values-ar/strings.xml b/leanback/src/main/res/values-ar/strings.xml
similarity index 100%
rename from leanback/res/values-ar/strings.xml
rename to leanback/src/main/res/values-ar/strings.xml
diff --git a/leanback/res/values-az/strings.xml b/leanback/src/main/res/values-az/strings.xml
similarity index 100%
rename from leanback/res/values-az/strings.xml
rename to leanback/src/main/res/values-az/strings.xml
diff --git a/leanback/res/values-b+sr+Latn/strings.xml b/leanback/src/main/res/values-b+sr+Latn/strings.xml
similarity index 100%
rename from leanback/res/values-b+sr+Latn/strings.xml
rename to leanback/src/main/res/values-b+sr+Latn/strings.xml
diff --git a/leanback/res/values-be/strings.xml b/leanback/src/main/res/values-be/strings.xml
similarity index 100%
rename from leanback/res/values-be/strings.xml
rename to leanback/src/main/res/values-be/strings.xml
diff --git a/leanback/res/values-bg/strings.xml b/leanback/src/main/res/values-bg/strings.xml
similarity index 100%
rename from leanback/res/values-bg/strings.xml
rename to leanback/src/main/res/values-bg/strings.xml
diff --git a/leanback/res/values-bn/strings.xml b/leanback/src/main/res/values-bn/strings.xml
similarity index 100%
rename from leanback/res/values-bn/strings.xml
rename to leanback/src/main/res/values-bn/strings.xml
diff --git a/leanback/res/values-bs/strings.xml b/leanback/src/main/res/values-bs/strings.xml
similarity index 100%
rename from leanback/res/values-bs/strings.xml
rename to leanback/src/main/res/values-bs/strings.xml
diff --git a/leanback/res/values-ca/strings.xml b/leanback/src/main/res/values-ca/strings.xml
similarity index 100%
rename from leanback/res/values-ca/strings.xml
rename to leanback/src/main/res/values-ca/strings.xml
diff --git a/leanback/res/values-cs/strings.xml b/leanback/src/main/res/values-cs/strings.xml
similarity index 100%
rename from leanback/res/values-cs/strings.xml
rename to leanback/src/main/res/values-cs/strings.xml
diff --git a/leanback/res/values-da/strings.xml b/leanback/src/main/res/values-da/strings.xml
similarity index 100%
rename from leanback/res/values-da/strings.xml
rename to leanback/src/main/res/values-da/strings.xml
diff --git a/leanback/res/values-de/strings.xml b/leanback/src/main/res/values-de/strings.xml
similarity index 100%
rename from leanback/res/values-de/strings.xml
rename to leanback/src/main/res/values-de/strings.xml
diff --git a/leanback/res/values-el/strings.xml b/leanback/src/main/res/values-el/strings.xml
similarity index 100%
rename from leanback/res/values-el/strings.xml
rename to leanback/src/main/res/values-el/strings.xml
diff --git a/leanback/res/values-en-rAU/strings.xml b/leanback/src/main/res/values-en-rAU/strings.xml
similarity index 100%
rename from leanback/res/values-en-rAU/strings.xml
rename to leanback/src/main/res/values-en-rAU/strings.xml
diff --git a/leanback/res/values-en-rCA/strings.xml b/leanback/src/main/res/values-en-rCA/strings.xml
similarity index 100%
rename from leanback/res/values-en-rCA/strings.xml
rename to leanback/src/main/res/values-en-rCA/strings.xml
diff --git a/leanback/res/values-en-rGB/strings.xml b/leanback/src/main/res/values-en-rGB/strings.xml
similarity index 100%
rename from leanback/res/values-en-rGB/strings.xml
rename to leanback/src/main/res/values-en-rGB/strings.xml
diff --git a/leanback/res/values-en-rIN/strings.xml b/leanback/src/main/res/values-en-rIN/strings.xml
similarity index 100%
rename from leanback/res/values-en-rIN/strings.xml
rename to leanback/src/main/res/values-en-rIN/strings.xml
diff --git a/leanback/res/values-en-rXC/strings.xml b/leanback/src/main/res/values-en-rXC/strings.xml
similarity index 100%
rename from leanback/res/values-en-rXC/strings.xml
rename to leanback/src/main/res/values-en-rXC/strings.xml
diff --git a/leanback/res/values-es-rUS/strings.xml b/leanback/src/main/res/values-es-rUS/strings.xml
similarity index 100%
rename from leanback/res/values-es-rUS/strings.xml
rename to leanback/src/main/res/values-es-rUS/strings.xml
diff --git a/leanback/res/values-es/strings.xml b/leanback/src/main/res/values-es/strings.xml
similarity index 100%
rename from leanback/res/values-es/strings.xml
rename to leanback/src/main/res/values-es/strings.xml
diff --git a/leanback/res/values-et/strings.xml b/leanback/src/main/res/values-et/strings.xml
similarity index 100%
rename from leanback/res/values-et/strings.xml
rename to leanback/src/main/res/values-et/strings.xml
diff --git a/leanback/res/values-eu/strings.xml b/leanback/src/main/res/values-eu/strings.xml
similarity index 100%
rename from leanback/res/values-eu/strings.xml
rename to leanback/src/main/res/values-eu/strings.xml
diff --git a/leanback/res/values-fa/strings.xml b/leanback/src/main/res/values-fa/strings.xml
similarity index 100%
rename from leanback/res/values-fa/strings.xml
rename to leanback/src/main/res/values-fa/strings.xml
diff --git a/leanback/res/values-fi/strings.xml b/leanback/src/main/res/values-fi/strings.xml
similarity index 100%
rename from leanback/res/values-fi/strings.xml
rename to leanback/src/main/res/values-fi/strings.xml
diff --git a/leanback/res/values-fr-rCA/strings.xml b/leanback/src/main/res/values-fr-rCA/strings.xml
similarity index 100%
rename from leanback/res/values-fr-rCA/strings.xml
rename to leanback/src/main/res/values-fr-rCA/strings.xml
diff --git a/leanback/res/values-fr/strings.xml b/leanback/src/main/res/values-fr/strings.xml
similarity index 100%
rename from leanback/res/values-fr/strings.xml
rename to leanback/src/main/res/values-fr/strings.xml
diff --git a/leanback/res/values-gl/strings.xml b/leanback/src/main/res/values-gl/strings.xml
similarity index 100%
rename from leanback/res/values-gl/strings.xml
rename to leanback/src/main/res/values-gl/strings.xml
diff --git a/leanback/res/values-gu/strings.xml b/leanback/src/main/res/values-gu/strings.xml
similarity index 100%
rename from leanback/res/values-gu/strings.xml
rename to leanback/src/main/res/values-gu/strings.xml
diff --git a/leanback/res/values-hi/strings.xml b/leanback/src/main/res/values-hi/strings.xml
similarity index 100%
rename from leanback/res/values-hi/strings.xml
rename to leanback/src/main/res/values-hi/strings.xml
diff --git a/leanback/res/values-hr/strings.xml b/leanback/src/main/res/values-hr/strings.xml
similarity index 100%
rename from leanback/res/values-hr/strings.xml
rename to leanback/src/main/res/values-hr/strings.xml
diff --git a/leanback/res/values-hu/strings.xml b/leanback/src/main/res/values-hu/strings.xml
similarity index 100%
rename from leanback/res/values-hu/strings.xml
rename to leanback/src/main/res/values-hu/strings.xml
diff --git a/leanback/res/values-hy/strings.xml b/leanback/src/main/res/values-hy/strings.xml
similarity index 100%
rename from leanback/res/values-hy/strings.xml
rename to leanback/src/main/res/values-hy/strings.xml
diff --git a/leanback/res/values-in/strings.xml b/leanback/src/main/res/values-in/strings.xml
similarity index 100%
rename from leanback/res/values-in/strings.xml
rename to leanback/src/main/res/values-in/strings.xml
diff --git a/leanback/res/values-is/strings.xml b/leanback/src/main/res/values-is/strings.xml
similarity index 100%
rename from leanback/res/values-is/strings.xml
rename to leanback/src/main/res/values-is/strings.xml
diff --git a/leanback/res/values-it/strings.xml b/leanback/src/main/res/values-it/strings.xml
similarity index 100%
rename from leanback/res/values-it/strings.xml
rename to leanback/src/main/res/values-it/strings.xml
diff --git a/leanback/res/values-iw/strings.xml b/leanback/src/main/res/values-iw/strings.xml
similarity index 100%
rename from leanback/res/values-iw/strings.xml
rename to leanback/src/main/res/values-iw/strings.xml
diff --git a/leanback/res/values-ja/strings.xml b/leanback/src/main/res/values-ja/strings.xml
similarity index 100%
rename from leanback/res/values-ja/strings.xml
rename to leanback/src/main/res/values-ja/strings.xml
diff --git a/leanback/res/values-ka/strings.xml b/leanback/src/main/res/values-ka/strings.xml
similarity index 100%
rename from leanback/res/values-ka/strings.xml
rename to leanback/src/main/res/values-ka/strings.xml
diff --git a/leanback/res/values-kk/strings.xml b/leanback/src/main/res/values-kk/strings.xml
similarity index 100%
rename from leanback/res/values-kk/strings.xml
rename to leanback/src/main/res/values-kk/strings.xml
diff --git a/leanback/res/values-km/strings.xml b/leanback/src/main/res/values-km/strings.xml
similarity index 100%
rename from leanback/res/values-km/strings.xml
rename to leanback/src/main/res/values-km/strings.xml
diff --git a/leanback/res/values-kn/strings.xml b/leanback/src/main/res/values-kn/strings.xml
similarity index 100%
rename from leanback/res/values-kn/strings.xml
rename to leanback/src/main/res/values-kn/strings.xml
diff --git a/leanback/res/values-ko/strings.xml b/leanback/src/main/res/values-ko/strings.xml
similarity index 100%
rename from leanback/res/values-ko/strings.xml
rename to leanback/src/main/res/values-ko/strings.xml
diff --git a/leanback/res/values-ky/strings.xml b/leanback/src/main/res/values-ky/strings.xml
similarity index 100%
rename from leanback/res/values-ky/strings.xml
rename to leanback/src/main/res/values-ky/strings.xml
diff --git a/leanback/res/values-ldrtl/dimens.xml b/leanback/src/main/res/values-ldrtl/dimens.xml
similarity index 100%
rename from leanback/res/values-ldrtl/dimens.xml
rename to leanback/src/main/res/values-ldrtl/dimens.xml
diff --git a/leanback/res/values-ldrtl/integers.xml b/leanback/src/main/res/values-ldrtl/integers.xml
similarity index 100%
rename from leanback/res/values-ldrtl/integers.xml
rename to leanback/src/main/res/values-ldrtl/integers.xml
diff --git a/leanback/res/values-lo/strings.xml b/leanback/src/main/res/values-lo/strings.xml
similarity index 100%
rename from leanback/res/values-lo/strings.xml
rename to leanback/src/main/res/values-lo/strings.xml
diff --git a/leanback/res/values-lt/strings.xml b/leanback/src/main/res/values-lt/strings.xml
similarity index 100%
rename from leanback/res/values-lt/strings.xml
rename to leanback/src/main/res/values-lt/strings.xml
diff --git a/leanback/res/values-lv/strings.xml b/leanback/src/main/res/values-lv/strings.xml
similarity index 100%
rename from leanback/res/values-lv/strings.xml
rename to leanback/src/main/res/values-lv/strings.xml
diff --git a/leanback/res/values-mk/strings.xml b/leanback/src/main/res/values-mk/strings.xml
similarity index 100%
rename from leanback/res/values-mk/strings.xml
rename to leanback/src/main/res/values-mk/strings.xml
diff --git a/leanback/res/values-ml/strings.xml b/leanback/src/main/res/values-ml/strings.xml
similarity index 100%
rename from leanback/res/values-ml/strings.xml
rename to leanback/src/main/res/values-ml/strings.xml
diff --git a/leanback/res/values-mn/strings.xml b/leanback/src/main/res/values-mn/strings.xml
similarity index 100%
rename from leanback/res/values-mn/strings.xml
rename to leanback/src/main/res/values-mn/strings.xml
diff --git a/leanback/src/main/res/values-mr/strings.xml b/leanback/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000..1fcb920
--- /dev/null
+++ b/leanback/src/main/res/values-mr/strings.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+Copyright (C) 2014 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="lb_navigation_menu_contentDescription" msgid="6215811486591629025">"नेव्हिगेशन मेनू"</string>
+    <string name="orb_search_action" msgid="5651268540267663887">"शोध क्रिया"</string>
+    <string name="lb_search_bar_hint" msgid="8325490927970116252">"शोधा"</string>
+    <string name="lb_search_bar_hint_speech" msgid="5511270823320183816">"शोधण्यासाठी बोला"</string>
+    <string name="lb_search_bar_hint_with_title" msgid="1627103380996590035">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधा"</string>
+    <string name="lb_search_bar_hint_with_title_speech" msgid="2712734639766312034">"<xliff:g id="SEARCH_CONTEXT">%1$s</xliff:g> शोधण्यासाठी बोला"</string>
+    <string name="lb_control_display_fast_forward_multiplier" msgid="4541442045214207774">"%1$dX"</string>
+    <string name="lb_control_display_rewind_multiplier" msgid="3097220783222910245">"%1$dX"</string>
+    <string name="lb_playback_controls_play" msgid="731953341987346903">"प्ले करा"</string>
+    <string name="lb_playback_controls_pause" msgid="6189521112079849518">"विराम द्या"</string>
+    <string name="lb_playback_controls_fast_forward" msgid="8569951318244687220">"फास्ट फॉरवर्ड करा"</string>
+    <string name="lb_playback_controls_fast_forward_multiplier" msgid="1058753672110224526">"फास्ट फॉरवर्ड %1$dX"</string>
+    <string name="lb_playback_controls_rewind" msgid="2227196334132350684">"रिवाईँड करा"</string>
+    <string name="lb_playback_controls_rewind_multiplier" msgid="1640629531440849942">"रीवाईंड %1$dX"</string>
+    <string name="lb_playback_controls_skip_next" msgid="2946499493161095772">"पुढील वगळा"</string>
+    <string name="lb_playback_controls_skip_previous" msgid="2326801832933178348">"मागील वगळा"</string>
+    <string name="lb_playback_controls_more_actions" msgid="2330770008796987655">"अधिक क्रिया"</string>
+    <string name="lb_playback_controls_thumb_up" msgid="6530420347129222601">"वर अंगठा निवड रद्द करा"</string>
+    <string name="lb_playback_controls_thumb_up_outline" msgid="1577637924003500946">"वर अंगठा निवडा"</string>
+    <string name="lb_playback_controls_thumb_down" msgid="4498041193172964797">"खाली अंगठा निवड रद्द करा"</string>
+    <string name="lb_playback_controls_thumb_down_outline" msgid="2936020280629424365">"खाली अंगठा निवडा"</string>
+    <string name="lb_playback_controls_repeat_none" msgid="87476947476529036">"काहीही पुनरावृत्ती करू नका"</string>
+    <string name="lb_playback_controls_repeat_all" msgid="6730354406289599000">"सर्व पुनरावृत्ती करा"</string>
+    <string name="lb_playback_controls_repeat_one" msgid="3285202316452203619">"एक पुनरावृत्ती करा"</string>
+    <string name="lb_playback_controls_shuffle_enable" msgid="1099874107835264529">"शफल करा सक्षम करा"</string>
+    <string name="lb_playback_controls_shuffle_disable" msgid="8388150597335115226">"शफल करा अक्षम करा"</string>
+    <string name="lb_playback_controls_high_quality_enable" msgid="202415780019335254">"उच्च गुणवत्ता सक्षम करा"</string>
+    <string name="lb_playback_controls_high_quality_disable" msgid="8637371582779057866">"उच्च गुणवत्ता अक्षम करा"</string>
+    <string name="lb_playback_controls_closed_captioning_enable" msgid="2429655367176440226">"उपशीर्षके सक्षम करा"</string>
+    <string name="lb_playback_controls_closed_captioning_disable" msgid="6133362019475930048">"सबटायटल अक्षम करा"</string>
+    <string name="lb_playback_controls_picture_in_picture" msgid="3040035547765350690">"चित्र मोडमध्ये चित्र एंटर करा"</string>
+    <string name="lb_playback_time_separator" msgid="3208380806582304911">"/"</string>
+    <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_media_player_error" msgid="3650250994187305396">"मीडियाप्लेअर एरर कोड %1$d अतिरिक्त %2$d"</string>
+    <string name="lb_onboarding_get_started" msgid="6961440391306351139">"सुरू करा"</string>
+    <string name="lb_onboarding_accessibility_next" msgid="2918313444257732434">"पुढील"</string>
+</resources>
diff --git a/leanback/res/values-ms/strings.xml b/leanback/src/main/res/values-ms/strings.xml
similarity index 100%
rename from leanback/res/values-ms/strings.xml
rename to leanback/src/main/res/values-ms/strings.xml
diff --git a/leanback/res/values-my/strings.xml b/leanback/src/main/res/values-my/strings.xml
similarity index 100%
rename from leanback/res/values-my/strings.xml
rename to leanback/src/main/res/values-my/strings.xml
diff --git a/leanback/res/values-nb/strings.xml b/leanback/src/main/res/values-nb/strings.xml
similarity index 100%
rename from leanback/res/values-nb/strings.xml
rename to leanback/src/main/res/values-nb/strings.xml
diff --git a/leanback/res/values-ne/strings.xml b/leanback/src/main/res/values-ne/strings.xml
similarity index 100%
rename from leanback/res/values-ne/strings.xml
rename to leanback/src/main/res/values-ne/strings.xml
diff --git a/leanback/res/values-nl/strings.xml b/leanback/src/main/res/values-nl/strings.xml
similarity index 100%
rename from leanback/res/values-nl/strings.xml
rename to leanback/src/main/res/values-nl/strings.xml
diff --git a/leanback/res/values-pa/strings.xml b/leanback/src/main/res/values-pa/strings.xml
similarity index 100%
rename from leanback/res/values-pa/strings.xml
rename to leanback/src/main/res/values-pa/strings.xml
diff --git a/leanback/res/values-pl/strings.xml b/leanback/src/main/res/values-pl/strings.xml
similarity index 100%
rename from leanback/res/values-pl/strings.xml
rename to leanback/src/main/res/values-pl/strings.xml
diff --git a/leanback/res/values-pt-rBR/strings.xml b/leanback/src/main/res/values-pt-rBR/strings.xml
similarity index 100%
rename from leanback/res/values-pt-rBR/strings.xml
rename to leanback/src/main/res/values-pt-rBR/strings.xml
diff --git a/leanback/res/values-pt-rPT/strings.xml b/leanback/src/main/res/values-pt-rPT/strings.xml
similarity index 100%
rename from leanback/res/values-pt-rPT/strings.xml
rename to leanback/src/main/res/values-pt-rPT/strings.xml
diff --git a/leanback/res/values-pt/strings.xml b/leanback/src/main/res/values-pt/strings.xml
similarity index 100%
rename from leanback/res/values-pt/strings.xml
rename to leanback/src/main/res/values-pt/strings.xml
diff --git a/leanback/res/values-ro/strings.xml b/leanback/src/main/res/values-ro/strings.xml
similarity index 100%
rename from leanback/res/values-ro/strings.xml
rename to leanback/src/main/res/values-ro/strings.xml
diff --git a/leanback/res/values-ru/strings.xml b/leanback/src/main/res/values-ru/strings.xml
similarity index 100%
rename from leanback/res/values-ru/strings.xml
rename to leanback/src/main/res/values-ru/strings.xml
diff --git a/leanback/res/values-si/strings.xml b/leanback/src/main/res/values-si/strings.xml
similarity index 100%
rename from leanback/res/values-si/strings.xml
rename to leanback/src/main/res/values-si/strings.xml
diff --git a/leanback/res/values-sk/strings.xml b/leanback/src/main/res/values-sk/strings.xml
similarity index 100%
rename from leanback/res/values-sk/strings.xml
rename to leanback/src/main/res/values-sk/strings.xml
diff --git a/leanback/res/values-sl/strings.xml b/leanback/src/main/res/values-sl/strings.xml
similarity index 100%
rename from leanback/res/values-sl/strings.xml
rename to leanback/src/main/res/values-sl/strings.xml
diff --git a/leanback/res/values-sq/strings.xml b/leanback/src/main/res/values-sq/strings.xml
similarity index 100%
rename from leanback/res/values-sq/strings.xml
rename to leanback/src/main/res/values-sq/strings.xml
diff --git a/leanback/res/values-sr/strings.xml b/leanback/src/main/res/values-sr/strings.xml
similarity index 100%
rename from leanback/res/values-sr/strings.xml
rename to leanback/src/main/res/values-sr/strings.xml
diff --git a/leanback/res/values-sv/strings.xml b/leanback/src/main/res/values-sv/strings.xml
similarity index 100%
rename from leanback/res/values-sv/strings.xml
rename to leanback/src/main/res/values-sv/strings.xml
diff --git a/leanback/res/values-sw/strings.xml b/leanback/src/main/res/values-sw/strings.xml
similarity index 100%
rename from leanback/res/values-sw/strings.xml
rename to leanback/src/main/res/values-sw/strings.xml
diff --git a/leanback/res/values-ta/strings.xml b/leanback/src/main/res/values-ta/strings.xml
similarity index 100%
rename from leanback/res/values-ta/strings.xml
rename to leanback/src/main/res/values-ta/strings.xml
diff --git a/leanback/res/values-te/strings.xml b/leanback/src/main/res/values-te/strings.xml
similarity index 100%
rename from leanback/res/values-te/strings.xml
rename to leanback/src/main/res/values-te/strings.xml
diff --git a/leanback/res/values-th/strings.xml b/leanback/src/main/res/values-th/strings.xml
similarity index 100%
rename from leanback/res/values-th/strings.xml
rename to leanback/src/main/res/values-th/strings.xml
diff --git a/leanback/res/values-tl/strings.xml b/leanback/src/main/res/values-tl/strings.xml
similarity index 100%
rename from leanback/res/values-tl/strings.xml
rename to leanback/src/main/res/values-tl/strings.xml
diff --git a/leanback/res/values-tr/strings.xml b/leanback/src/main/res/values-tr/strings.xml
similarity index 100%
rename from leanback/res/values-tr/strings.xml
rename to leanback/src/main/res/values-tr/strings.xml
diff --git a/leanback/res/values-uk/strings.xml b/leanback/src/main/res/values-uk/strings.xml
similarity index 100%
rename from leanback/res/values-uk/strings.xml
rename to leanback/src/main/res/values-uk/strings.xml
diff --git a/leanback/res/values-ur/strings.xml b/leanback/src/main/res/values-ur/strings.xml
similarity index 100%
rename from leanback/res/values-ur/strings.xml
rename to leanback/src/main/res/values-ur/strings.xml
diff --git a/leanback/res/values-uz/strings.xml b/leanback/src/main/res/values-uz/strings.xml
similarity index 100%
rename from leanback/res/values-uz/strings.xml
rename to leanback/src/main/res/values-uz/strings.xml
diff --git a/leanback/res/values-v18/themes.xml b/leanback/src/main/res/values-v18/themes.xml
similarity index 100%
rename from leanback/res/values-v18/themes.xml
rename to leanback/src/main/res/values-v18/themes.xml
diff --git a/leanback/res/values-v19/themes.xml b/leanback/src/main/res/values-v19/themes.xml
similarity index 100%
rename from leanback/res/values-v19/themes.xml
rename to leanback/src/main/res/values-v19/themes.xml
diff --git a/leanback/res/values-v21/styles.xml b/leanback/src/main/res/values-v21/styles.xml
similarity index 100%
rename from leanback/res/values-v21/styles.xml
rename to leanback/src/main/res/values-v21/styles.xml
diff --git a/leanback/res/values-v21/themes.xml b/leanback/src/main/res/values-v21/themes.xml
similarity index 100%
rename from leanback/res/values-v21/themes.xml
rename to leanback/src/main/res/values-v21/themes.xml
diff --git a/leanback/res/values-v22/integers.xml b/leanback/src/main/res/values-v22/integers.xml
similarity index 100%
rename from leanback/res/values-v22/integers.xml
rename to leanback/src/main/res/values-v22/integers.xml
diff --git a/leanback/res/values-vi/strings.xml b/leanback/src/main/res/values-vi/strings.xml
similarity index 100%
rename from leanback/res/values-vi/strings.xml
rename to leanback/src/main/res/values-vi/strings.xml
diff --git a/leanback/res/values-zh-rCN/strings.xml b/leanback/src/main/res/values-zh-rCN/strings.xml
similarity index 100%
rename from leanback/res/values-zh-rCN/strings.xml
rename to leanback/src/main/res/values-zh-rCN/strings.xml
diff --git a/leanback/res/values-zh-rHK/strings.xml b/leanback/src/main/res/values-zh-rHK/strings.xml
similarity index 100%
rename from leanback/res/values-zh-rHK/strings.xml
rename to leanback/src/main/res/values-zh-rHK/strings.xml
diff --git a/leanback/res/values-zh-rTW/strings.xml b/leanback/src/main/res/values-zh-rTW/strings.xml
similarity index 100%
rename from leanback/res/values-zh-rTW/strings.xml
rename to leanback/src/main/res/values-zh-rTW/strings.xml
diff --git a/leanback/res/values-zu/strings.xml b/leanback/src/main/res/values-zu/strings.xml
similarity index 100%
rename from leanback/res/values-zu/strings.xml
rename to leanback/src/main/res/values-zu/strings.xml
diff --git a/leanback/res/values/attrs.xml b/leanback/src/main/res/values/attrs.xml
similarity index 100%
rename from leanback/res/values/attrs.xml
rename to leanback/src/main/res/values/attrs.xml
diff --git a/leanback/res/values/colors.xml b/leanback/src/main/res/values/colors.xml
similarity index 100%
rename from leanback/res/values/colors.xml
rename to leanback/src/main/res/values/colors.xml
diff --git a/leanback/res/values/dimens.xml b/leanback/src/main/res/values/dimens.xml
similarity index 100%
rename from leanback/res/values/dimens.xml
rename to leanback/src/main/res/values/dimens.xml
diff --git a/leanback/res/values/ids.xml b/leanback/src/main/res/values/ids.xml
similarity index 100%
rename from leanback/res/values/ids.xml
rename to leanback/src/main/res/values/ids.xml
diff --git a/leanback/res/values/integers.xml b/leanback/src/main/res/values/integers.xml
similarity index 100%
rename from leanback/res/values/integers.xml
rename to leanback/src/main/res/values/integers.xml
diff --git a/leanback/res/values/strings.xml b/leanback/src/main/res/values/strings.xml
similarity index 100%
rename from leanback/res/values/strings.xml
rename to leanback/src/main/res/values/strings.xml
diff --git a/leanback/res/values/styles.xml b/leanback/src/main/res/values/styles.xml
similarity index 100%
rename from leanback/res/values/styles.xml
rename to leanback/src/main/res/values/styles.xml
diff --git a/leanback/res/values/themes.xml b/leanback/src/main/res/values/themes.xml
similarity index 100%
rename from leanback/res/values/themes.xml
rename to leanback/src/main/res/values/themes.xml
diff --git a/leanback/tests/NO_DOCS b/leanback/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/leanback/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java b/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
deleted file mode 100644
index 0ca1562..0000000
--- a/leanback/tests/java/android/support/v17/leanback/widget/GridWidgetTest.java
+++ /dev/null
@@ -1,6109 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v17.leanback.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.os.Build;
-import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v17.leanback.test.R;
-import android.support.v17.leanback.testutils.PollingCheck;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.support.v7.widget.DefaultItemAnimator;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerViewAccessibilityDelegate;
-import android.text.Selection;
-import android.text.Spannable;
-import android.util.DisplayMetrics;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
-import android.util.TypedValue;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.junit.After;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class GridWidgetTest {
-
-    private static final float DELTA = 1f;
-    private static final boolean HUMAN_DELAY = false;
-    private static final long WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS = 60000;
-    private static final int WAIT_FOR_LAYOUT_PASS_TIMEOUT_MS = 2000;
-    private static final int WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS = 6000;
-
-    protected ActivityTestRule<GridActivity> mActivityTestRule;
-    protected GridActivity mActivity;
-    protected BaseGridView mGridView;
-    protected GridLayoutManager mLayoutManager;
-    private GridLayoutManager.OnLayoutCompleteListener mWaitLayoutListener;
-    protected int mOrientation;
-    protected int mNumRows;
-    protected int[] mRemovedItems;
-
-    private final Comparator<View> mRowSortComparator = new Comparator<View>() {
-        @Override
-        public int compare(View lhs, View rhs) {
-            if (mOrientation == BaseGridView.HORIZONTAL) {
-                return lhs.getLeft() - rhs.getLeft();
-            } else {
-                return lhs.getTop() - rhs.getTop();
-            }
-        };
-    };
-
-    /**
-     * Verify margins between items on same row are same.
-     */
-    private final Runnable mVerifyLayout = new Runnable() {
-        @Override
-        public void run() {
-            verifyMargin();
-        }
-    };
-
-    @Rule public TestName testName = new TestName();
-
-    public static void sendKey(int keyCode) {
-        InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
-    }
-
-    public static void sendRepeatedKeys(int repeats, int keyCode) {
-        for (int i = 0; i < repeats; i++) {
-            InstrumentationRegistry.getInstrumentation().sendKeyDownUpSync(keyCode);
-        }
-    }
-
-    private void humanDelay(int delay) throws InterruptedException {
-        if (HUMAN_DELAY) Thread.sleep(delay);
-    }
-    /**
-     * Change size of the Adapter and notifyDataSetChanged.
-     */
-    private void changeArraySize(final int size) throws Throwable {
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.changeArraySize(size);
-            }
-        });
-    }
-
-    static String dumpGridView(BaseGridView gridView) {
-        return "findFocus:" + gridView.getRootView().findFocus()
-                + " isLayoutRequested:" + gridView.isLayoutRequested()
-                + " selectedPosition:" + gridView.getSelectedPosition()
-                + " adapter.itemCount:" + gridView.getAdapter().getItemCount()
-                + " itemAnimator.isRunning:" + gridView.getItemAnimator().isRunning()
-                + " scrollState:" + gridView.getScrollState();
-    }
-
-    /**
-     * Change selected position.
-     */
-    private void setSelectedPosition(final int position, final int scrollExtra) throws Throwable {
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPosition(position, scrollExtra);
-            }
-        });
-        waitForLayout(false);
-    }
-
-    private void setSelectedPosition(final int position) throws Throwable {
-        setSelectedPosition(position, 0);
-    }
-
-    private void setSelectedPositionSmooth(final int position) throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(position);
-            }
-        });
-    }
-    /**
-     * Scrolls using given key.
-     */
-    protected void scroll(int key, Runnable verify) throws Throwable {
-        do {
-            if (verify != null) {
-                mActivityTestRule.runOnUiThread(verify);
-            }
-            sendRepeatedKeys(10, key);
-            try {
-                Thread.sleep(300);
-            } catch (InterruptedException ex) {
-                break;
-            }
-        } while (mGridView.getLayoutManager().isSmoothScrolling()
-                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE);
-    }
-
-    protected void scrollToBegin(Runnable verify) throws Throwable {
-        int key;
-        // first move to first column/row
-        if (mOrientation == BaseGridView.HORIZONTAL) {
-            key = KeyEvent.KEYCODE_DPAD_UP;
-        } else {
-            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-                key = KeyEvent.KEYCODE_DPAD_RIGHT;
-            } else {
-                key = KeyEvent.KEYCODE_DPAD_LEFT;
-            }
-        }
-        scroll(key, null);
-        if (mOrientation == BaseGridView.HORIZONTAL) {
-            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-                key = KeyEvent.KEYCODE_DPAD_RIGHT;
-            } else {
-                key = KeyEvent.KEYCODE_DPAD_LEFT;
-            }
-        } else {
-            key = KeyEvent.KEYCODE_DPAD_UP;
-        }
-        scroll(key, verify);
-    }
-
-    protected void scrollToEnd(Runnable verify) throws Throwable {
-        int key;
-        // first move to first column/row
-        if (mOrientation == BaseGridView.HORIZONTAL) {
-            key = KeyEvent.KEYCODE_DPAD_UP;
-        } else {
-            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-                key = KeyEvent.KEYCODE_DPAD_RIGHT;
-            } else {
-                key = KeyEvent.KEYCODE_DPAD_LEFT;
-            }
-        }
-        scroll(key, null);
-        if (mOrientation == BaseGridView.HORIZONTAL) {
-            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-                key = KeyEvent.KEYCODE_DPAD_LEFT;
-            } else {
-                key = KeyEvent.KEYCODE_DPAD_RIGHT;
-            }
-        } else {
-            key = KeyEvent.KEYCODE_DPAD_DOWN;
-        }
-        scroll(key, verify);
-    }
-
-    /**
-     * Group and sort children by their position on each row (HORIZONTAL) or column(VERTICAL).
-     */
-    protected View[][] sortByRows() {
-        final HashMap<Integer, ArrayList<View>> rows = new HashMap<Integer, ArrayList<View>>();
-        ArrayList<Integer> rowLocations = new ArrayList<>();
-        for (int i = 0; i < mGridView.getChildCount(); i++) {
-            View v = mGridView.getChildAt(i);
-            int rowLocation;
-            if (mOrientation == BaseGridView.HORIZONTAL) {
-                rowLocation = v.getTop();
-            } else {
-                rowLocation = mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL
-                        ? v.getRight() : v.getLeft();
-            }
-            ArrayList<View> views = rows.get(rowLocation);
-            if (views == null) {
-                views = new ArrayList<View>();
-                rows.put(rowLocation, views);
-                rowLocations.add(rowLocation);
-            }
-            views.add(v);
-        }
-        Object[] sortedLocations = rowLocations.toArray();
-        Arrays.sort(sortedLocations);
-        if (mNumRows != rows.size()) {
-            assertEquals("Dump Views by rows "+rows, mNumRows, rows.size());
-        }
-        View[][] sorted = new View[rows.size()][];
-        for (int i = 0; i < rowLocations.size(); i++) {
-            Integer rowLocation = rowLocations.get(i);
-            ArrayList<View> arr = rows.get(rowLocation);
-            View[] views = arr.toArray(new View[arr.size()]);
-            Arrays.sort(views, mRowSortComparator);
-            sorted[i] = views;
-        }
-        return sorted;
-    }
-
-    protected void verifyMargin() {
-        View[][] sorted = sortByRows();
-        for (int row = 0; row < sorted.length; row++) {
-            View[] views = sorted[row];
-            int margin = -1;
-            for (int i = 1; i < views.length; i++) {
-                if (mOrientation == BaseGridView.HORIZONTAL) {
-                    assertEquals(mGridView.getHorizontalMargin(),
-                            views[i].getLeft() - views[i - 1].getRight());
-                } else {
-                    assertEquals(mGridView.getVerticalMargin(),
-                            views[i].getTop() - views[i - 1].getBottom());
-                }
-            }
-        }
-    }
-
-    protected void verifyBeginAligned() {
-        View[][] sorted = sortByRows();
-        int alignedLocation = 0;
-        if (mOrientation == BaseGridView.HORIZONTAL) {
-            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-                for (int i = 0; i < sorted.length; i++) {
-                    if (i == 0) {
-                        alignedLocation = sorted[i][sorted[i].length - 1].getRight();
-                    } else {
-                        assertEquals(alignedLocation, sorted[i][sorted[i].length - 1].getRight());
-                    }
-                }
-            } else {
-                for (int i = 0; i < sorted.length; i++) {
-                    if (i == 0) {
-                        alignedLocation = sorted[i][0].getLeft();
-                    } else {
-                        assertEquals(alignedLocation, sorted[i][0].getLeft());
-                    }
-                }
-            }
-        } else {
-            for (int i = 0; i < sorted.length; i++) {
-                if (i == 0) {
-                    alignedLocation = sorted[i][0].getTop();
-                } else {
-                    assertEquals(alignedLocation, sorted[i][0].getTop());
-                }
-            }
-        }
-    }
-
-    protected int[] getEndEdges() {
-        View[][] sorted = sortByRows();
-        int[] edges = new int[sorted.length];
-        if (mOrientation == BaseGridView.HORIZONTAL) {
-            if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-                for (int i = 0; i < sorted.length; i++) {
-                    edges[i] = sorted[i][0].getLeft();
-                }
-            } else {
-                for (int i = 0; i < sorted.length; i++) {
-                    edges[i] = sorted[i][sorted[i].length - 1].getRight();
-                }
-            }
-        } else {
-            for (int i = 0; i < sorted.length; i++) {
-                edges[i] = sorted[i][sorted[i].length - 1].getBottom();
-            }
-        }
-        return edges;
-    }
-
-    protected void verifyEdgesSame(int[] edges, int[] edges2) {
-        assertEquals(edges.length, edges2.length);
-        for (int i = 0; i < edges.length; i++) {
-            assertEquals(edges[i], edges2[i]);
-        }
-    }
-
-    protected void verifyBoundCount(int count) {
-        if (mActivity.getBoundCount() != count) {
-            StringBuffer b = new StringBuffer();
-            b.append("ItemsLength: ");
-            for (int i = 0; i < mActivity.mItemLengths.length; i++) {
-                b.append(mActivity.mItemLengths[i]).append(",");
-            }
-            assertEquals("Bound count does not match, ItemsLengths: "+ b,
-                    count, mActivity.getBoundCount());
-        }
-    }
-
-    private static int getCenterY(View v) {
-        return (v.getTop() + v.getBottom())/2;
-    }
-
-    private static int getCenterX(View v) {
-        return (v.getLeft() + v.getRight())/2;
-    }
-
-    private void initActivity(Intent intent) throws Throwable {
-        mActivityTestRule = new ActivityTestRule<GridActivity>(GridActivity.class, false, false);
-        mActivity = mActivityTestRule.launchActivity(intent);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mActivity.setTitle(testName.getMethodName());
-                }
-            });
-        Thread.sleep(1000);
-        mGridView = mActivity.mGridView;
-        mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager();
-    }
-
-    @After
-    public void clearTest() {
-        mWaitLayoutListener = null;
-        mLayoutManager = null;
-        mGridView = null;
-        mActivity = null;
-        mActivityTestRule = null;
-    }
-
-    /**
-     * Must be called before waitForLayout() to prepare layout listener.
-     */
-    protected void startWaitLayout() {
-        if (mWaitLayoutListener != null) {
-            throw new IllegalStateException("startWaitLayout() already called");
-        }
-        if (mLayoutManager.mLayoutCompleteListener != null) {
-            throw new IllegalStateException("Cannot startWaitLayout()");
-        }
-        mWaitLayoutListener = mLayoutManager.mLayoutCompleteListener =
-                mock(GridLayoutManager.OnLayoutCompleteListener.class);
-    }
-
-    /**
-     * wait layout to be called and remove the listener.
-     */
-    protected void waitForLayout() {
-        waitForLayout(true);
-    }
-
-    /**
-     * wait layout to be called and remove the listener.
-     * @param force True if always wait regardless if layout requested
-     */
-    protected void waitForLayout(boolean force) {
-        if (mWaitLayoutListener == null) {
-            throw new IllegalStateException("startWaitLayout() not called");
-        }
-        if (mWaitLayoutListener != mLayoutManager.mLayoutCompleteListener) {
-            throw new IllegalStateException("layout listener inconistent");
-        }
-        try {
-            if (force || mGridView.isLayoutRequested()) {
-                verify(mWaitLayoutListener, timeout(WAIT_FOR_LAYOUT_PASS_TIMEOUT_MS).atLeastOnce())
-                        .onLayoutCompleted(any(RecyclerView.State.class));
-            }
-        } finally {
-            mWaitLayoutListener = null;
-            mLayoutManager.mLayoutCompleteListener = null;
-        }
-    }
-
-    /**
-     * If currently running animator, wait for it to finish, otherwise return immediately.
-     * To wait the ItemAnimator start, you can use waitForLayout() to make sure layout pass has
-     * processed adapter change.
-     */
-    protected void waitForItemAnimation(int timeoutMs) throws Throwable {
-        final RecyclerView.ItemAnimator.ItemAnimatorFinishedListener listener = mock(
-                RecyclerView.ItemAnimator.ItemAnimatorFinishedListener.class);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().isRunning(listener);
-            }
-        });
-        verify(listener, timeout(timeoutMs).atLeastOnce()).onAnimationsFinished();
-    }
-
-    protected void waitForItemAnimation() throws Throwable {
-        waitForItemAnimation(WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS);
-    }
-
-    /**
-     * wait animation start
-     */
-    protected void waitForItemAnimationStart() throws Throwable {
-        long totalWait = 0;
-        while (!mGridView.getItemAnimator().isRunning()) {
-            Thread.sleep(10);
-            if ((totalWait += 10) > WAIT_FOR_ITEM_ANIMATION_FINISH_TIMEOUT_MS) {
-                throw new RuntimeException("waitForItemAnimationStart Timeout");
-            }
-        }
-    }
-
-    /**
-     * Run task in UI thread and wait for layout and ItemAnimator finishes.
-     */
-    protected void performAndWaitForAnimation(Runnable task) throws Throwable {
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(task);
-        waitForLayout();
-        waitForItemAnimation();
-    }
-
-    protected void waitForScrollIdle() throws Throwable {
-        waitForScrollIdle(null);
-    }
-
-    /**
-     * Wait for grid view stop scroll and optionally verify state of grid view.
-     */
-    protected void waitForScrollIdle(Runnable verify) throws Throwable {
-        Thread.sleep(100);
-        int total = 0;
-        while (mGridView.getLayoutManager().isSmoothScrolling()
-                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
-            if ((total += 100) >= WAIT_FOR_SCROLL_IDLE_TIMEOUT_MS) {
-                throw new RuntimeException("waitForScrollIdle Timeout");
-            }
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException ex) {
-                break;
-            }
-            if (verify != null) {
-                mActivityTestRule.runOnUiThread(verify);
-            }
-        }
-    }
-
-    @Test
-    public void testThreeRowHorizontalBasic() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        scrollToEnd(mVerifyLayout);
-
-        scrollToBegin(mVerifyLayout);
-
-        verifyBeginAligned();
-    }
-
-    static class DividerDecoration extends RecyclerView.ItemDecoration {
-
-        private ColorDrawable mTopDivider;
-        private ColorDrawable mBottomDivider;
-        private int mLeftOffset;
-        private int mRightOffset;
-        private int mTopOffset;
-        private int mBottomOffset;
-
-        DividerDecoration(int leftOffset, int topOffset, int rightOffset, int bottomOffset) {
-            mLeftOffset = leftOffset;
-            mTopOffset = topOffset;
-            mRightOffset = rightOffset;
-            mBottomOffset = bottomOffset;
-        }
-
-        @Override
-        public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
-            if (mTopDivider == null) {
-                mTopDivider = new ColorDrawable(Color.RED);
-            }
-            if (mBottomDivider == null) {
-                mBottomDivider = new ColorDrawable(Color.BLUE);
-            }
-            final int childCount = parent.getChildCount();
-            final int width = parent.getWidth();
-            for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
-                final View view = parent.getChildAt(childViewIndex);
-                mTopDivider.setBounds(0, (int) view.getY() - mTopOffset, width, (int) view.getY());
-                mTopDivider.draw(c);
-                mBottomDivider.setBounds(0, (int) view.getY() + view.getHeight(), width,
-                        (int) view.getY() + view.getHeight() + mBottomOffset);
-                mBottomDivider.draw(c);
-            }
-        }
-
-        @Override
-        public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                                   RecyclerView.State state) {
-            outRect.left = mLeftOffset;
-            outRect.top = mTopOffset;
-            outRect.right = mRightOffset;
-            outRect.bottom = mBottomOffset;
-        }
-    }
-
-    @Test
-    public void testItemDecorationAndMargins() throws Throwable {
-
-        final int leftMargin = 3;
-        final int topMargin = 4;
-        final int rightMargin = 7;
-        final int bottomMargin = 8;
-        final int itemHeight = 100;
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight});
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS,
-                new int[]{leftMargin, topMargin, rightMargin, bottomMargin});
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        final int paddingLeft = mGridView.getPaddingLeft();
-        final int paddingTop = mGridView.getPaddingTop();
-        final int verticalSpace = mGridView.getVerticalMargin();
-        final int decorationLeft = 17;
-        final int decorationTop = 1;
-        final int decorationRight = 19;
-        final int decorationBottom = 2;
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
-                        decorationRight, decorationBottom));
-            }
-        });
-
-        View child0 = mGridView.getChildAt(0);
-        View child1 = mGridView.getChildAt(1);
-        View child2 = mGridView.getChildAt(2);
-
-        assertEquals(itemHeight, child0.getBottom() - child0.getTop());
-
-        // verify left margins
-        assertEquals(paddingLeft + leftMargin + decorationLeft, child0.getLeft());
-        assertEquals(paddingLeft + leftMargin + decorationLeft, child1.getLeft());
-        assertEquals(paddingLeft + leftMargin + decorationLeft, child2.getLeft());
-        // verify top bottom margins and decoration offset
-        assertEquals(paddingTop + topMargin + decorationTop, child0.getTop());
-        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
-                child1.getTop() - child0.getBottom());
-        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
-                child2.getTop() - child1.getBottom());
-
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
-    @Test
-    public void testItemDecorationAndMarginsAndOpticalBounds() throws Throwable {
-        final int leftMargin = 3;
-        final int topMargin = 4;
-        final int rightMargin = 7;
-        final int bottomMargin = 8;
-        final int itemHeight = 100;
-        final int ninePatchDrawableResourceId = R.drawable.lb_card_shadow_focused;
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{itemHeight, itemHeight, itemHeight});
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_MARGINS,
-                new int[]{leftMargin, topMargin, rightMargin, bottomMargin});
-        intent.putExtra(GridActivity.EXTRA_NINEPATCH_SHADOW, ninePatchDrawableResourceId);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        final int paddingLeft = mGridView.getPaddingLeft();
-        final int paddingTop = mGridView.getPaddingTop();
-        final int verticalSpace = mGridView.getVerticalMargin();
-        final int decorationLeft = 17;
-        final int decorationTop = 1;
-        final int decorationRight = 19;
-        final int decorationBottom = 2;
-
-        final Rect opticalPaddings = new Rect();
-        mGridView.getResources().getDrawable(ninePatchDrawableResourceId)
-                .getPadding(opticalPaddings);
-        final int opticalInsetsLeft = opticalPaddings.left;
-        final int opticalInsetsTop = opticalPaddings.top;
-        final int opticalInsetsRight = opticalPaddings.right;
-        final int opticalInsetsBottom = opticalPaddings.bottom;
-        assertTrue(opticalInsetsLeft > 0);
-        assertTrue(opticalInsetsTop > 0);
-        assertTrue(opticalInsetsRight > 0);
-        assertTrue(opticalInsetsBottom > 0);
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.addItemDecoration(new DividerDecoration(decorationLeft, decorationTop,
-                        decorationRight, decorationBottom));
-            }
-        });
-
-        View child0 = mGridView.getChildAt(0);
-        View child1 = mGridView.getChildAt(1);
-        View child2 = mGridView.getChildAt(2);
-
-        assertEquals(itemHeight + opticalInsetsTop + opticalInsetsBottom,
-                child0.getBottom() - child0.getTop());
-
-        // verify left margins decoration and optical insets
-        assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft,
-                child0.getLeft());
-        assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft,
-                child1.getLeft());
-        assertEquals(paddingLeft + leftMargin + decorationLeft - opticalInsetsLeft,
-                child2.getLeft());
-        // verify top bottom margins decoration offset and optical insets
-        assertEquals(paddingTop + topMargin + decorationTop, child0.getTop() + opticalInsetsTop);
-        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
-                (child1.getTop() + opticalInsetsTop) - (child0.getBottom() - opticalInsetsBottom));
-        assertEquals(bottomMargin + decorationBottom + verticalSpace + decorationTop + topMargin,
-                (child2.getTop() + opticalInsetsTop) - (child1.getBottom() - opticalInsetsBottom));
-
-    }
-
-    @Test
-    public void testThreeColumnVerticalBasic() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-
-        scrollToEnd(mVerifyLayout);
-
-        scrollToBegin(mVerifyLayout);
-
-        verifyBeginAligned();
-    }
-
-    @Test
-    public void testRedundantAppendRemove() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid_testredundantappendremove);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
-                149,177,128,234,227,187,163,223,146,210,228,148,227,193,182,197,177,142,225,207,
-                157,171,209,204,187,184,123,221,197,153,202,179,193,214,226,173,225,143,188,159,
-                139,193,233,143,227,203,222,124,228,223,164,131,228,126,211,160,165,152,235,184,
-                155,224,149,181,171,229,200,234,177,130,164,172,188,139,132,203,179,220,147,131,
-                226,127,230,239,183,203,206,227,123,170,239,234,200,149,237,204,160,133,202,234,
-                173,122,139,149,151,153,216,231,121,145,227,153,186,174,223,180,123,215,206,216,
-                239,222,219,207,193,218,140,133,171,153,183,132,233,138,159,174,189,171,143,128,
-                152,222,141,202,224,190,134,120,181,231,230,136,132,224,136,210,207,150,128,183,
-                221,194,179,220,126,221,137,205,223,193,172,132,226,209,133,191,227,127,159,171,
-                180,149,237,177,194,207,170,202,161,144,147,199,205,186,164,140,193,203,224,129});
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-
-        scrollToEnd(mVerifyLayout);
-
-        scrollToBegin(mVerifyLayout);
-
-        verifyBeginAligned();
-    }
-
-    @Test
-    public void testRedundantAppendRemove2() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid_testredundantappendremove2);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
-                318,333,199,224,246,273,269,289,340,313,265,306,349,269,185,282,257,354,316,252,
-                237,290,283,343,196,313,290,343,191,262,342,228,343,349,251,203,226,305,265,213,
-                216,333,295,188,187,281,288,311,244,232,224,332,290,181,267,276,226,261,335,355,
-                225,217,219,183,234,285,257,304,182,250,244,223,257,219,342,185,347,205,302,315,
-                299,309,292,237,192,309,228,250,347,227,337,298,299,185,185,331,223,284,265,351});
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-        mLayoutManager = (GridLayoutManager) mGridView.getLayoutManager();
-
-        // test append without staggered result cache
-        scrollToEnd(mVerifyLayout);
-
-        int[] endEdges = getEndEdges();
-
-        scrollToBegin(mVerifyLayout);
-
-        verifyBeginAligned();
-
-        // now test append with staggered result cache
-        changeArraySize(3);
-        assertEquals("Staggerd cache should be kept as is when no item size change",
-                100, ((StaggeredGrid) mLayoutManager.mGrid).mLocations.size());
-
-        changeArraySize(100);
-
-        scrollToEnd(mVerifyLayout);
-
-        // we should get same aligned end edges
-        int[] endEdges2 = getEndEdges();
-        verifyEdgesSame(endEdges, endEdges2);
-    }
-
-
-    @Test
-    public void testLayoutWhenAViewIsInvalidated() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
-        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, true);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mNumRows = 1;
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        waitOneUiCycle();
-
-        // push views to cache.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.mItemLengths[0] = mActivity.mItemLengths[0] * 3;
-                mActivity.mGridView.getAdapter().notifyItemChanged(0);
-            }
-        });
-        waitForItemAnimation();
-
-        // notifyDataSetChange will mark the cached views FLAG_INVALID
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.mGridView.getAdapter().notifyDataSetChanged();
-            }
-        });
-        waitForItemAnimation();
-
-        // Cached views will be added in prelayout with FLAG_INVALID, in post layout we should
-        // handle it properly
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.mItemLengths[0] = mActivity.mItemLengths[0] / 3;
-                mActivity.mGridView.getAdapter().notifyItemChanged(0);
-            }
-        });
-
-        waitForItemAnimation();
-    }
-
-    @Test
-    public void testWrongInsertViewIndexInFastRelayout() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mNumRows = 1;
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-
-        // removing two children, they will be hidden views as first 2 children of RV.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setRemoveDuration(2000);
-                mActivity.removeItems(0, 2);
-            }
-        });
-        waitForItemAnimationStart();
-
-        // add three views and notify change of the first item.
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(0, new int[]{161, 161, 161});
-            }
-        });
-        waitForLayout();
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getAdapter().notifyItemChanged(0);
-            }
-        });
-        waitForLayout();
-        // after layout, the viewholder should still be the first child of LayoutManager.
-        assertEquals(0, mGridView.getChildAdapterPosition(
-                mGridView.getLayoutManager().getChildAt(0)));
-    }
-
-    @Test
-    public void testMoveIntoPrelayoutItems() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mNumRows = 1;
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-
-        final int lastItemPos = mGridView.getChildCount() - 1;
-        assertTrue(mGridView.getChildCount() >= 4);
-        // notify change of 3 items, so prelayout will layout extra 3 items, then move an item
-        // into the extra layout range. Post layout's fastRelayout() should handle this properly.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getAdapter().notifyItemChanged(lastItemPos - 3);
-                mGridView.getAdapter().notifyItemChanged(lastItemPos - 2);
-                mGridView.getAdapter().notifyItemChanged(lastItemPos - 1);
-                mActivity.moveItem(900, lastItemPos + 2, true);
-            }
-        });
-        waitForItemAnimation();
-    }
-
-    @Test
-    public void testMoveIntoPrelayoutItems2() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mNumRows = 1;
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-
-        setSelectedPosition(999);
-        final int firstItemPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(0));
-        assertTrue(mGridView.getChildCount() >= 4);
-        // notify change of 3 items, so prelayout will layout extra 3 items, then move an item
-        // into the extra layout range. Post layout's fastRelayout() should handle this properly.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getAdapter().notifyItemChanged(firstItemPos + 1);
-                mGridView.getAdapter().notifyItemChanged(firstItemPos + 2);
-                mGridView.getAdapter().notifyItemChanged(firstItemPos + 3);
-                mActivity.moveItem(0, firstItemPos - 2, true);
-            }
-        });
-        waitForItemAnimation();
-    }
-
-    void preparePredictiveLayout() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setAddDuration(1000);
-                mGridView.getItemAnimator().setRemoveDuration(1000);
-                mGridView.getItemAnimator().setMoveDuration(1000);
-                mGridView.getItemAnimator().setChangeDuration(1000);
-                mGridView.setSelectedPositionSmooth(50);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-    }
-
-    @Test
-    public void testPredictiveLayoutAdd1() throws Throwable {
-        preparePredictiveLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(51, new int[]{300, 300, 300, 300});
-            }
-        });
-        waitForItemAnimationStart();
-        waitForItemAnimation();
-        assertEquals(50, mGridView.getSelectedPosition());
-        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
-    }
-
-    @Test
-    public void testPredictiveLayoutAdd2() throws Throwable {
-        preparePredictiveLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(50, new int[]{300, 300, 300, 300});
-            }
-        });
-        waitForItemAnimationStart();
-        waitForItemAnimation();
-        assertEquals(54, mGridView.getSelectedPosition());
-        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
-    }
-
-    @Test
-    public void testPredictiveLayoutRemove1() throws Throwable {
-        preparePredictiveLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(51, 3);
-            }
-        });
-        waitForItemAnimationStart();
-        waitForItemAnimation();
-        assertEquals(50, mGridView.getSelectedPosition());
-        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
-    }
-
-    @Test
-    public void testPredictiveLayoutRemove2() throws Throwable {
-        preparePredictiveLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(47, 3);
-            }
-        });
-        waitForItemAnimationStart();
-        waitForItemAnimation();
-        assertEquals(47, mGridView.getSelectedPosition());
-        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
-    }
-
-    @Test
-    public void testPredictiveLayoutRemove3() throws Throwable {
-        preparePredictiveLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(0, 51);
-            }
-        });
-        waitForItemAnimationStart();
-        waitForItemAnimation();
-        assertEquals(0, mGridView.getSelectedPosition());
-        assertEquals(RecyclerView.SCROLL_STATE_IDLE, mGridView.getScrollState());
-    }
-
-    @Test
-    public void testPredictiveOnMeasureWrapContent() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear_wrap_content);
-        int count = 50;
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, count);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        waitForScrollIdle(mVerifyLayout);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setHasFixedSize(false);
-            }
-        });
-
-        for (int i = 0; i < 30; i++) {
-            final int oldCount = count;
-            final int newCount = i;
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (oldCount > 0) {
-                        mActivity.removeItems(0, oldCount);
-                    }
-                    if (newCount > 0) {
-                        int[] newItems = new int[newCount];
-                        for (int i = 0; i < newCount; i++) {
-                            newItems[i] = 400;
-                        }
-                        mActivity.addItems(0, newItems);
-                    }
-                }
-            });
-            waitForItemAnimationStart();
-            waitForItemAnimation();
-            count = newCount;
-        }
-
-    }
-
-    @Test
-    public void testPredictiveLayoutRemove4() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(50);
-            }
-        });
-        waitForScrollIdle();
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(0, 49);
-            }
-        });
-        assertEquals(1, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testPredictiveLayoutRemove5() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(50);
-            }
-        });
-        waitForScrollIdle();
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(50, 40);
-            }
-        });
-        assertEquals(50, mGridView.getSelectedPosition());
-        scrollToBegin(mVerifyLayout);
-        verifyBeginAligned();
-    }
-
-    void waitOneUiCycle() throws Throwable {
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-            }
-        });
-    }
-
-    @Test
-    public void testDontPruneMovingItem() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setMoveDuration(2000);
-                mGridView.setSelectedPosition(50);
-            }
-        });
-        waitForScrollIdle();
-        final ArrayList<RecyclerView.ViewHolder> moveViewHolders = new ArrayList();
-        for (int i = 51;; i++) {
-            RecyclerView.ViewHolder vh = mGridView.findViewHolderForAdapterPosition(i);
-            if (vh == null) {
-                break;
-            }
-            moveViewHolders.add(vh);
-        }
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // add a lot of items, so we will push everything to right of 51 out side window
-                int[] lots_items = new int[1000];
-                for (int i = 0; i < lots_items.length; i++) {
-                    lots_items[i] = 300;
-                }
-                mActivity.addItems(51, lots_items);
-            }
-        });
-        waitOneUiCycle();
-        // run a scroll pass, the scroll pass should not remove the animating views even they are
-        // outside visible areas.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.scrollBy(-3, 0);
-            }
-        });
-        waitOneUiCycle();
-        for (int i = 0; i < moveViewHolders.size(); i++) {
-            assertSame(mGridView, moveViewHolders.get(i).itemView.getParent());
-        }
-    }
-
-    @Test
-    public void testMoveItemToTheRight() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setAddDuration(2000);
-                mGridView.getItemAnimator().setMoveDuration(2000);
-                mGridView.setSelectedPosition(50);
-            }
-        });
-        waitForScrollIdle();
-        RecyclerView.ViewHolder moveViewHolder = mGridView.findViewHolderForAdapterPosition(51);
-
-        int lastPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(
-                mGridView.getChildCount() - 1));
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.moveItem(51, 1000, true);
-            }
-        });
-        final ArrayList<View> moveInViewHolders = new ArrayList();
-        waitForItemAnimationStart();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mGridView.getLayoutManager().getChildCount(); i++) {
-                    View v = mGridView.getLayoutManager().getChildAt(i);
-                    if (mGridView.getChildAdapterPosition(v) >= 51) {
-                        moveInViewHolders.add(v);
-                    }
-                }
-            }
-        });
-        waitOneUiCycle();
-        assertTrue("prelayout should layout extra items to slide in",
-                moveInViewHolders.size() > lastPos - 51);
-        // run a scroll pass, the scroll pass should not remove the animating views even they are
-        // outside visible areas.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.scrollBy(-3, 0);
-            }
-        });
-        waitOneUiCycle();
-        for (int i = 0; i < moveInViewHolders.size(); i++) {
-            assertSame(mGridView, moveInViewHolders.get(i).getParent());
-        }
-        assertSame(mGridView, moveViewHolder.itemView.getParent());
-        assertFalse(moveViewHolder.isRecyclable());
-        waitForItemAnimation();
-        assertNull(moveViewHolder.itemView.getParent());
-        assertTrue(moveViewHolder.isRecyclable());
-    }
-
-    @Test
-    public void testMoveItemToTheLeft() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setAddDuration(2000);
-                mGridView.getItemAnimator().setMoveDuration(2000);
-                mGridView.setSelectedPosition(1500);
-            }
-        });
-        waitForScrollIdle();
-        RecyclerView.ViewHolder moveViewHolder = mGridView.findViewHolderForAdapterPosition(1499);
-
-        int firstPos = mGridView.getChildAdapterPosition(mGridView.getChildAt(0));
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.moveItem(1499, 1, true);
-            }
-        });
-        final ArrayList<View> moveInViewHolders = new ArrayList();
-        waitForItemAnimationStart();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mGridView.getLayoutManager().getChildCount(); i++) {
-                    View v = mGridView.getLayoutManager().getChildAt(i);
-                    if (mGridView.getChildAdapterPosition(v) <= 1499) {
-                        moveInViewHolders.add(v);
-                    }
-                }
-            }
-        });
-        waitOneUiCycle();
-        assertTrue("prelayout should layout extra items to slide in ",
-                moveInViewHolders.size() > 1499 - firstPos);
-        // run a scroll pass, the scroll pass should not remove the animating views even they are
-        // outside visible areas.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.scrollBy(3, 0);
-            }
-        });
-        waitOneUiCycle();
-        for (int i = 0; i < moveInViewHolders.size(); i++) {
-            assertSame(mGridView, moveInViewHolders.get(i).getParent());
-        }
-        assertSame(mGridView, moveViewHolder.itemView.getParent());
-        assertFalse(moveViewHolder.isRecyclable());
-        waitForItemAnimation();
-        assertNull(moveViewHolder.itemView.getParent());
-        assertTrue(moveViewHolder.isRecyclable());
-    }
-
-    @Test
-    public void testContinuousSwapForward() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(150);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        for (int i = 150; i < 199; i++) {
-            final int swapIndex = i;
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mActivity.swap(swapIndex, swapIndex + 1);
-                }
-            });
-            Thread.sleep(10);
-        }
-        waitForItemAnimation();
-        assertEquals(199, mGridView.getSelectedPosition());
-        // check if ItemAnimation finishes at aligned positions:
-        int leftEdge = mGridView.getLayoutManager().findViewByPosition(199).getLeft();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(199).getLeft());
-    }
-
-    @Test
-    public void testContinuousSwapBackward() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(50);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        for (int i = 50; i > 0; i--) {
-            final int swapIndex = i;
-            mActivityTestRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mActivity.swap(swapIndex, swapIndex - 1);
-                }
-            });
-            Thread.sleep(10);
-        }
-        waitForItemAnimation();
-        assertEquals(0, mGridView.getSelectedPosition());
-        // check if ItemAnimation finishes at aligned positions:
-        int leftEdge = mGridView.getLayoutManager().findViewByPosition(0).getLeft();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(0).getLeft());
-    }
-
-    @Test
-    public void testScrollAndStuck() throws Throwable {
-        // see b/67370222 fastRelayout() may be stuck.
-        final int numItems = 19;
-        final int[] itemsLength = new int[numItems];
-        for (int i = 0; i < numItems; i++) {
-            itemsLength[i] = 288;
-        }
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        // set left right padding to 112, space between items to be 16.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ViewGroup.LayoutParams lp = mGridView.getLayoutParams();
-                lp.width = 1920;
-                mGridView.setLayoutParams(lp);
-                mGridView.setPadding(112, mGridView.getPaddingTop(), 112,
-                        mGridView.getPaddingBottom());
-                mGridView.setItemSpacing(16);
-            }
-        });
-        waitOneUiCycle();
-
-        int scrollPos = 0;
-        while (true) {
-            final View view = mGridView.getChildAt(mGridView.getChildCount() - 1);
-            final int pos = mGridView.getChildViewHolder(view).getAdapterPosition();
-            if (scrollPos != pos) {
-                scrollPos = pos;
-                mActivityTestRule.runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        mGridView.smoothScrollToPosition(pos);
-                    }
-                });
-            }
-            // wait until we see 2nd from last:
-            if (pos >= 17) {
-                if (pos == 17) {
-                    // great we can test fastRelayout() bug.
-                    Thread.sleep(50);
-                    mActivityTestRule.runOnUiThread(new Runnable() {
-                        @Override
-                        public void run() {
-                            view.requestLayout();
-                        }
-                    });
-                }
-                break;
-            }
-            Thread.sleep(16);
-        }
-        waitForScrollIdle();
-    }
-
-    @Test
-    public void testSwapAfterScroll() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setMoveDuration(1000);
-                mGridView.setSelectedPositionSmooth(150);
-            }
-        });
-        waitForScrollIdle();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(151);
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // we want to swap and select new target which is at 150 before swap
-                mGridView.setSelectedPositionSmooth(150);
-                mActivity.swap(150, 151);
-            }
-        });
-        waitForItemAnimation();
-        waitForScrollIdle();
-        assertEquals(151, mGridView.getSelectedPosition());
-        // check if ItemAnimation finishes at aligned positions:
-        int leftEdge = mGridView.getLayoutManager().findViewByPosition(151).getLeft();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(leftEdge, mGridView.getLayoutManager().findViewByPosition(151).getLeft());
-    }
-
-    void testScrollInSmoothScrolling(final boolean smooth, final boolean scrollToInvisible,
-            final boolean useRecyclerViewMethod) throws Throwable {
-        final int numItems = 100;
-        final int[] itemsLength = new int[numItems];
-        for (int i = 0; i < numItems; i++) {
-            itemsLength[i] = 288;
-        }
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        // start a smoothScroller
-        final int selectedPosition = 99;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.smoothScrollToPosition(selectedPosition);
-            }
-        });
-        Thread.sleep(50);
-        // while smoothScroller is still running, scroll to a different position
-        final int[] existing_position = new int[1];
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                existing_position[0] = mGridView.getChildAdapterPosition(
-                        mGridView.getChildAt(mGridView.getChildCount() - 1));
-                if (scrollToInvisible) {
-                    existing_position[0] = existing_position[0] + 3;
-                }
-                if (useRecyclerViewMethod) {
-                    if (smooth) {
-                        mGridView.smoothScrollToPosition(existing_position[0]);
-                    } else {
-                        mGridView.scrollToPosition(existing_position[0]);
-                    }
-                } else {
-                    if (smooth) {
-                        mGridView.setSelectedPositionSmooth(existing_position[0]);
-                    } else {
-                        mGridView.setSelectedPosition(existing_position[0]);
-                    }
-                }
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(existing_position[0], mGridView.getSelectedPosition());
-        assertTrue(mGridView.findViewHolderForAdapterPosition(existing_position[0])
-                .itemView.hasFocus());
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling1() throws Throwable {
-        testScrollInSmoothScrolling(false, false, false);
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling2() throws Throwable {
-        testScrollInSmoothScrolling(false, false, true);
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling3() throws Throwable {
-        testScrollInSmoothScrolling(false, true, false);
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling4() throws Throwable {
-        testScrollInSmoothScrolling(false, true, true);
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling5() throws Throwable {
-        testScrollInSmoothScrolling(true, false, false);
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling6() throws Throwable {
-        testScrollInSmoothScrolling(true, false, true);
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling7() throws Throwable {
-        testScrollInSmoothScrolling(true, true, false);
-    }
-
-    @Test
-    public void testScrollInSmoothScrolling8() throws Throwable {
-        testScrollInSmoothScrolling(true, true, true);
-    }
-
-    @Test
-    public void testScrollAfterRequestLayout() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setHasFixedSize(false);
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffsetPercent(30);
-            }
-        });
-        waitOneUiCycle();
-
-        final boolean[] scrolled = new boolean[1];
-        mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                if (dx != 0)  scrolled[0] = true;
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-                mGridView.setSelectedPosition(1);
-            }
-        });
-        waitOneUiCycle();
-        assertFalse(scrolled[0]);
-    }
-
-    @Test
-    public void testScrollAfterItemAnimator() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setHasFixedSize(false);
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffsetPercent(30);
-            }
-        });
-        waitOneUiCycle();
-
-        final boolean[] scrolled = new boolean[1];
-        mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                if (dx != 0)  scrolled[0] = true;
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.changeItem(0, 10);
-                mGridView.setSelectedPosition(1);
-            }
-        });
-        waitOneUiCycle();
-        assertFalse(scrolled[0]);
-    }
-
-    @Test
-    public void testItemMovedHorizontal() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(150);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.swap(150, 152);
-            }
-        });
-        mActivityTestRule.runOnUiThread(mVerifyLayout);
-
-        scrollToBegin(mVerifyLayout);
-
-        verifyBeginAligned();
-    }
-
-    @Test
-    public void testItemMovedHorizontalRtl() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear_rtl);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[] {40, 40, 40});
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.moveItem(0, 1, true);
-            }
-        });
-        assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(),
-                mGridView.findViewHolderForAdapterPosition(0).itemView.getRight());
-    }
-
-    @Test
-    public void testScrollSecondaryCannotScroll() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-        final int topPadding = 2;
-        final int bottomPadding = 2;
-        final int height = mGridView.getHeight();
-        final int spacing = 2;
-        final int rowHeight = (height - topPadding - bottomPadding) / 4 - spacing;
-        final HorizontalGridView horizontalGridView = (HorizontalGridView) mGridView;
-
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                horizontalGridView.setPadding(0, topPadding, 0, bottomPadding);
-                horizontalGridView.setItemSpacing(spacing);
-                horizontalGridView.setNumRows(mNumRows);
-                horizontalGridView.setRowHeight(rowHeight);
-            }
-        });
-        waitForLayout();
-        // navigate vertically in first column, first row should always be aligned to top padding
-        for (int i = 0; i < 3; i++) {
-            setSelectedPosition(i);
-            assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView
-                    .getTop());
-        }
-        // navigate vertically in 100th column, first row should always be aligned to top padding
-        for (int i = 300; i < 301; i++) {
-            setSelectedPosition(i);
-            assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(300).itemView
-                    .getTop());
-        }
-    }
-
-    @Test
-    public void testScrollSecondaryNeedScroll() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2000);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        // test a lot of rows so we have to scroll vertically to reach
-        mNumRows = 9;
-        final int topPadding = 2;
-        final int bottomPadding = 2;
-        final int height = mGridView.getHeight();
-        final int spacing = 2;
-        final int rowHeight = (height - topPadding - bottomPadding) / 4 - spacing;
-        final HorizontalGridView horizontalGridView = (HorizontalGridView) mGridView;
-
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                horizontalGridView.setPadding(0, topPadding, 0, bottomPadding);
-                horizontalGridView.setItemSpacing(spacing);
-                horizontalGridView.setNumRows(mNumRows);
-                horizontalGridView.setRowHeight(rowHeight);
-            }
-        });
-        waitForLayout();
-        View view;
-        // first row should be aligned to top padding
-        setSelectedPosition(0);
-        assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView.getTop());
-        // middle row should be aligned to keyline (1/2 of screen height)
-        setSelectedPosition(4);
-        view = mGridView.findViewHolderForAdapterPosition(4).itemView;
-        assertEquals(height / 2, (view.getTop() + view.getBottom()) / 2);
-        // last row should be aligned to bottom padding.
-        setSelectedPosition(8);
-        view = mGridView.findViewHolderForAdapterPosition(8).itemView;
-        assertEquals(height, view.getTop() + rowHeight + bottomPadding);
-        setSelectedPositionSmooth(4);
-        waitForScrollIdle();
-        // middle row should be aligned to keyline (1/2 of screen height)
-        setSelectedPosition(4);
-        view = mGridView.findViewHolderForAdapterPosition(4).itemView;
-        assertEquals(height / 2, (view.getTop() + view.getBottom()) / 2);
-        // first row should be aligned to top padding
-        setSelectedPositionSmooth(0);
-        waitForScrollIdle();
-        assertEquals(topPadding, mGridView.findViewHolderForAdapterPosition(0).itemView.getTop());
-    }
-
-    @Test
-    public void testItemMovedVertical() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-
-        mGridView.setSelectedPositionSmooth(150);
-        waitForScrollIdle(mVerifyLayout);
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.swap(150, 152);
-            }
-        });
-        mActivityTestRule.runOnUiThread(mVerifyLayout);
-
-        scrollToEnd(mVerifyLayout);
-        scrollToBegin(mVerifyLayout);
-
-        verifyBeginAligned();
-    }
-
-    @Test
-    public void testAddLastItemHorizontal() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        mGridView.setSelectedPositionSmooth(49);
-                    }
-                }
-        );
-        waitForScrollIdle(mVerifyLayout);
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(50, new int[]{150});
-            }
-        });
-
-        // assert new added item aligned to right edge
-        assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(),
-                mGridView.getLayoutManager().findViewByPosition(50).getRight());
-    }
-
-    @Test
-    public void testAddMultipleLastItemsHorizontal() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_BOTH_EDGE);
-                        mGridView.setWindowAlignmentOffsetPercent(50);
-                        mGridView.setSelectedPositionSmooth(49);
-                    }
-                }
-        );
-        waitForScrollIdle(mVerifyLayout);
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(50, new int[]{150, 150, 150, 150, 150, 150, 150, 150, 150,
-                        150, 150, 150, 150, 150});
-            }
-        });
-
-        // The focused item will be at center of window
-        View view = mGridView.getLayoutManager().findViewByPosition(49);
-        assertEquals(mGridView.getWidth() / 2, (view.getLeft() + view.getRight()) / 2);
-    }
-
-    @Test
-    public void testItemAddRemoveHorizontal() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        scrollToEnd(mVerifyLayout);
-        int[] endEdges = getEndEdges();
-
-        mGridView.setSelectedPositionSmooth(150);
-        waitForScrollIdle(mVerifyLayout);
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mRemovedItems = mActivity.removeItems(151, 4);
-            }
-        });
-
-        scrollToEnd(mVerifyLayout);
-        mGridView.setSelectedPositionSmooth(150);
-        waitForScrollIdle(mVerifyLayout);
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(151, mRemovedItems);
-            }
-        });
-        scrollToEnd(mVerifyLayout);
-
-        // we should get same aligned end edges
-        int[] endEdges2 = getEndEdges();
-        verifyEdgesSame(endEdges, endEdges2);
-
-        scrollToBegin(mVerifyLayout);
-        verifyBeginAligned();
-    }
-
-    @Test
-    public void testSetSelectedPositionDetached() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int focusToIndex = 49;
-        final ViewGroup parent = (ViewGroup) mGridView.getParent();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                parent.removeView(mGridView);
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex);
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                parent.addView(mGridView);
-                mGridView.requestFocus();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(mGridView.getSelectedPosition(), focusToIndex);
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex).hasFocus());
-
-        final int focusToIndex2 = 0;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                parent.removeView(mGridView);
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPosition(focusToIndex2);
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                parent.addView(mGridView);
-                mGridView.requestFocus();
-            }
-        });
-        assertEquals(mGridView.getSelectedPosition(), focusToIndex2);
-        waitForScrollIdle();
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(focusToIndex2).hasFocus());
-    }
-
-    @Test
-    public void testBug22209986() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 50);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int focusToIndex = mGridView.getChildCount() - 1;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex);
-            }
-        });
-
-        waitForScrollIdle();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex + 1);
-            }
-        });
-        // let the scroll running for a while and requestLayout during scroll
-        Thread.sleep(80);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertEquals(mGridView.getScrollState(), BaseGridView.SCROLL_STATE_SETTLING);
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-
-        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(leftEdge,
-                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
-    }
-
-    void testScrollAndRemove(int[] itemsLength, int numItems) throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        if (itemsLength != null) {
-            intent.putExtra(GridActivity.EXTRA_ITEMS, itemsLength);
-        } else {
-            intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        }
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int focusToIndex = mGridView.getChildCount() - 1;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex);
-            }
-        });
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(focusToIndex, 1);
-            }
-        });
-
-        waitOneUiCycle();
-        waitForScrollIdle();
-        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(leftEdge,
-                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft(), DELTA);
-    }
-
-    @Test
-    public void testScrollAndRemove() throws Throwable {
-        // test random lengths for 50 items
-        testScrollAndRemove(null, 50);
-    }
-
-    /**
-     * This test verifies if scroll limits are ignored when onLayoutChildren compensate remaining
-     * scroll distance. b/64931938
-     * In the test, second child is long, other children are short.
-     * Test scrolls to the long child, and when scrolling, remove the long child. We made it long
-     * to have enough remaining scroll distance when the layout pass kicks in.
-     * The onLayoutChildren() would compensate the remaining scroll distance, moving all items
-     * toward right, which will make the first item's left edge bigger than left padding,
-     * which would violate the "scroll limit of left" in a regular scroll case, but
-     * in layout pass, we still honor that scroll request, ignoring the scroll limit.
-     */
-    @Test
-    public void testScrollAndRemoveSample1() throws Throwable {
-        DisplayMetrics dm = InstrumentationRegistry.getInstrumentation().getTargetContext()
-                .getResources().getDisplayMetrics();
-        // screen width for long item and 4DP for other items
-        int longItemLength = dm.widthPixels;
-        int shortItemLength = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, dm);
-        int[] items = new int[1000];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = shortItemLength;
-        }
-        items[1] = longItemLength;
-        testScrollAndRemove(items, 0);
-    }
-
-    @Test
-    public void testScrollAndInsert() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        int[] items = new int[1000];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300 + (int)(Math.random() * 100);
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(150);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-
-        View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
-        final int focusToIndex = mGridView.getChildAdapterPosition(view);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex);
-            }
-        });
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int[] newItems = new int[]{300, 300, 300};
-                mActivity.addItems(0, newItems);
-            }
-        });
-        waitForScrollIdle();
-        int topEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getTop();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(topEdge,
-                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getTop());
-    }
-
-    @Test
-    public void testScrollAndInsertBeforeVisibleItem() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        int[] items = new int[1000];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300 + (int)(Math.random() * 100);
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(150);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-
-        View view =  mGridView.getChildAt(mGridView.getChildCount() - 1);
-        final int focusToIndex = mGridView.getChildAdapterPosition(view);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex);
-            }
-        });
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                int[] newItems = new int[]{300, 300, 300};
-                mActivity.addItems(focusToIndex, newItems);
-            }
-        });
-    }
-
-    @Test
-    public void testSmoothScrollAndRemove() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int focusToIndex = 200;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex);
-            }
-        });
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(focusToIndex, 1);
-            }
-        });
-
-        assertTrue("removing the index of not attached child should not affect smooth scroller",
-                mGridView.getLayoutManager().isSmoothScrolling());
-        waitForScrollIdle();
-        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(leftEdge,
-                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
-    }
-
-    @Test
-    public void testSmoothScrollAndRemove2() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int focusToIndex = 200;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusToIndex);
-            }
-        });
-
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final int removeIndex = mGridView.getChildViewHolder(
-                        mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition();
-                mActivity.removeItems(removeIndex, 1);
-            }
-        });
-        waitForLayout();
-
-        assertTrue("removing the index of attached child should not kill smooth scroller",
-                mGridView.getLayoutManager().isSmoothScrolling());
-        waitForItemAnimation();
-        waitForScrollIdle();
-        int leftEdge = mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft();
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(leftEdge,
-                mGridView.getLayoutManager().findViewByPosition(focusToIndex).getLeft());
-    }
-
-    @Test
-    public void testPendingSmoothScrollAndRemove() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 630 + (int)(Math.random() * 100);
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mGridView.setSelectedPositionSmooth(0);
-        waitForScrollIdle(mVerifyLayout);
-        assertTrue(mGridView.getChildAt(0).hasFocus());
-
-        // Pressing lots of key to make sure smooth scroller is running
-        mGridView.mLayoutManager.mMaxPendingMoves = 100;
-        for (int i = 0; i < 100; i++) {
-            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        }
-
-        assertTrue(mGridView.getLayoutManager().isSmoothScrolling());
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final int removeIndex = mGridView.getChildViewHolder(
-                        mGridView.getChildAt(mGridView.getChildCount() - 1)).getAdapterPosition();
-                mActivity.removeItems(removeIndex, 1);
-            }
-        });
-        waitForLayout();
-
-        assertTrue("removing the index of attached child should not kill smooth scroller",
-                mGridView.getLayoutManager().isSmoothScrolling());
-
-        waitForItemAnimation();
-        waitForScrollIdle();
-        int focusIndex = mGridView.getSelectedPosition();
-        int topEdge = mGridView.getLayoutManager().findViewByPosition(focusIndex).getTop();
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-            }
-        });
-        waitForScrollIdle();
-        assertEquals(topEdge,
-                mGridView.getLayoutManager().findViewByPosition(focusIndex).getTop());
-    }
-
-    @Test
-    public void testFocusToFirstItem() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 200);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mRemovedItems = mActivity.removeItems(0, 200);
-            }
-        });
-
-        humanDelay(500);
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(0, mRemovedItems);
-            }
-        });
-
-        humanDelay(500);
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus());
-
-        changeArraySize(0);
-
-        changeArraySize(200);
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(0).hasFocus());
-    }
-
-    @Test
-    public void testNonFocusableHorizontal() throws Throwable {
-        final int numItems = 200;
-        final int startPos = 45;
-        final int skips = 20;
-        final int numColumns = 3;
-        final int endPos = startPos + numColumns * (skips + 1);
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = numColumns;
-        boolean[] focusable = new boolean[numItems];
-        for (int i = 0; i < focusable.length; i++) {
-            focusable[i] = true;
-        }
-        for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) {
-            focusable[i] = false;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        mGridView.setSelectedPositionSmooth(startPos);
-        waitForScrollIdle(mVerifyLayout);
-
-        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
-        } else {
-            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
-        }
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(endPos, mGridView.getSelectedPosition());
-
-        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
-        } else {
-            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
-        }
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(startPos, mGridView.getSelectedPosition());
-
-    }
-
-    @Test
-    public void testNoInitialFocusable() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        final int numItems = 100;
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-        boolean[] focusable = new boolean[numItems];
-        final int firstFocusableIndex = 10;
-        for (int i = 0; i < firstFocusableIndex; i++) {
-            focusable[i] = false;
-        }
-        for (int i = firstFocusableIndex; i < focusable.length; i++) {
-            focusable[i] = true;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-        assertTrue(mGridView.isFocused());
-
-        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-            sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
-        } else {
-            sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
-        }
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(firstFocusableIndex, mGridView.getSelectedPosition());
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus());
-    }
-
-    @Test
-    public void testFocusOutOfEmptyListView() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        final int numItems = 100;
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-        initActivity(intent);
-
-        final View horizontalGridView = new HorizontalGridViewEx(mGridView.getContext());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                horizontalGridView.setFocusable(true);
-                horizontalGridView.setFocusableInTouchMode(true);
-                horizontalGridView.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
-                ((ViewGroup) mGridView.getParent()).addView(horizontalGridView, 0);
-                horizontalGridView.requestFocus();
-            }
-        });
-
-        assertTrue(horizontalGridView.isFocused());
-
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-
-        assertTrue(mGridView.hasFocus());
-    }
-
-    @Test
-    public void testTransferFocusToChildWhenGainFocus() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        final int numItems = 100;
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-        boolean[] focusable = new boolean[numItems];
-        final int firstFocusableIndex = 1;
-        for (int i = 0; i < firstFocusableIndex; i++) {
-            focusable[i] = false;
-        }
-        for (int i = firstFocusableIndex; i < focusable.length; i++) {
-            focusable[i] = true;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        assertEquals(firstFocusableIndex, mGridView.getSelectedPosition());
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(firstFocusableIndex).hasFocus());
-    }
-
-    @Test
-    public void testFocusFromSecondChild() throws Throwable {
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        final int numItems = 100;
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-        boolean[] focusable = new boolean[numItems];
-        for (int i = 0; i < focusable.length; i++) {
-            focusable[i] = false;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        // switching Adapter to cause a full rebind,  test if it will focus to second item.
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.mNumItems = numItems;
-                mActivity.mItemFocusables[1] = true;
-                mActivity.rebindToNewAdapter();
-            }
-        });
-        assertTrue(mGridView.findViewHolderForAdapterPosition(1).itemView.hasFocus());
-    }
-
-    @Test
-    public void removeFocusableItemAndFocusableRecyclerViewGetsFocus() throws Throwable {
-        final int numItems = 100;
-        final int numColumns = 3;
-        final int focusableIndex = 2;
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = numColumns;
-        boolean[] focusable = new boolean[numItems];
-        for (int i = 0; i < focusable.length; i++) {
-            focusable[i] = false;
-        }
-        focusable[focusableIndex] = true;
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(focusableIndex);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(focusableIndex, mGridView.getSelectedPosition());
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(focusableIndex, 1);
-            }
-        });
-        assertTrue(dumpGridView(mGridView), mGridView.isFocused());
-    }
-
-    @Test
-    public void removeFocusableItemAndUnFocusableRecyclerViewLosesFocus() throws Throwable {
-        final int numItems = 100;
-        final int numColumns = 3;
-        final int focusableIndex = 2;
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = numColumns;
-        boolean[] focusable = new boolean[numItems];
-        for (int i = 0; i < focusable.length; i++) {
-            focusable[i] = false;
-        }
-        focusable[focusableIndex] = true;
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setFocusableInTouchMode(false);
-                mGridView.setFocusable(false);
-                mGridView.setSelectedPositionSmooth(focusableIndex);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(focusableIndex, mGridView.getSelectedPosition());
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(focusableIndex, 1);
-            }
-        });
-        assertFalse(dumpGridView(mGridView), mGridView.hasFocus());
-    }
-
-    @Test
-    public void testNonFocusableVertical() throws Throwable {
-        final int numItems = 200;
-        final int startPos = 44;
-        final int skips = 20;
-        final int numColumns = 3;
-        final int endPos = startPos + numColumns * (skips + 1);
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = numColumns;
-        boolean[] focusable = new boolean[numItems];
-        for (int i = 0; i < focusable.length; i++) {
-            focusable[i] = true;
-        }
-        for (int i = startPos + mNumRows, j = 0; j < skips; i += mNumRows, j++) {
-            focusable[i] = false;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        mGridView.setSelectedPositionSmooth(startPos);
-        waitForScrollIdle(mVerifyLayout);
-
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(endPos, mGridView.getSelectedPosition());
-
-        sendKey(KeyEvent.KEYCODE_DPAD_UP);
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(startPos, mGridView.getSelectedPosition());
-
-    }
-
-    @Test
-    public void testLtrFocusOutStartDisabled() throws Throwable {
-        final int numItems = 200;
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_ltr);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestFocus();
-                mGridView.setSelectedPositionSmooth(0);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-
-        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
-        waitForScrollIdle(mVerifyLayout);
-        assertTrue(mGridView.hasFocus());
-    }
-
-    @Test
-    public void testRtlFocusOutStartDisabled() throws Throwable {
-        final int numItems = 200;
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_grid_rtl);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestFocus();
-                mGridView.setSelectedPositionSmooth(0);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-
-        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
-        waitForScrollIdle(mVerifyLayout);
-        assertTrue(mGridView.hasFocus());
-    }
-
-    @Test
-    public void testTransferFocusable() throws Throwable {
-        final int numItems = 200;
-        final int numColumns = 3;
-        final int startPos = 1;
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = numColumns;
-        boolean[] focusable = new boolean[numItems];
-        for (int i = 0; i < focusable.length; i++) {
-            focusable[i] = true;
-        }
-        for (int i = 0; i < startPos; i++) {
-            focusable[i] = false;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        changeArraySize(0);
-        assertTrue(mGridView.isFocused());
-
-        changeArraySize(numItems);
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
-    }
-
-    @Test
-    public void testTransferFocusable2() throws Throwable {
-        final int numItems = 200;
-        final int numColumns = 3;
-        final int startPos = 3; // make sure view at startPos is in visible area.
-
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, numItems);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = numColumns;
-        boolean[] focusable = new boolean[numItems];
-        for (int i = 0; i < focusable.length; i++) {
-            focusable[i] = true;
-        }
-        for (int i = 0; i < startPos; i++) {
-            focusable[i] = false;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE, focusable);
-        initActivity(intent);
-
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
-
-        changeArraySize(0);
-        assertTrue(mGridView.isFocused());
-
-        changeArraySize(numItems);
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(startPos).hasFocus());
-    }
-
-    @Test
-    public void testNonFocusableLoseInFastLayout() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        int[] items = new int[300];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 480;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-        int pressDown = 15;
-
-        initActivity(intent);
-
-        mGridView.setSelectedPositionSmooth(0);
-        waitForScrollIdle(mVerifyLayout);
-
-        for (int i = 0; i < pressDown; i++) {
-            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        }
-        waitForScrollIdle(mVerifyLayout);
-        assertFalse(mGridView.isFocused());
-
-    }
-
-    @Test
-    public void testFocusableViewAvailable() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_ITEMS_FOCUSABLE,
-                new boolean[]{false, false, true, false, false});
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // RecyclerView does not respect focusable and focusableInTouchMode flag, so
-                // set flags in code.
-                mGridView.setFocusableInTouchMode(false);
-                mGridView.setFocusable(false);
-            }
-        });
-
-        assertFalse(mGridView.isFocused());
-
-        final boolean[] scrolled = new boolean[]{false};
-        mGridView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy){
-                if (dy > 0) {
-                    scrolled[0] = true;
-                }
-            }
-        });
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(0, new int[]{200, 300, 500, 500, 200});
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-
-        assertFalse("GridView should not be scrolled", scrolled[0]);
-        assertTrue(mGridView.getLayoutManager().findViewByPosition(2).hasFocus());
-
-    }
-
-    @Test
-    public void testSetSelectionWithDelta() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 300);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(3);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        int top1 = mGridView.getLayoutManager().findViewByPosition(3).getTop();
-
-        humanDelay(1000);
-
-        // scroll to position with delta
-        setSelectedPosition(3, 100);
-        int top2 = mGridView.getLayoutManager().findViewByPosition(3).getTop();
-        assertEquals(top1 - 100, top2);
-
-        // scroll to same position without delta, it will be reset
-        setSelectedPosition(3, 0);
-        int top3 = mGridView.getLayoutManager().findViewByPosition(3).getTop();
-        assertEquals(top1, top3);
-
-        // scroll invisible item after last visible item
-        final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
-                .mGrid.getLastVisibleIndex();
-        setSelectedPosition(lastVisiblePos + 1, 100);
-        int top4 = mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1).getTop();
-        assertEquals(top1 - 100, top4);
-
-        // scroll invisible item before first visible item
-        final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
-                .mGrid.getFirstVisibleIndex();
-        setSelectedPosition(firstVisiblePos - 1, 100);
-        int top5 = mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1).getTop();
-        assertEquals(top1 - 100, top5);
-
-        // scroll to invisible item that is far away.
-        setSelectedPosition(50, 100);
-        int top6 = mGridView.getLayoutManager().findViewByPosition(50).getTop();
-        assertEquals(top1 - 100, top6);
-
-        // scroll to invisible item that is far away.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(100);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        int top7 = mGridView.getLayoutManager().findViewByPosition(100).getTop();
-        assertEquals(top1, top7);
-
-        // scroll to invisible item that is far away.
-        setSelectedPosition(10, 50);
-        int top8 = mGridView.getLayoutManager().findViewByPosition(10).getTop();
-        assertEquals(top1 - 50, top8);
-    }
-
-    @Test
-    public void testSetSelectionWithDeltaInGrid() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(10);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
-
-        humanDelay(500);
-
-        // scroll to position with delta
-        setSelectedPosition(20, 100);
-        int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
-        assertEquals(top1 - 100, top2);
-
-        // scroll to same position without delta, it will be reset
-        setSelectedPosition(20, 0);
-        int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
-        assertEquals(top1, top3);
-
-        // scroll invisible item after last visible item
-        final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
-                .mGrid.getLastVisibleIndex();
-        setSelectedPosition(lastVisiblePos + 1, 100);
-        int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1));
-        verifyMargin();
-        assertEquals(top1 - 100, top4);
-
-        // scroll invisible item before first visible item
-        final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
-                .mGrid.getFirstVisibleIndex();
-        setSelectedPosition(firstVisiblePos - 1, 100);
-        int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1));
-        assertEquals(top1 - 100, top5);
-
-        // scroll to invisible item that is far away.
-        setSelectedPosition(100, 100);
-        int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100));
-        assertEquals(top1 - 100, top6);
-
-        // scroll to invisible item that is far away.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(200);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        Thread.sleep(500);
-        int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200));
-        assertEquals(top1, top7);
-
-        // scroll to invisible item that is far away.
-        setSelectedPosition(10, 50);
-        int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
-        assertEquals(top1 - 50, top8);
-    }
-
-
-    @Test
-    public void testSetSelectionWithDeltaInGrid1() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{
-                193,176,153,141,203,184,232,139,177,206,222,136,132,237,172,137,
-                188,172,163,213,158,219,209,147,133,229,170,197,138,215,188,205,
-                223,192,225,170,195,127,229,229,210,195,134,142,160,139,130,222,
-                150,163,180,176,157,137,234,169,159,167,182,150,224,231,202,236,
-                123,140,181,223,120,185,183,221,123,210,134,158,166,208,149,128,
-                192,214,212,198,133,140,158,133,229,173,226,141,180,128,127,218,
-                192,235,183,213,216,150,143,193,125,141,219,210,195,195,192,191,
-                212,236,157,189,160,220,147,158,220,199,233,231,201,180,168,141,
-                156,204,191,183,190,153,123,210,238,151,139,221,223,200,175,191,
-                132,184,197,204,236,157,230,151,195,219,212,143,172,149,219,184,
-                164,211,132,187,172,142,174,146,127,147,206,238,188,129,199,226,
-                132,220,210,159,235,153,208,182,196,123,180,159,131,135,175,226,
-                127,134,237,211,133,225,132,124,160,226,224,200,173,137,217,169,
-                182,183,176,185,122,168,195,159,172,129,126,129,166,136,149,220,
-                178,191,192,238,180,208,234,154,222,206,239,228,129,140,203,125,
-                214,175,125,169,196,132,234,138,192,142,234,190,215,232,239,122,
-                188,158,128,221,159,237,207,157,232,138,132,214,122,199,121,191,
-                199,209,126,164,175,187,173,186,194,224,191,196,146,208,213,210,
-                164,176,202,213,123,157,179,138,217,129,186,166,237,211,157,130,
-                137,132,171,232,216,239,180,151,137,132,190,133,218,155,171,227,
-                193,147,197,164,120,218,193,154,170,196,138,222,161,235,143,154,
-                192,178,228,195,178,133,203,178,173,206,178,212,136,157,169,124,
-                172,121,128,223,238,125,217,187,184,156,169,215,231,124,210,174,
-                146,226,185,134,223,228,183,182,136,133,199,146,180,233,226,225,
-                174,233,145,235,216,170,192,171,132,132,134,223,233,148,154,162,
-                192,179,197,203,139,197,174,187,135,132,180,136,192,195,124,221,
-                120,189,233,233,146,225,234,163,215,143,132,198,156,205,151,190,
-                204,239,221,229,123,138,134,217,219,136,218,215,167,139,195,125,
-                202,225,178,226,145,208,130,194,228,197,157,215,124,147,174,123,
-                237,140,172,181,161,151,229,216,199,199,179,213,146,122,222,162,
-                139,173,165,150,160,217,207,137,165,175,129,158,134,133,178,199,
-                215,213,122,197
-        });
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, true);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(10);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        int top1 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
-
-        humanDelay(500);
-
-        // scroll to position with delta
-        setSelectedPosition(20, 100);
-        int top2 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
-        assertEquals(top1 - 100, top2);
-
-        // scroll to same position without delta, it will be reset
-        setSelectedPosition(20, 0);
-        int top3 = getCenterY(mGridView.getLayoutManager().findViewByPosition(20));
-        assertEquals(top1, top3);
-
-        // scroll invisible item after last visible item
-        final int lastVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
-                .mGrid.getLastVisibleIndex();
-        setSelectedPosition(lastVisiblePos + 1, 100);
-        int top4 = getCenterY(mGridView.getLayoutManager().findViewByPosition(lastVisiblePos + 1));
-        verifyMargin();
-        assertEquals(top1 - 100, top4);
-
-        // scroll invisible item before first visible item
-        final int firstVisiblePos = ((GridLayoutManager)mGridView.getLayoutManager())
-                .mGrid.getFirstVisibleIndex();
-        setSelectedPosition(firstVisiblePos - 1, 100);
-        int top5 = getCenterY(mGridView.getLayoutManager().findViewByPosition(firstVisiblePos - 1));
-        assertEquals(top1 - 100, top5);
-
-        // scroll to invisible item that is far away.
-        setSelectedPosition(100, 100);
-        int top6 = getCenterY(mGridView.getLayoutManager().findViewByPosition(100));
-        assertEquals(top1 - 100, top6);
-
-        // scroll to invisible item that is far away.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(200);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        Thread.sleep(500);
-        int top7 = getCenterY(mGridView.getLayoutManager().findViewByPosition(200));
-        assertEquals(top1, top7);
-
-        // scroll to invisible item that is far away.
-        setSelectedPosition(10, 50);
-        int top8 = getCenterY(mGridView.getLayoutManager().findViewByPosition(10));
-        assertEquals(top1 - 50, top8);
-    }
-
-    @Test
-    public void testSmoothScrollSelectionEvents() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(30);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        humanDelay(500);
-
-        final ArrayList<Integer> selectedPositions = new ArrayList<Integer>();
-        mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
-            @Override
-            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
-                selectedPositions.add(position);
-            }
-        });
-
-        sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP);
-        humanDelay(500);
-        waitForScrollIdle(mVerifyLayout);
-        // should only get childselected event for item 0 once
-        assertTrue(selectedPositions.size() > 0);
-        assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue());
-        for (int i = selectedPositions.size() - 2; i >= 0; i--) {
-            assertFalse(0 == selectedPositions.get(i).intValue());
-        }
-
-    }
-
-    @Test
-    public void testSmoothScrollSelectionEventsLinear() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 500);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(10);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        humanDelay(500);
-
-        final ArrayList<Integer> selectedPositions = new ArrayList<Integer>();
-        mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
-            @Override
-            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
-                selectedPositions.add(position);
-            }
-        });
-
-        sendRepeatedKeys(10, KeyEvent.KEYCODE_DPAD_UP);
-        humanDelay(500);
-        waitForScrollIdle(mVerifyLayout);
-        // should only get childselected event for item 0 once
-        assertTrue(selectedPositions.size() > 0);
-        assertEquals(0, selectedPositions.get(selectedPositions.size() - 1).intValue());
-        for (int i = selectedPositions.size() - 2; i >= 0; i--) {
-            assertFalse(0 == selectedPositions.get(i).intValue());
-        }
-
-    }
-
-    @Test
-    public void testScrollToNoneExisting() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 3;
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(99);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        humanDelay(500);
-
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(50);
-            }
-        });
-        Thread.sleep(100);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestLayout();
-                mGridView.setSelectedPositionSmooth(0);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        humanDelay(500);
-
-    }
-
-    @Test
-    public void testSmoothscrollerInterrupted() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 680;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mGridView.setSelectedPositionSmooth(0);
-        waitForScrollIdle(mVerifyLayout);
-        assertTrue(mGridView.getChildAt(0).hasFocus());
-
-        // Pressing lots of key to make sure smooth scroller is running
-        for (int i = 0; i < 20; i++) {
-            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        }
-        while (mGridView.getLayoutManager().isSmoothScrolling()
-                || mGridView.getScrollState() != BaseGridView.SCROLL_STATE_IDLE) {
-            // Repeatedly pressing to make sure pending keys does not drop to zero.
-            sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        }
-    }
-
-    @Test
-    public void testSmoothscrollerCancelled() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 680;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mGridView.setSelectedPositionSmooth(0);
-        waitForScrollIdle(mVerifyLayout);
-        assertTrue(mGridView.getChildAt(0).hasFocus());
-
-        int targetPosition = items.length - 1;
-        mGridView.setSelectedPositionSmooth(targetPosition);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.stopScroll();
-            }
-        });
-        waitForScrollIdle();
-        waitForItemAnimation();
-        assertEquals(mGridView.getSelectedPosition(), targetPosition);
-        assertSame(mGridView.getLayoutManager().findViewByPosition(targetPosition),
-                mGridView.findFocus());
-    }
-
-    @Test
-    public void testSetNumRowsAndAddItem() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[2];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mGridView.setSelectedPositionSmooth(0);
-        waitForScrollIdle(mVerifyLayout);
-
-        mActivity.addItems(items.length, new int[]{300});
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ((VerticalGridView) mGridView).setNumColumns(2);
-            }
-        });
-        Thread.sleep(1000);
-        assertTrue(mGridView.getChildAt(2).getLeft() != mGridView.getChildAt(1).getLeft());
-    }
-
-
-    @Test
-    public void testRequestLayoutBugInLayout() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(1);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-
-        sendKey(KeyEvent.KEYCODE_DPAD_UP);
-        waitForScrollIdle(mVerifyLayout);
-
-        assertEquals("Line 2", ((TextView) mGridView.findFocus()).getText().toString());
-    }
-
-
-    @Test
-    public void testChangeLayoutInChild() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_wrap_content);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
-        int[] items = new int[2];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(0);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        verifyMargin();
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(1);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        verifyMargin();
-    }
-
-    @Test
-    public void testWrapContent() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_grid_wrap);
-        int[] items = new int[200];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.attachToNewAdapter(new int[0]);
-            }
-        });
-
-    }
-
-    @Test
-    public void testZeroFixedSecondarySize() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_measured_with_zero);
-        intent.putExtra(GridActivity.EXTRA_SECONDARY_SIZE_ZERO, true);
-        int[] items = new int[2];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 0;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-    }
-
-    @Test
-    public void testChildStates() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 200;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-        mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD);
-
-        final SparseArray<Parcelable> container = new SparseArray<Parcelable>();
-
-        // 1 Save view states
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
-                        .getText()), 0, 1);
-                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1))
-                        .getText()), 0, 1);
-                mGridView.saveHierarchyState(container);
-            }
-        });
-
-        // 2 Change view states
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(0))
-                        .getText()), 1, 2);
-                Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(1))
-                        .getText()), 1, 2);
-            }
-        });
-
-        // 3 Detached and re-attached,  should still maintain state of (2)
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(1);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
-        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
-        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
-        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2);
-
-        // 4 Recycled and rebound, should load state from (2)
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(20);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPositionSmooth(0);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionStart(), 1);
-        assertEquals(((TextView) mGridView.getChildAt(0)).getSelectionEnd(), 2);
-        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionStart(), 1);
-        assertEquals(((TextView) mGridView.getChildAt(1)).getSelectionEnd(), 2);
-    }
-
-
-    @Test
-    public void testNoDispatchSaveChildState() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 200;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-        mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_NO_CHILD);
-
-        final SparseArray<Parcelable> container = new SparseArray<Parcelable>();
-
-        // 1. Set text selection, save view states should do nothing on child
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mGridView.getChildCount(); i++) {
-                    Selection.setSelection((Spannable)(((TextView) mGridView.getChildAt(i))
-                            .getText()), 0, 1);
-                }
-                mGridView.saveHierarchyState(container);
-            }
-        });
-
-        // 2. clear the text selection
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mGridView.getChildCount(); i++) {
-                    Selection.removeSelection((Spannable)(((TextView) mGridView.getChildAt(i))
-                            .getText()));
-                }
-            }
-        });
-
-        // 3. Restore view states should be a no-op for child
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.restoreHierarchyState(container);
-                for (int i = 0; i < mGridView.getChildCount(); i++) {
-                    assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionStart());
-                    assertEquals(-1, ((TextView) mGridView.getChildAt(i)).getSelectionEnd());
-                }
-            }
-        });
-    }
-
-
-    static interface ViewTypeProvider {
-        public int getViewType(int position);
-    }
-
-    static interface ItemAlignmentFacetProvider {
-        public ItemAlignmentFacet getItemAlignmentFacet(int viewType);
-    }
-
-    static class TwoViewTypesProvider implements ViewTypeProvider {
-        static int VIEW_TYPE_FIRST = 1;
-        static int VIEW_TYPE_DEFAULT = 0;
-        @Override
-        public int getViewType(int position) {
-            if (position == 0) {
-                return VIEW_TYPE_FIRST;
-            } else {
-                return VIEW_TYPE_DEFAULT;
-            }
-        }
-    }
-
-    static class ChangeableViewTypesProvider implements ViewTypeProvider {
-        static SparseIntArray sViewTypes = new SparseIntArray();
-        @Override
-        public int getViewType(int position) {
-            return sViewTypes.get(position);
-        }
-        public static void clear() {
-            sViewTypes.clear();
-        }
-        public static void setViewType(int position, int type) {
-            sViewTypes.put(position, type);
-        }
-    }
-
-    static class PositionItemAlignmentFacetProviderForRelativeLayout1
-            implements ItemAlignmentFacetProvider {
-        ItemAlignmentFacet mMultipleFacet;
-
-        PositionItemAlignmentFacetProviderForRelativeLayout1() {
-            mMultipleFacet = new ItemAlignmentFacet();
-            ItemAlignmentFacet.ItemAlignmentDef[] defs =
-                    new ItemAlignmentFacet.ItemAlignmentDef[2];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t1);
-            defs[1] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[1].setItemAlignmentViewId(R.id.t2);
-            defs[1].setItemAlignmentOffsetPercent(100);
-            defs[1].setItemAlignmentOffset(-10);
-            mMultipleFacet.setAlignmentDefs(defs);
-        }
-
-        @Override
-        public ItemAlignmentFacet getItemAlignmentFacet(int position) {
-            if (position == 0) {
-                return mMultipleFacet;
-            } else {
-                return null;
-            }
-        }
-    }
-
-    @Test
-    public void testMultipleScrollPosition1() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
-                TwoViewTypesProvider.class.getName());
-        // Set ItemAlignment for each ViewHolder and view type,  ViewHolder should
-        // override the view type settings.
-        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
-                PositionItemAlignmentFacetProviderForRelativeLayout1.class.getName());
-        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS,
-                ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName());
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top",
-                mGridView.getPaddingTop(), mGridView.getChildAt(0).getTop());
-
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        waitForScrollIdle(mVerifyLayout);
-
-        final View v = mGridView.getChildAt(0);
-        View t1 = v.findViewById(R.id.t1);
-        int t1align = (t1.getTop() + t1.getBottom()) / 2;
-        View t2 = v.findViewById(R.id.t2);
-        int t2align = t2.getBottom() - 10;
-        assertEquals("Expected alignment for 2nd textview",
-                mGridView.getPaddingTop() - (t2align - t1align),
-                v.getTop());
-    }
-
-    static class PositionItemAlignmentFacetProviderForRelativeLayout2 implements
-            ItemAlignmentFacetProvider {
-        ItemAlignmentFacet mMultipleFacet;
-
-        PositionItemAlignmentFacetProviderForRelativeLayout2() {
-            mMultipleFacet = new ItemAlignmentFacet();
-            ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t1);
-            defs[0].setItemAlignmentOffsetPercent(0);
-            defs[1] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[1].setItemAlignmentViewId(R.id.t2);
-            defs[1].setItemAlignmentOffsetPercent(ItemAlignmentFacet.ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
-            defs[1].setItemAlignmentOffset(-10);
-            mMultipleFacet.setAlignmentDefs(defs);
-        }
-
-        @Override
-        public ItemAlignmentFacet getItemAlignmentFacet(int position) {
-            if (position == 0) {
-                return mMultipleFacet;
-            } else {
-                return null;
-            }
-        }
-    }
-
-    @Test
-    public void testMultipleScrollPosition2() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
-                TwoViewTypesProvider.class.getName());
-        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
-                PositionItemAlignmentFacetProviderForRelativeLayout2.class.getName());
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        waitForScrollIdle(mVerifyLayout);
-
-        final View v = mGridView.getChildAt(0);
-        View t1 = v.findViewById(R.id.t1);
-        int t1align = t1.getTop();
-        View t2 = v.findViewById(R.id.t2);
-        int t2align = t2.getTop() - 10;
-        assertEquals("Expected alignment for 2nd textview",
-                mGridView.getPaddingTop() - (t2align - t1align), v.getTop());
-    }
-
-    static class ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2 implements
-            ItemAlignmentFacetProvider {
-        ItemAlignmentFacet mMultipleFacet;
-
-        ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2() {
-            mMultipleFacet = new ItemAlignmentFacet();
-            ItemAlignmentFacet.ItemAlignmentDef[] defs = new ItemAlignmentFacet.ItemAlignmentDef[2];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t1);
-            defs[0].setItemAlignmentOffsetPercent(0);
-            defs[1] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[1].setItemAlignmentViewId(R.id.t2);
-            defs[1].setItemAlignmentOffsetPercent(100);
-            defs[1].setItemAlignmentOffset(-10);
-            mMultipleFacet.setAlignmentDefs(defs);
-        }
-
-        @Override
-        public ItemAlignmentFacet getItemAlignmentFacet(int viewType) {
-            if (viewType == TwoViewTypesProvider.VIEW_TYPE_FIRST) {
-                return mMultipleFacet;
-            } else {
-                return null;
-            }
-        }
-    }
-
-    @Test
-    public void testMultipleScrollPosition3() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
-                TwoViewTypesProvider.class.getName());
-        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_VIEWTYPE_CLASS,
-                ViewTypePositionItemAlignmentFacetProviderForRelativeLayout2.class.getName());
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        waitForScrollIdle(mVerifyLayout);
-
-        final View v = mGridView.getChildAt(0);
-        View t1 = v.findViewById(R.id.t1);
-        int t1align = t1.getTop();
-        View t2 = v.findViewById(R.id.t2);
-        int t2align = t2.getBottom() - 10;
-        assertEquals("Expected alignment for 2nd textview",
-                mGridView.getPaddingTop() - (t2align - t1align), v.getTop());
-    }
-
-    @Test
-    public void testSelectionAndAddItemInOneCycle() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(0, new int[]{300, 300});
-                mGridView.setSelectedPosition(0);
-            }
-        });
-        assertEquals(0, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testSelectViewTaskSmoothWithAdapterChange() throws Throwable {
-        testSelectViewTaskWithAdapterChange(true /*smooth*/);
-    }
-
-    @Test
-    public void testSelectViewTaskWithAdapterChange() throws Throwable {
-        testSelectViewTaskWithAdapterChange(false /*smooth*/);
-    }
-
-    private void testSelectViewTaskWithAdapterChange(final boolean smooth) throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final View firstView = mGridView.getLayoutManager().findViewByPosition(0);
-        final View[] selectedViewByTask = new View[1];
-        final ViewHolderTask task = new ViewHolderTask() {
-            @Override
-            public void run(RecyclerView.ViewHolder viewHolder) {
-                selectedViewByTask[0] = viewHolder.itemView;
-            }
-        };
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(0, 1);
-                if (smooth) {
-                    mGridView.setSelectedPositionSmooth(0, task);
-                } else {
-                    mGridView.setSelectedPosition(0, task);
-                }
-            }
-        });
-        assertEquals(0, mGridView.getSelectedPosition());
-        assertNotNull(selectedViewByTask[0]);
-        assertNotSame(firstView, selectedViewByTask[0]);
-        assertSame(mGridView.getLayoutManager().findViewByPosition(0), selectedViewByTask[0]);
-    }
-
-    @Test
-    public void testNotifyItemTypeChangedSelectionEvent() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
-        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
-                ChangeableViewTypesProvider.class.getName());
-        ChangeableViewTypesProvider.clear();
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final ArrayList<Integer> selectedLog = new ArrayList<Integer>();
-        mGridView.setOnChildSelectedListener(new OnChildSelectedListener() {
-            @Override
-            public void onChildSelected(ViewGroup parent, View view, int position, long id) {
-                selectedLog.add(position);
-            }
-        });
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                ChangeableViewTypesProvider.setViewType(0, 1);
-                mGridView.getAdapter().notifyItemChanged(0, 1);
-            }
-        });
-        assertEquals(0, mGridView.getSelectedPosition());
-        assertEquals(selectedLog.size(), 1);
-        assertEquals((int) selectedLog.get(0), 0);
-    }
-
-    @Test
-    public void testNotifyItemChangedSelectionEvent() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        OnChildViewHolderSelectedListener listener =
-                Mockito.mock(OnChildViewHolderSelectedListener.class);
-        mGridView.setOnChildViewHolderSelectedListener(listener);
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getAdapter().notifyItemChanged(0, 1);
-            }
-        });
-        Mockito.verify(listener, times(1)).onChildViewHolderSelected(any(RecyclerView.class),
-                any(RecyclerView.ViewHolder.class), anyInt(), anyInt());
-        assertEquals(0, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testSelectionSmoothAndAddItemInOneCycle() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 0);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.addItems(0, new int[]{300, 300});
-                mGridView.setSelectedPositionSmooth(0);
-            }
-        });
-        assertEquals(0, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testExtraLayoutSpace() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        initActivity(intent);
-
-        final int windowSize = mGridView.getHeight();
-        final int extraLayoutSize = windowSize;
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        // add extra layout space
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setExtraLayoutSpace(extraLayoutSize);
-            }
-        });
-        waitForLayout();
-        View v;
-        v = mGridView.getChildAt(mGridView.getChildCount() - 1);
-        assertTrue(v.getTop() < windowSize + extraLayoutSize);
-        assertTrue(v.getBottom() >= windowSize + extraLayoutSize - mGridView.getVerticalMargin());
-
-        mGridView.setSelectedPositionSmooth(150);
-        waitForScrollIdle(mVerifyLayout);
-        v = mGridView.getChildAt(0);
-        assertTrue(v.getBottom() > - extraLayoutSize);
-        assertTrue(v.getTop() <= -extraLayoutSize + mGridView.getVerticalMargin());
-
-        // clear extra layout space
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setExtraLayoutSpace(0);
-                verifyMargin();
-            }
-        });
-        Thread.sleep(50);
-        v = mGridView.getChildAt(mGridView.getChildCount() - 1);
-        assertTrue(v.getTop() < windowSize);
-        assertTrue(v.getBottom() >= windowSize - mGridView.getVerticalMargin());
-    }
-
-    @Test
-    public void testFocusFinder() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 3);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        // test focus from button to vertical grid view
-        final View button = mActivity.findViewById(R.id.button);
-        assertTrue(button.isFocused());
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        assertFalse(mGridView.isFocused());
-        assertTrue(mGridView.hasFocus());
-
-        // FocusFinder should find last focused(2nd) item on DPAD_DOWN
-        final View secondChild = mGridView.getChildAt(1);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                secondChild.requestFocus();
-                button.requestFocus();
-            }
-        });
-        assertTrue(button.isFocused());
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        assertTrue(secondChild.isFocused());
-
-        // Bug 26918143 Even VerticalGridView is not focusable, FocusFinder should find last focused
-        // (2nd) item on DPAD_DOWN.
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                button.requestFocus();
-            }
-        });
-        mGridView.setFocusable(false);
-        mGridView.setFocusableInTouchMode(false);
-        assertTrue(button.isFocused());
-        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
-        assertTrue(secondChild.isFocused());
-    }
-
-    @Test
-    public void testRestoreIndexAndAddItems() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 4);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        assertEquals(mGridView.getSelectedPosition(), 0);
-        final SparseArray<Parcelable> states = new SparseArray<>();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.saveHierarchyState(states);
-                mGridView.setAdapter(null);
-            }
-
-        });
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.restoreHierarchyState(states);
-                mActivity.attachToNewAdapter(new int[0]);
-                mActivity.addItems(0, new int[]{100, 100, 100, 100});
-            }
-
-        });
-        assertEquals(mGridView.getSelectedPosition(), 0);
-    }
-
-    @Test
-    public void testRestoreIndexAndAddItemsSelect1() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 4);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPosition(1);
-            }
-
-        });
-        assertEquals(mGridView.getSelectedPosition(), 1);
-        final SparseArray<Parcelable> states = new SparseArray<>();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.saveHierarchyState(states);
-                mGridView.setAdapter(null);
-            }
-
-        });
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.restoreHierarchyState(states);
-                mActivity.attachToNewAdapter(new int[0]);
-                mActivity.addItems(0, new int[]{100, 100, 100, 100});
-            }
-
-        });
-        assertEquals(mGridView.getSelectedPosition(), 1);
-    }
-
-    @Test
-    public void testRestoreStateAfterAdapterChange() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.selectable_text_view);
-        intent.putExtra(GridActivity.EXTRA_ITEMS, new int[]{50, 50, 50, 50});
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setSelectedPosition(1);
-                mGridView.setSaveChildrenPolicy(VerticalGridView.SAVE_ALL_CHILD);
-            }
-
-        });
-        assertEquals(mGridView.getSelectedPosition(), 1);
-        final SparseArray<Parcelable> states = new SparseArray<>();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Selection.setSelection((Spannable) (((TextView) mGridView.getChildAt(0))
-                        .getText()), 1, 2);
-                Selection.setSelection((Spannable) (((TextView) mGridView.getChildAt(1))
-                        .getText()), 0, 1);
-                mGridView.saveHierarchyState(states);
-                mGridView.setAdapter(null);
-            }
-
-        });
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.restoreHierarchyState(states);
-                mActivity.attachToNewAdapter(new int[]{50, 50, 50, 50});
-            }
-
-        });
-        assertEquals(mGridView.getSelectedPosition(), 1);
-        assertEquals(1, ((TextView) mGridView.getChildAt(0)).getSelectionStart());
-        assertEquals(2, ((TextView) mGridView.getChildAt(0)).getSelectionEnd());
-        assertEquals(0, ((TextView) mGridView.getChildAt(1)).getSelectionStart());
-        assertEquals(1, ((TextView) mGridView.getChildAt(1)).getSelectionEnd());
-    }
-
-    @Test
-    public void test27766012() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 2);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        // set remove animator two seconds
-        mGridView.getItemAnimator().setRemoveDuration(2000);
-        final View view = mGridView.getChildAt(1);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestFocus();
-            }
-        });
-        assertTrue(view.hasFocus());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(0, 2);
-            }
-
-        });
-        // wait one second, removing second view is still attached to parent
-        Thread.sleep(1000);
-        assertSame(view.getParent(), mGridView);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // refocus to the removed item and do a focus search.
-                view.requestFocus();
-                view.focusSearch(View.FOCUS_UP);
-            }
-
-        });
-    }
-
-    @Test
-    public void testBug27258366() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.horizontal_item);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        // move item1 500 pixels right, when focus is on item1, default focus finder will pick
-        // item0 and item2 for the best match of focusSearch(FOCUS_LEFT).  The grid widget
-        // must override default addFocusables(), not to add item0 or item2.
-        mActivity.mAdapterListener = new GridActivity.AdapterListener() {
-            @Override
-            public void onBind(RecyclerView.ViewHolder vh, int position) {
-                if (position == 1) {
-                    vh.itemView.setPaddingRelative(500, 0, 0, 0);
-                } else {
-                    vh.itemView.setPaddingRelative(0, 0, 0, 0);
-                }
-            }
-        };
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getAdapter().notifyDataSetChanged();
-            }
-        });
-        Thread.sleep(100);
-
-        final ViewGroup secondChild = (ViewGroup) mGridView.getChildAt(1);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                secondChild.requestFocus();
-            }
-        });
-        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
-        Thread.sleep(100);
-        final View button = mActivity.findViewById(R.id.button);
-        assertTrue(button.isFocused());
-    }
-
-    @Test
-    public void testUpdateHeightScrollHorizontal() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, false);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, true);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int childTop = mGridView.getChildAt(0).getTop();
-        // scroll to end, all children's top should not change.
-        scrollToEnd(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mGridView.getChildCount(); i++) {
-                    assertEquals(childTop, mGridView.getChildAt(i).getTop());
-                }
-            }
-        });
-        // sanity check last child has focus with a larger height.
-        assertTrue(mGridView.getChildAt(0).getHeight()
-                < mGridView.getChildAt(mGridView.getChildCount() - 1).getHeight());
-    }
-
-    @Test
-    public void testUpdateWidthScrollHorizontal() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, true);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int childTop = mGridView.getChildAt(0).getTop();
-        // scroll to end, all children's top should not change.
-        scrollToEnd(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mGridView.getChildCount(); i++) {
-                    assertEquals(childTop, mGridView.getChildAt(i).getTop());
-                }
-            }
-        });
-        // sanity check last child has focus with a larger width.
-        assertTrue(mGridView.getChildAt(0).getWidth()
-                < mGridView.getChildAt(mGridView.getChildCount() - 1).getWidth());
-        if (mGridView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
-            assertEquals(mGridView.getPaddingLeft(),
-                    mGridView.getChildAt(mGridView.getChildCount() - 1).getLeft());
-        } else {
-            assertEquals(mGridView.getWidth() - mGridView.getPaddingRight(),
-                    mGridView.getChildAt(mGridView.getChildCount() - 1).getRight());
-        }
-    }
-
-    @Test
-    public void testUpdateWidthScrollHorizontalRtl() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear_rtl);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 30);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_LAYOUT_ONFOCUS, true);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE, true);
-        intent.putExtra(GridActivity.EXTRA_UPDATE_SIZE_SECONDARY, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        final int childTop = mGridView.getChildAt(0).getTop();
-        // scroll to end, all children's top should not change.
-        scrollToEnd(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mGridView.getChildCount(); i++) {
-                    assertEquals(childTop, mGridView.getChildAt(i).getTop());
-                }
-            }
-        });
-        // sanity check last child has focus with a larger width.
-        assertTrue(mGridView.getChildAt(0).getWidth()
-                < mGridView.getChildAt(mGridView.getChildCount() - 1).getWidth());
-        assertEquals(mGridView.getPaddingLeft(),
-                mGridView.getChildAt(mGridView.getChildCount() - 1).getLeft());
-    }
-
-    @Test
-    public void testAccessibility() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 1000);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        assertTrue(0 == mGridView.getSelectedPosition());
-
-        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
-                .getCompatAccessibilityDelegate();
-        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
-            }
-        });
-        assertTrue("test sanity", info.isScrollable());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.performAccessibilityAction(mGridView,
-                        AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        int selectedPosition1 = mGridView.getSelectedPosition();
-        assertTrue(0 < selectedPosition1);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
-            }
-        });
-        assertTrue("test sanity", info.isScrollable());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.performAccessibilityAction(mGridView,
-                        AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        int selectedPosition2 = mGridView.getSelectedPosition();
-        assertTrue(selectedPosition2 < selectedPosition1);
-    }
-
-    @Test
-    public void testAccessibilityScrollForwardHalfVisible() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom);
-        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        int height = mGridView.getHeight() - mGridView.getPaddingTop()
-                - mGridView.getPaddingBottom();
-        final int childHeight = height - mGridView.getVerticalSpacing() - 100;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffset(100);
-                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
-                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-                mGridView.setItemAlignmentOffset(0);
-                mGridView.setItemAlignmentOffsetPercent(BaseGridView
-                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
-            }
-        });
-        mActivity.addItems(0, new int[]{childHeight, childHeight});
-        waitForItemAnimation();
-        setSelectedPosition(0);
-
-        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
-                .getCompatAccessibilityDelegate();
-        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
-            }
-        });
-        assertTrue("test sanity", info.isScrollable());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.performAccessibilityAction(mGridView,
-                        AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD, null);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(1, mGridView.getSelectedPosition());
-    }
-
-    private boolean hasAction(AccessibilityNodeInfoCompat info, Object action) {
-        if (Build.VERSION.SDK_INT >= 21) {
-            AccessibilityNodeInfoCompat.AccessibilityActionCompat convertedAction =
-                    (AccessibilityNodeInfoCompat.AccessibilityActionCompat) action;
-            return ((info.getActions() & convertedAction.getId()) != 0);
-        } else {
-            int convertedAction = (int) action;
-            return ((info.getActions() & convertedAction) != 0);
-        }
-    }
-
-    private void setUpActivityForScrollingTest(final boolean isRTL, boolean isHorizontal,
-            int numChildViews, boolean isSiblingViewVisible) throws Throwable {
-        Intent intent = new Intent();
-        int layout;
-        if (isHorizontal) {
-            layout = isRTL ? R.layout.horizontal_linear_rtl : R.layout.horizontal_linear;
-        } else {
-            layout = R.layout.vertical_linear;
-        }
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, layout);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_bottom);
-        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        initActivity(intent);
-        mOrientation = isHorizontal ? BaseGridView.HORIZONTAL : BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        final int offset = (isSiblingViewVisible ? 2 : 1) * (isHorizontal
-                ? mGridView.getHorizontalSpacing() : mGridView.getVerticalSpacing());
-        final int childSize = (isHorizontal ? mGridView.getWidth() : mGridView.getHeight())
-                - offset - (isHorizontal ? 2 * mGridView.getHorizontalSpacing() :
-                mGridView.getVerticalSpacing());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (isRTL) {
-                    mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
-                }
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffset(offset);
-                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
-                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-                mGridView.setItemAlignmentOffset(0);
-                mGridView.setItemAlignmentOffsetPercent(BaseGridView
-                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
-            }
-        });
-        int[] widthArrays = new int[numChildViews];
-        Arrays.fill(widthArrays, childSize);
-        mActivity.addItems(0, widthArrays);
-    }
-
-    private void testScrollingAction(boolean isRTL, boolean isHorizontal) throws Throwable {
-        waitForItemAnimation();
-        setSelectedPosition(1);
-        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
-                .getCompatAccessibilityDelegate();
-        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
-            }
-        });
-        // We are currently focusing on item 1, calculating the direction to get me to item 0
-        final AccessibilityNodeInfoCompat.AccessibilityActionCompat itemZeroDirection;
-        if (isHorizontal) {
-            itemZeroDirection = isRTL
-                    ? AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT :
-                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT;
-        } else {
-            itemZeroDirection =
-                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_UP;
-        }
-        final int translatedItemZeroDirection = AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD;
-
-        assertTrue("test sanity", info.isScrollable());
-        if (Build.VERSION.SDK_INT >= 23) {
-            assertTrue("test sanity", hasAction(info, itemZeroDirection));
-        } else {
-            assertTrue("test sanity", hasAction(info, translatedItemZeroDirection));
-        }
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (Build.VERSION.SDK_INT >= 23) {
-                    delegateCompat.performAccessibilityAction(mGridView, itemZeroDirection.getId(),
-                            null);
-                } else {
-                    delegateCompat.performAccessibilityAction(mGridView,
-                            translatedItemZeroDirection, null);
-                }
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(0, mGridView.getSelectedPosition());
-        setSelectedPosition(0);
-        // We are at item 0, calculate the direction that lead us to the item 1
-        final AccessibilityNodeInfoCompat.AccessibilityActionCompat itemOneDirection;
-        if (isHorizontal) {
-            itemOneDirection = isRTL
-                    ? AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_LEFT
-                    : AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_RIGHT;
-        } else {
-            itemOneDirection =
-                    AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_SCROLL_DOWN;
-        }
-        final int translatedItemOneDirection = AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD;
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
-            }
-        });
-        if (Build.VERSION.SDK_INT >= 23) {
-            assertTrue("test sanity", hasAction(info, itemOneDirection));
-        } else {
-            assertTrue("test sanity", hasAction(info, translatedItemOneDirection));
-        }
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (Build.VERSION.SDK_INT >= 23) {
-                    delegateCompat.performAccessibilityAction(mGridView, itemOneDirection.getId(),
-                            null);
-                } else {
-                    delegateCompat.performAccessibilityAction(mGridView, translatedItemOneDirection,
-                            null);
-                }
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(1, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testAccessibilityRespondToLeftRightInvisible() throws Throwable {
-        boolean isRTL = false;
-        boolean isHorizontal = true;
-        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
-                false /* next child partially visible */);
-        testScrollingAction(isRTL, isHorizontal);
-    }
-
-    @Test
-    public void testAccessibilityRespondToLeftRightPartiallyVisible() throws Throwable {
-        boolean isRTL = false;
-        boolean isHorizontal = true;
-        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
-                true /* next child partially visible */);
-        testScrollingAction(isRTL, isHorizontal);
-    }
-
-    @Test
-    public void testAccessibilityRespondToLeftRightRtlInvisible()
-            throws Throwable {
-        boolean isRTL = true;
-        boolean isHorizontal = true;
-        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
-                false /* next child partially visible */);
-        testScrollingAction(isRTL, isHorizontal);
-    }
-
-    @Test
-    public void testAccessibilityRespondToLeftRightRtlPartiallyVisible() throws Throwable {
-        boolean isRTL = true;
-        boolean isHorizontal = true;
-        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
-                true /* next child partially visible */);
-        testScrollingAction(isRTL, isHorizontal);
-    }
-
-    @Test
-    public void testAccessibilityRespondToScrollUpDownActionInvisible() throws Throwable {
-        boolean isRTL = false;
-        boolean isHorizontal = false;
-        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
-                false /* next child partially visible */);
-        testScrollingAction(isRTL, isHorizontal);
-    }
-
-    @Test
-    public void testAccessibilityRespondToScrollUpDownActionPartiallyVisible() throws Throwable {
-        boolean isRTL = false;
-        boolean isHorizontal = false;
-        setUpActivityForScrollingTest(isRTL, isHorizontal, 2 /* numChild */,
-                true /* next child partially visible */);
-        testScrollingAction(isRTL, isHorizontal);
-    }
-
-    @Test
-    public void testAccessibilityScrollBackwardHalfVisible() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.item_button_at_top);
-        intent.putExtra(GridActivity.EXTRA_ITEMS,  new int[]{});
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        initActivity(intent);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        int height = mGridView.getHeight() - mGridView.getPaddingTop()
-                - mGridView.getPaddingBottom();
-        final int childHeight = height - mGridView.getVerticalSpacing() - 100;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffset(100);
-                mGridView.setWindowAlignmentOffsetPercent(BaseGridView
-                        .WINDOW_ALIGN_OFFSET_PERCENT_DISABLED);
-                mGridView.setItemAlignmentOffset(0);
-                mGridView.setItemAlignmentOffsetPercent(BaseGridView
-                        .ITEM_ALIGN_OFFSET_PERCENT_DISABLED);
-            }
-        });
-        mActivity.addItems(0, new int[]{childHeight, childHeight});
-        waitForItemAnimation();
-        setSelectedPosition(1);
-
-        final RecyclerViewAccessibilityDelegate delegateCompat = mGridView
-                .getCompatAccessibilityDelegate();
-        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityNodeInfo(mGridView, info);
-            }
-        });
-        assertTrue("test sanity", info.isScrollable());
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.performAccessibilityAction(mGridView,
-                        AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD, null);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertEquals(0, mGridView.getSelectedPosition());
-    }
-
-    void slideInAndWaitIdle() throws Throwable {
-        slideInAndWaitIdle(5000);
-    }
-
-    void slideInAndWaitIdle(long timeout) throws Throwable {
-        // animateIn() would reset position
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateIn();
-            }
-        });
-        PollingCheck.waitFor(timeout, new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return !mGridView.getLayoutManager().isSmoothScrolling()
-                        && mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-    }
-
-    @Test
-    public void testAnimateOutBlockScrollTo() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateOut();
-            }
-        });
-        // wait until sliding out.
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
-            }
-        });
-        // scrollToPosition() should not affect slideOut status
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.scrollToPosition(0);
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
-                >= mGridView.getHeight());
-
-        slideInAndWaitIdle();
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-    }
-
-    @Test
-    public void testAnimateOutBlockSmoothScrolling() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        int[] items = new int[30];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateOut();
-            }
-        });
-        // wait until sliding out.
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
-            }
-        });
-        // smoothScrollToPosition() should not affect slideOut status
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.smoothScrollToPosition(29);
-            }
-        });
-        PollingCheck.waitFor(10000, new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
-                >= mGridView.getHeight());
-
-        slideInAndWaitIdle();
-        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
-        assertSame("Scrolled to last child",
-                mGridView.findViewHolderForAdapterPosition(29).itemView, lastChild);
-    }
-
-    @Test
-    public void testAnimateOutBlockLongScrollTo() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        int[] items = new int[30];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateOut();
-            }
-        });
-        // wait until sliding out.
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
-            }
-        });
-        // smoothScrollToPosition() should not affect slideOut status
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.scrollToPosition(29);
-            }
-        });
-        PollingCheck.waitFor(10000, new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
-                >= mGridView.getHeight());
-
-        slideInAndWaitIdle();
-        View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
-        assertSame("Scrolled to last child",
-                mGridView.findViewHolderForAdapterPosition(29).itemView, lastChild);
-    }
-
-    @Test
-    public void testAnimateOutBlockLayout() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateOut();
-            }
-        });
-        // wait until sliding out.
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
-            }
-        });
-        // change adapter should not affect slideOut status
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.changeItem(0, 200);
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
-                >= mGridView.getHeight());
-        assertEquals("onLayout suppressed during slide out", 300,
-                mGridView.getChildAt(0).getHeight());
-
-        slideInAndWaitIdle();
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-        // size of item should be updated immediately after slide in animation finishes:
-        PollingCheck.waitFor(1000, new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return 200 == mGridView.getChildAt(0).getHeight();
-            }
-        });
-    }
-
-    @Test
-    public void testAnimateOutBlockFocusChange() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateOut();
-                mActivity.findViewById(R.id.button).requestFocus();
-            }
-        });
-        assertTrue(mActivity.findViewById(R.id.button).hasFocus());
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getChildAt(0).getTop() > mGridView.getPaddingTop();
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.requestFocus();
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-        assertTrue("First view slided Out", mGridView.getChildAt(0).getTop()
-                >= mGridView.getHeight());
-
-        slideInAndWaitIdle();
-        assertEquals("First view is aligned with padding top", mGridView.getPaddingTop(),
-                mGridView.getChildAt(0).getTop());
-    }
-
-    @Test
-    public void testHorizontalAnimateOutBlockScrollTo() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding left", mGridView.getPaddingLeft(),
-                mGridView.getChildAt(0).getLeft());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateOut();
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getChildAt(0).getLeft() > mGridView.getPaddingLeft();
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.scrollToPosition(0);
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-
-        assertTrue("First view is slided out", mGridView.getChildAt(0).getLeft()
-                > mGridView.getWidth());
-
-        slideInAndWaitIdle();
-        assertEquals("First view is aligned with padding left", mGridView.getPaddingLeft(),
-                mGridView.getChildAt(0).getLeft());
-
-    }
-
-    @Test
-    public void testHorizontalAnimateOutRtl() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.horizontal_linear_rtl);
-        int[] items = new int[100];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        assertEquals("First view is aligned with padding right",
-                mGridView.getWidth() - mGridView.getPaddingRight(),
-                mGridView.getChildAt(0).getRight());
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.animateOut();
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getChildAt(0).getRight()
-                        < mGridView.getWidth() - mGridView.getPaddingRight();
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.smoothScrollToPosition(0);
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mGridView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE;
-            }
-        });
-
-        assertTrue("First view is slided out", mGridView.getChildAt(0).getRight() < 0);
-
-        slideInAndWaitIdle();
-        assertEquals("First view is aligned with padding right",
-                mGridView.getWidth() - mGridView.getPaddingRight(),
-                mGridView.getChildAt(0).getRight());
-    }
-
-    @Test
-    public void testSmoothScrollerOutRange() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID,
-                R.layout.vertical_linear_with_button_onleft);
-        intent.putExtra(GridActivity.EXTRA_REQUEST_FOCUS_ONLAYOUT, true);
-        int[] items = new int[30];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 680;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        final View button = mActivity.findViewById(R.id.button);
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            public void run() {
-                button.requestFocus();
-            }
-        });
-
-        mGridView.setSelectedPositionSmooth(0);
-        waitForScrollIdle(mVerifyLayout);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            public void run() {
-                mGridView.setSelectedPositionSmooth(120);
-            }
-        });
-        waitForScrollIdle(mVerifyLayout);
-        assertTrue(button.hasFocus());
-        int key;
-        if (mGridView.getLayoutDirection() == ViewGroup.LAYOUT_DIRECTION_RTL) {
-            key = KeyEvent.KEYCODE_DPAD_LEFT;
-        } else {
-            key = KeyEvent.KEYCODE_DPAD_RIGHT;
-        }
-        sendKey(key);
-        // the GridView should has focus in its children
-        assertTrue(mGridView.hasFocus());
-        assertFalse(mGridView.isFocused());
-        assertEquals(29, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testRemoveLastItemWithStableId() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, true);
-        int[] items = new int[1];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 680;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setRemoveDuration(2000);
-                mActivity.removeItems(0, 1, false);
-                mGridView.getAdapter().notifyDataSetChanged();
-            }
-        });
-        Thread.sleep(500);
-        assertEquals(-1, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testUpdateAndSelect1() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getAdapter().notifyDataSetChanged();
-                mGridView.setSelectedPosition(1);
-            }
-        });
-        waitOneUiCycle();
-        assertEquals(1, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testUpdateAndSelect2() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getAdapter().notifyDataSetChanged();
-                mGridView.setSelectedPosition(50);
-            }
-        });
-        waitOneUiCycle();
-        assertEquals(50, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testUpdateAndSelect3() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_HAS_STABLE_IDS, false);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 10);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int[] newItems = new int[100];
-                for (int i = 0; i < newItems.length; i++) {
-                    newItems[i] = mActivity.mItemLengths[0];
-                }
-                mActivity.addItems(0, newItems, false);
-                mGridView.getAdapter().notifyDataSetChanged();
-                mGridView.setSelectedPosition(50);
-            }
-        });
-        waitOneUiCycle();
-        assertEquals(50, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testFocusedPositonAfterRemoved1() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        final int[] items = new int[2];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-        setSelectedPosition(1);
-        assertEquals(1, mGridView.getSelectedPosition());
-
-        final int[] newItems = new int[3];
-        for (int i = 0; i < newItems.length; i++) {
-            newItems[i] = 300;
-        }
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(0, 2, true);
-                mActivity.addItems(0, newItems, true);
-            }
-        });
-        assertEquals(0, mGridView.getSelectedPosition());
-    }
-
-    @Test
-    public void testFocusedPositonAfterRemoved2() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        final int[] items = new int[2];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-        setSelectedPosition(1);
-        assertEquals(1, mGridView.getSelectedPosition());
-
-        final int[] newItems = new int[3];
-        for (int i = 0; i < newItems.length; i++) {
-            newItems[i] = 300;
-        }
-        performAndWaitForAnimation(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.removeItems(1, 1, true);
-                mActivity.addItems(1, newItems, true);
-            }
-        });
-        assertEquals(1, mGridView.getSelectedPosition());
-    }
-
-    static void assertNoCollectionItemInfo(AccessibilityNodeInfoCompat info) {
-        AccessibilityNodeInfoCompat.CollectionItemInfoCompat nodeInfoCompat =
-                info.getCollectionItemInfo();
-        if (nodeInfoCompat == null) {
-            return;
-        }
-        assertTrue(nodeInfoCompat.getRowIndex() < 0);
-        assertTrue(nodeInfoCompat.getColumnIndex() < 0);
-    }
-
-    /**
-     * This test would need talkback on.
-     */
-    @Test
-    public void testAccessibilityOfItemsBeingPushedOut() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        final int lastPos = mGridView.getChildAdapterPosition(
-                mGridView.getChildAt(mGridView.getChildCount() - 1));
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getLayoutManager().setItemPrefetchEnabled(false);
-            }
-        });
-        final int numItemsToPushOut = mNumRows;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // set longer enough so that accessibility service will initialize node
-                // within setImportantForAccessibility().
-                mGridView.getItemAnimator().setRemoveDuration(2000);
-                mGridView.getItemAnimator().setAddDuration(2000);
-                final int[] newItems = new int[numItemsToPushOut];
-                final int newItemValue = mActivity.mItemLengths[0];
-                for (int i = 0; i < newItems.length; i++) {
-                    newItems[i] = newItemValue;
-                }
-                mActivity.addItems(lastPos - numItemsToPushOut + 1, newItems);
-            }
-        });
-        waitForItemAnimation();
-    }
-
-    /**
-     * This test simulates talkback by calling setImportanceForAccessibility at end of animation
-     */
-    @Test
-    public void simulatesAccessibilityOfItemsBeingPushedOut() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 100);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        final HashSet<View> moveAnimationViews = new HashSet();
-        mActivity.mImportantForAccessibilityListener =
-                new GridActivity.ImportantForAccessibilityListener() {
-            RecyclerView.LayoutManager mLM = mGridView.getLayoutManager();
-            @Override
-            public void onImportantForAccessibilityChanged(View view, int newValue) {
-                // simulates talkack, having setImportantForAccessibility to call
-                // onInitializeAccessibilityNodeInfoForItem() for the DISAPPEARING items.
-                if (moveAnimationViews.contains(view)) {
-                    AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
-                    mLM.onInitializeAccessibilityNodeInfoForItem(
-                            null, null, view, info);
-                }
-            }
-        };
-        final int lastPos = mGridView.getChildAdapterPosition(
-                mGridView.getChildAt(mGridView.getChildCount() - 1));
-        final int numItemsToPushOut = mNumRows;
-        for (int i = 0; i < numItemsToPushOut; i++) {
-            moveAnimationViews.add(
-                    mGridView.getChildAt(mGridView.getChildCount() - 1 - i));
-        }
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setItemAnimator(new DefaultItemAnimator() {
-                    @Override
-                    public void onMoveFinished(RecyclerView.ViewHolder item) {
-                        moveAnimationViews.remove(item.itemView);
-                    }
-                });
-                mGridView.getLayoutManager().setItemPrefetchEnabled(false);
-            }
-        });
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final int[] newItems = new int[numItemsToPushOut];
-                final int newItemValue = mActivity.mItemLengths[0] + 1;
-                for (int i = 0; i < newItems.length; i++) {
-                    newItems[i] = newItemValue;
-                }
-                mActivity.addItems(lastPos - numItemsToPushOut + 1, newItems);
-            }
-        });
-        while (moveAnimationViews.size() != 0) {
-            Thread.sleep(100);
-        }
-    }
-
-    @Test
-    public void testAccessibilityNodeInfoOnRemovedFirstItem() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 6);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        final View lastView = mGridView.findViewHolderForAdapterPosition(0).itemView;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setRemoveDuration(20000);
-                mActivity.removeItems(0, 1);
-            }
-        });
-        waitForItemAnimationStart();
-        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(lastView);
-        mGridView.getLayoutManager().onInitializeAccessibilityNodeInfoForItem(null, null,
-                lastView, info);
-        assertNoCollectionItemInfo(info);
-    }
-
-    @Test
-    public void testAccessibilityNodeInfoOnRemovedLastItem() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_grid);
-        intent.putExtra(GridActivity.EXTRA_NUM_ITEMS, 6);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 3;
-
-        initActivity(intent);
-
-        final View lastView = mGridView.findViewHolderForAdapterPosition(5).itemView;
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.getItemAnimator().setRemoveDuration(20000);
-                mActivity.removeItems(5, 1);
-            }
-        });
-        waitForItemAnimationStart();
-        AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain(lastView);
-        mGridView.getLayoutManager().onInitializeAccessibilityNodeInfoForItem(null, null,
-                lastView, info);
-        assertNoCollectionItemInfo(info);
-    }
-
-    static class FiveViewTypesProvider implements ViewTypeProvider {
-
-        @Override
-        public int getViewType(int position) {
-            switch (position) {
-                case 0:
-                    return 0;
-                case 1:
-                    return 1;
-                case 2:
-                    return 2;
-                case 3:
-                    return 3;
-                case 4:
-                    return 4;
-            }
-            return 199;
-        }
-    }
-
-    // Used by testItemAlignmentVertical() testItemAlignmentHorizontal()
-    static class ItemAlignmentWithPaddingFacetProvider implements
-            ItemAlignmentFacetProvider {
-        final ItemAlignmentFacet mFacet0;
-        final ItemAlignmentFacet mFacet1;
-        final ItemAlignmentFacet mFacet2;
-        final ItemAlignmentFacet mFacet3;
-        final ItemAlignmentFacet mFacet4;
-
-        ItemAlignmentWithPaddingFacetProvider() {
-            ItemAlignmentFacet.ItemAlignmentDef[] defs;
-            mFacet0 = new ItemAlignmentFacet();
-            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t1);
-            defs[0].setItemAlignmentOffsetPercent(0);
-            defs[0].setItemAlignmentOffsetWithPadding(false);
-            mFacet0.setAlignmentDefs(defs);
-            mFacet1 = new ItemAlignmentFacet();
-            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t1);
-            defs[0].setItemAlignmentOffsetPercent(0);
-            defs[0].setItemAlignmentOffsetWithPadding(true);
-            mFacet1.setAlignmentDefs(defs);
-            mFacet2 = new ItemAlignmentFacet();
-            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t2);
-            defs[0].setItemAlignmentOffsetPercent(100);
-            defs[0].setItemAlignmentOffsetWithPadding(true);
-            mFacet2.setAlignmentDefs(defs);
-            mFacet3 = new ItemAlignmentFacet();
-            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t2);
-            defs[0].setItemAlignmentOffsetPercent(50);
-            defs[0].setItemAlignmentOffsetWithPadding(true);
-            mFacet3.setAlignmentDefs(defs);
-            mFacet4 = new ItemAlignmentFacet();
-            defs = new ItemAlignmentFacet.ItemAlignmentDef[1];
-            defs[0] = new ItemAlignmentFacet.ItemAlignmentDef();
-            defs[0].setItemAlignmentViewId(R.id.t2);
-            defs[0].setItemAlignmentOffsetPercent(50);
-            defs[0].setItemAlignmentOffsetWithPadding(false);
-            mFacet4.setAlignmentDefs(defs);
-        }
-
-        @Override
-        public ItemAlignmentFacet getItemAlignmentFacet(int viewType) {
-            switch (viewType) {
-                case 0:
-                    return mFacet0;
-                case 1:
-                    return mFacet1;
-                case 2:
-                    return mFacet2;
-                case 3:
-                    return mFacet3;
-                case 4:
-                    return mFacet4;
-            }
-            return null;
-        }
-    }
-
-    @Test
-    public void testItemAlignmentVertical() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.vertical_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout2);
-        int[] items = new int[5];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
-                FiveViewTypesProvider.class.getName());
-        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
-                ItemAlignmentWithPaddingFacetProvider.class.getName());
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffsetPercent(50);
-                mGridView.setWindowAlignmentOffset(0);
-            }
-        });
-        waitForLayout();
-
-        final float windowAlignCenter = mGridView.getHeight() / 2f;
-        Rect rect = new Rect();
-        View textView;
-
-        // test 1: does not include padding
-        textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1);
-        rect.set(0, 0, textView.getWidth(), textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.top, DELTA);
-
-        // test 2: including low padding
-        setSelectedPosition(1);
-        textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1);
-        assertTrue(textView.getPaddingTop() > 0);
-        rect.set(0, textView.getPaddingTop(), textView.getWidth(), textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.top, DELTA);
-
-        // test 3: including high padding
-        setSelectedPosition(2);
-        textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingBottom() > 0);
-        rect.set(0, 0, textView.getWidth(),
-                textView.getHeight() - textView.getPaddingBottom());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.bottom, DELTA);
-
-        // test 4: including padding will be ignored if offsetPercent is not 0 or 100
-        setSelectedPosition(3);
-        textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingTop() != textView.getPaddingBottom());
-        rect.set(0, 0, textView.getWidth(), textView.getHeight() / 2);
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.bottom, DELTA);
-
-        // test 5: does not include padding
-        setSelectedPosition(4);
-        textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingTop() != textView.getPaddingBottom());
-        rect.set(0, 0, textView.getWidth(), textView.getHeight() / 2);
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.bottom, DELTA);
-    }
-
-    @Test
-    public void testItemAlignmentHorizontal() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout3);
-        int[] items = new int[5];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
-                FiveViewTypesProvider.class.getName());
-        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
-                ItemAlignmentWithPaddingFacetProvider.class.getName());
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffsetPercent(50);
-                mGridView.setWindowAlignmentOffset(0);
-            }
-        });
-        waitForLayout();
-
-        final float windowAlignCenter = mGridView.getWidth() / 2f;
-        Rect rect = new Rect();
-        View textView;
-
-        // test 1: does not include padding
-        textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1);
-        rect.set(0, 0, textView.getWidth(), textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.left, DELTA);
-
-        // test 2: including low padding
-        setSelectedPosition(1);
-        textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1);
-        assertTrue(textView.getPaddingLeft() > 0);
-        rect.set(textView.getPaddingLeft(), 0, textView.getWidth(), textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.left, DELTA);
-
-        // test 3: including high padding
-        setSelectedPosition(2);
-        textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingRight() > 0);
-        rect.set(0, 0, textView.getWidth() - textView.getPaddingRight(),
-                textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.right, DELTA);
-
-        // test 4: including padding will be ignored if offsetPercent is not 0 or 100
-        setSelectedPosition(3);
-        textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
-        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.right, DELTA);
-
-        // test 5: does not include padding
-        setSelectedPosition(4);
-        textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
-        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.right, DELTA);
-    }
-
-    @Test
-    public void testItemAlignmentHorizontalRtl() throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
-        intent.putExtra(GridActivity.EXTRA_CHILD_LAYOUT_ID, R.layout.relative_layout3);
-        int[] items = new int[5];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 300;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        intent.putExtra(GridActivity.EXTRA_VIEWTYPEPROVIDER_CLASS,
-                FiveViewTypesProvider.class.getName());
-        intent.putExtra(GridActivity.EXTRA_ITEMALIGNMENTPROVIDER_CLASS,
-                ItemAlignmentWithPaddingFacetProvider.class.getName());
-        mOrientation = BaseGridView.VERTICAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
-                mGridView.setWindowAlignment(BaseGridView.WINDOW_ALIGN_NO_EDGE);
-                mGridView.setWindowAlignmentOffsetPercent(50);
-                mGridView.setWindowAlignmentOffset(0);
-            }
-        });
-        waitForLayout();
-
-        final float windowAlignCenter = mGridView.getWidth() / 2f;
-        Rect rect = new Rect();
-        View textView;
-
-        // test 1: does not include padding
-        textView = mGridView.findViewHolderForAdapterPosition(0).itemView.findViewById(R.id.t1);
-        rect.set(0, 0, textView.getWidth(), textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.right, DELTA);
-
-        // test 2: including low padding
-        setSelectedPosition(1);
-        textView = mGridView.findViewHolderForAdapterPosition(1).itemView.findViewById(R.id.t1);
-        assertTrue(textView.getPaddingRight() > 0);
-        rect.set(0, 0, textView.getWidth() - textView.getPaddingRight(),
-                textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.right, DELTA);
-
-        // test 3: including high padding
-        setSelectedPosition(2);
-        textView = mGridView.findViewHolderForAdapterPosition(2).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingLeft() > 0);
-        rect.set(textView.getPaddingLeft(), 0, textView.getWidth(),
-                textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.left, DELTA);
-
-        // test 4: including padding will be ignored if offsetPercent is not 0 or 100
-        setSelectedPosition(3);
-        textView = mGridView.findViewHolderForAdapterPosition(3).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
-        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.right, DELTA);
-
-        // test 5: does not include padding
-        setSelectedPosition(4);
-        textView = mGridView.findViewHolderForAdapterPosition(4).itemView.findViewById(R.id.t2);
-        assertTrue(textView.getPaddingLeft() != textView.getPaddingRight());
-        rect.set(0, 0, textView.getWidth() / 2, textView.getHeight());
-        mGridView.offsetDescendantRectToMyCoords(textView, rect);
-        assertEquals(windowAlignCenter, rect.right, DELTA);
-    }
-
-    enum ItemLocation {
-        ITEM_AT_LOW,
-        ITEM_AT_KEY_LINE,
-        ITEM_AT_HIGH
-    };
-
-    static class ItemAt {
-        final int mScrollPosition;
-        final int mPosition;
-        final ItemLocation mLocation;
-
-        ItemAt(int scrollPosition, int position, ItemLocation loc) {
-            mScrollPosition = scrollPosition;
-            mPosition = position;
-            mLocation = loc;
-        }
-
-        ItemAt(int position, ItemLocation loc) {
-            mScrollPosition = position;
-            mPosition = position;
-            mLocation = loc;
-        }
-    }
-
-    /**
-     * When scroll to position, item at position is expected at given location.
-     */
-    static ItemAt itemAt(int position, ItemLocation location) {
-        return new ItemAt(position, location);
-    }
-
-    /**
-     * When scroll to scrollPosition, item at position is expected at given location.
-     */
-    static ItemAt itemAt(int scrollPosition, int position, ItemLocation location) {
-        return new ItemAt(scrollPosition, position, location);
-    }
-
-    void prepareKeyLineTest(int numItems) throws Throwable {
-        Intent intent = new Intent();
-        intent.putExtra(GridActivity.EXTRA_LAYOUT_RESOURCE_ID, R.layout.horizontal_linear);
-        int[] items = new int[numItems];
-        for (int i = 0; i < items.length; i++) {
-            items[i] = 32;
-        }
-        intent.putExtra(GridActivity.EXTRA_ITEMS, items);
-        intent.putExtra(GridActivity.EXTRA_STAGGERED, false);
-        mOrientation = BaseGridView.HORIZONTAL;
-        mNumRows = 1;
-
-        initActivity(intent);
-    }
-
-    public void testPreferKeyLine(final int windowAlignment,
-            final boolean preferKeyLineOverLow,
-            final boolean preferKeyLineOverHigh,
-            ItemLocation assertFirstItemLocation,
-            ItemLocation assertLastItemLocation) throws Throwable {
-        testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh,
-                itemAt(0, assertFirstItemLocation),
-                itemAt(mActivity.mNumItems - 1, assertLastItemLocation));
-    }
-
-    public void testPreferKeyLine(final int windowAlignment,
-            final boolean preferKeyLineOverLow,
-            final boolean preferKeyLineOverHigh,
-            ItemLocation assertFirstItemLocation,
-            ItemAt assertLastItemLocation) throws Throwable {
-        testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh,
-                itemAt(0, assertFirstItemLocation),
-                assertLastItemLocation);
-    }
-
-    public void testPreferKeyLine(final int windowAlignment,
-            final boolean preferKeyLineOverLow,
-            final boolean preferKeyLineOverHigh,
-            ItemAt assertFirstItemLocation,
-            ItemLocation assertLastItemLocation) throws Throwable {
-        testPreferKeyLine(windowAlignment, preferKeyLineOverLow, preferKeyLineOverHigh,
-                assertFirstItemLocation,
-                itemAt(mActivity.mNumItems - 1, assertLastItemLocation));
-    }
-
-    public void testPreferKeyLine(final int windowAlignment,
-            final boolean preferKeyLineOverLow,
-            final boolean preferKeyLineOverHigh,
-            ItemAt assertFirstItemLocation,
-            ItemAt assertLastItemLocation) throws Throwable {
-        TestPreferKeyLineOptions options = new TestPreferKeyLineOptions();
-        options.mAssertItemLocations = new ItemAt[] {assertFirstItemLocation,
-                assertLastItemLocation};
-        options.mPreferKeyLineOverLow = preferKeyLineOverLow;
-        options.mPreferKeyLineOverHigh = preferKeyLineOverHigh;
-        options.mWindowAlignment = windowAlignment;
-
-        options.mRtl = false;
-        testPreferKeyLine(options);
-
-        options.mRtl = true;
-        testPreferKeyLine(options);
-    }
-
-    static class TestPreferKeyLineOptions {
-        int mWindowAlignment;
-        boolean mPreferKeyLineOverLow;
-        boolean mPreferKeyLineOverHigh;
-        ItemAt[] mAssertItemLocations;
-        boolean mRtl;
-    }
-
-    public void testPreferKeyLine(final TestPreferKeyLineOptions options) throws Throwable {
-        startWaitLayout();
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (options.mRtl) {
-                    mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
-                } else {
-                    mGridView.setLayoutDirection(View.LAYOUT_DIRECTION_LTR);
-                }
-                mGridView.setWindowAlignment(options.mWindowAlignment);
-                mGridView.setWindowAlignmentOffsetPercent(50);
-                mGridView.setWindowAlignmentOffset(0);
-                mGridView.setWindowAlignmentPreferKeyLineOverLowEdge(options.mPreferKeyLineOverLow);
-                mGridView.setWindowAlignmentPreferKeyLineOverHighEdge(
-                        options.mPreferKeyLineOverHigh);
-            }
-        });
-        waitForLayout();
-
-        final int paddingStart = mGridView.getPaddingStart();
-        final int paddingEnd = mGridView.getPaddingEnd();
-        final int windowAlignCenter = mGridView.getWidth() / 2;
-
-        for (int i = 0; i < options.mAssertItemLocations.length; i++) {
-            ItemAt assertItemLocation = options.mAssertItemLocations[i];
-            setSelectedPosition(assertItemLocation.mScrollPosition);
-            View view = mGridView.findViewHolderForAdapterPosition(assertItemLocation.mPosition)
-                    .itemView;
-            switch (assertItemLocation.mLocation) {
-                case ITEM_AT_LOW:
-                    if (options.mRtl) {
-                        assertEquals(mGridView.getWidth() - paddingStart, view.getRight());
-                    } else {
-                        assertEquals(paddingStart, view.getLeft());
-                    }
-                    break;
-                case ITEM_AT_HIGH:
-                    if (options.mRtl) {
-                        assertEquals(paddingEnd, view.getLeft());
-                    } else {
-                        assertEquals(mGridView.getWidth() - paddingEnd, view.getRight());
-                    }
-                    break;
-                case ITEM_AT_KEY_LINE:
-                    assertEquals(windowAlignCenter, (view.getLeft() + view.getRight()) / 2, DELTA);
-                    break;
-            }
-        }
-    }
-
-    @Test
-    public void testPreferKeyLine1() throws Throwable {
-        prepareKeyLineTest(1);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false,
-                ItemLocation.ITEM_AT_HIGH, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false,
-                ItemLocation.ITEM_AT_HIGH, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_LOW);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-    }
-
-    @Test
-    public void testPreferKeyLine2() throws Throwable {
-        prepareKeyLineTest(2);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false,
-                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true,
-                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false,
-                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
-                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true,
-                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
-                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false,
-                itemAt(0, 1, ItemLocation.ITEM_AT_HIGH),
-                itemAt(1, 1, ItemLocation.ITEM_AT_HIGH));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true,
-                itemAt(0, 0, ItemLocation.ITEM_AT_KEY_LINE),
-                itemAt(1, 0, ItemLocation.ITEM_AT_KEY_LINE));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false,
-                itemAt(0, 1, ItemLocation.ITEM_AT_HIGH),
-                itemAt(1, 1, ItemLocation.ITEM_AT_HIGH));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true,
-                itemAt(0, 0, ItemLocation.ITEM_AT_KEY_LINE),
-                itemAt(1, 0, ItemLocation.ITEM_AT_KEY_LINE));
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false,
-                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true,
-                ItemLocation.ITEM_AT_LOW, itemAt(1, 0, ItemLocation.ITEM_AT_LOW));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false,
-                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
-                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true,
-                itemAt(0, 1, ItemLocation.ITEM_AT_KEY_LINE),
-                itemAt(1, 1, ItemLocation.ITEM_AT_KEY_LINE));
-    }
-
-    @Test
-    public void testPreferKeyLine10000() throws Throwable {
-        prepareKeyLineTest(10000);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, false, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_NO_EDGE, true, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_KEY_LINE);
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, false,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, false, true,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, false,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_LOW_EDGE, true, true,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_KEY_LINE);
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, false, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, false,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_HIGH_EDGE, true, true,
-                ItemLocation.ITEM_AT_KEY_LINE, ItemLocation.ITEM_AT_HIGH);
-
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, false,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, false, true,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, false,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
-        testPreferKeyLine(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE, true, true,
-                ItemLocation.ITEM_AT_LOW, ItemLocation.ITEM_AT_HIGH);
-    }
-}
diff --git a/leanback/tests/res/layout/vertical_grid_rtl.xml b/leanback/tests/res/layout/vertical_grid_rtl.xml
deleted file mode 100644
index b9a53e8..0000000
--- a/leanback/tests/res/layout/vertical_grid_rtl.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:lb="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layoutDirection="rtl"
-    >
-  <Button android:id="@+id/button"
-      android:layout_width="wrap_content"
-      android:layout_height="wrap_content"
-      android:layout_alignParentStart="true"
-      android:text="button"
-      />
-  <android.support.v17.leanback.widget.VerticalGridViewEx
-      android:id="@+id/gridview"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent"
-      android:layout_toEndOf="@id/button"
-      android:clipToPadding="false"
-      android:focusable="true"
-      android:focusableInTouchMode="true"
-      android:background="#00ffff"
-      android:horizontalSpacing="12dip"
-      android:verticalSpacing="24dip"
-      lb:numberOfColumns="1"
-      lb:columnWidth="150dip"
-      lb:focusOutSideStart="false"
-      lb:focusOutSideEnd="true"
-      android:paddingBottom="12dip"
-      android:paddingLeft="12dip"
-      android:paddingRight="12dip"
-      android:paddingTop="12dip" />
-</RelativeLayout>
diff --git a/lifecycle/extensions/src/androidTest/AndroidManifest.xml b/lifecycle/extensions/src/androidTest/AndroidManifest.xml
index 08e1de6..db921fd 100644
--- a/lifecycle/extensions/src/androidTest/AndroidManifest.xml
+++ b/lifecycle/extensions/src/androidTest/AndroidManifest.xml
@@ -17,6 +17,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.arch.lifecycle.extensions.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
 
     <application>
         <activity android:name="android.arch.lifecycle.viewmodeltest.ViewModelActivity"
diff --git a/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml b/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml
index 722f480..e60c9f4 100644
--- a/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml
+++ b/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml
@@ -17,6 +17,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.arch.lifecycle.reactivestreams.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
 
     <application>
         <activity android:name="android.arch.lifecycle.viewmodeltest.ViewModelActivity"
diff --git a/loader/Android.mk b/loader/Android.mk
new file mode 100644
index 0000000..089be12
--- /dev/null
+++ b/loader/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2011 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+# Here is the final static library that apps can link against.
+# Applications that use this library must specify
+#
+#   LOCAL_STATIC_ANDROID_LIBRARIES := \
+#       android-support-loader
+#
+# in their makefiles to include the resources and their dependencies in their package.
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE := android-support-loader
+LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src/main/java)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
+LOCAL_JAVA_LIBRARIES := \
+    android-support-annotations \
+    android-support-compat
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    android-arch-lifecycle-livedata-core \
+    android-arch-lifecycle-viewmodel
+LOCAL_JAR_EXCLUDE_FILES := none
+LOCAL_JAVA_LANGUAGE_VERSION := 1.7
+LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
diff --git a/loader/OWNERS b/loader/OWNERS
new file mode 100644
index 0000000..ac839ec
--- /dev/null
+++ b/loader/OWNERS
@@ -0,0 +1,3 @@
+ilake@google.com
+mount@google.com
+adamp@google.com
diff --git a/loader/api/current.txt b/loader/api/current.txt
new file mode 100644
index 0000000..954bb03
--- /dev/null
+++ b/loader/api/current.txt
@@ -0,0 +1,100 @@
+package android.support.v4.app {
+
+  public abstract class LoaderManager {
+    ctor public LoaderManager();
+    method public abstract void destroyLoader(int);
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public static <T extends android.arch.lifecycle.LifecycleOwner & android.arch.lifecycle.ViewModelStoreOwner> android.support.v4.app.LoaderManager getInstance(T);
+    method public abstract <D> android.support.v4.content.Loader<D> getLoader(int);
+    method public boolean hasRunningLoaders();
+    method public abstract <D> android.support.v4.content.Loader<D> initLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract void markForRedelivery();
+    method public abstract <D> android.support.v4.content.Loader<D> restartLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+  }
+
+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
+    method public abstract android.support.v4.content.Loader<D> onCreateLoader(int, android.os.Bundle);
+    method public abstract void onLoadFinished(android.support.v4.content.Loader<D>, D);
+    method public abstract void onLoaderReset(android.support.v4.content.Loader<D>);
+  }
+
+}
+
+package android.support.v4.content {
+
+  public abstract class AsyncTaskLoader<D> extends android.support.v4.content.Loader {
+    ctor public AsyncTaskLoader(android.content.Context);
+    method public void cancelLoadInBackground();
+    method public boolean isLoadInBackgroundCanceled();
+    method public abstract D loadInBackground();
+    method public void onCanceled(D);
+    method protected D onLoadInBackground();
+    method public void setUpdateThrottle(long);
+  }
+
+  public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
+    ctor public CursorLoader(android.content.Context);
+    ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public void deliverResult(android.database.Cursor);
+    method public java.lang.String[] getProjection();
+    method public java.lang.String getSelection();
+    method public java.lang.String[] getSelectionArgs();
+    method public java.lang.String getSortOrder();
+    method public android.net.Uri getUri();
+    method public android.database.Cursor loadInBackground();
+    method public void onCanceled(android.database.Cursor);
+    method public void setProjection(java.lang.String[]);
+    method public void setSelection(java.lang.String);
+    method public void setSelectionArgs(java.lang.String[]);
+    method public void setSortOrder(java.lang.String);
+    method public void setUri(android.net.Uri);
+  }
+
+  public class Loader<D> {
+    ctor public Loader(android.content.Context);
+    method public void abandon();
+    method public boolean cancelLoad();
+    method public void commitContentChanged();
+    method public java.lang.String dataToString(D);
+    method public void deliverCancellation();
+    method public void deliverResult(D);
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void forceLoad();
+    method public android.content.Context getContext();
+    method public int getId();
+    method public boolean isAbandoned();
+    method public boolean isReset();
+    method public boolean isStarted();
+    method protected void onAbandon();
+    method protected boolean onCancelLoad();
+    method public void onContentChanged();
+    method protected void onForceLoad();
+    method protected void onReset();
+    method protected void onStartLoading();
+    method protected void onStopLoading();
+    method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+    method public void reset();
+    method public void rollbackContentChanged();
+    method public final void startLoading();
+    method public void stopLoading();
+    method public boolean takeContentChanged();
+    method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+  }
+
+  public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+    ctor public Loader.ForceLoadContentObserver();
+  }
+
+  public static abstract interface Loader.OnLoadCanceledListener<D> {
+    method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
+  }
+
+  public static abstract interface Loader.OnLoadCompleteListener<D> {
+    method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
+  }
+
+}
+
diff --git a/loader/build.gradle b/loader/build.gradle
new file mode 100644
index 0000000..45cad2a
--- /dev/null
+++ b/loader/build.gradle
@@ -0,0 +1,29 @@
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+    api(ARCH_LIFECYCLE_LIVEDATA_CORE, libs.exclude_annotations_transitive)
+    api(ARCH_LIFECYCLE_VIEWMODEL, libs.exclude_annotations_transitive)
+
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+}
+
+supportLibrary {
+    name = "Android Support Library loader"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2011"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
+}
+
diff --git a/loader/src/androidTest/AndroidManifest.xml b/loader/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..61bea05
--- /dev/null
+++ b/loader/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.loader.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <application>
+        <activity android:name="android.support.v4.app.test.EmptyActivity" />
+    </application>
+
+</manifest>
+
diff --git a/loader/src/androidTest/java/android/support/v4/app/LoaderInfoTest.java b/loader/src/androidTest/java/android/support/v4/app/LoaderInfoTest.java
new file mode 100644
index 0000000..5df61dc
--- /dev/null
+++ b/loader/src/androidTest/java/android/support/v4/app/LoaderInfoTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.support.annotation.Nullable;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.test.DummyLoaderCallbacks;
+import android.support.v4.app.test.EmptyActivity;
+import android.support.v4.content.AsyncTaskLoader;
+import android.support.v4.content.Loader;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LoaderInfoTest {
+
+    @Rule
+    public ActivityTestRule<EmptyActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyActivity.class);
+
+    @Test
+    public void testIsCallbackWaitingForData() throws Throwable {
+        final DummyLoaderCallbacks loaderCallback = new DummyLoaderCallbacks(mock(Context.class));
+        final CountDownLatch deliverResultLatch = new CountDownLatch(1);
+        Loader<Boolean> delayLoader = new AsyncTaskLoader<Boolean>(mock(Context.class)) {
+            @Override
+            public Boolean loadInBackground() {
+                SystemClock.sleep(50);
+                return true;
+            }
+
+            @Override
+            protected void onStartLoading() {
+                forceLoad();
+            }
+
+            @Override
+            public void deliverResult(@Nullable Boolean data) {
+                super.deliverResult(data);
+                deliverResultLatch.countDown();
+            }
+        };
+        final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
+                0, null, delayLoader);
+        assertFalse("isCallbackWaitingForData should be false before setCallback",
+                loaderInfo.isCallbackWaitingForData());
+
+        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
+        assertTrue("isCallbackWaitingForData should be true immediately after setCallback",
+                loaderInfo.isCallbackWaitingForData());
+
+        assertTrue("Loader timed out delivering results",
+                deliverResultLatch.await(1, TimeUnit.SECONDS));
+        // Results are posted to the UI thread, so we wait for them there
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue("onLoadFinished should be called after setCallback",
+                        loaderCallback.mOnLoadFinished);
+                assertFalse("isCallbackWaitingForData should be false after onLoadFinished",
+                        loaderInfo.isCallbackWaitingForData());
+            }
+        });
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetCallback() throws Throwable {
+        final DummyLoaderCallbacks loaderCallback = new DummyLoaderCallbacks(mock(Context.class));
+        Loader<Boolean> loader = loaderCallback.onCreateLoader(0, null);
+        final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
+                0, null, loader);
+        assertFalse("onLoadFinished shouldn't be called before setCallback",
+                loaderCallback.mOnLoadFinished);
+
+        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
+        assertTrue("onLoadFinished should be called after setCallback",
+                loaderCallback.mOnLoadFinished);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetCallback_replace() throws Throwable {
+        final DummyLoaderCallbacks initialCallback = new DummyLoaderCallbacks(mock(Context.class));
+        Loader<Boolean> loader = initialCallback.onCreateLoader(0, null);
+        LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
+                0, null, loader);
+        assertFalse("onLoadFinished for initial shouldn't be called before setCallback initial",
+                initialCallback.mOnLoadFinished);
+
+        loaderInfo.setCallback(mActivityRule.getActivity(), initialCallback);
+        assertTrue("onLoadFinished for initial should be called after setCallback initial",
+                initialCallback.mOnLoadFinished);
+
+        final DummyLoaderCallbacks replacementCallback =
+                new DummyLoaderCallbacks(mActivityRule.getActivity());
+        initialCallback.mOnLoadFinished = false;
+
+        loaderInfo.setCallback(mActivityRule.getActivity(), replacementCallback);
+        assertFalse("onLoadFinished for initial should not be called "
+                        + "after setCallback replacement",
+                initialCallback.mOnLoadFinished);
+        assertTrue("onLoadFinished for replacement should be called "
+                        + " after setCallback replacement",
+                replacementCallback.mOnLoadFinished);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testDestroy() throws Throwable {
+        final DummyLoaderCallbacks loaderCallback = new DummyLoaderCallbacks(mock(Context.class));
+        final Loader<Boolean> loader = loaderCallback.onCreateLoader(0, null);
+        final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
+                0, null, loader);
+
+        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
+        assertTrue("Loader should be started after setCallback", loader.isStarted());
+        loaderInfo.destroy();
+        assertFalse("Loader should not be started after destroy", loader.isStarted());
+    }
+}
diff --git a/loader/src/androidTest/java/android/support/v4/app/LoaderManagerTest.java b/loader/src/androidTest/java/android/support/v4/app/LoaderManagerTest.java
new file mode 100644
index 0000000..3b55565
--- /dev/null
+++ b/loader/src/androidTest/java/android/support/v4/app/LoaderManagerTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+
+import android.arch.lifecycle.Lifecycle;
+import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.LifecycleRegistry;
+import android.arch.lifecycle.ViewModelStore;
+import android.arch.lifecycle.ViewModelStoreOwner;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.test.DummyLoaderCallbacks;
+import android.support.v4.app.test.EmptyActivity;
+import android.support.v4.content.Loader;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LoaderManagerTest {
+
+    @Rule
+    public ActivityTestRule<EmptyActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyActivity.class);
+
+    @Test
+    public void testDestroyFromOnCreateLoader() throws Throwable {
+        final LoaderOwner loaderOwner = new LoaderOwner();
+        final CountDownLatch onCreateLoaderLatch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                LoaderManager.getInstance(loaderOwner).initLoader(65, null,
+                        new DummyLoaderCallbacks(mock(Context.class)) {
+                            @NonNull
+                            @Override
+                            public Loader<Boolean> onCreateLoader(int id, Bundle args) {
+                                try {
+                                    LoaderManager.getInstance(loaderOwner).destroyLoader(65);
+                                    fail("Calling destroyLoader in onCreateLoader should throw an "
+                                            + "IllegalStateException");
+                                } catch (IllegalStateException e) {
+                                    // Expected
+                                    onCreateLoaderLatch.countDown();
+                                }
+                                return super.onCreateLoader(id, args);
+                            }
+                        });
+            }
+        });
+        onCreateLoaderLatch.await(1, TimeUnit.SECONDS);
+    }
+
+    /**
+     * Test to ensure that loader operations, such as destroyLoader, can safely be called
+     * in onLoadFinished
+     */
+    @Test
+    public void testDestroyFromOnLoadFinished() throws Throwable {
+        final LoaderOwner loaderOwner = new LoaderOwner();
+        final CountDownLatch onLoadFinishedLatch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                LoaderManager.getInstance(loaderOwner).initLoader(43, null,
+                        new DummyLoaderCallbacks(mock(Context.class)) {
+                            @Override
+                            public void onLoadFinished(@NonNull Loader<Boolean> loader,
+                                    Boolean data) {
+                                super.onLoadFinished(loader, data);
+                                LoaderManager.getInstance(loaderOwner).destroyLoader(43);
+                            }
+                        });
+            }
+        });
+        onLoadFinishedLatch.await(1, TimeUnit.SECONDS);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void enforceOnMainThread_initLoader() {
+        LoaderOwner loaderOwner = new LoaderOwner();
+        LoaderManager.getInstance(loaderOwner).initLoader(-1, null,
+                new DummyLoaderCallbacks(mock(Context.class)));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void enforceOnMainThread_restartLoader() {
+        LoaderOwner loaderOwner = new LoaderOwner();
+        LoaderManager.getInstance(loaderOwner).restartLoader(-1, null,
+                new DummyLoaderCallbacks(mock(Context.class)));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void enforceOnMainThread_destroyLoader() {
+        LoaderOwner loaderOwner = new LoaderOwner();
+        LoaderManager.getInstance(loaderOwner).destroyLoader(-1);
+    }
+
+    class LoaderOwner implements LifecycleOwner, ViewModelStoreOwner {
+
+        private LifecycleRegistry mLifecycle = new LifecycleRegistry(this);
+        private ViewModelStore mViewModelStore = new ViewModelStore();
+
+        LoaderOwner() {
+            mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
+        }
+
+        @NonNull
+        @Override
+        public Lifecycle getLifecycle() {
+            return mLifecycle;
+        }
+
+        @NonNull
+        @Override
+        public ViewModelStore getViewModelStore() {
+            return mViewModelStore;
+        }
+    }
+}
diff --git a/loader/src/androidTest/java/android/support/v4/app/LoaderObserverTest.java b/loader/src/androidTest/java/android/support/v4/app/LoaderObserverTest.java
new file mode 100644
index 0000000..2fb27f7
--- /dev/null
+++ b/loader/src/androidTest/java/android/support/v4/app/LoaderObserverTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.v4.app.test.DummyLoaderCallbacks;
+import android.support.v4.content.Loader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class LoaderObserverTest {
+
+    @Test
+    public void testOnChanged() {
+        DummyLoaderCallbacks callback = new DummyLoaderCallbacks(mock(Context.class));
+        @SuppressWarnings("unchecked")
+        LoaderManagerImpl.LoaderObserver<Boolean> observer = new LoaderManagerImpl.LoaderObserver<>(
+                mock(Loader.class), callback);
+        assertFalse("LoaderObserver should not have delivered data before onChanged",
+                observer.hasDeliveredData());
+        assertFalse("onLoadFinished should not be called before onChanged",
+                callback.mOnLoadFinished);
+
+
+        observer.onChanged(true);
+        assertTrue("LoaderObserver should have delivered data after onChanged",
+                observer.hasDeliveredData());
+        assertTrue("onLoadFinished should be called after onChanged",
+                callback.mOnLoadFinished);
+    }
+
+    @Test
+    public void testReset() {
+        DummyLoaderCallbacks callback = new DummyLoaderCallbacks(mock(Context.class));
+        @SuppressWarnings("unchecked")
+        LoaderManagerImpl.LoaderObserver<Boolean> observer = new LoaderManagerImpl.LoaderObserver<>(
+                mock(Loader.class), callback);
+        assertFalse("onLoaderReset shouldn't be called before onChanged+reset",
+                callback.mOnLoaderReset);
+
+        observer.reset();
+        assertFalse("onLoaderReset should not be called after only reset",
+                callback.mOnLoaderReset);
+    }
+
+    @Test
+    public void testResetWithOnChanged() {
+        DummyLoaderCallbacks callback = new DummyLoaderCallbacks(mock(Context.class));
+        @SuppressWarnings("unchecked")
+        LoaderManagerImpl.LoaderObserver<Boolean> observer = new LoaderManagerImpl.LoaderObserver<>(
+                mock(Loader.class), callback);
+        assertFalse("onLoaderReset shouldn't be called before onChanged+reset",
+                callback.mOnLoaderReset);
+
+        observer.onChanged(true);
+        observer.reset();
+        assertTrue("onLoaderReset should be called after onChanged+reset",
+                callback.mOnLoaderReset);
+    }
+}
diff --git a/loader/src/androidTest/java/android/support/v4/app/LoaderViewModelTest.java b/loader/src/androidTest/java/android/support/v4/app/LoaderViewModelTest.java
new file mode 100644
index 0000000..36384ce
--- /dev/null
+++ b/loader/src/androidTest/java/android/support/v4/app/LoaderViewModelTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.v4.app.test.DummyLoader;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+@SmallTest
+public class LoaderViewModelTest {
+
+    @Test
+    public void testHasRunningLoaders() {
+        LoaderManagerImpl.LoaderViewModel loaderViewModel = new LoaderManagerImpl.LoaderViewModel();
+        assertFalse("LoaderViewModel should not be running with before putLoader",
+                loaderViewModel.hasRunningLoaders());
+
+        AlwaysRunningLoaderInfo info = new AlwaysRunningLoaderInfo(mock(Context.class));
+        loaderViewModel.putLoader(0, info);
+        assertTrue("LoaderViewModel should be running after a running LoaderInfo is added",
+                loaderViewModel.hasRunningLoaders());
+
+        loaderViewModel.removeLoader(0);
+        assertFalse("LoaderViewModel should not be running after all LoaderInfos are removed",
+                loaderViewModel.hasRunningLoaders());
+    }
+
+    @Test
+    public void testOnCleared() {
+        LoaderManagerImpl.LoaderViewModel loaderViewModel = new LoaderManagerImpl.LoaderViewModel();
+        AlwaysRunningLoaderInfo info = new AlwaysRunningLoaderInfo(mock(Context.class));
+        loaderViewModel.putLoader(0, info);
+
+        assertFalse("LoaderInfo shouldn't be destroyed before onCleared", info.mDestroyed);
+        loaderViewModel.onCleared();
+        assertTrue("LoaderInfo should be destroyed after onCleared", info.mDestroyed);
+        assertNull("LoaderInfo should be removed from LoaderViewModel after onCleared",
+                loaderViewModel.getLoader(0));
+    }
+
+    private class AlwaysRunningLoaderInfo extends LoaderManagerImpl.LoaderInfo<Boolean> {
+        boolean mDestroyed = false;
+
+        AlwaysRunningLoaderInfo(Context context) {
+            super(0, null, new DummyLoader(context));
+        }
+
+        @Override
+        boolean isCallbackWaitingForData() {
+            return true;
+        }
+
+        @Override
+        void destroy() {
+            mDestroyed = true;
+        }
+    }
+}
diff --git a/loader/src/androidTest/java/android/support/v4/app/test/DummyLoader.java b/loader/src/androidTest/java/android/support/v4/app/test/DummyLoader.java
new file mode 100644
index 0000000..1668397
--- /dev/null
+++ b/loader/src/androidTest/java/android/support/v4/app/test/DummyLoader.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app.test;
+
+import android.content.Context;
+import android.support.v4.content.Loader;
+
+public class DummyLoader extends Loader<Boolean> {
+    public DummyLoader(Context context) {
+        super(context);
+    }
+
+    @Override
+    protected void onStartLoading() {
+        deliverResult(true);
+    }
+}
diff --git a/loader/src/androidTest/java/android/support/v4/app/test/DummyLoaderCallbacks.java b/loader/src/androidTest/java/android/support/v4/app/test/DummyLoaderCallbacks.java
new file mode 100644
index 0000000..2c09a2c
--- /dev/null
+++ b/loader/src/androidTest/java/android/support/v4/app/test/DummyLoaderCallbacks.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app.test;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.LoaderManager;
+import android.support.v4.content.Loader;
+
+public class DummyLoaderCallbacks implements LoaderManager.LoaderCallbacks<Boolean> {
+    private final Context mContext;
+
+    public boolean mOnLoadFinished;
+    public boolean mOnLoaderReset;
+
+    public DummyLoaderCallbacks(Context context) {
+        mContext = context;
+    }
+
+    @NonNull
+    @Override
+    public Loader<Boolean> onCreateLoader(int id, Bundle args) {
+        return new DummyLoader(mContext);
+    }
+
+    @Override
+    public void onLoadFinished(@NonNull Loader<Boolean> loader, Boolean data) {
+        mOnLoadFinished = true;
+    }
+
+    @Override
+    public void onLoaderReset(@NonNull Loader<Boolean> loader) {
+        mOnLoaderReset = true;
+    }
+}
diff --git a/loader/src/androidTest/java/android/support/v4/app/test/EmptyActivity.java b/loader/src/androidTest/java/android/support/v4/app/test/EmptyActivity.java
new file mode 100644
index 0000000..7c069f4
--- /dev/null
+++ b/loader/src/androidTest/java/android/support/v4/app/test/EmptyActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app.test;
+
+import android.support.v4.app.SupportActivity;
+
+public class EmptyActivity extends SupportActivity {
+}
diff --git a/core-utils/tests/java/android/support/v4/content/ModernAsyncTaskTest.java b/loader/src/androidTest/java/android/support/v4/content/ModernAsyncTaskTest.java
similarity index 100%
rename from core-utils/tests/java/android/support/v4/content/ModernAsyncTaskTest.java
rename to loader/src/androidTest/java/android/support/v4/content/ModernAsyncTaskTest.java
diff --git a/loader/src/main/AndroidManifest.xml b/loader/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..08b7004
--- /dev/null
+++ b/loader/src/main/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.loader"/>
+
diff --git a/loader/src/main/java/android/support/v4/app/LoaderManager.java b/loader/src/main/java/android/support/v4/app/LoaderManager.java
new file mode 100644
index 0000000..4774b7b
--- /dev/null
+++ b/loader/src/main/java/android/support/v4/app/LoaderManager.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.ViewModelStoreOwner;
+import android.os.Bundle;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.content.Loader;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Static library support version of the framework's {@link android.app.LoaderManager}.
+ * Used to write apps that run on platforms prior to Android 3.0.  When running
+ * on Android 3.0 or above, this implementation is still used; it does not try
+ * to switch to the framework's implementation.  See the framework SDK
+ * documentation for a class overview.
+ *
+ * <p>Your activity must derive from {@link FragmentActivity} to use this.
+ */
+public abstract class LoaderManager {
+    /**
+     * Callback interface for a client to interact with the manager.
+     */
+    public interface LoaderCallbacks<D> {
+        /**
+         * Instantiate and return a new Loader for the given ID.
+         *
+         * <p>This will always be called from the process's main thread.
+         *
+         * @param id The ID whose loader is to be created.
+         * @param args Any arguments supplied by the caller.
+         * @return Return a new Loader instance that is ready to start loading.
+         */
+        @MainThread
+        @NonNull
+        Loader<D> onCreateLoader(int id, @Nullable Bundle args);
+
+        /**
+         * Called when a previously created loader has finished its load.  Note
+         * that normally an application is <em>not</em> allowed to commit fragment
+         * transactions while in this call, since it can happen after an
+         * activity's state is saved.  See {@link FragmentManager#beginTransaction()
+         * FragmentManager.openTransaction()} for further discussion on this.
+         *
+         * <p>This function is guaranteed to be called prior to the release of
+         * the last data that was supplied for this Loader.  At this point
+         * you should remove all use of the old data (since it will be released
+         * soon), but should not do your own release of the data since its Loader
+         * owns it and will take care of that.  The Loader will take care of
+         * management of its data so you don't have to.  In particular:
+         *
+         * <ul>
+         * <li> <p>The Loader will monitor for changes to the data, and report
+         * them to you through new calls here.  You should not monitor the
+         * data yourself.  For example, if the data is a {@link android.database.Cursor}
+         * and you place it in a {@link android.widget.CursorAdapter}, use
+         * the {@link android.widget.CursorAdapter#CursorAdapter(android.content.Context,
+         * android.database.Cursor, int)} constructor <em>without</em> passing
+         * in either {@link android.widget.CursorAdapter#FLAG_AUTO_REQUERY}
+         * or {@link android.widget.CursorAdapter#FLAG_REGISTER_CONTENT_OBSERVER}
+         * (that is, use 0 for the flags argument).  This prevents the CursorAdapter
+         * from doing its own observing of the Cursor, which is not needed since
+         * when a change happens you will get a new Cursor throw another call
+         * here.
+         * <li> The Loader will release the data once it knows the application
+         * is no longer using it.  For example, if the data is
+         * a {@link android.database.Cursor} from a {@link android.content.CursorLoader},
+         * you should not call close() on it yourself.  If the Cursor is being placed in a
+         * {@link android.widget.CursorAdapter}, you should use the
+         * {@link android.widget.CursorAdapter#swapCursor(android.database.Cursor)}
+         * method so that the old Cursor is not closed.
+         * </ul>
+         *
+         * <p>This will always be called from the process's main thread.
+         *
+         * @param loader The Loader that has finished.
+         * @param data The data generated by the Loader.
+         */
+        @MainThread
+        void onLoadFinished(@NonNull Loader<D> loader, D data);
+
+        /**
+         * Called when a previously created loader is being reset, and thus
+         * making its data unavailable.  The application should at this point
+         * remove any references it has to the Loader's data.
+         *
+         * <p>This will always be called from the process's main thread.
+         *
+         * @param loader The Loader that is being reset.
+         */
+        @MainThread
+        void onLoaderReset(@NonNull Loader<D> loader);
+    }
+
+    /**
+     * Gets a LoaderManager associated with the given owner, such as a {@link FragmentActivity} or
+     * {@link Fragment}.
+     *
+     * @param owner The owner that should be used to create the returned LoaderManager
+     * @param <T> A class that maintains its own {@link android.arch.lifecycle.Lifecycle} and
+     *           {@link android.arch.lifecycle.ViewModelStore}. For instance,
+     *           {@link FragmentActivity} or {@link Fragment}.
+     * @return A valid LoaderManager
+     */
+    @NonNull
+    public static <T extends LifecycleOwner & ViewModelStoreOwner> LoaderManager getInstance(
+            @NonNull T owner) {
+        return new LoaderManagerImpl(owner, owner.getViewModelStore());
+    }
+
+    /**
+     * Ensures a loader is initialized and active.  If the loader doesn't
+     * already exist, one is created and (if the activity/fragment is currently
+     * started) starts the loader.  Otherwise the last created
+     * loader is re-used.
+     *
+     * <p>In either case, the given callback is associated with the loader, and
+     * will be called as the loader state changes.  If at the point of call
+     * the caller is in its started state, and the requested loader
+     * already exists and has generated its data, then
+     * callback {@link LoaderCallbacks#onLoadFinished} will
+     * be called immediately (inside of this function), so you must be prepared
+     * for this to happen.
+     *
+     * <p>Must be called from the process's main thread.
+     *
+     * @param id A unique identifier for this loader.  Can be whatever you want.
+     * Identifiers are scoped to a particular LoaderManager instance.
+     * @param args Optional arguments to supply to the loader at construction.
+     * If a loader already exists (a new one does not need to be created), this
+     * parameter will be ignored and the last arguments continue to be used.
+     * @param callback Interface the LoaderManager will call to report about
+     * changes in the state of the loader.  Required.
+     */
+    @MainThread
+    @NonNull
+    public abstract <D> Loader<D> initLoader(int id, @Nullable Bundle args,
+            @NonNull LoaderManager.LoaderCallbacks<D> callback);
+
+    /**
+     * Starts a new or restarts an existing {@link android.content.Loader} in
+     * this manager, registers the callbacks to it,
+     * and (if the activity/fragment is currently started) starts loading it.
+     * If a loader with the same id has previously been
+     * started it will automatically be destroyed when the new loader completes
+     * its work. The callback will be delivered before the old loader
+     * is destroyed.
+     *
+     * <p>Must be called from the process's main thread.
+     *
+     * @param id A unique identifier for this loader.  Can be whatever you want.
+     * Identifiers are scoped to a particular LoaderManager instance.
+     * @param args Optional arguments to supply to the loader at construction.
+     * @param callback Interface the LoaderManager will call to report about
+     * changes in the state of the loader.  Required.
+     */
+    @MainThread
+    @NonNull
+    public abstract <D> Loader<D> restartLoader(int id, @Nullable Bundle args,
+            @NonNull LoaderManager.LoaderCallbacks<D> callback);
+
+    /**
+     * Stops and removes the loader with the given ID.  If this loader
+     * had previously reported data to the client through
+     * {@link LoaderCallbacks#onLoadFinished(Loader, Object)}, a call
+     * will be made to {@link LoaderCallbacks#onLoaderReset(Loader)}.
+     *
+     * <p>Must be called from the process's main thread.
+     */
+    @MainThread
+    public abstract void destroyLoader(int id);
+
+    /**
+     * Return the Loader with the given id or null if no matching Loader
+     * is found.
+     */
+    @Nullable
+    public abstract <D> Loader<D> getLoader(int id);
+
+    /**
+     * Mark all Loaders associated with this LoaderManager for redelivery of their current
+     * data (if any), waiting for the next time the Loader is started if it is currently stopped.
+     * In cases where no data has yet been delivered, this is effectively a no-op. In cases where
+     * data has already been delivered via {@link LoaderCallbacks#onLoadFinished(Loader, Object)},
+     * this will ensure that {@link LoaderCallbacks#onLoadFinished(Loader, Object)} is called again
+     * with the same data.
+     * <p>
+     * Call this only if you are implementing a {@link LifecycleOwner} where the views/elements that
+     * developers are likely to use in {@link LoaderCallbacks#onLoadFinished(Loader, Object)} can be
+     * created and destroyed multiple times without the {@link LifecycleOwner} itself being
+     * destroyed. Call this when the views/elements are being destroyed to ensure that the data
+     * is redelivered upon recreation.
+     */
+    public abstract void markForRedelivery();
+
+    /**
+     * Print the LoaderManager's state into the given stream.
+     *
+     * @param prefix Text to print at the front of each line.
+     * @param fd The raw file descriptor that the dump is being sent to.
+     * @param writer A PrintWriter to which the dump is to be set.
+     * @param args Additional arguments to the dump request.
+     */
+    public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
+
+    /**
+     * Control whether the framework's internal loader manager debugging
+     * logs are turned on.  If enabled, you will see output in logcat as
+     * the framework performs loader operations.
+     */
+    public static void enableDebugLogging(boolean enabled) {
+        LoaderManagerImpl.DEBUG = enabled;
+    }
+
+    /**
+     * Returns true if any loaders managed are currently running and have not
+     * returned data to the application yet.
+     */
+    public boolean hasRunningLoaders() { return false; }
+}
diff --git a/loader/src/main/java/android/support/v4/app/LoaderManagerImpl.java b/loader/src/main/java/android/support/v4/app/LoaderManagerImpl.java
new file mode 100644
index 0000000..fbda089
--- /dev/null
+++ b/loader/src/main/java/android/support/v4/app/LoaderManagerImpl.java
@@ -0,0 +1,468 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.app;
+
+import android.arch.lifecycle.LifecycleOwner;
+import android.arch.lifecycle.MutableLiveData;
+import android.arch.lifecycle.Observer;
+import android.arch.lifecycle.ViewModel;
+import android.arch.lifecycle.ViewModelProvider;
+import android.arch.lifecycle.ViewModelStore;
+import android.os.Bundle;
+import android.os.Looper;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.content.Loader;
+import android.support.v4.util.DebugUtils;
+import android.support.v4.util.SparseArrayCompat;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.lang.reflect.Modifier;
+
+class LoaderManagerImpl extends LoaderManager {
+    static final String TAG = "LoaderManager";
+    static boolean DEBUG = false;
+
+    /**
+     * Class which manages the state of a {@link Loader} and its associated
+     * {@link LoaderCallbacks}
+     *
+     * @param <D> Type of data the Loader handles
+     */
+    public static class LoaderInfo<D> extends MutableLiveData<D>
+            implements Loader.OnLoadCompleteListener<D> {
+
+        private final int mId;
+        private final @Nullable Bundle mArgs;
+        private final @NonNull Loader<D> mLoader;
+        private LifecycleOwner mLifecycleOwner;
+        private LoaderObserver<D> mObserver;
+
+        LoaderInfo(int id, @Nullable Bundle args, @NonNull Loader<D> loader) {
+            mId = id;
+            mArgs = args;
+            mLoader = loader;
+            mLoader.registerListener(id, this);
+        }
+
+        @NonNull
+        Loader<D> getLoader() {
+            return mLoader;
+        }
+
+        @Override
+        protected void onActive() {
+            if (DEBUG) Log.v(TAG, "  Starting: " + LoaderInfo.this);
+            mLoader.startLoading();
+        }
+
+        @Override
+        protected void onInactive() {
+            if (DEBUG) Log.v(TAG, "  Stopping: " + LoaderInfo.this);
+            mLoader.stopLoading();
+        }
+
+        /**
+         * Set the {@link LoaderCallbacks} to associate with this {@link Loader}. This
+         * removes any existing {@link LoaderCallbacks}.
+         *
+         * @param owner The lifecycle that should be used to start and stop the {@link Loader}
+         * @param callback The new {@link LoaderCallbacks} to use
+         * @return The {@link Loader} associated with this LoaderInfo
+         */
+        @MainThread
+        @NonNull
+        Loader<D> setCallback(@NonNull LifecycleOwner owner,
+                @NonNull LoaderCallbacks<D> callback) {
+            LoaderObserver<D> observer = new LoaderObserver<>(mLoader, callback);
+            // Add the new observer
+            observe(owner, observer);
+            // Loaders only support one observer at a time, so remove the current observer, if any
+            if (mObserver != null) {
+                removeObserver(mObserver);
+            }
+            mLifecycleOwner = owner;
+            mObserver = observer;
+            return mLoader;
+        }
+
+        void markForRedelivery() {
+            LifecycleOwner lifecycleOwner = mLifecycleOwner;
+            LoaderObserver<D> observer = mObserver;
+            if (lifecycleOwner != null && observer != null) {
+                // Removing and re-adding the observer ensures that the
+                // observer is called again, even if they had already
+                // received the current data
+                removeObserver(observer);
+                observe(lifecycleOwner, observer);
+            }
+        }
+
+        boolean isCallbackWaitingForData() {
+            //noinspection SimplifiableIfStatement
+            if (!hasActiveObservers()) {
+                // No active observers means no one is waiting for data
+                return false;
+            }
+            return mObserver != null && !mObserver.hasDeliveredData();
+        }
+
+        @Override
+        public void removeObserver(@NonNull Observer<D> observer) {
+            super.removeObserver(observer);
+            // Clear out our references when the observer is removed to avoid leaking
+            mLifecycleOwner = null;
+            mObserver = null;
+        }
+
+        @MainThread
+        void destroy() {
+            if (DEBUG) Log.v(TAG, "  Destroying: " + this);
+            // First tell the Loader that we don't need it anymore
+            mLoader.cancelLoad();
+            mLoader.abandon();
+            // Then clean up the LoaderObserver
+            LoaderObserver<D> observer = mObserver;
+            if (observer != null) {
+                removeObserver(observer);
+                observer.reset();
+            }
+            // Finally, send the reset to the Loader
+            mLoader.unregisterListener(this);
+            mLoader.reset();
+        }
+
+        @Override
+        public void onLoadComplete(@NonNull Loader<D> loader, @Nullable D data) {
+            if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
+            if (Looper.myLooper() == Looper.getMainLooper()) {
+                setValue(data);
+            } else {
+                // The Loader#deliverResult method that calls this should
+                // only be called on the main thread, so this should never
+                // happen, but we don't want to lose the data
+                if (DEBUG) {
+                    Log.w(TAG, "onLoadComplete was incorrectly called on a "
+                            + "background thread");
+                }
+                postValue(data);
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(64);
+            sb.append("LoaderInfo{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" #");
+            sb.append(mId);
+            sb.append(" : ");
+            DebugUtils.buildShortClassTag(mLoader, sb);
+            sb.append("}}");
+            return sb.toString();
+        }
+
+        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+            writer.print(prefix); writer.print("mId="); writer.print(mId);
+            writer.print(" mArgs="); writer.println(mArgs);
+            writer.print(prefix); writer.print("mLoader="); writer.println(mLoader);
+            mLoader.dump(prefix + "  ", fd, writer, args);
+            if (mObserver != null) {
+                writer.print(prefix); writer.print("mCallbacks="); writer.println(mObserver);
+                mObserver.dump(prefix + "  ", writer);
+            }
+            writer.print(prefix); writer.print("mData="); writer.println(
+                    getLoader().dataToString(getValue()));
+            writer.print(prefix); writer.print("mStarted="); writer.println(
+                    hasActiveObservers());
+        }
+    }
+
+    /**
+     * Encapsulates the {@link LoaderCallbacks} as a {@link Observer}.
+     *
+     * @param <D> Type of data the LoaderCallbacks handles
+     */
+    static class LoaderObserver<D> implements Observer<D> {
+
+        private final @NonNull Loader<D> mLoader;
+        private final @NonNull LoaderCallbacks<D> mCallback;
+
+        private boolean mDeliveredData = false;
+
+        LoaderObserver(@NonNull Loader<D> loader, @NonNull LoaderCallbacks<D> callback) {
+            mLoader = loader;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onChanged(@Nullable D data) {
+            if (DEBUG) {
+                Log.v(TAG, "  onLoadFinished in " + mLoader + ": "
+                        + mLoader.dataToString(data));
+            }
+            mCallback.onLoadFinished(mLoader, data);
+            mDeliveredData = true;
+        }
+
+        boolean hasDeliveredData() {
+            return mDeliveredData;
+        }
+
+        @MainThread
+        void reset() {
+            if (mDeliveredData) {
+                if (DEBUG) Log.v(TAG, "  Resetting: " + mLoader);
+                mCallback.onLoaderReset(mLoader);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return mCallback.toString();
+        }
+
+        public void dump(String prefix, PrintWriter writer) {
+            writer.print(prefix); writer.print("mDeliveredData="); writer.println(
+                    mDeliveredData);
+        }
+    }
+
+    /**
+     * ViewModel responsible for retaining {@link LoaderInfo} instances across configuration changes
+     */
+    static class LoaderViewModel extends ViewModel {
+        private static final ViewModelProvider.Factory FACTORY = new ViewModelProvider.Factory() {
+            @NonNull
+            @Override
+            @SuppressWarnings("unchecked")
+            public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
+                return (T) new LoaderViewModel();
+            }
+        };
+
+        @NonNull
+        static LoaderViewModel getInstance(ViewModelStore viewModelStore) {
+            return new ViewModelProvider(viewModelStore, FACTORY).get(LoaderViewModel.class);
+        }
+
+        private SparseArrayCompat<LoaderInfo> mLoaders = new SparseArrayCompat<>();
+        private boolean mCreatingLoader = false;
+
+        void startCreatingLoader() {
+            mCreatingLoader = true;
+        }
+
+        boolean isCreatingLoader() {
+            return mCreatingLoader;
+        }
+
+        void finishCreatingLoader() {
+            mCreatingLoader = false;
+        }
+
+        void putLoader(int id, @NonNull LoaderInfo info) {
+            mLoaders.put(id, info);
+        }
+
+        @SuppressWarnings("unchecked")
+        <D> LoaderInfo<D> getLoader(int id) {
+            return mLoaders.get(id);
+        }
+
+        void removeLoader(int id) {
+            mLoaders.remove(id);
+        }
+
+        boolean hasRunningLoaders() {
+            int size = mLoaders.size();
+            for (int index = 0; index < size; index++) {
+                LoaderInfo info = mLoaders.valueAt(index);
+                if (info.isCallbackWaitingForData()) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        void markForRedelivery() {
+            int size = mLoaders.size();
+            for (int index = 0; index < size; index++) {
+                LoaderInfo info = mLoaders.valueAt(index);
+                info.markForRedelivery();
+            }
+        }
+
+        @Override
+        protected void onCleared() {
+            super.onCleared();
+            int size = mLoaders.size();
+            for (int index = 0; index < size; index++) {
+                LoaderInfo info = mLoaders.valueAt(index);
+                info.destroy();
+            }
+            mLoaders.clear();
+        }
+
+        public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+            if (mLoaders.size() > 0) {
+                writer.print(prefix); writer.println("Loaders:");
+                String innerPrefix = prefix + "    ";
+                for (int i = 0; i < mLoaders.size(); i++) {
+                    LoaderInfo info = mLoaders.valueAt(i);
+                    writer.print(prefix); writer.print("  #"); writer.print(mLoaders.keyAt(i));
+                    writer.print(": "); writer.println(info.toString());
+                    info.dump(innerPrefix, fd, writer, args);
+                }
+            }
+        }
+    }
+
+    private final @NonNull LifecycleOwner mLifecycleOwner;
+    private final @NonNull LoaderViewModel mLoaderViewModel;
+
+    LoaderManagerImpl(@NonNull LifecycleOwner lifecycleOwner,
+            @NonNull ViewModelStore viewModelStore) {
+        mLifecycleOwner = lifecycleOwner;
+        mLoaderViewModel = LoaderViewModel.getInstance(viewModelStore);
+    }
+
+    @MainThread
+    @NonNull
+    private <D> Loader<D> createAndInstallLoader(int id, @Nullable Bundle args,
+            @NonNull LoaderCallbacks<D> callback) {
+        LoaderInfo<D> info;
+        try {
+            mLoaderViewModel.startCreatingLoader();
+            Loader<D> loader = callback.onCreateLoader(id, args);
+            if (loader.getClass().isMemberClass()
+                    && !Modifier.isStatic(loader.getClass().getModifiers())) {
+                throw new IllegalArgumentException("Object returned from onCreateLoader "
+                        + "must not be a non-static inner member class: "
+                        + loader);
+            }
+            info = new LoaderInfo<>(id, args, loader);
+            if (DEBUG) Log.v(TAG, "  Created new loader " + info);
+            mLoaderViewModel.putLoader(id, info);
+        } finally {
+            mLoaderViewModel.finishCreatingLoader();
+        }
+        return info.setCallback(mLifecycleOwner, callback);
+    }
+
+    @MainThread
+    @NonNull
+    @Override
+    public <D> Loader<D> initLoader(int id, @Nullable Bundle args,
+            @NonNull LoaderCallbacks<D> callback) {
+        if (mLoaderViewModel.isCreatingLoader()) {
+            throw new IllegalStateException("Called while creating a loader");
+        }
+        if (Looper.getMainLooper() != Looper.myLooper()) {
+            throw new IllegalStateException("initLoader must be called on the main thread");
+        }
+
+        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
+
+        if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
+
+        if (info == null) {
+            // Loader doesn't already exist; create.
+            return createAndInstallLoader(id, args, callback);
+        } else {
+            if (DEBUG) Log.v(TAG, "  Re-using existing loader " + info);
+            return info.setCallback(mLifecycleOwner, callback);
+        }
+    }
+
+    @MainThread
+    @NonNull
+    @Override
+    public <D> Loader<D> restartLoader(int id, @Nullable Bundle args,
+            @NonNull LoaderCallbacks<D> callback) {
+        if (mLoaderViewModel.isCreatingLoader()) {
+            throw new IllegalStateException("Called while creating a loader");
+        }
+        if (Looper.getMainLooper() != Looper.myLooper()) {
+            throw new IllegalStateException("restartLoader must be called on the main thread");
+        }
+
+        if (DEBUG) Log.v(TAG, "restartLoader in " + this + ": args=" + args);
+        // Destroy any existing Loader
+        destroyLoader(id);
+        // And create a new Loader
+        return createAndInstallLoader(id, args, callback);
+    }
+
+    @MainThread
+    @Override
+    public void destroyLoader(int id) {
+        if (mLoaderViewModel.isCreatingLoader()) {
+            throw new IllegalStateException("Called while creating a loader");
+        }
+        if (Looper.getMainLooper() != Looper.myLooper()) {
+            throw new IllegalStateException("destroyLoader must be called on the main thread");
+        }
+
+        if (DEBUG) Log.v(TAG, "destroyLoader in " + this + " of " + id);
+        LoaderInfo info = mLoaderViewModel.getLoader(id);
+        if (info != null) {
+            info.destroy();
+            mLoaderViewModel.removeLoader(id);
+        }
+    }
+
+    @Nullable
+    @Override
+    public <D> Loader<D> getLoader(int id) {
+        if (mLoaderViewModel.isCreatingLoader()) {
+            throw new IllegalStateException("Called while creating a loader");
+        }
+
+        LoaderInfo<D> info = mLoaderViewModel.getLoader(id);
+        return info != null ? info.getLoader() : null;
+    }
+
+    @Override
+    public void markForRedelivery() {
+        mLoaderViewModel.markForRedelivery();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("LoaderManager{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(" in ");
+        DebugUtils.buildShortClassTag(mLifecycleOwner, sb);
+        sb.append("}}");
+        return sb.toString();
+    }
+
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        mLoaderViewModel.dump(prefix, fd, writer, args);
+    }
+
+    @Override
+    public boolean hasRunningLoaders() {
+        return mLoaderViewModel.hasRunningLoaders();
+    }
+}
diff --git a/core-utils/java/android/support/v4/content/AsyncTaskLoader.java b/loader/src/main/java/android/support/v4/content/AsyncTaskLoader.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/AsyncTaskLoader.java
rename to loader/src/main/java/android/support/v4/content/AsyncTaskLoader.java
diff --git a/core-utils/java/android/support/v4/content/CursorLoader.java b/loader/src/main/java/android/support/v4/content/CursorLoader.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/CursorLoader.java
rename to loader/src/main/java/android/support/v4/content/CursorLoader.java
diff --git a/core-utils/java/android/support/v4/content/Loader.java b/loader/src/main/java/android/support/v4/content/Loader.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/Loader.java
rename to loader/src/main/java/android/support/v4/content/Loader.java
diff --git a/core-utils/java/android/support/v4/content/ModernAsyncTask.java b/loader/src/main/java/android/support/v4/content/ModernAsyncTask.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/ModernAsyncTask.java
rename to loader/src/main/java/android/support/v4/content/ModernAsyncTask.java
diff --git a/localbroadcastmanager/api/current.txt b/localbroadcastmanager/api/current.txt
new file mode 100644
index 0000000..5c02abe
--- /dev/null
+++ b/localbroadcastmanager/api/current.txt
@@ -0,0 +1,12 @@
+package android.support.v4.content {
+
+  public final class LocalBroadcastManager {
+    method public static android.support.v4.content.LocalBroadcastManager getInstance(android.content.Context);
+    method public void registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
+    method public boolean sendBroadcast(android.content.Intent);
+    method public void sendBroadcastSync(android.content.Intent);
+    method public void unregisterReceiver(android.content.BroadcastReceiver);
+  }
+
+}
+
diff --git a/localbroadcastmanager/build.gradle b/localbroadcastmanager/build.gradle
new file mode 100644
index 0000000..a3d35bf
--- /dev/null
+++ b/localbroadcastmanager/build.gradle
@@ -0,0 +1,19 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+}
+
+supportLibrary {
+    name = "Android Support Library Local Broadcast Manager"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/localbroadcastmanager/src/main/AndroidManifest.xml b/localbroadcastmanager/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..611729b
--- /dev/null
+++ b/localbroadcastmanager/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.localbroadcastmanager"/>
diff --git a/core-utils/java/android/support/v4/content/LocalBroadcastManager.java b/localbroadcastmanager/src/main/java/android/support/v4/content/LocalBroadcastManager.java
similarity index 100%
rename from core-utils/java/android/support/v4/content/LocalBroadcastManager.java
rename to localbroadcastmanager/src/main/java/android/support/v4/content/LocalBroadcastManager.java
diff --git a/media-compat/Android.mk b/media-compat/Android.mk
deleted file mode 100644
index 8538752..0000000
--- a/media-compat/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-media-compat \
-#       android-support-compat \
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-media-compat
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,api21) \
-    $(call all-java-files-under,api22) \
-    $(call all-java-files-under,api23) \
-    $(call all-java-files-under,api24) \
-    $(call all-java-files-under,api26) \
-    $(call all-java-files-under,java) \
-    $(call all-Iaidl-files-under,java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/media-compat/AndroidManifest.xml b/media-compat/AndroidManifest.xml
deleted file mode 100644
index cd3e5e2..0000000
--- a/media-compat/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.mediacompat">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index ffa6e93..29c91b7 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -19,16 +19,14 @@
 
 android {
     sourceSets {
-        main.java.srcDirs = [
+        main.java.srcDirs += [
                 'api21',
                 'api22',
                 'api23',
                 'api24',
                 'api26',
-                'java'
         ]
-        main.aidl.srcDirs = ['java']
-        main.res.srcDirs 'res', 'res-public'
+        main.res.srcDirs += 'src/main/res-public'
     }
 
     buildTypes.all {
@@ -43,5 +41,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2011"
     description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
-    legacySourceLocation = true
 }
diff --git a/media-compat/src/main/AndroidManifest.xml b/media-compat/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b64f726
--- /dev/null
+++ b/media-compat/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.mediacompat"/>
diff --git a/media-compat/java/android/support/v4/media/MediaDescriptionCompat.aidl b/media-compat/src/main/aidl/android/support/v4/media/MediaDescriptionCompat.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaDescriptionCompat.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/MediaDescriptionCompat.aidl
diff --git a/media-compat/java/android/support/v4/media/MediaMetadataCompat.aidl b/media-compat/src/main/aidl/android/support/v4/media/MediaMetadataCompat.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaMetadataCompat.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/MediaMetadataCompat.aidl
diff --git a/media-compat/java/android/support/v4/media/RatingCompat.aidl b/media-compat/src/main/aidl/android/support/v4/media/RatingCompat.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/RatingCompat.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/RatingCompat.aidl
diff --git a/media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl b/media-compat/src/main/aidl/android/support/v4/media/session/IMediaControllerCallback.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/IMediaControllerCallback.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/session/IMediaControllerCallback.aidl
diff --git a/media-compat/java/android/support/v4/media/session/IMediaSession.aidl b/media-compat/src/main/aidl/android/support/v4/media/session/IMediaSession.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/IMediaSession.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/session/IMediaSession.aidl
diff --git a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.aidl b/media-compat/src/main/aidl/android/support/v4/media/session/MediaSessionCompat.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/MediaSessionCompat.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/session/MediaSessionCompat.aidl
diff --git a/media-compat/java/android/support/v4/media/session/ParcelableVolumeInfo.aidl b/media-compat/src/main/aidl/android/support/v4/media/session/ParcelableVolumeInfo.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/ParcelableVolumeInfo.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/session/ParcelableVolumeInfo.aidl
diff --git a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.aidl b/media-compat/src/main/aidl/android/support/v4/media/session/PlaybackStateCompat.aidl
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/PlaybackStateCompat.aidl
rename to media-compat/src/main/aidl/android/support/v4/media/session/PlaybackStateCompat.aidl
diff --git a/media-compat/java/android/support/v4/media/AudioAttributesCompat.java b/media-compat/src/main/java/android/support/v4/media/AudioAttributesCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/AudioAttributesCompat.java
rename to media-compat/src/main/java/android/support/v4/media/AudioAttributesCompat.java
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserCompat.java b/media-compat/src/main/java/android/support/v4/media/MediaBrowserCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaBrowserCompat.java
rename to media-compat/src/main/java/android/support/v4/media/MediaBrowserCompat.java
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserCompatUtils.java b/media-compat/src/main/java/android/support/v4/media/MediaBrowserCompatUtils.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaBrowserCompatUtils.java
rename to media-compat/src/main/java/android/support/v4/media/MediaBrowserCompatUtils.java
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserProtocol.java b/media-compat/src/main/java/android/support/v4/media/MediaBrowserProtocol.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaBrowserProtocol.java
rename to media-compat/src/main/java/android/support/v4/media/MediaBrowserProtocol.java
diff --git a/media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java b/media-compat/src/main/java/android/support/v4/media/MediaBrowserServiceCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaBrowserServiceCompat.java
rename to media-compat/src/main/java/android/support/v4/media/MediaBrowserServiceCompat.java
diff --git a/media-compat/java/android/support/v4/media/MediaDescriptionCompat.java b/media-compat/src/main/java/android/support/v4/media/MediaDescriptionCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaDescriptionCompat.java
rename to media-compat/src/main/java/android/support/v4/media/MediaDescriptionCompat.java
diff --git a/media-compat/java/android/support/v4/media/MediaMetadataCompat.java b/media-compat/src/main/java/android/support/v4/media/MediaMetadataCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/MediaMetadataCompat.java
rename to media-compat/src/main/java/android/support/v4/media/MediaMetadataCompat.java
diff --git a/media-compat/java/android/support/v4/media/RatingCompat.java b/media-compat/src/main/java/android/support/v4/media/RatingCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/RatingCompat.java
rename to media-compat/src/main/java/android/support/v4/media/RatingCompat.java
diff --git a/media-compat/java/android/support/v4/media/VolumeProviderCompat.java b/media-compat/src/main/java/android/support/v4/media/VolumeProviderCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/VolumeProviderCompat.java
rename to media-compat/src/main/java/android/support/v4/media/VolumeProviderCompat.java
diff --git a/media-compat/java/android/support/v4/media/app/NotificationCompat.java b/media-compat/src/main/java/android/support/v4/media/app/NotificationCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/app/NotificationCompat.java
rename to media-compat/src/main/java/android/support/v4/media/app/NotificationCompat.java
diff --git a/media-compat/java/android/support/v4/media/session/MediaButtonReceiver.java b/media-compat/src/main/java/android/support/v4/media/session/MediaButtonReceiver.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/MediaButtonReceiver.java
rename to media-compat/src/main/java/android/support/v4/media/session/MediaButtonReceiver.java
diff --git a/media-compat/java/android/support/v4/media/session/MediaControllerCompat.java b/media-compat/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/MediaControllerCompat.java
rename to media-compat/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
diff --git a/media-compat/java/android/support/v4/media/session/MediaSessionCompat.java b/media-compat/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/MediaSessionCompat.java
rename to media-compat/src/main/java/android/support/v4/media/session/MediaSessionCompat.java
diff --git a/media-compat/java/android/support/v4/media/session/ParcelableVolumeInfo.java b/media-compat/src/main/java/android/support/v4/media/session/ParcelableVolumeInfo.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/ParcelableVolumeInfo.java
rename to media-compat/src/main/java/android/support/v4/media/session/ParcelableVolumeInfo.java
diff --git a/media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java b/media-compat/src/main/java/android/support/v4/media/session/PlaybackStateCompat.java
similarity index 100%
rename from media-compat/java/android/support/v4/media/session/PlaybackStateCompat.java
rename to media-compat/src/main/java/android/support/v4/media/session/PlaybackStateCompat.java
diff --git a/media-compat/res-public/values/public_styles.xml b/media-compat/src/main/res-public/values/public_styles.xml
similarity index 100%
rename from media-compat/res-public/values/public_styles.xml
rename to media-compat/src/main/res-public/values/public_styles.xml
diff --git a/media-compat/res/layout/notification_media_action.xml b/media-compat/src/main/res/layout/notification_media_action.xml
similarity index 100%
rename from media-compat/res/layout/notification_media_action.xml
rename to media-compat/src/main/res/layout/notification_media_action.xml
diff --git a/media-compat/res/layout/notification_media_cancel_action.xml b/media-compat/src/main/res/layout/notification_media_cancel_action.xml
similarity index 100%
rename from media-compat/res/layout/notification_media_cancel_action.xml
rename to media-compat/src/main/res/layout/notification_media_cancel_action.xml
diff --git a/media-compat/res/layout/notification_template_big_media.xml b/media-compat/src/main/res/layout/notification_template_big_media.xml
similarity index 100%
rename from media-compat/res/layout/notification_template_big_media.xml
rename to media-compat/src/main/res/layout/notification_template_big_media.xml
diff --git a/media-compat/res/layout/notification_template_big_media_custom.xml b/media-compat/src/main/res/layout/notification_template_big_media_custom.xml
similarity index 100%
rename from media-compat/res/layout/notification_template_big_media_custom.xml
rename to media-compat/src/main/res/layout/notification_template_big_media_custom.xml
diff --git a/media-compat/res/layout/notification_template_big_media_narrow.xml b/media-compat/src/main/res/layout/notification_template_big_media_narrow.xml
similarity index 100%
rename from media-compat/res/layout/notification_template_big_media_narrow.xml
rename to media-compat/src/main/res/layout/notification_template_big_media_narrow.xml
diff --git a/media-compat/res/layout/notification_template_big_media_narrow_custom.xml b/media-compat/src/main/res/layout/notification_template_big_media_narrow_custom.xml
similarity index 100%
rename from media-compat/res/layout/notification_template_big_media_narrow_custom.xml
rename to media-compat/src/main/res/layout/notification_template_big_media_narrow_custom.xml
diff --git a/media-compat/res/layout/notification_template_lines_media.xml b/media-compat/src/main/res/layout/notification_template_lines_media.xml
similarity index 100%
rename from media-compat/res/layout/notification_template_lines_media.xml
rename to media-compat/src/main/res/layout/notification_template_lines_media.xml
diff --git a/media-compat/res/layout/notification_template_media.xml b/media-compat/src/main/res/layout/notification_template_media.xml
similarity index 100%
rename from media-compat/res/layout/notification_template_media.xml
rename to media-compat/src/main/res/layout/notification_template_media.xml
diff --git a/media-compat/res/layout/notification_template_media_custom.xml b/media-compat/src/main/res/layout/notification_template_media_custom.xml
similarity index 100%
rename from media-compat/res/layout/notification_template_media_custom.xml
rename to media-compat/src/main/res/layout/notification_template_media_custom.xml
diff --git a/media-compat/res/values-v21/styles.xml b/media-compat/src/main/res/values-v21/styles.xml
similarity index 100%
rename from media-compat/res/values-v21/styles.xml
rename to media-compat/src/main/res/values-v21/styles.xml
diff --git a/media-compat/res/values-v24/styles.xml b/media-compat/src/main/res/values-v24/styles.xml
similarity index 100%
rename from media-compat/res/values-v24/styles.xml
rename to media-compat/src/main/res/values-v24/styles.xml
diff --git a/media-compat/res/values/colors.xml b/media-compat/src/main/res/values/colors.xml
similarity index 100%
rename from media-compat/res/values/colors.xml
rename to media-compat/src/main/res/values/colors.xml
diff --git a/media-compat/res/values/colors_material.xml b/media-compat/src/main/res/values/colors_material.xml
similarity index 100%
rename from media-compat/res/values/colors_material.xml
rename to media-compat/src/main/res/values/colors_material.xml
diff --git a/media-compat/res/values/config.xml b/media-compat/src/main/res/values/config.xml
similarity index 100%
rename from media-compat/res/values/config.xml
rename to media-compat/src/main/res/values/config.xml
diff --git a/media-compat/res/values/styles.xml b/media-compat/src/main/res/values/styles.xml
similarity index 100%
rename from media-compat/res/values/styles.xml
rename to media-compat/src/main/res/values/styles.xml
diff --git a/media-compat/tests/NO_DOCS b/media-compat/tests/NO_DOCS
deleted file mode 100644
index 092a39c..0000000
--- a/media-compat/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/media-compat/version-compat-tests/current/client/build.gradle b/media-compat/version-compat-tests/current/client/build.gradle
index 9c4f879..2a247df 100644
--- a/media-compat/version-compat-tests/current/client/build.gradle
+++ b/media-compat/version-compat-tests/current/client/build.gradle
@@ -26,7 +26,3 @@
 
     androidTestImplementation(TEST_RUNNER)
 }
-
-supportLibrary {
-    legacySourceLocation = true
-}
\ No newline at end of file
diff --git a/media-compat/version-compat-tests/current/client/tests/AndroidManifest.xml b/media-compat/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/current/client/tests/AndroidManifest.xml
rename to media-compat/version-compat-tests/current/client/src/androidTest/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java b/media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/AudioAttributesCompatTest.java
similarity index 100%
rename from media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
rename to media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/AudioAttributesCompatTest.java
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java b/media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/ClientBroadcastReceiver.java
similarity index 100%
rename from media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
rename to media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/ClientBroadcastReceiver.java
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java b/media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
similarity index 100%
rename from media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
rename to media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java b/media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
similarity index 100%
rename from media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
rename to media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaItemTest.java b/media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaItemTest.java
similarity index 100%
rename from media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
rename to media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/MediaItemTest.java
diff --git a/media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java b/media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/PlaybackStateCompatTest.java
similarity index 100%
rename from media-compat/version-compat-tests/current/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
rename to media-compat/version-compat-tests/current/client/src/androidTest/java/android/support/mediacompat/client/PlaybackStateCompatTest.java
diff --git a/media-compat/version-compat-tests/current/client/AndroidManifest.xml b/media-compat/version-compat-tests/current/client/src/main/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/current/client/AndroidManifest.xml
rename to media-compat/version-compat-tests/current/client/src/main/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/current/client/tests/NO_DOCS b/media-compat/version-compat-tests/current/client/tests/NO_DOCS
deleted file mode 100644
index 61c9b1a..0000000
--- a/media-compat/version-compat-tests/current/client/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/media-compat/version-compat-tests/current/service/build.gradle b/media-compat/version-compat-tests/current/service/build.gradle
index 3cb3a49..2a247df 100644
--- a/media-compat/version-compat-tests/current/service/build.gradle
+++ b/media-compat/version-compat-tests/current/service/build.gradle
@@ -26,7 +26,3 @@
 
     androidTestImplementation(TEST_RUNNER)
 }
-
-supportLibrary {
-    legacySourceLocation = true
-}
diff --git a/media-compat/version-compat-tests/current/service/tests/AndroidManifest.xml b/media-compat/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/current/service/tests/AndroidManifest.xml
rename to media-compat/version-compat-tests/current/service/src/androidTest/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/current/service/tests/NO_DOCS b/media-compat/version-compat-tests/current/service/src/androidTest/NO_DOCS
similarity index 100%
rename from media-compat/version-compat-tests/current/service/tests/NO_DOCS
rename to media-compat/version-compat-tests/current/service/src/androidTest/NO_DOCS
diff --git a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
similarity index 100%
rename from media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
rename to media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
diff --git a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/ServiceBroadcastReceiver.java b/media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/ServiceBroadcastReceiver.java
similarity index 100%
rename from media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/ServiceBroadcastReceiver.java
rename to media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/ServiceBroadcastReceiver.java
diff --git a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java b/media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
similarity index 100%
rename from media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
rename to media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
diff --git a/media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java b/media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
similarity index 100%
rename from media-compat/version-compat-tests/current/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
rename to media-compat/version-compat-tests/current/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
diff --git a/media-compat/version-compat-tests/current/service/AndroidManifest.xml b/media-compat/version-compat-tests/current/service/src/main/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/current/service/AndroidManifest.xml
rename to media-compat/version-compat-tests/current/service/src/main/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/lib/build.gradle b/media-compat/version-compat-tests/lib/build.gradle
index db9f2ae..caa6c7e 100644
--- a/media-compat/version-compat-tests/lib/build.gradle
+++ b/media-compat/version-compat-tests/lib/build.gradle
@@ -23,7 +23,3 @@
 dependencies {
     implementation(JUNIT)
 }
-
-supportLibrary {
-    legacySourceLocation = true
-}
diff --git a/media-compat/version-compat-tests/lib/AndroidManifest.xml b/media-compat/version-compat-tests/lib/src/main/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/lib/AndroidManifest.xml
rename to media-compat/version-compat-tests/lib/src/main/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/previous/client/build.gradle b/media-compat/version-compat-tests/previous/client/build.gradle
index 2788a1a..31f33fe 100644
--- a/media-compat/version-compat-tests/previous/client/build.gradle
+++ b/media-compat/version-compat-tests/previous/client/build.gradle
@@ -26,13 +26,3 @@
 
     androidTestImplementation(TEST_RUNNER)
 }
-
-android {
-    defaultConfig {
-        minSdkVersion 14
-    }
-}
-
-supportLibrary {
-    legacySourceLocation = true
-}
\ No newline at end of file
diff --git a/media-compat/version-compat-tests/previous/client/tests/AndroidManifest.xml b/media-compat/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/tests/AndroidManifest.xml
rename to media-compat/version-compat-tests/previous/client/src/androidTest/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java b/media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/AudioAttributesCompatTest.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/AudioAttributesCompatTest.java
rename to media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/AudioAttributesCompatTest.java
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java b/media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/ClientBroadcastReceiver.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/ClientBroadcastReceiver.java
rename to media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/ClientBroadcastReceiver.java
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java b/media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaBrowserCompatTest.java
rename to media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaBrowserCompatTest.java
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java b/media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
rename to media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaControllerCompatCallbackTest.java
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaItemTest.java b/media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaItemTest.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/MediaItemTest.java
rename to media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/MediaItemTest.java
diff --git a/media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java b/media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/PlaybackStateCompatTest.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/tests/src/android/support/mediacompat/client/PlaybackStateCompatTest.java
rename to media-compat/version-compat-tests/previous/client/src/androidTest/java/android/support/mediacompat/client/PlaybackStateCompatTest.java
diff --git a/media-compat/version-compat-tests/previous/client/AndroidManifest.xml b/media-compat/version-compat-tests/previous/client/src/main/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/previous/client/AndroidManifest.xml
rename to media-compat/version-compat-tests/previous/client/src/main/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/previous/client/tests/NO_DOCS b/media-compat/version-compat-tests/previous/client/tests/NO_DOCS
deleted file mode 100644
index 61c9b1a..0000000
--- a/media-compat/version-compat-tests/previous/client/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/media-compat/version-compat-tests/previous/service/build.gradle b/media-compat/version-compat-tests/previous/service/build.gradle
index 469f6e4..765e406 100644
--- a/media-compat/version-compat-tests/previous/service/build.gradle
+++ b/media-compat/version-compat-tests/previous/service/build.gradle
@@ -21,18 +21,8 @@
 }
 
 dependencies {
-    androidTestImplementation project(':support-media-compat-test-lib')
+    androidTestImplementation(project(":support-media-compat-test-lib"))
     androidTestImplementation "com.android.support:support-media-compat:27.0.1"
 
     androidTestImplementation(TEST_RUNNER)
 }
-
-android {
-    defaultConfig {
-        minSdkVersion 14
-    }
-}
-
-supportLibrary {
-    legacySourceLocation = true
-}
diff --git a/media-compat/version-compat-tests/previous/service/tests/AndroidManifest.xml b/media-compat/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/previous/service/tests/AndroidManifest.xml
rename to media-compat/version-compat-tests/previous/service/src/androidTest/AndroidManifest.xml
diff --git a/media-compat/version-compat-tests/previous/service/tests/NO_DOCS b/media-compat/version-compat-tests/previous/service/src/androidTest/NO_DOCS
similarity index 100%
rename from media-compat/version-compat-tests/previous/service/tests/NO_DOCS
rename to media-compat/version-compat-tests/previous/service/src/androidTest/NO_DOCS
diff --git a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java b/media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
rename to media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/MediaSessionCompatCallbackTest.java
diff --git a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/ServiceBroadcastReceiver.java b/media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/ServiceBroadcastReceiver.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/ServiceBroadcastReceiver.java
rename to media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/ServiceBroadcastReceiver.java
diff --git a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java b/media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
rename to media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompat.java
diff --git a/media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java b/media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
similarity index 100%
rename from media-compat/version-compat-tests/previous/service/tests/src/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
rename to media-compat/version-compat-tests/previous/service/src/androidTest/java/android/support/mediacompat/service/StubMediaBrowserServiceCompatWithDelayedMediaSession.java
diff --git a/media-compat/version-compat-tests/previous/service/AndroidManifest.xml b/media-compat/version-compat-tests/previous/service/src/main/AndroidManifest.xml
similarity index 100%
rename from media-compat/version-compat-tests/previous/service/AndroidManifest.xml
rename to media-compat/version-compat-tests/previous/service/src/main/AndroidManifest.xml
diff --git a/pathmap.mk b/pathmap.mk
index 3e73be7..ebc023e 100644
--- a/pathmap.mk
+++ b/pathmap.mk
@@ -14,58 +14,82 @@
 # limitations under the License.
 #
 
-#
-# A list of all source roots under frameworks/support.
-#
-FRAMEWORKS_SUPPORT_SUBDIRS := \
-    annotations \
-    compat \
-    core-ui \
-    core-utils \
-    customtabs \
-    design \
-    dynamic-animation \
-    exifinterface \
-    fragment \
-    media-compat \
-    percent \
-    recommendation \
-    transition \
-    tv-provider \
-    v7/cardview \
-    v7/gridlayout \
-    v7/mediarouter \
-    v7/palette \
-    v7/preference \
-    v13 \
-    v14/preference \
-    v17/leanback \
-    v17/preference-leanback \
-    wear
-
-#
-# A version of FRAMEWORKS_SUPPORT_SUBDIRS that is expanded to full paths from
-# the root of the tree.
-#
-FRAMEWORKS_SUPPORT_JAVA_SRC_DIRS := \
-    $(addprefix frameworks/support/,$(FRAMEWORKS_SUPPORT_SUBDIRS)) \
-    frameworks/support/graphics/drawable/animated \
-    frameworks/support/graphics/drawable/static \
-    frameworks/support/v7/appcompat/src \
-    frameworks/support/v7/recyclerview/src \
-    frameworks/support/emoji/core/src \
-    frameworks/support/emoji/appcompat/src \
-    frameworks/support/emoji/bundled/src
-
-#
-# A list of support library modules.
-#
+# The list of support library modules made available to the platform docs build.
 FRAMEWORKS_SUPPORT_JAVA_LIBRARIES := \
-    $(foreach dir,$(FRAMEWORKS_SUPPORT_SUBDIRS),android-support-$(subst /,-,$(dir))) \
-    android-support-vectordrawable \
     android-support-animatedvectordrawable \
-    android-support-v7-appcompat \
-    android-support-v7-recyclerview \
+    android-support-annotations \
     android-support-emoji \
     android-support-emoji-appcompat \
-    android-support-emoji-bundled
+    android-support-emoji-bundled \
+    android-support-compat \
+    android-support-core-ui \
+    android-support-core-utils \
+    android-support-customtabs \
+    android-support-design \
+    android-support-dynamic-animation \
+    android-support-exifinterface \
+    android-support-fragment \
+    android-support-heifwriter \
+    android-support-media-compat \
+    android-support-percent \
+    android-support-recommendation \
+    android-support-transition \
+    android-support-tv-provider \
+    android-support-v7-appcompat \
+    android-support-v7-cardview \
+    android-support-v7-gridlayout \
+    android-support-v7-mediarouter \
+    android-support-v7-palette \
+    android-support-v7-preference \
+    android-support-v7-recyclerview \
+    android-support-v13 \
+    android-support-v14-preference \
+    android-support-v17-leanback \
+    android-support-v17-preference-leanback \
+    android-support-vectordrawable \
+    android-support-wear
+
+# List of all Design transitive dependencies. Use this instead of android-support-design.
+ANDROID_SUPPORT_DESIGN_TARGETS := \
+    android-support-design \
+    android-support-compat \
+    android-support-core-ui \
+    android-support-core-utils \
+    android-support-fragment \
+    android-support-transition \
+    android-support-v7-appcompat \
+    android-support-v7-cardview \
+    android-support-v7-recyclerview \
+    android-support-design-animation \
+    android-support-design-bottomnavigation \
+    android-support-design-bottomsheet \
+    android-support-design-button \
+    android-support-design-canvas \
+    android-support-design-card \
+    android-support-design-chip \
+    android-support-design-circularreveal \
+    android-support-design-circularreveal-cardview \
+    android-support-design-circularreveal-coordinatorlayout \
+    android-support-design-color \
+    android-support-design-dialog \
+    android-support-design-drawable \
+    android-support-design-expandable \
+    android-support-design-floatingactionbutton \
+    android-support-design-math \
+    android-support-design-resources \
+    android-support-design-ripple \
+    android-support-design-snackbar \
+    android-support-design-stateful \
+    android-support-design-textfield \
+    android-support-design-theme \
+    android-support-design-transformation \
+    android-support-design-typography \
+    android-support-design-widget \
+    android-support-design-internal \
+    flexbox
+
+# List of all Car transitive dependencies. Use this instead of android-support-car.
+ANDROID_SUPPORT_CAR_TARGETS := \
+    android-support-car \
+    $(ANDROID_SUPPORT_DESIGN_TARGETS) \
+    android-support-media-compat
diff --git a/percent/Android.mk b/percent/Android.mk
deleted file mode 100644
index 66ce397..0000000
--- a/percent/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must include it with
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-percent \
-#       android-support-compat
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-percent
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_SHARED_ANDROID_LIBRARIES := android-support-v4
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/percent/AndroidManifest.xml b/percent/AndroidManifest.xml
deleted file mode 100644
index 5d4707d..0000000
--- a/percent/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.percent">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/percent/build.gradle b/percent/build.gradle
index 951a0e0..9585323 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -26,5 +26,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Percent Support Library"
-    legacySourceLocation = true
 }
diff --git a/percent/tests/AndroidManifest.xml b/percent/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from percent/tests/AndroidManifest.xml
rename to percent/src/androidTest/AndroidManifest.xml
diff --git a/percent/tests/java/android/support/percent/BaseInstrumentationTestCase.java b/percent/src/androidTest/java/android/support/percent/BaseInstrumentationTestCase.java
similarity index 100%
rename from percent/tests/java/android/support/percent/BaseInstrumentationTestCase.java
rename to percent/src/androidTest/java/android/support/percent/BaseInstrumentationTestCase.java
diff --git a/percent/tests/java/android/support/percent/BaseTestActivity.java b/percent/src/androidTest/java/android/support/percent/BaseTestActivity.java
similarity index 100%
rename from percent/tests/java/android/support/percent/BaseTestActivity.java
rename to percent/src/androidTest/java/android/support/percent/BaseTestActivity.java
diff --git a/percent/tests/java/android/support/percent/LayoutDirectionActions.java b/percent/src/androidTest/java/android/support/percent/LayoutDirectionActions.java
similarity index 100%
rename from percent/tests/java/android/support/percent/LayoutDirectionActions.java
rename to percent/src/androidTest/java/android/support/percent/LayoutDirectionActions.java
diff --git a/percent/tests/java/android/support/percent/PercentDynamicLayoutActivity.java b/percent/src/androidTest/java/android/support/percent/PercentDynamicLayoutActivity.java
similarity index 100%
rename from percent/tests/java/android/support/percent/PercentDynamicLayoutActivity.java
rename to percent/src/androidTest/java/android/support/percent/PercentDynamicLayoutActivity.java
diff --git a/percent/tests/java/android/support/percent/PercentDynamicLayoutTest.java b/percent/src/androidTest/java/android/support/percent/PercentDynamicLayoutTest.java
similarity index 100%
rename from percent/tests/java/android/support/percent/PercentDynamicLayoutTest.java
rename to percent/src/androidTest/java/android/support/percent/PercentDynamicLayoutTest.java
diff --git a/percent/tests/java/android/support/percent/PercentFrameTest.java b/percent/src/androidTest/java/android/support/percent/PercentFrameTest.java
similarity index 100%
rename from percent/tests/java/android/support/percent/PercentFrameTest.java
rename to percent/src/androidTest/java/android/support/percent/PercentFrameTest.java
diff --git a/percent/tests/java/android/support/percent/PercentRelativeRtlTest.java b/percent/src/androidTest/java/android/support/percent/PercentRelativeRtlTest.java
similarity index 100%
rename from percent/tests/java/android/support/percent/PercentRelativeRtlTest.java
rename to percent/src/androidTest/java/android/support/percent/PercentRelativeRtlTest.java
diff --git a/percent/tests/java/android/support/percent/PercentRelativeTest.java b/percent/src/androidTest/java/android/support/percent/PercentRelativeTest.java
similarity index 100%
rename from percent/tests/java/android/support/percent/PercentRelativeTest.java
rename to percent/src/androidTest/java/android/support/percent/PercentRelativeTest.java
diff --git a/percent/tests/java/android/support/percent/TestFrameActivity.java b/percent/src/androidTest/java/android/support/percent/TestFrameActivity.java
similarity index 100%
rename from percent/tests/java/android/support/percent/TestFrameActivity.java
rename to percent/src/androidTest/java/android/support/percent/TestFrameActivity.java
diff --git a/percent/tests/java/android/support/percent/TestRelativeActivity.java b/percent/src/androidTest/java/android/support/percent/TestRelativeActivity.java
similarity index 100%
rename from percent/tests/java/android/support/percent/TestRelativeActivity.java
rename to percent/src/androidTest/java/android/support/percent/TestRelativeActivity.java
diff --git a/percent/tests/java/android/support/percent/TestRelativeRtlActivity.java b/percent/src/androidTest/java/android/support/percent/TestRelativeRtlActivity.java
similarity index 100%
rename from percent/tests/java/android/support/percent/TestRelativeRtlActivity.java
rename to percent/src/androidTest/java/android/support/percent/TestRelativeRtlActivity.java
diff --git a/percent/tests/res/layout/percent_dynamic_layout.xml b/percent/src/androidTest/res/layout/percent_dynamic_layout.xml
similarity index 100%
rename from percent/tests/res/layout/percent_dynamic_layout.xml
rename to percent/src/androidTest/res/layout/percent_dynamic_layout.xml
diff --git a/percent/tests/res/layout/percent_frame_layout.xml b/percent/src/androidTest/res/layout/percent_frame_layout.xml
similarity index 100%
rename from percent/tests/res/layout/percent_frame_layout.xml
rename to percent/src/androidTest/res/layout/percent_frame_layout.xml
diff --git a/percent/tests/res/layout/percent_frame_layout_hpaddings.xml b/percent/src/androidTest/res/layout/percent_frame_layout_hpaddings.xml
similarity index 100%
rename from percent/tests/res/layout/percent_frame_layout_hpaddings.xml
rename to percent/src/androidTest/res/layout/percent_frame_layout_hpaddings.xml
diff --git a/percent/tests/res/layout/percent_frame_layout_vpaddings.xml b/percent/src/androidTest/res/layout/percent_frame_layout_vpaddings.xml
similarity index 100%
rename from percent/tests/res/layout/percent_frame_layout_vpaddings.xml
rename to percent/src/androidTest/res/layout/percent_frame_layout_vpaddings.xml
diff --git a/percent/tests/res/layout/percent_relative_layout.xml b/percent/src/androidTest/res/layout/percent_relative_layout.xml
similarity index 100%
rename from percent/tests/res/layout/percent_relative_layout.xml
rename to percent/src/androidTest/res/layout/percent_relative_layout.xml
diff --git a/percent/tests/res/layout/percent_relative_layout_hpaddings.xml b/percent/src/androidTest/res/layout/percent_relative_layout_hpaddings.xml
similarity index 100%
rename from percent/tests/res/layout/percent_relative_layout_hpaddings.xml
rename to percent/src/androidTest/res/layout/percent_relative_layout_hpaddings.xml
diff --git a/percent/tests/res/layout/percent_relative_layout_rtl.xml b/percent/src/androidTest/res/layout/percent_relative_layout_rtl.xml
similarity index 100%
rename from percent/tests/res/layout/percent_relative_layout_rtl.xml
rename to percent/src/androidTest/res/layout/percent_relative_layout_rtl.xml
diff --git a/percent/tests/res/layout/percent_relative_layout_vpaddings.xml b/percent/src/androidTest/res/layout/percent_relative_layout_vpaddings.xml
similarity index 100%
rename from percent/tests/res/layout/percent_relative_layout_vpaddings.xml
rename to percent/src/androidTest/res/layout/percent_relative_layout_vpaddings.xml
diff --git a/percent/src/main/AndroidManifest.xml b/percent/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4c32f76
--- /dev/null
+++ b/percent/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.percent"/>
diff --git a/percent/tests/NO_DOCS b/percent/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/percent/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/preference-leanback/Android.mk b/preference-leanback/Android.mk
deleted file mode 100644
index e2ad1de..0000000
--- a/preference-leanback/Android.mk
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v17-preference-leanback \
-#       android-support-v17-leanback \
-#       android-support-v14-preference \
-#       android-support-v7-preference \
-#       android-support-v7-appcompat \
-#       android-support-v7-recyclerview \
-#       android-support-v4
-#
-# in their makefiles to include the resources in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE := android-support-v17-preference-leanback
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,api21) \
-    $(call all-java-files-under,src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v17-leanback \
-    android-support-v14-preference \
-    android-support-v7-preference \
-    android-support-v7-appcompat \
-    android-support-v7-recyclerview \
-    android-support-v4
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/preference-leanback/AndroidManifest.xml b/preference-leanback/AndroidManifest.xml
deleted file mode 100644
index 028f582..0000000
--- a/preference-leanback/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v17.preference">
-    <uses-sdk android:minSdkVersion="17" />
-</manifest>
diff --git a/preference-leanback/build.gradle b/preference-leanback/build.gradle
index c5fb9f5..fc88f28 100644
--- a/preference-leanback/build.gradle
+++ b/preference-leanback/build.gradle
@@ -16,11 +16,9 @@
 
 android {
     sourceSets {
-        main.java.srcDirs = [
-                'api21',
-                'src'
+        main.java.srcDirs += [
+                'api21'
         ]
-        main.res.srcDir 'res'
     }
 }
 
@@ -31,6 +29,5 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Leanback Preference v17"
-    legacySourceLocation = true
     minSdkVersion = 17
 }
\ No newline at end of file
diff --git a/preference-leanback/src/main/AndroidManifest.xml b/preference-leanback/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..c643474
--- /dev/null
+++ b/preference-leanback/src/main/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest package="android.support.v17.preference"/>
diff --git a/preference-leanback/src/android/support/v17/preference/BaseLeanbackPreferenceFragment.java b/preference-leanback/src/main/java/android/support/v17/preference/BaseLeanbackPreferenceFragment.java
similarity index 100%
rename from preference-leanback/src/android/support/v17/preference/BaseLeanbackPreferenceFragment.java
rename to preference-leanback/src/main/java/android/support/v17/preference/BaseLeanbackPreferenceFragment.java
diff --git a/preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java b/preference-leanback/src/main/java/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
similarity index 100%
rename from preference-leanback/src/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
rename to preference-leanback/src/main/java/android/support/v17/preference/LeanbackListPreferenceDialogFragment.java
diff --git a/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java b/preference-leanback/src/main/java/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
similarity index 100%
rename from preference-leanback/src/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
rename to preference-leanback/src/main/java/android/support/v17/preference/LeanbackPreferenceDialogFragment.java
diff --git a/preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java b/preference-leanback/src/main/java/android/support/v17/preference/LeanbackPreferenceFragment.java
similarity index 100%
rename from preference-leanback/src/android/support/v17/preference/LeanbackPreferenceFragment.java
rename to preference-leanback/src/main/java/android/support/v17/preference/LeanbackPreferenceFragment.java
diff --git a/preference-leanback/src/android/support/v17/preference/LeanbackSettingsFragment.java b/preference-leanback/src/main/java/android/support/v17/preference/LeanbackSettingsFragment.java
similarity index 100%
rename from preference-leanback/src/android/support/v17/preference/LeanbackSettingsFragment.java
rename to preference-leanback/src/main/java/android/support/v17/preference/LeanbackSettingsFragment.java
diff --git a/preference-leanback/src/android/support/v17/preference/LeanbackSettingsRootView.java b/preference-leanback/src/main/java/android/support/v17/preference/LeanbackSettingsRootView.java
similarity index 100%
rename from preference-leanback/src/android/support/v17/preference/LeanbackSettingsRootView.java
rename to preference-leanback/src/main/java/android/support/v17/preference/LeanbackSettingsRootView.java
diff --git a/preference-leanback/res/color/lb_preference_item_primary_text_color.xml b/preference-leanback/src/main/res/color/lb_preference_item_primary_text_color.xml
similarity index 100%
rename from preference-leanback/res/color/lb_preference_item_primary_text_color.xml
rename to preference-leanback/src/main/res/color/lb_preference_item_primary_text_color.xml
diff --git a/preference-leanback/res/color/lb_preference_item_secondary_text_color.xml b/preference-leanback/src/main/res/color/lb_preference_item_secondary_text_color.xml
similarity index 100%
rename from preference-leanback/res/color/lb_preference_item_secondary_text_color.xml
rename to preference-leanback/src/main/res/color/lb_preference_item_secondary_text_color.xml
diff --git a/preference-leanback/res/layout-v21/leanback_preference_category.xml b/preference-leanback/src/main/res/layout-v21/leanback_preference_category.xml
similarity index 100%
rename from preference-leanback/res/layout-v21/leanback_preference_category.xml
rename to preference-leanback/src/main/res/layout-v21/leanback_preference_category.xml
diff --git a/preference-leanback/res/layout-v21/leanback_settings_fragment.xml b/preference-leanback/src/main/res/layout-v21/leanback_settings_fragment.xml
similarity index 100%
rename from preference-leanback/res/layout-v21/leanback_settings_fragment.xml
rename to preference-leanback/src/main/res/layout-v21/leanback_settings_fragment.xml
diff --git a/preference-leanback/res/layout/leanback_list_preference_fragment.xml b/preference-leanback/src/main/res/layout/leanback_list_preference_fragment.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_list_preference_fragment.xml
rename to preference-leanback/src/main/res/layout/leanback_list_preference_fragment.xml
diff --git a/preference-leanback/res/layout/leanback_list_preference_item_multi.xml b/preference-leanback/src/main/res/layout/leanback_list_preference_item_multi.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_list_preference_item_multi.xml
rename to preference-leanback/src/main/res/layout/leanback_list_preference_item_multi.xml
diff --git a/preference-leanback/res/layout/leanback_list_preference_item_single.xml b/preference-leanback/src/main/res/layout/leanback_list_preference_item_single.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_list_preference_item_single.xml
rename to preference-leanback/src/main/res/layout/leanback_list_preference_item_single.xml
diff --git a/preference-leanback/res/layout/leanback_preference.xml b/preference-leanback/src/main/res/layout/leanback_preference.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_preference.xml
rename to preference-leanback/src/main/res/layout/leanback_preference.xml
diff --git a/preference-leanback/res/layout/leanback_preference_category.xml b/preference-leanback/src/main/res/layout/leanback_preference_category.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_preference_category.xml
rename to preference-leanback/src/main/res/layout/leanback_preference_category.xml
diff --git a/preference-leanback/res/layout/leanback_preference_fragment.xml b/preference-leanback/src/main/res/layout/leanback_preference_fragment.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_preference_fragment.xml
rename to preference-leanback/src/main/res/layout/leanback_preference_fragment.xml
diff --git a/preference-leanback/res/layout/leanback_preference_information.xml b/preference-leanback/src/main/res/layout/leanback_preference_information.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_preference_information.xml
rename to preference-leanback/src/main/res/layout/leanback_preference_information.xml
diff --git a/preference-leanback/res/layout/leanback_preference_widget_seekbar.xml b/preference-leanback/src/main/res/layout/leanback_preference_widget_seekbar.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_preference_widget_seekbar.xml
rename to preference-leanback/src/main/res/layout/leanback_preference_widget_seekbar.xml
diff --git a/preference-leanback/res/layout/leanback_preferences_list.xml b/preference-leanback/src/main/res/layout/leanback_preferences_list.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_preferences_list.xml
rename to preference-leanback/src/main/res/layout/leanback_preferences_list.xml
diff --git a/preference-leanback/res/layout/leanback_settings_fragment.xml b/preference-leanback/src/main/res/layout/leanback_settings_fragment.xml
similarity index 100%
rename from preference-leanback/res/layout/leanback_settings_fragment.xml
rename to preference-leanback/src/main/res/layout/leanback_settings_fragment.xml
diff --git a/preference-leanback/res/values/colors.xml b/preference-leanback/src/main/res/values/colors.xml
similarity index 100%
rename from preference-leanback/res/values/colors.xml
rename to preference-leanback/src/main/res/values/colors.xml
diff --git a/preference-leanback/res/values/dimens.xml b/preference-leanback/src/main/res/values/dimens.xml
similarity index 100%
rename from preference-leanback/res/values/dimens.xml
rename to preference-leanback/src/main/res/values/dimens.xml
diff --git a/preference-leanback/res/values/styles.xml b/preference-leanback/src/main/res/values/styles.xml
similarity index 100%
rename from preference-leanback/res/values/styles.xml
rename to preference-leanback/src/main/res/values/styles.xml
diff --git a/preference-leanback/res/values/themes.xml b/preference-leanback/src/main/res/values/themes.xml
similarity index 100%
rename from preference-leanback/res/values/themes.xml
rename to preference-leanback/src/main/res/values/themes.xml
diff --git a/core-utils/src/main/java/android/support/v4/print/OWNERS b/print/OWNERS
similarity index 100%
rename from core-utils/src/main/java/android/support/v4/print/OWNERS
rename to print/OWNERS
diff --git a/print/api/current.txt b/print/api/current.txt
new file mode 100644
index 0000000..5277150
--- /dev/null
+++ b/print/api/current.txt
@@ -0,0 +1,29 @@
+package android.support.v4.print {
+
+  public final class PrintHelper {
+    ctor public PrintHelper(android.content.Context);
+    method public int getColorMode();
+    method public int getOrientation();
+    method public int getScaleMode();
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap);
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap, android.support.v4.print.PrintHelper.OnPrintFinishCallback);
+    method public void printBitmap(java.lang.String, android.net.Uri) throws java.io.FileNotFoundException;
+    method public void printBitmap(java.lang.String, android.net.Uri, android.support.v4.print.PrintHelper.OnPrintFinishCallback) throws java.io.FileNotFoundException;
+    method public void setColorMode(int);
+    method public void setOrientation(int);
+    method public void setScaleMode(int);
+    method public static boolean systemSupportsPrint();
+    field public static final int COLOR_MODE_COLOR = 2; // 0x2
+    field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
+    field public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
+    field public static final int ORIENTATION_PORTRAIT = 2; // 0x2
+    field public static final int SCALE_MODE_FILL = 2; // 0x2
+    field public static final int SCALE_MODE_FIT = 1; // 0x1
+  }
+
+  public static abstract interface PrintHelper.OnPrintFinishCallback {
+    method public abstract void onFinish();
+  }
+
+}
+
diff --git a/print/build.gradle b/print/build.gradle
new file mode 100644
index 0000000..78fc9db
--- /dev/null
+++ b/print/build.gradle
@@ -0,0 +1,19 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+}
+
+supportLibrary {
+    name = "Android Support Library Print"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/print/src/main/AndroidManifest.xml b/print/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..bccf7e2
--- /dev/null
+++ b/print/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.print"/>
diff --git a/core-utils/java/android/support/v4/print/PrintHelper.java b/print/src/main/java/android/support/v4/print/PrintHelper.java
similarity index 100%
rename from core-utils/java/android/support/v4/print/PrintHelper.java
rename to print/src/main/java/android/support/v4/print/PrintHelper.java
diff --git a/recommendation/Android.mk b/recommendation/Android.mk
deleted file mode 100644
index 6249df7..0000000
--- a/recommendation/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must include it with
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-recommendation \
-#       android-support-v4
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-recommendation
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v4
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/recommendation/AndroidManifest.xml b/recommendation/AndroidManifest.xml
deleted file mode 100644
index 98e1ae9..0000000
--- a/recommendation/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.recommendation">
-    <uses-sdk android:minSdkVersion="21"/>
-</manifest>
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index bf2265d..b401eb8 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -16,6 +16,5 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Recommendation"
-    legacySourceLocation = true
     minSdkVersion = 21
 }
diff --git a/recommendation/src/main/AndroidManifest.xml b/recommendation/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..8a11dee
--- /dev/null
+++ b/recommendation/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.recommendation"/>
diff --git a/recyclerview-selection/Android.mk b/recyclerview-selection/Android.mk
deleted file mode 100644
index 511806f..0000000
--- a/recyclerview-selection/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-recyclerview-selection
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v7-recyclerview \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/recyclerview-selection/AndroidManifest.xml b/recyclerview-selection/AndroidManifest.xml
deleted file mode 100644
index 544b837..0000000
--- a/recyclerview-selection/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="androidx.widget.recyclerview.selection">
-    <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/recyclerview-selection/build.gradle b/recyclerview-selection/build.gradle
index d468582..c0915bc 100644
--- a/recyclerview-selection/build.gradle
+++ b/recyclerview-selection/build.gradle
@@ -23,9 +23,9 @@
 }
 
 dependencies {
-    api project(':recyclerview-v7')
-    api project(':support-annotations')
-    api project(':support-compat')
+    api(project(":recyclerview-v7"))
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
 
     androidTestImplementation(TEST_RUNNER)
     androidTestImplementation(ESPRESSO_CORE)
@@ -34,21 +34,11 @@
     androidTestImplementation(JUNIT)
 }
 
-android {
-    defaultConfig {
-        minSdkVersion 14
-    }
-    sourceSets {
-        main.res.srcDirs 'res', 'res-public'
-    }
-}
-
 supportLibrary {
-    name 'Android RecyclerView Selection'
-    publish false
+    name = "Android RecyclerView Selection"
+    publish = false
     mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
-    inceptionYear '2017'
-    description 'Library providing item selection framework for RecyclerView. Support for touch based and band selection is provided.'
-    legacySourceLocation true
+    inceptionYear = "2017"
+    description = "Library providing item selection framework for RecyclerView. Support for touch based and band selection is provided."
 }
diff --git a/recyclerview-selection/src/androidTest/AndroidManifest.xml b/recyclerview-selection/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..01f1904
--- /dev/null
+++ b/recyclerview-selection/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.widget.recyclerview.selection.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <application android:supportsRtl="true">
+    </application>
+</manifest>
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/BandSelectionHelperTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/BandSelectionHelperTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/BandSelectionHelperTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/BandSelectionHelperTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/DefaultSelectionTrackerTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/DefaultSelectionTrackerTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/DefaultSelectionTrackerTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/DefaultSelectionTrackerTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/DefaultSelectionTracker_SingleSelectTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/DefaultSelectionTracker_SingleSelectTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/DefaultSelectionTracker_SingleSelectTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/DefaultSelectionTracker_SingleSelectTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GestureRouterTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GestureRouterTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GestureRouterTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GestureRouterTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GestureSelectionHelperTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GestureSelectionHelperTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GestureSelectionHelperTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GestureSelectionHelperTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GestureSelectionHelper_RecyclerViewDelegateTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GridModelTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GridModelTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/GridModelTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/GridModelTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/MouseInputHandlerTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/MouseInputHandlerTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/MouseInputHandlerTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/MouseInputHandlerTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/MouseInputHandler_RangeTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/MouseInputHandler_RangeTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/MouseInputHandler_RangeTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/MouseInputHandler_RangeTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/OperationMonitorTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/OperationMonitorTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/OperationMonitorTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/OperationMonitorTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/RangeTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/RangeTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/RangeTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/RangeTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/SelectionTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/SelectionTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/SelectionTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/SelectionTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/SelectionTracker_InstanceStateTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/SelectionTracker_InstanceStateTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/SelectionTracker_InstanceStateTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/SelectionTracker_InstanceStateTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/StorageStrategy_LongTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/StorageStrategy_LongTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/StorageStrategy_LongTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/StorageStrategy_LongTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/StorageStrategy_ParcelableTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/StorageStrategy_ParcelableTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/StorageStrategy_ParcelableTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/StorageStrategy_ParcelableTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/StorageStrategy_StringTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/StorageStrategy_StringTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/StorageStrategy_StringTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/StorageStrategy_StringTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/TouchInputHandlerTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/TouchInputHandlerTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/TouchInputHandlerTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/TouchInputHandlerTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/ViewAutoScrollerTest.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/ViewAutoScrollerTest.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/ViewAutoScrollerTest.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/ViewAutoScrollerTest.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/Bundles.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/Bundles.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/Bundles.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/Bundles.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/SelectionProbe.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/SelectionProbe.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/SelectionProbe.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/SelectionProbe.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/SelectionTrackers.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/SelectionTrackers.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/SelectionTrackers.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/SelectionTrackers.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestAdapter.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestAdapter.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestAdapter.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestAdapter.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestAutoScroller.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestAutoScroller.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestAutoScroller.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestAutoScroller.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestBandPredicate.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestBandPredicate.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestBandPredicate.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestBandPredicate.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestData.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestData.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestData.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestData.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestEvents.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestEvents.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestEvents.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestEvents.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestFocusDelegate.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestFocusDelegate.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestFocusDelegate.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestFocusDelegate.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestHolder.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestHolder.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestHolder.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestHolder.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestItemDetails.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestItemDetails.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestItemDetails.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestItemDetails.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestItemDetailsLookup.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestItemDetailsLookup.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestItemDetailsLookup.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestItemDetailsLookup.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestItemKeyProvider.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestItemKeyProvider.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestItemKeyProvider.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestItemKeyProvider.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestOnContextClickListener.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestOnContextClickListener.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestOnContextClickListener.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestOnContextClickListener.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestOnItemActivatedListener.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestOnItemActivatedListener.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestOnItemActivatedListener.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestOnItemActivatedListener.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestRunnable.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestRunnable.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestRunnable.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestRunnable.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestSelectionObserver.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestSelectionObserver.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestSelectionObserver.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestSelectionObserver.java
diff --git a/recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestSelectionPredicate.java b/recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestSelectionPredicate.java
similarity index 100%
rename from recyclerview-selection/tests/java/androidx/widget/recyclerview/selection/testing/TestSelectionPredicate.java
rename to recyclerview-selection/src/androidTest/java/androidx/widget/recyclerview/selection/testing/TestSelectionPredicate.java
diff --git a/recyclerview-selection/src/main/AndroidManifest.xml b/recyclerview-selection/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..95b01b0
--- /dev/null
+++ b/recyclerview-selection/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="androidx.widget.recyclerview.selection"/>
diff --git a/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/ToolHandlerRegistry.java b/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/ToolHandlerRegistry.java
index d474964..a368efb 100644
--- a/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/ToolHandlerRegistry.java
+++ b/recyclerview-selection/src/main/java/androidx/widget/recyclerview/selection/ToolHandlerRegistry.java
@@ -39,7 +39,7 @@
     // highest value. UNKNOWN is zero, so we add one. This allows delegates to be
     // registered by type, and avoid the auto-boxing that would be necessary were we
     // to store delegates in a Map<Integer, Delegate>.
-    private static final int sNumInputTypes = MotionEvent.TOOL_TYPE_ERASER + 1;
+    private static final int NUM_INPUT_TYPES = MotionEvent.TOOL_TYPE_ERASER + 1;
 
     private final List<T> mHandlers = Arrays.asList(null, null, null, null, null);
     private final T mDefault;
@@ -49,7 +49,7 @@
         mDefault = defaultDelegate;
 
         // Initialize all values to null.
-        for (int i = 0; i < sNumInputTypes; i++) {
+        for (int i = 0; i < NUM_INPUT_TYPES; i++) {
             mHandlers.set(i, null);
         }
     }
diff --git a/recyclerview-selection/res/drawable/selection_band_overlay.xml b/recyclerview-selection/src/main/res/drawable/selection_band_overlay.xml
similarity index 100%
rename from recyclerview-selection/res/drawable/selection_band_overlay.xml
rename to recyclerview-selection/src/main/res/drawable/selection_band_overlay.xml
diff --git a/recyclerview-selection/tests/AndroidManifest.xml b/recyclerview-selection/tests/AndroidManifest.xml
deleted file mode 100644
index 144adb5..0000000
--- a/recyclerview-selection/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright 2017 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
-          package="androidx.widget.recyclerview.selection.test">
-    <uses-sdk android:minSdkVersion="14" />
-
-    <application android:supportsRtl="true">
-    </application>
-</manifest>
diff --git a/recyclerview-selection/tests/NO_DOCS b/recyclerview-selection/tests/NO_DOCS
deleted file mode 100644
index 61c9b1a..0000000
--- a/recyclerview-selection/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java
index dff2940..ba78fe8 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/NestedRecyclerViewActivity.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Color;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
 import android.support.v7.widget.DividerItemDecoration;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -135,7 +136,7 @@
         }
 
         @Override
-        public void onViewRecycled(ViewHolder holder) {
+        public void onViewRecycled(@NonNull ViewHolder holder) {
             mSavedStates.set(holder.getAdapterPosition(),
                     holder.mRecyclerView.getLayoutManager().onSaveInstanceState());
         }
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/PopupMenuActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/PopupMenuActivity.java
index fa59903..d8620b2 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/PopupMenuActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/PopupMenuActivity.java
@@ -17,11 +17,14 @@
 package com.example.android.supportv7.widget;
 
 import android.os.Bundle;
+import android.support.v4.view.MenuCompat;
 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.ContextMenu;
 import android.view.Gravity;
+import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
@@ -68,7 +71,7 @@
                 }
 
                 final MenuInflater menuInflater = popupMenu.getMenuInflater();
-                menuInflater.inflate(R.menu.popup_menu, popupMenu.getMenu());
+                populateMenu(menuInflater, popupMenu.getMenu());
                 final MenuItem editItem = popupMenu.getMenu().findItem(R.id.action_edit);
                 MenuItemCompat.setContentDescription(editItem,
                         getString(R.string.popup_menu_edit_description));
@@ -97,6 +100,20 @@
                 popupMenu.show();
             }
         });
+        // Long tap will show a context menu which is always a platform (not support) menu.
+        registerForContextMenu(button);
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu menu, View v,
+            ContextMenu.ContextMenuInfo menuInfo) {
+        populateMenu(getMenuInflater(), menu);
+    }
+
+    private void populateMenu(MenuInflater menuInflater, Menu menu) {
+        SwitchCompat dividersToggle = findViewById(R.id.dividers_toggle);
+        menuInflater.inflate(R.menu.popup_menu, menu);
+        MenuCompat.setGroupDividerEnabled(menu, dividersToggle.isChecked());
     }
 
     private void addToLog(String toLog) {
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/touch/ItemTouchHelperActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/touch/ItemTouchHelperActivity.java
index 679af89..e2b5643 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/touch/ItemTouchHelperActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/touch/ItemTouchHelperActivity.java
@@ -16,14 +16,11 @@
 
 package com.example.android.supportv7.widget.touch;
 
-import com.example.android.supportv7.Cheeses;
-import com.example.android.supportv7.R;
-import com.example.android.supportv7.widget.util.ConfigToggle;
-import com.example.android.supportv7.widget.util.ConfigViewHolder;
-
 import android.app.Activity;
 import android.graphics.Canvas;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v7.widget.CardView;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -34,6 +31,11 @@
 import android.widget.Button;
 import android.widget.TextView;
 
+import com.example.android.supportv7.Cheeses;
+import com.example.android.supportv7.R;
+import com.example.android.supportv7.widget.util.ConfigToggle;
+import com.example.android.supportv7.widget.util.ConfigViewHolder;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -103,32 +105,34 @@
     public ItemTouchHelper.Callback createCallback() {
         return new ItemTouchHelper.Callback() {
             @Override
-            public int getMovementFlags(RecyclerView recyclerView,
-                    RecyclerView.ViewHolder viewHolder) {
+            public int getMovementFlags(@NonNull RecyclerView recyclerView,
+                    @NonNull RecyclerView.ViewHolder viewHolder) {
                 return ItemTouchHelperActivity.this.getMovementFlags(recyclerView, viewHolder);
             }
 
             @Override
-            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
-                    RecyclerView.ViewHolder target) {
+            public boolean onMove(@NonNull RecyclerView recyclerView,
+                    @NonNull RecyclerView.ViewHolder viewHolder,
+                    @NonNull RecyclerView.ViewHolder target) {
                 mAdapter.move(viewHolder.getAdapterPosition(), target.getAdapterPosition());
                 return true;
             }
 
             @Override
-            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
+            public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
                 mAdapter.delete(viewHolder.getAdapterPosition());
             }
 
             @Override
-            public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+            public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder,
+                    int actionState) {
                 super.onSelectedChanged(viewHolder, actionState);
                 ItemTouchHelperActivity.this.onSelectedChanged(viewHolder, actionState);
             }
 
             @Override
-            public void onChildDraw(Canvas c, RecyclerView recyclerView,
-                    RecyclerView.ViewHolder viewHolder,
+            public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
+                    @NonNull RecyclerView.ViewHolder viewHolder,
                     float dX, float dY, int actionState, boolean isCurrentlyActive) {
                 if (ItemTouchHelperActivity.this.onChildDraw(c, recyclerView, viewHolder,
                         dX, dY, actionState, isCurrentlyActive)) {
@@ -139,7 +143,7 @@
             }
 
             @Override
-            public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
+            public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
                     RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
                     boolean isCurrentlyActive) {
                 if (ItemTouchHelperActivity.this.onChildDrawOver(c, recyclerView, viewHolder,
@@ -161,7 +165,8 @@
             }
 
             @Override
-            public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+            public void clearView(@NonNull RecyclerView recyclerView,
+                    @NonNull RecyclerView.ViewHolder viewHolder) {
                 super.clearView(recyclerView, viewHolder);
                 ItemTouchHelperActivity.this.clearView(viewHolder);
             }
@@ -203,10 +208,9 @@
     }
 
     public ItemTouchViewHolder onCreateViewHolder(ViewGroup parent) {
-        ItemTouchViewHolder itemTouchViewHolder = new ItemTouchViewHolder(
+        return new ItemTouchViewHolder(
                 LayoutInflater.from(parent.getContext())
                         .inflate(R.layout.touch_item, parent, false));
-        return itemTouchViewHolder;
     }
 
     abstract public int getMovementFlags(RecyclerView recyclerView,
diff --git a/samples/Support7Demos/src/main/res/layout/popup_menu_activity.xml b/samples/Support7Demos/src/main/res/layout/popup_menu_activity.xml
index 552a996..136a4c3 100644
--- a/samples/Support7Demos/src/main/res/layout/popup_menu_activity.xml
+++ b/samples/Support7Demos/src/main/res/layout/popup_menu_activity.xml
@@ -37,6 +37,16 @@
         android:checked="true"
         android:text="@string/popup_default_elevation" />
 
+    <android.support.v7.widget.SwitchCompat
+        android:id="@+id/dividers_toggle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/elevation_toggle"
+        android:layout_marginLeft="8dp"
+        android:layout_marginRight="8dp"
+        android:checked="true"
+        android:text="@string/popup_group_dividers" />
+
     <TextView
         android:id="@+id/log"
         android:layout_width="match_parent"
diff --git a/samples/Support7Demos/src/main/res/menu/popup_menu.xml b/samples/Support7Demos/src/main/res/menu/popup_menu.xml
index 09d3bfa..c4ed632 100644
--- a/samples/Support7Demos/src/main/res/menu/popup_menu.xml
+++ b/samples/Support7Demos/src/main/res/menu/popup_menu.xml
@@ -19,12 +19,15 @@
           android:title="@string/popup_menu_highlight"
           app:contentDescription="@string/popup_menu_highlight_description"
           app:tooltipText="@string/popup_menu_highlight_tooltip" />
-    <item android:id="@+id/action_edit"
-          android:title="@string/popup_menu_edit" />
-    <item android:id="@+id/action_delete"
-          android:title="@string/popup_menu_delete" />
+    <group android:id="@+id/group1">
+        <item android:id="@+id/action_edit"
+              android:title="@string/popup_menu_edit" />
+        <item android:id="@+id/action_delete"
+              android:title="@string/popup_menu_delete" />
+    </group>
     <item android:id="@+id/action_ignore"
-          android:title="@string/popup_menu_ignore" />
+          android:title="@string/popup_menu_ignore"
+          android:checkable="true" />
     <item android:id="@+id/action_share"
           android:title="@string/popup_menu_share">
         <menu>
diff --git a/samples/Support7Demos/src/main/res/values/strings.xml b/samples/Support7Demos/src/main/res/values/strings.xml
index 8f6f37c..d93f0b0 100644
--- a/samples/Support7Demos/src/main/res/values/strings.xml
+++ b/samples/Support7Demos/src/main/res/values/strings.xml
@@ -247,4 +247,5 @@
     <string name="text_link_disabled">With <a href="http://www.google.com">link</a> disabled</string>
 
     <string name="menu_item_icon_tinting">AppCompat/Menu Item Icons</string>
+    <string name="popup_group_dividers">Display group dividers</string>
 </resources>
diff --git a/samples/SupportContentDemos/build.gradle b/samples/SupportContentDemos/build.gradle
index ad52f77..d2b55f9 100644
--- a/samples/SupportContentDemos/build.gradle
+++ b/samples/SupportContentDemos/build.gradle
@@ -19,7 +19,9 @@
 }
 
 dependencies {
-    implementation(project(":design"))
+    implementation("com.android.support:design:28.0.0-SNAPSHOT", { transitive = false })
+    implementation(project(":transition"))
+    implementation(project(":recyclerview-v7"))
     implementation(project(":appcompat-v7"))
     implementation(project(":support-content"))
 }
diff --git a/samples/SupportDesignDemos/build.gradle b/samples/SupportDesignDemos/build.gradle
index 89dc8b0..51d6884 100644
--- a/samples/SupportDesignDemos/build.gradle
+++ b/samples/SupportDesignDemos/build.gradle
@@ -3,7 +3,10 @@
 }
 
 dependencies {
-    implementation(project(":design"))
+    implementation("com.android.support:design:28.0.0-SNAPSHOT", { transitive = false })
+    implementation(project(":transition"))
+    implementation(project(":recyclerview-v7"))
+    implementation(project(":appcompat-v7"))
 }
 
 android {
diff --git a/samples/SupportDesignDemos/proguard.flags b/samples/SupportDesignDemos/proguard.flags
deleted file mode 100644
index 9ebd737..0000000
--- a/samples/SupportDesignDemos/proguard.flags
+++ /dev/null
@@ -1,7 +0,0 @@
--keep public class * extends android.support.design.widget.CoordinatorLayout$Behavior {
-    public <init>(android.content.Context, android.util.AttributeSet);
-}
-
--keep public class * extends android.support.v7.widget.LinearLayoutManager {
-    public <init>(android.content.Context, android.util.AttributeSet, int, int);
-}
diff --git a/samples/SupportPreferenceDemos/proguard.flags b/samples/SupportPreferenceDemos/proguard.flags
deleted file mode 100644
index 9ebd737..0000000
--- a/samples/SupportPreferenceDemos/proguard.flags
+++ /dev/null
@@ -1,7 +0,0 @@
--keep public class * extends android.support.design.widget.CoordinatorLayout$Behavior {
-    public <init>(android.content.Context, android.util.AttributeSet);
-}
-
--keep public class * extends android.support.v7.widget.LinearLayoutManager {
-    public <init>(android.content.Context, android.util.AttributeSet, int, int);
-}
diff --git a/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml b/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml
index f469af2..4d1dca7 100644
--- a/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml
+++ b/samples/SupportPreferenceDemos/src/main/res/xml/preferences.xml
@@ -31,6 +31,12 @@
         android:title="@string/title_stylish_preference"
         android:summary="@string/summary_stylish_preference" />
 
+    <Preference
+        android:key="preference_with_icon"
+        android:title="Preference with icon"
+        android:summary="This preference has an icon"
+        android:icon="@android:drawable/ic_menu_camera" />
+
     <PreferenceCategory
         android:title="@string/inline_preferences">
 
@@ -39,6 +45,11 @@
             android:title="@string/title_checkbox_preference"
             android:summary="@string/summary_checkbox_preference" />
 
+        <SwitchPreference
+            android:key="switch_preference"
+            android:title="Switch preference"
+            android:summary="This is a switch" />
+
         <DropDownPreference
             android:key="dropdown_preference"
             android:title="@string/title_dropdown_preference"
diff --git a/samples/SupportSliceDemos/OWNERS b/samples/SupportSliceDemos/OWNERS
new file mode 100644
index 0000000..921a517
--- /dev/null
+++ b/samples/SupportSliceDemos/OWNERS
@@ -0,0 +1,2 @@
+jmonk@google.com
+madym@google.com
diff --git a/samples/SupportSliceDemos/build.gradle b/samples/SupportSliceDemos/build.gradle
new file mode 100644
index 0000000..a0b236d
--- /dev/null
+++ b/samples/SupportSliceDemos/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static android.support.dependencies.DependenciesKt.*
+
+plugins {
+    id("SupportAndroidTestAppPlugin")
+}
+
+dependencies {
+    implementation(project(":slices-view"))
+    implementation(project(":slices-builders"))
+    implementation(project(":slices-core"))
+    implementation("com.android.support:design:28.0.0-SNAPSHOT", { transitive = false })
+    implementation(project(":transition"))
+    implementation(project(":recyclerview-v7"))
+    implementation(project(":appcompat-v7"))
+    implementation(project(":cardview-v7"))
+    api(ARCH_LIFECYCLE_EXTENSIONS, libs.exclude_annotations_transitive)
+}
+
+android {
+    defaultConfig {
+        applicationId "com.example.androidx.slice.demos"
+    }
+}
+
+supportTestApp {
+    minSdkVersion = 26
+}
diff --git a/samples/SupportSliceDemos/src/main/AndroidManifest.xml b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5285c34
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/AndroidManifest.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:tools="http://schemas.android.com/tools"
+          package="com.example.androidx.slice.demos">
+
+    <uses-sdk tools:overrideLibrary="androidx.app.slice.view, androidx.app.slice.builders, androidx.app.slice.core" />
+
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.BIND_SLICE" />
+
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"
+        android:roundIcon="@mipmap/ic_launcher_round"
+        android:supportsRtl="true"
+        android:theme="@style/AppTheme">
+        <activity
+            android:name=".SliceBrowser"
+            android:label="@string/app_name"
+            android:theme="@style/AppTheme.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+            <intent-filter>
+                <action android:name="androidx.intent.SLICE_ACTION"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
+        <provider android:authorities="com.example.androidx.slice.demos"
+                  android:name=".SampleSliceProvider"
+                  android:grantUriPermissions="true">
+            <intent-filter>
+                <action android:name="androidx.intent.SLICE_ACTION"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </provider>
+
+        <receiver
+            android:name=".SliceBroadcastReceiver"
+            android:exported="true" >
+            <intent-filter>
+                <action android:name="com.example.androidx.slice.action.*"/>
+            </intent-filter>
+        </receiver>
+    </application>
+
+</manifest>
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
new file mode 100644
index 0000000..de764a1
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.androidx.slice.demos;
+
+import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
+
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.annotation.NonNull;
+import android.text.SpannableString;
+import android.text.format.DateUtils;
+import android.text.style.ForegroundColorSpan;
+
+import java.util.Calendar;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.builders.GridBuilder;
+import androidx.app.slice.builders.ListBuilder;
+import androidx.app.slice.builders.MessagingSliceBuilder;
+import androidx.app.slice.builders.SliceAction;
+
+/**
+ * Examples of using slice template builders.
+ */
+public class SampleSliceProvider extends SliceProvider {
+
+    public static final String ACTION_WIFI_CHANGED =
+            "com.example.androidx.slice.action.WIFI_CHANGED";
+    public static final String ACTION_TOAST =
+            "com.example.androidx.slice.action.TOAST";
+    public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE";
+    public static final String ACTION_TOAST_RANGE_VALUE =
+            "com.example.androidx.slice.action.TOAST_RANGE_VALUE";
+
+    public static final int LOADING_DELAY_MS = 4000;
+
+    public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
+            "toggle2", "contact", "gallery", "weather", "reservation", "loadlist", "loadlist2",
+            "loadgrid", "loadgrid2", "inputrange", "range"};
+
+    /**
+     * @return Uri with the provided path
+     */
+    public static Uri getUri(String path, Context context) {
+        return new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(context.getPackageName())
+                .appendPath(path)
+                .build();
+    }
+
+    @Override
+    public boolean onCreateSliceProvider() {
+        return true;
+    }
+
+    @NonNull
+    @Override
+    public Uri onMapIntentToUri(Intent intent) {
+        return getUri("wifi", getContext());
+    }
+
+    @Override
+    public Slice onBindSlice(Uri sliceUri) {
+        String path = sliceUri.getPath();
+        switch (path) {
+            // TODO: add list / grid slices with 'see more' options
+            case "/message":
+                return createMessagingSlice(sliceUri);
+            case "/wifi":
+                return createWifiSlice(sliceUri);
+            case "/note":
+                return createNoteSlice(sliceUri);
+            case "/ride":
+                return createRideSlice(sliceUri);
+            case "/toggle":
+                return createCustomToggleSlice(sliceUri);
+            case "/toggle2":
+                return createTwoCustomToggleSlices(sliceUri);
+            case "/contact":
+                return createContact(sliceUri);
+            case "/gallery":
+                return createGallery(sliceUri);
+            case "/weather":
+                return createWeather(sliceUri);
+            case "/reservation":
+                return createReservationSlice(sliceUri);
+            case "/loadlist":
+                return createLoadingSlice(sliceUri, false /* loadAll */, true /* isList */);
+            case "/loadlist2":
+                return createLoadingSlice(sliceUri, true /* loadAll */, true /* isList */);
+            case "/loadgrid":
+                return createLoadingSlice(sliceUri, false /* loadAll */, false /* isList */);
+            case "/loadgrid2":
+                return createLoadingSlice(sliceUri, true /* loadAll */, false /* isList */);
+            case "/inputrange":
+                return createStarRatingInputRange(sliceUri);
+            case "/range":
+                return createDownloadProgressRange(sliceUri);
+        }
+        throw new IllegalArgumentException("Unknown uri " + sliceUri);
+    }
+
+    private Slice createWeather(Uri sliceUri) {
+        SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
+                "open weather app"), Icon.createWithResource(getContext(), R.drawable.weather_1),
+                "Weather is happening!");
+        return new ListBuilder(getContext(), sliceUri).addGrid(gb -> gb
+                .setPrimaryAction(primaryAction)
+                .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+                        .addText("MON")
+                        .addTitleText("69\u00B0"))
+                .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_2))
+                        .addText("TUE")
+                        .addTitleText("71\u00B0"))
+                .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_3))
+                        .addText("WED")
+                        .addTitleText("76\u00B0"))
+                .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_4))
+                        .addText("THU")
+                        .addTitleText("72\u00B0"))
+                .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+                        .addText("FRI")
+                        .addTitleText("68\u00B0")))
+                .build();
+    }
+
+    private Slice createGallery(Uri sliceUri) {
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xff4285F4)
+                .addRow(b -> b
+                    .setTitle("Family trip to Hawaii")
+                    .setSubtitle("Sep 30, 2017 - Oct 2, 2017"))
+                .addAction(new SliceAction(
+                        getBroadcastIntent(ACTION_TOAST, "cast photo album"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_cast),
+                        "Cast photo album"))
+                .addAction(new SliceAction(
+                        getBroadcastIntent(ACTION_TOAST, "share photo album"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_share),
+                        "Share photo album"))
+                .addGrid(b -> b
+                    .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_1)))
+                    .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_2)))
+                    .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_3)))
+                    .addCell(cb -> cb
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_4))))
+                .build();
+    }
+
+    private Slice createContact(Uri sliceUri) {
+        final long lastCalled = System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS;
+        CharSequence lastCalledString = DateUtils.getRelativeTimeSpanString(lastCalled,
+                Calendar.getInstance().getTimeInMillis(),
+                DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);
+        SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
+                "See contact info"), Icon.createWithResource(getContext(),
+                R.drawable.mady), "Mady");
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xff3949ab)
+                .setHeader(b -> b
+                        .setTitle("Mady Pitza")
+                        .setSummarySubtitle("Called " + lastCalledString)
+                        .setPrimaryAction(primaryAction))
+                .addRow(b -> b
+                        .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_call))
+                        .setTitle("314-259-2653")
+                        .setSubtitle("Call lasted 1 hr 17 min")
+                        .addEndItem(lastCalled))
+                .addRow(b -> b
+                        .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_text))
+                        .setTitle("You: Coooooool see you then")
+                        .addEndItem(System.currentTimeMillis() - 40 * DateUtils.MINUTE_IN_MILLIS))
+                .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "call"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_call), "Call mady"))
+                .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "text"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_text), "Text mady"))
+                .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "video"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_video),
+                        "Video call mady"))
+                .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "email"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_email), "Email mady"))
+                .build();
+    }
+
+    private Slice createMessagingSlice(Uri sliceUri) {
+        // TODO: Remote input.
+        return new MessagingSliceBuilder(getContext(), sliceUri)
+                .add(b -> b
+                        .addText("yo home \uD83C\uDF55, I emailed you the info")
+                        .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS)
+                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                .add(b -> b
+                        .addText("just bought my tickets")
+                        .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS))
+                .add(b -> b
+                        .addText("yay! can't wait for getContext() weekend!\n"
+                                + "\uD83D\uDE00")
+                        .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS)
+                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                .build();
+
+    }
+
+    private Slice createNoteSlice(Uri sliceUri) {
+        // TODO: Remote input.
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xfff4b400)
+                .addRow(b -> b.setTitle("Create new note"))
+                .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "create note"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_create),
+                        "Create note"))
+                .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "voice note"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_voice),
+                        "Voice note"))
+                .addAction(new SliceAction(getIntent("android.media.action.IMAGE_CAPTURE"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_camera),
+                        "Photo note"))
+                .build();
+    }
+
+    private Slice createReservationSlice(Uri sliceUri) {
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xffFF5252)
+                .setHeader(b -> b
+                    .setTitle("Upcoming trip to Seattle")
+                    .setSubtitle("Feb 1 - 19 | 2 guests"))
+                .addAction(new SliceAction(
+                        getBroadcastIntent(ACTION_TOAST, "show location on map"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_location),
+                        "Show reservation location"))
+                .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "contact host"),
+                        Icon.createWithResource(getContext(), R.drawable.ic_text),
+                        "Contact host"))
+                .addGrid(b -> b
+                    .addCell(cb -> cb
+                        .addLargeImage(
+                                Icon.createWithResource(getContext(), R.drawable.reservation))))
+                .addGrid(b -> b
+                    .addCell(cb -> cb
+                        .addTitleText("Check In")
+                        .addText("12:00 PM, Feb 1"))
+                    .addCell(cb -> cb
+                        .addTitleText("Check Out")
+                        .addText("11:00 AM, Feb 19")))
+                .build();
+    }
+
+    private Slice createRideSlice(Uri sliceUri) {
+        final ForegroundColorSpan colorSpan = new ForegroundColorSpan(0xff0F9D58);
+        SpannableString headerSubtitle = new SpannableString("Ride in 4 min");
+        headerSubtitle.setSpan(colorSpan, 8, headerSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+        SpannableString homeSubtitle = new SpannableString("12 miles | 12 min | $9.00");
+        homeSubtitle.setSpan(colorSpan, 20, homeSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+        SpannableString workSubtitle = new SpannableString("44 miles | 1 hour 45 min | $31.41");
+        workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+
+        SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST, "get ride"),
+                Icon.createWithResource(getContext(), R.drawable.ic_car), "Get Ride");
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xff0F9D58)
+                .setHeader(b -> b
+                    .setTitle("Get ride")
+                    .setSubtitle(headerSubtitle)
+                    .setSummarySubtitle("Ride to work in 12 min | Ride home in 1 hour 45 min")
+                    .setPrimaryAction(primaryAction))
+                .addRow(b -> b
+                    .setTitle("Work")
+                    .setSubtitle(workSubtitle)
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "work"),
+                            Icon.createWithResource(getContext(), R.drawable.ic_work),
+                            "Get ride to work")))
+                .addRow(b -> b
+                    .setTitle("Home")
+                    .setSubtitle(homeSubtitle)
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "home"),
+                            Icon.createWithResource(getContext(), R.drawable.ic_home),
+                            "Get ride home")))
+                .build();
+    }
+
+    private Slice createCustomToggleSlice(Uri sliceUri) {
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xffff4081)
+                .addRow(b -> b
+                    .setTitle("Custom toggle")
+                    .setSubtitle("It can support two states")
+                    .setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST,
+                            "star toggled"),
+                            Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                            "Toggle star", true /* isChecked */)))
+                .build();
+    }
+
+    private Slice createTwoCustomToggleSlices(Uri sliceUri) {
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xffff4081)
+                .addRow(b -> b
+                        .setTitle("2 toggles")
+                        .setSubtitle("each supports two states")
+                        .addEndItem(new SliceAction(
+                                getBroadcastIntent(ACTION_TOAST, "first star toggled"),
+                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                "Toggle star", true /* isChecked */))
+                        .addEndItem(new SliceAction(
+                                getBroadcastIntent(ACTION_TOAST, "second star toggled"),
+                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                "Toggle star", false /* isChecked */)))
+                .build();
+    }
+
+    private Slice createWifiSlice(Uri sliceUri) {
+        // Get wifi state
+        WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        int wifiState = wifiManager.getWifiState();
+        boolean wifiEnabled = false;
+        String state;
+        switch (wifiState) {
+            case WifiManager.WIFI_STATE_DISABLED:
+            case WifiManager.WIFI_STATE_DISABLING:
+                state = "disconnected";
+                break;
+            case WifiManager.WIFI_STATE_ENABLED:
+            case WifiManager.WIFI_STATE_ENABLING:
+                state = wifiManager.getConnectionInfo().getSSID();
+                wifiEnabled = true;
+                break;
+            case WifiManager.WIFI_STATE_UNKNOWN:
+            default:
+                state = ""; // just don't show anything?
+                break;
+        }
+        boolean finalWifiEnabled = wifiEnabled;
+        SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
+                Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xff4285f4)
+                .addRow(b -> b
+                    .setTitle("Wi-fi")
+                    .setSubtitle(state)
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
+                            "Toggle wifi", finalWifiEnabled))
+                    .setPrimaryAction(primaryAction))
+                .build();
+    }
+
+    private Slice createStarRatingInputRange(Uri sliceUri) {
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xffff4081)
+                .addInputRange(c -> c
+                        .setTitle("Star rating")
+                        .setThumb(Icon.createWithResource(getContext(), R.drawable.ic_star_on))
+                        .setAction(getBroadcastIntent(ACTION_TOAST_RANGE_VALUE, null))
+                        .setMax(5)
+                        .setValue(3))
+                .build();
+    }
+
+    private Slice createDownloadProgressRange(Uri sliceUri) {
+        return new ListBuilder(getContext(), sliceUri)
+                .setColor(0xffff4081)
+                .addRange(c -> c
+                        .setTitle("Download progress")
+                        .setMax(100)
+                        .setValue(75))
+                .build();
+    }
+
+    private Handler mHandler = new Handler();
+    private Runnable mLoader;
+    private boolean mLoaded = false;
+
+    private Slice createLoadingSlice(Uri sliceUri, boolean loadAll, boolean isList) {
+        if (!mLoaded || mLoader != null) {
+            // Need to load content or we're still loading so just return partial
+            if (!mLoaded) {
+                mLoader = () -> {
+                    // Note that we've loaded things
+                    mLoader = null;
+                    mLoaded = true;
+                    // Notify to update the slice
+                    getContext().getContentResolver().notifyChange(sliceUri, null);
+                };
+                mHandler.postDelayed(mLoader, LOADING_DELAY_MS);
+            }
+            if (loadAll) {
+                return new ListBuilder(getContext(), sliceUri).build();
+            }
+            return createPartialSlice(sliceUri, true, isList);
+        } else {
+            mLoaded = false;
+            return createPartialSlice(sliceUri, false, isList);
+        }
+    }
+
+    private Slice createPartialSlice(Uri sliceUri, boolean isPartial, boolean isList) {
+        Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_star_on);
+        PendingIntent intent = getBroadcastIntent(ACTION_TOAST, "star tapped");
+        PendingIntent intent2 = getBroadcastIntent(ACTION_TOAST, "toggle tapped");
+        if (isPartial) {
+            if (isList) {
+                return new ListBuilder(getContext(), sliceUri)
+                        .addRow(b -> createRow(b, "Slice that has content to load",
+                                "Temporary subtitle", icon, intent, true))
+                        .addRow(b -> createRow(b, null, null, null, intent, true))
+                        .addRow(b -> b
+                                .setTitle("My title")
+                                .addEndItem(new SliceAction(intent2, "Some action",
+                                        false /* isChecked */),
+                                        true /* isLoading */))
+                        .build();
+            } else {
+                return new ListBuilder(getContext(), sliceUri).addGrid(gb -> gb
+                        .addCell(b -> createCell(b, null, null, null, true))
+                        .addCell(b -> createCell(b, "Two stars", null, icon, true))
+                        .addCell(b -> createCell(b, null, null, null, true)))
+                        .build();
+            }
+        } else {
+            if (isList) {
+                return new ListBuilder(getContext(), sliceUri)
+                        .addRow(b -> createRow(b, "Slice that has content to load",
+                                "Subtitle loaded", icon, intent, false))
+                        .addRow(b -> createRow(b, "Loaded row", "Loaded subtitle",
+                                icon, intent, false))
+                        .addRow(b -> b
+                                .setTitle("My title")
+                                .addEndItem(new SliceAction(intent2, "Some action",
+                                                false /* isChecked */)))
+                        .build();
+            } else {
+                return new ListBuilder(getContext(), sliceUri).addGrid(gb -> gb
+                        .addCell(b -> createCell(b, "One star", "meh", icon, false))
+                        .addCell(b -> createCell(b, "Two stars", "good", icon, false))
+                        .addCell(b -> createCell(b, "Three stars", "best", icon, false)))
+                        .build();
+            }
+        }
+    }
+
+    private ListBuilder.RowBuilder createRow(ListBuilder.RowBuilder rb, String title,
+            String subtitle, Icon icon, PendingIntent content, boolean isLoading) {
+        SliceAction primaryAction = new SliceAction(content, icon, title);
+        return rb.setTitle(title, isLoading)
+          .setSubtitle(subtitle, isLoading)
+          .addEndItem(icon, isLoading)
+          .setPrimaryAction(primaryAction);
+    }
+
+    private GridBuilder.CellBuilder createCell(GridBuilder.CellBuilder cb, String text1,
+            String text2, Icon icon, boolean isLoading) {
+        return cb.addText(text1, isLoading).addText(text2, isLoading).addImage(icon, isLoading);
+    }
+
+    private PendingIntent getIntent(String action) {
+        Intent intent = new Intent(action);
+        PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+        return pi;
+    }
+
+    private PendingIntent getBroadcastIntent(String action, String message) {
+        Intent intent = new Intent(action);
+        intent.setClass(getContext(), SliceBroadcastReceiver.class);
+        // Ensure a new PendingIntent is created for each message.
+        int requestCode = 0;
+        if (message != null) {
+            intent.putExtra(EXTRA_TOAST_MESSAGE, message);
+            requestCode = message.hashCode();
+        }
+        return PendingIntent.getBroadcast(getContext(), requestCode, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+}
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBroadcastReceiver.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBroadcastReceiver.java
new file mode 100644
index 0000000..9e87dc0
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBroadcastReceiver.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.androidx.slice.demos;
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+import static androidx.app.slice.core.SliceHints.EXTRA_RANGE_VALUE;
+import static com.example.androidx.slice.demos.SampleSliceProvider.getUri;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.widget.Toast;
+
+/**
+ * Responds to actions performed on slices and notifies slices of updates in state changes.
+ */
+public class SliceBroadcastReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent i) {
+        String action = i.getAction();
+        switch (action) {
+            case SampleSliceProvider.ACTION_WIFI_CHANGED:
+                WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+                boolean newState = i.getBooleanExtra(EXTRA_TOGGLE_STATE, wm.isWifiEnabled());
+                wm.setWifiEnabled(newState);
+                // Wait a bit for wifi to update (TODO: is there a better way to do this?)
+                Handler h = new Handler();
+                h.postDelayed(() -> {
+                    context.getContentResolver().notifyChange(getUri("wifi", context), null);
+                }, 1000);
+                break;
+            case SampleSliceProvider.ACTION_TOAST:
+                String message = i.getExtras().getString(SampleSliceProvider.EXTRA_TOAST_MESSAGE,
+                        "no message");
+                Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
+                break;
+            case SampleSliceProvider.ACTION_TOAST_RANGE_VALUE:
+                int range = i.getExtras().getInt(EXTRA_RANGE_VALUE, 0);
+                Toast.makeText(context, "value: " + range, Toast.LENGTH_SHORT).show();
+                break;
+        }
+    }
+}
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
new file mode 100644
index 0000000..d9d0284
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.androidx.slice.demos;
+
+import static com.example.androidx.slice.demos.SampleSliceProvider.URI_PATHS;
+import static com.example.androidx.slice.demos.SampleSliceProvider.getUri;
+
+import android.arch.lifecycle.LiveData;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.BaseColumns;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.ViewGroup;
+import android.widget.CursorAdapter;
+import android.widget.SearchView;
+import android.widget.SimpleCursorAdapter;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.widget.EventInfo;
+import androidx.app.slice.widget.SliceLiveData;
+import androidx.app.slice.widget.SliceView;
+
+/**
+ * Example use of SliceView. Uses a search bar to select/auto-complete a slice uri which is
+ * then displayed in the selected mode with SliceView.
+ */
+@RequiresApi(api = 28)
+public class SliceBrowser extends AppCompatActivity implements SliceView.OnSliceActionListener {
+
+    private static final String TAG = "SlicePresenter";
+
+    private static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
+    private static final boolean TEST_INTENT = false;
+    private static final boolean TEST_THEMES = false;
+
+    private ArrayList<Uri> mSliceUris = new ArrayList<Uri>();
+    private int mSelectedMode;
+    private ViewGroup mContainer;
+    private SearchView mSearchView;
+    private SimpleCursorAdapter mAdapter;
+    private SubMenu mTypeMenu;
+    private LiveData<Slice> mSliceLiveData;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_layout);
+
+        Toolbar toolbar = findViewById(R.id.search_toolbar);
+        setSupportActionBar(toolbar);
+
+        // Shows the slice
+        mContainer = findViewById(R.id.slice_preview);
+        mSearchView = findViewById(R.id.search_view);
+
+        final String[] from = new String[]{"uri"};
+        final int[] to = new int[]{android.R.id.text1};
+        mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1,
+                null, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
+        mSearchView.setSuggestionsAdapter(mAdapter);
+        mSearchView.setIconifiedByDefault(false);
+        mSearchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
+            @Override
+            public boolean onSuggestionClick(int position) {
+                mSearchView.setQuery(((Cursor) mAdapter.getItem(position)).getString(1), true);
+                return true;
+            }
+
+            @Override
+            public boolean onSuggestionSelect(int position) {
+                mSearchView.setQuery(((Cursor) mAdapter.getItem(position)).getString(1), true);
+                return true;
+            }
+        });
+        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
+            @Override
+            public boolean onQueryTextSubmit(String s) {
+                addSlice(Uri.parse(s));
+                mSearchView.clearFocus();
+                return false;
+            }
+
+            @Override
+            public boolean onQueryTextChange(String s) {
+                populateAdapter(s);
+                return false;
+            }
+        });
+
+        mSelectedMode = (savedInstanceState != null)
+                ? savedInstanceState.getInt("SELECTED_MODE", SliceView.MODE_LARGE)
+                : SliceView.MODE_LARGE;
+        if (savedInstanceState != null) {
+            mSearchView.setQuery(savedInstanceState.getString("SELECTED_QUERY"), true);
+        }
+
+        grantPackage(getPackageName());
+        // TODO: Listen for changes.
+        updateAvailableSlices();
+        if (TEST_INTENT) {
+            addSlice(new Intent("androidx.intent.SLICE_ACTION").setPackage(getPackageName()));
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        mTypeMenu = menu.addSubMenu("Type");
+        mTypeMenu.setIcon(R.drawable.ic_large);
+        mTypeMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+        mTypeMenu.add("Shortcut");
+        mTypeMenu.add("Small");
+        mTypeMenu.add("Large");
+        menu.add("Auth");
+        super.onCreateOptionsMenu(menu);
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getTitle().toString()) {
+            case "Auth":
+                authAllSlices();
+                return true;
+            case "Shortcut":
+                mTypeMenu.setIcon(R.drawable.ic_shortcut);
+                mSelectedMode = SliceView.MODE_SHORTCUT;
+                updateSliceModes();
+                return true;
+            case "Small":
+                mTypeMenu.setIcon(R.drawable.ic_small);
+                mSelectedMode = SliceView.MODE_SMALL;
+                updateSliceModes();
+                return true;
+            case "Large":
+                mTypeMenu.setIcon(R.drawable.ic_large);
+                mSelectedMode = SliceView.MODE_LARGE;
+                updateSliceModes();
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt("SELECTED_MODE", mSelectedMode);
+        outState.putString("SELECTED_QUERY", mSearchView.getQuery().toString());
+    }
+
+    private void authAllSlices() {
+        List<ApplicationInfo> packages = getPackageManager().getInstalledApplications(0);
+        packages.forEach(info -> {
+            grantPackage(info.packageName);
+        });
+    }
+
+    private void grantPackage(String packageName) {
+        for (int i = 0; i < URI_PATHS.length; i++) {
+            grantUriPermission(packageName, getUri(URI_PATHS[i], getApplicationContext()),
+                    Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        }
+    }
+
+    private void updateAvailableSlices() {
+        mSliceUris.clear();
+        List<PackageInfo> packageInfos = getPackageManager()
+                .getInstalledPackages(PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+        for (PackageInfo pi : packageInfos) {
+            ActivityInfo[] activityInfos = pi.activities;
+            if (activityInfos != null) {
+                for (ActivityInfo ai : activityInfos) {
+                    if (ai.metaData != null) {
+                        String sliceUri = ai.metaData.getString(SLICE_METADATA_KEY);
+                        if (sliceUri != null) {
+                            mSliceUris.add(Uri.parse(sliceUri));
+                        }
+                    }
+                }
+            }
+        }
+        for (int i = 0; i < URI_PATHS.length; i++) {
+            mSliceUris.add(getUri(URI_PATHS[i], getApplicationContext()));
+        }
+        populateAdapter(String.valueOf(mSearchView.getQuery()));
+    }
+
+    private void addSlice(Intent intent) {
+        SliceView v = createSliceView();
+        v.setTag(intent);
+        mContainer.removeAllViews();
+        mContainer.addView(v);
+        mSliceLiveData = SliceLiveData.fromIntent(this, intent);
+        v.setMode(mSelectedMode);
+        mSliceLiveData.observe(this, v);
+    }
+
+    private void addSlice(Uri uri) {
+        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
+            SliceView v = createSliceView();
+            v.setTag(uri);
+            mContainer.removeAllViews();
+            mContainer.addView(v);
+            mSliceLiveData = SliceLiveData.fromUri(this, uri);
+            v.setMode(mSelectedMode);
+            mSliceLiveData.observe(this, v);
+        } else {
+            Log.w(TAG, "Invalid uri, skipping slice: " + uri);
+        }
+    }
+
+    private void updateSliceModes() {
+        final int count = mContainer.getChildCount();
+        for (int i = 0; i < count; i++) {
+            ((SliceView) mContainer.getChildAt(i)).setMode(mSelectedMode);
+        }
+    }
+
+    private void populateAdapter(String query) {
+        final MatrixCursor c = new MatrixCursor(new String[]{BaseColumns._ID, "uri"});
+        ArrayMap<String, Integer> ranking = new ArrayMap<>();
+        ArrayList<String> suggestions = new ArrayList();
+        mSliceUris.forEach(uri -> {
+            String uriString = uri.toString();
+            if (uriString.contains(query)) {
+                ranking.put(uriString, uriString.indexOf(query));
+                suggestions.add(uriString);
+            }
+        });
+        suggestions.sort(new Comparator<String>() {
+            @Override
+            public int compare(String o1, String o2) {
+                return Integer.compare(ranking.get(o1), ranking.get(o2));
+            }
+        });
+        for (int i = 0; i < suggestions.size(); i++) {
+            c.addRow(new Object[]{i, suggestions.get(i)});
+        }
+        mAdapter.changeCursor(c);
+    }
+
+    @Override
+    public void onSliceAction(@NonNull EventInfo info, @NonNull SliceItem item) {
+        Log.w(TAG, "onSliceAction, info: " + info);
+        Log.w(TAG, "onSliceAction, sliceItem: \n" + item);
+    }
+
+    private SliceView createSliceView() {
+        SliceView v = TEST_THEMES
+                ? (SliceView) getLayoutInflater().inflate(
+                R.layout.slice_view, mContainer, false)
+                : new SliceView(getApplicationContext());
+        v.setOnSliceActionListener(this);
+        if (mSliceLiveData != null) {
+            mSliceLiveData.removeObservers(this);
+        }
+        return v;
+    }
+}
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_call.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_call.xml
new file mode 100644
index 0000000..ebf9de6
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_call.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6.62,10.79c1.44,2.83 3.76,5.14 6.59,6.59l2.2,-2.2c0.27,-0.27 0.67,-0.36 1.02,-0.24 1.12,0.37 2.33,0.57 3.57,0.57 0.55,0 1,0.45 1,1V20c0,0.55 -0.45,1 -1,1 -9.39,0 -17,-7.61 -17,-17 0,-0.55 0.45,-1 1,-1h3.5c0.55,0 1,0.45 1,1 0,1.25 0.2,2.45 0.57,3.57 0.11,0.35 0.03,0.74 -0.25,1.02l-2.2,2.2z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_camera.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_camera.xml
new file mode 100644
index 0000000..74b6bf9
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_camera.xml
@@ -0,0 +1,32 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M 12 8.8 C 13.7673111995 8.8 15.2 10.2326888005 15.2 12 C 15.2 13.7673111995 13.7673111995 15.2 12 15.2 C 10.2326888005 15.2 8.8 13.7673111995 8.8 12 C 8.8 10.2326888005 10.2326888005 8.8 12 8.8 Z" />
+    <path
+        android:fillColor="#000000"
+        android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
+2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
+5-2.24 5-5 5z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_car.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_car.xml
new file mode 100644
index 0000000..6bab660
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_car.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M18.92 6.01C18.72 5.42 18.16 5 17.5 5h-11c-.66 0-1.21 .42 -1.42 1.01L3 12v8c0
+.55 .45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55 .45 1 1 1h1c.55 0 1-.45
+1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5 .67 1.5
+1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5 .67 1.5
+1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_cast.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_cast.xml
new file mode 100644
index 0000000..4f62c5e
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_cast.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_create.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_create.xml
new file mode 100644
index 0000000..d1666a8
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_create.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_email.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_email.xml
new file mode 100644
index 0000000..ce97ab8
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_email.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_home.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_home.xml
new file mode 100644
index 0000000..b278230
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_home.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_large.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_large.xml
new file mode 100644
index 0000000..79ac590
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_large.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/>
+    <path
+        android:strokeColor="#FF000000"
+        android:strokeWidth="2"
+        android:pathData="M16,18 l16,0 l0,10 l-16,0z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_location.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_location.xml
new file mode 100644
index 0000000..2f2db39
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_location.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_share.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_share.xml
new file mode 100644
index 0000000..4f68d87
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_share.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_shortcut.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_shortcut.xml
new file mode 100644
index 0000000..bf9572a
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_shortcut.xml
@@ -0,0 +1,34 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="48.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="48.0dp">
+    <path
+        android:fillColor="#e2e2e2"
+        android:pathData="M24.0,24.0m-19.0,0.0a19.0,19.0 0.0,1.0 1.0,38.0 0.0a19.0,19.0 0.0,1.0 1.0,-38.0 0.0"/>
+    <group
+        android:scaleX=".7"
+        android:scaleY=".7"
+        android:translateX="7.2"
+        android:translateY="7.2">
+
+        <path
+            android:fillColor="#ff000000"
+            android:pathData="M12.0,36.0c0.0,1.0 0.9,2.0 2.0,2.0l2.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l4.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l2.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L36.0,16.0L12.0,16.0l0.0,20.0zM7.0,16.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L10.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zm34.0,0.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L44.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zM31.06,4.32l2.61,-2.61c0.39,-0.3 0.39,-1.02 0.0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0.0L29.3,3.25C27.7,2.46 25.91,2.0 24.0,2.0c-1.92,0.0 -3.7,0.46 -5.33,1.26L15.0,0.29c-0.39,-0.39 -1.02,-0.39 -1.41,0.0 -0.3,0.39 -0.39,1.02 0.0,1.41l2.62,2.62C13.94,6.51 12.0,10.03 12.0,14.0l24.0,0.0c0.0,-3.98 -1.95,-7.5 -4.94,-9.68zM20.0,10.0l-2.0,0.0L18.0,8.0l2.0,0.0l0.0,2.0zm10.0,0.0l-2.0,0.0L28.0,8.0l2.0,0.0l0.0,2.0z"/>
+    </group>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_small.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_small.xml
new file mode 100644
index 0000000..8fd43df
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_small.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M16,18 l16,0 l0,4 l-16,0z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_star_off.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_star_off.xml
new file mode 100644
index 0000000..7f023b3
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_star_off.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_star_on.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_star_on.xml
new file mode 100644
index 0000000..f3ca086
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_star_on.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_text.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_text.xml
new file mode 100644
index 0000000..d2876bf
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_text.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_video.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_video.xml
new file mode 100644
index 0000000..e23eac8
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_video.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_voice.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_voice.xml
new file mode 100644
index 0000000..8f465bb
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_voice.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi.xml
new file mode 100644
index 0000000..4fbfd60
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_work.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_work.xml
new file mode 100644
index 0000000..6806402
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_work.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M0 0h24v24H0z" />
+    <path
+        android:fillColor="#000000"
+        android:pathData="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99 .89 -1.99 2L2
+19c0 1.11 .89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z" />
+</vector>
\ No newline at end of file
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/mady.jpg b/samples/SupportSliceDemos/src/main/res/drawable/mady.jpg
new file mode 100644
index 0000000..8b61f1b
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/mady.jpg
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/reservation.png b/samples/SupportSliceDemos/src/main/res/drawable/reservation.png
new file mode 100644
index 0000000..16acc98
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/reservation.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/slices_1.jpg b/samples/SupportSliceDemos/src/main/res/drawable/slices_1.jpg
new file mode 100644
index 0000000..31cc065
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/slices_1.jpg
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/slices_2.jpg b/samples/SupportSliceDemos/src/main/res/drawable/slices_2.jpg
new file mode 100644
index 0000000..adbe1d3
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/slices_2.jpg
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/slices_3.jpg b/samples/SupportSliceDemos/src/main/res/drawable/slices_3.jpg
new file mode 100644
index 0000000..6617019
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/slices_3.jpg
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/slices_4.jpg b/samples/SupportSliceDemos/src/main/res/drawable/slices_4.jpg
new file mode 100644
index 0000000..d00a8b3
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/slices_4.jpg
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/toggle_star.xml b/samples/SupportSliceDemos/src/main/res/drawable/toggle_star.xml
new file mode 100644
index 0000000..e964925
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/toggle_star.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/on"
+        android:state_checked="true"
+        android:drawable="@drawable/ic_star_on" />
+    <item
+        android:id="@+id/off"
+        android:drawable="@drawable/ic_star_off" />
+</selector>
\ No newline at end of file
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/weather_1.png b/samples/SupportSliceDemos/src/main/res/drawable/weather_1.png
new file mode 100644
index 0000000..7c4034e
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/weather_1.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/weather_2.png b/samples/SupportSliceDemos/src/main/res/drawable/weather_2.png
new file mode 100644
index 0000000..f1b6672
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/weather_2.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/weather_3.png b/samples/SupportSliceDemos/src/main/res/drawable/weather_3.png
new file mode 100644
index 0000000..a5db683
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/weather_3.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/weather_4.png b/samples/SupportSliceDemos/src/main/res/drawable/weather_4.png
new file mode 100644
index 0000000..0b7f3b0
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/weather_4.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/layout/activity_demo.xml b/samples/SupportSliceDemos/src/main/res/layout/activity_demo.xml
new file mode 100644
index 0000000..f557f40
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/layout/activity_demo.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.android.support.content.demos.ContentPagerDemoActivity">
+
+    <android.support.v7.widget.Toolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="?attr/actionBarSize"
+        android:background="?attr/colorPrimary"
+        android:theme="@style/AppTheme.AppBarOverlay"
+        app:popupTheme="@style/AppTheme.PopupOverlay"/>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</LinearLayout>
diff --git a/samples/SupportSliceDemos/src/main/res/layout/activity_layout.xml b/samples/SupportSliceDemos/src/main/res/layout/activity_layout.xml
new file mode 100644
index 0000000..6a087a3
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/layout/activity_layout.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="top"
+    android:orientation="vertical" >
+
+    <FrameLayout
+        android:id="@+id/search_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="#f2f2f2">
+        <android.support.v7.widget.CardView
+            android:id="@+id/search_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="8dp"
+            app:cardCornerRadius="2dp"
+            app:cardBackgroundColor="?android:attr/colorBackground"
+            app:cardElevation="2dp">
+            <android.support.v7.widget.Toolbar
+                android:id="@+id/search_toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="48dp"
+                android:background="?android:attr/selectableItemBackground"
+                android:contentInsetStart="0dp"
+                android:contentInsetStartWithNavigation="0dp"
+                android:theme="?android:attr/actionBarTheme">
+                <SearchView
+                    android:id="@+id/search_view"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:iconifiedByDefault="false"
+                    android:imeOptions="actionSearch|flagNoExtractUi"
+                    android:queryHint="content://..."
+                    android:searchIcon="@null"/>
+            </android.support.v7.widget.Toolbar>
+        </android.support.v7.widget.CardView>
+    </FrameLayout>
+
+
+    <ScrollView
+        android:id="@+id/container"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" >
+
+        <FrameLayout
+            android:id="@+id/slice_preview"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="8dp"
+            android:orientation="vertical"
+            android:background="?android:attr/colorBackground"
+            android:elevation="10dp" />
+    </ScrollView>
+
+</LinearLayout>
diff --git a/samples/SupportSliceDemos/src/main/res/layout/slice_view.xml b/samples/SupportSliceDemos/src/main/res/layout/slice_view.xml
new file mode 100644
index 0000000..8d5eb61
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/layout/slice_view.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<androidx.app.slice.widget.SliceView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    style="@style/CustomSliceView"/>
\ No newline at end of file
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-hdpi/ic_launcher.png b/samples/SupportSliceDemos/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-hdpi/ic_launcher_round.png b/samples/SupportSliceDemos/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-mdpi/ic_launcher.png b/samples/SupportSliceDemos/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-mdpi/ic_launcher_round.png b/samples/SupportSliceDemos/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-xhdpi/ic_launcher.png b/samples/SupportSliceDemos/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/samples/SupportSliceDemos/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-xxhdpi/ic_launcher.png b/samples/SupportSliceDemos/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/SupportSliceDemos/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/samples/SupportSliceDemos/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/SupportSliceDemos/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/SupportSliceDemos/src/main/res/values/colors.xml b/samples/SupportSliceDemos/src/main/res/values/colors.xml
new file mode 100644
index 0000000..86b4304
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/samples/SupportSliceDemos/src/main/res/values/strings.xml b/samples/SupportSliceDemos/src/main/res/values/strings.xml
new file mode 100644
index 0000000..89583bd
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">Slice Browser</string>
+</resources>
diff --git a/samples/SupportSliceDemos/src/main/res/values/styles.xml b/samples/SupportSliceDemos/src/main/res/values/styles.xml
new file mode 100644
index 0000000..a01e0aa
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/values/styles.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
+
+    <style name="CustomSliceView" parent="Widget.SliceView">
+        <item name="titleColor">@color/colorAccent</item>
+        <item name="tintColor">@color/colorAccent</item>
+        <item name="headerTitleSize">20sp</item>
+        <item name="headerSubtitleSize">16sp</item>
+        <item name="android:paddingLeft">14dp</item>
+        <item name="android:paddingTop">8dp</item>
+        <item name="android:paddingRight">20dp</item>
+        <item name="android:paddingBottom">8dp</item>
+    </style>
+</resources>
diff --git a/settings.gradle b/settings.gradle
index 059f57a..06b1c32 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,122 +1,98 @@
 /////////////////////////////
 //
+// Buildscript utils
+//
+/////////////////////////////
+
+
+// Calling includeProject(name, filePath) is shorthand for:
+//
+//   include(name)
+//   project(name).projectDir = new File(filePath)
+//
+// Note that <name> directly controls the Gradle project name, and also indirectly sets:
+//   the project name in the IDE
+//   the Maven artifactId
+//
+def includeProject(name, filePath) {
+    settings.include(name)
+
+    def file
+    if (filePath instanceof String) {
+        file = new File(filePath)
+    } else {
+        file = filePath
+    }
+    project(name).projectDir = file
+}
+
+
+/////////////////////////////
+//
 // Libraries
 //
 /////////////////////////////
 
-include ':support-annotations'
-project(':support-annotations').projectDir = new File(rootDir, 'annotations')
-
-include ':support-compat'
-project(':support-compat').projectDir = new File(rootDir, 'compat')
-
-include ':support-media-compat'
-project(':support-media-compat').projectDir = new File(rootDir, 'media-compat')
-
-include ':support-core-ui'
-project(':support-core-ui').projectDir = new File(rootDir, 'core-ui')
-
-include ':support-fragment'
-project(':support-fragment').projectDir = new File(rootDir, 'fragment')
-
-include ':support-core-utils'
-project(':support-core-utils').projectDir = new File(rootDir, 'core-utils')
-
-include ':support-v4'
-project(':support-v4').projectDir = new File(rootDir, 'v4')
-
-include ':appcompat-v7'
-project(':appcompat-v7').projectDir = new File(rootDir, 'v7/appcompat')
-
-include ':gridlayout-v7'
-project(':gridlayout-v7').projectDir = new File(rootDir, 'v7/gridlayout')
-
-include ':mediarouter-v7'
-project(':mediarouter-v7').projectDir = new File(rootDir, 'v7/mediarouter')
-
-include ':palette-v7'
-project(':palette-v7').projectDir = new File(rootDir, 'v7/palette')
-
-include ':recyclerview-v7'
-project(':recyclerview-v7').projectDir = new File(rootDir, 'v7/recyclerview')
-
-include ':recyclerview-selection'
-project(':recyclerview-selection').projectDir = new File(rootDir, 'recyclerview-selection')
-
-include ':cardview-v7'
-project(':cardview-v7').projectDir = new File(rootDir, 'v7/cardview')
-
-include ':preference-v7'
-project(':preference-v7').projectDir = new File(rootDir, 'v7/preference')
-
-include ':preference-v14'
-project(':preference-v14').projectDir = new File(rootDir, 'v14/preference')
-
-include ':preference-leanback-v17'
-project(':preference-leanback-v17').projectDir = new File(rootDir, 'preference-leanback')
-
-include ':support-v13'
-project(':support-v13').projectDir = new File(rootDir, 'v13')
-
-include ':leanback-v17'
-project(':leanback-v17').projectDir = new File(rootDir, 'leanback')
-
-include ':design'
-project(':design').projectDir = new File(rootDir, 'design')
-
-include ':percent'
-project(':percent').projectDir = new File(rootDir, 'percent')
-
-include ':customtabs'
-project(':customtabs').projectDir = new File(rootDir, 'customtabs')
-
-include ':recommendation'
-project(':recommendation').projectDir = new File(rootDir, 'recommendation')
-
-include ':support-vector-drawable'
-project(':support-vector-drawable').projectDir = new File(rootDir, 'graphics/drawable/static')
-
-include ':animated-vector-drawable'
-project(':animated-vector-drawable').projectDir = new File(rootDir, 'graphics/drawable/animated')
-
-include ':transition'
-project(':transition').projectDir = new File(rootDir, 'transition')
-
-include ':support-dynamic-animation'
-project(':support-dynamic-animation').projectDir = new File(rootDir, 'dynamic-animation')
-
-include ':viewpager2'
-project(':viewpager2').projectDir = new File(rootDir, 'viewpager2')
-
-include ':exifinterface'
-project(':exifinterface').projectDir = new File(rootDir, 'exifinterface')
-
-include ':wear'
-project(':wear').projectDir = new File(rootDir, 'wear')
-
-include ':support-tv-provider'
-project(':support-tv-provider').projectDir = new File(rootDir, 'tv-provider')
-
-include ':support-emoji'
-project(':support-emoji').projectDir = new File(rootDir, 'emoji/core')
-
-include ':support-emoji-bundled'
-project(':support-emoji-bundled').projectDir = new File(rootDir, 'emoji/bundled')
-
-include ':support-emoji-appcompat'
-project(':support-emoji-appcompat').projectDir = new File(rootDir, 'emoji/appcompat')
-
-include ':support-content'
-project(':support-content').projectDir = new File(rootDir, 'content')
-
-include ':car'
-project(':car').projectDir = new File(rootDir, 'car')
-
-include ':webkit'
-project(':webkit').projectDir = new File(rootDir, 'webkit')
-
-include ':webkit-codegen'
-project(':webkit-codegen').projectDir = new File(rootDir, 'webkit-codegen')
+includeProject(":animated-vector-drawable", "graphics/drawable/animated")
+includeProject(":appcompat-v7", "v7/appcompat")
+includeProject(":asynclayoutinflater", "asynclayoutinflater")
+includeProject(":car", "car")
+includeProject(":cardview-v7", "v7/cardview")
+includeProject(":collections", "collections")
+includeProject(":coordinatorlayout", "coordinatorlayout")
+includeProject(":cursoradapter", "cursoradapter")
+includeProject(":customtabs", "customtabs")
+includeProject(":customview", "customview")
+includeProject(":documentfile", "documentfile")
+includeProject(":drawerlayout", "drawerlayout")
+includeProject(":exifinterface", "exifinterface")
+includeProject(":gridlayout-v7", "v7/gridlayout")
+includeProject(":heifwriter", "heifwriter")
+includeProject(":interpolator", "interpolator")
+includeProject(":jetifier-core", "jetifier/jetifier/core")
+includeProject(":jetifier-gradle-plugin", "jetifier/jetifier/gradle-plugin")
+includeProject(":jetifier-standalone", "jetifier/jetifier/standalone")
+includeProject(":jetifier-preprocessor", "jetifier/jetifier/preprocessor")
+includeProject(":leanback-v17", "leanback")
+includeProject(":loader", "loader")
+includeProject(":localbroadcastmanager", "localbroadcastmanager")
+includeProject(":mediarouter-v7", "v7/mediarouter")
+includeProject(":palette-v7", "v7/palette")
+includeProject(":percent", "percent")
+includeProject(":preference-v7", "v7/preference")
+includeProject(":preference-v14", "v14/preference")
+includeProject(":preference-leanback-v17", "preference-leanback")
+includeProject(":print", "print")
+includeProject(":recommendation", "recommendation")
+includeProject(":recyclerview-v7", "v7/recyclerview")
+includeProject(":recyclerview-selection", "recyclerview-selection")
+includeProject(":slices-core", "slices/core")
+includeProject(":slices-view", "slices/view")
+includeProject(":slices-builders", "slices/builders")
+includeProject(":slidingpanelayout", "slidingpanelayout")
+includeProject(":support-annotations", "annotations")
+includeProject(":support-compat", "compat")
+includeProject(":support-content", "content")
+includeProject(":support-core-ui", "core-ui")
+includeProject(":support-core-utils", "core-utils")
+includeProject(":support-dynamic-animation", "dynamic-animation")
+includeProject(":support-emoji", "emoji/core")
+includeProject(":support-emoji-bundled", "emoji/bundled")
+includeProject(":support-emoji-appcompat", "emoji/appcompat")
+includeProject(":support-fragment", "fragment")
+includeProject(":support-media-compat", "media-compat")
+includeProject(":support-tv-provider", "tv-provider")
+includeProject(":support-vector-drawable", "graphics/drawable/static")
+includeProject(":support-v4", "v4")
+includeProject(":support-v13", "v13")
+includeProject(":swiperefreshlayout", "swiperefreshlayout")
+includeProject(":textclassifier", "textclassifier")
+includeProject(":transition", "transition")
+includeProject(":viewpager", "viewpager")
+includeProject(":viewpager2", "viewpager2")
+includeProject(":wear", "wear")
+includeProject(":webkit", "webkit")
+includeProject(":webkit-codegen", "webkit-codegen")
 
 /////////////////////////////
 //
@@ -124,66 +100,34 @@
 //
 /////////////////////////////
 
-File samplesRoot = new File(rootDir, 'samples')
+File samplesRoot = new File(rootDir, "samples")
 
-include ':support-content-demos'
-project(':support-content-demos').projectDir = new File(samplesRoot, 'SupportContentDemos')
+includeProject(":support-animation-demos", new File(samplesRoot, "SupportAnimationDemos"))
+includeProject(":support-app-navigation", new File(samplesRoot, "SupportAppNavigation"))
+includeProject(":support-car-demos", new File(samplesRoot, "SupportCarDemos"))
+includeProject(":support-content-demos", new File(samplesRoot, "SupportContentDemos"))
+includeProject(":support-design-demos", new File(samplesRoot, "SupportDesignDemos"))
+includeProject(":support-emoji-demos", new File(samplesRoot, "SupportEmojiDemos"))
+includeProject(":support-leanback-demos", new File(samplesRoot, "SupportLeanbackDemos"))
+includeProject(":support-leanback-jank", new File(samplesRoot, "SupportLeanbackJank"))
+includeProject(":support-percent-demos", new File(samplesRoot, "SupportPercentDemos"))
+includeProject(":support-preference-demos", new File(samplesRoot, "SupportPreferenceDemos"))
+includeProject(":support-slices-demos", new File(samplesRoot, "SupportSliceDemos"))
+includeProject(":support-transition-demos", new File(samplesRoot, "SupportTransitionDemos"))
+includeProject(":support-vector-drawable-demos", new File(samplesRoot, "SupportVectorDrawableDemos"))
+includeProject(":support-v4-demos", new File(samplesRoot, "Support4Demos"))
+includeProject(":support-v7-demos", new File(samplesRoot, "Support7Demos"))
+includeProject(":support-v13-demos", new File(samplesRoot, "Support13Demos"))
+includeProject(":support-wear-demos", new File(samplesRoot, "SupportWearDemos"))
+includeProject(":viewpager2-demos", new File(samplesRoot, "ViewPager2Demos"))
 
-include ':support-design-demos'
-project(':support-design-demos').projectDir = new File(samplesRoot, 'SupportDesignDemos')
-
-include ':support-leanback-demos'
-project(':support-leanback-demos').projectDir = new File(samplesRoot, 'SupportLeanbackDemos')
-
-include ':support-leanback-jank'
-project(':support-leanback-jank').projectDir = new File(samplesRoot, 'SupportLeanbackJank')
-
-include ':support-percent-demos'
-project(':support-percent-demos').projectDir = new File(samplesRoot, 'SupportPercentDemos')
-
-include ':support-preference-demos'
-project(':support-preference-demos').projectDir = new File(samplesRoot, 'SupportPreferenceDemos')
-
-include ':support-transition-demos'
-project(':support-transition-demos').projectDir = new File(samplesRoot, 'SupportTransitionDemos')
-
-include ':support-v4-demos'
-project(':support-v4-demos').projectDir = new File(samplesRoot, 'Support4Demos')
-
-include ':support-v7-demos'
-project(':support-v7-demos').projectDir = new File(samplesRoot, 'Support7Demos')
-
-include ':support-v13-demos'
-project(':support-v13-demos').projectDir = new File(samplesRoot, 'Support13Demos')
-
-include ':support-vector-drawable-demos'
-project(':support-vector-drawable-demos').projectDir = new File(samplesRoot, 'SupportVectorDrawableDemos')
-
-include ':support-animation-demos'
-project(':support-animation-demos').projectDir = new File(samplesRoot, 'SupportAnimationDemos')
-
-include ':viewpager2-demos'
-project(':viewpager2-demos').projectDir = new File(samplesRoot, 'ViewPager2Demos')
-
-include ':support-wear-demos'
-project(':support-wear-demos').projectDir = new File(samplesRoot, 'SupportWearDemos')
-
-include ':support-app-navigation'
-project(':support-app-navigation').projectDir = new File(samplesRoot, 'SupportAppNavigation')
-
-include ':support-emoji-demos'
-project(':support-emoji-demos').projectDir = new File(samplesRoot, 'SupportEmojiDemos')
-
-include ':support-car-demos'
-project(':support-car-demos').projectDir = new File(samplesRoot, 'SupportCarDemos')
 /////////////////////////////
 //
 // Testing libraries
 //
 /////////////////////////////
 
-include ':support-testutils'
-project(':support-testutils').projectDir = new File(rootDir, 'testutils')
+includeProject(":support-testutils", "testutils")
 
 /////////////////////////////
 //
@@ -191,20 +135,11 @@
 //
 /////////////////////////////
 
-include ':support-media-compat-test-client'
-project(':support-media-compat-test-client').projectDir = new File(rootDir, 'media-compat/version-compat-tests/current/client')
-
-include ':support-media-compat-test-client-previous'
-project(':support-media-compat-test-client-previous').projectDir = new File(rootDir, 'media-compat/version-compat-tests/previous/client')
-
-include ':support-media-compat-test-service'
-project(':support-media-compat-test-service').projectDir = new File(rootDir, 'media-compat/version-compat-tests/current/service')
-
-include ':support-media-compat-test-service-previous'
-project(':support-media-compat-test-service-previous').projectDir = new File(rootDir, 'media-compat/version-compat-tests/previous/service')
-
-include ':support-media-compat-test-lib'
-project(':support-media-compat-test-lib').projectDir = new File(rootDir, 'media-compat/version-compat-tests/lib')
+includeProject(":support-media-compat-test-client", "media-compat/version-compat-tests/current/client")
+includeProject(":support-media-compat-test-client-previous", "media-compat/version-compat-tests/previous/client")
+includeProject(":support-media-compat-test-service", "media-compat/version-compat-tests/current/service")
+includeProject(":support-media-compat-test-service-previous", "media-compat/version-compat-tests/previous/service")
+includeProject(":support-media-compat-test-lib", "media-compat/version-compat-tests/lib")
 
 /////////////////////////////
 //
@@ -212,14 +147,11 @@
 //
 /////////////////////////////
 
-File externalRoot = new File(rootDir, '../../external')
+apply(from: "include-composite-deps.gradle")
+File externalRoot = new File(rootDir, "../../external")
 
-includeBuild new File(externalRoot, 'doclava')
-
-includeBuild new File(externalRoot, 'jdiff')
-
-include ':noto-emoji-compat'
-project(':noto-emoji-compat').projectDir = new File(externalRoot, 'noto-fonts/emoji-compat')
+includeProject(":noto-emoji-compat", new File(externalRoot, "noto-fonts/emoji-compat"))
+includeProject(":webview-support-interfaces", new File(externalRoot, "webview_support_interfaces"))
 
 ///// FLATFOOT START
 
diff --git a/slices/OWNERS b/slices/OWNERS
new file mode 100644
index 0000000..921a517
--- /dev/null
+++ b/slices/OWNERS
@@ -0,0 +1,2 @@
+jmonk@google.com
+madym@google.com
diff --git a/slices/builders/api/current.txt b/slices/builders/api/current.txt
new file mode 100644
index 0000000..15b248b
--- /dev/null
+++ b/slices/builders/api/current.txt
@@ -0,0 +1,111 @@
+package androidx.app.slice.builders {
+
+  public class GridBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
+    ctor public GridBuilder(androidx.app.slice.builders.ListBuilder);
+    method public androidx.app.slice.builders.GridBuilder addCell(androidx.app.slice.builders.GridBuilder.CellBuilder);
+    method public androidx.app.slice.builders.GridBuilder addCell(java.util.function.Consumer<androidx.app.slice.builders.GridBuilder.CellBuilder>);
+    method public androidx.app.slice.builders.GridBuilder addSeeMoreAction(android.app.PendingIntent);
+    method public androidx.app.slice.builders.GridBuilder addSeeMoreCell(androidx.app.slice.builders.GridBuilder.CellBuilder);
+    method public androidx.app.slice.builders.GridBuilder addSeeMoreCell(java.util.function.Consumer<androidx.app.slice.builders.GridBuilder.CellBuilder>);
+    method public androidx.app.slice.builders.GridBuilder setPrimaryAction(androidx.app.slice.builders.SliceAction);
+  }
+
+  public static final class GridBuilder.CellBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
+    ctor public GridBuilder.CellBuilder(androidx.app.slice.builders.GridBuilder);
+    ctor public GridBuilder.CellBuilder(androidx.app.slice.builders.GridBuilder, android.net.Uri);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, boolean);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addLargeImage(android.graphics.drawable.Icon);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addLargeImage(android.graphics.drawable.Icon, boolean);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addText(java.lang.CharSequence);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addText(java.lang.CharSequence, boolean);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addTitleText(java.lang.CharSequence);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder addTitleText(java.lang.CharSequence, boolean);
+    method public androidx.app.slice.builders.GridBuilder.CellBuilder setContentIntent(android.app.PendingIntent);
+  }
+
+  public class ListBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
+    ctor public ListBuilder(android.content.Context, android.net.Uri);
+    method public androidx.app.slice.builders.ListBuilder addAction(androidx.app.slice.builders.SliceAction);
+    method public androidx.app.slice.builders.ListBuilder addGrid(androidx.app.slice.builders.GridBuilder);
+    method public androidx.app.slice.builders.ListBuilder addGrid(java.util.function.Consumer<androidx.app.slice.builders.GridBuilder>);
+    method public androidx.app.slice.builders.ListBuilder addInputRange(androidx.app.slice.builders.ListBuilder.InputRangeBuilder);
+    method public androidx.app.slice.builders.ListBuilder addInputRange(java.util.function.Consumer<androidx.app.slice.builders.ListBuilder.InputRangeBuilder>);
+    method public androidx.app.slice.builders.ListBuilder addRange(androidx.app.slice.builders.ListBuilder.RangeBuilder);
+    method public androidx.app.slice.builders.ListBuilder addRange(java.util.function.Consumer<androidx.app.slice.builders.ListBuilder.RangeBuilder>);
+    method public androidx.app.slice.builders.ListBuilder addRow(androidx.app.slice.builders.ListBuilder.RowBuilder);
+    method public androidx.app.slice.builders.ListBuilder addRow(java.util.function.Consumer<androidx.app.slice.builders.ListBuilder.RowBuilder>);
+    method public androidx.app.slice.builders.ListBuilder addSeeMoreAction(android.app.PendingIntent);
+    method public androidx.app.slice.builders.ListBuilder addSeeMoreRow(androidx.app.slice.builders.ListBuilder.RowBuilder);
+    method public androidx.app.slice.builders.ListBuilder addSeeMoreRow(java.util.function.Consumer<androidx.app.slice.builders.ListBuilder.RowBuilder>);
+    method public androidx.app.slice.builders.ListBuilder setHeader(androidx.app.slice.builders.ListBuilder.HeaderBuilder);
+    method public androidx.app.slice.builders.ListBuilder setHeader(java.util.function.Consumer<androidx.app.slice.builders.ListBuilder.HeaderBuilder>);
+  }
+
+  public static class ListBuilder.HeaderBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
+    ctor public ListBuilder.HeaderBuilder(androidx.app.slice.builders.ListBuilder);
+    method public androidx.app.slice.builders.ListBuilder.HeaderBuilder setPrimaryAction(androidx.app.slice.builders.SliceAction);
+    method public androidx.app.slice.builders.ListBuilder.HeaderBuilder setSubtitle(java.lang.CharSequence);
+    method public androidx.app.slice.builders.ListBuilder.HeaderBuilder setSummarySubtitle(java.lang.CharSequence);
+    method public androidx.app.slice.builders.ListBuilder.HeaderBuilder setTitle(java.lang.CharSequence);
+  }
+
+  public static class ListBuilder.InputRangeBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
+    ctor public ListBuilder.InputRangeBuilder(androidx.app.slice.builders.ListBuilder);
+    method public androidx.app.slice.builders.ListBuilder.InputRangeBuilder setAction(android.app.PendingIntent);
+    method public androidx.app.slice.builders.ListBuilder.InputRangeBuilder setMax(int);
+    method public androidx.app.slice.builders.ListBuilder.InputRangeBuilder setThumb(android.graphics.drawable.Icon);
+    method public androidx.app.slice.builders.ListBuilder.InputRangeBuilder setTitle(java.lang.CharSequence);
+    method public androidx.app.slice.builders.ListBuilder.InputRangeBuilder setValue(int);
+  }
+
+  public static class ListBuilder.RangeBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
+    ctor public ListBuilder.RangeBuilder(androidx.app.slice.builders.ListBuilder);
+    method public androidx.app.slice.builders.ListBuilder.RangeBuilder setMax(int);
+    method public androidx.app.slice.builders.ListBuilder.RangeBuilder setTitle(java.lang.CharSequence);
+    method public androidx.app.slice.builders.ListBuilder.RangeBuilder setValue(int);
+  }
+
+  public static class ListBuilder.RowBuilder extends androidx.app.slice.builders.TemplateSliceBuilder {
+    ctor public ListBuilder.RowBuilder(androidx.app.slice.builders.ListBuilder);
+    ctor public ListBuilder.RowBuilder(androidx.app.slice.builders.ListBuilder, android.net.Uri);
+    ctor public ListBuilder.RowBuilder(android.content.Context, android.net.Uri);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(long);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, boolean);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.app.slice.builders.SliceAction);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.app.slice.builders.SliceAction, boolean);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setPrimaryAction(androidx.app.slice.builders.SliceAction);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setSubtitle(java.lang.CharSequence);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setSubtitle(java.lang.CharSequence, boolean);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitle(java.lang.CharSequence);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitle(java.lang.CharSequence, boolean);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(long);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, boolean);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.app.slice.builders.SliceAction);
+    method public androidx.app.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.app.slice.builders.SliceAction, boolean);
+  }
+
+  public class SliceAction {
+    ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence);
+    ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence, boolean);
+    ctor public SliceAction(android.app.PendingIntent, java.lang.CharSequence, boolean);
+    method public android.app.PendingIntent getAction();
+    method public java.lang.CharSequence getContentDescription();
+    method public android.graphics.drawable.Icon getIcon();
+    method public int getPriority();
+    method public java.lang.CharSequence getTitle();
+    method public boolean isChecked();
+    method public boolean isToggle();
+    method public androidx.app.slice.builders.SliceAction setChecked(boolean);
+    method public androidx.app.slice.builders.SliceAction setContentDescription(java.lang.CharSequence);
+    method public androidx.app.slice.builders.SliceAction setPriority(int);
+  }
+
+  public abstract class TemplateSliceBuilder {
+    method public androidx.app.slice.Slice build();
+  }
+
+}
+
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
new file mode 100644
index 0000000..ae7407b
--- /dev/null
+++ b/slices/builders/build.gradle
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryVersions
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    implementation(project(":slices-core"))
+    implementation project(":support-annotations")
+}
+
+supportLibrary {
+    name = "Slice builders"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SLICES
+    inceptionYear = "2017"
+    description = "A set of builders to create templates using SliceProvider APIs"
+    minSdkVersion = 24
+}
diff --git a/slices/builders/lint-baseline.xml b/slices/builders/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/slices/builders/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/slices/builders/src/main/AndroidManifest.xml b/slices/builders/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6f19650
--- /dev/null
+++ b/slices/builders/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="androidx.app.slice.builders"/>
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java
new file mode 100644
index 0000000..07089bf
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/GridBuilder.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+
+import java.util.function.Consumer;
+
+import androidx.app.slice.builders.impl.TemplateBuilderImpl;
+
+
+/**
+ * Builder to construct a row of slice content in a grid format.
+ * <p>
+ * A grid row is composed of cells, each cell can have a combination of text and images. For more
+ * details see {@link CellBuilder}.
+ * </p>
+ */
+public class GridBuilder extends TemplateSliceBuilder {
+
+    private androidx.app.slice.builders.impl.GridBuilder mImpl;
+    private boolean mHasSeeMore;
+
+    /**
+     * Create a builder which will construct a slice displayed in a grid format.
+     * @param parent The builder constructing the parent slice.
+     */
+    public GridBuilder(@NonNull ListBuilder parent) {
+        super(parent.getImpl().createGridBuilder());
+    }
+
+    @Override
+    void setImpl(TemplateBuilderImpl impl) {
+        mImpl = (androidx.app.slice.builders.impl.GridBuilder) impl;
+    }
+
+    /**
+     * Add a cell to the grid builder.
+     */
+    @NonNull
+    public GridBuilder addCell(@NonNull CellBuilder builder) {
+        mImpl.addCell((TemplateBuilderImpl) builder.mImpl);
+        return this;
+    }
+
+    /**
+     * Add a cell to the grid builder.
+     */
+    @RequiresApi(Build.VERSION_CODES.N)
+    @NonNull
+    public GridBuilder addCell(@NonNull Consumer<CellBuilder> c) {
+        CellBuilder b = new CellBuilder(this);
+        c.accept(b);
+        return addCell(b);
+    }
+
+    /**
+     * If all content in a slice cannot be shown, the cell added here may be displayed where the
+     * content is cut off.
+     * <p>
+     * This method should only be used if you want to display a custom cell to indicate more
+     * content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
+     * choose to specify a custom cell, the cell should have
+     * {@link CellBuilder#setContentIntent(PendingIntent)} specified to take the user to an
+     * activity to see all of the content.
+     * </p>
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    @NonNull
+    public GridBuilder addSeeMoreCell(@NonNull CellBuilder builder) {
+        if (mHasSeeMore) {
+            throw new IllegalStateException("Trying to add see more cell when one has "
+                    + "already been added");
+        }
+        mImpl.addSeeMoreCell((TemplateBuilderImpl) builder.mImpl);
+        mHasSeeMore = true;
+        return this;
+    }
+
+    /**
+     * If all content in a slice cannot be shown, the cell added here may be displayed where the
+     * content is cut off.
+     * <p>
+     * This method should only be used if you want to display a custom cell to indicate more
+     * content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
+     * choose to specify a custom cell, the cell should have
+     * {@link CellBuilder#setContentIntent(PendingIntent)} specified to take the user to an
+     * activity to see all of the content.
+     * </p>
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    @RequiresApi(Build.VERSION_CODES.N)
+    @NonNull
+    public GridBuilder addSeeMoreCell(@NonNull Consumer<CellBuilder> c) {
+        CellBuilder b = new CellBuilder(this);
+        c.accept(b);
+        return addSeeMoreCell(b);
+    }
+
+    /**
+     * If all content in a slice cannot be shown, a "see more" affordance may be displayed where
+     * the content is cut off. The action added here should take the user to an activity to see
+     * all of the content, and will be invoked when the "see more" affordance is tapped.
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    @NonNull
+    public GridBuilder addSeeMoreAction(@NonNull PendingIntent intent) {
+        if (mHasSeeMore) {
+            throw new IllegalStateException("Trying to add see more action when one has "
+                    + "already been added");
+        }
+        mImpl.addSeeMoreAction(intent);
+        mHasSeeMore = true;
+        return this;
+    }
+
+    /**
+     * Sets the intent to send when the slice is activated.
+     */
+    @NonNull
+    public GridBuilder setPrimaryAction(@NonNull SliceAction action) {
+        mImpl.setPrimaryAction(action);
+        return this;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public androidx.app.slice.builders.impl.GridBuilder getImpl() {
+        return mImpl;
+    }
+
+    /**
+     * Sub-builder to construct a cell to be displayed in a grid.
+     * <p>
+     * Content added to a cell will be displayed in order vertically, for example the below code
+     * would construct a cell with "First text", and image below it, and then "Second text" below
+     * the image.
+     *
+     * <pre class="prettyprint">
+     * CellBuilder cb = new CellBuilder(parent, sliceUri);
+     * cb.addText("First text")
+     *   .addImage(middleIcon)
+     *   .addText("Second text");
+     * </pre>
+     *
+     * A cell can have at most two text items and one image.
+     * </p>
+     */
+    public static final class CellBuilder extends TemplateSliceBuilder {
+        private androidx.app.slice.builders.impl.GridBuilder.CellBuilder mImpl;
+
+        /**
+         * Create a builder which will construct a slice displayed as a cell in a grid.
+         * @param parent The builder constructing the parent slice.
+         */
+        public CellBuilder(@NonNull GridBuilder parent) {
+            super(parent.mImpl.createGridBuilder());
+        }
+
+        /**
+         * Create a builder which will construct a slice displayed as a cell in a grid.
+         * @param uri Uri to tag for this slice.
+         */
+        public CellBuilder(@NonNull GridBuilder parent, @NonNull Uri uri) {
+            super(parent.mImpl.createGridBuilder(uri));
+        }
+
+        @Override
+        void setImpl(TemplateBuilderImpl impl) {
+            mImpl = (androidx.app.slice.builders.impl.GridBuilder.CellBuilder) impl;
+        }
+
+        /**
+         * Adds text to the cell. There can be at most two text items, the first two added
+         * will be used, others will be ignored.
+         */
+        @NonNull
+        public CellBuilder addText(@NonNull CharSequence text) {
+            return addText(text, false /* isLoading */);
+        }
+
+        /**
+         * Adds text to the cell. There can be at most two text items, the first two added
+         * will be used, others will be ignored.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public CellBuilder addText(@Nullable CharSequence text, boolean isLoading) {
+            mImpl.addText(text, isLoading);
+            return this;
+        }
+
+        /**
+         * Adds text to the cell. Text added with this method will be styled as a title.
+         * There can be at most two text items, the first two added will be used, others
+         * will be ignored.
+         */
+        @NonNull
+        public CellBuilder addTitleText(@NonNull CharSequence text) {
+            return addTitleText(text, false /* isLoading */);
+        }
+
+        /**
+         * Adds text to the cell. Text added with this method will be styled as a title.
+         * There can be at most two text items, the first two added will be used, others
+         * will be ignored.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public CellBuilder addTitleText(@Nullable CharSequence text, boolean isLoading) {
+            mImpl.addTitleText(text, isLoading);
+            return this;
+        }
+
+        /**
+         * Adds an image to the cell that should be displayed as large as the cell allows.
+         * There can be at most one image, the first one added will be used, others will be ignored.
+         *
+         * @param image the image to display in the cell.
+         */
+        @NonNull
+        public CellBuilder addLargeImage(@NonNull Icon image) {
+            return addLargeImage(image, false /* isLoading */);
+        }
+
+        /**
+         * Adds an image to the cell that should be displayed as large as the cell allows.
+         * There can be at most one image, the first one added will be used, others will be ignored.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public CellBuilder addLargeImage(@Nullable Icon image, boolean isLoading) {
+            mImpl.addLargeImage(image, isLoading);
+            return this;
+        }
+
+        /**
+         * Adds an image to the cell. There can be at most one image, the first one added
+         * will be used, others will be ignored.
+         *
+         * @param image the image to display in the cell.
+         */
+        @NonNull
+        public CellBuilder addImage(@NonNull Icon image) {
+            return addImage(image, false /* isLoading */);
+        }
+
+        /**
+         * Adds an image to the cell. There can be at most one image, the first one added
+         * will be used, others will be ignored.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public CellBuilder addImage(@Nullable Icon image, boolean isLoading) {
+            mImpl.addImage(image, isLoading);
+            return this;
+        }
+
+        /**
+         * Sets the action to be invoked if the user taps on this cell in the row.
+         */
+        @NonNull
+        public CellBuilder setContentIntent(@NonNull PendingIntent intent) {
+            mImpl.setContentIntent(intent);
+            return this;
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java
new file mode 100644
index 0000000..fd7ac96
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/ListBuilder.java
@@ -0,0 +1,750 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+
+import java.util.function.Consumer;
+
+import androidx.app.slice.SliceSpecs;
+import androidx.app.slice.builders.impl.ListBuilderBasicImpl;
+import androidx.app.slice.builders.impl.ListBuilderV1Impl;
+import androidx.app.slice.builders.impl.TemplateBuilderImpl;
+
+/**
+ * Builder to construct slice content in a list format.
+ * <p>
+ * Use this builder for showing rows of content which is composed of text, images, and actions. For
+ * more details see {@link RowBuilder}.
+ * </p>
+ * <p>
+ * Slices can be displayed in different formats:
+ * <ul>
+ *     <li>Shortcut - The slice is displayed as an icon with a text label.</li>
+ *     <li>Small - Only a single row of content is displayed in small format, to specify which
+ *         row to display in small format see {@link #setHeader(HeaderBuilder)}.</li>
+ *     <li>Large - As many rows of content are shown as possible. If the presenter of the slice
+ *         allows scrolling then all rows of content will be displayed in a scrollable view.</li>
+ * </ul>
+ * </p>
+ *
+ * @see RowBuilder
+ */
+public class ListBuilder extends TemplateSliceBuilder {
+
+    private boolean mHasSeeMore;
+    private androidx.app.slice.builders.impl.ListBuilder mImpl;
+
+    /**
+     * Create a builder which will construct a slice that will display rows of content.
+     * @param uri Uri to tag for this slice.
+     */
+    public ListBuilder(@NonNull Context context, @NonNull Uri uri) {
+        super(context, uri);
+    }
+
+    @Override
+    void setImpl(TemplateBuilderImpl impl) {
+        mImpl = (androidx.app.slice.builders.impl.ListBuilder) impl;
+    }
+
+    /**
+     * Add a row to list builder.
+     */
+    @NonNull
+    public ListBuilder addRow(@NonNull RowBuilder builder) {
+        mImpl.addRow((TemplateBuilderImpl) builder.mImpl);
+        return this;
+    }
+
+    /**
+     * Add a row the list builder.
+     */
+    @RequiresApi(api = Build.VERSION_CODES.N)
+    @NonNull
+    public ListBuilder addRow(@NonNull Consumer<RowBuilder> c) {
+        RowBuilder b = new RowBuilder(this);
+        c.accept(b);
+        return addRow(b);
+    }
+
+    /**
+     * Add a grid row to the list builder.
+     */
+    @NonNull
+    public ListBuilder addGrid(@NonNull GridBuilder builder) {
+        mImpl.addGrid((TemplateBuilderImpl) builder.getImpl());
+        return this;
+    }
+
+    /**
+     * Add a grid row to the list builder.
+     */
+    @RequiresApi(api = Build.VERSION_CODES.N)
+    @NonNull
+    public ListBuilder addGrid(@NonNull Consumer<GridBuilder> c) {
+        GridBuilder b = new GridBuilder(this);
+        c.accept(b);
+        return addGrid(b);
+    }
+
+    /**
+     * Adds a header to this template.
+     * <p>
+     * The header should contain a title that is representative of the content in this slice along
+     * with an intent that links to the app activity associated with this content.
+     */
+    @NonNull
+    public ListBuilder setHeader(@NonNull HeaderBuilder builder) {
+        mImpl.setHeader((TemplateBuilderImpl) builder.mImpl);
+        return this;
+    }
+
+    /**
+     * Adds a header to this template.
+     * <p>
+     * The header should contain a title that is representative of the content in this slice along
+     * with an intent that links to the app activity associated with this content.
+     */
+    @RequiresApi(api = Build.VERSION_CODES.N)
+    @NonNull
+    public ListBuilder setHeader(@NonNull Consumer<HeaderBuilder> c) {
+        HeaderBuilder b = new HeaderBuilder(this);
+        c.accept(b);
+        return setHeader(b);
+    }
+
+    /**
+     * Adds an action to this template. Actions added with this method are grouped together and
+     * may be shown on the template in large or small formats. Generally these actions will be
+     * displayed in the order they were added, however, if not all actions can be displayed then
+     * actions with a higher priority may be shown first.
+     *
+     * @see SliceAction
+     * @see SliceAction#setPriority(int)
+     */
+    @NonNull
+    public ListBuilder addAction(@NonNull SliceAction action) {
+        mImpl.addAction(action);
+        return this;
+    }
+
+    /**
+     * Sets the color to tint items displayed by this template (e.g. icons).
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @NonNull
+    public ListBuilder setColor(@ColorInt int color) {
+        mImpl.setColor(color);
+        return this;
+    }
+
+    /**
+     * If all content in a slice cannot be shown, the row added here may be displayed where the
+     * content is cut off. This row should have an affordance to take the user to an activity to
+     * see all of the content.
+     * <p>
+     * This method should only be used if you want to display a custom row to indicate more
+     * content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
+     * choose to specify a custom row, the row should have a content intent or action end item
+     * specified to take the user to an activity to see all of the content.
+     * </p>
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    @NonNull
+    public ListBuilder addSeeMoreRow(@NonNull RowBuilder builder) {
+        if (mHasSeeMore) {
+            throw new IllegalArgumentException("Trying to add see more row when one has "
+                    + "already been added");
+        }
+        mImpl.addSeeMoreRow((TemplateBuilderImpl) builder.mImpl);
+        mHasSeeMore = true;
+        return this;
+    }
+
+    /**
+     * If all content in a slice cannot be shown, the row added here may be displayed where the
+     * content is cut off. This row should have an affordance to take the user to an activity to
+     * see all of the content.
+     * <p>
+     * This method should only be used if you want to display a custom row to indicate more
+     * content, consider using {@link #addSeeMoreAction(PendingIntent)} otherwise. If you do
+     * choose to specify a custom row, the row should have a content intent or action end item
+     * specified to take the user to an activity to see all of the content.
+     * </p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    @RequiresApi(api = Build.VERSION_CODES.N)
+    @NonNull
+    public ListBuilder addSeeMoreRow(@NonNull Consumer<RowBuilder> c) {
+        RowBuilder b = new RowBuilder(this);
+        c.accept(b);
+        return addSeeMoreRow(b);
+    }
+
+    /**
+     * If all content in a slice cannot be shown, a "see more" affordance may be displayed where
+     * the content is cut off. The action added here should take the user to an activity to see
+     * all of the content, and will be invoked when the "see more" affordance is tapped.
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    @NonNull
+    public ListBuilder addSeeMoreAction(@NonNull PendingIntent intent) {
+        if (mHasSeeMore) {
+            throw new IllegalArgumentException("Trying to add see more action when one has "
+                    + "already been added");
+        }
+        mImpl.addSeeMoreAction(intent);
+        mHasSeeMore = true;
+        return this;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @Override
+    protected TemplateBuilderImpl selectImpl() {
+        if (checkCompatible(SliceSpecs.LIST)) {
+            return new ListBuilderV1Impl(getBuilder(), SliceSpecs.LIST);
+        } else if (checkCompatible(SliceSpecs.BASIC)) {
+            return new ListBuilderBasicImpl(getBuilder(), SliceSpecs.BASIC);
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public androidx.app.slice.builders.impl.ListBuilder getImpl() {
+        return mImpl;
+    }
+
+    /**
+     * Add an input range row to the list builder.
+     */
+    @NonNull
+    public ListBuilder addInputRange(@NonNull InputRangeBuilder b) {
+        mImpl.addInputRange((TemplateBuilderImpl) b.mImpl);
+        return this;
+    }
+
+    /**
+     * Add an input range row to the list builder.
+     */
+    @NonNull
+    public ListBuilder addInputRange(@NonNull Consumer<InputRangeBuilder> c) {
+        InputRangeBuilder inputRangeBuilder = new InputRangeBuilder(this);
+        c.accept(inputRangeBuilder);
+        return addInputRange(inputRangeBuilder);
+    }
+
+    /**
+     * Add a range row to the list builder.
+     */
+    @NonNull
+    public ListBuilder addRange(@NonNull RangeBuilder rangeBuilder) {
+        mImpl.addRange((TemplateBuilderImpl) rangeBuilder.mImpl);
+        return this;
+    }
+
+    /**
+     * Add a range row to the list builder.
+     */
+    @NonNull
+    public ListBuilder addRange(@NonNull Consumer<RangeBuilder> c) {
+        RangeBuilder rangeBuilder = new RangeBuilder(this);
+        c.accept(rangeBuilder);
+        return addRange(rangeBuilder);
+    }
+
+    /**
+     * Builder to construct a range row.
+     */
+    public static class RangeBuilder extends TemplateSliceBuilder {
+        private androidx.app.slice.builders.impl.ListBuilder.RangeBuilder mImpl;
+
+        public RangeBuilder(@NonNull ListBuilder parent) {
+            super(parent.mImpl.createRangeBuilder());
+        }
+
+        /**
+         * Set the upper limit of the range. The default is 100.
+         */
+        @NonNull
+        public RangeBuilder setMax(int max) {
+            mImpl.setMax(max);
+            return this;
+        }
+
+        /**
+         * Set the current value of the range.
+         */
+        @NonNull
+        public RangeBuilder setValue(int value) {
+            mImpl.setValue(value);
+            return this;
+        }
+
+        /**
+         * Set the title.
+         */
+        @NonNull
+        public RangeBuilder setTitle(@NonNull CharSequence title) {
+            mImpl.setTitle(title);
+            return this;
+        }
+
+        @Override
+        void setImpl(TemplateBuilderImpl impl) {
+            mImpl = (androidx.app.slice.builders.impl.ListBuilder.RangeBuilder) impl;
+        }
+    }
+
+    /**
+     * Builder to construct a input range row.
+     */
+    public static class InputRangeBuilder extends TemplateSliceBuilder {
+        private androidx.app.slice.builders.impl.ListBuilder.InputRangeBuilder mImpl;
+
+        public InputRangeBuilder(@NonNull ListBuilder parent) {
+            super(parent.mImpl.createInputRangeBuilder());
+        }
+
+        /**
+         * Set the upper limit of the range. The default is 100.
+         */
+        @NonNull
+        public InputRangeBuilder setMax(int max) {
+            mImpl.setMax(max);
+            return this;
+        }
+
+        /**
+         * Set the current value of the range.
+         */
+        @NonNull
+        public InputRangeBuilder setValue(int value) {
+            mImpl.setValue(value);
+            return this;
+        }
+
+        /**
+         * Set the title.
+         */
+        @NonNull
+        public InputRangeBuilder setTitle(@NonNull CharSequence title) {
+            mImpl.setTitle(title);
+            return this;
+        }
+
+
+        /**
+         * Set the {@link PendingIntent} to send when the current value is updated.
+         */
+        @NonNull
+        public InputRangeBuilder setAction(@NonNull PendingIntent action) {
+            mImpl.setAction(action);
+            return this;
+        }
+
+        /**
+         * Set the {@link Icon} to be displayed as the thumb on the input range.
+         */
+        @NonNull
+        public InputRangeBuilder setThumb(@NonNull Icon thumb) {
+            mImpl.setThumb(thumb);
+            return this;
+        }
+
+        @Override
+        void setImpl(TemplateBuilderImpl impl) {
+            mImpl = (androidx.app.slice.builders.impl.ListBuilder.InputRangeBuilder) impl;
+        }
+    }
+
+    /**
+     * Sub-builder to construct a row of slice content.
+     * <p>
+     * Row content can have:
+     * <ul>
+     *     <li>Title item - This is only displayed if this is a list item in a large template, it
+     *     will not be shown if this template is being used for small format. The item appears at
+     *     the start of the template. There can only be one title item displayed, and it could be a
+     *     timestamp, image, or a tappable icon.</li>
+     *     <li>Title - Formatted as a title.</li>
+     *     <li>Subtitle - Appears below the title (if one exists) and is formatted as normal text.
+     *     </li>
+     *     <li>End item -  Appears at the end of the template, there can be multiple end items but
+     *     they are only shown if there's enough space. End items can be a timestamp, image, or a
+     *     tappable icon.</li>
+     * </ul>
+     * </p>
+     *
+     * @see ListBuilder
+     */
+    public static class RowBuilder extends TemplateSliceBuilder {
+
+        private androidx.app.slice.builders.impl.ListBuilder.RowBuilder mImpl;
+
+        private boolean mHasEndActionOrToggle;
+        private boolean mHasEndImage;
+        private boolean mHasDefaultToggle;
+        private boolean mHasTimestamp;
+
+        /**
+         * Create a builder which will construct a slice displayed in a row format.
+         * @param parent The builder constructing the parent slice.
+         */
+        public RowBuilder(@NonNull ListBuilder parent) {
+            super(parent.mImpl.createRowBuilder());
+        }
+
+        /**
+         * Create a builder which will construct a slice displayed in a row format.
+         * @param uri Uri to tag for this slice.
+         */
+        public RowBuilder(@NonNull ListBuilder parent, @NonNull Uri uri) {
+            super(parent.mImpl.createRowBuilder(uri));
+        }
+
+        /**
+         * Create a builder which will construct a slice displayed in a row format.
+         * @param uri Uri to tag for this slice.
+         */
+        public RowBuilder(@NonNull Context context, @NonNull Uri uri) {
+            super(new ListBuilder(context, uri).mImpl.createRowBuilder(uri));
+        }
+
+        /**
+         * Sets the title item to be the provided timestamp. Only one timestamp can be added, if
+         * one is already added this will throw {@link IllegalArgumentException}.
+         * <p>
+         * There can only be one title item, this will replace any other title
+         * items that may have been set.
+         */
+        @NonNull
+        public RowBuilder setTitleItem(long timeStamp) {
+            if (mHasTimestamp) {
+                throw new IllegalArgumentException("Trying to add a timestamp when one has "
+                        + "already been added");
+            }
+            mImpl.setTitleItem(timeStamp);
+            mHasTimestamp = true;
+            return this;
+        }
+
+        /**
+         * Sets the title item to be the provided icon. There can only be one title item, this
+         * will replace any other title items that may have been set.
+         */
+        @NonNull
+        public RowBuilder setTitleItem(@NonNull Icon icon) {
+            mImpl.setTitleItem(icon);
+            return this;
+        }
+
+        /**
+         * Sets the title item to be the provided icon. There can only be one title item, this
+         * will replace any other title items that may have been set.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public RowBuilder setTitleItem(@Nullable Icon icon, boolean isLoading) {
+            mImpl.setTitleItem(icon, isLoading);
+            return this;
+        }
+
+        /**
+         * Sets the title item to be a tappable icon. There can only be one title item, this will
+         * replace any other title items that may have been set.
+         */
+        @NonNull
+        public RowBuilder setTitleItem(@NonNull SliceAction action) {
+            return setTitleItem(action, false /* isLoading */);
+        }
+
+        /**
+         * Sets the title item to be a tappable icon. There can only be one title item, this will
+         * replace any other title items that may have been set.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public RowBuilder setTitleItem(@NonNull SliceAction action, boolean isLoading) {
+            mImpl.setTitleItem(action, isLoading);
+            return this;
+        }
+
+        /**
+         * Sets the action to be invoked if the user taps on the main content of the template.
+         */
+        @NonNull
+        public RowBuilder setPrimaryAction(@NonNull SliceAction action) {
+            mImpl.setPrimaryAction(action);
+            return this;
+        }
+
+        /**
+         * Sets the title text.
+         */
+        @NonNull
+        public RowBuilder setTitle(@NonNull CharSequence title) {
+            mImpl.setTitle(title);
+            return this;
+        }
+
+        /**
+         * Sets the title text.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public RowBuilder setTitle(@Nullable CharSequence title, boolean isLoading) {
+            mImpl.setTitle(title, isLoading);
+            return this;
+        }
+
+        /**
+         * Sets the subtitle text.
+         */
+        @NonNull
+        public RowBuilder setSubtitle(@NonNull CharSequence subtitle) {
+            return setSubtitle(subtitle, false /* isLoading */);
+        }
+
+        /**
+         * Sets the subtitle text.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public RowBuilder setSubtitle(@Nullable CharSequence subtitle, boolean isLoading) {
+            mImpl.setSubtitle(subtitle, isLoading);
+            return this;
+        }
+
+        /**
+         * Adds a timestamp to be displayed at the end of the row. Only one timestamp can be added,
+         * if one is already added this will throw {@link IllegalArgumentException}.
+         */
+        @NonNull
+        public RowBuilder addEndItem(long timeStamp) {
+            if (mHasTimestamp) {
+                throw new IllegalArgumentException("Trying to add a timestamp when one has "
+                        + "already been added");
+            }
+            mImpl.addEndItem(timeStamp);
+            mHasTimestamp = true;
+            return this;
+        }
+
+        /**
+         * Adds an icon to be displayed at the end of the row. A mixture of icons and actions
+         * is not permitted. If an action has already been added this will throw
+         * {@link IllegalArgumentException}.
+         */
+        @NonNull
+        public RowBuilder addEndItem(@NonNull Icon icon) {
+            return addEndItem(icon, false /* isLoading */);
+        }
+
+        /**
+         * Adds an icon to be displayed at the end of the row. A mixture of icons and actions
+         * is not permitted. If an action has already been added this will throw
+         * {@link IllegalArgumentException}.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public RowBuilder addEndItem(@NonNull Icon icon, boolean isLoading) {
+            if (mHasEndActionOrToggle) {
+                throw new IllegalArgumentException("Trying to add an icon to end items when an"
+                        + "action has already been added. End items cannot have a mixture of "
+                        + "actions and icons.");
+            }
+            mImpl.addEndItem(icon, isLoading);
+            mHasEndImage = true;
+            return this;
+        }
+
+        /**
+         * Adds an action to display at the end of the row. A mixture of icons and
+         * actions is not permitted. If an icon has already been added, this will throw
+         * {@link IllegalArgumentException}.
+         */
+        @NonNull
+        public RowBuilder addEndItem(@NonNull SliceAction action) {
+            return addEndItem(action, false /* isLoading */);
+        }
+
+        /**
+         * Adds an action to be displayed at the end of the row. A mixture of icons and
+         * actions is not permitted. If an icon has already been added, this will throw
+         * {@link IllegalArgumentException}.
+         * <p>
+         * Use this method to specify content that will appear in the template once it's been
+         * loaded.
+         * </p>
+         * @param isLoading indicates whether the app is doing work to load the added content in the
+         *                  background or not.
+         */
+        @NonNull
+        public RowBuilder addEndItem(@NonNull SliceAction action, boolean isLoading) {
+            if (mHasEndImage) {
+                throw new IllegalArgumentException("Trying to add an action to end items when an"
+                        + "icon has already been added. End items cannot have a mixture of "
+                        + "actions and icons.");
+            }
+            if (mHasDefaultToggle) {
+                throw new IllegalStateException("Only one non-custom toggle can be added "
+                        + "in a single row. If you would like to include multiple toggles "
+                        + "in a row, set a custom icon for each toggle.");
+            }
+            mImpl.addEndItem(action, isLoading);
+            mHasDefaultToggle = action.isDefaultToggle();
+            mHasEndActionOrToggle = true;
+            return this;
+        }
+
+        @Override
+        void setImpl(TemplateBuilderImpl impl) {
+            mImpl = (androidx.app.slice.builders.impl.ListBuilder.RowBuilder) impl;
+        }
+
+        /**
+         * @hide
+         */
+        @RestrictTo(LIBRARY)
+        public androidx.app.slice.builders.impl.ListBuilder.RowBuilder getImpl() {
+            return mImpl;
+        }
+
+    }
+
+    /**
+     * Builder to construct a header. A header is displayed at the top of a list and can have
+     * a title, subtitle, and an action.
+     *
+     * @see ListBuilder#setHeader(HeaderBuilder)
+     */
+    public static class HeaderBuilder extends TemplateSliceBuilder {
+        private androidx.app.slice.builders.impl.ListBuilder.HeaderBuilder mImpl;
+
+        /**
+         * Create builder for header templates.
+         */
+        public HeaderBuilder(@NonNull ListBuilder parent) {
+            super(parent.mImpl.createHeaderBuilder());
+        }
+
+        /**
+         * Create builder for header templates.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        public HeaderBuilder(@NonNull ListBuilder parent, @NonNull Uri uri) {
+            super(parent.mImpl.createHeaderBuilder(uri));
+        }
+
+        /**
+         * Sets the title to be shown in this header.
+         */
+        @NonNull
+        public HeaderBuilder setTitle(@NonNull CharSequence title) {
+            mImpl.setTitle(title);
+            return this;
+        }
+
+        /**
+         * Sets the subtitle to be shown in this header.
+         */
+        @NonNull
+        public HeaderBuilder setSubtitle(@NonNull CharSequence subtitle) {
+            mImpl.setSubtitle(subtitle);
+            return this;
+        }
+
+        /**
+         * Sets the summary subtitle to be shown in this header. If unset, the normal subtitle
+         * will be used. The summary is used when the parent template is presented in a
+         * small format.
+         */
+        @NonNull
+        public HeaderBuilder setSummarySubtitle(@NonNull CharSequence summarySubtitle) {
+            mImpl.setSummarySubtitle(summarySubtitle);
+            return this;
+        }
+
+        /**
+         * Sets the action to invoke when the header is activated.
+         */
+        @NonNull
+        public HeaderBuilder setPrimaryAction(@NonNull SliceAction action) {
+            mImpl.setPrimaryAction(action);
+            return this;
+        }
+
+        @Override
+        void setImpl(TemplateBuilderImpl impl) {
+            mImpl = (androidx.app.slice.builders.impl.ListBuilder.HeaderBuilder) impl;
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/MessagingSliceBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/MessagingSliceBuilder.java
new file mode 100644
index 0000000..e51fd0b
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/MessagingSliceBuilder.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+
+import java.util.function.Consumer;
+
+import androidx.app.slice.SliceSpecs;
+import androidx.app.slice.builders.impl.MessagingBasicImpl;
+import androidx.app.slice.builders.impl.MessagingBuilder;
+import androidx.app.slice.builders.impl.MessagingListV1Impl;
+import androidx.app.slice.builders.impl.MessagingV1Impl;
+import androidx.app.slice.builders.impl.TemplateBuilderImpl;
+
+/**
+ * Builder to construct slice content in a messaging format.
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class MessagingSliceBuilder extends TemplateSliceBuilder {
+
+    /**
+     * The maximum number of messages that will be retained in the Slice itself (the
+     * number displayed is up to the platform).
+     */
+    public static final int MAXIMUM_RETAINED_MESSAGES = 50;
+
+    private MessagingBuilder mBuilder;
+
+    /**
+     * Create a MessagingSliceBuilder with the specified uri.
+     */
+    public MessagingSliceBuilder(@NonNull Context context, @NonNull Uri uri) {
+        super(context, uri);
+    }
+
+    /**
+     * Add a subslice to this builder.
+     */
+    public MessagingSliceBuilder add(MessageBuilder builder) {
+        mBuilder.add((TemplateBuilderImpl) builder.mImpl);
+        return this;
+    }
+
+    /**
+     * Add a subslice to this builder.
+     */
+    @RequiresApi(api = Build.VERSION_CODES.N)
+    public MessagingSliceBuilder add(Consumer<MessageBuilder> c) {
+        MessageBuilder b = new MessageBuilder(this);
+        c.accept(b);
+        return add(b);
+    }
+
+    @Override
+    void setImpl(TemplateBuilderImpl impl) {
+        mBuilder = (MessagingBuilder) impl;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @Override
+    protected TemplateBuilderImpl selectImpl() {
+        if (checkCompatible(SliceSpecs.MESSAGING)) {
+            return new MessagingV1Impl(getBuilder(), SliceSpecs.MESSAGING);
+        } else if (checkCompatible(SliceSpecs.LIST)) {
+            return new MessagingListV1Impl(getBuilder(), SliceSpecs.LIST);
+        } else if (checkCompatible(SliceSpecs.BASIC)) {
+            return new MessagingBasicImpl(getBuilder(), SliceSpecs.BASIC);
+        }
+        return null;
+    }
+
+    /**
+     * Builder for adding a message to {@link MessagingSliceBuilder}.
+     */
+    public static final class MessageBuilder extends TemplateSliceBuilder {
+
+        private MessagingBuilder.MessageBuilder mImpl;
+
+        /**
+         * Creates a MessageBuilder with the specified parent.
+         */
+        public MessageBuilder(MessagingSliceBuilder parent) {
+            super(parent.mBuilder.createMessageBuilder());
+        }
+
+        /**
+         * Add the icon used to display contact in the messaging experience
+         */
+        public MessageBuilder addSource(Icon source) {
+            mImpl.addSource(source);
+            return this;
+        }
+
+        /**
+         * Add the text to be used for this message.
+         */
+        public MessageBuilder addText(CharSequence text) {
+            mImpl.addText(text);
+            return this;
+        }
+
+        /**
+         * Add the time at which this message arrived in ms since Unix epoch
+         */
+        public MessageBuilder addTimestamp(long timestamp) {
+            mImpl.addTimestamp(timestamp);
+            return this;
+        }
+
+        @Override
+        void setImpl(TemplateBuilderImpl impl) {
+            mImpl = (MessagingBuilder.MessageBuilder) impl;
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/SliceAction.java b/slices/builders/src/main/java/androidx/app/slice/builders/SliceAction.java
new file mode 100644
index 0000000..57d289b
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/SliceAction.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders;
+
+import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.Slice.SUBTYPE_CONTENT_DESCRIPTION;
+import static android.app.slice.Slice.SUBTYPE_PRIORITY;
+import static android.app.slice.Slice.SUBTYPE_TOGGLE;
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+
+/**
+ * Class representing an action, supports tappable icons, custom toggle icons, and default toggles.
+ */
+public class SliceAction {
+
+    private PendingIntent mAction;
+    private Icon mIcon;
+    private CharSequence mTitle;
+    private CharSequence mContentDescription;
+    private boolean mIsToggle;
+    private boolean mIsChecked;
+    private int mPriority = -1;
+
+    /**
+     * Construct a SliceAction representing a tappable icon.
+     *
+     * @param action the pending intent to invoke for this action.
+     * @param actionIcon the icon to display for this action.
+     * @param actionTitle the title for this action, also used for content description if one hasn't
+     *                    been set via {@link #setContentDescription(CharSequence)}.
+     */
+    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+            @NonNull CharSequence actionTitle) {
+        mAction = action;
+        mIcon = actionIcon;
+        mTitle = actionTitle;
+    }
+
+    /**
+     * Construct a SliceAction representing a custom toggle icon.
+     *
+     * @param action the pending intent to invoke for this toggle.
+     * @param actionIcon the icon to display for this toggle, should have a checked and unchecked
+     *                   state.
+     * @param actionTitle the title for this toggle, also used for content description if one hasn't
+     *                    been set via {@link #setContentDescription(CharSequence)}.
+     * @param isChecked the state of the toggle.
+     */
+    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+            @NonNull CharSequence actionTitle, boolean isChecked) {
+        this(action, actionIcon, actionTitle);
+        mIsChecked = isChecked;
+        mIsToggle = true;
+    }
+
+    /**
+     * Construct a SliceAction representing a default toggle.
+     *
+     * @param action the pending intent to invoke for this toggle.
+     * @param actionTitle the title for this toggle, also used for content description if one hasn't
+     *                    been set via {@link #setContentDescription(CharSequence)}.
+     * @param isChecked the state of the toggle.
+     */
+    public SliceAction(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,
+            boolean isChecked) {
+        mAction = action;
+        mTitle = actionTitle;
+        mIsToggle = true;
+        mIsChecked = isChecked;
+
+    }
+
+    /**
+     * @param description the content description for this action.
+     */
+    @Nullable
+    public SliceAction setContentDescription(@NonNull CharSequence description) {
+        mContentDescription = description;
+        return this;
+    }
+
+    /**
+     * @param isChecked whether the state of this action is checked or not; only used for toggle
+     *                  actions.
+     */
+    public SliceAction setChecked(boolean isChecked) {
+        mIsChecked = isChecked;
+        return this;
+    }
+
+    /**
+     * Sets the priority of this action, with the lowest priority having the highest ranking.
+     */
+    public SliceAction setPriority(@IntRange(from = 0) int priority) {
+        mPriority = priority;
+        return this;
+    }
+
+    /**
+     * @return the {@link PendingIntent} associated with this action.
+     */
+    @NonNull
+    public PendingIntent getAction() {
+        return mAction;
+    }
+
+    /**
+     * @return the {@link Icon} to display for this action. This can be null when the action
+     * represented is a default toggle.
+     */
+    @Nullable
+    public Icon getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * @return the title for this action.
+     */
+    @NonNull
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * @return the content description to use for this action.
+     */
+    @Nullable
+    public CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+    /**
+     * @return the priority associated with this action, -1 if unset.
+     */
+    public int getPriority() {
+        return mPriority;
+    }
+
+    /**
+     * @return whether this action represents a toggle (i.e. has a checked and unchecked state).
+     */
+    public boolean isToggle() {
+        return mIsToggle;
+    }
+
+    /**
+     * @return whether the state of this action is checked or not; only used for toggle actions.
+     */
+    public boolean isChecked() {
+        return mIsChecked;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public boolean isDefaultToggle() {
+        return mIsToggle && mIcon == null;
+    }
+
+    /**
+     * @param builder this should be a new builder that has any additional hints the action might
+     *                need.
+     * @return the slice representation of this action.
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @NonNull
+    public Slice buildSlice(@NonNull Slice.Builder builder) {
+        Slice.Builder sb = new Slice.Builder(builder);
+        if (mIcon != null) {
+            sb.addIcon(mIcon, null);
+        }
+        if (mTitle != null) {
+            sb.addText(mTitle, null, HINT_TITLE);
+        }
+        if (mContentDescription != null) {
+            sb.addText(mContentDescription, SUBTYPE_CONTENT_DESCRIPTION);
+        }
+        if (mIsToggle && mIsChecked) {
+            sb.addHints(HINT_SELECTED);
+        }
+        if (mPriority != -1) {
+            sb.addInt(mPriority, SUBTYPE_PRIORITY);
+        }
+        String subtype = mIsToggle ? SUBTYPE_TOGGLE : null;
+        builder.addHints(HINT_SHORTCUT);
+        builder.addAction(mAction, sb.build(), subtype);
+        return builder.build();
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/TemplateSliceBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/TemplateSliceBuilder.java
new file mode 100644
index 0000000..f0a495c
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/TemplateSliceBuilder.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.annotation.RestrictTo;
+import android.util.Log;
+import android.util.Pair;
+
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.SliceSpec;
+import androidx.app.slice.SliceSpecs;
+import androidx.app.slice.builders.impl.TemplateBuilderImpl;
+
+/**
+ * Base class of builders of various template types.
+ */
+public abstract class TemplateSliceBuilder {
+
+    private static final String TAG = "TemplateSliceBuilder";
+
+    private final Slice.Builder mBuilder;
+    private final Context mContext;
+    private final TemplateBuilderImpl mImpl;
+    private List<SliceSpec> mSpecs;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    protected TemplateSliceBuilder(TemplateBuilderImpl impl) {
+        mContext = null;
+        mBuilder = null;
+        mImpl = impl;
+        setImpl(impl);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    protected TemplateSliceBuilder(Slice.Builder b, Context context) {
+        mBuilder = b;
+        mContext = context;
+        mSpecs = getSpecs();
+        mImpl = selectImpl();
+        if (mImpl == null) {
+            throw new IllegalArgumentException("No valid specs found");
+        }
+        setImpl(mImpl);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public TemplateSliceBuilder(Context context, Uri uri) {
+        mBuilder = new Slice.Builder(uri);
+        mContext = context;
+        mSpecs = getSpecs();
+        mImpl = selectImpl();
+        if (mImpl == null) {
+            throw new IllegalArgumentException("No valid specs found");
+        }
+        setImpl(mImpl);
+    }
+
+    /**
+     * Construct the slice.
+     */
+    public Slice build() {
+        return mImpl.build();
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    protected Slice.Builder getBuilder() {
+        return mBuilder;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    abstract void setImpl(TemplateBuilderImpl impl);
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    protected TemplateBuilderImpl selectImpl() {
+        return null;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    protected boolean checkCompatible(SliceSpec candidate) {
+        final int size = mSpecs.size();
+        for (int i = 0; i < size; i++) {
+            if (mSpecs.get(i).canRender(candidate)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private List<SliceSpec> getSpecs() {
+        if (SliceProvider.getCurrentSpecs() != null) {
+            return SliceProvider.getCurrentSpecs();
+        }
+        // TODO: Support getting specs from pinned info.
+        Log.w(TAG, "Not currently bunding a slice");
+        return Arrays.asList(SliceSpecs.BASIC);
+    }
+
+    /**
+     * This is for typing, to clean up the code.
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    static <T> Pair<SliceSpec, Class<? extends TemplateBuilderImpl>> pair(SliceSpec spec,
+            Class<T> cls) {
+        return new Pair(spec, cls);
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java
new file mode 100644
index 0000000..066304c
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilder.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.builders.SliceAction;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public interface GridBuilder {
+    /**
+     * Create an TemplateBuilderImpl that implements {@link CellBuilder}.
+     */
+    TemplateBuilderImpl createGridBuilder();
+
+    /**
+     * Create an TemplateBuilderImpl that implements {@link CellBuilder} with the specified Uri.
+     */
+    TemplateBuilderImpl createGridBuilder(Uri uri);
+
+    /**
+     * Add a cell to this builder. Expected to be a builder from {@link #createGridBuilder}.
+     */
+    void addCell(TemplateBuilderImpl impl);
+
+    /**
+     * If all content in a slice cannot be shown, the cell added here will be displayed where the
+     * content is cut off. This cell should have an affordance to take the user to an activity to
+     * see all of the content. Expected to be a builder from {@link #createGridBuilder}.
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    void addSeeMoreCell(TemplateBuilderImpl impl);
+
+    /**
+     * If all content in a slice cannot be shown, a "see more" affordance will be displayed where
+     * the content is cut off. The action added here should take the user to an activity to see
+     * all of the content, and will be invoked when the "see more" affordance is tapped.
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    void addSeeMoreAction(PendingIntent intent);
+
+    /**
+     * Sets the action to be invoked if the user taps on the main content of the template.
+     */
+    void setPrimaryAction(SliceAction action);
+
+    /**
+     */
+    interface CellBuilder {
+        /**
+         * Adds text to the cell. There can be at most two text items, the first two added
+         * will be used, others will be ignored.
+         */
+        @NonNull
+        void addText(@NonNull CharSequence text);
+
+        /**
+         * Adds text to the cell. There can be at most two text items, the first two added
+         * will be used, others will be ignored.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        @NonNull
+        void addText(@Nullable CharSequence text, boolean isLoading);
+
+        /**
+         * Adds text to the cell. Text added with this method will be styled as a title.
+         * There can be at most two text items, the first two added will be used, others
+         * will be ignored.
+         */
+        @NonNull
+        void addTitleText(@NonNull CharSequence text);
+
+        /**
+         * Adds text to the cell. Text added with this method will be styled as a title.
+         * There can be at most two text items, the first two added will be used, others
+         * will be ignored.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        @NonNull
+        void addTitleText(@Nullable CharSequence text, boolean isLoading);
+
+        /**
+         * Adds an image to the cell that should be displayed as large as the cell allows.
+         * There can be at most one image, the first one added will be used, others will be ignored.
+         *
+         * @param image the image to display in the cell.
+         */
+        @NonNull
+        void addLargeImage(@NonNull Icon image);
+
+        /**
+         * Adds an image to the cell that should be displayed as large as the cell allows.
+         * There can be at most one image, the first one added will be used, others will be ignored.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        @NonNull
+        void addLargeImage(@Nullable Icon image, boolean isLoading);
+
+        /**
+         * Adds an image to the cell. There can be at most one image, the first one added
+         * will be used, others will be ignored.
+         *
+         * @param image the image to display in the cell.
+         */
+        @NonNull
+        void addImage(@NonNull Icon image);
+
+        /**
+         * Adds an image to the cell. There can be at most one image, the first one added
+         * will be used, others will be ignored.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.l.
+         */
+        @NonNull
+        void addImage(@NonNull Icon image, boolean isLoading);
+
+        /**
+         * Sets the action to be invoked if the user taps on this cell in the row.
+         */
+        @NonNull
+        void setContentIntent(@NonNull PendingIntent intent);
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderBasicImpl.java
new file mode 100644
index 0000000..f0cb570
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderBasicImpl.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.builders.SliceAction;
+
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public class GridBuilderBasicImpl extends TemplateBuilderImpl implements GridBuilder {
+
+    /**
+     */
+    public GridBuilderBasicImpl(@NonNull ListBuilderBasicImpl parent) {
+        super(parent.createChildBuilder(), null);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createGridBuilder() {
+        return new CellBuilder(this);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createGridBuilder(Uri uri) {
+        return new CellBuilder(uri);
+    }
+
+    /**
+     */
+    @Override
+    public void addCell(TemplateBuilderImpl impl) {
+        // TODO: Consider extracting some grid content for the basic version.
+    }
+
+    /**
+     */
+    @Override
+    public void addSeeMoreCell(TemplateBuilderImpl impl) {
+    }
+
+    /**
+     */
+    @Override
+    public void addSeeMoreAction(PendingIntent intent) {
+    }
+
+    /**
+     */
+    @Override
+    public void setPrimaryAction(SliceAction action) {
+    }
+
+    /**
+     */
+    @Override
+    public void apply(Slice.Builder builder) {
+
+    }
+
+    /**
+     */
+    public static final class CellBuilder extends TemplateBuilderImpl implements
+            GridBuilder.CellBuilder {
+
+        /**
+         */
+        public CellBuilder(@NonNull GridBuilderBasicImpl parent) {
+            super(parent.createChildBuilder(), null);
+        }
+
+        /**
+         */
+        public CellBuilder(@NonNull Uri uri) {
+            super(new Slice.Builder(uri), null);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addText(@NonNull CharSequence text) {
+        }
+
+        /**
+         */
+        @Override
+        public void addText(@Nullable CharSequence text, boolean isLoading) {
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addTitleText(@NonNull CharSequence text) {
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addTitleText(@Nullable CharSequence text, boolean isLoading) {
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addLargeImage(@NonNull Icon image) {
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addLargeImage(@Nullable Icon image, boolean isLoading) {
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addImage(@NonNull Icon image) {
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addImage(@Nullable Icon image, boolean isLoading) {
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setContentIntent(@NonNull PendingIntent intent) {
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder builder) {
+
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderListV1Impl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderListV1Impl.java
new file mode 100644
index 0000000..2856b9f
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/GridBuilderListV1Impl.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.app.slice.Slice.HINT_HORIZONTAL;
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_PARTIAL;
+import static android.app.slice.Slice.HINT_SEE_MORE;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.builders.SliceAction;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public class GridBuilderListV1Impl extends TemplateBuilderImpl implements GridBuilder {
+
+    private SliceAction mPrimaryAction;
+
+    /**
+     */
+    public GridBuilderListV1Impl(@NonNull ListBuilderV1Impl parent) {
+        super(parent.createChildBuilder(), null);
+    }
+
+    /**
+     */
+    @Override
+    @NonNull
+    public Slice build() {
+        Slice.Builder sb = new Slice.Builder(getBuilder())
+                .addHints(HINT_HORIZONTAL, HINT_LIST_ITEM);
+        sb.addSubSlice(getBuilder().addHints(HINT_HORIZONTAL, HINT_LIST_ITEM).build());
+        if (mPrimaryAction != null) {
+            Slice.Builder actionBuilder = new Slice.Builder(getBuilder())
+                    .addHints(HINT_SHORTCUT, HINT_TITLE);
+            sb.addSubSlice(mPrimaryAction.buildSlice(actionBuilder));
+        }
+        return sb.build();
+    }
+
+    /**
+     */
+    @Override
+    public void apply(Slice.Builder builder) {
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createGridBuilder() {
+        return new CellBuilder(this);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createGridBuilder(Uri uri) {
+        return new CellBuilder(uri);
+    }
+
+    /**
+     */
+    @Override
+    public void addCell(TemplateBuilderImpl builder) {
+        getBuilder().addSubSlice(builder.build());
+    }
+
+
+    /**
+     */
+    @Override
+    public void addSeeMoreCell(@NonNull TemplateBuilderImpl builder) {
+        builder.getBuilder().addHints(HINT_SEE_MORE);
+        getBuilder().addSubSlice(builder.build());
+    }
+
+    /**
+     */
+    @Override
+    public void addSeeMoreAction(PendingIntent intent) {
+        getBuilder().addSubSlice(
+                new Slice.Builder(getBuilder())
+                        .addHints(HINT_SEE_MORE)
+                        .addAction(intent, new Slice.Builder(getBuilder()).build(), null)
+                        .build());
+    }
+
+    /**
+     */
+    @Override
+    public void setPrimaryAction(SliceAction action) {
+        mPrimaryAction = action;
+    }
+
+    /**
+     */
+    public static final class CellBuilder extends TemplateBuilderImpl implements
+            GridBuilder.CellBuilder {
+
+        private PendingIntent mContentIntent;
+
+        /**
+         */
+        public CellBuilder(@NonNull GridBuilderListV1Impl parent) {
+            super(parent.createChildBuilder(), null);
+        }
+
+        /**
+         */
+        public CellBuilder(@NonNull Uri uri) {
+            super(new Slice.Builder(uri), null);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addText(@NonNull CharSequence text) {
+            addText(text, false /* isLoading */);
+        }
+
+        /**
+         */
+        @Override
+        public void addText(@Nullable CharSequence text, boolean isLoading) {
+            @Slice.SliceHint String[] hints = isLoading
+                    ? new String[] {HINT_PARTIAL}
+                    : new String[0];
+            getBuilder().addText(text, null, hints);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addTitleText(@NonNull CharSequence text) {
+            addTitleText(text, false /* isLoading */);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addTitleText(@Nullable CharSequence text, boolean isLoading) {
+            @Slice.SliceHint String[] hints = isLoading
+                    ? new String[] {HINT_PARTIAL, HINT_LARGE}
+                    : new String[] {HINT_LARGE};
+            getBuilder().addText(text, null, hints);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addLargeImage(@NonNull Icon image) {
+            addLargeImage(image, false /* isLoading */);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addLargeImage(@Nullable Icon image, boolean isLoading) {
+            @Slice.SliceHint String[] hints = isLoading
+                    ? new String[] {HINT_PARTIAL, HINT_LARGE}
+                    : new String[] {HINT_LARGE};
+            getBuilder().addIcon(image, null, hints);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addImage(@NonNull Icon image) {
+            addImage(image, false /* isLoading */);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addImage(@Nullable Icon image, boolean isLoading) {
+            @Slice.SliceHint String[] hints = isLoading
+                    ? new String[] {HINT_PARTIAL}
+                    : new String[0];
+            getBuilder().addIcon(image, null, hints);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setContentIntent(@NonNull PendingIntent intent) {
+            mContentIntent = intent;
+        }
+
+        /**
+         * @hide
+         */
+        @RestrictTo(LIBRARY)
+        @Override
+        public void apply(Slice.Builder b) {
+        }
+
+        /**
+         */
+        @Override
+        @NonNull
+        public Slice build() {
+            if (mContentIntent != null) {
+                return new Slice.Builder(getBuilder())
+                        .addHints(HINT_HORIZONTAL, HINT_LIST_ITEM)
+                        .addAction(mContentIntent, getBuilder().build(), null)
+                        .build();
+            }
+            return getBuilder().addHints(HINT_HORIZONTAL, HINT_LIST_ITEM).build();
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilder.java
new file mode 100644
index 0000000..c16da2b
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilder.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.builders.SliceAction;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public interface ListBuilder {
+
+    /**
+     * Add a row to list builder.
+     */
+    void addRow(TemplateBuilderImpl impl);
+    /**
+     * Add a grid row to the list builder.
+     */
+    void addGrid(TemplateBuilderImpl impl);
+
+    /**
+     * Adds a header to this template.
+     * <p>
+     * The header should contain a title that is representative of the content in this slice along
+     * with an intent that links to the app activity associated with this content.
+     */
+    void setHeader(TemplateBuilderImpl impl);
+
+    /**
+     * Adds an action to this template. Actions added with this method are grouped together and
+     * may be shown on the template in large or small formats.
+     */
+    void addAction(SliceAction action);
+
+    /**
+     * Add an input range row to the list builder.
+     */
+    void addInputRange(TemplateBuilderImpl builder);
+
+    /**
+     * Add a range row to the list builder.
+     */
+    void addRange(TemplateBuilderImpl builder);
+
+    /**
+     * If all content in a slice cannot be shown, the row added here will be displayed where the
+     * content is cut off. This row should have an affordance to take the user to an activity to
+     * see all of the content.
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    void addSeeMoreRow(TemplateBuilderImpl builder);
+    /**
+     * If all content in a slice cannot be shown, a "see more" affordance will be displayed where
+     * the content is cut off. The action added here should take the user to an activity to see
+     * all of the content, and will be invoked when the "see more" affordance is tapped.
+     * <p>
+     * Only one see more affordance can be added, this throws {@link IllegalStateException} if
+     * a row or action has been previously added.
+     * </p>
+     */
+    void addSeeMoreAction(PendingIntent intent);
+
+    /**
+     * Sets the color to tint items displayed by this template (e.g. icons).
+     */
+    void setColor(@ColorInt int color);
+
+    /**
+     * Create a builder that implements {@link RowBuilder}.
+     */
+    TemplateBuilderImpl createRowBuilder();
+    /**
+     * Create a builder that implements {@link RowBuilder}.
+     */
+    TemplateBuilderImpl createRowBuilder(Uri uri);
+    /**
+     * Create a builder that implements {@link GridBuilder}.
+     */
+    TemplateBuilderImpl createGridBuilder();
+    /**
+     * Create a builder that implements {@link HeaderBuilder}.
+     */
+    TemplateBuilderImpl createHeaderBuilder();
+    /**
+     * Create a builder that implements {@link HeaderBuilder}.
+     */
+    TemplateBuilderImpl createHeaderBuilder(Uri uri);
+    /**
+     * Create a builder that implements {@link InputRangeBuilder}.
+     */
+    TemplateBuilderImpl createInputRangeBuilder();
+    /**
+     * Create a builder that implements {@link RangeBuilder}.
+     */
+    TemplateBuilderImpl createRangeBuilder();
+
+    /**
+     * Builder to construct a range.
+     */
+    interface RangeBuilder {
+        /**
+         * Set the upper limit.
+         */
+        void setMax(int max);
+
+        /**
+         * Set the current value.
+         */
+        void setValue(int value);
+
+        /**
+         * Set the title.
+         */
+        void setTitle(@NonNull CharSequence title);
+    }
+
+    /**
+     * Builder to construct an input range.
+     */
+    interface InputRangeBuilder extends RangeBuilder {
+        /**
+         * Set the {@link PendingIntent} to send when the value changes.
+         */
+        void setAction(@NonNull PendingIntent action);
+
+        /**
+         * Set the {@link Icon} to be displayed as the thumb on the input range.
+         */
+        void setThumb(@NonNull Icon thumb);
+    }
+
+    /**
+     */
+    interface RowBuilder {
+
+        /**
+         * Sets the title item to be the provided timestamp. Only one timestamp can be added, if
+         * one is already added this will throw {@link IllegalArgumentException}.
+         * <p>
+         * There can only be one title item, this will replace any other title
+         * items that may have been set.
+         */
+        void setTitleItem(long timeStamp);
+
+        /**
+         * Sets the title item to be the provided icon. There can only be one title item, this
+         * will replace any other title items that may have been set.
+         */
+        void setTitleItem(Icon icon);
+
+        /**
+         * Sets the title item to be the provided icon. There can only be one title item, this
+         * will replace any other title items that may have been set.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        void setTitleItem(Icon icon, boolean isLoading);
+
+        /**
+         * Sets the title item to be a tappable icon. There can only be one title item, this will
+         * replace any other title items that may have been set.
+         */
+        void setTitleItem(SliceAction action);
+
+        /**
+         * Sets the title item to be a tappable icon. There can only be one title item, this will
+         * replace any other title items that may have been set.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        void setTitleItem(SliceAction action, boolean isLoading);
+
+        /**
+         * Sets the action to be invoked if the user taps on the main content of the template.
+         */
+        void setPrimaryAction(SliceAction action);
+
+        /**
+         * Sets the title text.
+         */
+        void setTitle(CharSequence title);
+
+        /**
+         * Sets the title text.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        void setTitle(CharSequence title, boolean isLoading);
+
+        /**
+         * Sets the subtitle text.
+         */
+        void setSubtitle(CharSequence subtitle);
+
+        /**
+         * Sets the subtitle text.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        void setSubtitle(CharSequence subtitle, boolean isLoading);
+
+        /**
+         * Adds a timestamp to be displayed at the end of the row.
+         */
+        void addEndItem(long timeStamp);
+
+        /**
+         * Adds an icon to be displayed at the end of the row.
+         */
+        void addEndItem(Icon icon);
+
+        /**
+         * Adds an icon to be displayed at the end of the row.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        void addEndItem(Icon icon, boolean isLoading);
+
+        /**
+         * Adds a tappable icon to be displayed at the end of the row.
+         */
+        void addEndItem(SliceAction action);
+
+        /**
+         * Adds a tappable icon to be displayed at the end of the row.
+         * <p>
+         * When set to true, the parameter {@code isLoading} indicates that the app is doing work
+         * to load this content in the background, in this case the template displays a placeholder
+         * until updated.
+         */
+        void addEndItem(SliceAction action, boolean isLoading);
+    }
+
+
+    /**
+     * Builder to construct a header. A header is displayed at the top of a list and can have
+     * a title, subtitle, and an action.
+     */
+    public interface HeaderBuilder {
+
+        /**
+         * Sets the title to be shown in this header.
+         */
+        void setTitle(CharSequence title);
+
+        /**
+         * Sets the subtitle to be shown in this header.
+         */
+        void setSubtitle(CharSequence subtitle);
+
+        /**
+         * Sets the summary subtitle to be shown in this header. If unset, the normal subtitle
+         * will be used. The summary is used when the parent template is presented in a
+         * small format.
+         */
+        void setSummarySubtitle(CharSequence summarySubtitle);
+
+        /**
+         * Sets the action to invoke when the header is activated.
+         */
+        void setPrimaryAction(SliceAction action);
+    }
+}
+
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderBasicImpl.java
new file mode 100644
index 0000000..b47e7f2
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderBasicImpl.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceSpec;
+import androidx.app.slice.builders.SliceAction;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public class ListBuilderBasicImpl extends TemplateBuilderImpl implements ListBuilder {
+
+    /**
+     */
+    public ListBuilderBasicImpl(Slice.Builder b, SliceSpec spec) {
+        super(b, spec);
+    }
+
+    /**
+     */
+    @Override
+    public void addRow(TemplateBuilderImpl impl) {
+        // Do nothing.
+    }
+
+    /**
+     */
+    @Override
+    public void addGrid(TemplateBuilderImpl impl) {
+        // Do nothing.
+    }
+
+    /**
+     */
+    @Override
+    public void addAction(SliceAction impl) {
+        // Do nothing.
+    }
+
+    /**
+     */
+    @Override
+    public void setHeader(TemplateBuilderImpl impl) {
+        // Do nothing.
+    }
+
+    @Override
+    public void addInputRange(TemplateBuilderImpl builder) {
+        // Do nothing.
+    }
+
+    @Override
+    public void addRange(TemplateBuilderImpl builder) {
+        // Do nothing.
+    }
+
+    /**
+     */
+    @Override
+    public void addSeeMoreRow(TemplateBuilderImpl builder) {
+    }
+
+    /**
+     */
+    @Override
+    public void addSeeMoreAction(PendingIntent intent) {
+    }
+
+    /**
+     */
+    @Override
+    public void setColor(@ColorInt int color) {
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createRowBuilder() {
+        return new RowBuilderImpl(this);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createRowBuilder(Uri uri) {
+        return new RowBuilderImpl(uri);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createGridBuilder() {
+        return new GridBuilderBasicImpl(this);
+    }
+
+    @Override
+    public TemplateBuilderImpl createHeaderBuilder() {
+        return new HeaderBuilderImpl(this);
+    }
+
+    @Override
+    public TemplateBuilderImpl createHeaderBuilder(Uri uri) {
+        return new HeaderBuilderImpl(uri);
+    }
+
+    @Override
+    public TemplateBuilderImpl createInputRangeBuilder() {
+        return new ListBuilderV1Impl.InputRangeBuilderImpl(getBuilder());
+    }
+
+    @Override
+    public TemplateBuilderImpl createRangeBuilder() {
+        return new ListBuilderV1Impl.RangeBuilderImpl(getBuilder());
+    }
+
+    /**
+     */
+    @Override
+    public void apply(Slice.Builder builder) {
+
+    }
+
+    /**
+     */
+    public static class RowBuilderImpl extends TemplateBuilderImpl
+            implements ListBuilder.RowBuilder {
+
+        /**
+         */
+        public RowBuilderImpl(@NonNull ListBuilderBasicImpl parent) {
+            super(parent.createChildBuilder(), null);
+        }
+
+        /**
+         */
+        public RowBuilderImpl(@NonNull Uri uri) {
+            super(new Slice.Builder(uri), null);
+        }
+
+        /**
+         */
+        @Override
+        public void addEndItem(Icon icon) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void addEndItem(Icon icon, boolean isLoading) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void addEndItem(SliceAction action) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void addEndItem(SliceAction action, boolean isLoading) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setTitleItem(long timeStamp) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setTitleItem(Icon icon) {
+        }
+
+        /**
+         */
+        @Override
+        public void setTitleItem(Icon icon, boolean isLoading) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setTitleItem(SliceAction action) {
+        }
+
+        /**
+         */
+        @Override
+        public void setTitleItem(SliceAction action, boolean isLoading) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setPrimaryAction(SliceAction action) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setTitle(CharSequence title) {
+        }
+
+        /**
+         */
+        @Override
+        public void setTitle(CharSequence title, boolean isLoading) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setSubtitle(CharSequence subtitle) {
+        }
+
+        /**
+         */
+        @Override
+        public void setSubtitle(CharSequence subtitle, boolean isLoading) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void addEndItem(long timeStamp) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder builder) {
+
+        }
+    }
+
+    /**
+     */
+    public static class HeaderBuilderImpl extends TemplateBuilderImpl
+            implements ListBuilder.HeaderBuilder {
+
+        /**
+         */
+        public HeaderBuilderImpl(@NonNull ListBuilderBasicImpl parent) {
+            super(parent.createChildBuilder(), null);
+        }
+
+        /**
+         */
+        public HeaderBuilderImpl(@NonNull Uri uri) {
+            super(new Slice.Builder(uri), null);
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder builder) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setTitle(CharSequence title) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setSubtitle(CharSequence subtitle) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setSummarySubtitle(CharSequence summarySubtitle) {
+
+        }
+
+        /**
+         */
+        @Override
+        public void setPrimaryAction(SliceAction action) {
+
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderV1Impl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderV1Impl.java
new file mode 100644
index 0000000..0a73f34
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/ListBuilderV1Impl.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_PARTIAL;
+import static android.app.slice.Slice.HINT_SEE_MORE;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_SUMMARY;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import static androidx.app.slice.core.SliceHints.SUBTYPE_MAX;
+import static androidx.app.slice.core.SliceHints.SUBTYPE_RANGE;
+import static androidx.app.slice.core.SliceHints.SUBTYPE_VALUE;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.SliceSpec;
+import androidx.app.slice.builders.SliceAction;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public class ListBuilderV1Impl extends TemplateBuilderImpl implements ListBuilder {
+
+    private List<Slice> mSliceActions;
+    private Slice mSliceHeader;
+
+    /**
+     */
+    public ListBuilderV1Impl(Slice.Builder b, SliceSpec spec) {
+        super(b, spec);
+    }
+
+    /**
+     */
+    @Override
+    public void apply(Slice.Builder builder) {
+        if (mSliceHeader != null) {
+            builder.addSubSlice(mSliceHeader);
+        }
+        if (mSliceActions != null) {
+            Slice.Builder sb = new Slice.Builder(builder);
+            for (int i = 0; i < mSliceActions.size(); i++) {
+                sb.addSubSlice(mSliceActions.get(i));
+            }
+            builder.addSubSlice(sb.addHints(HINT_ACTIONS).build());
+        }
+    }
+
+    /**
+     * Add a row to list builder.
+     */
+    @NonNull
+    @Override
+    public void addRow(@NonNull TemplateBuilderImpl builder) {
+        getBuilder().addSubSlice(builder.build());
+    }
+
+    /**
+     */
+    @NonNull
+    @Override
+    public void addGrid(@NonNull TemplateBuilderImpl builder) {
+        getBuilder().addSubSlice(builder.build());
+    }
+
+    /**
+     */
+    @Override
+    public void setHeader(@NonNull TemplateBuilderImpl builder) {
+        mSliceHeader = builder.build();
+    }
+
+    /**
+     */
+    @Override
+    public void addAction(@NonNull SliceAction action) {
+        if (mSliceActions == null) {
+            mSliceActions = new ArrayList<>();
+        }
+        Slice.Builder b = new Slice.Builder(getBuilder()).addHints(HINT_ACTIONS);
+        mSliceActions.add(action.buildSlice(b));
+    }
+
+    @Override
+    public void addInputRange(TemplateBuilderImpl builder) {
+        getBuilder().addSubSlice(builder.build(), SUBTYPE_RANGE);
+    }
+
+    @Override
+    public void addRange(TemplateBuilderImpl builder) {
+        getBuilder().addSubSlice(builder.build(), SUBTYPE_RANGE);
+    }
+
+    /**
+     */
+    @Override
+    public void addSeeMoreRow(TemplateBuilderImpl builder) {
+        builder.getBuilder().addHints(HINT_SEE_MORE);
+        getBuilder().addSubSlice(builder.build());
+    }
+
+    /**
+     */
+    @Override
+    public void addSeeMoreAction(PendingIntent intent) {
+        getBuilder().addSubSlice(
+                new Slice.Builder(getBuilder())
+                        .addHints(HINT_SEE_MORE)
+                        .addAction(intent, new Slice.Builder(getBuilder()).build(), null)
+                        .build());
+    }
+
+
+    /**
+     * Builder to construct an input row.
+     */
+    public static class RangeBuilderImpl extends TemplateBuilderImpl implements RangeBuilder {
+        private int mMax = 100;
+        private int mValue = 0;
+        private CharSequence mTitle;
+
+        public RangeBuilderImpl(Slice.Builder sb) {
+            super(sb, null);
+        }
+
+        @Override
+        public void setMax(int max) {
+            mMax = max;
+        }
+
+        @Override
+        public void setValue(int value) {
+            mValue = value;
+        }
+
+        @Override
+        public void setTitle(@NonNull CharSequence title) {
+            mTitle = title;
+        }
+
+        @Override
+        public void apply(Slice.Builder builder) {
+            if (mTitle != null) {
+                builder.addText(mTitle, null, HINT_TITLE);
+            }
+            builder.addHints(HINT_LIST_ITEM)
+                    .addInt(mMax, SUBTYPE_MAX)
+                    .addInt(mValue, SUBTYPE_VALUE);
+        }
+    }
+
+    /**
+     * Builder to construct an input range row.
+     */
+    public static class InputRangeBuilderImpl
+            extends RangeBuilderImpl implements InputRangeBuilder {
+        private PendingIntent mAction;
+        private Icon mThumb;
+
+        public InputRangeBuilderImpl(Slice.Builder sb) {
+            super(sb);
+        }
+
+        @Override
+        public void setAction(@NonNull PendingIntent action) {
+            mAction = action;
+        }
+
+        @Override
+        public void setThumb(@NonNull Icon thumb) {
+            mThumb = thumb;
+        }
+
+        @Override
+        public void apply(Slice.Builder builder) {
+            if (mAction == null) {
+                throw new IllegalStateException("Input ranges must have an associated action.");
+            }
+            Slice.Builder sb = new Slice.Builder(builder);
+            super.apply(sb);
+            if (mThumb != null) {
+                sb.addIcon(mThumb, null);
+            }
+            builder.addAction(mAction, sb.build(), SUBTYPE_RANGE).addHints(HINT_LIST_ITEM);
+        }
+    }
+
+    /**
+     */
+    @NonNull
+    @Override
+    public void setColor(@ColorInt int color) {
+        getBuilder().addInt(color, SUBTYPE_COLOR);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createRowBuilder() {
+        return new RowBuilderImpl(this);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createRowBuilder(Uri uri) {
+        return new RowBuilderImpl(uri);
+    }
+
+
+    @Override
+    public TemplateBuilderImpl createInputRangeBuilder() {
+        return new InputRangeBuilderImpl(createChildBuilder());
+    }
+
+    @Override
+    public TemplateBuilderImpl createRangeBuilder() {
+        return new RangeBuilderImpl(createChildBuilder());
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createGridBuilder() {
+        return new GridBuilderListV1Impl(this);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createHeaderBuilder() {
+        return new HeaderBuilderImpl(this);
+    }
+
+    @Override
+    public TemplateBuilderImpl createHeaderBuilder(Uri uri) {
+        return new HeaderBuilderImpl(uri);
+    }
+
+    /**
+     */
+    public static class RowBuilderImpl extends TemplateBuilderImpl
+            implements ListBuilder.RowBuilder {
+
+        private SliceAction mPrimaryAction;
+        private SliceItem mTitleItem;
+        private SliceItem mSubtitleItem;
+        private Slice mStartItem;
+        private ArrayList<Slice> mEndItems = new ArrayList<>();
+
+        /**
+         */
+        public RowBuilderImpl(@NonNull ListBuilderV1Impl parent) {
+            super(parent.createChildBuilder(), null);
+        }
+
+        /**
+         */
+        public RowBuilderImpl(@NonNull Uri uri) {
+            super(new Slice.Builder(uri), null);
+        }
+
+        /**
+         */
+        public RowBuilderImpl(Slice.Builder builder) {
+            super(builder, null);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setTitleItem(long timeStamp) {
+            mStartItem = new Slice.Builder(getBuilder())
+                    .addTimestamp(timeStamp, null).addHints(HINT_TITLE).build();
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setTitleItem(@NonNull Icon icon) {
+            setTitleItem(icon, false /* isLoading */);
+        }
+
+        /**
+         */
+        @Override
+        public void setTitleItem(@Nullable Icon icon, boolean isLoading) {
+            Slice.Builder sb = new Slice.Builder(getBuilder()).addIcon(icon, null /* subtype */);
+            if (isLoading) {
+                sb.addHints(HINT_PARTIAL);
+            }
+            mStartItem = sb.addHints(HINT_TITLE).build();
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setTitleItem(@NonNull SliceAction action) {
+            setTitleItem(action, false /* isLoading */);
+        }
+
+        /**
+         */
+        @Override
+        public void setTitleItem(SliceAction action, boolean isLoading) {
+            Slice.Builder sb = new Slice.Builder(getBuilder()).addHints(HINT_TITLE);
+            if (isLoading) {
+                sb.addHints(HINT_PARTIAL);
+            }
+            mStartItem = action.buildSlice(sb);
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setPrimaryAction(@NonNull SliceAction action) {
+            mPrimaryAction = action;
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setTitle(CharSequence title) {
+            setTitle(title, false /* isLoading */);
+        }
+
+        /**
+         */
+        @Override
+        public void setTitle(CharSequence title, boolean isLoading) {
+            mTitleItem = new SliceItem(title, FORMAT_TEXT, null, new String[] {HINT_TITLE});
+            if (isLoading) {
+                mTitleItem.addHint(HINT_PARTIAL);
+            }
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void setSubtitle(CharSequence subtitle) {
+            setSubtitle(subtitle, false /* isLoading */);
+        }
+
+        /**
+         */
+        @Override
+        public void setSubtitle(CharSequence subtitle, boolean isLoading) {
+            mSubtitleItem = new SliceItem(subtitle, FORMAT_TEXT, null, new String[0]);
+            if (isLoading) {
+                mSubtitleItem.addHint(HINT_PARTIAL);
+            }
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addEndItem(long timeStamp) {
+            mEndItems.add(new Slice.Builder(getBuilder()).addTimestamp(timeStamp,
+                    null, new String[0]).build());
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addEndItem(@NonNull Icon icon) {
+            addEndItem(icon, false /* isLoading */);
+        }
+
+        /**
+         */
+        @Override
+        public void addEndItem(Icon icon, boolean isLoading) {
+            Slice.Builder sb = new Slice.Builder(getBuilder()).addIcon(icon, null /* subType */,
+                    HINT_NO_TINT, HINT_LARGE);
+            if (isLoading) {
+                sb.addHints(HINT_PARTIAL);
+            }
+            mEndItems.add(sb.build());
+        }
+
+        /**
+         */
+        @NonNull
+        @Override
+        public void addEndItem(@NonNull SliceAction action) {
+            addEndItem(action, false /* isLoading */);
+        }
+
+        /**
+         */
+        @Override
+        public void addEndItem(@NonNull SliceAction action, boolean isLoading) {
+            Slice.Builder sb = new Slice.Builder(getBuilder());
+            if (isLoading) {
+                sb.addHints(HINT_PARTIAL);
+            }
+            mEndItems.add(action.buildSlice(sb));
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder b) {
+            if (mStartItem != null) {
+                b.addSubSlice(mStartItem);
+            }
+            if (mTitleItem != null) {
+                b.addItem(mTitleItem);
+            }
+            if (mSubtitleItem != null) {
+                b.addItem(mSubtitleItem);
+            }
+            for (int i = 0; i < mEndItems.size(); i++) {
+                Slice item = mEndItems.get(i);
+                b.addSubSlice(item);
+            }
+            if (mPrimaryAction != null) {
+                Slice.Builder sb = new Slice.Builder(
+                        getBuilder()).addHints(HINT_TITLE, HINT_SHORTCUT);
+                b.addSubSlice(mPrimaryAction.buildSlice(sb), null);
+            }
+            b.addHints(HINT_LIST_ITEM);
+        }
+    }
+
+    /**
+     */
+    public static class HeaderBuilderImpl extends TemplateBuilderImpl
+            implements ListBuilder.HeaderBuilder {
+
+        private CharSequence mTitle;
+        private CharSequence mSubtitle;
+        private CharSequence mSummarySubtitle;
+        private SliceAction mPrimaryAction;
+
+        /**
+         */
+        public HeaderBuilderImpl(@NonNull ListBuilderV1Impl parent) {
+            super(parent.createChildBuilder(), null);
+        }
+
+        /**
+         */
+        public HeaderBuilderImpl(@NonNull Uri uri) {
+            super(new Slice.Builder(uri), null);
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder b) {
+            if (mTitle != null) {
+                b.addText(mTitle, null /* subtype */, HINT_TITLE);
+            }
+            if (mSubtitle != null) {
+                b.addText(mSubtitle, null /* subtype */);
+            }
+            if (mSummarySubtitle != null) {
+                b.addText(mSummarySubtitle, null /* subtype */, HINT_SUMMARY);
+            }
+            if (mPrimaryAction != null) {
+                Slice.Builder sb = new Slice.Builder(
+                        getBuilder()).addHints(HINT_TITLE, HINT_SHORTCUT);
+                b.addSubSlice(mPrimaryAction.buildSlice(sb), null /* subtype */);
+            }
+        }
+
+        /**
+         */
+        @Override
+        public void setTitle(CharSequence title) {
+            mTitle = title;
+        }
+
+        /**
+         */
+        @Override
+        public void setSubtitle(CharSequence subtitle) {
+            mSubtitle = subtitle;
+        }
+
+        /**
+         */
+        @Override
+        public void setSummarySubtitle(CharSequence summarySubtitle) {
+            mSummarySubtitle = summarySubtitle;
+        }
+
+        /**
+         */
+        @Override
+        public void setPrimaryAction(SliceAction action) {
+            mPrimaryAction = action;
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingBasicImpl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingBasicImpl.java
new file mode 100644
index 0000000..843302c
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingBasicImpl.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.graphics.drawable.Icon;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceSpec;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public class MessagingBasicImpl extends TemplateBuilderImpl implements
+        MessagingBuilder {
+    private MessageBuilder mLastMessage;
+
+    /**
+     */
+    public MessagingBasicImpl(Slice.Builder builder, SliceSpec spec) {
+        super(builder, spec);
+    }
+
+    /**
+     */
+    @Override
+    public void apply(Slice.Builder builder) {
+        if (mLastMessage != null) {
+            if (mLastMessage.mIcon != null) {
+                builder.addIcon(mLastMessage.mIcon, null);
+            }
+            if (mLastMessage.mText != null) {
+                builder.addText(mLastMessage.mText, null);
+            }
+        }
+    }
+
+    /**
+     */
+    @Override
+    public void add(TemplateBuilderImpl builder) {
+        MessageBuilder b = (MessageBuilder) builder;
+        if (mLastMessage == null || mLastMessage.mTimestamp < b.mTimestamp) {
+            mLastMessage = b;
+        }
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createMessageBuilder() {
+        return new MessageBuilder(this);
+    }
+
+    /**
+     */
+    public static final class MessageBuilder extends TemplateBuilderImpl
+            implements MessagingBuilder.MessageBuilder {
+
+        private Icon mIcon;
+        private CharSequence mText;
+        private long mTimestamp;
+
+        /**
+         */
+        public MessageBuilder(MessagingBasicImpl parent) {
+            this(parent.createChildBuilder());
+        }
+
+        /**
+         */
+        private MessageBuilder(Slice.Builder builder) {
+            super(builder, null);
+        }
+
+        /**
+         */
+        @Override
+        public void addSource(Icon source) {
+            mIcon = source;
+        }
+
+        /**
+         */
+        @Override
+        public void addText(CharSequence text) {
+            mText = text;
+        }
+
+        /**
+         */
+        @Override
+        public void addTimestamp(long timestamp) {
+            mTimestamp = timestamp;
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder builder) {
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingBuilder.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingBuilder.java
new file mode 100644
index 0000000..635f160
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.graphics.drawable.Icon;
+import android.support.annotation.RestrictTo;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public interface MessagingBuilder {
+    /**
+     * Add a subslice to this builder.
+     */
+    void add(TemplateBuilderImpl builder);
+
+    /**
+     * Create a builder that implements {@link MessageBuilder}
+     */
+    TemplateBuilderImpl createMessageBuilder();
+
+    /**
+     */
+    public interface MessageBuilder {
+
+        /**
+         * Add the icon used to display contact in the messaging experience
+         */
+        void addSource(Icon source);
+
+        /**
+         * Add the text to be used for this message.
+         */
+        void addText(CharSequence text);
+
+        /**
+         * Add the time at which this message arrived in ms since Unix epoch
+         */
+        void addTimestamp(long timestamp);
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingListV1Impl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingListV1Impl.java
new file mode 100644
index 0000000..408ad0b
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingListV1Impl.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.graphics.drawable.Icon;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceSpec;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public class MessagingListV1Impl extends TemplateBuilderImpl implements MessagingBuilder{
+
+    private final ListBuilderV1Impl mListBuilder;
+
+    /**
+     */
+    public MessagingListV1Impl(Slice.Builder b, SliceSpec spec) {
+        super(b, spec);
+        mListBuilder = new ListBuilderV1Impl(b, spec);
+    }
+
+    /**
+     */
+    @Override
+    public void add(TemplateBuilderImpl builder) {
+        MessageBuilder b = (MessageBuilder) builder;
+        mListBuilder.addRow(b.mListBuilder);
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createMessageBuilder() {
+        return new MessageBuilder(this);
+    }
+
+    /**
+     */
+    @Override
+    public void apply(Slice.Builder builder) {
+        mListBuilder.apply(builder);
+    }
+
+    /**
+     */
+    public static final class MessageBuilder extends TemplateBuilderImpl
+            implements MessagingBuilder.MessageBuilder {
+        private final ListBuilderV1Impl.RowBuilderImpl mListBuilder;
+
+        /**
+         */
+        public MessageBuilder(MessagingListV1Impl parent) {
+            this(parent.createChildBuilder());
+        }
+
+        private MessageBuilder(Slice.Builder builder) {
+            super(builder, null);
+            mListBuilder = new ListBuilderV1Impl.RowBuilderImpl(builder);
+        }
+
+        /**
+         */
+        @Override
+        public void addSource(Icon source) {
+            mListBuilder.setTitleItem(source);
+        }
+
+        /**
+         */
+        @Override
+        public void addText(CharSequence text) {
+            mListBuilder.setSubtitle(text);
+        }
+
+        /**
+         */
+        @Override
+        public void addTimestamp(long timestamp) {
+            mListBuilder.addEndItem(timestamp);
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder builder) {
+            mListBuilder.apply(builder);
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingV1Impl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingV1Impl.java
new file mode 100644
index 0000000..4e07139
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/MessagingV1Impl.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.app.slice.Slice.SUBTYPE_MESSAGE;
+
+import android.graphics.drawable.Icon;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceSpec;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class MessagingV1Impl extends TemplateBuilderImpl implements MessagingBuilder {
+
+    /**
+     */
+    public MessagingV1Impl(Slice.Builder b, SliceSpec spec) {
+        super(b, spec);
+    }
+
+    /**
+     */
+    @Override
+    public void add(TemplateBuilderImpl builder) {
+        getBuilder().addSubSlice(builder.build(), SUBTYPE_MESSAGE);
+    }
+
+    /**
+     */
+    @Override
+    public void apply(Slice.Builder builder) {
+
+    }
+
+    /**
+     */
+    @Override
+    public TemplateBuilderImpl createMessageBuilder() {
+        return new MessageBuilder(this);
+    }
+
+    /**
+     */
+    public static final class MessageBuilder extends TemplateBuilderImpl
+            implements MessagingBuilder.MessageBuilder {
+        /**
+         */
+        public MessageBuilder(MessagingV1Impl parent) {
+            super(parent.createChildBuilder(), null);
+        }
+
+        /**
+         */
+        @Override
+        public void addSource(Icon source) {
+            getBuilder().addIcon(source, android.app.slice.Slice.SUBTYPE_SOURCE);
+        }
+
+        /**
+         */
+        @Override
+        public void addText(CharSequence text) {
+            getBuilder().addText(text, null);
+        }
+
+        /**
+         */
+        @Override
+        public void addTimestamp(long timestamp) {
+            getBuilder().addTimestamp(timestamp, null);
+        }
+
+        /**
+         */
+        @Override
+        public void apply(Slice.Builder builder) {
+        }
+    }
+}
diff --git a/slices/builders/src/main/java/androidx/app/slice/builders/impl/TemplateBuilderImpl.java b/slices/builders/src/main/java/androidx/app/slice/builders/impl/TemplateBuilderImpl.java
new file mode 100644
index 0000000..294677e
--- /dev/null
+++ b/slices/builders/src/main/java/androidx/app/slice/builders/impl/TemplateBuilderImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.builders.impl;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceSpec;
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public abstract class TemplateBuilderImpl {
+
+    private final Slice.Builder mSliceBuilder;
+    private final SliceSpec mSpec;
+
+    protected TemplateBuilderImpl(Slice.Builder b, SliceSpec spec) {
+        mSliceBuilder = b;
+        mSpec = spec;
+    }
+
+    /**
+     * Construct the slice.
+     */
+    public Slice build() {
+        mSliceBuilder.setSpec(mSpec);
+        apply(mSliceBuilder);
+        return mSliceBuilder.build();
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public Slice.Builder getBuilder() {
+        return mSliceBuilder;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public Slice.Builder createChildBuilder() {
+        return new Slice.Builder(mSliceBuilder);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public abstract void apply(Slice.Builder builder);
+}
diff --git a/slices/core/api/current.txt b/slices/core/api/current.txt
new file mode 100644
index 0000000..77936d6
--- /dev/null
+++ b/slices/core/api/current.txt
@@ -0,0 +1,38 @@
+package androidx.app.slice {
+
+  public final class Slice {
+    method public java.util.List<java.lang.String> getHints();
+    method public java.util.List<androidx.app.slice.SliceItem> getItems();
+    method public android.net.Uri getUri();
+  }
+
+  public class SliceConvert {
+    ctor public SliceConvert();
+    method public static android.app.slice.Slice unwrap(androidx.app.slice.Slice);
+    method public static androidx.app.slice.Slice wrap(android.app.slice.Slice);
+  }
+
+  public class SliceItem {
+    method public android.app.PendingIntent getAction();
+    method public java.lang.String getFormat();
+    method public java.util.List<java.lang.String> getHints();
+    method public android.graphics.drawable.Icon getIcon();
+    method public int getInt();
+    method public androidx.app.slice.Slice getSlice();
+    method public java.lang.String getSubType();
+    method public java.lang.CharSequence getText();
+    method public long getTimestamp();
+    method public boolean hasHint(java.lang.String);
+  }
+
+  public abstract class SliceProvider extends android.content.ContentProvider {
+    ctor public SliceProvider();
+    method public abstract androidx.app.slice.Slice onBindSlice(android.net.Uri);
+    method public abstract boolean onCreateSliceProvider();
+    method public android.net.Uri onMapIntentToUri(android.content.Intent);
+    method public void onSlicePinned(android.net.Uri);
+    method public void onSliceUnpinned(android.net.Uri);
+  }
+
+}
+
diff --git a/slices/core/build.gradle b/slices/core/build.gradle
new file mode 100644
index 0000000..879b409
--- /dev/null
+++ b/slices/core/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static android.support.dependencies.DependenciesKt.*
+
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    implementation project(":support-annotations")
+    implementation project(":appcompat-v7")
+
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy)
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy)
+}
+
+supportLibrary {
+    name = "Common utilities for slices"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SLICES
+    inceptionYear = "2017"
+    description = "The slices core library provides utilities for the slices view and provider libraries"
+    minSdkVersion = 24
+}
diff --git a/slices/core/lint-baseline.xml b/slices/core/lint-baseline.xml
new file mode 100644
index 0000000..2cadde1
--- /dev/null
+++ b/slices/core/lint-baseline.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+</issues>
diff --git a/slices/core/src/androidTest/AndroidManifest.xml b/slices/core/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..90dbbcc
--- /dev/null
+++ b/slices/core/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.app.slice.core.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <application>
+        <provider android:name="androidx.app.slice.SliceTestProvider"
+            android:authorities="androidx.app.slice.core.test"
+            android:process=":provider"
+            android:exported="true" />
+    </application>
+
+</manifest>
diff --git a/slices/core/src/androidTest/java/androidx/app/slice/SliceTest.java b/slices/core/src/androidTest/java/androidx/app/slice/SliceTest.java
new file mode 100644
index 0000000..0ede29d
--- /dev/null
+++ b/slices/core/src/androidTest/java/androidx/app/slice/SliceTest.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_LIST;
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+import static android.app.slice.SliceProvider.SLICE_TYPE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.app.PendingIntent.CanceledException;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import androidx.app.slice.core.test.R;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SliceTest {
+
+    public static boolean sFlag = false;
+
+    private static final Uri BASE_URI = Uri.parse("content://androidx.app.slice.core.test/");
+    private final Context mContext = InstrumentationRegistry.getContext();
+
+    @Test
+    public void testProcess() {
+        sFlag = false;
+        Slice.bindSlice(mContext,
+                BASE_URI.buildUpon().appendPath("set_flag").build(),
+                Collections.<SliceSpec>emptyList());
+        assertFalse(sFlag);
+    }
+
+    @Test
+    public void testType() {
+        assertEquals(SLICE_TYPE, mContext.getContentResolver().getType(BASE_URI));
+    }
+
+    @Test
+    public void testSliceUri() {
+        Slice s = Slice.bindSlice(mContext, BASE_URI, Collections.<SliceSpec>emptyList());
+        assertEquals(BASE_URI, s.getUri());
+    }
+
+    @Test
+    public void testSubSlice() {
+        Uri uri = BASE_URI.buildUpon().appendPath("subslice").build();
+        Slice s = Slice.bindSlice(mContext, uri, Collections.<SliceSpec>emptyList());
+        assertEquals(uri, s.getUri());
+        assertEquals(1, s.getItems().size());
+
+        SliceItem item = s.getItems().get(0);
+        assertEquals(FORMAT_SLICE, item.getFormat());
+        assertEquals("subslice", item.getSubType());
+        // The item should start with the same Uri as the parent, but be different.
+        assertTrue(item.getSlice().getUri().toString().startsWith(uri.toString()));
+        assertNotEquals(uri, item.getSlice().getUri());
+    }
+
+    @Test
+    public void testText() {
+        Uri uri = BASE_URI.buildUpon().appendPath("text").build();
+        Slice s = Slice.bindSlice(mContext, uri, Collections.<SliceSpec>emptyList());
+        assertEquals(uri, s.getUri());
+        assertEquals(1, s.getItems().size());
+
+        SliceItem item = s.getItems().get(0);
+        assertEquals(FORMAT_TEXT, item.getFormat());
+        // TODO: Test spannables here.
+        assertEquals("Expected text", item.getText());
+    }
+
+    @Test
+    public void testIcon() {
+        Uri uri = BASE_URI.buildUpon().appendPath("icon").build();
+        Slice s = Slice.bindSlice(mContext, uri, Collections.<SliceSpec>emptyList());
+        assertEquals(uri, s.getUri());
+        assertEquals(1, s.getItems().size());
+
+        SliceItem item = s.getItems().get(0);
+        assertEquals(FORMAT_IMAGE, item.getFormat());
+        assertEquals(Icon.createWithResource(mContext, R.drawable.size_48x48).toString(),
+                item.getIcon().toString());
+    }
+
+    @Test
+    public void testAction() {
+        sFlag = false;
+        final CountDownLatch latch = new CountDownLatch(1);
+        BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                sFlag = true;
+                latch.countDown();
+            }
+        };
+        mContext.registerReceiver(receiver,
+                new IntentFilter(mContext.getPackageName() + ".action"));
+        Uri uri = BASE_URI.buildUpon().appendPath("action").build();
+        Slice s = Slice.bindSlice(mContext, uri, Collections.<SliceSpec>emptyList());
+        assertEquals(uri, s.getUri());
+        assertEquals(1, s.getItems().size());
+
+        SliceItem item = s.getItems().get(0);
+        assertEquals(FORMAT_ACTION, item.getFormat());
+        try {
+            item.getAction().send();
+        } catch (CanceledException e) {
+        }
+
+        try {
+            latch.await(100, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        assertTrue(sFlag);
+        mContext.unregisterReceiver(receiver);
+    }
+
+    @Test
+    public void testInt() {
+        Uri uri = BASE_URI.buildUpon().appendPath("int").build();
+        Slice s = Slice.bindSlice(mContext, uri, Collections.<SliceSpec>emptyList());
+        assertEquals(uri, s.getUri());
+        assertEquals(1, s.getItems().size());
+
+        SliceItem item = s.getItems().get(0);
+        assertEquals(FORMAT_INT, item.getFormat());
+        assertEquals(0xff121212, item.getInt());
+    }
+
+    @Test
+    public void testTimestamp() {
+        Uri uri = BASE_URI.buildUpon().appendPath("timestamp").build();
+        Slice s = Slice.bindSlice(mContext, uri, Collections.<SliceSpec>emptyList());
+        assertEquals(uri, s.getUri());
+        assertEquals(1, s.getItems().size());
+
+        SliceItem item = s.getItems().get(0);
+        assertEquals(FORMAT_TIMESTAMP, item.getFormat());
+        assertEquals(43, item.getTimestamp());
+    }
+
+    @Test
+    public void testHints() {
+        // Note this tests that hints are propagated through to the client but not that any specific
+        // hints have any effects.
+        Uri uri = BASE_URI.buildUpon().appendPath("hints").build();
+        Slice s = Slice.bindSlice(mContext, uri, Collections.<SliceSpec>emptyList());
+        assertEquals(uri, s.getUri());
+
+        assertEquals(Arrays.asList(HINT_LIST), s.getHints());
+        assertEquals(Arrays.asList(HINT_TITLE), s.getItems().get(0).getHints());
+        assertEquals(Arrays.asList(HINT_NO_TINT, HINT_LARGE),
+                s.getItems().get(1).getHints());
+    }
+}
diff --git a/slices/core/src/androidTest/java/androidx/app/slice/SliceTestProvider.java b/slices/core/src/androidTest/java/androidx/app/slice/SliceTestProvider.java
new file mode 100644
index 0000000..9320bc9
--- /dev/null
+++ b/slices/core/src/androidTest/java/androidx/app/slice/SliceTestProvider.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_LIST;
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_TITLE;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+
+import androidx.app.slice.Slice.Builder;
+import androidx.app.slice.core.test.R;
+
+public class SliceTestProvider extends androidx.app.slice.SliceProvider {
+
+    @Override
+    public boolean onCreateSliceProvider() {
+        return true;
+    }
+
+    @Override
+    public Slice onBindSlice(Uri sliceUri) {
+        switch (sliceUri.getPath()) {
+            case "/set_flag":
+                SliceTest.sFlag = true;
+                break;
+            case "/subslice":
+                Builder b = new Builder(sliceUri);
+                return b.addSubSlice(new Slice.Builder(b).build(), "subslice").build();
+            case "/text":
+                return new Slice.Builder(sliceUri).addText("Expected text", "text").build();
+            case "/icon":
+                return new Slice.Builder(sliceUri).addIcon(
+                        Icon.createWithResource(getContext(), R.drawable.size_48x48),
+                        "icon").build();
+            case "/action":
+                Builder builder = new Builder(sliceUri);
+                Slice subSlice = new Slice.Builder(builder).build();
+                PendingIntent broadcast = PendingIntent.getBroadcast(getContext(), 0,
+                        new Intent(getContext().getPackageName() + ".action"), 0);
+                return builder.addAction(broadcast, subSlice, "action").build();
+            case "/int":
+                return new Slice.Builder(sliceUri).addInt(0xff121212, "int").build();
+            case "/timestamp":
+                return new Slice.Builder(sliceUri).addTimestamp(43, "timestamp").build();
+            case "/hints":
+                return new Slice.Builder(sliceUri)
+                        .addHints(HINT_LIST)
+                        .addText("Text", null, HINT_TITLE)
+                        .addIcon(Icon.createWithResource(getContext(), R.drawable.size_48x48),
+                                null, HINT_NO_TINT, HINT_LARGE)
+                        .build();
+        }
+        return new Slice.Builder(sliceUri).build();
+    }
+
+}
diff --git a/slices/core/src/androidTest/java/androidx/app/slice/compat/CompatPinnedListTest.java b/slices/core/src/androidTest/java/androidx/app/slice/compat/CompatPinnedListTest.java
new file mode 100644
index 0000000..18bb606
--- /dev/null
+++ b/slices/core/src/androidTest/java/androidx/app/slice/compat/CompatPinnedListTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.compat;
+
+import static android.content.Context.MODE_PRIVATE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertArrayEquals;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import androidx.app.slice.SliceSpec;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CompatPinnedListTest {
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+    private CompatPinnedList mCompatPinnedList;
+    private List<SliceSpec> mSpecs;
+
+    private static final SliceSpec[] FIRST_SPECS = new SliceSpec[]{
+            new SliceSpec("spec1", 3),
+            new SliceSpec("spec2", 3),
+            new SliceSpec("spec3", 2),
+            new SliceSpec("spec4", 1),
+    };
+
+    private static final SliceSpec[] SECOND_SPECS = new SliceSpec[]{
+            new SliceSpec("spec2", 1),
+            new SliceSpec("spec3", 2),
+            new SliceSpec("spec4", 3),
+            new SliceSpec("spec5", 4),
+    };
+
+    @Before
+    public void setup() {
+        mCompatPinnedList = new CompatPinnedList(mContext, "test_file");
+        mSpecs = Collections.emptyList();
+    }
+
+    @After
+    public void tearDown() {
+        mContext.getSharedPreferences("test_file", MODE_PRIVATE).edit().clear().commit();
+    }
+
+    @Test
+    public void testAddFirstPin() {
+        assertTrue(mCompatPinnedList.addPin(Uri.parse("content://something/something"), "my_pkg",
+                mSpecs));
+    }
+
+    @Test
+    public void testAddSecondPin() {
+        assertTrue(mCompatPinnedList.addPin(Uri.parse("content://something/something"), "my_pkg",
+                mSpecs));
+        assertFalse(mCompatPinnedList.addPin(Uri.parse("content://something/something"), "my_pkg2",
+                mSpecs));
+    }
+
+    @Test
+    public void testAddMultipleUris() {
+        assertTrue(mCompatPinnedList.addPin(Uri.parse("content://something/something"), "my_pkg",
+                mSpecs));
+        assertTrue(mCompatPinnedList.addPin(Uri.parse("content://something/something2"), "my_pkg",
+                mSpecs));
+    }
+
+    @Test
+    public void testRemovePin() {
+        mCompatPinnedList.addPin(Uri.parse("content://something/something"), "my_pkg", mSpecs);
+        mCompatPinnedList.addPin(Uri.parse("content://something/something"), "my_pkg2", mSpecs);
+        assertFalse(mCompatPinnedList.removePin(Uri.parse("content://something/something"),
+                    "my_pkg"));
+        assertTrue(mCompatPinnedList.removePin(Uri.parse("content://something/something"),
+                    "my_pkg2"));
+    }
+
+    @Test
+    public void testMergeSpecs() {
+        Uri uri = Uri.parse("content://something/something");
+
+        assertEquals(Collections.emptyList(), mCompatPinnedList.getSpecs(uri));
+
+        mCompatPinnedList.addPin(uri, "my_pkg", Arrays.asList(FIRST_SPECS));
+        assertArrayEquals(FIRST_SPECS, mCompatPinnedList.getSpecs(uri).toArray(new SliceSpec[0]));
+
+        mCompatPinnedList.addPin(uri, "my_pkg2", Arrays.asList(SECOND_SPECS));
+        assertArrayEquals(new SliceSpec[]{
+                // spec1 is gone because it's not in the second set.
+                new SliceSpec("spec2", 1), // spec2 is 1 because it's smaller in the second set.
+                new SliceSpec("spec3", 2), // spec3 is the same in both sets
+                new SliceSpec("spec4", 1), // spec4 is 1 because it's smaller in the first set.
+                // spec5 is gone because it's not in the first set.
+        }, mCompatPinnedList.getSpecs(uri).toArray(new SliceSpec[0]));
+
+    }
+}
diff --git a/slices/core/src/androidTest/res/drawable/size_48x48.jpg b/slices/core/src/androidTest/res/drawable/size_48x48.jpg
new file mode 100644
index 0000000..5c2291e
--- /dev/null
+++ b/slices/core/src/androidTest/res/drawable/size_48x48.jpg
Binary files differ
diff --git a/slices/core/src/main/AndroidManifest.xml b/slices/core/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..38f75d2
--- /dev/null
+++ b/slices/core/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.app.slice.core">
+    <application>
+        <activity android:name="androidx.app.slice.compat.SlicePermissionActivity">
+        </activity>
+    </application>
+</manifest>
diff --git a/slices/core/src/main/java/androidx/app/slice/ArrayUtils.java b/slices/core/src/main/java/androidx/app/slice/ArrayUtils.java
new file mode 100644
index 0000000..669f66a
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/ArrayUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.app.slice;
+
+
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+import java.lang.reflect.Array;
+import java.util.Objects;
+
+/**
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+class ArrayUtils {
+
+    public static <T> boolean contains(T[] array, T item) {
+        for (T t : array) {
+            if (Objects.equals(t, item)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static <T> T[] appendElement(Class<T> kind, T[] array, T element) {
+        final T[] result;
+        final int end;
+        if (array != null) {
+            end = array.length;
+            result = (T[]) Array.newInstance(kind, end + 1);
+            System.arraycopy(array, 0, result, 0, end);
+        } else {
+            end = 0;
+            result = (T[]) Array.newInstance(kind, 1);
+        }
+        result[end] = element;
+        return result;
+    }
+
+    public static <T> T[] removeElement(Class<T> kind, T[] array, T element) {
+        if (array != null) {
+            if (!contains(array, element)) {
+                return array;
+            }
+            final int length = array.length;
+            for (int i = 0; i < length; i++) {
+                if (Objects.equals(array[i], element)) {
+                    if (length == 1) {
+                        return null;
+                    }
+                    T[] result = (T[]) Array.newInstance(kind, length - 1);
+                    System.arraycopy(array, 0, result, 0, i);
+                    System.arraycopy(array, i + 1, result, i, length - i - 1);
+                    return result;
+                }
+            }
+        }
+        return array;
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/Slice.java b/slices/core/src/main/java/androidx/app/slice/Slice.java
new file mode 100644
index 0000000..966c877
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/Slice.java
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_HORIZONTAL;
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_LIST;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_PARTIAL;
+import static android.app.slice.Slice.HINT_SEE_MORE;
+import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_SUMMARY;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import static androidx.app.slice.SliceConvert.unwrap;
+
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.app.slice.SliceManager;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.annotation.StringDef;
+import android.support.v4.os.BuildCompat;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.app.slice.compat.SliceProviderCompat;
+
+/**
+ * A slice is a piece of app content and actions that can be surfaced outside of the app.
+ *
+ * <p>They are constructed using {@link androidx.app.slice.builders.TemplateSliceBuilder}s
+ * in a tree structure that provides the OS some information about how the content should be
+ * displayed.
+ */
+public final class Slice {
+
+    private static final String HINTS = "hints";
+    private static final String ITEMS = "items";
+    private static final String URI = "uri";
+    private static final String SPEC_TYPE = "type";
+    private static final String SPEC_REVISION = "revision";
+    private final SliceSpec mSpec;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
+            HINT_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL, HINT_SUMMARY, HINT_SEE_MORE,
+            HINT_SHORTCUT})
+    public @interface SliceHint{ }
+
+    private final SliceItem[] mItems;
+    private final @SliceHint String[] mHints;
+    private Uri mUri;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    Slice(ArrayList<SliceItem> items, @SliceHint String[] hints, Uri uri,
+            SliceSpec spec) {
+        mHints = hints;
+        mItems = items.toArray(new SliceItem[items.size()]);
+        mUri = uri;
+        mSpec = spec;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public Slice(Bundle in) {
+        mHints = in.getStringArray(HINTS);
+        Parcelable[] items = in.getParcelableArray(ITEMS);
+        mItems = new SliceItem[items.length];
+        for (int i = 0; i < mItems.length; i++) {
+            if (items[i] instanceof Bundle) {
+                mItems[i] = new SliceItem((Bundle) items[i]);
+            }
+        }
+        mUri = in.getParcelable(URI);
+        mSpec = in.containsKey(SPEC_TYPE)
+                ? new SliceSpec(in.getString(SPEC_TYPE), in.getInt(SPEC_REVISION))
+                : null;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public Bundle toBundle() {
+        Bundle b = new Bundle();
+        b.putStringArray(HINTS, mHints);
+        Parcelable[] p = new Parcelable[mItems.length];
+        for (int i = 0; i < mItems.length; i++) {
+            p[i] = mItems[i].toBundle();
+        }
+        b.putParcelableArray(ITEMS, p);
+        b.putParcelable(URI, mUri);
+        if (mSpec != null) {
+            b.putString(SPEC_TYPE, mSpec.getType());
+            b.putInt(SPEC_REVISION, mSpec.getRevision());
+        }
+        return b;
+    }
+
+    /**
+     * @return The spec for this slice
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public @Nullable SliceSpec getSpec() {
+        return mSpec;
+    }
+
+    /**
+     * @return The Uri that this Slice represents.
+     */
+    public Uri getUri() {
+        return mUri;
+    }
+
+    /**
+     * @return All child {@link SliceItem}s that this Slice contains.
+     */
+    public List<SliceItem> getItems() {
+        return Arrays.asList(mItems);
+    }
+
+    /**
+     * @return All hints associated with this Slice.
+     */
+    public @SliceHint List<String> getHints() {
+        return Arrays.asList(mHints);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    public boolean hasHint(@SliceHint String hint) {
+        return ArrayUtils.contains(mHints, hint);
+    }
+
+    /**
+     * A Builder used to construct {@link Slice}s
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    public static class Builder {
+
+        private final Uri mUri;
+        private ArrayList<SliceItem> mItems = new ArrayList<>();
+        private @SliceHint ArrayList<String> mHints = new ArrayList<>();
+        private SliceSpec mSpec;
+
+        /**
+         * Create a builder which will construct a {@link Slice} for the Given Uri.
+         * @param uri Uri to tag for this slice.
+         */
+        public Builder(@NonNull Uri uri) {
+            mUri = uri;
+        }
+
+        /**
+         * Create a builder for a {@link Slice} that is a sub-slice of the slice
+         * being constructed by the provided builder.
+         * @param parent The builder constructing the parent slice
+         */
+        public Builder(@NonNull Slice.Builder parent) {
+            mUri = parent.mUri.buildUpon().appendPath("_gen")
+                    .appendPath(String.valueOf(mItems.size())).build();
+        }
+
+        /**
+         * Add the spec for this slice.
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        public Builder setSpec(SliceSpec spec) {
+            mSpec = spec;
+            return this;
+        }
+
+        /**
+         * Add hints to the Slice being constructed
+         */
+        public Builder addHints(@SliceHint String... hints) {
+            mHints.addAll(Arrays.asList(hints));
+            return this;
+        }
+
+        /**
+         * Add hints to the Slice being constructed
+         */
+        public Builder addHints(@SliceHint List<String> hints) {
+            return addHints(hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add a sub-slice to the slice being constructed
+         */
+        public Builder addSubSlice(@NonNull Slice slice) {
+            return addSubSlice(slice, null);
+        }
+
+        /**
+         * Add a sub-slice to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addSubSlice(@NonNull Slice slice, String subType) {
+            mItems.add(new SliceItem(slice, FORMAT_SLICE, subType, slice.getHints().toArray(
+                    new String[slice.getHints().size()])));
+            return this;
+        }
+
+        /**
+         * Add an action to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Slice.Builder addAction(@NonNull PendingIntent action,
+                @NonNull Slice s, @Nullable String subType) {
+            @SliceHint String[] hints = s != null
+                    ? s.getHints().toArray(new String[s.getHints().size()]) : new String[0];
+            mItems.add(new SliceItem(action, s, FORMAT_ACTION, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add text to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addText(CharSequence text, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(text, FORMAT_TEXT, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add text to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addText(CharSequence text, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            return addText(text, subType, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add an image to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addIcon(Icon icon, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(icon, FORMAT_IMAGE, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add an image to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addIcon(Icon icon, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            return addIcon(icon, subType, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add remote input to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            return addRemoteInput(remoteInput, subType, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add remote input to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+        public Slice.Builder addRemoteInput(RemoteInput remoteInput, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(remoteInput, FORMAT_REMOTE_INPUT, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add a int to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addInt(int value, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(value, FORMAT_INT, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add a int to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Builder addInt(int value, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            return addInt(value, subType, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add a timestamp to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Slice.Builder addTimestamp(long time, @Nullable String subType,
+                @SliceHint String... hints) {
+            mItems.add(new SliceItem(time, FORMAT_TIMESTAMP, subType, hints));
+            return this;
+        }
+
+        /**
+         * Add a timestamp to the slice being constructed
+         * @param subType Optional template-specific type information
+         * @see {@link SliceItem#getSubType()}
+         */
+        public Slice.Builder addTimestamp(long time, @Nullable String subType,
+                @SliceHint List<String> hints) {
+            return addTimestamp(time, subType, hints.toArray(new String[hints.size()]));
+        }
+
+        /**
+         * Add a SliceItem to the slice being constructed.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY)
+        public Slice.Builder addItem(SliceItem item) {
+            mItems.add(item);
+            return this;
+        }
+
+        /**
+         * Construct the slice.
+         */
+        public Slice build() {
+            return new Slice(mItems, mHints.toArray(new String[mHints.size()]), mUri, mSpec);
+        }
+    }
+
+    /**
+     * @hide
+     * @return A string representation of this slice.
+     */
+    @RestrictTo(Scope.LIBRARY)
+    @Override
+    public String toString() {
+        return toString("");
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public String toString(String indent) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < mItems.length; i++) {
+            sb.append(indent);
+            if (FORMAT_SLICE.equals(mItems[i].getFormat())) {
+                sb.append("slice:\n");
+                sb.append(mItems[i].getSlice().toString(indent + "   "));
+            } else if (FORMAT_ACTION.equals(mItems[i].getFormat())) {
+                sb.append("action:\n");
+                sb.append(mItems[i].getSlice().toString(indent + "   "));
+            } else if (FORMAT_TEXT.equals(mItems[i].getFormat())) {
+                sb.append("text: ");
+                sb.append(mItems[i].getText());
+                sb.append("\n");
+            } else {
+                sb.append(SliceItem.typeToString(mItems[i].getFormat()));
+                sb.append("\n");
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Turns a slice Uri into slice content.
+     *
+     * @hide
+     * @param context Context to be used.
+     * @param uri The URI to a slice provider
+     * @return The Slice provided by the app or null if none is given.
+     * @see Slice
+     */
+    @RestrictTo(Scope.LIBRARY_GROUP)
+    @SuppressWarnings("NewApi")
+    public static @Nullable Slice bindSlice(Context context, @NonNull Uri uri,
+                List<SliceSpec> supportedSpecs) {
+        if (BuildCompat.isAtLeastP()) {
+            return callBindSlice(context, uri, supportedSpecs);
+        } else {
+            return SliceProviderCompat.bindSlice(context, uri, supportedSpecs);
+        }
+    }
+
+    @TargetApi(28)
+    private static Slice callBindSlice(Context context, Uri uri,
+            List<SliceSpec> supportedSpecs) {
+        return SliceConvert.wrap(context.getSystemService(SliceManager.class)
+                .bindSlice(uri, unwrap(supportedSpecs)));
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceConvert.java b/slices/core/src/main/java/androidx/app/slice/SliceConvert.java
new file mode 100644
index 0000000..0bacae7
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceConvert.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.app.slice;
+
+
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Convert between {@link androidx.app.slice.Slice} and {@link android.app.slice.Slice}
+ */
+@RequiresApi(28)
+public class SliceConvert {
+
+    /**
+     * Convert {@link androidx.app.slice.Slice} to {@link android.app.slice.Slice}
+     */
+    public static android.app.slice.Slice unwrap(androidx.app.slice.Slice slice) {
+        android.app.slice.Slice.Builder builder = new android.app.slice.Slice.Builder(
+                slice.getUri());
+        builder.addHints(slice.getHints());
+        builder.setSpec(unwrap(slice.getSpec()));
+        for (androidx.app.slice.SliceItem item : slice.getItems()) {
+            switch (item.getFormat()) {
+                case FORMAT_SLICE:
+                    builder.addSubSlice(unwrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_IMAGE:
+                    builder.addIcon(item.getIcon(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_REMOTE_INPUT:
+                    builder.addRemoteInput(item.getRemoteInput(), item.getSubType(),
+                            item.getHints());
+                    break;
+                case FORMAT_ACTION:
+                    builder.addAction(item.getAction(), unwrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_TEXT:
+                    builder.addText(item.getText(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_INT:
+                    builder.addInt(item.getInt(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_TIMESTAMP:
+                    builder.addTimestamp(item.getTimestamp(), item.getSubType(), item.getHints());
+                    break;
+            }
+        }
+        return builder.build();
+    }
+
+    private static android.app.slice.SliceSpec unwrap(androidx.app.slice.SliceSpec spec) {
+        if (spec == null) return null;
+        return new android.app.slice.SliceSpec(spec.getType(), spec.getRevision());
+    }
+
+    static List<android.app.slice.SliceSpec> unwrap(
+            List<androidx.app.slice.SliceSpec> supportedSpecs) {
+        List<android.app.slice.SliceSpec> ret = new ArrayList<>();
+        for (androidx.app.slice.SliceSpec spec : supportedSpecs) {
+            ret.add(unwrap(spec));
+        }
+        return ret;
+    }
+
+    /**
+     * Convert {@link android.app.slice.Slice} to {@link androidx.app.slice.Slice}
+     */
+    public static androidx.app.slice.Slice wrap(android.app.slice.Slice slice) {
+        androidx.app.slice.Slice.Builder builder = new androidx.app.slice.Slice.Builder(
+                slice.getUri());
+        builder.addHints(slice.getHints());
+        builder.setSpec(wrap(slice.getSpec()));
+        for (android.app.slice.SliceItem item : slice.getItems()) {
+            switch (item.getFormat()) {
+                case FORMAT_SLICE:
+                    builder.addSubSlice(wrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_IMAGE:
+                    builder.addIcon(item.getIcon(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_REMOTE_INPUT:
+                    builder.addRemoteInput(item.getRemoteInput(), item.getSubType(),
+                            item.getHints());
+                    break;
+                case FORMAT_ACTION:
+                    builder.addAction(item.getAction(), wrap(item.getSlice()), item.getSubType());
+                    break;
+                case FORMAT_TEXT:
+                    builder.addText(item.getText(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_INT:
+                    builder.addInt(item.getInt(), item.getSubType(), item.getHints());
+                    break;
+                case FORMAT_TIMESTAMP:
+                    builder.addTimestamp(item.getTimestamp(), item.getSubType(), item.getHints());
+                    break;
+            }
+        }
+        return builder.build();
+    }
+
+    private static androidx.app.slice.SliceSpec wrap(android.app.slice.SliceSpec spec) {
+        if (spec == null) return null;
+        return new androidx.app.slice.SliceSpec(spec.getType(), spec.getRevision());
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public static List<androidx.app.slice.SliceSpec> wrap(
+            List<android.app.slice.SliceSpec> supportedSpecs) {
+        List<androidx.app.slice.SliceSpec> ret = new ArrayList<>();
+        for (android.app.slice.SliceSpec spec : supportedSpecs) {
+            ret.add(wrap(spec));
+        }
+        return ret;
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceItem.java b/slices/core/src/main/java/androidx/app/slice/SliceItem.java
new file mode 100644
index 0000000..e7d2729
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceItem.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.support.annotation.StringDef;
+import android.text.TextUtils;
+import android.util.Pair;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+/**
+ * A SliceItem is a single unit in the tree structure of a {@link Slice}.
+ * <p>
+ * A SliceItem a piece of content and some hints about what that content
+ * means or how it should be displayed. The types of content can be:
+ * <li>{@link android.app.slice.SliceItem#FORMAT_SLICE}</li>
+ * <li>{@link android.app.slice.SliceItem#FORMAT_TEXT}</li>
+ * <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
+ * <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
+ * <li>{@link android.app.slice.SliceItem#FORMAT_INT}</li>
+ * <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
+ * <p>
+ * The hints that a {@link SliceItem} are a set of strings which annotate
+ * the content. The hints that are guaranteed to be understood by the system
+ * are defined on {@link Slice}.
+ */
+public class SliceItem {
+
+    private static final String HINTS = "hints";
+    private static final String FORMAT = "format";
+    private static final String SUBTYPE = "subtype";
+    private static final String OBJ = "obj";
+    private static final String OBJ_2 = "obj_2";
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    @StringDef({FORMAT_SLICE, FORMAT_TEXT, FORMAT_IMAGE, FORMAT_ACTION, FORMAT_INT,
+            FORMAT_TIMESTAMP, FORMAT_REMOTE_INPUT})
+    public @interface SliceType {
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    protected @Slice.SliceHint String[] mHints;
+    private final String mFormat;
+    private final String mSubType;
+    private final Object mObj;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public SliceItem(Object obj, @SliceType String format, String subType,
+            @Slice.SliceHint String[] hints) {
+        mHints = hints;
+        mFormat = format;
+        mSubType = subType;
+        mObj = obj;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public SliceItem(Object obj, @SliceType String format, String subType,
+            @Slice.SliceHint List<String> hints) {
+        this (obj, format, subType, hints.toArray(new String[hints.size()]));
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public SliceItem(PendingIntent intent, Slice slice, String format, String subType,
+            @Slice.SliceHint String[] hints) {
+        this(new Pair<>(intent, slice), format, subType, hints);
+    }
+
+    /**
+     * Gets all hints associated with this SliceItem.
+     *
+     * @return Array of hints.
+     */
+    public @NonNull @Slice.SliceHint List<String> getHints() {
+        return Arrays.asList(mHints);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public void addHint(@Slice.SliceHint String hint) {
+        mHints = ArrayUtils.appendElement(String.class, mHints, hint);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public void removeHint(String hint) {
+        ArrayUtils.removeElement(String.class, mHints, hint);
+    }
+
+    /**
+     * Get the format of this SliceItem.
+     * <p>
+     * The format will be one of the following types supported by the platform:
+     * <li>{@link android.app.slice.SliceItem#FORMAT_SLICE}</li>
+     * <li>{@link android.app.slice.SliceItem#FORMAT_TEXT}</li>
+     * <li>{@link android.app.slice.SliceItem#FORMAT_IMAGE}</li>
+     * <li>{@link android.app.slice.SliceItem#FORMAT_ACTION}</li>
+     * <li>{@link android.app.slice.SliceItem#FORMAT_INT}</li>
+     * <li>{@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}</li>
+     * <li>{@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}</li>
+     * @see #getSubType() ()
+     */
+    public @SliceType String getFormat() {
+        return mFormat;
+    }
+
+    /**
+     * Get the sub-type of this SliceItem.
+     * <p>
+     * Subtypes provide additional information about the type of this information beyond basic
+     * interpretations inferred by {@link #getFormat()}. For example a slice may contain
+     * many {@link android.app.slice.SliceItem#FORMAT_TEXT} items, but only some of them may be
+     * {@link android.app.slice.Slice#SUBTYPE_MESSAGE}.
+     * @see #getFormat()
+     */
+    public String getSubType() {
+        return mSubType;
+    }
+
+    /**
+     * @return The text held by this {@link android.app.slice.SliceItem#FORMAT_TEXT} SliceItem
+     */
+    public CharSequence getText() {
+        return (CharSequence) mObj;
+    }
+
+    /**
+     * @return The icon held by this {@link android.app.slice.SliceItem#FORMAT_IMAGE} SliceItem
+     */
+    @RequiresApi(23)
+    public Icon getIcon() {
+        return (Icon) mObj;
+    }
+
+    /**
+     * @return The pending intent held by this {@link android.app.slice.SliceItem#FORMAT_ACTION}
+     * SliceItem
+     */
+    public PendingIntent getAction() {
+        return ((Pair<PendingIntent, Slice>) mObj).first;
+    }
+
+    /**
+     * @return The remote input held by this {@link android.app.slice.SliceItem#FORMAT_REMOTE_INPUT}
+     * SliceItem
+     * @hide
+     */
+    @RequiresApi(20)
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public RemoteInput getRemoteInput() {
+        return (RemoteInput) mObj;
+    }
+
+    /**
+     * @return The color held by this {@link android.app.slice.SliceItem#FORMAT_INT} SliceItem
+     */
+    public int getInt() {
+        return (Integer) mObj;
+    }
+
+    /**
+     * @return The slice held by this {@link android.app.slice.SliceItem#FORMAT_ACTION} or
+     * {@link android.app.slice.SliceItem#FORMAT_SLICE} SliceItem
+     */
+    public Slice getSlice() {
+        if (FORMAT_ACTION.equals(getFormat())) {
+            return ((Pair<PendingIntent, Slice>) mObj).second;
+        }
+        return (Slice) mObj;
+    }
+
+    /**
+     * @return The timestamp held by this {@link android.app.slice.SliceItem#FORMAT_TIMESTAMP}
+     * SliceItem
+     */
+    public long getTimestamp() {
+        return (Long) mObj;
+    }
+
+    /**
+     * @param hint The hint to check for
+     * @return true if this item contains the given hint
+     */
+    public boolean hasHint(@Slice.SliceHint String hint) {
+        return ArrayUtils.contains(mHints, hint);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public SliceItem(Bundle in) {
+        mHints = in.getStringArray(HINTS);
+        mFormat = in.getString(FORMAT);
+        mSubType = in.getString(SUBTYPE);
+        mObj = readObj(mFormat, in);
+    }
+
+    /**
+     * @hide
+     * @return
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public Bundle toBundle() {
+        Bundle b = new Bundle();
+        b.putStringArray(HINTS, mHints);
+        b.putString(FORMAT, mFormat);
+        b.putString(SUBTYPE, mSubType);
+        writeObj(b, mObj, mFormat);
+        return b;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public boolean hasHints(@Slice.SliceHint String[] hints) {
+        if (hints == null) return true;
+        for (String hint : hints) {
+            if (!TextUtils.isEmpty(hint) && !ArrayUtils.contains(mHints, hint)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public boolean hasAnyHints(@Slice.SliceHint String... hints) {
+        if (hints == null) return false;
+        for (String hint : hints) {
+            if (ArrayUtils.contains(mHints, hint)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void writeObj(Bundle dest, Object obj, String type) {
+        switch (type) {
+            case FORMAT_IMAGE:
+            case FORMAT_REMOTE_INPUT:
+                dest.putParcelable(OBJ, (Parcelable) obj);
+                break;
+            case FORMAT_SLICE:
+                dest.putParcelable(OBJ, ((Slice) obj).toBundle());
+                break;
+            case FORMAT_ACTION:
+                dest.putParcelable(OBJ, ((Pair<PendingIntent, Slice>) obj).first);
+                dest.putBundle(OBJ_2, ((Pair<PendingIntent, Slice>) obj).second.toBundle());
+                break;
+            case FORMAT_TEXT:
+                dest.putCharSequence(OBJ, (CharSequence) obj);
+                break;
+            case FORMAT_INT:
+                dest.putInt(OBJ, (Integer) mObj);
+                break;
+            case FORMAT_TIMESTAMP:
+                dest.putLong(OBJ, (Long) mObj);
+                break;
+        }
+    }
+
+    private static Object readObj(String type, Bundle in) {
+        switch (type) {
+            case FORMAT_IMAGE:
+            case FORMAT_REMOTE_INPUT:
+                return in.getParcelable(OBJ);
+            case FORMAT_SLICE:
+                return new Slice(in.getBundle(OBJ));
+            case FORMAT_TEXT:
+                return in.getCharSequence(OBJ);
+            case FORMAT_ACTION:
+                return new Pair<>(
+                        (PendingIntent) in.getParcelable(OBJ),
+                        new Slice(in.getBundle(OBJ_2)));
+            case FORMAT_INT:
+                return in.getInt(OBJ);
+            case FORMAT_TIMESTAMP:
+                return in.getLong(OBJ);
+        }
+        throw new RuntimeException("Unsupported type " + type);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(Scope.LIBRARY)
+    public static String typeToString(String format) {
+        switch (format) {
+            case FORMAT_SLICE:
+                return "Slice";
+            case FORMAT_TEXT:
+                return "Text";
+            case FORMAT_IMAGE:
+                return "Image";
+            case FORMAT_ACTION:
+                return "Action";
+            case FORMAT_INT:
+                return "Int";
+            case FORMAT_TIMESTAMP:
+                return "Timestamp";
+            case FORMAT_REMOTE_INPUT:
+                return "RemoteInput";
+        }
+        return "Unrecognized format: " + format;
+    }
+
+    /**
+     * @hide
+     * @return A string representation of this slice item.
+     */
+    @RestrictTo(Scope.LIBRARY)
+    @Override
+    public String toString() {
+        return toString("");
+    }
+
+    private String toString(String indent) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(indent);
+        if (FORMAT_SLICE.equals(mFormat)) {
+            sb.append("slice:\n");
+            sb.append(getSlice().toString(indent + "   "));
+        } else if (FORMAT_ACTION.equals(mFormat)) {
+            sb.append("action:\n");
+            sb.append(getSlice().toString(indent + "   "));
+        } else if (FORMAT_TEXT.equals(mFormat)) {
+            sb.append("text: ");
+            sb.append(getText());
+            sb.append("\n");
+        } else {
+            sb.append(SliceItem.typeToString(getFormat()));
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceProvider.java b/slices/core/src/main/java/androidx/app/slice/SliceProvider.java
new file mode 100644
index 0000000..80b9879
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceProvider.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.app.slice;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ProviderInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.v4.os.BuildCompat;
+
+import java.util.List;
+
+import androidx.app.slice.compat.ContentProviderWrapper;
+import androidx.app.slice.compat.SliceProviderCompat;
+import androidx.app.slice.compat.SliceProviderWrapperContainer;
+
+/**
+ * A SliceProvider allows an app to provide content to be displayed in system spaces. This content
+ * is templated and can contain actions, and the behavior of how it is surfaced is specific to the
+ * system surface.
+ * <p>
+ * Slices are not currently live content. They are bound once and shown to the user. If the content
+ * changes due to a callback from user interaction, then
+ * {@link ContentResolver#notifyChange(Uri, ContentObserver)} should be used to notify the system.
+ * </p>
+ * <p>
+ * The provider needs to be declared in the manifest to provide the authority for the app. The
+ * authority for most slices is expected to match the package of the application.
+ * </p>
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <provider
+ *     android:name="com.android.mypkg.MySliceProvider"
+ *     android:authorities="com.android.mypkg" />}
+ * </pre>
+ * <p>
+ * Slices can be identified by a Uri or by an Intent. To link an Intent with a slice, the provider
+ * must have an {@link IntentFilter} matching the slice intent. When a slice is being requested via
+ * an intent, {@link #onMapIntentToUri(Intent)} can be called and is expected to return an
+ * appropriate Uri representing the slice.
+ *
+ * <pre class="prettyprint">
+ * {@literal
+ * <provider
+ *     android:name="com.android.mypkg.MySliceProvider"
+ *     android:authorities="com.android.mypkg">
+ *     <intent-filter>
+ *         <action android:name="android.intent.action.MY_SLICE_INTENT" />
+ *     </intent-filter>
+ * </provider>}
+ * </pre>
+ *
+ * @see android.app.slice.Slice
+ */
+public abstract class SliceProvider extends ContentProviderWrapper {
+
+    private static List<SliceSpec> sSpecs;
+
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        ContentProvider impl;
+        if (BuildCompat.isAtLeastP()) {
+            impl = new SliceProviderWrapperContainer.SliceProviderWrapper(this);
+        } else {
+            impl = new SliceProviderCompat(this);
+        }
+        super.attachInfo(context, info, impl);
+    }
+
+    /**
+     * Implement this to initialize your slice provider on startup.
+     * This method is called for all registered slice providers on the
+     * application main thread at application launch time.  It must not perform
+     * lengthy operations, or application startup will be delayed.
+     *
+     * <p>You should defer nontrivial initialization (such as opening,
+     * upgrading, and scanning databases) until the slice provider is used
+     * (via #onBindSlice, etc).  Deferred initialization
+     * keeps application startup fast, avoids unnecessary work if the provider
+     * turns out not to be needed, and stops database errors (such as a full
+     * disk) from halting application launch.
+     *
+     * @return true if the provider was successfully loaded, false otherwise
+     */
+    public abstract boolean onCreateSliceProvider();
+
+    /**
+     * Implemented to create a slice. Will be called on the main thread.
+     * <p>
+     * onBindSlice should return as quickly as possible so that the UI tied
+     * to this slice can be responsive. No network or other IO will be allowed
+     * during onBindSlice. Any loading that needs to be done should happen
+     * off the main thread with a call to {@link ContentResolver#notifyChange(Uri, ContentObserver)}
+     * when the app is ready to provide the complete data in onBindSlice.
+     * <p>
+     *
+     * @see {@link Slice}.
+     * @see {@link android.app.slice.Slice#HINT_PARTIAL}
+     */
+    // TODO: Provide alternate notifyChange that takes in the slice (i.e. notifyChange(Uri, Slice)).
+    public abstract Slice onBindSlice(Uri sliceUri);
+
+    /**
+     * Called to inform an app that a slice has been pinned.
+     * <p>
+     * Pinning is a way that slice hosts use to notify apps of which slices
+     * they care about updates for. When a slice is pinned the content is
+     * expected to be relatively fresh and kept up to date.
+     * <p>
+     * Being pinned does not provide any escalated privileges for the slice
+     * provider. So apps should do things such as turn on syncing or schedule
+     * a job in response to a onSlicePinned.
+     * <p>
+     * Pinned state is not persisted through a reboot, and apps can expect a
+     * new call to onSlicePinned for any slices that should remain pinned
+     * after a reboot occurs.
+     *
+     * @param sliceUri The uri of the slice being unpinned.
+     * @see #onSliceUnpinned(Uri)
+     */
+    public void onSlicePinned(Uri sliceUri) {
+    }
+
+    /**
+     * Called to inform an app that a slices is no longer pinned.
+     * <p>
+     * This means that no other apps on the device care about updates to this
+     * slice anymore and therefore it is not important to be updated. Any syncs
+     * or jobs related to this slice should be cancelled.
+     * @see #onSlicePinned(Uri)
+     */
+    public void onSliceUnpinned(Uri sliceUri) {
+    }
+
+    /**
+     * This method must be overridden if an {@link IntentFilter} is specified on the SliceProvider.
+     * In that case, this method can be called and is expected to return a non-null Uri representing
+     * a slice. Otherwise this will throw {@link UnsupportedOperationException}.
+     *
+     * @return Uri representing the slice associated with the provided intent.
+     * @see {@link android.app.slice.Slice}
+     */
+    public @NonNull Uri onMapIntentToUri(Intent intent) {
+        throw new UnsupportedOperationException(
+                "This provider has not implemented intent to uri mapping");
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public static void setSpecs(List<SliceSpec> specs) {
+        sSpecs = specs;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static List<SliceSpec> getCurrentSpecs() {
+        return sSpecs;
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceSpec.java b/slices/core/src/main/java/androidx/app/slice/SliceSpec.java
new file mode 100644
index 0000000..0d7a157
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceSpec.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+/**
+ * Class describing the structure of the data contained within a slice.
+ * <p>
+ * A data version contains a string which describes the type of structure
+ * and a revision which denotes this specific implementation. Revisions are expected
+ * to be backwards compatible and monotonically increasing. Meaning if a
+ * SliceSpec has the same type and an equal or lesser revision,
+ * it is expected to be compatible.
+ * <p>
+ * Apps rendering slices will provide a list of supported versions to the OS which
+ * will also be given to the app. Apps should only return a {@link Slice} with a
+ * {@link SliceSpec} that one of the supported {@link SliceSpec}s provided
+ * {@link #canRender}.
+ *
+ * @hide
+ * @see Slice
+ * @see SliceProvider#onBindSlice(Uri)
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class SliceSpec {
+
+    private final String mType;
+    private final int mRevision;
+
+    public SliceSpec(@NonNull String type, int revision) {
+        mType = type;
+        mRevision = revision;
+    }
+
+    /**
+     * Gets the type of the version.
+     */
+    public String getType() {
+        return mType;
+    }
+
+    /**
+     * Gets the revision of the version.
+     */
+    public int getRevision() {
+        return mRevision;
+    }
+
+    /**
+     * Indicates that this spec can be used to render the specified spec.
+     * <p>
+     * Rendering support is not bi-directional (e.g. Spec v3 can render
+     * Spec v2, but Spec v2 cannot render Spec v3).
+     *
+     * @param candidate candidate format of data.
+     * @return true if versions are compatible.
+     * @see androidx.app.slice.widget.SliceView
+     */
+    public boolean canRender(@NonNull SliceSpec candidate) {
+        if (!mType.equals(candidate.mType)) return false;
+        return mRevision >= candidate.mRevision;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof SliceSpec)) return false;
+        SliceSpec other = (SliceSpec) obj;
+        return mType.equals(other.mType) && mRevision == other.mRevision;
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/SliceSpecs.java b/slices/core/src/main/java/androidx/app/slice/SliceSpecs.java
new file mode 100644
index 0000000..6629f21
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/SliceSpecs.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import android.support.annotation.RestrictTo;
+
+/**
+ * Constants for each of the slice specs
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class SliceSpecs {
+
+    /**
+     * Most basic slice, only has icon, title, and summary.
+     */
+    public static final SliceSpec BASIC = new SliceSpec("androidx.app.slice.BASIC", 1);
+
+    /**
+     * List of rows, each row has start/end items, title, summary.
+     * Also supports grid rows.
+     */
+    public static final SliceSpec LIST = new SliceSpec("androidx.app.slice.LIST", 1);
+
+    /**
+     * Messaging template. Each message contains a timestamp and a message, it optionally contains
+     * a source of where the message came from.
+     */
+    public static final SliceSpec MESSAGING = new SliceSpec("androidx.app.slice.MESSAGING", 1);
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/CompatPinnedList.java b/slices/core/src/main/java/androidx/app/slice/compat/CompatPinnedList.java
new file mode 100644
index 0000000..7a3b900
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/CompatPinnedList.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.compat;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.ArraySet;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import androidx.app.slice.SliceSpec;
+
+/**
+ * Tracks the current packages requesting pinning of any given slice. It will clear the
+ * list after a reboot since the packages are no longer requesting pinning.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class CompatPinnedList {
+
+    private static final String LAST_BOOT = "last_boot";
+    private static final String PIN_PREFIX = "pinned_";
+    private static final String SPEC_NAME_PREFIX = "spec_names_";
+    private static final String SPEC_REV_PREFIX = "spec_revs_";
+
+    // Max skew between bootup times that we think its probably rebooted.
+    // There could be some difference in our calculated boot up time if the thread
+    // sleeps between currentTimeMillis and elapsedRealtime.
+    // Its probably safe to assume the device can't boot twice within 2 secs.
+    private static final long BOOT_THRESHOLD = 2000;
+
+    private final Context mContext;
+    private final String mPrefsName;
+
+    public CompatPinnedList(Context context, String prefsName) {
+        mContext = context;
+        mPrefsName = prefsName;
+    }
+
+    private SharedPreferences getPrefs() {
+        SharedPreferences prefs = mContext.getSharedPreferences(mPrefsName, Context.MODE_PRIVATE);
+        long lastBootTime = prefs.getLong(LAST_BOOT, 0);
+        long currentBootTime = getBootTime();
+        if (Math.abs(lastBootTime - currentBootTime) > BOOT_THRESHOLD) {
+            prefs.edit()
+                    .clear()
+                    .putLong(LAST_BOOT, currentBootTime)
+                    .commit();
+        }
+        return prefs;
+    }
+
+    private Set<String> getPins(Uri uri) {
+        return getPrefs().getStringSet(PIN_PREFIX + uri.toString(), new ArraySet<String>());
+    }
+
+    /**
+     * Get the list of specs for a pinned Uri.
+     */
+    public synchronized List<SliceSpec> getSpecs(Uri uri) {
+        List<SliceSpec> specs = new ArrayList<>();
+        SharedPreferences prefs = getPrefs();
+        String specNamesStr = prefs.getString(SPEC_NAME_PREFIX + uri.toString(), null);
+        String specRevsStr = prefs.getString(SPEC_REV_PREFIX + uri.toString(), null);
+        if (TextUtils.isEmpty(specNamesStr) || TextUtils.isEmpty(specRevsStr)) {
+            return Collections.emptyList();
+        }
+        String[] specNames = specNamesStr.split(",");
+        String[] specRevs = specRevsStr.split(",");
+        if (specNames.length != specRevs.length) {
+            return Collections.emptyList();
+        }
+        for (int i = 0; i < specNames.length; i++) {
+            specs.add(new SliceSpec(specNames[i], Integer.parseInt(specRevs[i])));
+        }
+        return specs;
+    }
+
+    private void setPins(Uri uri, Set<String> pins) {
+        getPrefs().edit()
+                .putStringSet(PIN_PREFIX + uri.toString(), pins)
+                .commit();
+    }
+
+    private void setSpecs(Uri uri, List<SliceSpec> specs) {
+        String[] specNames = new String[specs.size()];
+        String[] specRevs = new String[specs.size()];
+        for (int i = 0; i < specs.size(); i++) {
+            specNames[i] = specs.get(i).getType();
+            specRevs[i] = String.valueOf(specs.get(i).getRevision());
+        }
+        getPrefs().edit()
+                .putString(SPEC_NAME_PREFIX + uri.toString(), TextUtils.join(",", specNames))
+                .putString(SPEC_REV_PREFIX + uri.toString(), TextUtils.join(",", specRevs))
+                .commit();
+    }
+
+    @VisibleForTesting
+    protected long getBootTime() {
+        return System.currentTimeMillis() - SystemClock.elapsedRealtime();
+    }
+
+    /**
+     * Adds a pin for a specific uri/pkg pair and returns true if the
+     * uri was not previously pinned.
+     */
+    public synchronized boolean addPin(Uri uri, String pkg, List<SliceSpec> specs) {
+        Set<String> pins = getPins(uri);
+        boolean wasNotPinned = pins.isEmpty();
+        pins.add(pkg);
+        setPins(uri, pins);
+        if (wasNotPinned) {
+            setSpecs(uri, specs);
+        } else {
+            setSpecs(uri, mergeSpecs(getSpecs(uri), specs));
+        }
+        return wasNotPinned;
+    }
+
+    /**
+     * Removes a pin for a specific uri/pkg pair and returns true if the
+     * uri is no longer pinned (but was).
+     */
+    public synchronized boolean removePin(Uri uri, String pkg) {
+        Set<String> pins = getPins(uri);
+        if (pins.isEmpty() || !pins.contains(pkg)) {
+            return false;
+        }
+        pins.remove(pkg);
+        setPins(uri, pins);
+        return pins.size() == 0;
+    }
+
+    private static List<SliceSpec> mergeSpecs(List<SliceSpec> specs,
+            List<SliceSpec> supportedSpecs) {
+        for (int i = 0; i < specs.size(); i++) {
+            SliceSpec s = specs.get(i);
+            SliceSpec other = findSpec(supportedSpecs, s.getType());
+            if (other == null) {
+                specs.remove(i--);
+            } else if (other.getRevision() < s.getRevision()) {
+                specs.set(i, other);
+            }
+        }
+        return specs;
+    }
+
+    private static SliceSpec findSpec(List<SliceSpec> specs, String type) {
+        for (SliceSpec spec : specs) {
+            if (Objects.equals(spec.getType(), type)) {
+                return spec;
+            }
+        }
+        return null;
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/ContentProviderWrapper.java b/slices/core/src/main/java/androidx/app/slice/compat/ContentProviderWrapper.java
new file mode 100644
index 0000000..9e02b3a
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/ContentProviderWrapper.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.app.slice.compat;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+
+/**
+ * @hide
+ */
+// TODO: Remove as soon as we have better systems in place for this.
+@RestrictTo(Scope.LIBRARY)
+public class ContentProviderWrapper extends ContentProvider {
+
+    private ContentProvider mImpl;
+
+    /**
+     * Triggers an attach with the object to wrap.
+     */
+    public void attachInfo(Context context, ProviderInfo info, ContentProvider impl) {
+        mImpl = impl;
+        super.attachInfo(context, info);
+        mImpl.attachInfo(context, info);
+    }
+
+    @Override
+    public final boolean onCreate() {
+        return mImpl.onCreate();
+    }
+
+    @Nullable
+    @Override
+    public final Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+            @Nullable String selection, @Nullable String[] selectionArgs,
+            @Nullable String sortOrder) {
+        return mImpl.query(uri, projection, selection, selectionArgs, sortOrder);
+    }
+
+    @Nullable
+    @Override
+    @RequiresApi(28)
+    public final Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+            @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) {
+        return mImpl.query(uri, projection, queryArgs, cancellationSignal);
+    }
+
+    @Nullable
+    @Override
+    public final Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+            @Nullable String selection, @Nullable String[] selectionArgs,
+            @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
+        return mImpl.query(uri, projection, selection, selectionArgs, sortOrder,
+                cancellationSignal);
+    }
+
+    @Nullable
+    @Override
+    public final String getType(@NonNull Uri uri) {
+        return mImpl.getType(uri);
+    }
+
+    @Nullable
+    @Override
+    public final Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
+        return mImpl.insert(uri, values);
+    }
+
+    @Override
+    public final int bulkInsert(@NonNull Uri uri, @NonNull ContentValues[] values) {
+        return mImpl.bulkInsert(uri, values);
+    }
+
+    @Override
+    public final int delete(@NonNull Uri uri, @Nullable String selection,
+            @Nullable String[] selectionArgs) {
+        return mImpl.delete(uri, selection, selectionArgs);
+    }
+
+    @Override
+    public final int update(@NonNull Uri uri, @Nullable ContentValues values,
+            @Nullable String selection, @Nullable String[] selectionArgs) {
+        return mImpl.update(uri, values, selection, selectionArgs);
+    }
+
+    @Nullable
+    @Override
+    public final Bundle call(@NonNull String method, @Nullable String arg,
+            @Nullable Bundle extras) {
+        return mImpl.call(method, arg, extras);
+    }
+
+    @Nullable
+    @Override
+    public final Uri canonicalize(@NonNull Uri url) {
+        return mImpl.canonicalize(url);
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/SlicePermissionActivity.java b/slices/core/src/main/java/androidx/app/slice/compat/SlicePermissionActivity.java
new file mode 100644
index 0000000..78170ab
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/SlicePermissionActivity.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.compat;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.DialogInterface.OnDismissListener;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.RestrictTo;
+import android.util.Log;
+import android.widget.TextView;
+
+import androidx.app.slice.core.R;
+
+/**
+ * Dialog that grants slice permissions for an app.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public class SlicePermissionActivity extends Activity implements OnClickListener,
+        OnDismissListener {
+
+    private static final String TAG = "SlicePermissionActivity";
+
+    private Uri mUri;
+    private String mCallingPkg;
+    private String mProviderPkg;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mUri = getIntent().getParcelableExtra(SliceProviderCompat.EXTRA_BIND_URI);
+        mCallingPkg = getIntent().getStringExtra(SliceProviderCompat.EXTRA_PKG);
+        mProviderPkg = getIntent().getStringExtra(SliceProviderCompat.EXTRA_PROVIDER_PKG);
+
+        try {
+            PackageManager pm = getPackageManager();
+            CharSequence app1 = pm.getApplicationInfo(mCallingPkg, 0).loadLabel(pm);
+            CharSequence app2 = pm.getApplicationInfo(mProviderPkg, 0).loadLabel(pm);
+            AlertDialog dialog = new AlertDialog.Builder(this)
+                    .setTitle(getString(R.string.abc_slice_permission_title, app1, app2))
+                    .setView(R.layout.abc_slice_permission_request)
+                    .setNegativeButton(R.string.abc_slice_permission_deny, this)
+                    .setPositiveButton(R.string.abc_slice_permission_allow, this)
+                    .setOnDismissListener(this)
+                    .show();
+            TextView t1 = dialog.getWindow().getDecorView().findViewById(R.id.text1);
+            t1.setText(getString(R.string.abc_slice_permission_text_1, app2));
+            TextView t2 = dialog.getWindow().getDecorView().findViewById(R.id.text2);
+            t2.setText(getString(R.string.abc_slice_permission_text_2, app2));
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Couldn't find package", e);
+            finish();
+        }
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        if (which == DialogInterface.BUTTON_POSITIVE) {
+            grantUriPermission(mCallingPkg, mUri.buildUpon().path("").build(),
+                    Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
+                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                            | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
+            getContentResolver().notifyChange(mUri, null);
+        }
+        finish();
+    }
+
+    @Override
+    public void onDismiss(DialogInterface dialog) {
+        finish();
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java
new file mode 100644
index 0000000..d1a8e65
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderCompat.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.app.slice.compat;
+
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.SliceProvider.SLICE_TYPE;
+
+import android.Manifest.permission;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.ContentProvider;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Parcelable;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.StrictMode;
+import android.os.StrictMode.ThreadPolicy;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.RestrictTo.Scope;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.SliceSpec;
+import androidx.app.slice.core.R;
+
+/**
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY)
+public class SliceProviderCompat extends ContentProvider {
+
+    private static final String TAG = "SliceProvider";
+
+    public static final String EXTRA_BIND_URI = "slice_uri";
+    public static final String METHOD_SLICE = "bind_slice";
+    public static final String METHOD_MAP_INTENT = "map_slice";
+    public static final String METHOD_PIN = "pin_slice";
+    public static final String METHOD_UNPIN = "unpin_slice";
+    public static final String METHOD_GET_PINNED_SPECS = "get_specs";
+
+    public static final String EXTRA_INTENT = "slice_intent";
+    public static final String EXTRA_SLICE = "slice";
+    public static final String EXTRA_SUPPORTED_SPECS = "specs";
+    public static final String EXTRA_SUPPORTED_SPECS_REVS = "revs";
+    public static final String EXTRA_PKG = "pkg";
+    public static final String EXTRA_PROVIDER_PKG = "provider_pkg";
+    private static final String DATA_PREFIX = "slice_data_";
+
+    private static final boolean DEBUG = false;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private SliceProvider mSliceProvider;
+    private CompatPinnedList mPinnedList;
+    private String mBindingPkg;
+
+    public SliceProviderCompat(SliceProvider provider) {
+        mSliceProvider = provider;
+    }
+
+    /**
+     * Return the package name of the caller that initiated the binding request
+     * currently happening. The returned package will have been
+     * verified to belong to the calling UID. Returns {@code null} if not
+     * currently performing an {@link SliceProvider#onBindSlice(Uri)}.
+     */
+    public final @Nullable String getBindingPackage() {
+        return mBindingPkg;
+    }
+
+    @Override
+    public boolean onCreate() {
+        mPinnedList = new CompatPinnedList(getContext(),
+                DATA_PREFIX + mSliceProvider.getClass().getName());
+        return mSliceProvider.onCreateSliceProvider();
+    }
+
+    @Override
+    public final int update(Uri uri, ContentValues values, String selection,
+            String[] selectionArgs) {
+        if (DEBUG) Log.d(TAG, "update " + uri);
+        return 0;
+    }
+
+    @Override
+    public final int delete(Uri uri, String selection, String[] selectionArgs) {
+        if (DEBUG) Log.d(TAG, "delete " + uri);
+        return 0;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, String selection,
+            String[] selectionArgs, String sortOrder) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, String selection, String[]
+            selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Cursor query(Uri uri, String[] projection, Bundle queryArgs,
+            CancellationSignal cancellationSignal) {
+        if (DEBUG) Log.d(TAG, "query " + uri);
+        return null;
+    }
+
+    @Override
+    public final Uri insert(Uri uri, ContentValues values) {
+        if (DEBUG) Log.d(TAG, "insert " + uri);
+        return null;
+    }
+
+    @Override
+    public final String getType(Uri uri) {
+        if (DEBUG) Log.d(TAG, "getFormat " + uri);
+        return SLICE_TYPE;
+    }
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        if (method.equals(METHOD_SLICE)) {
+            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            if (Binder.getCallingUid() != Process.myUid()) {
+                getContext().enforceUriPermission(uri, permission.BIND_SLICE,
+                        permission.BIND_SLICE, Binder.getCallingPid(), Binder.getCallingUid(),
+                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                        "Slice binding requires the permission BIND_SLICE");
+            }
+            List<SliceSpec> specs = getSpecs(extras);
+
+            Slice s = handleBindSlice(uri, specs, getCallingPackage());
+            Bundle b = new Bundle();
+            b.putParcelable(EXTRA_SLICE, s.toBundle());
+            return b;
+        } else if (method.equals(METHOD_MAP_INTENT)) {
+            if (Binder.getCallingUid() != Process.myUid()) {
+                getContext().enforceCallingPermission(permission.BIND_SLICE,
+                        "Slice binding requires the permission BIND_SLICE");
+            }
+            Intent intent = extras.getParcelable(EXTRA_INTENT);
+            Uri uri = mSliceProvider.onMapIntentToUri(intent);
+            Bundle b = new Bundle();
+            if (uri != null) {
+                List<SliceSpec> specs = getSpecs(extras);
+                Slice s = handleBindSlice(uri, specs, getCallingPackage());
+                b.putParcelable(EXTRA_SLICE, s.toBundle());
+            } else {
+                b.putParcelable(EXTRA_SLICE, null);
+            }
+            return b;
+        } else if (method.equals(METHOD_PIN)) {
+            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            List<SliceSpec> specs = getSpecs(extras);
+            String pkg = extras.getString(EXTRA_PKG);
+            if (mPinnedList.addPin(uri, pkg, specs)) {
+                handleSlicePinned(uri);
+            }
+            return null;
+        } else if (method.equals(METHOD_UNPIN)) {
+            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            String pkg = extras.getString(EXTRA_PKG);
+            if (mPinnedList.removePin(uri, pkg)) {
+                handleSliceUnpinned(uri);
+            }
+            return null;
+        } else if (method.equals(METHOD_GET_PINNED_SPECS)) {
+            Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+            Bundle b = new Bundle();
+            addSpecs(b, mPinnedList.getSpecs(uri));
+            return b;
+        }
+        return super.call(method, arg, extras);
+    }
+
+    private void handleSlicePinned(final Uri sliceUri) {
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            mSliceProvider.onSlicePinned(sliceUri);
+        } else {
+            final CountDownLatch latch = new CountDownLatch(1);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSliceProvider.onSlicePinned(sliceUri);
+                    latch.countDown();
+                }
+            });
+            try {
+                latch.await();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private void handleSliceUnpinned(final Uri sliceUri) {
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            mSliceProvider.onSliceUnpinned(sliceUri);
+        } else {
+            final CountDownLatch latch = new CountDownLatch(1);
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSliceProvider.onSliceUnpinned(sliceUri);
+                    latch.countDown();
+                }
+            });
+            try {
+                latch.await();
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private Slice handleBindSlice(final Uri sliceUri, final List<SliceSpec> specs,
+            final String callingPkg) {
+        // This can be removed once Slice#bindSlice is removed and everyone is using
+        // SliceManager#bindSlice.
+        String pkg = callingPkg != null ? callingPkg
+                : getContext().getPackageManager().getNameForUid(Binder.getCallingUid());
+        if (Binder.getCallingUid() != Process.myUid()) {
+            try {
+                getContext().enforceUriPermission(sliceUri,
+                        Binder.getCallingPid(), Binder.getCallingUid(),
+                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+                        "Slice binding requires write access to Uri");
+            } catch (SecurityException e) {
+                return createPermissionSlice(getContext(), sliceUri, pkg);
+            }
+        }
+        if (Looper.myLooper() == Looper.getMainLooper()) {
+            return onBindSliceStrict(sliceUri, specs, callingPkg);
+        } else {
+            final CountDownLatch latch = new CountDownLatch(1);
+            final Slice[] output = new Slice[1];
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    output[0] = onBindSliceStrict(sliceUri, specs, callingPkg);
+                    latch.countDown();
+                }
+            });
+            try {
+                latch.await();
+                return output[0];
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    /**
+     * Generate a slice that contains a permission request.
+     */
+    public static Slice createPermissionSlice(Context context, Uri sliceUri,
+            String callingPackage) {
+        return new Slice.Builder(sliceUri)
+                .addAction(createPermissionIntent(context, sliceUri, callingPackage),
+                        new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
+                                .addText(getPermissionString(context, callingPackage), null)
+                                .build(), null)
+                .addHints(HINT_LIST_ITEM)
+                .build();
+    }
+
+    /**
+     * Create a PendingIntent pointing at the permission dialog.
+     */
+    public static PendingIntent createPermissionIntent(Context context, Uri sliceUri,
+            String callingPackage) {
+        Intent intent = new Intent();
+        intent.setComponent(new ComponentName(context.getPackageName(),
+                "androidx.app.slice.compat.SlicePermissionActivity"));
+        intent.putExtra(EXTRA_BIND_URI, sliceUri);
+        intent.putExtra(EXTRA_PKG, callingPackage);
+        intent.putExtra(EXTRA_PROVIDER_PKG, context.getPackageName());
+        // Unique pending intent.
+        intent.setData(sliceUri.buildUpon().appendQueryParameter("package", callingPackage)
+                .build());
+
+        return PendingIntent.getActivity(context, 0, intent, 0);
+    }
+
+    /**
+     * Get string describing permission request.
+     */
+    public static CharSequence getPermissionString(Context context, String callingPackage) {
+        PackageManager pm = context.getPackageManager();
+        try {
+            return context.getString(R.string.abc_slices_permission_request,
+                    pm.getApplicationInfo(callingPackage, 0).loadLabel(pm),
+                    context.getApplicationInfo().loadLabel(pm));
+        } catch (PackageManager.NameNotFoundException e) {
+            // This shouldn't be possible since the caller is verified.
+            throw new RuntimeException("Unknown calling app", e);
+        }
+    }
+
+    private Slice onBindSliceStrict(Uri sliceUri, List<SliceSpec> specs, String callingPackage) {
+        ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
+        try {
+            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
+                    .detectAll()
+                    .penaltyDeath()
+                    .build());
+            SliceProvider.setSpecs(specs);
+            try {
+                mBindingPkg = callingPackage;
+                return mSliceProvider.onBindSlice(sliceUri);
+            } finally {
+                mBindingPkg = null;
+                SliceProvider.setSpecs(null);
+            }
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+    }
+
+    /**
+     * Compat version of {@link Slice#bindSlice}.
+     */
+    public static Slice bindSlice(Context context, Uri uri,
+            List<SliceSpec> supportedSpecs) {
+        ContentProviderClient provider = context.getContentResolver()
+                .acquireContentProviderClient(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_BIND_URI, uri);
+            addSpecs(extras, supportedSpecs);
+            final Bundle res = provider.call(METHOD_SLICE, null, extras);
+            if (res == null) {
+                return null;
+            }
+            Parcelable bundle = res.getParcelable(EXTRA_SLICE);
+            if (!(bundle instanceof Bundle)) {
+                return null;
+            }
+            return new Slice((Bundle) bundle);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            provider.close();
+        }
+    }
+
+    private static void addSpecs(Bundle extras, List<SliceSpec> supportedSpecs) {
+        ArrayList<String> types = new ArrayList<>();
+        ArrayList<Integer> revs = new ArrayList<>();
+        for (SliceSpec spec : supportedSpecs) {
+            types.add(spec.getType());
+            revs.add(spec.getRevision());
+        }
+        extras.putStringArrayList(EXTRA_SUPPORTED_SPECS, types);
+        extras.putIntegerArrayList(EXTRA_SUPPORTED_SPECS_REVS, revs);
+    }
+
+    private static List<SliceSpec> getSpecs(Bundle extras) {
+        ArrayList<SliceSpec> specs = new ArrayList<>();
+        ArrayList<String> types = extras.getStringArrayList(EXTRA_SUPPORTED_SPECS);
+        ArrayList<Integer> revs = extras.getIntegerArrayList(EXTRA_SUPPORTED_SPECS_REVS);
+        for (int i = 0; i < types.size(); i++) {
+            specs.add(new SliceSpec(types.get(i), revs.get(i)));
+        }
+        return specs;
+    }
+
+    /**
+     * Compat version of {@link Slice#bindSlice}.
+     */
+    public static Slice bindSlice(Context context, Intent intent,
+            List<SliceSpec> supportedSpecs) {
+        ContentResolver resolver = context.getContentResolver();
+
+        // Check if the intent has data for the slice uri on it and use that
+        final Uri intentData = intent.getData();
+        if (intentData != null && SLICE_TYPE.equals(resolver.getType(intentData))) {
+            return bindSlice(context, intentData, supportedSpecs);
+        }
+        // Otherwise ask the app
+        List<ResolveInfo> providers =
+                context.getPackageManager().queryIntentContentProviders(intent, 0);
+        if (providers == null) {
+            throw new IllegalArgumentException("Unable to resolve intent " + intent);
+        }
+        String authority = providers.get(0).providerInfo.authority;
+        Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(authority).build();
+        ContentProviderClient provider = resolver.acquireContentProviderClient(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_INTENT, intent);
+            addSpecs(extras, supportedSpecs);
+            final Bundle res = provider.call(METHOD_MAP_INTENT, null, extras);
+            if (res == null) {
+                return null;
+            }
+            Parcelable bundle = res.getParcelable(EXTRA_SLICE);
+            if (!(bundle instanceof Bundle)) {
+                return null;
+            }
+            return new Slice((Bundle) bundle);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            provider.close();
+        }
+    }
+
+    /**
+     * Compat version of {@link android.app.slice.SliceManager#pinSlice}.
+     */
+    public static void pinSlice(Context context, Uri uri,
+            List<SliceSpec> supportedSpecs) {
+        ContentProviderClient provider = context.getContentResolver()
+                .acquireContentProviderClient(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_BIND_URI, uri);
+            extras.putString(EXTRA_PKG, context.getPackageName());
+            addSpecs(extras, supportedSpecs);
+            provider.call(METHOD_PIN, null, extras);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+        } finally {
+            provider.close();
+        }
+    }
+
+    /**
+     * Compat version of {@link android.app.slice.SliceManager#unpinSlice}.
+     */
+    public static void unpinSlice(Context context, Uri uri,
+            List<SliceSpec> supportedSpecs) {
+        ContentProviderClient provider = context.getContentResolver()
+                .acquireContentProviderClient(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_BIND_URI, uri);
+            extras.putString(EXTRA_PKG, context.getPackageName());
+            addSpecs(extras, supportedSpecs);
+            provider.call(METHOD_UNPIN, null, extras);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+        } finally {
+            provider.close();
+        }
+    }
+
+    /**
+     * Compat version of {@link android.app.slice.SliceManager#getPinnedSpecs(Uri)}.
+     */
+    public static List<SliceSpec> getPinnedSpecs(Context context, Uri uri) {
+        ContentProviderClient provider = context.getContentResolver()
+                .acquireContentProviderClient(uri);
+        if (provider == null) {
+            throw new IllegalArgumentException("Unknown URI " + uri);
+        }
+        try {
+            Bundle extras = new Bundle();
+            extras.putParcelable(EXTRA_BIND_URI, uri);
+            final Bundle res = provider.call(METHOD_GET_PINNED_SPECS, null, extras);
+            if (res == null) {
+                return null;
+            }
+            return getSpecs(res);
+        } catch (RemoteException e) {
+            // Arbitrary and not worth documenting, as Activity
+            // Manager will kill this process shortly anyway.
+            return null;
+        } finally {
+            provider.close();
+        }
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderWrapperContainer.java b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderWrapperContainer.java
new file mode 100644
index 0000000..ebc2ad1
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/compat/SliceProviderWrapperContainer.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.compat;
+
+import static androidx.app.slice.SliceConvert.wrap;
+
+import android.annotation.TargetApi;
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+import android.app.slice.SliceSpec;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import java.util.List;
+
+import androidx.app.slice.SliceConvert;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(28)
+public class SliceProviderWrapperContainer {
+
+    /**
+     */
+    public static class SliceProviderWrapper extends SliceProvider {
+
+        private androidx.app.slice.SliceProvider mSliceProvider;
+
+        public SliceProviderWrapper(androidx.app.slice.SliceProvider provider) {
+            mSliceProvider = provider;
+        }
+
+        @Override
+        public boolean onCreate() {
+            return mSliceProvider.onCreateSliceProvider();
+        }
+
+        @Override
+        public Slice onBindSlice(Uri sliceUri, List<SliceSpec> supportedVersions) {
+            androidx.app.slice.SliceProvider.setSpecs(wrap(supportedVersions));
+            try {
+                return SliceConvert.unwrap(mSliceProvider.onBindSlice(sliceUri));
+            } finally {
+                androidx.app.slice.SliceProvider.setSpecs(null);
+            }
+        }
+
+        @Override
+        public void onSlicePinned(Uri sliceUri) {
+            mSliceProvider.onSlicePinned(sliceUri);
+        }
+
+        @Override
+        public void onSliceUnpinned(Uri sliceUri) {
+            mSliceProvider.onSliceUnpinned(sliceUri);
+        }
+
+        /**
+         * Maps intents to uris.
+         */
+        @Override
+        public @NonNull Uri onMapIntentToUri(Intent intent) {
+            return mSliceProvider.onMapIntentToUri(intent);
+        }
+    }
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
new file mode 100644
index 0000000..e566825
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/core/SliceHints.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.core;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
+
+/**
+ * Temporary class to contain hint constants for slices to be used.
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class SliceHints {
+    /**
+     * Subtype to range an item representing a range.
+     */
+    public static final String SUBTYPE_RANGE = "range";
+
+    /**
+     * Subtype indicating that this content is the maximum value for a range.
+     */
+    public static final String SUBTYPE_MAX = "max";
+
+    /**
+     * Subtype indicating that this content is the current value for a range.
+     */
+    public static final String SUBTYPE_VALUE = "value";
+
+    /**
+     * Key to retrieve an extra added to an intent when the value of an input range has changed.
+     */
+    public static final String EXTRA_RANGE_VALUE = "android.app.slice.extra.RANGE_VALUE";
+}
diff --git a/slices/core/src/main/java/androidx/app/slice/core/SliceQuery.java b/slices/core/src/main/java/androidx/app/slice/core/SliceQuery.java
new file mode 100644
index 0000000..f0f2371
--- /dev/null
+++ b/slices/core/src/main/java/androidx/app/slice/core/SliceQuery.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.core;
+
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+
+import android.annotation.TargetApi;
+import android.support.annotation.RestrictTo;
+import android.text.TextUtils;
+
+import java.util.ArrayDeque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Queue;
+import java.util.Spliterators;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+
+/**
+ * Utilities for finding content within a Slice.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+// TODO: Not expect 24.
+@TargetApi(24)
+public class SliceQuery {
+
+    /**
+     */
+    public static boolean hasAnyHints(SliceItem item, String... hints) {
+        if (hints == null) return false;
+        List<String> itemHints = item.getHints();
+        for (String hint : hints) {
+            if (itemHints.contains(hint)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     */
+    public static boolean hasHints(SliceItem item, String... hints) {
+        if (hints == null) return true;
+        List<String> itemHints = item.getHints();
+        for (String hint : hints) {
+            if (!TextUtils.isEmpty(hint) && !itemHints.contains(hint)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     */
+    public static boolean hasHints(Slice item, String... hints) {
+        if (hints == null) return true;
+        List<String> itemHints = item.getHints();
+        for (String hint : hints) {
+            if (!TextUtils.isEmpty(hint) && !itemHints.contains(hint)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     */
+    public static SliceItem findNotContaining(SliceItem container, List<SliceItem> list) {
+        SliceItem ret = null;
+        while (ret == null && list.size() != 0) {
+            SliceItem remove = list.remove(0);
+            if (!contains(container, remove)) {
+                ret = remove;
+            }
+        }
+        return ret;
+    }
+
+    /**
+     */
+    private static boolean contains(SliceItem container, final SliceItem item) {
+        if (container == null || item == null) return false;
+        return stream(container).filter(new Predicate<SliceItem>() {
+            @Override
+            public boolean test(SliceItem s) {
+                return s == item;
+            }
+        }).findAny().isPresent();
+    }
+
+    /**
+     */
+    public static List<SliceItem> findAll(SliceItem s, String format) {
+        return findAll(s, format, (String[]) null, null);
+    }
+
+    /**
+     */
+    public static List<SliceItem> findAll(Slice s, String format, String hints, String nonHints) {
+        return findAll(s, format, new String[]{ hints }, new String[]{ nonHints });
+    }
+
+    /**
+     */
+    public static List<SliceItem> findAll(SliceItem s, String format, String hints,
+            String nonHints) {
+        return findAll(s, format, new String[]{ hints }, new String[]{ nonHints });
+    }
+
+    /**
+     */
+    public static List<SliceItem> findAll(Slice s, final String format, final String[] hints,
+            final String[] nonHints) {
+        return stream(s).filter(new Predicate<SliceItem>() {
+            @Override
+            public boolean test(SliceItem item) {
+                return checkFormat(item, format)
+                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
+            }
+        }).collect(Collectors.<SliceItem>toList());
+    }
+
+    /**
+     */
+    public static List<SliceItem> findAll(SliceItem s, final String format, final String[] hints,
+            final String[] nonHints) {
+        return stream(s).filter(new Predicate<SliceItem>() {
+            @Override
+            public boolean test(SliceItem item) {
+                return checkFormat(item, format)
+                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
+            }
+        }).collect(Collectors.<SliceItem>toList());
+    }
+
+    /**
+     */
+    public static SliceItem find(Slice s, String format, String hints, String nonHints) {
+        return find(s, format, new String[]{ hints }, new String[]{ nonHints });
+    }
+
+    /**
+     */
+    public static SliceItem find(Slice s, String format) {
+        return find(s, format, (String[]) null, null);
+    }
+
+    /**
+     */
+    public static SliceItem find(SliceItem s, String format) {
+        return find(s, format, (String[]) null, null);
+    }
+
+    /**
+     */
+    public static SliceItem find(SliceItem s, String format, String hints, String nonHints) {
+        return find(s, format, new String[]{ hints }, new String[]{ nonHints });
+    }
+
+    /**
+     */
+    public static SliceItem find(Slice s, final String format, final String[] hints,
+            final String[] nonHints) {
+        return stream(s).filter(new Predicate<SliceItem>() {
+            @Override
+            public boolean test(SliceItem item) {
+                return checkFormat(item, format)
+                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
+            }
+        }).findFirst().orElse(null);
+    }
+
+    /**
+     */
+    public static SliceItem findSubtype(Slice s, final String format, final String subtype) {
+        return stream(s).filter(new Predicate<SliceItem>() {
+            @Override
+            public boolean test(SliceItem item) {
+                return checkFormat(item, format) && checkSubtype(item, subtype);
+            }
+        }).findFirst().orElse(null);
+    }
+
+    /**
+     */
+    public static SliceItem findSubtype(SliceItem s, final String format, final String subtype) {
+        return stream(s).filter(new Predicate<SliceItem>() {
+            @Override
+            public boolean test(SliceItem item) {
+                return checkFormat(item, format) && checkSubtype(item, subtype);
+            }
+        }).findFirst().orElse(null);
+    }
+
+    /**
+     */
+    public static SliceItem find(SliceItem s, final String format, final String[] hints,
+            final String[] nonHints) {
+        return stream(s).filter(new Predicate<SliceItem>() {
+            @Override
+            public boolean test(SliceItem item) {
+                return checkFormat(item, format)
+                        && (hasHints(item, hints) && !hasAnyHints(item, nonHints));
+            }
+        }).findFirst().orElse(null);
+    }
+
+    private static boolean checkFormat(SliceItem item, String format) {
+        return format == null || format.equals(item.getFormat());
+    }
+
+    private static boolean checkSubtype(SliceItem item, String subtype) {
+        return subtype == null || subtype.equals(item.getSubType());
+    }
+
+    /**
+     */
+    public static Stream<SliceItem> stream(SliceItem slice) {
+        Queue<SliceItem> items = new ArrayDeque<>();
+        items.add(slice);
+        return getSliceItemStream(items);
+    }
+
+    /**
+     */
+    public static Stream<SliceItem> stream(Slice slice) {
+        Queue<SliceItem> items = new ArrayDeque<>();
+        items.addAll(slice.getItems());
+        return getSliceItemStream(items);
+    }
+
+    /**
+     */
+    private static Stream<SliceItem> getSliceItemStream(final Queue<SliceItem> items) {
+        Iterator<SliceItem> iterator = new Iterator<SliceItem>() {
+            @Override
+            public boolean hasNext() {
+                return items.size() != 0;
+            }
+
+            @Override
+            public SliceItem next() {
+                SliceItem item = items.poll();
+                if (FORMAT_SLICE.equals(item.getFormat())
+                        || FORMAT_ACTION.equals(item.getFormat())) {
+                    items.addAll(item.getSlice().getItems());
+                }
+                return item;
+            }
+        };
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
+    }
+}
diff --git a/slices/core/src/main/res-public/values-v28/strings.xml b/slices/core/src/main/res-public/values-v28/strings.xml
new file mode 100644
index 0000000..cb2a320
--- /dev/null
+++ b/slices/core/src/main/res-public/values-v28/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="slice_provider">androidx.app.slice.compat.SliceProviderWrapperContainer.SliceProviderWrapper</string>
+</resources>
\ No newline at end of file
diff --git a/slices/core/src/main/res-public/values/strings.xml b/slices/core/src/main/res-public/values/strings.xml
new file mode 100644
index 0000000..d492a38
--- /dev/null
+++ b/slices/core/src/main/res-public/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="slice_provider">androidx.app.slice.compat.SliceProviderCompat</string>
+</resources>
diff --git a/slices/core/src/main/res/layout/abc_slice_permission_request.xml b/slices/core/src/main/res/layout/abc_slice_permission_request.xml
new file mode 100644
index 0000000..43f895b
--- /dev/null
+++ b/slices/core/src/main/res/layout/abc_slice_permission_request.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<!-- Extends LinearLayout -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingStart="16dp"
+    android:paddingEnd="16dp"
+    android:orientation="vertical">
+
+    <TextView
+        android:id="@+id/text2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="8dp"
+        android:paddingStart="8dp"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="@string/abc_slice_permission_text_1" />
+
+    <TextView
+        android:id="@+id/text1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="8dp"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:paddingBottom="16dp"
+        android:text="@string/abc_slice_permission_text_2" />
+
+</LinearLayout>
diff --git a/slices/core/src/main/res/values/strings.xml b/slices/core/src/main/res/values/strings.xml
new file mode 100644
index 0000000..2959af8
--- /dev/null
+++ b/slices/core/src/main/res/values/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+~ Copyright 2018 The Android Open Source Project
+~
+~ Licensed under the Apache License, Version 2.0 (the "License");
+~ you may not use this file except in compliance with the License.
+~ You may obtain a copy of the License at
+~
+~      http://www.apache.org/licenses/LICENSE-2.0
+~
+~ Unless required by applicable law or agreed to in writing, software
+~ distributed under the License is distributed on an "AS IS" BASIS,
+~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+~ See the License for the specific language governing permissions and
+~ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Text describing a permission request for one app to show another app's
+         slices [CHAR LIMIT=NONE] -->
+    <string name="abc_slices_permission_request"><xliff:g id="app" example="Example App">%1$s</xliff:g> wants to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices</string>
+
+    <!-- Title of prompt requesting access to display slices [CHAR LIMIT=NONE] -->
+    <string name="abc_slice_permission_title">Allow <xliff:g id="app" example="Example App">%1$s</xliff:g> to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices?</string>
+
+    <!-- Description of what kind of access is given to a slice host [CHAR LIMIT=NONE] -->
+    <string name="abc_slice_permission_text_1"> - It can read information from <xliff:g id="app" example="Example App">%1$s</xliff:g></string>
+    <!-- Description of what kind of access is given to a slice host [CHAR LIMIT=NONE] -->
+    <string name="abc_slice_permission_text_2"> - It can take actions inside <xliff:g id="app" example="Example App">%1$s</xliff:g></string>
+
+    <!-- Text on checkbox allowing the app to show slices from all apps [CHAR LIMIT=NONE] -->
+    <string name="abc_slice_permission_checkbox">Allow <xliff:g id="app" example="Example App">%1$s</xliff:g> to show slices from any app</string>
+
+    <!-- Option to grant the slice permission request on the screen [CHAR LIMIT=15] -->
+    <string name="abc_slice_permission_allow">Allow</string>
+
+    <!-- Option to grant the slice permission request on the screen [CHAR LIMIT=15] -->
+    <string name="abc_slice_permission_deny">Deny</string>
+
+</resources>
diff --git a/slices/view/api/current.txt b/slices/view/api/current.txt
new file mode 100644
index 0000000..6c93db0
--- /dev/null
+++ b/slices/view/api/current.txt
@@ -0,0 +1,97 @@
+package androidx.app.slice {
+
+  public abstract class SliceManager {
+    method public abstract androidx.app.slice.Slice bindSlice(android.net.Uri);
+    method public abstract androidx.app.slice.Slice bindSlice(android.content.Intent);
+    method public static androidx.app.slice.SliceManager getInstance(android.content.Context);
+    method public abstract void pinSlice(android.net.Uri);
+    method public abstract void registerSliceCallback(android.net.Uri, androidx.app.slice.SliceManager.SliceCallback);
+    method public abstract void registerSliceCallback(android.net.Uri, java.util.concurrent.Executor, androidx.app.slice.SliceManager.SliceCallback);
+    method public abstract void unpinSlice(android.net.Uri);
+    method public abstract void unregisterSliceCallback(android.net.Uri, androidx.app.slice.SliceManager.SliceCallback);
+  }
+
+  public static abstract interface SliceManager.SliceCallback {
+    method public abstract void onSliceUpdated(androidx.app.slice.Slice);
+  }
+
+  public class SliceUtils {
+    method public static int getLoadingState(androidx.app.slice.Slice);
+    method public static java.util.List<androidx.app.slice.SliceItem> getSliceActions(androidx.app.slice.Slice);
+    method public static androidx.app.slice.Slice parseSlice(java.io.InputStream, java.lang.String) throws java.io.IOException;
+    method public static void serializeSlice(androidx.app.slice.Slice, android.content.Context, java.io.OutputStream, java.lang.String, androidx.app.slice.SliceUtils.SerializeOptions) throws java.io.IOException;
+    field public static final int LOADING_ALL = 0; // 0x0
+    field public static final int LOADING_COMPLETE = 2; // 0x2
+    field public static final int LOADING_PARTIAL = 1; // 0x1
+  }
+
+  public static class SliceUtils.SerializeOptions {
+    ctor public SliceUtils.SerializeOptions();
+    method public androidx.app.slice.SliceUtils.SerializeOptions setActionMode(int);
+    method public androidx.app.slice.SliceUtils.SerializeOptions setImageMode(int);
+    field public static final int MODE_DISABLE = 2; // 0x2
+    field public static final int MODE_REMOVE = 1; // 0x1
+    field public static final int MODE_THROW = 0; // 0x0
+  }
+
+}
+
+package androidx.app.slice.widget {
+
+  public class EventInfo {
+    ctor public EventInfo(int, int, int, int);
+    method public void setPosition(int, int, int);
+    field public static final int ACTION_TYPE_BUTTON = 1; // 0x1
+    field public static final int ACTION_TYPE_CONTENT = 3; // 0x3
+    field public static final int ACTION_TYPE_SLIDER = 2; // 0x2
+    field public static final int ACTION_TYPE_TOGGLE = 0; // 0x0
+    field public static final int POSITION_CELL = 2; // 0x2
+    field public static final int POSITION_END = 1; // 0x1
+    field public static final int POSITION_START = 0; // 0x0
+    field public static final int ROW_TYPE_GRID = 1; // 0x1
+    field public static final int ROW_TYPE_LIST = 0; // 0x0
+    field public static final int ROW_TYPE_MESSAGING = 2; // 0x2
+    field public static final int ROW_TYPE_SHORTCUT = -1; // 0xffffffff
+    field public static final int STATE_OFF = 0; // 0x0
+    field public static final int STATE_ON = 1; // 0x1
+    field public int actionCount;
+    field public int actionIndex;
+    field public int actionPosition;
+    field public int actionType;
+    field public int rowIndex;
+    field public int rowTemplateType;
+    field public int sliceMode;
+    field public int state;
+  }
+
+  public final class SliceLiveData {
+    ctor public SliceLiveData();
+    method public static android.arch.lifecycle.LiveData<androidx.app.slice.Slice> fromIntent(android.content.Context, android.content.Intent);
+    method public static android.arch.lifecycle.LiveData<androidx.app.slice.Slice> fromUri(android.content.Context, android.net.Uri);
+  }
+
+  public class SliceView extends android.view.ViewGroup implements android.arch.lifecycle.Observer {
+    ctor public SliceView(android.content.Context);
+    ctor public SliceView(android.content.Context, android.util.AttributeSet);
+    ctor public SliceView(android.content.Context, android.util.AttributeSet, int);
+    ctor public SliceView(android.content.Context, android.util.AttributeSet, int, int);
+    method public int getMode();
+    method public java.util.List<androidx.app.slice.SliceItem> getSliceActions();
+    method public void onChanged(androidx.app.slice.Slice);
+    method public void setMode(int);
+    method public void setOnSliceActionListener(androidx.app.slice.widget.SliceView.OnSliceActionListener);
+    method public void setScrollable(boolean);
+    method public void setSlice(androidx.app.slice.Slice);
+    method public void setSliceActions(java.util.List<androidx.app.slice.SliceItem>);
+    method public void setTint(int);
+    field public static final int MODE_LARGE = 2; // 0x2
+    field public static final int MODE_SHORTCUT = 3; // 0x3
+    field public static final int MODE_SMALL = 1; // 0x1
+  }
+
+  public static abstract interface SliceView.OnSliceActionListener {
+    method public abstract void onSliceAction(androidx.app.slice.widget.EventInfo, androidx.app.slice.SliceItem);
+  }
+
+}
+
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
new file mode 100644
index 0000000..93e9fc5
--- /dev/null
+++ b/slices/view/build.gradle
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryVersions
+import android.support.LibraryGroups
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    implementation(project(":slices-core"))
+    implementation(project(":slices-builders"))
+    implementation(project(":recyclerview-v7"))
+    api(ARCH_LIFECYCLE_EXTENSIONS, libs.exclude_annotations_transitive)
+
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy)
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy)
+}
+
+android {
+}
+
+supportLibrary {
+    name = "Slice views"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SLICES
+    inceptionYear = "2017"
+    description = "A library that handles rendering of slice content into supported templates"
+    minSdkVersion = 24
+}
diff --git a/slices/view/lint-baseline.xml b/slices/view/lint-baseline.xml
new file mode 100644
index 0000000..49d372e
--- /dev/null
+++ b/slices/view/lint-baseline.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 3.0.0">
+
+    <issue
+        id="WrongConstant"
+        message="Must be one of: SliceView.MODE_SMALL, SliceView.MODE_LARGE, SliceView.MODE_SHORTCUT"
+        errorLine1="        return mMode;"
+        errorLine2="               ~~~~~">
+        <location
+            file="src/main/java/androidx/app/slice/widget/SliceView.java"
+            line="290"
+            column="16"/>
+    </issue>
+
+</issues>
diff --git a/slices/view/src/androidTest/AndroidManifest.xml b/slices/view/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..ec64cc1
--- /dev/null
+++ b/slices/view/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.app.slice.view.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
+    <application>
+        <provider android:name="androidx.app.slice.SliceManagerTest$TestSliceProvider"
+                  android:authorities="androidx.app.slice.view.test"
+                  android:exported="true"/>
+
+        <activity android:name="androidx.app.slice.render.SliceRenderActivity"
+            android:theme="@style/AppTheme.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/SliceManagerTest.java b/slices/view/src/androidTest/java/androidx/app/slice/SliceManagerTest.java
new file mode 100644
index 0000000..a20a5cc
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/SliceManagerTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.os.BuildCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+import androidx.app.slice.widget.SliceLiveData;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SliceManagerTest {
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+    private SliceProvider mSliceProvider;
+    private SliceManager mManager;
+
+    @Before
+    public void setup() {
+        TestSliceProvider.sSliceProviderReceiver = mSliceProvider = mock(SliceProvider.class);
+        mManager = createSliceManager(mContext);
+    }
+
+    private SliceManager createSliceManager(Context context) {
+        if (BuildCompat.isAtLeastP()) {
+            android.app.slice.SliceManager manager = mock(android.app.slice.SliceManager.class);
+            doAnswer(new Answer<Void>() {
+                @Override
+                public Void answer(InvocationOnMock invocation) throws Throwable {
+                    TestSliceProvider.sSliceProviderReceiver.onSlicePinned(
+                            (Uri) invocation.getArguments()[0]);
+                    return null;
+                }
+            }).when(manager).pinSlice(any(Uri.class), any(List.class));
+            doAnswer(new Answer<Void>() {
+                @Override
+                public Void answer(InvocationOnMock invocation) throws Throwable {
+                    TestSliceProvider.sSliceProviderReceiver.onSliceUnpinned(
+                            (Uri) invocation.getArguments()[0]);
+                    return null;
+                }
+            }).when(manager).unpinSlice(any(Uri.class));
+            return new SliceManagerWrapper(context, manager);
+        } else {
+            return SliceManager.getInstance(context);
+        }
+    }
+
+    @Test
+    public void testPin() {
+        Uri uri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(mContext.getPackageName())
+                .build();
+        mManager.pinSlice(uri);
+        verify(mSliceProvider).onSlicePinned(eq(uri));
+    }
+
+    @Test
+    public void testUnpin() {
+        Uri uri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(mContext.getPackageName())
+                .build();
+        mManager.pinSlice(uri);
+        clearInvocations(mSliceProvider);
+        mManager.unpinSlice(uri);
+        verify(mSliceProvider).onSliceUnpinned(eq(uri));
+    }
+
+    @Test
+    public void testCallback() {
+        if (BuildCompat.isAtLeastP()) {
+            return;
+        }
+        Uri uri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(mContext.getPackageName())
+                .build();
+        Slice s = new Slice.Builder(uri).build();
+        SliceManager.SliceCallback callback = mock(SliceManager.SliceCallback.class);
+        when(mSliceProvider.onBindSlice(eq(uri))).thenReturn(s);
+        mManager.registerSliceCallback(uri, new Executor() {
+            @Override
+            public void execute(@NonNull Runnable command) {
+                command.run();
+            }
+        }, callback);
+
+        mContext.getContentResolver().notifyChange(uri, null);
+
+        verify(callback, timeout(2000)).onSliceUpdated(any(Slice.class));
+    }
+
+    @Test
+    public void testPinnedSpecs() {
+        if (BuildCompat.isAtLeastP()) {
+            return;
+        }
+        Uri uri = new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority(mContext.getPackageName())
+                .build();
+        mManager.pinSlice(uri);
+        verify(mSliceProvider).onSlicePinned(eq(uri));
+
+        assertEquals(SliceLiveData.SUPPORTED_SPECS, mManager.getPinnedSpecs(uri));
+    }
+
+    public static class TestSliceProvider extends SliceProvider {
+
+        public static SliceProvider sSliceProviderReceiver;
+
+        @Override
+        public boolean onCreateSliceProvider() {
+            if (sSliceProviderReceiver != null) {
+                sSliceProviderReceiver.onCreateSliceProvider();
+            }
+            return true;
+        }
+
+        @Override
+        public Slice onBindSlice(Uri sliceUri) {
+            if (sSliceProviderReceiver != null) {
+                return sSliceProviderReceiver.onBindSlice(sliceUri);
+            }
+            return null;
+        }
+
+        @NonNull
+        @Override
+        public Uri onMapIntentToUri(Intent intent) {
+            if (sSliceProviderReceiver != null) {
+                return sSliceProviderReceiver.onMapIntentToUri(intent);
+            }
+            return null;
+        }
+
+        @Override
+        public void onSlicePinned(Uri sliceUri) {
+            if (sSliceProviderReceiver != null) {
+                sSliceProviderReceiver.onSlicePinned(sliceUri);
+            }
+        }
+
+        @Override
+        public void onSliceUnpinned(Uri sliceUri) {
+            if (sSliceProviderReceiver != null) {
+                sSliceProviderReceiver.onSliceUnpinned(sliceUri);
+            }
+        }
+    }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/SliceXmlTest.java b/slices/view/src/androidTest/java/androidx/app/slice/SliceXmlTest.java
new file mode 100644
index 0000000..5e4444d
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/SliceXmlTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SliceXmlTest {
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testThrowForAction() throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Slice s = new Slice.Builder(Uri.parse("content://pkg/slice"))
+                .addAction(null, null, null)
+                .build();
+        SliceUtils.serializeSlice(s, mContext, outputStream, "UTF-8", new SliceUtils
+                .SerializeOptions());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testThrowForRemoteInput() throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Slice s = new Slice.Builder(Uri.parse("content://pkg/slice"))
+                .addRemoteInput(null, null)
+                .build();
+        SliceUtils.serializeSlice(s, mContext, outputStream, "UTF-8", new SliceUtils
+                .SerializeOptions());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testThrowForImage() throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Slice s = new Slice.Builder(Uri.parse("content://pkg/slice"))
+                .addIcon(null, null)
+                .build();
+        SliceUtils.serializeSlice(s, mContext, outputStream, "UTF-8", new SliceUtils
+                .SerializeOptions());
+    }
+
+    @Test
+    public void testNoThrowForAction() throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Slice s = new Slice.Builder(Uri.parse("content://pkg/slice"))
+                .addAction(null, null, null)
+                .build();
+        SliceUtils.serializeSlice(s, mContext, outputStream, "UTF-8", new SliceUtils
+                .SerializeOptions().setActionMode(SliceUtils.SerializeOptions.MODE_REMOVE));
+    }
+
+    @Test
+    public void testNoThrowForRemoteInput() throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Slice s = new Slice.Builder(Uri.parse("content://pkg/slice"))
+                .addRemoteInput(null, null)
+                .build();
+        SliceUtils.serializeSlice(s, mContext, outputStream, "UTF-8", new SliceUtils
+                .SerializeOptions().setActionMode(SliceUtils.SerializeOptions.MODE_REMOVE));
+    }
+
+    @Test
+    public void testNoThrowForImage() throws IOException {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        Slice s = new Slice.Builder(Uri.parse("content://pkg/slice"))
+                .addIcon(null, null)
+                .build();
+        SliceUtils.serializeSlice(s, mContext, outputStream, "UTF-8", new SliceUtils
+                .SerializeOptions().setImageMode(SliceUtils.SerializeOptions.MODE_REMOVE));
+    }
+
+    @Test
+    public void testSerialization() throws IOException {
+        Bitmap b = Bitmap.createBitmap(50, 25, Bitmap.Config.ARGB_8888);
+        new Canvas(b).drawColor(0xffff0000);
+        // Create a slice containing all the types in a hierarchy.
+        Slice before = new Slice.Builder(Uri.parse("content://pkg/slice"))
+                .addSubSlice(new Slice.Builder(Uri.parse("content://pkg/slice/sub"))
+                        .addTimestamp(System.currentTimeMillis(), null, "Hint")
+                        .build())
+                .addIcon(Icon.createWithBitmap(b), null)
+                .addText("Some text", null)
+                .addAction(null, new Slice.Builder(Uri.parse("content://pkg/slice/sub"))
+                        .addText("Action text", null)
+                        .build(), null)
+                .addInt(0xff00ff00, "subtype")
+                .addHints("Hint 1", "Hint 2")
+                .build();
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        SliceUtils.serializeSlice(before, mContext, outputStream, "UTF-8",
+                new SliceUtils.SerializeOptions()
+                        .setImageMode(SliceUtils.SerializeOptions.MODE_DISABLE)
+                        .setActionMode(SliceUtils.SerializeOptions.MODE_DISABLE));
+
+        byte[] bytes = outputStream.toByteArray();
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
+        Slice after = SliceUtils.parseSlice(inputStream, "UTF-8");
+
+        assertEquivalent(before, after);
+    }
+
+    private void assertEquivalent(Slice desired, Slice actual) {
+        assertEquals(desired.getUri(), actual.getUri());
+        assertEquals(desired.getHints(), actual.getHints());
+        assertEquals(desired.getItems().size(), actual.getItems().size());
+
+        for (int i = 0; i < desired.getItems().size(); i++) {
+            assertEquivalent(desired.getItems().get(i), actual.getItems().get(i));
+        }
+    }
+
+    private void assertEquivalent(SliceItem desired, SliceItem actual) {
+        boolean isSliceType = FORMAT_SLICE.equals(desired.getFormat())
+                || FORMAT_ACTION.equals(desired.getFormat());
+        if (isSliceType) {
+            assertTrue(FORMAT_SLICE.equals(actual.getFormat())
+                    || FORMAT_ACTION.equals(actual.getFormat()));
+        } else {
+            assertEquals(desired.getFormat(), actual.getFormat());
+            if (FORMAT_TEXT.equals(desired.getFormat())) {
+                assertEquals(String.valueOf(desired.getText()), String.valueOf(actual.getText()));
+            }
+        }
+    }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java b/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java
new file mode 100644
index 0000000..3a71268
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/RenderTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.render;
+
+import static androidx.app.slice.render.SliceRenderer.SCREENSHOT_DIR;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RenderTest {
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+
+    @Test
+    public void testRender() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(1);
+        BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+            }
+        };
+        mContext.registerReceiver(receiver,
+                new IntentFilter(SliceRenderActivity.ACTION_RENDER_DONE));
+        mContext.startActivity(new Intent(mContext, SliceRenderActivity.class)
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+
+        latch.await(30000, TimeUnit.MILLISECONDS);
+        String path = mContext.getDataDir().toString() + "/" + SCREENSHOT_DIR;
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "mv " + path + " " + "/sdcard/");
+    }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java
new file mode 100644
index 0000000..a252b7f
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceCreator.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.render;
+
+import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
+
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.text.SpannableString;
+import android.text.format.DateUtils;
+import android.text.style.ForegroundColorSpan;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.builders.GridBuilder;
+import androidx.app.slice.builders.ListBuilder;
+import androidx.app.slice.builders.MessagingSliceBuilder;
+import androidx.app.slice.builders.SliceAction;
+import androidx.app.slice.view.test.R;
+
+/**
+ * Examples of using slice template builders.
+ */
+public class SliceCreator {
+
+    public static final String ACTION_WIFI_CHANGED =
+            "com.example.androidx.slice.action.WIFI_CHANGED";
+    public static final String ACTION_TOAST =
+            "com.example.androidx.slice.action.TOAST";
+    public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE";
+
+    public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
+            "toggle2", "contact", "gallery", "weather"};
+
+    private final Context mContext;
+
+    public SliceCreator(Context context) {
+        mContext = context;
+    }
+
+    private Context getContext() {
+        return mContext;
+    }
+
+    /**
+     * @return Uri with the provided path
+     */
+    public static Uri getUri(String path, Context context) {
+        return new Uri.Builder()
+                .scheme(ContentResolver.SCHEME_CONTENT)
+                .authority("androidx.app.slice.view.test")
+                .appendPath(path)
+                .build();
+    }
+
+    public Slice onBindSlice(Uri sliceUri) {
+        String path = sliceUri.getPath();
+        switch (path) {
+            case "/message":
+                return createMessagingSlice(sliceUri);
+            case "/wifi":
+                return createWifiSlice(sliceUri);
+            case "/note":
+                return createNoteSlice(sliceUri);
+            case "/ride":
+                return createRideSlice(sliceUri);
+            case "/toggle":
+                return createCustomToggleSlice(sliceUri);
+            case "/toggle2":
+                return createTwoCustomToggleSlices(sliceUri);
+            case "/contact":
+                return createContact(sliceUri);
+            case "/gallery":
+                return createGallery(sliceUri);
+            case "/weather":
+                return createWeather(sliceUri);
+        }
+        throw new IllegalArgumentException("Unknown uri " + sliceUri);
+    }
+
+    private Slice createWeather(Uri sliceUri) {
+        SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
+                "open weather app"), Icon.createWithResource(getContext(), R.drawable.weather_1),
+                "Weather is happening!");
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        GridBuilder gb = new GridBuilder(b);
+        gb.setPrimaryAction(primaryAction);
+        gb.addCell(new GridBuilder.CellBuilder(gb)
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+                        .addText("MON")
+                        .addTitleText("69\u00B0"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_2))
+                        .addText("TUE")
+                        .addTitleText("71\u00B0"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_3))
+                        .addText("WED")
+                        .addTitleText("76\u00B0"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_4))
+                        .addText("THU")
+                        .addTitleText("72\u00B0"))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                        .addLargeImage(Icon.createWithResource(getContext(), R.drawable.weather_1))
+                        .addText("FRI")
+                        .addTitleText("68\u00B0"));
+        return b.addGrid(gb).build();
+    }
+
+    private Slice createGallery(Uri sliceUri) {
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        GridBuilder gb = new GridBuilder(b);
+        return gb.addCell(new GridBuilder.CellBuilder(gb)
+                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_1)))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_2)))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_3)))
+                .addCell(new GridBuilder.CellBuilder(gb)
+                    .addLargeImage(Icon.createWithResource(getContext(), R.drawable.slices_4)))
+                .build();
+    }
+
+    private Slice createContact(Uri sliceUri) {
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(b);
+        GridBuilder gb = new GridBuilder(b);
+        return b.setColor(0xff3949ab)
+                .addRow(rb
+                        .setTitle("Mady Pitza")
+                        .setSubtitle("Frequently contacted contact")
+                        .addEndItem(Icon.createWithResource(getContext(), R.drawable.mady)))
+                .addGrid(gb
+                        .addCell(new GridBuilder.CellBuilder(gb)
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call))
+                            .addText("Call")
+                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
+                        .addCell(new GridBuilder.CellBuilder(gb)
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text))
+                            .addText("Text")
+                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
+                        .addCell(new GridBuilder.CellBuilder(gb)
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video))
+                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
+                            .addText("Video"))
+                        .addCell(new GridBuilder.CellBuilder(gb)
+                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email))
+                            .addText("Email")
+                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
+                .build();
+    }
+
+    private Slice createMessagingSlice(Uri sliceUri) {
+        // TODO: Remote input.
+        MessagingSliceBuilder mb = new MessagingSliceBuilder(getContext(), sliceUri);
+        return mb
+                .add(new MessagingSliceBuilder.MessageBuilder(mb)
+                        .addText("yo home \uD83C\uDF55, I emailed you the info")
+                        .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS)
+                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                .add(new MessagingSliceBuilder.MessageBuilder(mb)
+                        .addText("just bought my tickets")
+                        .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS))
+                .add(new MessagingSliceBuilder.MessageBuilder(mb)
+                        .addText("yay! can't wait for getContext() weekend!\n"
+                                + "\uD83D\uDE00")
+                        .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS)
+                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                .build();
+
+    }
+
+    private Slice createNoteSlice(Uri sliceUri) {
+        // TODO: Remote input.
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+        return lb.setColor(0xfff4b400)
+                .addRow(new ListBuilder.RowBuilder(lb)
+                    .setTitle("Create new note")
+                    .setSubtitle("with this note taking app")
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "create note"),
+                            Icon.createWithResource(getContext(), R.drawable.ic_create),
+                            "Create note"))
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "voice note"),
+                            Icon.createWithResource(getContext(), R.drawable.ic_voice),
+                            "Voice note"))
+                    .addEndItem(new SliceAction(getIntent("android.media.action.IMAGE_CAPTURE"),
+                            Icon.createWithResource(getContext(), R.drawable.ic_camera),
+                            "Photo note")))
+                .build();
+    }
+
+    private Slice createRideSlice(Uri sliceUri) {
+        final ForegroundColorSpan colorSpan = new ForegroundColorSpan(0xff0F9D58);
+        SpannableString headerSubtitle = new SpannableString("Ride in 4 min");
+        headerSubtitle.setSpan(colorSpan, 8, headerSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+        SpannableString homeSubtitle = new SpannableString("12 miles | 12 min | $9.00");
+        homeSubtitle.setSpan(colorSpan, 20, homeSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+        SpannableString workSubtitle = new SpannableString("44 miles | 1 hour 45 min | $31.41");
+        workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
+        SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST, "get ride"),
+                Icon.createWithResource(getContext(), R.drawable.ic_car), "Get Ride");
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+        return lb.setColor(0xff0F9D58)
+                .setHeader(new ListBuilder.HeaderBuilder(lb)
+                        .setTitle("Get ride")
+                        .setSubtitle(headerSubtitle)
+                        .setSummarySubtitle("Ride to work in 12 min | Ride home in 1 hour 45 min")
+                        .setPrimaryAction(primaryAction))
+                .addRow(new ListBuilder.RowBuilder(lb)
+                        .setTitle("Work")
+                        .setSubtitle(workSubtitle)
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "work"),
+                                Icon.createWithResource(getContext(), R.drawable.ic_work),
+                                "Get ride work")))
+                .addRow(new ListBuilder.RowBuilder(lb)
+                        .setTitle("Home")
+                        .setSubtitle(homeSubtitle)
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "home"),
+                                Icon.createWithResource(getContext(), R.drawable.ic_home),
+                                "Get ride home")))
+                .build();
+    }
+
+    private Slice createCustomToggleSlice(Uri sliceUri) {
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        return b.setColor(0xffff4081)
+                .addRow(new ListBuilder.RowBuilder(b)
+                    .setTitle("Custom toggle")
+                    .setSubtitle("It can support two states")
+                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "star toggled"),
+                            Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                            "Toggle star", true /* isChecked */)))
+                .build();
+    }
+
+    private Slice createTwoCustomToggleSlices(Uri sliceUri) {
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+        return lb.setColor(0xffff4081)
+                .addRow(new ListBuilder.RowBuilder(lb)
+                        .setTitle("2 toggles")
+                        .setSubtitle("each supports two states")
+                        .addEndItem(new SliceAction(
+                                getBroadcastIntent(ACTION_TOAST, "first star toggled"),
+                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                "Toggle star", true /* isChecked */))
+                        .addEndItem(new SliceAction(
+                                getBroadcastIntent(ACTION_TOAST, "second star toggled"),
+                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                "Toggle star", false /* isChecked */)))
+                .build();
+    }
+
+    private Slice createWifiSlice(Uri sliceUri) {
+        // Get wifi state
+        WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        int wifiState = wifiManager.getWifiState();
+        boolean wifiEnabled = false;
+        String state;
+        switch (wifiState) {
+            case WifiManager.WIFI_STATE_DISABLED:
+            case WifiManager.WIFI_STATE_DISABLING:
+                state = "disconnected";
+                break;
+            case WifiManager.WIFI_STATE_ENABLED:
+            case WifiManager.WIFI_STATE_ENABLING:
+                state = wifiManager.getConnectionInfo().getSSID();
+                wifiEnabled = true;
+                break;
+            case WifiManager.WIFI_STATE_UNKNOWN:
+            default:
+                state = ""; // just don't show anything?
+                break;
+        }
+        boolean finalWifiEnabled = wifiEnabled;
+        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
+                Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
+        return b.setColor(0xff4285f4)
+                .addRow(new ListBuilder.RowBuilder(b)
+                    .setTitle("Wi-fi")
+                    .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
+                    .setSubtitle(state)
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
+                                "Toggle wifi", finalWifiEnabled))
+                    .setPrimaryAction(primaryAction))
+            .build();
+    }
+
+    private PendingIntent getIntent(String action) {
+        Intent intent = new Intent(action);
+        intent.setClassName(getContext().getPackageName(), SliceRenderActivity.class.getName());
+        PendingIntent pi = PendingIntent.getActivity(getContext(), 0, intent, 0);
+        return pi;
+    }
+
+    private PendingIntent getBroadcastIntent(String action, String message) {
+        Intent intent = new Intent(action);
+        intent.setClassName(getContext().getPackageName(), SliceRenderActivity.class.getName());
+        // Ensure a new PendingIntent is created for each message.
+        int requestCode = 0;
+        if (message != null) {
+            intent.putExtra(EXTRA_TOAST_MESSAGE, message);
+            requestCode = message.hashCode();
+        }
+        return PendingIntent.getBroadcast(getContext(), requestCode, intent,
+                PendingIntent.FLAG_UPDATE_CURRENT);
+    }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderActivity.java b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderActivity.java
new file mode 100644
index 0000000..debb280
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderActivity.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.render;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+public class SliceRenderActivity extends Activity {
+    public static final String ACTION_RENDER_DONE = "androidx.app.slice.render.RENDER_DONE";
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        new SliceRenderer(this).renderAll(new Runnable() {
+
+            @Override
+            public void run() {
+                sendBroadcast(new Intent(ACTION_RENDER_DONE));
+                finish();
+            }
+        });
+    }
+}
diff --git a/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
new file mode 100644
index 0000000..056af32
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/app/slice/render/SliceRenderer.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.render;
+
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.util.concurrent.CountDownLatch;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceProvider;
+import androidx.app.slice.view.test.R;
+import androidx.app.slice.widget.SliceLiveData;
+import androidx.app.slice.widget.SliceView;
+
+public class SliceRenderer {
+
+    private static final String TAG = "SliceRenderer";
+    public static final String SCREENSHOT_DIR = "slice-screenshots";
+    private static File sScreenshotDirectory;
+
+    private final Activity mContext;
+    private final View mLayout;
+    private final SliceView mSV1;
+    private final SliceView mSV2;
+    private final SliceView mSV3;
+    private final ViewGroup mParent;
+    private final Handler mHandler;
+    private final SliceCreator mSliceCreator;
+    private CountDownLatch mDoneLatch;
+
+    public SliceRenderer(Activity context) {
+        mContext = context;
+        mParent = new ViewGroup(mContext) {
+            @Override
+            protected void onLayout(boolean changed, int l, int t, int r, int b) {
+                int width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 900,
+                        mContext.getResources().getDisplayMetrics());
+                int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200,
+                        mContext.getResources().getDisplayMetrics());
+                mLayout.measure(makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+                        makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+                mLayout.layout(0, 0, width, height);
+            }
+
+            @Override
+            protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+                return false;
+            }
+        };
+        mLayout = LayoutInflater.from(context).inflate(R.layout.render_layout, null);
+        mSV1 = mLayout.findViewById(R.id.sv1);
+        mSV1.setMode(SliceView.MODE_SHORTCUT);
+        mSV2 = mLayout.findViewById(R.id.sv2);
+        mSV2.setMode(SliceView.MODE_SMALL);
+        mSV3 = mLayout.findViewById(R.id.sv3);
+        mSV3.setMode(SliceView.MODE_LARGE);
+        disableAnims(mLayout);
+        mHandler = new Handler();
+        ((ViewGroup) mContext.getWindow().getDecorView()).addView(mParent);
+        mParent.addView(mLayout);
+        SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+        mSliceCreator = new SliceCreator(mContext);
+    }
+
+    private void disableAnims(View view) {
+        if (view instanceof RecyclerView) {
+            ((RecyclerView) view).setItemAnimator(null);
+        }
+        if (view instanceof ViewGroup) {
+            ViewGroup viewGroup = (ViewGroup) view;
+            for (int i = 0; i < viewGroup.getChildCount(); i++) {
+                disableAnims(viewGroup.getChildAt(i));
+            }
+        }
+    }
+
+
+    private File getScreenshotDirectory() {
+        if (sScreenshotDirectory == null) {
+            File storage = mContext.getDataDir();
+            sScreenshotDirectory = new File(storage, SCREENSHOT_DIR);
+            if (!sScreenshotDirectory.exists()) {
+                if (!sScreenshotDirectory.mkdirs()) {
+                    throw new RuntimeException(
+                            "Failed to create a screenshot directory.");
+                }
+            }
+        }
+        return sScreenshotDirectory;
+    }
+
+
+    private void doRender() {
+        File output = getScreenshotDirectory();
+        if (!output.exists()) {
+            output.mkdir();
+        }
+        mDoneLatch = new CountDownLatch(SliceCreator.URI_PATHS.length);
+        for (String slice : SliceCreator.URI_PATHS) {
+            doRender(slice, new File(output, String.format("%s.png", slice)));
+        }
+        Log.d(TAG, "Wrote render to " + output.getAbsolutePath());
+        mContext.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ((ViewGroup) mParent.getParent()).removeView(mParent);
+            }
+        });
+        try {
+            mDoneLatch.await();
+        } catch (InterruptedException e) {
+        }
+    }
+
+    private void doRender(final String slice, final File file) {
+        Log.d(TAG, "Rendering " + slice + " to " + file.getAbsolutePath());
+
+        final Slice s = mSliceCreator.onBindSlice(SliceCreator.getUri(slice, mContext));
+
+        final CountDownLatch l = new CountDownLatch(1);
+        mContext.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mSV1.setSlice(s);
+                mSV2.setSlice(s);
+                mSV3.setSlice(s);
+                mSV1.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+                    @Override
+                    public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                            int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                        mSV1.removeOnLayoutChangeListener(this);
+                        mSV1.postDelayed(new Runnable() {
+                            @Override
+                            public void run() {
+                                Log.d(TAG, "Drawing " + slice);
+                                Bitmap b = Bitmap.createBitmap(mLayout.getMeasuredWidth(),
+                                        mLayout.getMeasuredHeight(),
+                                        Bitmap.Config.ARGB_8888);
+
+                                mLayout.draw(new Canvas(b));
+                                try {
+                                    doCompress(slice, b, new FileOutputStream(file));
+                                } catch (FileNotFoundException e) {
+                                    throw new RuntimeException(e);
+                                }
+                                l.countDown();
+                            }
+                        }, 10);
+                    }
+                });
+            }
+        });
+        try {
+            l.await();
+        } catch (InterruptedException e) {
+        }
+    }
+
+    private void doCompress(final String slice, final Bitmap b, final FileOutputStream s) {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                Log.d(TAG, "Compressing " + slice);
+                if (!b.compress(Bitmap.CompressFormat.PNG, 100, s)) {
+                    throw new RuntimeException("Unable to compress");
+                }
+
+                b.recycle();
+                Log.d(TAG, "Done " + slice);
+                mDoneLatch.countDown();
+            }
+        });
+    }
+
+    public void renderAll(final Runnable runnable) {
+        final ProgressDialog dialog = ProgressDialog.show(mContext, null, "Rendering...");
+        new Thread(new Runnable() {
+            @Override
+            public void run() {
+                doRender();
+                mContext.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        dialog.dismiss();
+                        runnable.run();
+                    }
+                });
+            }
+        }).start();
+    }
+}
diff --git a/slices/view/src/androidTest/res/drawable/ic_call.xml b/slices/view/src/androidTest/res/drawable/ic_call.xml
new file mode 100644
index 0000000..ebf9de6
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_call.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6.62,10.79c1.44,2.83 3.76,5.14 6.59,6.59l2.2,-2.2c0.27,-0.27 0.67,-0.36 1.02,-0.24 1.12,0.37 2.33,0.57 3.57,0.57 0.55,0 1,0.45 1,1V20c0,0.55 -0.45,1 -1,1 -9.39,0 -17,-7.61 -17,-17 0,-0.55 0.45,-1 1,-1h3.5c0.55,0 1,0.45 1,1 0,1.25 0.2,2.45 0.57,3.57 0.11,0.35 0.03,0.74 -0.25,1.02l-2.2,2.2z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_camera.xml b/slices/view/src/androidTest/res/drawable/ic_camera.xml
new file mode 100644
index 0000000..74b6bf9
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_camera.xml
@@ -0,0 +1,32 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M 12 8.8 C 13.7673111995 8.8 15.2 10.2326888005 15.2 12 C 15.2 13.7673111995 13.7673111995 15.2 12 15.2 C 10.2326888005 15.2 8.8 13.7673111995 8.8 12 C 8.8 10.2326888005 10.2326888005 8.8 12 8.8 Z" />
+    <path
+        android:fillColor="#000000"
+        android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
+2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
+5-2.24 5-5 5z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/ic_car.xml b/slices/view/src/androidTest/res/drawable/ic_car.xml
new file mode 100644
index 0000000..6bab660
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_car.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M18.92 6.01C18.72 5.42 18.16 5 17.5 5h-11c-.66 0-1.21 .42 -1.42 1.01L3 12v8c0
+.55 .45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55 .45 1 1 1h1c.55 0 1-.45
+1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5 .67 1.5
+1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5 .67 1.5
+1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/ic_create.xml b/slices/view/src/androidTest/res/drawable/ic_create.xml
new file mode 100644
index 0000000..d1666a8
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_create.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_email.xml b/slices/view/src/androidTest/res/drawable/ic_email.xml
new file mode 100644
index 0000000..ce97ab8
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_email.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_home.xml b/slices/view/src/androidTest/res/drawable/ic_home.xml
new file mode 100644
index 0000000..b278230
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_home.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#000000"
+        android:pathData="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/ic_large.xml b/slices/view/src/androidTest/res/drawable/ic_large.xml
new file mode 100644
index 0000000..79ac590
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_large.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/>
+    <path
+        android:strokeColor="#FF000000"
+        android:strokeWidth="2"
+        android:pathData="M16,18 l16,0 l0,10 l-16,0z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_shortcut.xml b/slices/view/src/androidTest/res/drawable/ic_shortcut.xml
new file mode 100644
index 0000000..bf9572a
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_shortcut.xml
@@ -0,0 +1,34 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="48.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="48.0dp">
+    <path
+        android:fillColor="#e2e2e2"
+        android:pathData="M24.0,24.0m-19.0,0.0a19.0,19.0 0.0,1.0 1.0,38.0 0.0a19.0,19.0 0.0,1.0 1.0,-38.0 0.0"/>
+    <group
+        android:scaleX=".7"
+        android:scaleY=".7"
+        android:translateX="7.2"
+        android:translateY="7.2">
+
+        <path
+            android:fillColor="#ff000000"
+            android:pathData="M12.0,36.0c0.0,1.0 0.9,2.0 2.0,2.0l2.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l4.0,0.0l0.0,7.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0l0.0,-7.0l2.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L36.0,16.0L12.0,16.0l0.0,20.0zM7.0,16.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L10.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zm34.0,0.0c-1.66,0.0 -3.0,1.34 -3.0,3.0l0.0,14.0c0.0,1.66 1.34,3.0 3.0,3.0s3.0,-1.34 3.0,-3.0L44.0,19.0c0.0,-1.66 -1.34,-3.0 -3.0,-3.0zM31.06,4.32l2.61,-2.61c0.39,-0.3 0.39,-1.02 0.0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0.0L29.3,3.25C27.7,2.46 25.91,2.0 24.0,2.0c-1.92,0.0 -3.7,0.46 -5.33,1.26L15.0,0.29c-0.39,-0.39 -1.02,-0.39 -1.41,0.0 -0.3,0.39 -0.39,1.02 0.0,1.41l2.62,2.62C13.94,6.51 12.0,10.03 12.0,14.0l24.0,0.0c0.0,-3.98 -1.95,-7.5 -4.94,-9.68zM20.0,10.0l-2.0,0.0L18.0,8.0l2.0,0.0l0.0,2.0zm10.0,0.0l-2.0,0.0L28.0,8.0l2.0,0.0l0.0,2.0z"/>
+    </group>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_small.xml b/slices/view/src/androidTest/res/drawable/ic_small.xml
new file mode 100644
index 0000000..8fd43df
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_small.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M34.0,2.02L14.0,2.0c-2.21,0.0 -4.0,1.79 -4.0,4.0l0.0,36.0c0.0,2.21 1.79,4.0 4.0,4.0l20.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L38.0,6.0c0.0,-2.21 -1.79,-3.98 -4.0,-3.98zM34.0,38.0L14.0,38.0L14.0,10.0l20.0,0.0l0.0,28.0z"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M16,18 l16,0 l0,4 l-16,0z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_star_off.xml b/slices/view/src/androidTest/res/drawable/ic_star_off.xml
new file mode 100644
index 0000000..7f023b3
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_star_off.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_star_on.xml b/slices/view/src/androidTest/res/drawable/ic_star_on.xml
new file mode 100644
index 0000000..f3ca086
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_star_on.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_text.xml b/slices/view/src/androidTest/res/drawable/ic_text.xml
new file mode 100644
index 0000000..d2876bf
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_text.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,2L4,2c-1.1,0 -1.99,0.9 -1.99,2L2,22l4,-4h14c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM18,14L6,14v-2h12v2zM18,11L6,11L6,9h12v2zM18,8L6,8L6,6h12v2z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_video.xml b/slices/view/src/androidTest/res/drawable/ic_video.xml
new file mode 100644
index 0000000..e23eac8
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_video.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_voice.xml b/slices/view/src/androidTest/res/drawable/ic_voice.xml
new file mode 100644
index 0000000..8f465bb
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_voice.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,15c1.66,0 2.99,-1.34 2.99,-3L15,6c0,-1.66 -1.34,-3 -3,-3S9,4.34 9,6v6c0,1.66 1.34,3 3,3zM17.3,12c0,3 -2.54,5.1 -5.3,5.1S6.7,15 6.7,12L5,12c0,3.42 2.72,6.23 6,6.72L11,22h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi.xml b/slices/view/src/androidTest/res/drawable/ic_wifi.xml
new file mode 100644
index 0000000..4fbfd60
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_work.xml b/slices/view/src/androidTest/res/drawable/ic_work.xml
new file mode 100644
index 0000000..6806402
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_work.xml
@@ -0,0 +1,28 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M0 0h24v24H0z" />
+    <path
+        android:fillColor="#000000"
+        android:pathData="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99 .89 -1.99 2L2
+19c0 1.11 .89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z" />
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/mady.jpg b/slices/view/src/androidTest/res/drawable/mady.jpg
new file mode 100644
index 0000000..8b61f1b
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/mady.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_1.jpg b/slices/view/src/androidTest/res/drawable/slices_1.jpg
new file mode 100644
index 0000000..31cc065
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_1.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_2.jpg b/slices/view/src/androidTest/res/drawable/slices_2.jpg
new file mode 100644
index 0000000..adbe1d3
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_2.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_3.jpg b/slices/view/src/androidTest/res/drawable/slices_3.jpg
new file mode 100644
index 0000000..6617019
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_3.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/slices_4.jpg b/slices/view/src/androidTest/res/drawable/slices_4.jpg
new file mode 100644
index 0000000..d00a8b3
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/slices_4.jpg
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/toggle_star.xml b/slices/view/src/androidTest/res/drawable/toggle_star.xml
new file mode 100644
index 0000000..e964925
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/toggle_star.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/on"
+        android:state_checked="true"
+        android:drawable="@drawable/ic_star_on" />
+    <item
+        android:id="@+id/off"
+        android:drawable="@drawable/ic_star_off" />
+</selector>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/drawable/weather_1.png b/slices/view/src/androidTest/res/drawable/weather_1.png
new file mode 100644
index 0000000..7c4034e
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_1.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/weather_2.png b/slices/view/src/androidTest/res/drawable/weather_2.png
new file mode 100644
index 0000000..f1b6672
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_2.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/weather_3.png b/slices/view/src/androidTest/res/drawable/weather_3.png
new file mode 100644
index 0000000..a5db683
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_3.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/drawable/weather_4.png b/slices/view/src/androidTest/res/drawable/weather_4.png
new file mode 100644
index 0000000..0b7f3b0
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/weather_4.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/layout/activity_demo.xml b/slices/view/src/androidTest/res/layout/activity_demo.xml
new file mode 100644
index 0000000..f557f40
--- /dev/null
+++ b/slices/view/src/androidTest/res/layout/activity_demo.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="com.example.android.support.content.demos.ContentPagerDemoActivity">
+
+    <android.support.v7.widget.Toolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="?attr/actionBarSize"
+        android:background="?attr/colorPrimary"
+        android:theme="@style/AppTheme.AppBarOverlay"
+        app:popupTheme="@style/AppTheme.PopupOverlay"/>
+
+    <android.support.v7.widget.RecyclerView
+        android:id="@+id/list"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</LinearLayout>
diff --git a/slices/view/src/androidTest/res/layout/render_layout.xml b/slices/view/src/androidTest/res/layout/render_layout.xml
new file mode 100644
index 0000000..a8ed779
--- /dev/null
+++ b/slices/view/src/androidTest/res/layout/render_layout.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="1200dp"
+              android:layout_height="400dp"
+              android:background="@android:color/black"
+              android:orientation="horizontal"
+              android:padding="20dp">
+
+
+    <FrameLayout android:layout_width="wrap_content"
+                 android:layout_height="wrap_content">
+        <androidx.app.slice.widget.SliceView
+            android:id="@+id/sv1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+    </FrameLayout>
+
+    <FrameLayout android:layout_width="400dp"
+                 android:layout_height="wrap_content"
+                 android:layout_marginStart="20dp">
+        <androidx.app.slice.widget.SliceView
+            android:id="@+id/sv2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="@android:color/white"
+            android:paddingEnd="16dp"
+            android:paddingStart="16dp"/>
+    </FrameLayout>
+
+    <FrameLayout android:layout_width="400dp"
+                 android:layout_height="wrap_content"
+                 android:layout_marginStart="20dp">
+        <androidx.app.slice.widget.SliceView
+            android:id="@+id/sv3"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="@android:color/white"
+            android:paddingEnd="16dp"
+            android:paddingStart="16dp"/>
+    </FrameLayout>
+
+
+</LinearLayout>
\ No newline at end of file
diff --git a/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9a078e3
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..efc028a
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..3af2608
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9bec2e6
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher.png b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..aee44e1
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher_round.png b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..34947cd
--- /dev/null
+++ b/slices/view/src/androidTest/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/slices/view/src/androidTest/res/values/colors.xml b/slices/view/src/androidTest/res/values/colors.xml
new file mode 100644
index 0000000..86b4304
--- /dev/null
+++ b/slices/view/src/androidTest/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <color name="colorPrimary">#3F51B5</color>
+    <color name="colorPrimaryDark">#303F9F</color>
+    <color name="colorAccent">#FF4081</color>
+</resources>
diff --git a/slices/view/src/androidTest/res/values/strings.xml b/slices/view/src/androidTest/res/values/strings.xml
new file mode 100644
index 0000000..89583bd
--- /dev/null
+++ b/slices/view/src/androidTest/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name">Slice Browser</string>
+</resources>
diff --git a/slices/view/src/androidTest/res/values/styles.xml b/slices/view/src/androidTest/res/values/styles.xml
new file mode 100644
index 0000000..afb6bad
--- /dev/null
+++ b/slices/view/src/androidTest/res/values/styles.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+        <item name="colorPrimary">@color/colorPrimary</item>
+        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+        <item name="colorAccent">@color/colorAccent</item>
+    </style>
+    <style name="AppTheme.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+    <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
+    <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
+
+</resources>
diff --git a/slices/view/src/main/AndroidManifest.xml b/slices/view/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..9263885
--- /dev/null
+++ b/slices/view/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="androidx.app.slice.view"/>
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceManager.java b/slices/view/src/main/java/androidx/app/slice/SliceManager.java
new file mode 100644
index 0000000..ba8c376
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/SliceManager.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v4.os.BuildCompat;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/**
+ * Class to handle interactions with {@link Slice}s.
+ * <p>
+ * The SliceManager manages permissions and pinned state for slices.
+ */
+public abstract class SliceManager {
+
+    /**
+     * Get a {@link SliceManager}.
+     */
+    @SuppressWarnings("NewApi")
+    public static @NonNull SliceManager getInstance(@NonNull Context context) {
+        if (BuildCompat.isAtLeastP()) {
+            return new SliceManagerWrapper(context);
+        } else {
+            return new SliceManagerCompat(context);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    SliceManager() {
+    }
+
+    /**
+     * Adds a callback to a specific slice uri.
+     * <p>
+     * This is a convenience that performs a few slice actions at once. It will put
+     * the slice in a pinned state since there is a callback attached. It will also
+     * listen for content changes, when a content change observes, the android system
+     * will bind the new slice and provide it to all registered {@link SliceCallback}s.
+     *
+     * @param uri The uri of the slice being listened to.
+     * @param callback The listener that should receive the callbacks.
+     * @see SliceProvider#onSlicePinned(Uri)
+     */
+    public abstract void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback);
+
+    /**
+     * Adds a callback to a specific slice uri.
+     * <p>
+     * This is a convenience that performs a few slice actions at once. It will put
+     * the slice in a pinned state since there is a callback attached. It will also
+     * listen for content changes, when a content change observes, the android system
+     * will bind the new slice and provide it to all registered {@link SliceCallback}s.
+     *
+     * @param uri The uri of the slice being listened to.
+     * @param callback The listener that should receive the callbacks.
+     * @see SliceProvider#onSlicePinned(Uri)
+     */
+    public abstract void registerSliceCallback(@NonNull Uri uri, @NonNull Executor executor,
+            @NonNull SliceCallback callback);
+
+    /**
+     * Removes a callback for a specific slice uri.
+     * <p>
+     * Removes the app from the pinned state (if there are no other apps/callbacks pinning it)
+     * in addition to removing the callback.
+     *
+     * @param uri The uri of the slice being listened to
+     * @param callback The listener that should no longer receive callbacks.
+     * @see #registerSliceCallback
+     */
+    public abstract void unregisterSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback);
+
+    /**
+     * Ensures that a slice is in a pinned state.
+     * <p>
+     * Pinned state is not persisted across reboots, so apps are expected to re-pin any slices
+     * they still care about after a reboot.
+     *
+     * @param uri The uri of the slice being pinned.
+     * @see SliceProvider#onSlicePinned(Uri)
+     */
+    public abstract void pinSlice(@NonNull Uri uri);
+
+    /**
+     * Remove a pin for a slice.
+     * <p>
+     * If the slice has no other pins/callbacks then the slice will be unpinned.
+     *
+     * @param uri The uri of the slice being unpinned.
+     * @see #pinSlice
+     * @see SliceProvider#onSliceUnpinned(Uri)
+     */
+    public abstract void unpinSlice(@NonNull Uri uri);
+
+    /**
+     * Get the current set of specs for a pinned slice.
+     * <p>
+     * This is the set of specs supported for a specific pinned slice. It will take
+     * into account all clients and returns only specs supported by all.
+     * @hide
+     * @see SliceSpec
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public abstract @NonNull List<SliceSpec> getPinnedSpecs(@NonNull Uri uri);
+
+    /**
+     * Turns a slice Uri into slice content.
+     *
+     * @param uri The URI to a slice provider
+     * @return The Slice provided by the app or null if none is given.
+     * @see Slice
+     */
+    public abstract @Nullable Slice bindSlice(@NonNull Uri uri);
+
+    /**
+     * Turns a slice intent into slice content. Expects an explicit intent. If there is no
+     * {@link android.content.ContentProvider} associated with the given intent this will throw
+     * {@link IllegalArgumentException}.
+     *
+     * @param intent The intent associated with a slice.
+     * @return The Slice provided by the app or null if none is given.
+     * @see Slice
+     * @see androidx.app.slice.SliceProvider#onMapIntentToUri(Intent)
+     * @see Intent
+     */
+    public abstract @Nullable Slice bindSlice(@NonNull Intent intent);
+
+    /**
+     * Class that listens to changes in {@link Slice}s.
+     */
+    public interface SliceCallback {
+
+        /**
+         * Called when slice is updated.
+         *
+         * @param s The updated slice.
+         * @see #registerSliceCallback
+         */
+        void onSliceUpdated(@NonNull Slice s);
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceManagerBase.java b/slices/view/src/main/java/androidx/app/slice/SliceManagerBase.java
new file mode 100644
index 0000000..8731658
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/SliceManagerBase.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static androidx.app.slice.widget.SliceLiveData.SUPPORTED_SPECS;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.util.ArrayMap;
+import android.util.Pair;
+
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public abstract class SliceManagerBase extends SliceManager {
+    private final ArrayMap<Pair<Uri, SliceCallback>, SliceListenerImpl> mListenerLookup =
+            new ArrayMap<>();
+    protected final Context mContext;
+
+    SliceManagerBase(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback) {
+        final Handler h = new Handler(Looper.getMainLooper());
+        registerSliceCallback(uri, new Executor() {
+            @Override
+            public void execute(@NonNull Runnable command) {
+                h.post(command);
+            }
+        }, callback);
+    }
+
+    @Override
+    public void registerSliceCallback(@NonNull Uri uri, @NonNull Executor executor,
+            @NonNull SliceCallback callback) {
+        pinSlice(uri);
+        getListener(uri, callback, new SliceListenerImpl(uri, executor, callback)).startListening();
+    }
+
+    @Override
+    public void unregisterSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback) {
+        unpinSlice(uri);
+        SliceListenerImpl impl = mListenerLookup.remove(new Pair<>(uri, callback));
+        if (impl != null) impl.stopListening();
+    }
+
+    private SliceListenerImpl getListener(Uri uri, SliceCallback callback,
+            SliceListenerImpl listener) {
+        Pair<Uri, SliceCallback> key = new Pair<>(uri, callback);
+        if (mListenerLookup.containsKey(key)) {
+            mListenerLookup.get(key).stopListening();
+        }
+        mListenerLookup.put(key, listener);
+        return listener;
+    }
+
+    private class SliceListenerImpl {
+
+        private Uri mUri;
+        private final Executor mExecutor;
+        private final SliceCallback mCallback;
+
+        SliceListenerImpl(Uri uri, Executor executor, SliceCallback callback) {
+            mUri = uri;
+            mExecutor = executor;
+            mCallback = callback;
+        }
+
+        void startListening() {
+            mContext.getContentResolver().registerContentObserver(mUri, true, mObserver);
+        }
+
+        void stopListening() {
+            mContext.getContentResolver().unregisterContentObserver(mObserver);
+        }
+
+        private final Runnable mUpdateSlice = new Runnable() {
+            @Override
+            public void run() {
+                final Slice s = Slice.bindSlice(mContext, mUri, SUPPORTED_SPECS);
+                mExecutor.execute(new Runnable() {
+                    @Override
+                    public void run() {
+                        mCallback.onSliceUpdated(s);
+                    }
+                });
+            }
+        };
+
+        private final ContentObserver mObserver = new ContentObserver(
+                new Handler(Looper.getMainLooper())) {
+            @Override
+            public void onChange(boolean selfChange) {
+                AsyncTask.execute(mUpdateSlice);
+            }
+        };
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceManagerCompat.java b/slices/view/src/main/java/androidx/app/slice/SliceManagerCompat.java
new file mode 100644
index 0000000..1f301b7
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/SliceManagerCompat.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static androidx.app.slice.widget.SliceLiveData.SUPPORTED_SPECS;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import java.util.List;
+
+import androidx.app.slice.compat.SliceProviderCompat;
+import androidx.app.slice.widget.SliceLiveData;
+
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class SliceManagerCompat extends SliceManagerBase {
+
+    SliceManagerCompat(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void pinSlice(@NonNull Uri uri) {
+        SliceProviderCompat.pinSlice(mContext, uri, SliceLiveData.SUPPORTED_SPECS);
+    }
+
+    @Override
+    public void unpinSlice(@NonNull Uri uri) {
+        SliceProviderCompat.unpinSlice(mContext, uri, SliceLiveData.SUPPORTED_SPECS);
+    }
+
+    @Override
+    public @NonNull List<SliceSpec> getPinnedSpecs(@NonNull Uri uri) {
+        return SliceProviderCompat.getPinnedSpecs(mContext, uri);
+    }
+
+    @Nullable
+    @Override
+    public Slice bindSlice(@NonNull Uri uri) {
+        return SliceProviderCompat.bindSlice(mContext, uri, SUPPORTED_SPECS);
+    }
+
+    @Nullable
+    @Override
+    public Slice bindSlice(@NonNull Intent intent) {
+        return SliceProviderCompat.bindSlice(mContext, intent, SUPPORTED_SPECS);
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceManagerWrapper.java b/slices/view/src/main/java/androidx/app/slice/SliceManagerWrapper.java
new file mode 100644
index 0000000..a60f418
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/SliceManagerWrapper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static androidx.app.slice.SliceConvert.unwrap;
+import static androidx.app.slice.widget.SliceLiveData.SUPPORTED_SPECS;
+
+import android.app.slice.SliceSpec;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@RequiresApi(api = 28)
+class SliceManagerWrapper extends SliceManagerBase {
+
+    private final android.app.slice.SliceManager mManager;
+    private final List<SliceSpec> mSpecs;
+
+    SliceManagerWrapper(Context context) {
+        this(context, context.getSystemService(android.app.slice.SliceManager.class));
+    }
+
+    SliceManagerWrapper(Context context, android.app.slice.SliceManager manager) {
+        super(context);
+        mManager = manager;
+        mSpecs = unwrap(SUPPORTED_SPECS);
+    }
+
+    @Override
+    public void pinSlice(@NonNull Uri uri) {
+        mManager.pinSlice(uri, mSpecs);
+    }
+
+    @Override
+    public void unpinSlice(@NonNull Uri uri) {
+        mManager.unpinSlice(uri);
+    }
+
+    @Override
+    public @NonNull List<androidx.app.slice.SliceSpec> getPinnedSpecs(@NonNull Uri uri) {
+        return SliceConvert.wrap(mManager.getPinnedSpecs(uri));
+    }
+
+    @Nullable
+    @Override
+    public androidx.app.slice.Slice bindSlice(@NonNull Uri uri) {
+        return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
+                mContext.getContentResolver(), uri, unwrap(SUPPORTED_SPECS)));
+    }
+
+    @Nullable
+    @Override
+    public androidx.app.slice.Slice bindSlice(@NonNull Intent intent) {
+        return SliceConvert.wrap(android.app.slice.Slice.bindSlice(
+                mContext, intent, unwrap(SUPPORTED_SPECS)));
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceUtils.java b/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
new file mode 100644
index 0000000..117aee3
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/SliceUtils.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_PARTIAL;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+
+import android.content.Context;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import androidx.app.slice.core.SliceQuery;
+
+/**
+ * Utilities for dealing with slices.
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class SliceUtils {
+
+    private SliceUtils() {
+    }
+
+    /**
+     * Serialize a slice to an OutputStream.
+     * <p>
+     * The slice can later be read into slice form again with {@link #parseSlice}.
+     * Some slice types cannot be serialized, their handling is controlled by
+     * {@link SerializeOptions}.
+     *
+     * @param s The slice to serialize.
+     * @param context Context used to load any resources in the slice.
+     * @param output The output of the serialization.
+     * @param encoding The encoding to use for serialization.
+     * @param options Options defining how to handle non-serializable items.
+     */
+    public static void serializeSlice(@NonNull Slice s, @NonNull Context context,
+            @NonNull OutputStream output, @NonNull String encoding,
+            @NonNull SerializeOptions options) throws IOException {
+        SliceXml.serializeSlice(s, context, output, encoding, options);
+    }
+
+    /**
+     * Parse a slice that has been previously serialized.
+     * <p>
+     * Parses a slice that was serialized with {@link #serializeSlice}.
+     *
+     * @param input The input stream to read from.
+     * @param encoding The encoding to read as.
+     */
+    public static @NonNull Slice parseSlice(@NonNull InputStream input, @NonNull String encoding)
+            throws IOException {
+        return SliceXml.parseSlice(input, encoding);
+    }
+
+    /**
+     * Holds options for how to handle SliceItems that cannot be serialized.
+     */
+    public static class SerializeOptions {
+        /**
+         * Constant indicating that the an {@link IllegalArgumentException} should be thrown
+         * when this format is encountered.
+         */
+        public static final int MODE_THROW = 0;
+        /**
+         * Constant indicating that the SliceItem should be removed when this format is encountered.
+         */
+        public static final int MODE_REMOVE = 1;
+        /**
+         * Constant indicating that the SliceItem should be serialized as much as possible.
+         * <p>
+         * For images this means it will be replaced with an empty image. For actions, the
+         * action will be removed but the content of the action will be serialized.
+         */
+        public static final int MODE_DISABLE = 2;
+
+        @IntDef({MODE_THROW, MODE_REMOVE, MODE_DISABLE})
+        @interface FormatMode {
+        }
+
+        private int mActionMode = MODE_THROW;
+        private int mImageMode = MODE_THROW;
+
+        /**
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY)
+        public void checkThrow(String format) {
+            switch (format) {
+                case FORMAT_ACTION:
+                case FORMAT_REMOTE_INPUT:
+                    if (mActionMode != MODE_THROW) return;
+                    break;
+                case FORMAT_IMAGE:
+                    if (mImageMode != MODE_THROW) return;
+                    break;
+                default:
+                    return;
+            }
+            throw new IllegalArgumentException(format + " cannot be serialized");
+        }
+
+        /**
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY)
+        public @FormatMode int getActionMode() {
+            return mActionMode;
+        }
+
+        /**
+         * @hide
+         */
+        @RestrictTo(RestrictTo.Scope.LIBRARY)
+        public @FormatMode int getImageMode() {
+            return mImageMode;
+        }
+
+        /**
+         * Sets how {@link android.app.slice.SliceItem#FORMAT_ACTION} items should be handled.
+         *
+         * The default mode is {@link #MODE_THROW}.
+         * @param mode The desired mode.
+         */
+        public SerializeOptions setActionMode(@FormatMode int mode) {
+            mActionMode = mode;
+            return this;
+        }
+
+        /**
+         * Sets how {@link android.app.slice.SliceItem#FORMAT_IMAGE} items should be handled.
+         *
+         * The default mode is {@link #MODE_THROW}.
+         * @param mode The desired mode.
+         */
+        public SerializeOptions setImageMode(@FormatMode int mode) {
+            mImageMode = mode;
+            return this;
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+            LOADING_ALL, LOADING_PARTIAL, LOADING_COMPLETE
+    })
+    public @interface SliceLoadingState{}
+
+    /**
+     * Indicates this slice is empty and waiting for content to be loaded.
+     */
+    public static final int LOADING_ALL = 0;
+    /**
+     * Indicates this slice has some content but is waiting for other content to be loaded.
+     */
+    public static final int LOADING_PARTIAL = 1;
+    /**
+     * Indicates this slice has fully loaded and is not waiting for other content.
+     */
+    public static final int LOADING_COMPLETE = 2;
+
+    /**
+     * @return the current loading state of the provided {@link Slice}.
+     *
+     * @see #LOADING_ALL
+     * @see #LOADING_PARTIAL
+     * @see #LOADING_COMPLETE
+     */
+    public static int getLoadingState(@NonNull Slice slice) {
+        // Check loading state
+        boolean hasHintPartial =
+                SliceQuery.find(slice, null, HINT_PARTIAL, null) != null;
+        if (hasHintPartial && slice.getItems().size() == 0) {
+            // Empty slice
+            return LOADING_ALL;
+        } else if (hasHintPartial) {
+            // Slice with specific content to load
+            return LOADING_PARTIAL;
+        } else {
+            // Full slice
+            return LOADING_COMPLETE;
+        }
+    }
+
+    /**
+     * @return the group of actions associated with the provided slice, if they exist.
+     */
+    @Nullable
+    public static List<SliceItem> getSliceActions(@NonNull Slice slice) {
+        SliceItem actionGroup = SliceQuery.find(slice, FORMAT_SLICE, HINT_ACTIONS, null);
+        String[] hints = new String[] {HINT_ACTIONS, HINT_SHORTCUT};
+        return (actionGroup != null)
+                ? SliceQuery.findAll(actionGroup, FORMAT_SLICE, hints, null)
+                : null;
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/SliceXml.java b/slices/view/src/main/java/androidx/app/slice/SliceXml.java
new file mode 100644
index 0000000..2500ef6
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/SliceXml.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice;
+
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.support.annotation.RestrictTo;
+import android.text.Html;
+import android.text.Spanned;
+import android.text.TextUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+class SliceXml {
+
+    private static final String NAMESPACE = null;
+
+    private static final String TAG_SLICE = "slice";
+    private static final String TAG_ITEM = "item";
+
+    private static final String ATTR_URI = "uri";
+    private static final String ATTR_FORMAT = "format";
+    private static final String ATTR_SUBTYPE = "subtype";
+    private static final String ATTR_HINTS = "hints";
+
+    public static Slice parseSlice(InputStream input, String encoding) throws IOException {
+        try {
+            XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
+            parser.setInput(input, encoding);
+
+            int outerDepth = parser.getDepth();
+            int type;
+            Slice s = null;
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type != START_TAG) {
+                    continue;
+                }
+                s = parseSlice(parser);
+            }
+            return s;
+        } catch (XmlPullParserException e) {
+            throw new IOException("Unable to init XML Serialization", e);
+        }
+    }
+
+    @SuppressLint("WrongConstant")
+    private static Slice parseSlice(XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        if (!TAG_SLICE.equals(parser.getName())) {
+            throw new IOException("Unexpected tag " + parser.getName());
+        }
+        int outerDepth = parser.getDepth();
+        int type;
+        String uri = parser.getAttributeValue(NAMESPACE, ATTR_URI);
+        Slice.Builder b = new Slice.Builder(Uri.parse(uri));
+        String[] hints = hints(parser.getAttributeValue(NAMESPACE, ATTR_HINTS));
+        b.addHints(hints);
+
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == START_TAG && TAG_ITEM.equals(parser.getName())) {
+                parseItem(b, parser);
+            }
+        }
+        return b.build();
+    }
+
+    @SuppressLint("WrongConstant")
+    private static void parseItem(Slice.Builder b, XmlPullParser parser)
+            throws IOException, XmlPullParserException {
+        int type;
+        int outerDepth = parser.getDepth();
+        String format = parser.getAttributeValue(NAMESPACE, ATTR_FORMAT);
+        String subtype = parser.getAttributeValue(NAMESPACE, ATTR_SUBTYPE);
+        String hintStr = parser.getAttributeValue(NAMESPACE, ATTR_HINTS);
+        String[] hints = hints(hintStr);
+        String v;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == TEXT) {
+                switch (format) {
+                    case android.app.slice.SliceItem.FORMAT_REMOTE_INPUT:
+                        // Nothing for now.
+                        break;
+                    case android.app.slice.SliceItem.FORMAT_IMAGE:
+                        v = parser.getText();
+                        if (!TextUtils.isEmpty(v)) {
+                            if (android.os.Build.VERSION.SDK_INT
+                                    >= android.os.Build.VERSION_CODES.M) {
+                                String[] split = v.split(",");
+                                int w = Integer.parseInt(split[0]);
+                                int h = Integer.parseInt(split[1]);
+                                Bitmap image = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
+                                b.addIcon(Icon.createWithBitmap(image), subtype, hints);
+                            }
+                        }
+                        break;
+                    case android.app.slice.SliceItem.FORMAT_INT:
+                        v = parser.getText();
+                        b.addInt(Integer.parseInt(v), subtype, hints);
+                        break;
+                    case android.app.slice.SliceItem.FORMAT_TEXT:
+                        v = parser.getText();
+                        b.addText(Html.fromHtml(v), subtype, hints);
+                        break;
+                    case android.app.slice.SliceItem.FORMAT_TIMESTAMP:
+                        v = parser.getText();
+                        b.addTimestamp(Long.parseLong(v), subtype, hints);
+                        break;
+                    default:
+                        throw new IllegalArgumentException("Unrecognized format " + format);
+                }
+            } else if (type == START_TAG && TAG_SLICE.equals(parser.getName())) {
+                b.addSubSlice(parseSlice(parser), subtype);
+            }
+        }
+    }
+
+    private static String[] hints(String hintStr) {
+        return TextUtils.isEmpty(hintStr) ? new String[0] : hintStr.split(",");
+    }
+
+    public static void serializeSlice(Slice s, Context context, OutputStream output,
+            String encoding, SliceUtils.SerializeOptions options) throws IOException {
+        try {
+            XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer();
+            serializer.setOutput(output, encoding);
+            serializer.startDocument(encoding, null);
+
+            serialize(s, context, options, serializer);
+
+            serializer.endDocument();
+            serializer.flush();
+        } catch (XmlPullParserException e) {
+            throw new IOException("Unable to init XML Serialization", e);
+        }
+    }
+
+    private static void serialize(Slice s, Context context, SliceUtils.SerializeOptions options,
+            XmlSerializer serializer) throws IOException {
+        serializer.startTag(NAMESPACE, TAG_SLICE);
+        serializer.attribute(NAMESPACE, ATTR_URI, s.getUri().toString());
+        if (!s.getHints().isEmpty()) {
+            serializer.attribute(NAMESPACE, ATTR_HINTS, hintStr(s.getHints()));
+        }
+        for (SliceItem item : s.getItems()) {
+            serialize(item, context, options, serializer);
+        }
+
+        serializer.endTag(NAMESPACE, TAG_SLICE);
+    }
+
+    private static void serialize(SliceItem item, Context context,
+            SliceUtils.SerializeOptions options, XmlSerializer serializer) throws IOException {
+        String format = item.getFormat();
+        options.checkThrow(format);
+
+        serializer.startTag(NAMESPACE, TAG_ITEM);
+        serializer.attribute(NAMESPACE, ATTR_FORMAT, format);
+        if (item.getSubType() != null) {
+            serializer.attribute(NAMESPACE, ATTR_SUBTYPE, item.getSubType());
+        }
+        if (!item.getHints().isEmpty()) {
+            serializer.attribute(NAMESPACE, ATTR_HINTS, hintStr(item.getHints()));
+        }
+
+        switch (format) {
+            case android.app.slice.SliceItem.FORMAT_ACTION:
+                if (options.getActionMode() == SliceUtils.SerializeOptions.MODE_DISABLE) {
+                    serialize(item.getSlice(), context, options, serializer);
+                }
+                break;
+            case android.app.slice.SliceItem.FORMAT_REMOTE_INPUT:
+                // Nothing for now.
+                break;
+            case android.app.slice.SliceItem.FORMAT_IMAGE:
+                if (options.getImageMode() == SliceUtils.SerializeOptions.MODE_DISABLE) {
+                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
+                        Drawable d = item.getIcon().loadDrawable(context);
+                        serializer.text(String.format("%d,%d",
+                                d.getIntrinsicWidth(), d.getIntrinsicHeight()));
+                    }
+                }
+                break;
+            case android.app.slice.SliceItem.FORMAT_INT:
+                serializer.text(String.valueOf(item.getInt()));
+                break;
+            case android.app.slice.SliceItem.FORMAT_SLICE:
+                serialize(item.getSlice(), context, options, serializer);
+                break;
+            case android.app.slice.SliceItem.FORMAT_TEXT:
+                if (item.getText() instanceof Spanned) {
+                    serializer.text(Html.toHtml((Spanned) item.getText()));
+                } else {
+                    serializer.text(String.valueOf(item.getText()));
+                }
+                break;
+            case android.app.slice.SliceItem.FORMAT_TIMESTAMP:
+                serializer.text(String.valueOf(item.getTimestamp()));
+                break;
+            default:
+                throw new IllegalArgumentException("Unrecognized format " + format);
+        }
+        serializer.endTag(NAMESPACE, TAG_ITEM);
+    }
+
+    private static String hintStr(List<String> hints) {
+        return TextUtils.join(",", hints);
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ActionContent.java b/slices/view/src/main/java/androidx/app/slice/widget/ActionContent.java
new file mode 100644
index 0000000..ba5c70c
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ActionContent.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.Slice.SUBTYPE_CONTENT_DESCRIPTION;
+import static android.app.slice.Slice.SUBTYPE_PRIORITY;
+import static android.app.slice.Slice.SUBTYPE_TOGGLE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+
+/**
+ * Extracts information required to present an action button from a slice.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class ActionContent {
+    private SliceItem mSliceItem;
+    private SliceItem mIconItem;
+    private SliceItem mActionItem;
+    private SliceItem mTitleItem;
+    private SliceItem mContentDescItem;
+    private boolean mIsToggle;
+    private boolean mIsChecked;
+    private int mPriority;
+
+    public ActionContent(@NonNull SliceItem slice) {
+        populate(slice);
+    }
+
+    /**
+     * @return whether this slice is a valid action.
+     */
+    private boolean populate(@NonNull SliceItem slice) {
+        mSliceItem = slice;
+        if (slice.hasHint(HINT_SHORTCUT) && FORMAT_SLICE.equals(slice.getFormat())) {
+            mActionItem = SliceQuery.find(slice, FORMAT_ACTION);
+            if (mActionItem == null) {
+                // Can't have action slice without action
+                return false;
+            }
+            mIconItem = SliceQuery.find(mActionItem.getSlice(), FORMAT_IMAGE);
+            mTitleItem = SliceQuery.find(mActionItem.getSlice(), FORMAT_TEXT, HINT_TITLE,
+                    null /* nonHints */);
+            mContentDescItem = SliceQuery.findSubtype(mActionItem.getSlice(), FORMAT_TEXT,
+                    SUBTYPE_CONTENT_DESCRIPTION);
+            mIsToggle = SUBTYPE_TOGGLE.equals(mActionItem.getSubType());
+            if (mIsToggle) {
+                mIsChecked = mActionItem.hasHint(HINT_SELECTED);
+            }
+            SliceItem priority = SliceQuery.findSubtype(mActionItem.getSlice(), FORMAT_INT,
+                    SUBTYPE_PRIORITY);
+            mPriority = priority != null ? priority.getInt() : -1;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return the SliceItem used to construct this ActionContent.
+     */
+    @NonNull
+    public SliceItem getSliceItem() {
+        return mSliceItem;
+    }
+
+    /**
+     * @return the pending intent associated with this action.
+     */
+    @Nullable
+    public SliceItem getActionItem() {
+        return mActionItem;
+    }
+
+    /**
+     * @return the icon associated with this action.
+     */
+    @Nullable
+    public SliceItem getIconItem() {
+        return mIconItem;
+    }
+
+    /**
+     * @return the title associated with this action.
+     */
+    @Nullable
+    public SliceItem getTitleItem() {
+        return mTitleItem;
+    }
+
+    /**
+     * @return the subtitle associated with this action.
+     */
+    @Nullable
+    public SliceItem getContentDescriptionItem() {
+        return mContentDescItem;
+    }
+
+    /**
+     * @return the priority associated with this action, if it exists.
+     */
+    public int getPriority() {
+        return mPriority;
+    }
+
+    /**
+     * @return Whether this action is toggleable.
+     */
+    public boolean isToggle() {
+        return mIsToggle;
+    }
+
+    /**
+     * @return Whether this action represents a custom toggle.
+     */
+    public boolean isCustomToggle() {
+        return mIconItem != null && mIsToggle;
+    }
+
+    /**
+     * @return Whether this action is 'checked' or not (i.e. if toggle is on).
+     */
+    public boolean isChecked() {
+        return mIsChecked;
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java b/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java
new file mode 100644
index 0000000..f517061
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ActionRow.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
+
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.app.RemoteInput;
+import android.app.slice.Slice;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewParent;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.List;
+import java.util.function.Consumer;
+
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(24)
+public class ActionRow extends FrameLayout {
+
+    private static final int MAX_ACTIONS = 5;
+    private final int mSize;
+    private final int mIconPadding;
+    private final LinearLayout mActionsGroup;
+    private final boolean mFullActions;
+    private int mColor = Color.BLACK;
+
+    public ActionRow(Context context, boolean fullActions) {
+        super(context);
+        mFullActions = fullActions;
+        mSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48,
+                context.getResources().getDisplayMetrics());
+        mIconPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 12,
+                context.getResources().getDisplayMetrics());
+        mActionsGroup = new LinearLayout(context);
+        mActionsGroup.setOrientation(LinearLayout.HORIZONTAL);
+        mActionsGroup.setLayoutParams(
+                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+        addView(mActionsGroup);
+    }
+
+    private void setColor(int color) {
+        mColor = color;
+        for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
+            View view = mActionsGroup.getChildAt(i);
+            SliceItem item = (SliceItem) view.getTag();
+            boolean tint = !item.hasHint(HINT_NO_TINT);
+            if (tint) {
+                ((ImageView) view).setImageTintList(ColorStateList.valueOf(mColor));
+            }
+        }
+    }
+
+    private ImageView addAction(Icon icon, boolean allowTint, SliceItem image) {
+        ImageView imageView = new ImageView(getContext());
+        imageView.setPadding(mIconPadding, mIconPadding, mIconPadding, mIconPadding);
+        imageView.setScaleType(ScaleType.FIT_CENTER);
+        imageView.setImageIcon(icon);
+        if (allowTint) {
+            imageView.setImageTintList(ColorStateList.valueOf(mColor));
+        }
+        imageView.setBackground(SliceViewUtil.getDrawable(getContext(),
+                android.R.attr.selectableItemBackground));
+        imageView.setTag(image);
+        addAction(imageView);
+        return imageView;
+    }
+
+    /**
+     * Set the actions and color for this action row.
+     */
+    public void setActions(@NonNull List<SliceItem> actions, int color) {
+        removeAllViews();
+        mActionsGroup.removeAllViews();
+        addView(mActionsGroup);
+        if (color != -1) {
+            setColor(color);
+        }
+        actions.forEach(new Consumer<SliceItem>() {
+            @Override
+            public void accept(final SliceItem action) {
+                if (mActionsGroup.getChildCount() >= MAX_ACTIONS) {
+                    return;
+                }
+                final SliceItem input = SliceQuery.find(action, FORMAT_REMOTE_INPUT);
+                final SliceItem image = SliceQuery.find(action, FORMAT_IMAGE);
+                if (input != null && image != null
+                        && input.getRemoteInput().getAllowFreeFormInput()) {
+                    boolean tint = !image.hasHint(HINT_NO_TINT);
+                    addAction(image.getIcon(), tint, image).setOnClickListener(
+                            new OnClickListener() {
+                                @Override
+                                public void onClick(View v) {
+                                    handleRemoteInputClick(v, action.getAction(),
+                                            input.getRemoteInput());
+                                }
+                            });
+                    createRemoteInputView(mColor, getContext());
+                } else if (action.hasHint(Slice.HINT_SHORTCUT)) {
+                    final ActionContent ac = new ActionContent(action);
+                    SliceItem iconItem = ac.getIconItem();
+                    if (iconItem != null && ac.getActionItem() != null) {
+                        boolean tint = !iconItem.hasHint(HINT_NO_TINT);
+                        addAction(iconItem.getIcon(), tint, image).setOnClickListener(
+                                new OnClickListener() {
+                                    @Override
+                                    public void onClick(View v) {
+                                        try {
+                                            ac.getActionItem().getAction().send();
+                                        } catch (CanceledException e) {
+                                            e.printStackTrace();
+                                        }
+                                    }
+                                });
+                    }
+                }
+            }
+        });
+        setVisibility(getChildCount() != 0 ? View.VISIBLE : View.GONE);
+    }
+
+    private void addAction(View child) {
+        mActionsGroup.addView(child, new LinearLayout.LayoutParams(mSize, mSize, 1));
+    }
+
+    private void createRemoteInputView(int color, Context context) {
+        View riv = RemoteInputView.inflate(context, this);
+        riv.setVisibility(View.INVISIBLE);
+        addView(riv, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+        riv.setBackgroundColor(color);
+    }
+
+    private boolean handleRemoteInputClick(View view, PendingIntent pendingIntent,
+            RemoteInput input) {
+        if (input == null) {
+            return false;
+        }
+
+        ViewParent p = view.getParent().getParent();
+        RemoteInputView riv = null;
+        while (p != null) {
+            if (p instanceof View) {
+                View pv = (View) p;
+                riv = findRemoteInputView(pv);
+                if (riv != null) {
+                    break;
+                }
+            }
+            p = p.getParent();
+        }
+        if (riv == null) {
+            return false;
+        }
+
+        int width = view.getWidth();
+        if (view instanceof TextView) {
+            // Center the reveal on the text which might be off-center from the TextView
+            TextView tv = (TextView) view;
+            if (tv.getLayout() != null) {
+                int innerWidth = (int) tv.getLayout().getLineWidth(0);
+                innerWidth += tv.getCompoundPaddingLeft() + tv.getCompoundPaddingRight();
+                width = Math.min(width, innerWidth);
+            }
+        }
+        int cx = view.getLeft() + width / 2;
+        int cy = view.getTop() + view.getHeight() / 2;
+        int w = riv.getWidth();
+        int h = riv.getHeight();
+        int r = Math.max(
+                Math.max(cx + cy, cx + (h - cy)),
+                Math.max((w - cx) + cy, (w - cx) + (h - cy)));
+
+        riv.setRevealParameters(cx, cy, r);
+        riv.setPendingIntent(pendingIntent);
+        riv.setRemoteInput(new RemoteInput[] {
+                input
+        }, input);
+        riv.focusAnimated();
+        return true;
+    }
+
+    private RemoteInputView findRemoteInputView(View v) {
+        if (v == null) {
+            return null;
+        }
+        return (RemoteInputView) v.findViewWithTag(RemoteInputView.VIEW_TAG);
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/EventInfo.java b/slices/view/src/main/java/androidx/app/slice/widget/EventInfo.java
new file mode 100644
index 0000000..d45a34d
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/EventInfo.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import android.support.annotation.IntDef;
+import android.support.annotation.RestrictTo;
+
+/**
+ * Represents information associated with a logged event on {@link SliceView}.
+ */
+public class EventInfo {
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+            ROW_TYPE_SHORTCUT, ROW_TYPE_LIST, ROW_TYPE_GRID, ROW_TYPE_MESSAGING
+    })
+    public @interface SliceRowType {}
+
+    /**
+     * Indicates the slice is represented as a shortcut.
+     */
+    public static final int ROW_TYPE_SHORTCUT = -1;
+    /**
+     * Indicates the row is represented in a list template.
+     */
+    public static final int ROW_TYPE_LIST = 0;
+    /**
+     * Indicates the row is represented in a grid template.
+     */
+    public static final int ROW_TYPE_GRID = 1;
+    /**
+     * Indicates the row is represented as a messaging template.
+     */
+    public static final int ROW_TYPE_MESSAGING = 2;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+            ACTION_TYPE_TOGGLE, ACTION_TYPE_BUTTON, ACTION_TYPE_SLIDER, ACTION_TYPE_CONTENT
+    })
+    public @interface SliceActionType{}
+
+    /**
+     * Indicates the event was an interaction with a toggle. Check {@link EventInfo#state} to
+     * see the new state of the toggle.
+     */
+    public static final int ACTION_TYPE_TOGGLE = 0;
+    /**
+     * Indicates the event was an interaction with a button. Check {@link EventInfo#actionPosition}
+     * to see where on the card the button is placed.
+     */
+    public static final int ACTION_TYPE_BUTTON = 1;
+    /**
+     * Indicates the event was an interaction with a slider. Check {@link EventInfo#state} to
+     * see the new state of the slider.
+     */
+    public static final int ACTION_TYPE_SLIDER = 2;
+    /**
+     * Indicates the event was a tap on the entire row.
+     */
+    public static final int ACTION_TYPE_CONTENT = 3;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+            POSITION_START, POSITION_END, POSITION_CELL
+    })
+    public @interface SliceButtonPosition{}
+
+    /**
+     * Indicates the event was an interaction with a button positioned at the start of the row.
+     */
+    public static final int POSITION_START = 0;
+    /**
+     * Indicates the event was an interaction with a button positioned at the end of the row,
+     * potentially grouped with other buttons.
+     */
+    public static final int POSITION_END = 1;
+    /**
+     * Indicates the event was an interaction with a button positioned in a grid cell.
+     */
+    public static final int POSITION_CELL = 2;
+
+    /**
+     * Indicates the state of a toggle is off.
+     */
+    public static final int STATE_OFF = 0;
+    /**
+     * Indicates the state of a toggle is on.
+     */
+    public static final int STATE_ON = 1;
+
+    /**
+     * The display mode of the slice being interacted with.
+     */
+    public @SliceView.SliceMode int sliceMode;
+    /**
+     * The type of action that occurred.
+     */
+    public @SliceActionType int actionType;
+    /**
+     * The template type of the row that was interacted with in the slice.
+     */
+    public @SliceRowType int rowTemplateType;
+    /**
+     * Index of the row that was interacted with in the slice.
+     */
+    public int rowIndex;
+    /**
+     * If multiple buttons are presented in this {@link #actionPosition} on the row, then this is
+     * the index of that button that was interacted with. For total number of actions
+     * see {@link #actionCount}.
+     *
+     * <p>If the {@link #actionPosition} is {@link #POSITION_CELL} the button is a cell within
+     * a grid, and this index would represent the cell position.</p>
+     * <p>If the {@link #actionPosition} is {@link #POSITION_END} there might be other buttons
+     * in the end position, and this index would represent the position.</p>
+     */
+    public int actionIndex;
+    /**
+     * Total number of actions available in this row of the slice.
+     *
+     * <p>If the {@link #actionPosition} is {@link #POSITION_CELL} the button is a cell within
+     * a grid row, and this is the number of cells in the row.</p>
+     * <p>If the {@link #actionPosition} is {@link #POSITION_END} this is the number of buttons
+     * in the end position of this row.</p>
+     */
+    public int actionCount;
+    /**
+     * Position of the button on the template.
+     *
+     * {@link #POSITION_START}
+     * {@link #POSITION_END}
+     * {@link #POSITION_CELL}
+     */
+    public @SliceButtonPosition int actionPosition;
+    /**
+     * Represents the state after the event or -1 if not applicable for the event type.
+     *
+     * <p>For {@link #ACTION_TYPE_TOGGLE} events, the state will be either {@link #STATE_OFF}
+     * or {@link #STATE_ON}.</p>
+     * <p>For {@link #ACTION_TYPE_SLIDER} events, the state will be a number representing
+     * the new position of the slider.</p>
+     */
+    public int state;
+
+    /**
+     * Constructs an event info object with the required information for an event.
+     *
+     * @param sliceMode The display mode of the slice interacted with.
+     * @param actionType The type of action this event represents.
+     * @param rowTemplateType The template type of the row interacted with.
+     * @param rowIndex The index of the row that was interacted with in the slice.
+     */
+    public EventInfo(@SliceView.SliceMode int sliceMode, @SliceActionType int actionType,
+            @SliceRowType int rowTemplateType, int rowIndex) {
+        this.sliceMode = sliceMode;
+        this.actionType = actionType;
+        this.rowTemplateType = rowTemplateType;
+        this.rowIndex = rowIndex;
+
+        this.actionPosition = -1;
+        this.actionIndex = -1;
+        this.actionCount = -1;
+        this.state = -1;
+    }
+
+    /**
+     * Sets positional information for the event.
+     *
+     * @param actionPosition The position of the button on the template.
+     * @param actionIndex The index of that button that was interacted with.
+     * @param actionCount The number of actions available in this group of buttons on the slice.
+     */
+    public void setPosition(@SliceButtonPosition int actionPosition, int actionIndex,
+            int actionCount) {
+        this.actionPosition = actionPosition;
+        this.actionIndex = actionIndex;
+        this.actionCount = actionCount;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("mode=").append(SliceView.modeToString(sliceMode));
+        sb.append(", actionType=").append(actionToString(actionType));
+        sb.append(", rowTemplateType=").append(rowTypeToString(rowTemplateType));
+        sb.append(", rowIndex=").append(rowIndex);
+        sb.append(", actionPosition=").append(positionToString(actionPosition));
+        sb.append(", actionIndex=").append(actionIndex);
+        sb.append(", actionCount=").append(actionCount);
+        sb.append(", state=").append(state);
+        return sb.toString();
+    }
+
+    /**
+     * @return String representation of the provided position.
+     */
+    private static String positionToString(@SliceButtonPosition int position) {
+        switch (position) {
+            case POSITION_START:
+                return "START";
+            case POSITION_END:
+                return "END";
+            case POSITION_CELL:
+                return "CELL";
+            default:
+                return "unknown position: " + position;
+        }
+    }
+
+    /**
+     * @return String representation of the provided action.
+     */
+    private static String actionToString(@SliceActionType int action) {
+        switch (action) {
+            case ACTION_TYPE_TOGGLE:
+                return "TOGGLE";
+            case ACTION_TYPE_BUTTON:
+                return "BUTTON";
+            case ACTION_TYPE_SLIDER:
+                return "SLIDER";
+            case ACTION_TYPE_CONTENT:
+                return "CONTENT";
+            default:
+                return "unknown action: " + action;
+        }
+    }
+
+    /**
+     * @return String representation of the provided row template type.
+     */
+    private static String rowTypeToString(@SliceRowType int type) {
+        switch (type) {
+            case ROW_TYPE_LIST:
+                return "LIST";
+            case ROW_TYPE_GRID:
+                return "GRID";
+            case ROW_TYPE_MESSAGING:
+                return "MESSAGING";
+            case ROW_TYPE_SHORTCUT:
+                return "SHORTCUT";
+            default:
+                return "unknown row type: " + type;
+        }
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java b/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java
new file mode 100644
index 0000000..41a9640
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridContent.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+
+/**
+ * Extracts information required to present content in a grid format from a slice.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class GridContent {
+
+    private boolean mAllImages;
+    private SliceItem mColorItem;
+    private SliceItem mPrimaryAction;
+    private ArrayList<CellContent> mGridContent = new ArrayList<>();
+    private int mMaxCellLineCount;
+    private boolean mHasImage;
+
+    public GridContent(SliceItem gridItem) {
+        populate(gridItem);
+    }
+
+    private void reset() {
+        mColorItem = null;
+        mMaxCellLineCount = 0;
+        mHasImage = false;
+        mGridContent.clear();
+    }
+
+    /**
+     * @return whether this grid has content that is valid to display.
+     */
+    public boolean populate(SliceItem gridItem) {
+        reset();
+        mColorItem = SliceQuery.findSubtype(gridItem, FORMAT_INT, SUBTYPE_COLOR);
+        String[] hints = new String[] {HINT_SHORTCUT, HINT_TITLE};
+        mPrimaryAction = SliceQuery.find(gridItem, FORMAT_SLICE, hints,
+                new String[] {HINT_ACTIONS} /* nonHints */);
+        mAllImages = true;
+        if (FORMAT_SLICE.equals(gridItem.getFormat())) {
+            List<SliceItem> items = gridItem.getSlice().getItems();
+            items = filterInvalidItems(items);
+            // Check if it it's only one item that is a slice
+            if (items.size() == 1 && items.get(0).getFormat().equals(FORMAT_SLICE)) {
+                items = items.get(0).getSlice().getItems();
+            }
+            for (int i = 0; i < items.size(); i++) {
+                SliceItem item = items.get(i);
+                CellContent cc = new CellContent(item);
+                processContent(cc);
+            }
+        } else {
+            CellContent cc = new CellContent(gridItem);
+            processContent(cc);
+        }
+        return isValid();
+    }
+
+    private void processContent(CellContent cc) {
+        if (cc.isValid()) {
+            mGridContent.add(cc);
+            if (!cc.isImageOnly()) {
+                mAllImages = false;
+            }
+            mMaxCellLineCount = Math.max(mMaxCellLineCount, cc.getTextCount());
+            mHasImage |= cc.hasImage();
+        }
+    }
+
+    /**
+     * @return the list of cell content for this grid.
+     */
+    @NonNull
+    public ArrayList<CellContent> getGridContent() {
+        return mGridContent;
+    }
+
+    /**
+     * @return the color to tint content in this grid.
+     */
+    @Nullable
+    public SliceItem getColorItem() {
+        return mColorItem;
+    }
+
+    /**
+     * @return the content intent item for this grid.
+     */
+    @Nullable
+    public SliceItem getContentIntent() {
+        return mPrimaryAction;
+    }
+
+    /**
+     * @return whether this grid has content that is valid to display.
+     */
+    public boolean isValid() {
+        return mGridContent.size() > 0;
+    }
+
+    /**
+     * @return whether the contents of this grid is just images.
+     */
+    public boolean isAllImages() {
+        return mAllImages;
+    }
+
+    private List<SliceItem> filterInvalidItems(List<SliceItem> items) {
+        List<SliceItem> filteredItems = new ArrayList<>();
+        for (int i = 0; i < items.size(); i++) {
+            SliceItem item = items.get(i);
+            if (!item.hasHint(HINT_SHORTCUT)) {
+                filteredItems.add(item);
+            }
+        }
+        return filteredItems;
+    }
+
+    /**
+     * @return the max number of lines of text in the cells of this grid row.
+     */
+    public int getMaxCellLineCount() {
+        return mMaxCellLineCount;
+    }
+
+    /**
+     * @return whether this row contains an image.
+     */
+    public boolean hasImage() {
+        return mHasImage;
+    }
+
+    /**
+     * Extracts information required to present content in a cell.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    public static class CellContent {
+        private SliceItem mContentIntent;
+        private ArrayList<SliceItem> mCellItems = new ArrayList<>();
+        private int mTextCount;
+        private boolean mHasImage;
+
+        public CellContent(SliceItem cellItem) {
+            populate(cellItem);
+        }
+
+        /**
+         * @return whether this row has content that is valid to display.
+         */
+        public boolean populate(SliceItem cellItem) {
+            final String format = cellItem.getFormat();
+            if (!cellItem.hasHint(HINT_SHORTCUT)
+                    && (FORMAT_SLICE.equals(format) || FORMAT_ACTION.equals(format))) {
+                List<SliceItem> items = cellItem.getSlice().getItems();
+                // If we've only got one item that's a slice / action use those items instead
+                if (items.size() == 1 && (FORMAT_ACTION.equals(items.get(0).getFormat())
+                        || FORMAT_SLICE.equals(items.get(0).getFormat()))) {
+                    mContentIntent = items.get(0);
+                    items = items.get(0).getSlice().getItems();
+                }
+                if (FORMAT_ACTION.equals(format)) {
+                    mContentIntent = cellItem;
+                }
+                mTextCount = 0;
+                int imageCount = 0;
+                for (int i = 0; i < items.size(); i++) {
+                    final SliceItem item = items.get(i);
+                    final String itemFormat = item.getFormat();
+                    if (mTextCount < 2 && (FORMAT_TEXT.equals(itemFormat)
+                            || FORMAT_TIMESTAMP.equals(itemFormat))) {
+                        mTextCount++;
+                        mCellItems.add(item);
+                    } else if (imageCount < 1 && FORMAT_IMAGE.equals(item.getFormat())) {
+                        imageCount++;
+                        mHasImage = true;
+                        mCellItems.add(item);
+                    }
+                }
+            } else if (isValidCellContent(cellItem)) {
+                mCellItems.add(cellItem);
+            }
+            return isValid();
+        }
+
+        /**
+         * @return the action to activate when this cell is tapped.
+         */
+        public SliceItem getContentIntent() {
+            return mContentIntent;
+        }
+
+        /**
+         * @return the slice items to display in this cell.
+         */
+        public ArrayList<SliceItem> getCellItems() {
+            return mCellItems;
+        }
+
+        /**
+         * @return whether this is content that is valid to show in a grid cell.
+         */
+        private boolean isValidCellContent(SliceItem cellItem) {
+            final String format = cellItem.getFormat();
+            return FORMAT_TEXT.equals(format)
+                    || FORMAT_TIMESTAMP.equals(format)
+                    || FORMAT_IMAGE.equals(format);
+        }
+
+        /**
+         * @return whether this grid has content that is valid to display.
+         */
+        public boolean isValid() {
+            return mCellItems.size() > 0 && mCellItems.size() <= 3;
+        }
+
+        /**
+         * @return whether this cell contains just an image.
+         */
+        public boolean isImageOnly() {
+            return mCellItems.size() == 1 && FORMAT_IMAGE.equals(mCellItems.get(0).getFormat());
+        }
+
+        /**
+         * @return number of text items in this cell.
+         */
+        public int getTextCount() {
+            return mTextCount;
+        }
+
+        /**
+         * @return whether this cell contains an image.
+         */
+        public boolean hasImage() {
+            return mHasImage;
+        }
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
new file mode 100644
index 0000000..f267bdb
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/GridRowView.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.support.annotation.ColorInt;
+import android.support.annotation.RestrictTo;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Pair;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(24)
+public class GridRowView extends SliceChildView implements View.OnClickListener {
+
+    private static final String TAG = "GridView";
+
+    // TODO -- Should add notion to the builder so that apps could define the "see more" intent
+    private static final boolean ALLOW_SEE_MORE = false;
+
+    private static final int TITLE_TEXT_LAYOUT = R.layout.abc_slice_title;
+    private static final int TEXT_LAYOUT = R.layout.abc_slice_secondary_text;
+    // Max number of *just* images that can be shown in a row
+    private static final int MAX_IMAGES = 3;
+    // Max number of normal cell items that can be shown in a row
+    private static final int MAX_ALL = 5;
+
+    // Max number of text items that can show in a cell
+    private static final int MAX_CELL_TEXT = 2;
+    // Max number of text items that can show in a cell if the mode is small
+    private static final int MAX_CELL_TEXT_SMALL = 1;
+    // Max number of images that can show in a cell
+    private static final int MAX_CELL_IMAGES = 1;
+
+    private int mRowIndex;
+    private boolean mIsAllImages;
+
+    private int mIconSize;
+    private int mLargeIconSize;
+    private int mBigPictureHeight;
+    private int mAllImagesHeight;
+    private GridContent mGridContent;
+    private LinearLayout mViewContainer;
+
+    public GridRowView(Context context) {
+        this(context, null);
+    }
+
+    public GridRowView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        final Resources res = getContext().getResources();
+        mIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
+        mLargeIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_large_icon_size);
+        mBigPictureHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_big_picture_height);
+        mAllImagesHeight = res.getDimensionPixelSize(R.dimen.abc_slice_grid_image_only_height);
+        mViewContainer = new LinearLayout(getContext());
+        mViewContainer.setOrientation(LinearLayout.HORIZONTAL);
+        addView(mViewContainer, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mIsAllImages) {
+            int count = getChildCount();
+            int height = (count == 1) ? mBigPictureHeight : mAllImagesHeight;
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+            getLayoutParams().height = height;
+            for (int i = 0; i < count; i++) {
+                getChildAt(i).getLayoutParams().height = height;
+            }
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    public void setTint(@ColorInt int tintColor) {
+        super.setTint(tintColor);
+        if (mGridContent != null) {
+            // TODO -- could be smarter about this
+            resetView();
+            populateViews(mGridContent);
+        }
+    }
+
+    /**
+     * This is called when GridView is the parent template.
+     */
+    @Override
+    public void setSlice(Slice slice) {
+        resetView();
+        mRowIndex = 0;
+        mGridContent = new GridContent(slice.getItems().get(0));
+        populateViews(mGridContent);
+    }
+
+    /**
+     * This is called when GridView is being used as a component in a larger template.
+     */
+    @Override
+    public void setSliceItem(SliceItem slice, boolean isHeader, int index,
+            SliceView.OnSliceActionListener observer) {
+        resetView();
+        setSliceActionListener(observer);
+        mRowIndex = index;
+        mGridContent = new GridContent(slice);
+        populateViews(mGridContent);
+    }
+
+    private void populateViews(GridContent gc) {
+        if (gc.getContentIntent() != null) {
+            EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_CONTENT,
+                    EventInfo.ROW_TYPE_GRID, mRowIndex);
+            Pair<SliceItem, EventInfo> tagItem = new Pair<>(gc.getContentIntent(), info);
+            mViewContainer.setTag(tagItem);
+            makeClickable(mViewContainer);
+        }
+        mIsAllImages = gc.isAllImages();
+        ArrayList<GridContent.CellContent> cells = gc.getGridContent();
+        final int max = mIsAllImages ? MAX_IMAGES : MAX_ALL;
+        for (int i = 0; i < cells.size(); i++) {
+            if (isFull()) {
+                break;
+            }
+            addCell(cells.get(i), i, Math.min(cells.size(), max));
+        }
+        if (ALLOW_SEE_MORE && mIsAllImages && cells.size() > getChildCount()) {
+            addSeeMoreCount(cells.size() - getChildCount());
+        }
+    }
+
+    private void addSeeMoreCount(int numExtra) {
+        View last = getChildAt(getChildCount() - 1);
+        FrameLayout frame = new FrameLayout(getContext());
+        frame.setLayoutParams(last.getLayoutParams());
+
+        removeView(last);
+        frame.addView(last, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+        TextView v = new TextView(getContext());
+        v.setTextColor(Color.WHITE);
+        v.setBackgroundColor(0x4d000000);
+        v.setText(getResources().getString(R.string.abc_slice_more_content, numExtra));
+        v.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18);
+        v.setGravity(Gravity.CENTER);
+        frame.addView(v, new LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+        mViewContainer.addView(frame);
+    }
+
+    private boolean isFull() {
+        return getChildCount() >= (mIsAllImages ? MAX_IMAGES : MAX_ALL);
+    }
+
+    /**
+     * Adds a cell to the grid view based on the provided {@link SliceItem}.
+     */
+    private void addCell(GridContent.CellContent cell, int index, int total) {
+        final int maxCellText = getMode() == SliceView.MODE_SMALL
+                ? MAX_CELL_TEXT_SMALL
+                : MAX_CELL_TEXT;
+        LinearLayout cellContainer = new LinearLayout(getContext());
+        cellContainer.setOrientation(LinearLayout.VERTICAL);
+        cellContainer.setGravity(Gravity.CENTER_HORIZONTAL);
+
+        ArrayList<SliceItem> cellItems = cell.getCellItems();
+        SliceItem contentIntentItem = cell.getContentIntent();
+
+        int textCount = 0;
+        int imageCount = 0;
+        boolean added = false;
+        boolean singleItem = cellItems.size() == 1;
+        List<SliceItem> textItems = null;
+        // In small format we display one text item and prefer titles
+        if (!singleItem && getMode() == SliceView.MODE_SMALL) {
+            // Get all our text items
+            textItems = cellItems.stream().filter(new Predicate<SliceItem>() {
+                @Override
+                public boolean test(SliceItem s) {
+                    return FORMAT_TEXT.equals(s.getFormat());
+                }
+            }).collect(Collectors.<SliceItem>toList());
+            // If we have more than 1 remove non-titles
+            Iterator<SliceItem> iterator = textItems.iterator();
+            while (textItems.size() > 1) {
+                SliceItem item = iterator.next();
+                if (!item.hasHint(HINT_TITLE)) {
+                    iterator.remove();
+                }
+            }
+        }
+        for (int i = 0; i < cellItems.size(); i++) {
+            SliceItem item = cellItems.get(i);
+            final String itemFormat = item.getFormat();
+            if (textCount < maxCellText && (FORMAT_TEXT.equals(itemFormat)
+                    || FORMAT_TIMESTAMP.equals(itemFormat))) {
+                if (textItems != null && !textItems.contains(item)) {
+                    continue;
+                }
+                if (addItem(item, mTintColor, cellContainer, singleItem)) {
+                    textCount++;
+                    added = true;
+                }
+            } else if (imageCount < MAX_CELL_IMAGES && FORMAT_IMAGE.equals(item.getFormat())) {
+                if (addItem(item, mTintColor, cellContainer, singleItem)) {
+                    imageCount++;
+                    added = true;
+                }
+            }
+        }
+        if (added) {
+            mViewContainer.addView(cellContainer,
+                    new LinearLayout.LayoutParams(0, WRAP_CONTENT, 1));
+            if (contentIntentItem != null) {
+                EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_BUTTON,
+                        EventInfo.ROW_TYPE_GRID, mRowIndex);
+                info.setPosition(EventInfo.POSITION_CELL, index, total);
+                Pair<SliceItem, EventInfo> tagItem = new Pair<>(contentIntentItem, info);
+                cellContainer.setTag(tagItem);
+                makeClickable(cellContainer);
+            }
+        }
+    }
+
+    /**
+     * Adds simple items to a container. Simple items include icons, text, and timestamps.
+     * @return Whether an item was added.
+     */
+    private boolean addItem(SliceItem item, int color, ViewGroup container, boolean singleItem) {
+        final String format = item.getFormat();
+        View addedView = null;
+        if (FORMAT_TEXT.equals(format) || FORMAT_TIMESTAMP.equals(format)) {
+            boolean title = SliceQuery.hasAnyHints(item, HINT_LARGE, HINT_TITLE);
+            TextView tv = (TextView) LayoutInflater.from(getContext()).inflate(title
+                    ? TITLE_TEXT_LAYOUT : TEXT_LAYOUT, null);
+            tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, title ? mTitleSize : mSubtitleSize);
+            tv.setTextColor(title ? mTitleColor : mSubtitleColor);
+            CharSequence text = FORMAT_TIMESTAMP.equals(format)
+                    ? SliceViewUtil.getRelativeTimeString(item.getTimestamp())
+                    : item.getText();
+            tv.setText(text);
+            container.addView(tv);
+            addedView = tv;
+        } else if (FORMAT_IMAGE.equals(format)) {
+            ImageView iv = new ImageView(getContext());
+            iv.setImageIcon(item.getIcon());
+            if (color != -1 && !item.hasHint(HINT_NO_TINT) && !item.hasHint(HINT_LARGE)) {
+                iv.setColorFilter(color);
+            }
+            int size = mIconSize;
+            if (item.hasHint(HINT_LARGE)) {
+                iv.setScaleType(ScaleType.CENTER_CROP);
+                size = singleItem ? MATCH_PARENT : mLargeIconSize;
+            }
+            container.addView(iv, new LayoutParams(size, size));
+            addedView = iv;
+        }
+        return addedView != null;
+    }
+
+    private void makeClickable(View layout) {
+        layout.setOnClickListener(this);
+        layout.setBackground(SliceViewUtil.getDrawable(getContext(),
+                android.R.attr.selectableItemBackground));
+    }
+
+    @Override
+    public void onClick(View view) {
+        Pair<SliceItem, EventInfo> tagItem = (Pair<SliceItem, EventInfo>) view.getTag();
+        final SliceItem actionItem = tagItem.first;
+        final EventInfo info = tagItem.second;
+        if (actionItem != null && FORMAT_ACTION.equals(actionItem.getFormat())) {
+            try {
+                actionItem.getAction().send();
+                if (mObserver != null) {
+                    mObserver.onSliceAction(info, actionItem);
+                }
+            } catch (PendingIntent.CanceledException e) {
+                Log.w(TAG, "PendingIntent for slice cannot be sent", e);
+            }
+        }
+    }
+
+    @Override
+    public void resetView() {
+        mIsAllImages = true;
+        mViewContainer.removeAllViews();
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java b/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java
new file mode 100644
index 0000000..b64cd01
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeSliceAdapter.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_HORIZONTAL;
+import static android.app.slice.Slice.SUBTYPE_MESSAGE;
+import static android.app.slice.Slice.SUBTYPE_SOURCE;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import static androidx.app.slice.widget.SliceView.MODE_LARGE;
+
+import android.annotation.TargetApi;
+import android.app.slice.Slice;
+import android.content.Context;
+import android.support.annotation.RestrictTo;
+import android.support.v7.widget.RecyclerView;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(24)
+public class LargeSliceAdapter extends RecyclerView.Adapter<LargeSliceAdapter.SliceViewHolder> {
+
+    static final int TYPE_DEFAULT       = 1;
+    static final int TYPE_HEADER        = 2; // TODO: headers shouldn't scroll off
+    static final int TYPE_GRID          = 3;
+    static final int TYPE_MESSAGE       = 4;
+    static final int TYPE_MESSAGE_LOCAL = 5;
+
+    private final IdGenerator mIdGen = new IdGenerator();
+    private final Context mContext;
+    private List<SliceWrapper> mSlices = new ArrayList<>();
+    private SliceView.OnSliceActionListener mSliceObserver;
+    private int mColor;
+    private AttributeSet mAttrs;
+    private List<SliceItem> mSliceActions;
+
+    public LargeSliceAdapter(Context context) {
+        mContext = context;
+        setHasStableIds(true);
+    }
+
+    public void setSliceObserver(SliceView.OnSliceActionListener observer) {
+        mSliceObserver = observer;
+    }
+
+    /**
+     * Sets the actions to display for this slice, this adjusts what's displayed in the header item.
+     */
+    public void setSliceActions(List<SliceItem> actions) {
+        mSliceActions = actions;
+        if (getItemCount() > 0) {
+            notifyItemChanged(0); // Header item (index 0) displays the actions
+        }
+    }
+
+    /**
+     * Set the {@link SliceItem}'s to be displayed in the adapter and the accent color.
+     */
+    public void setSliceItems(List<SliceItem> slices, int color) {
+        if (slices == null) {
+            mSlices.clear();
+        } else {
+            mIdGen.resetUsage();
+            mSlices = slices.stream().map(new Function<SliceItem, SliceWrapper>() {
+                @Override
+                public SliceWrapper apply(SliceItem s) {
+                    return new SliceWrapper(s, mIdGen);
+                }
+            }).collect(Collectors.<SliceWrapper>toList());
+        }
+        mColor = color;
+        notifyDataSetChanged();
+    }
+
+    /**
+     * Sets the attribute set to use for views in the list.
+     */
+    public void setStyle(AttributeSet attrs) {
+        mAttrs = attrs;
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public SliceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        View v = inflateForType(viewType);
+        v.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
+        return new SliceViewHolder(v);
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mSlices.get(position).mType;
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return mSlices.get(position).mId;
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSlices.size();
+    }
+
+    @Override
+    public void onBindViewHolder(SliceViewHolder holder, int position) {
+        SliceWrapper slice = mSlices.get(position);
+        if (holder.mSliceView != null) {
+            final boolean isHeader = position == 0;
+            holder.mSliceView.setTint(mColor);
+            holder.mSliceView.setStyle(mAttrs);
+            holder.mSliceView.setSliceItem(slice.mItem, isHeader, position, mSliceObserver);
+            if (isHeader && holder.mSliceView instanceof RowView) {
+                holder.mSliceView.setSliceActions(mSliceActions);
+            }
+        }
+    }
+
+    private View inflateForType(int viewType) {
+        View v = new RowView(mContext);
+        switch (viewType) {
+            case TYPE_GRID:
+                v = LayoutInflater.from(mContext).inflate(R.layout.abc_slice_grid, null);
+                break;
+            case TYPE_MESSAGE:
+                v = LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message, null);
+                break;
+            case TYPE_MESSAGE_LOCAL:
+                v = LayoutInflater.from(mContext).inflate(R.layout.abc_slice_message_local,
+                        null);
+                break;
+        }
+        ((SliceChildView) v).setMode(MODE_LARGE);
+        return v;
+    }
+
+    protected static class SliceWrapper {
+        private final SliceItem mItem;
+        private final int mType;
+        private final long mId;
+
+        public SliceWrapper(SliceItem item, IdGenerator idGen) {
+            mItem = item;
+            mType = getFormat(item);
+            mId = idGen.getId(item);
+        }
+
+        public static int getFormat(SliceItem item) {
+            if (SUBTYPE_MESSAGE.equals(item.getSubType())) {
+                // TODO: Better way to determine me or not? Something more like Messaging style.
+                if (SliceQuery.findSubtype(item, null, SUBTYPE_SOURCE) != null) {
+                    return TYPE_MESSAGE;
+                } else {
+                    return TYPE_MESSAGE_LOCAL;
+                }
+            }
+            if (item.hasHint(HINT_HORIZONTAL)) {
+                return TYPE_GRID;
+            }
+            if (!item.hasHint(Slice.HINT_LIST_ITEM)) {
+                return TYPE_HEADER;
+            }
+            return TYPE_DEFAULT;
+        }
+    }
+
+    /**
+     * A {@link RecyclerView.ViewHolder} for presenting slices in {@link LargeSliceAdapter}.
+     */
+    public static class SliceViewHolder extends RecyclerView.ViewHolder {
+        public final SliceChildView mSliceView;
+
+        public SliceViewHolder(View itemView) {
+            super(itemView);
+            mSliceView = itemView instanceof SliceChildView ? (SliceChildView) itemView : null;
+        }
+    }
+
+    private static class IdGenerator {
+        private long mNextLong = 0;
+        private final ArrayMap<String, Long> mCurrentIds = new ArrayMap<>();
+        private final ArrayMap<String, Integer> mUsedIds = new ArrayMap<>();
+
+        public long getId(SliceItem item) {
+            String str = genString(item);
+            if (!mCurrentIds.containsKey(str)) {
+                mCurrentIds.put(str, mNextLong++);
+            }
+            long id = mCurrentIds.get(str);
+            int index = mUsedIds.getOrDefault(str, 0);
+            mUsedIds.put(str, index + 1);
+            return id + index * 10000;
+        }
+
+        private String genString(SliceItem item) {
+            final StringBuilder builder = new StringBuilder();
+            SliceQuery.stream(item).forEach(new Consumer<SliceItem>() {
+                @Override
+                public void accept(SliceItem i) {
+                    builder.append(i.getFormat());
+                    //i.removeHint(Slice.HINT_SELECTED);
+                    builder.append(i.getHints());
+                    switch (i.getFormat()) {
+                        case FORMAT_IMAGE:
+                            builder.append(i.getIcon());
+                            break;
+                        case FORMAT_TEXT:
+                            builder.append(i.getText());
+                            break;
+                        case FORMAT_INT:
+                            builder.append(i.getInt());
+                            break;
+                    }
+                }
+            });
+            return builder.toString();
+        }
+
+        public void resetUsage() {
+            mUsedIds.clear();
+        }
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
new file mode 100644
index 0000000..7aace75
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/LargeTemplateView.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_PARTIAL;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.support.annotation.RestrictTo;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(24)
+public class LargeTemplateView extends SliceChildView {
+
+    private final LargeSliceAdapter mAdapter;
+    private final RecyclerView mRecyclerView;
+    private final int mDefaultHeight;
+    private Slice mSlice;
+    private boolean mIsScrollable;
+    private ListContent mListContent;
+
+    public LargeTemplateView(Context context) {
+        super(context);
+        mRecyclerView = new RecyclerView(getContext());
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        mAdapter = new LargeSliceAdapter(context);
+        mRecyclerView.setAdapter(mAdapter);
+        addView(mRecyclerView);
+        mDefaultHeight = getResources().getDimensionPixelSize(R.dimen.abc_slice_large_height);
+    }
+
+    @Override
+    public void setTint(int tint) {
+        super.setTint(tint);
+        populate();
+    }
+
+    @Override
+    public @SliceView.SliceMode int getMode() {
+        return SliceView.MODE_LARGE;
+    }
+
+    @Override
+    public void setSliceActionListener(SliceView.OnSliceActionListener observer) {
+        mObserver = observer;
+        if (mAdapter != null) {
+            mAdapter.setSliceObserver(mObserver);
+        }
+    }
+
+    @Override
+    public void setSliceActions(List<SliceItem> actions) {
+        mAdapter.setSliceActions(actions);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        mRecyclerView.getLayoutParams().height = WRAP_CONTENT;
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        if (mRecyclerView.getMeasuredHeight() > width
+                || (mSlice != null && SliceQuery.hasHints(mSlice, HINT_PARTIAL))) {
+            mRecyclerView.getLayoutParams().height = width;
+        } else {
+            mRecyclerView.getLayoutParams().height = mRecyclerView.getMeasuredHeight();
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    public void setSlice(Slice slice) {
+        mSlice = slice;
+        populate();
+    }
+
+    @Override
+    public void setStyle(AttributeSet attrs) {
+        super.setStyle(attrs);
+        mAdapter.setStyle(attrs);
+    }
+
+    private void populate() {
+        if (mSlice == null) {
+            return;
+        }
+        mListContent = new ListContent(mSlice);
+        mAdapter.setSliceItems(mListContent.getRowItems(), mTintColor);
+    }
+
+    /**
+     * Whether or not the content in this template should be scrollable.
+     */
+    public void setScrollable(boolean isScrollable) {
+        // TODO -- restrict / enable how much this view can show
+        mIsScrollable = isScrollable;
+    }
+
+    @Override
+    public void resetView() {
+        mSlice = null;
+        mAdapter.setSliceItems(null, -1);
+        mListContent = null;
+        mAdapter.setSliceItems(null, -1);
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java b/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
new file mode 100644
index 0000000..79bfa39
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ListContent.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.SliceUtils;
+import androidx.app.slice.core.SliceQuery;
+
+/**
+ * Extracts information required to present content in a list format from a slice.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class ListContent {
+
+    private SliceItem mHeaderItem;
+    private SliceItem mColorItem;
+    private ArrayList<SliceItem> mRowItems = new ArrayList<>();
+    private List<SliceItem> mSliceActions;
+
+    public ListContent(Slice slice) {
+        populate(slice);
+    }
+
+    /**
+     * Resets the content.
+     */
+    public void reset() {
+        mColorItem = null;
+        mHeaderItem = null;
+        mRowItems.clear();
+    }
+
+    /**
+     * @return whether this row has content that is valid to display.
+     */
+    public boolean populate(Slice slice) {
+        reset();
+        mColorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
+        // Find slice actions
+        mSliceActions = SliceUtils.getSliceActions(slice);
+        // Find header
+        mHeaderItem = findHeaderItem(slice);
+        if (mHeaderItem != null) {
+            mRowItems.add(mHeaderItem);
+        }
+        // Filter + create row items
+        List<SliceItem> children = slice.getItems();
+        for (int i = 0; i < children.size(); i++) {
+            final SliceItem child = children.get(i);
+            final String format = child.getFormat();
+            if (!child.hasAnyHints(HINT_ACTIONS)
+                    && (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
+                if (mHeaderItem == null && !child.hasHint(HINT_LIST_ITEM)) {
+                    mHeaderItem = child;
+                    mRowItems.add(0, child);
+                } else if (child.hasHint(HINT_LIST_ITEM)) {
+                    mRowItems.add(child);
+                }
+            }
+        }
+        // Ensure we have something for the header -- use first row
+        if (mHeaderItem == null && mRowItems.size() >= 1) {
+            mHeaderItem = mRowItems.get(0);
+        }
+        return isValid();
+    }
+
+    /**
+     * @return whether this list has content that is valid to display.
+     */
+    public boolean isValid() {
+        return mRowItems.size() > 0;
+    }
+
+    @Nullable
+    public SliceItem getColorItem() {
+        return mColorItem;
+    }
+
+    @Nullable
+    public SliceItem getHeaderItem() {
+        return mHeaderItem;
+    }
+
+    @Nullable
+    public List<SliceItem> getSliceActions() {
+        return mSliceActions;
+    }
+
+    public ArrayList<SliceItem> getRowItems() {
+        return mRowItems;
+    }
+
+    /**
+     * @return whether this list has an explicit header (i.e. row item without HINT_LIST_ITEM)
+     */
+    public boolean hasHeader() {
+        return mHeaderItem != null && isValidHeader(mHeaderItem);
+    }
+
+    @Nullable
+    private static SliceItem findHeaderItem(@NonNull Slice slice) {
+        // See if header is specified
+        String[] nonHints = new String[] {HINT_LIST_ITEM, HINT_SHORTCUT, HINT_ACTIONS};
+        SliceItem header = SliceQuery.find(slice, FORMAT_SLICE, null, nonHints);
+        if (header != null && isValidHeader(header)) {
+            return header;
+        }
+        return null;
+    }
+
+    private static boolean isValidHeader(SliceItem sliceItem) {
+        if (FORMAT_SLICE.equals(sliceItem.getFormat()) && !sliceItem.hasHint(HINT_LIST_ITEM)
+                && !sliceItem.hasHint(HINT_ACTIONS)) {
+             // Minimum valid header is a slice with text
+            SliceItem item = SliceQuery.find(sliceItem, FORMAT_TEXT, (String) null, null);
+            return item != null;
+        }
+        return false;
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/MessageView.java b/slices/view/src/main/java/androidx/app/slice/widget/MessageView.java
new file mode 100644
index 0000000..9c4a705
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/MessageView.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.SUBTYPE_SOURCE;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.RestrictTo;
+import android.text.SpannableStringBuilder;
+import android.util.TypedValue;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.function.Consumer;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(24)
+public class MessageView extends SliceChildView {
+
+    private TextView mDetails;
+    private ImageView mIcon;
+
+    private int mRowIndex;
+
+    public MessageView(Context context) {
+        super(context);
+    }
+
+    @Override
+    public int getMode() {
+        return SliceView.MODE_LARGE;
+    }
+
+    @Override
+    public void setSlice(Slice slice) {
+        // Do nothing it's always a list item
+    }
+
+    @Override
+    public void resetView() {
+        // TODO
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mDetails = findViewById(android.R.id.summary);
+        mIcon = findViewById(android.R.id.icon);
+    }
+
+    @Override
+    public void setSliceItem(SliceItem slice, boolean isHeader, int index,
+            SliceView.OnSliceActionListener observer) {
+        setSliceActionListener(observer);
+        mRowIndex = index;
+        SliceItem source = SliceQuery.findSubtype(slice, FORMAT_IMAGE, SUBTYPE_SOURCE);
+        if (source != null) {
+            final int iconSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+                    24, getContext().getResources().getDisplayMetrics());
+            // TODO: try and turn this into a drawable
+            Bitmap iconBm = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+            Canvas iconCanvas = new Canvas(iconBm);
+            Drawable d = source.getIcon().loadDrawable(getContext());
+            d.setBounds(0, 0, iconSize, iconSize);
+            d.draw(iconCanvas);
+            mIcon.setImageBitmap(SliceViewUtil.getCircularBitmap(iconBm));
+        }
+        final SpannableStringBuilder builder = new SpannableStringBuilder();
+        SliceQuery.findAll(slice, FORMAT_TEXT).forEach(new Consumer<SliceItem>() {
+            @Override
+            public void accept(SliceItem text) {
+                if (builder.length() != 0) {
+                    builder.append('\n');
+                }
+                builder.append(text.getText());
+            }
+        });
+        mDetails.setText(builder.toString());
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RemoteInputView.java b/slices/view/src/main/java/androidx/app/slice/widget/RemoteInputView.java
new file mode 100644
index 0000000..da35018
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RemoteInputView.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import android.animation.Animator;
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.annotation.RestrictTo;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.inputmethod.CompletionInfo;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.app.slice.view.R;
+
+/**
+ * Host for the remote input.
+ *
+ * @hide
+ */
+// TODO this should be unified with SystemUI RemoteInputView (b/67527720)
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(23)
+public class RemoteInputView extends LinearLayout implements View.OnClickListener, TextWatcher {
+
+    private static final String TAG = "RemoteInput";
+
+    /**
+     * A marker object that let's us easily find views of this class.
+     */
+    public static final Object VIEW_TAG = new Object();
+
+    private RemoteEditText mEditText;
+    private ImageButton mSendButton;
+    private ProgressBar mProgressBar;
+    private PendingIntent mPendingIntent;
+    private RemoteInput[] mRemoteInputs;
+    private RemoteInput mRemoteInput;
+
+    private int mRevealCx;
+    private int mRevealCy;
+    private int mRevealR;
+    private boolean mResetting;
+
+    public RemoteInputView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mProgressBar = findViewById(R.id.remote_input_progress);
+        mSendButton = findViewById(R.id.remote_input_send);
+        mSendButton.setOnClickListener(this);
+
+        mEditText = (RemoteEditText) getChildAt(0);
+        mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+                final boolean isSoftImeEvent = event == null
+                        && (actionId == EditorInfo.IME_ACTION_DONE
+                                || actionId == EditorInfo.IME_ACTION_NEXT
+                                || actionId == EditorInfo.IME_ACTION_SEND);
+                final boolean isKeyboardEnterKey = event != null
+                        && isConfirmKey(event.getKeyCode())
+                        && event.getAction() == KeyEvent.ACTION_DOWN;
+
+                if (isSoftImeEvent || isKeyboardEnterKey) {
+                    if (mEditText.length() > 0) {
+                        sendRemoteInput();
+                    }
+                    // Consume action to prevent IME from closing.
+                    return true;
+                }
+                return false;
+            }
+        });
+        mEditText.addTextChangedListener(this);
+        mEditText.setInnerFocusable(false);
+        mEditText.mRemoteInputView = this;
+    }
+
+    private void sendRemoteInput() {
+        Bundle results = new Bundle();
+        results.putString(mRemoteInput.getResultKey(), mEditText.getText().toString());
+        Intent fillInIntent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        RemoteInput.addResultsToIntent(mRemoteInputs, fillInIntent,
+                results);
+
+        mEditText.setEnabled(false);
+        mSendButton.setVisibility(INVISIBLE);
+        mProgressBar.setVisibility(VISIBLE);
+        mEditText.mShowImeOnInputConnection = false;
+
+        // TODO: Figure out API for telling the system about slice interaction.
+        // Tell ShortcutManager that this package has been "activated".  ShortcutManager
+        // will reset the throttling for this package.
+        // Strictly speaking, the intent receiver may be different from the intent creator,
+        // but that's an edge case, and also because we can't always know which package will receive
+        // an intent, so we just reset for the creator.
+        //getContext().getSystemService(ShortcutManager.class).onApplicationActive(
+        //        mPendingIntent.getCreatorPackage(),
+        //        getContext().getUserId());
+
+        try {
+            mPendingIntent.send(getContext(), 0, fillInIntent);
+            reset();
+        } catch (PendingIntent.CanceledException e) {
+            Log.i(TAG, "Unable to send remote input result", e);
+            Toast.makeText(getContext(), "Failure sending pending intent for inline reply :(",
+                    Toast.LENGTH_SHORT).show();
+            reset();
+        }
+    }
+
+    /**
+     * Creates a remote input view.
+     */
+    public static RemoteInputView inflate(Context context, ViewGroup root) {
+        RemoteInputView v = (RemoteInputView) LayoutInflater.from(context).inflate(
+                R.layout.abc_slice_remote_input, root, false);
+        v.setTag(VIEW_TAG);
+        return v;
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mSendButton) {
+            sendRemoteInput();
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        super.onTouchEvent(event);
+
+        // We never want for a touch to escape to an outer view or one we covered.
+        return true;
+    }
+
+    private void onDefocus() {
+        setVisibility(INVISIBLE);
+    }
+
+    /**
+     * Set the pending intent for remote input.
+     */
+    public void setPendingIntent(PendingIntent pendingIntent) {
+        mPendingIntent = pendingIntent;
+    }
+
+    /**
+     * Set the remote inputs for this view.
+     */
+    public void setRemoteInput(RemoteInput[] remoteInputs, RemoteInput remoteInput) {
+        mRemoteInputs = remoteInputs;
+        mRemoteInput = remoteInput;
+        mEditText.setHint(mRemoteInput.getLabel());
+    }
+
+    /**
+     * Focuses the remote input view.
+     */
+    public void focusAnimated() {
+        if (getVisibility() != VISIBLE) {
+            Animator animator = ViewAnimationUtils.createCircularReveal(
+                    this, mRevealCx, mRevealCy, 0, mRevealR);
+            animator.setDuration(200);
+            animator.start();
+        }
+        focus();
+    }
+
+    private void focus() {
+        setVisibility(VISIBLE);
+        mEditText.setInnerFocusable(true);
+        mEditText.mShowImeOnInputConnection = true;
+        mEditText.setSelection(mEditText.getText().length());
+        mEditText.requestFocus();
+        updateSendButton();
+    }
+
+    private void reset() {
+        mResetting = true;
+
+        mEditText.getText().clear();
+        mEditText.setEnabled(true);
+        mSendButton.setVisibility(VISIBLE);
+        mProgressBar.setVisibility(INVISIBLE);
+        updateSendButton();
+        onDefocus();
+
+        mResetting = false;
+    }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (mResetting && child == mEditText) {
+            // Suppress text events if it happens during resetting. Ideally this would be
+            // suppressed by the text view not being shown, but that doesn't work here because it
+            // needs to stay visible for the animation.
+            return false;
+        }
+        return super.onRequestSendAccessibilityEvent(child, event);
+    }
+
+    private void updateSendButton() {
+        mSendButton.setEnabled(mEditText.getText().length() != 0);
+    }
+
+    @Override
+    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+    }
+
+    @Override
+    public void onTextChanged(CharSequence s, int start, int before, int count) {
+    }
+
+    @Override
+    public void afterTextChanged(Editable s) {
+        updateSendButton();
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void setRevealParameters(int cx, int cy, int r) {
+        mRevealCx = cx;
+        mRevealCy = cy;
+        mRevealR = r;
+    }
+
+    @Override
+    public void dispatchStartTemporaryDetach() {
+        super.dispatchStartTemporaryDetach();
+        // Detach the EditText temporarily such that it doesn't get onDetachedFromWindow and
+        // won't lose IME focus.
+        detachViewFromParent(mEditText);
+    }
+
+    @Override
+    public void dispatchFinishTemporaryDetach() {
+        if (isAttachedToWindow()) {
+            attachViewToParent(mEditText, 0, mEditText.getLayoutParams());
+        } else {
+            removeDetachedView(mEditText, false /* animate */);
+        }
+        super.dispatchFinishTemporaryDetach();
+    }
+
+    /**
+     * An EditText that changes appearance based on whether it's focusable and becomes un-focusable
+     * whenever the user navigates away from it or it becomes invisible.
+     */
+    public static class RemoteEditText extends EditText {
+
+        private final Drawable mBackground;
+        private RemoteInputView mRemoteInputView;
+        boolean mShowImeOnInputConnection;
+
+        public RemoteEditText(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            mBackground = getBackground();
+        }
+
+        private void defocusIfNeeded(boolean animate) {
+            if (mRemoteInputView != null || isTemporarilyDetached()) {
+                if (isTemporarilyDetached()) {
+                    // We might get reattached but then the other one of HUN / expanded might steal
+                    // our focus, so we'll need to save our text here.
+                }
+                return;
+            }
+            if (isFocusable() && isEnabled()) {
+                setInnerFocusable(false);
+                if (mRemoteInputView != null) {
+                    mRemoteInputView.onDefocus();
+                }
+                mShowImeOnInputConnection = false;
+            }
+        }
+
+        @Override
+        protected void onVisibilityChanged(View changedView, int visibility) {
+            super.onVisibilityChanged(changedView, visibility);
+
+            if (!isShown()) {
+                defocusIfNeeded(false /* animate */);
+            }
+        }
+
+        @Override
+        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+            super.onFocusChanged(focused, direction, previouslyFocusedRect);
+            if (!focused) {
+                defocusIfNeeded(true /* animate */);
+            }
+        }
+
+        @Override
+        public void getFocusedRect(Rect r) {
+            super.getFocusedRect(r);
+            r.top = getScrollY();
+            r.bottom = getScrollY() + (getBottom() - getTop());
+        }
+
+        @Override
+        public boolean onKeyDown(int keyCode, KeyEvent event) {
+            if (keyCode == KeyEvent.KEYCODE_BACK) {
+                // Eat the DOWN event here to prevent any default behavior.
+                return true;
+            }
+            return super.onKeyDown(keyCode, event);
+        }
+
+        @Override
+        public boolean onKeyUp(int keyCode, KeyEvent event) {
+            if (keyCode == KeyEvent.KEYCODE_BACK) {
+                defocusIfNeeded(true /* animate */);
+                return true;
+            }
+            return super.onKeyUp(keyCode, event);
+        }
+
+        @Override
+        public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+            final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+
+            if (mShowImeOnInputConnection && inputConnection != null) {
+                final InputMethodManager imm = getContext().getSystemService(
+                        InputMethodManager.class);
+                if (imm != null) {
+                    // onCreateInputConnection is called by InputMethodManager in the middle of
+                    // setting up the connection to the IME; wait with requesting the IME until that
+                    // work has completed.
+                    post(new Runnable() {
+                        @Override
+                        public void run() {
+                            imm.viewClicked(RemoteEditText.this);
+                            imm.showSoftInput(RemoteEditText.this, 0);
+                        }
+                    });
+                }
+            }
+
+            return inputConnection;
+        }
+
+        @Override
+        public void onCommitCompletion(CompletionInfo text) {
+            clearComposingText();
+            setText(text.getText());
+            setSelection(getText().length());
+        }
+
+        void setInnerFocusable(boolean focusable) {
+            setFocusableInTouchMode(focusable);
+            setFocusable(focusable);
+            setCursorVisible(focusable);
+
+            if (focusable) {
+                requestFocus();
+                setBackground(mBackground);
+            } else {
+                setBackground(null);
+            }
+
+        }
+    }
+
+    /** Whether key will, by default, trigger a click on the focused view.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public static final boolean isConfirmKey(int keyCode) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_CENTER:
+            case KeyEvent.KEYCODE_ENTER:
+            case KeyEvent.KEYCODE_SPACE:
+            case KeyEvent.KEYCODE_NUMPAD_ENTER:
+                return true;
+            default:
+                return false;
+        }
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
new file mode 100644
index 0000000..920dc52
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowContent.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_SUMMARY;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import static androidx.app.slice.core.SliceHints.SUBTYPE_RANGE;
+
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+
+/**
+ * Extracts information required to present content in a row format from a slice.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+public class RowContent {
+    private static final String TAG = "RowContent";
+
+    private SliceItem mPrimaryAction;
+    private SliceItem mStartItem;
+    private SliceItem mTitleItem;
+    private SliceItem mSubtitleItem;
+    private SliceItem mSummaryItem;
+    private ArrayList<SliceItem> mEndItems = new ArrayList<>();
+    private boolean mEndItemsContainAction;
+    private SliceItem mRange;
+    private boolean mIsHeader;
+
+    public RowContent(SliceItem rowSlice, boolean isHeader) {
+        populate(rowSlice, isHeader);
+    }
+
+    /**
+     * Resets the content.
+     */
+    public void reset() {
+        mPrimaryAction = null;
+        mStartItem = null;
+        mTitleItem = null;
+        mSubtitleItem = null;
+        mEndItems.clear();
+        mIsHeader = false;
+    }
+
+    /**
+     * @return whether this row has content that is valid to display.
+     */
+    public boolean populate(SliceItem rowSlice, boolean isHeader) {
+        reset();
+        mIsHeader = isHeader;
+        if (!isValidRow(rowSlice)) {
+            Log.w(TAG, "Provided SliceItem is invalid for RowContent");
+            return false;
+        }
+        // Find primary action first (otherwise filtered out of valid row items)
+        String[] hints = new String[] {HINT_SHORTCUT, HINT_TITLE};
+        mPrimaryAction = SliceQuery.find(rowSlice, FORMAT_SLICE, hints,
+                new String[] { HINT_ACTIONS } /* nonHints */);
+
+        // Filter anything not viable for displaying in a row
+        ArrayList<SliceItem> rowItems = filterInvalidItems(rowSlice);
+        // If we've only got one item that's a slice / action use those items instead
+        if (rowItems.size() == 1 && (FORMAT_ACTION.equals(rowItems.get(0).getFormat())
+                || FORMAT_SLICE.equals(rowItems.get(0).getFormat()))
+                && !rowItems.get(0).hasHint(HINT_SHORTCUT)) {
+            if (isValidRow(rowItems.get(0))) {
+                rowSlice = rowItems.get(0);
+                rowItems = filterInvalidItems(rowSlice);
+            }
+        }
+        if (SUBTYPE_RANGE.equals(rowSlice.getSubType())) {
+            mRange = rowSlice;
+        }
+        if (rowItems.size() > 0) {
+            // Start item
+            SliceItem firstItem = rowItems.get(0);
+            if (FORMAT_SLICE.equals(firstItem.getFormat())) {
+                SliceItem unwrappedItem = firstItem.getSlice().getItems().get(0);
+                if (isStartType(unwrappedItem)) {
+                    mStartItem = unwrappedItem;
+                    rowItems.remove(0);
+                }
+            }
+
+            // Text + end items
+            ArrayList<SliceItem> endItems = new ArrayList<>();
+            for (int i = 0; i < rowItems.size(); i++) {
+                final SliceItem item = rowItems.get(i);
+                if (FORMAT_TEXT.equals(item.getFormat())) {
+                    if ((mTitleItem == null || !mTitleItem.hasHint(HINT_TITLE))
+                            && item.hasHint(HINT_TITLE) && !item.hasHint(HINT_SUMMARY)) {
+                        mTitleItem = item;
+                    } else if (mSubtitleItem == null && !item.hasHint(HINT_SUMMARY)) {
+                        mSubtitleItem = item;
+                    } else if (mSummaryItem == null && item.hasHint(HINT_SUMMARY)) {
+                        mSummaryItem = item;
+                    }
+                } else {
+                    endItems.add(item);
+                }
+            }
+            // Special rules for end items: only one timestamp, can't be mixture of icons / actions
+            boolean hasTimestamp = mStartItem != null
+                    && FORMAT_TIMESTAMP.equals(mStartItem.getFormat());
+            String desiredFormat = null;
+            for (int i = 0; i < endItems.size(); i++) {
+                final SliceItem item = endItems.get(i);
+                boolean isAction = FORMAT_SLICE.equals(item.getFormat())
+                        && item.hasHint(HINT_SHORTCUT);
+                if (FORMAT_TIMESTAMP.equals(item.getFormat())) {
+                    if (!hasTimestamp) {
+                        hasTimestamp = true;
+                        mEndItems.add(item);
+                    }
+                } else if (desiredFormat == null) {
+                    desiredFormat = item.getFormat();
+                    mEndItems.add(item);
+                    mEndItemsContainAction |= isAction;
+                } else if (desiredFormat.equals(item.getFormat())) {
+                    mEndItems.add(item);
+                    mEndItemsContainAction |= isAction;
+                }
+            }
+        }
+        return isValid();
+    }
+
+    /**
+     * @return the {@link SliceItem} representing the range in the row; can be null.
+     */
+    @Nullable
+    public SliceItem getRange() {
+        return mRange;
+    }
+
+    /**
+     * @return whether this row has content that is valid to display.
+     */
+    public boolean isValid() {
+        return mStartItem != null
+                || mTitleItem != null
+                || mSubtitleItem != null
+                || mEndItems.size() > 0;
+    }
+
+    @Nullable
+    public SliceItem getPrimaryAction() {
+        return mPrimaryAction;
+    }
+
+    @Nullable
+    public SliceItem getStartItem() {
+        return mIsHeader ? null : mStartItem;
+    }
+
+    @Nullable
+    public SliceItem getTitleItem() {
+        return mTitleItem;
+    }
+
+    @Nullable
+    public SliceItem getSubtitleItem() {
+        return mSubtitleItem;
+    }
+
+    @Nullable
+    public SliceItem getSummaryItem() {
+        return mSummaryItem == null ? mSubtitleItem : mSummaryItem;
+    }
+
+    public ArrayList<SliceItem> getEndItems() {
+        return mEndItems;
+    }
+
+    /**
+     * @return whether {@link #getEndItems()} contains a SliceItem with FORMAT_SLICE, HINT_SHORTCUT
+     */
+    public boolean endItemsContainAction() {
+        return mEndItemsContainAction;
+    }
+
+    /**
+     * @return whether this is a valid item to use to populate a row of content.
+     */
+    private static boolean isValidRow(SliceItem rowSlice) {
+        if (rowSlice == null) {
+            return false;
+        }
+        // Must be slice or action
+        if (FORMAT_SLICE.equals(rowSlice.getFormat())
+                || FORMAT_ACTION.equals(rowSlice.getFormat())) {
+            // Must have at least one legitimate child
+            List<SliceItem> rowItems = rowSlice.getSlice().getItems();
+            for (int i = 0; i < rowItems.size(); i++) {
+                if (isValidRowContent(rowSlice, rowItems.get(i))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static ArrayList<SliceItem> filterInvalidItems(SliceItem rowSlice) {
+        ArrayList<SliceItem> filteredList = new ArrayList<>();
+        for (SliceItem i : rowSlice.getSlice().getItems()) {
+            if (isValidRowContent(rowSlice, i)) {
+                filteredList.add(i);
+            }
+        }
+        return filteredList;
+    }
+
+    /**
+     * @return whether this item is valid content to display in a row.
+     */
+    private static boolean isValidRowContent(SliceItem slice, SliceItem item) {
+        if (FORMAT_SLICE.equals(item.getFormat()) && !item.hasHint(HINT_SHORTCUT)) {
+            // Unpack contents of slice
+            item = item.getSlice().getItems().get(0);
+        }
+        final String itemFormat = item.getFormat();
+        return FORMAT_TEXT.equals(itemFormat)
+                || FORMAT_IMAGE.equals(itemFormat)
+                || FORMAT_TIMESTAMP.equals(itemFormat)
+                || FORMAT_REMOTE_INPUT.equals(itemFormat)
+                || (FORMAT_SLICE.equals(itemFormat) && item.hasHint(HINT_TITLE)
+                && !item.hasHint(HINT_SHORTCUT))
+                || (FORMAT_SLICE.equals(itemFormat) && item.hasHint(HINT_SHORTCUT)
+                && !item.hasHint(HINT_TITLE))
+                || FORMAT_ACTION.equals(itemFormat)
+                || (FORMAT_INT.equals(itemFormat) && SUBTYPE_RANGE.equals(slice.getSubType()));
+    }
+
+    /**
+     * @return Whether this item is appropriate to be considered a "start" item, i.e. go in the
+     *         front slot of a row.
+     */
+    private static boolean isStartType(SliceItem item) {
+        final String type = item.getFormat();
+        return (FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null))
+                    || FORMAT_IMAGE.equals(type)
+                    || FORMAT_TIMESTAMP.equals(type);
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/RowView.java b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
new file mode 100644
index 0000000..5b3e74c
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/RowView.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.SUBTYPE_TOGGLE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import static androidx.app.slice.core.SliceHints.EXTRA_RANGE_VALUE;
+import static androidx.app.slice.core.SliceHints.SUBTYPE_MAX;
+import static androidx.app.slice.core.SliceHints.SUBTYPE_VALUE;
+import static androidx.app.slice.widget.SliceView.MODE_SMALL;
+
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.support.annotation.ColorInt;
+import android.support.annotation.RestrictTo;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.SeekBar;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
+
+/**
+ * Row item is in small template format and can be used to construct list items for use
+ * with {@link LargeTemplateView}.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(23)
+public class RowView extends SliceChildView implements View.OnClickListener {
+
+    private static final String TAG = "RowView";
+
+    // The number of items that fit on the right hand side of a small slice
+    private static final int MAX_END_ITEMS = 3;
+
+    private LinearLayout mStartContainer;
+    private LinearLayout mContent;
+    private TextView mPrimaryText;
+    private TextView mSecondaryText;
+    private View mDivider;
+    private ArrayList<CompoundButton> mToggles = new ArrayList<>();
+    private LinearLayout mEndContainer;
+    private SeekBar mSeekBar;
+    private ProgressBar mProgressBar;
+
+    private int mRowIndex;
+    private RowContent mRowContent;
+    private ActionContent mRowAction;
+    private boolean mIsHeader;
+    private List<SliceItem> mHeaderActions;
+
+    private int mIconSize;
+    private int mPadding;
+
+    public RowView(Context context) {
+        super(context);
+        mIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.abc_slice_icon_size);
+        mPadding = getContext().getResources().getDimensionPixelSize(R.dimen.abc_slice_padding);
+        inflate(context, R.layout.abc_slice_small_template, this);
+
+        mStartContainer = (LinearLayout) findViewById(R.id.icon_frame);
+        mContent = (LinearLayout) findViewById(android.R.id.content);
+        mPrimaryText = (TextView) findViewById(android.R.id.title);
+        mSecondaryText = (TextView) findViewById(android.R.id.summary);
+        mDivider = findViewById(R.id.divider);
+        mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
+        mSeekBar = (SeekBar) findViewById(R.id.seek_bar);
+        mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
+    }
+    @Override
+    public void setTint(@ColorInt int tintColor) {
+        super.setTint(tintColor);
+        if (mRowContent != null) {
+            // TODO -- can be smarter about this
+            populateViews();
+        }
+    }
+
+    @Override
+    public void setSliceActions(List<SliceItem> actions) {
+        mHeaderActions = actions;
+        if (mRowContent != null) {
+            populateViews();
+        }
+    }
+
+    /**
+     * This is called when RowView is being used as a component in a large template.
+     */
+    @Override
+    public void setSliceItem(SliceItem slice, boolean isHeader, int index,
+            SliceView.OnSliceActionListener observer) {
+        setSliceActionListener(observer);
+        mRowIndex = index;
+        mIsHeader = isHeader;
+        mHeaderActions = null;
+        mRowContent = new RowContent(slice, mIsHeader);
+        populateViews();
+    }
+
+    /**
+     * This is called when RowView is being used as a small template.
+     */
+    @Override
+    public void setSlice(Slice slice) {
+        mRowIndex = 0;
+        mIsHeader = true;
+        mHeaderActions = null;
+        ListContent lc = new ListContent(slice);
+        mRowContent = new RowContent(lc.getHeaderItem(), true /* isHeader */);
+        populateViews();
+    }
+
+    private void populateViews() {
+        resetView();
+        boolean showStart = false;
+        final SliceItem startItem = mRowContent.getStartItem();
+        if (startItem != null) {
+            final EventInfo info = new EventInfo(getMode(),
+                    EventInfo.ACTION_TYPE_BUTTON,
+                    EventInfo.ROW_TYPE_LIST, mRowIndex);
+            info.setPosition(EventInfo.POSITION_START, 0, 1);
+            showStart = addItem(startItem, mTintColor, true /* isStart */, 0 /* padding */, info);
+        }
+        mStartContainer.setVisibility(showStart ? View.VISIBLE : View.GONE);
+
+        final SliceItem titleItem = mRowContent.getTitleItem();
+        if (titleItem != null) {
+            mPrimaryText.setText(titleItem.getText());
+        }
+        mPrimaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mIsHeader
+                ? mHeaderTitleSize
+                : mTitleSize);
+        mPrimaryText.setTextColor(mTitleColor);
+        mPrimaryText.setVisibility(titleItem != null ? View.VISIBLE : View.GONE);
+
+        final SliceItem subTitle = getMode() == MODE_SMALL
+                ? mRowContent.getSummaryItem()
+                : mRowContent.getSubtitleItem();
+        if (subTitle != null) {
+            mSecondaryText.setText(subTitle.getText());
+        }
+        mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mIsHeader
+                ? mHeaderSubtitleSize
+                : mSubtitleSize);
+        mSecondaryText.setTextColor(mSubtitleColor);
+        mSecondaryText.setVisibility(subTitle != null ? View.VISIBLE : View.GONE);
+
+        final SliceItem range = mRowContent.getRange();
+        if (range != null) {
+            addRange(range);
+            return;
+        }
+
+        SliceItem primaryAction = mRowContent.getPrimaryAction();
+        if (primaryAction != null) {
+            mRowAction = new ActionContent(primaryAction);
+            if (mRowAction.isToggle()) {
+                // If primary action is a toggle, add it and we're done
+                addToggle(mRowAction, mTintColor, mEndContainer);
+                setViewClickable(this, true);
+                return;
+            }
+        }
+        List<SliceItem> endItems = mRowContent.getEndItems();
+
+        // If we're here we might be able to show end items
+        String desiredFormat = FORMAT_ACTION;
+        if (mIsHeader && mHeaderActions != null && mHeaderActions.size() > 0) {
+            // Use these if we have them instead
+            endItems = mHeaderActions;
+        } else if (!endItems.isEmpty()) {
+            // Prefer to show actions as end items if possible; fall back to the first format type.
+            SliceItem firstEndItem = endItems.get(0);
+            desiredFormat = mRowContent.endItemsContainAction()
+                    ? FORMAT_ACTION : firstEndItem.getSlice().getItems().get(0).getFormat();
+        }
+        boolean hasRowAction = mRowAction != null;
+        if (endItems.isEmpty()) {
+            if (hasRowAction) setViewClickable(this, true);
+            return;
+        }
+
+        // If we're here we might be able to show end items
+        int itemCount = 0;
+        boolean firstItemIsADefaultToggle = false;
+        for (int i = 0; i < endItems.size(); i++) {
+            final SliceItem endItem = endItems.get(i);
+            final String endFormat = endItem.hasHint(HINT_SHORTCUT)
+                    ? FORMAT_ACTION
+                    : endItem.getSlice().getItems().get(0).getFormat();
+            // Only show one type of format at the end of the slice, use whatever is first
+            if (itemCount < MAX_END_ITEMS
+                    && (desiredFormat.equals(endFormat)
+                    || FORMAT_TIMESTAMP.equals(endFormat))) {
+                final EventInfo info = new EventInfo(getMode(),
+                        EventInfo.ACTION_TYPE_BUTTON,
+                        EventInfo.ROW_TYPE_LIST, mRowIndex);
+                info.setPosition(EventInfo.POSITION_END, i,
+                        Math.min(endItems.size(), MAX_END_ITEMS));
+                if (addItem(endItem, mTintColor, false /* isStart */, mPadding, info)) {
+                    itemCount++;
+                    if (itemCount == 1) {
+                        firstItemIsADefaultToggle = !mToggles.isEmpty()
+                                && SliceQuery.find(endItem.getSlice(), FORMAT_IMAGE) == null;
+                    }
+                }
+            }
+        }
+
+        boolean hasEndItemAction = FORMAT_ACTION.contentEquals(desiredFormat);
+        // If there is a row action and the first end item is a default toggle, show the divider.
+        mDivider.setVisibility(hasRowAction && firstItemIsADefaultToggle
+                ? View.VISIBLE : View.GONE);
+        if (hasRowAction) {
+            if (itemCount > 0 && hasEndItemAction) {
+                setViewClickable(mContent, true);
+            } else {
+                setViewClickable(this, true);
+            }
+        } else {
+            // If the only end item is an action, make the whole row clickable.
+            if (mRowContent.endItemsContainAction() && itemCount == 1) {
+                SliceItem unwrappedActionItem = endItems.get(0).getSlice().getItems().get(0);
+                if (!SUBTYPE_TOGGLE.equals(unwrappedActionItem.getSubType())) {
+                    mRowAction = new ActionContent(endItems.get(0));
+                }
+                setViewClickable(this, true);
+            }
+        }
+    }
+
+    private void addRange(final SliceItem range) {
+        final ProgressBar progressBar;
+        if (FORMAT_ACTION.equals(range.getFormat())) {
+            // An input range is displayed as a seek bar
+            progressBar = mSeekBar;
+            mSeekBar.setVisibility(View.VISIBLE);
+            SliceItem thumb = SliceQuery.find(range, FORMAT_IMAGE);
+            if (thumb != null) {
+                mSeekBar.setThumb(thumb.getIcon().loadDrawable(getContext()));
+            }
+            mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+                @Override
+                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                    try {
+                        PendingIntent pi = range.getAction();
+                        Intent i = new Intent().putExtra(EXTRA_RANGE_VALUE, progress);
+                        // TODO: sending this PendingIntent should be rate limited.
+                        pi.send(getContext(), 0, i, null, null);
+                    } catch (CanceledException e) { }
+                }
+
+                @Override
+                public void onStartTrackingTouch(SeekBar seekBar) { }
+
+                @Override
+                public void onStopTrackingTouch(SeekBar seekBar) { }
+            });
+        } else {
+            // A range is displayed as a progress bar.
+            progressBar = mProgressBar;
+            mProgressBar.setVisibility(View.VISIBLE);
+        }
+        SliceItem max = SliceQuery.findSubtype(range, FORMAT_INT, SUBTYPE_MAX);
+        if (max != null) {
+            progressBar.setMax(max.getInt());
+        }
+        SliceItem progress = SliceQuery.findSubtype(range, FORMAT_INT, SUBTYPE_VALUE);
+        if (progress != null) {
+            progressBar.setProgress(progress.getInt());
+        }
+    }
+
+    /**
+     * Add a toggle view to container.
+     */
+    private void addToggle(final ActionContent actionContent, int color, ViewGroup container) {
+        // Check if this is a custom toggle
+        final CompoundButton toggle;
+        if (actionContent.isCustomToggle()) {
+            Icon checkedIcon = actionContent.getIconItem().getIcon();
+            if (color != -1) {
+                // TODO - Should custom toggle buttons be tinted? What if the app wants diff
+                // colors per state?
+                checkedIcon.setTint(color);
+            }
+            toggle = new ToggleButton(getContext());
+            ((ToggleButton) toggle).setTextOff("");
+            ((ToggleButton) toggle).setTextOn("");
+            toggle.setBackground(checkedIcon.loadDrawable(getContext()));
+            container.addView(toggle);
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) toggle.getLayoutParams();
+            lp.width = mIconSize;
+            lp.height = mIconSize;
+        } else {
+            toggle = new Switch(getContext());
+            container.addView(toggle);
+        }
+        toggle.setChecked(actionContent.isChecked());
+        toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+            @Override
+            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+                try {
+                    PendingIntent pi = actionContent.getActionItem().getAction();
+                    Intent i = new Intent().putExtra(EXTRA_TOGGLE_STATE, isChecked);
+                    pi.send(getContext(), 0, i, null, null);
+                    if (mObserver != null) {
+                        final EventInfo info = new EventInfo(getMode(),
+                                EventInfo.ACTION_TYPE_TOGGLE,
+                                EventInfo.ROW_TYPE_LIST, mRowIndex);
+                        info.state = isChecked ? EventInfo.STATE_ON : EventInfo.STATE_OFF;
+                        mObserver.onSliceAction(info, actionContent.getSliceItem());
+                    }
+                } catch (CanceledException e) {
+                    toggle.setSelected(!isChecked);
+                }
+            }
+        });
+        mToggles.add(toggle);
+    }
+
+    /**
+     * Adds simple items to a container. Simple items include actions with icons, images, or
+     * timestamps.
+     */
+    private boolean addItem(SliceItem sliceItem, int color, boolean isStart, int padding,
+            final EventInfo info) {
+        SliceItem image = null;
+        SliceItem action = null;
+        SliceItem timeStamp = null;
+        ActionContent actionContent = null;
+        ViewGroup container = isStart ? mStartContainer : mEndContainer;
+        if (FORMAT_SLICE.equals(sliceItem.getFormat())) {
+            // It's an action.... let's make it so
+            if (sliceItem.hasHint(HINT_SHORTCUT)) {
+                actionContent = new ActionContent(sliceItem);
+            } else {
+                sliceItem = sliceItem.getSlice().getItems().get(0);
+            }
+        }
+        if (actionContent != null) {
+            if (actionContent.isToggle()) {
+                addToggle(actionContent, color, container);
+                return true;
+            }
+            action = actionContent.getActionItem();
+            image = actionContent.getIconItem();
+        }
+        if (FORMAT_IMAGE.equals(sliceItem.getFormat())) {
+            image = sliceItem;
+        } else if (FORMAT_TIMESTAMP.equals(sliceItem.getFormat())) {
+            timeStamp = sliceItem;
+        }
+        View addedView = null;
+        if (image != null) {
+            ImageView iv = new ImageView(getContext());
+            iv.setImageIcon(image.getIcon());
+            if (color != -1 && !sliceItem.hasHint(HINT_NO_TINT)) {
+                iv.setColorFilter(color);
+            }
+            container.addView(iv);
+            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) iv.getLayoutParams();
+            lp.width = mIconSize;
+            lp.height = mIconSize;
+            lp.setMarginStart(padding);
+            addedView = iv;
+        } else if (timeStamp != null) {
+            TextView tv = new TextView(getContext());
+            tv.setText(SliceViewUtil.getRelativeTimeString(sliceItem.getTimestamp()));
+            tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, mSubtitleSize);
+            tv.setTextColor(mSubtitleColor);
+            container.addView(tv);
+            addedView = tv;
+        }
+        if (action != null && addedView != null) {
+            final SliceItem sliceAction = action;
+            addedView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    try {
+                        sliceAction.getAction().send();
+                        if (mObserver != null) {
+                            mObserver.onSliceAction(info, sliceAction);
+                        }
+                    } catch (CanceledException e) {
+                        e.printStackTrace();
+                    }
+                }
+            });
+            addedView.setBackground(SliceViewUtil.getDrawable(getContext(),
+                    android.R.attr.selectableItemBackground));
+        }
+        return addedView != null;
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (mRowAction != null && mRowAction.getActionItem() != null && !mRowAction.isToggle()) {
+            // Check for a row action
+            try {
+                mRowAction.getActionItem().getAction().send();
+                if (mObserver != null) {
+                    EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_CONTENT,
+                            EventInfo.ROW_TYPE_LIST, mRowIndex);
+                    mObserver.onSliceAction(info, mRowAction.getSliceItem());
+                }
+            } catch (CanceledException e) {
+                Log.w(TAG, "PendingIntent for slice cannot be sent", e);
+            }
+        } else if (mToggles.size() == 1) {
+            // If there is only one toggle and no row action, just toggle it.
+            mToggles.get(0).toggle();
+        }
+    }
+
+    private void setViewClickable(View layout, boolean isClickable) {
+        layout.setOnClickListener(isClickable ? this : null);
+        layout.setBackground(isClickable ? SliceViewUtil.getDrawable(getContext(),
+                android.R.attr.selectableItemBackground) : null);
+        layout.setClickable(isClickable);
+    }
+
+    @Override
+    public void resetView() {
+        setViewClickable(this, false);
+        setViewClickable(mContent, false);
+        mStartContainer.removeAllViews();
+        mEndContainer.removeAllViews();
+        mPrimaryText.setText(null);
+        mSecondaryText.setText(null);
+        mToggles.clear();
+        mRowAction = null;
+        mDivider.setVisibility(View.GONE);
+        mSeekBar.setVisibility(View.GONE);
+        mProgressBar.setVisibility(View.GONE);
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/ShortcutView.java b/slices/view/src/main/java/androidx/app/slice/widget/ShortcutView.java
new file mode 100644
index 0000000..75e97b1
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/ShortcutView.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+import static android.app.slice.Slice.SUBTYPE_SOURCE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.net.Uri;
+import android.support.annotation.RestrictTo;
+import android.widget.ImageView;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
+
+/**
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(23)
+public class ShortcutView extends SliceChildView {
+
+    private static final String TAG = "ShortcutView";
+
+    private Slice mSlice;
+    private Uri mUri;
+    private SliceItem mActionItem;
+    private SliceItem mLabel;
+    private SliceItem mIcon;
+
+    private int mLargeIconSize;
+    private int mSmallIconSize;
+
+    public ShortcutView(Context context) {
+        super(context);
+        final Resources res = getResources();
+        mSmallIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_icon_size);
+        mLargeIconSize = res.getDimensionPixelSize(R.dimen.abc_slice_shortcut_size);
+    }
+
+    @Override
+    public void setSlice(Slice slice) {
+        resetView();
+        mSlice = slice;
+        determineShortcutItems(getContext(), slice);
+        SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
+        if (colorItem == null) {
+            colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
+        }
+        final int color = colorItem != null
+                ? colorItem.getInt()
+                : SliceViewUtil.getColorAccent(getContext());
+        ShapeDrawable circle = new ShapeDrawable(new OvalShape());
+        circle.setTint(color);
+        ImageView iv = new ImageView(getContext());
+        iv.setBackground(circle);
+        addView(iv);
+        if (mIcon != null) {
+            final boolean isLarge = mIcon.hasHint(HINT_LARGE)
+                    || SUBTYPE_SOURCE.equals(mIcon.getSubType());
+            final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize;
+            SliceViewUtil.createCircledIcon(getContext(), iconSize, mIcon.getIcon(),
+                    isLarge, this /* parent */);
+            mUri = slice.getUri();
+            setClickable(true);
+        } else {
+            setClickable(false);
+        }
+    }
+
+    @Override
+    public @SliceView.SliceMode int getMode() {
+        return SliceView.MODE_SHORTCUT;
+    }
+
+    @Override
+    public boolean performClick() {
+        if (!callOnClick()) {
+            try {
+                if (mActionItem != null) {
+                    mActionItem.getAction().send();
+                } else {
+                    Intent intent = new Intent(Intent.ACTION_VIEW).setData(mUri);
+                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    getContext().startActivity(intent);
+                }
+                if (mObserver != null) {
+                    EventInfo ei = new EventInfo(SliceView.MODE_SHORTCUT,
+                            EventInfo.ACTION_TYPE_BUTTON,
+                            EventInfo.ROW_TYPE_SHORTCUT, 0 /* rowIndex */);
+                    SliceItem interactedItem = mActionItem != null
+                            ? mActionItem
+                            : new SliceItem(mSlice, FORMAT_SLICE, null /* subtype */,
+                                    mSlice.getHints());
+                    mObserver.onSliceAction(ei, interactedItem);
+                }
+            } catch (CanceledException e) {
+                e.printStackTrace();
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Looks at the slice and determines which items are best to use to compose the shortcut.
+     */
+    private void determineShortcutItems(Context context, Slice slice) {
+        SliceItem titleItem = SliceQuery.find(slice, FORMAT_ACTION,
+                HINT_TITLE, null);
+
+        if (titleItem != null) {
+            // Preferred case: hinted action containing hinted image and text
+            mActionItem = titleItem;
+            mIcon = SliceQuery.find(titleItem.getSlice(), FORMAT_IMAGE, HINT_TITLE,
+                    null);
+            mLabel = SliceQuery.find(titleItem.getSlice(), FORMAT_TEXT, HINT_TITLE,
+                    null);
+        } else {
+            // No hinted action; just use the first one
+            mActionItem = SliceQuery.find(slice, FORMAT_ACTION, (String) null, null);
+        }
+        // First fallback: any hinted image and text
+        if (mIcon == null) {
+            mIcon = SliceQuery.find(slice, FORMAT_IMAGE, HINT_TITLE,
+                    null);
+        }
+        if (mLabel == null) {
+            mLabel = SliceQuery.find(slice, FORMAT_TEXT, HINT_TITLE,
+                    null);
+        }
+        // Second fallback: first image and text
+        if (mIcon == null) {
+            mIcon = SliceQuery.find(slice, FORMAT_IMAGE, (String) null,
+                    null);
+        }
+        if (mLabel == null) {
+            mLabel = SliceQuery.find(slice, FORMAT_TEXT, (String) null,
+                    null);
+        }
+        // Final fallback: use app info
+        if (mIcon == null || mLabel == null || mActionItem == null) {
+            PackageManager pm = context.getPackageManager();
+            ProviderInfo providerInfo = pm.resolveContentProvider(
+                    slice.getUri().getAuthority(), 0);
+            ApplicationInfo appInfo = providerInfo.applicationInfo;
+            if (appInfo != null) {
+                if (mIcon == null) {
+                    Slice.Builder sb = new Slice.Builder(slice.getUri());
+                    Drawable icon = pm.getApplicationIcon(appInfo);
+                    sb.addIcon(SliceViewUtil.createIconFromDrawable(icon), HINT_LARGE);
+                    mIcon = sb.build().getItems().get(0);
+                }
+                if (mLabel == null) {
+                    Slice.Builder sb = new Slice.Builder(slice.getUri());
+                    sb.addText(pm.getApplicationLabel(appInfo), null);
+                    mLabel = sb.build().getItems().get(0);
+                }
+                if (mActionItem == null) {
+                    mActionItem = new SliceItem(PendingIntent.getActivity(context, 0,
+                            pm.getLaunchIntentForPackage(appInfo.packageName), 0),
+                            new Slice.Builder(slice.getUri()).build(), FORMAT_SLICE,
+                            null /* subtype */, null);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void resetView() {
+        mSlice = null;
+        mUri = null;
+        mActionItem = null;
+        mLabel = null;
+        mIcon = null;
+        setBackground(null);
+        removeAllViews();
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
new file mode 100644
index 0000000..9a5279f
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceChildView.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.view.R;
+
+/**
+ * Base class for children views of {@link SliceView}.
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+public abstract class SliceChildView extends FrameLayout {
+
+    protected SliceView.OnSliceActionListener mObserver;
+    protected int mMode;
+    protected int mTintColor = -1;
+    protected int mTitleColor;
+    protected int mSubtitleColor;
+    protected int mHeaderTitleSize;
+    protected int mHeaderSubtitleSize;
+    protected int mTitleSize;
+    protected int mSubtitleSize;
+    protected int mGridTitleSize;
+    protected int mGridSubtitleSize;
+
+    public SliceChildView(@NonNull Context context) {
+        super(context);
+    }
+
+    public SliceChildView(Context context, AttributeSet attributeSet) {
+        this(context);
+    }
+
+
+    /**
+     * Set the mode of the slice being presented.
+     */
+    public void setMode(int mode) {
+        mMode = mode;
+    }
+
+    /**
+     * @return the mode of the slice being presented.
+     */
+    @SliceView.SliceMode
+    public int getMode() {
+        return mMode;
+    }
+
+    /**
+     * @param slice the slice to show in this view.
+     */
+    public abstract void setSlice(Slice slice);
+
+    /**
+     * Called when the view should be reset.
+     */
+    public abstract void resetView();
+
+    /**
+     * @return the view.
+     */
+    public View getView() {
+        return this;
+    }
+
+    /**
+     * Sets a custom color to use for tinting elements like icons for this view.
+     */
+    public void setTint(@ColorInt int tintColor) {
+        mTintColor = tintColor;
+    }
+
+    /**
+     * Sets the observer to notify when an interaction events occur on the view.
+     */
+    public void setSliceActionListener(SliceView.OnSliceActionListener observer) {
+        mObserver = observer;
+    }
+
+    /**
+     * Populates style information for this view.
+     */
+    public void setStyle(AttributeSet attrs) {
+        TypedArray a = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.SliceView,
+                R.attr.sliceViewStyle, R.style.Widget_SliceView);
+        try {
+            int themeColor = a.getColor(R.styleable.SliceView_tintColor, -1);
+            mTintColor = themeColor != -1 ? themeColor : mTintColor;
+            mTitleColor = a.getColor(R.styleable.SliceView_titleColor, 0);
+            mSubtitleColor = a.getColor(R.styleable.SliceView_subtitleColor, 0);
+            mHeaderTitleSize = (int) a.getDimension(
+                    R.styleable.SliceView_headerTitleSize, 0);
+            mHeaderSubtitleSize = (int) a.getDimension(
+                    R.styleable.SliceView_headerSubtitleSize, 0);
+            mTitleSize = (int) a.getDimension(R.styleable.SliceView_titleSize, 0);
+            mSubtitleSize = (int) a.getDimension(
+                    R.styleable.SliceView_subtitleSize, 0);
+            mGridTitleSize = (int) a.getDimension(R.styleable.SliceView_gridTitleSize, 0);
+            mGridSubtitleSize = (int) a.getDimension(
+                    R.styleable.SliceView_gridSubtitleSize, 0);
+        } finally {
+            a.recycle();
+        }
+    }
+
+    /**
+     * Called when the slice being displayed in this view is an element of a larger list.
+     */
+    public void setSliceItem(SliceItem slice, boolean isHeader, int rowIndex,
+            SliceView.OnSliceActionListener observer) {
+        // Do nothing
+    }
+
+    /**
+     * Sets the slice actions for this view.
+     */
+    public void setSliceActions(List<SliceItem> actions) {
+        // Do nothing
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceLiveData.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceLiveData.java
new file mode 100644
index 0000000..5da98d2
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceLiveData.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.app.slice.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY;
+
+import android.arch.lifecycle.LiveData;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+
+import java.util.Arrays;
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceManager;
+import androidx.app.slice.SliceSpec;
+import androidx.app.slice.SliceSpecs;
+
+/**
+ * Class with factory methods for creating LiveData that observes slices.
+ *
+ * @see #fromUri(Context, Uri)
+ * @see LiveData
+ */
+public final class SliceLiveData {
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public static final List<SliceSpec> SUPPORTED_SPECS = Arrays.asList(SliceSpecs.BASIC,
+            SliceSpecs.LIST);
+
+    /**
+     * Produces an {@link LiveData} that tracks a Slice for a given Uri. To use
+     * this method your app must have the permission to the slice Uri or hold
+     * {@link android.Manifest.permission#BIND_SLICE}).
+     */
+    public static LiveData<Slice> fromUri(Context context, Uri uri) {
+        return new SliceLiveDataImpl(context.getApplicationContext(), uri);
+    }
+
+    /**
+     * Produces an {@link LiveData} that tracks a Slice for a given Intent. To use
+     * this method your app must have the permission to the slice Uri or hold
+     * {@link android.Manifest.permission#BIND_SLICE}).
+     */
+    public static LiveData<Slice> fromIntent(@NonNull Context context, @NonNull Intent intent) {
+        return new SliceLiveDataImpl(context.getApplicationContext(), intent);
+    }
+
+    private static class SliceLiveDataImpl extends LiveData<Slice> {
+        private final Intent mIntent;
+        private final SliceManager mSliceManager;
+        private Uri mUri;
+
+        private SliceLiveDataImpl(Context context, Uri uri) {
+            super();
+            mSliceManager = SliceManager.getInstance(context);
+            mUri = uri;
+            mIntent = null;
+            // TODO: Check if uri points at a Slice?
+        }
+
+        private SliceLiveDataImpl(Context context, Intent intent) {
+            super();
+            mSliceManager = SliceManager.getInstance(context);
+            mUri = null;
+            mIntent = intent;
+        }
+
+        @Override
+        protected void onActive() {
+            AsyncTask.execute(mUpdateSlice);
+            if (mUri != null) {
+                mSliceManager.registerSliceCallback(mUri, mSliceCallback);
+            }
+        }
+
+        @Override
+        protected void onInactive() {
+            if (mUri != null) {
+                mSliceManager.unregisterSliceCallback(mUri, mSliceCallback);
+            }
+        }
+
+        private final Runnable mUpdateSlice = new Runnable() {
+            @Override
+            public void run() {
+                Slice s = mUri != null ? mSliceManager.bindSlice(mUri)
+                        : mSliceManager.bindSlice(mIntent);
+                if (mUri == null && s != null) {
+                    mUri = s.getUri();
+                    mSliceManager.registerSliceCallback(mUri, mSliceCallback);
+                }
+                postValue(s);
+            }
+        };
+
+        private final SliceManager.SliceCallback mSliceCallback = new SliceManager.SliceCallback() {
+            @Override
+            public void onSliceUpdated(@NonNull Slice s) {
+                postValue(s);
+            }
+        };
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
new file mode 100644
index 0000000..3648234
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceView.java
@@ -0,0 +1,477 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import static android.app.slice.Slice.HINT_HORIZONTAL;
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+import static android.app.slice.SliceItem.FORMAT_INT;
+
+import android.arch.lifecycle.Observer;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.ColorDrawable;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+import androidx.app.slice.Slice;
+import androidx.app.slice.SliceItem;
+import androidx.app.slice.SliceUtils;
+import androidx.app.slice.core.SliceQuery;
+import androidx.app.slice.view.R;
+
+/**
+ * A view for displaying a {@link Slice} which is a piece of app content and actions. SliceView is
+ * able to present slice content in a templated format outside of the associated app. The way this
+ * content is displayed depends on the structure of the slice, the hints associated with the
+ * content, and the mode that SliceView is configured for. The modes that SliceView supports are:
+ * <ul>
+ * <li><b>Shortcut</b>: A shortcut is presented as an icon and a text label representing the main
+ * content or action associated with the slice.</li>
+ * <li><b>Small</b>: The small format has a restricted height and can present a single
+ * {@link SliceItem} or a limited collection of items.</li>
+ * <li><b>Large</b>: The large format displays multiple small templates in a list, if scrolling is
+ * not enabled (see {@link #setScrollable(boolean)}) the view will show as many items as it can
+ * comfortably fit.</li>
+ * </ul>
+ * <p>
+ * When constructing a slice, the contents of it can be annotated with hints, these provide the OS
+ * with some information on how the content should be displayed. For example, text annotated with
+ * {@link android.app.slice.Slice#HINT_TITLE} would be placed in the title position of a template.
+ * A slice annotated with {@link android.app.slice.Slice#HINT_LIST} would present the child items
+ * of that slice in a list.
+ * <p>
+ * Example usage:
+ *
+ * <pre class="prettyprint">
+ * SliceView v = new SliceView(getContext());
+ * v.setMode(desiredMode);
+ * LiveData<Slice> liveData = SliceLiveData.fromUri(sliceUri);
+ * liveData.observe(lifecycleOwner, v);
+ * </pre>
+ * @see SliceLiveData
+ */
+public class SliceView extends ViewGroup implements Observer<Slice> {
+
+    private static final String TAG = "SliceView";
+
+    /**
+     * Implement this interface to be notified of interactions with the slice displayed
+     * in this view.
+     * @see EventInfo
+     */
+    public interface OnSliceActionListener {
+        /**
+         * Called when an interaction has occurred with an element in this view.
+         * @param info the type of event that occurred.
+         * @param item the specific item within the {@link Slice} that was interacted with.
+         */
+        void onSliceAction(@NonNull EventInfo info, @NonNull SliceItem item);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+            MODE_SMALL, MODE_LARGE, MODE_SHORTCUT
+    })
+    public @interface SliceMode {}
+
+    /**
+     * Mode indicating this slice should be presented in small template format.
+     */
+    public static final int MODE_SMALL       = 1;
+    /**
+     * Mode indicating this slice should be presented in large template format.
+     */
+    public static final int MODE_LARGE       = 2;
+    /**
+     * Mode indicating this slice should be presented as an icon. A shortcut requires an intent,
+     * icon, and label. This can be indicated by using {@link android.app.slice.Slice#HINT_TITLE}
+     * on an action in a slice.
+     */
+    public static final int MODE_SHORTCUT    = 3;
+
+    /**
+     * Will select the type of slice binding based on size of the View. TODO: Put in some info about
+     * that selection.
+     */
+    private static final int MODE_AUTO = 0;
+
+    private int mMode = MODE_AUTO;
+    private Slice mCurrentSlice;
+    private SliceChildView mCurrentView;
+    private List<SliceItem> mActions;
+    private final ActionRow mActionRow;
+
+    private boolean mShowActions = false;
+    private boolean mIsScrollable = true;
+
+    private final int mShortcutSize;
+    private AttributeSet mAttrs;
+    private int mThemeTintColor = -1;
+
+    private OnSliceActionListener mSliceObserver;
+
+    public SliceView(Context context) {
+        this(context, null);
+    }
+
+    public SliceView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, R.attr.sliceViewStyle);
+    }
+
+    public SliceView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, R.style.Widget_SliceView);
+    }
+
+    public SliceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mAttrs = attrs;
+        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SliceView,
+                defStyleAttr, defStyleRes);
+        try {
+            mThemeTintColor = a.getColor(R.styleable.SliceView_tintColor, -1);
+        } finally {
+            a.recycle();
+        }
+        // TODO: action row background should support light / dark / maybe presenter customization
+        mActionRow = new ActionRow(getContext(), true);
+        mActionRow.setBackground(new ColorDrawable(0xffeeeeee));
+        mCurrentView = new LargeTemplateView(getContext());
+        addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
+        addView(mActionRow, getChildLp(mActionRow));
+        mShortcutSize = getContext().getResources()
+                .getDimensionPixelSize(R.dimen.abc_slice_shortcut_size);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int width = MeasureSpec.getSize(widthMeasureSpec);
+        int childWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int childHeight = MeasureSpec.getSize(heightMeasureSpec);
+        if (MODE_SHORTCUT == mMode) {
+            // TODO: consider scaling the shortcut to fit
+            childWidth = mShortcutSize;
+            width = mShortcutSize;
+        }
+        final int left = getPaddingLeft();
+        final int top = getPaddingTop();
+        final int right = getPaddingRight();
+        final int bot = getPaddingBottom();
+
+        // Measure the children without the padding
+        childWidth -= left + right;
+        childHeight -= top + bot;
+        int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
+        int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY);
+        measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);
+
+        // Figure out parent height
+        int actionHeight = mActionRow.getVisibility() != View.GONE
+                ? mActionRow.getMeasuredHeight()
+                : 0;
+        int currViewHeight = mCurrentView.getView().getMeasuredHeight() + top + bot;
+        int newHeightSpec = MeasureSpec.makeMeasureSpec(currViewHeight + actionHeight,
+                MeasureSpec.EXACTLY);
+        // Figure out parent width
+        width += left + right;
+        setMeasuredDimension(width, newHeightSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        View v = mCurrentView.getView();
+        final int left = getPaddingLeft();
+        final int top = getPaddingTop();
+        final int right = getPaddingRight();
+        final int bottom = getPaddingBottom();
+        v.layout(left, top, left + v.getMeasuredWidth(), top + v.getMeasuredHeight());
+        if (mActionRow.getVisibility() != View.GONE) {
+            mActionRow.layout(left,
+                    top + v.getMeasuredHeight() + bottom,
+                    left + mActionRow.getMeasuredWidth() + right,
+                    top + v.getMeasuredHeight() + bottom + mActionRow.getMeasuredHeight());
+        }
+    }
+
+    @Override
+    public void onChanged(@Nullable Slice slice) {
+        setSlice(slice);
+    }
+
+    /**
+     * Populates this view to the provided {@link Slice}.
+     *
+     * This will not update automatically if the slice content changes, for live
+     * content see {@link SliceLiveData}.
+     */
+    public void setSlice(@Nullable Slice slice) {
+        if (slice != null) {
+            if (mCurrentSlice == null || mCurrentSlice.getUri() != slice.getUri()) {
+                // New slice, new actions
+                mActions = SliceUtils.getSliceActions(slice);
+                mCurrentView.resetView();
+            }
+        } else {
+            // No slice, no actions
+            mActions = null;
+        }
+        mCurrentSlice = slice;
+        reinflate();
+    }
+
+    /**
+     * Returns the slice actions presented in this view.
+     */
+    @Nullable
+    public List<SliceItem> getSliceActions() {
+        return mActions;
+    }
+
+    /**
+     * Sets the slice actions to display for the slice contained in this view. Normally SliceView
+     * will automatically show actions, however, it is possible to reorder or omit actions on the
+     * view using this method. This is generally discouraged.
+     * <p>
+     * It is required that the slice be set on this view before actions can be set, otherwise
+     * this will throw {@link IllegalStateException}. If any of the actions supplied are not
+     * available for the slice set on this view (i.e. the action is not returned by
+     * {@link SliceUtils#getSliceActions(Slice)} this will throw {@link IllegalArgumentException}.
+     */
+    public void setSliceActions(@Nullable List<SliceItem> newActions) {
+        // Check that these actions are part of available set
+        if (mCurrentSlice == null) {
+            throw new IllegalStateException("Trying to set actions on a view without a slice");
+        }
+        List<SliceItem> availableActions = SliceUtils.getSliceActions(mCurrentSlice);
+        if (availableActions != null && newActions != null) {
+            for (int i = 0; i < newActions.size(); i++) {
+                if (!availableActions.contains(newActions.get(i))) {
+                    throw new IllegalArgumentException(
+                            "Trying to set an action that isn't available: " + newActions.get(i));
+                }
+            }
+        }
+        mActions = newActions;
+        updateActions();
+    }
+
+    /**
+     * Set the mode this view should present in.
+     */
+    public void setMode(@SliceMode int mode) {
+        setMode(mode, false /* animate */);
+    }
+
+    /**
+     * Set whether this view should allow scrollable content when presenting in {@link #MODE_LARGE}.
+     */
+    public void setScrollable(boolean isScrollable) {
+        mIsScrollable = isScrollable;
+        reinflate();
+    }
+
+    /**
+     * Sets the listener to notify when an interaction events occur on the view.
+     * @see EventInfo
+     */
+    public void setOnSliceActionListener(@Nullable OnSliceActionListener observer) {
+        mSliceObserver = observer;
+        mCurrentView.setSliceActionListener(mSliceObserver);
+    }
+
+    /**
+     * Contents of a slice such as icons, text, and controls (e.g. toggle) can be tinted. Normally
+     * a color for tinting will be provided by the slice. Using this method will override
+     * this color information and instead tint elements with the provided color.
+     *
+     * @param tintColor the color to use for tinting contents of this view.
+     */
+    public void setTint(int tintColor) {
+        mThemeTintColor = tintColor;
+        mCurrentView.setTint(tintColor);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void setMode(@SliceMode int mode, boolean animate) {
+        if (animate) {
+            Log.e(TAG, "Animation not supported yet");
+        }
+        if (mMode == mode) {
+            return;
+        }
+        mMode = mode;
+        reinflate();
+    }
+
+    /**
+     * @return the mode this view is presenting in.
+     */
+    public @SliceMode int getMode() {
+        if (mMode == MODE_AUTO) {
+            return MODE_LARGE;
+        }
+        return mMode;
+    }
+
+    /**
+     * @hide
+     *
+     * Whether this view should show a row of actions with it.
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void setShowActionRow(boolean show) {
+        mShowActions = show;
+        updateActions();
+    }
+
+    /**
+     * @return whether this view is showing a row of actions.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public boolean isShowingActionRow() {
+        return mShowActions;
+    }
+
+    private SliceChildView createView(int mode, boolean isGrid) {
+        switch (mode) {
+            case MODE_SHORTCUT:
+                return new ShortcutView(getContext());
+            case MODE_SMALL:
+                return isGrid ? new GridRowView(getContext()) : new RowView(getContext());
+        }
+        return new LargeTemplateView(getContext());
+    }
+
+    private void reinflate() {
+        if (mCurrentSlice == null) {
+            mCurrentView.resetView();
+            return;
+        }
+        ListContent lc = new ListContent(mCurrentSlice);
+        if (!lc.isValid()) {
+            mCurrentView.resetView();
+            mCurrentView.setVisibility(View.GONE);
+            return;
+        }
+        // TODO: Smarter mapping here from one state to the next.
+        int mode = getMode();
+        boolean reuseView = mode == mCurrentView.getMode();
+        SliceItem header = lc.getHeaderItem();
+        boolean isSmallGrid = header != null && SliceQuery.hasHints(header, HINT_HORIZONTAL);
+        if (reuseView && mode == MODE_SMALL) {
+            reuseView = (mCurrentView instanceof GridRowView) == isSmallGrid;
+        }
+        if (!reuseView) {
+            removeAllViews();
+            mCurrentView = createView(mode, isSmallGrid);
+            if (mSliceObserver != null) {
+                mCurrentView.setSliceActionListener(mSliceObserver);
+            }
+            addView(mCurrentView.getView(), getChildLp(mCurrentView.getView()));
+            addView(mActionRow, getChildLp(mActionRow));
+            mCurrentView.setMode(mMode);
+        }
+        // Scrolling
+        if (mode == MODE_LARGE && (mCurrentView instanceof LargeTemplateView)) {
+            ((LargeTemplateView) mCurrentView).setScrollable(mIsScrollable);
+        }
+        // Styles
+        mCurrentView.setStyle(mAttrs);
+        mCurrentView.setTint(getTintColor());
+        mCurrentView.setVisibility(lc.isValid() ? View.VISIBLE : View.GONE);
+        // Set the slice
+        mCurrentView.setSlice(mCurrentSlice);
+        updateActions();
+    }
+
+    private void updateActions() {
+        if (mActions == null || mActions.isEmpty()) {
+            // No actions, hide the row, clear out the view
+            mActionRow.setVisibility(View.GONE);
+            mCurrentView.setSliceActions(null);
+            return;
+        }
+
+        // TODO: take priority attached to actions into account
+        if (mShowActions && mMode != MODE_SHORTCUT && mActions.size() >= 2) {
+            // Show in action row if available
+            mActionRow.setActions(mActions, getTintColor());
+            mActionRow.setVisibility(View.VISIBLE);
+            // Hide them on the template
+            mCurrentView.setSliceActions(null);
+        } else if (mActions.size() > 0) {
+            // Otherwise set them on the template
+            mCurrentView.setSliceActions(mActions);
+            mActionRow.setVisibility(View.GONE);
+        }
+    }
+
+    private int getTintColor() {
+        if (mThemeTintColor != -1) {
+            // Theme has specified a color, use that
+            return mThemeTintColor;
+        } else {
+            final SliceItem colorItem = SliceQuery.findSubtype(
+                    mCurrentSlice, FORMAT_INT, SUBTYPE_COLOR);
+            return colorItem != null
+                    ? colorItem.getInt()
+                    : SliceViewUtil.getColorAccent(getContext());
+        }
+    }
+
+    private LayoutParams getChildLp(View child) {
+        if (child instanceof ShortcutView) {
+            return new LayoutParams(mShortcutSize, mShortcutSize);
+        } else {
+            return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+        }
+    }
+
+    /**
+     * @return String representation of the provided mode.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public static String modeToString(@SliceMode int mode) {
+        switch(mode) {
+            case MODE_AUTO:
+                return "MODE AUTO";
+            case MODE_SHORTCUT:
+                return "MODE SHORTCUT";
+            case MODE_SMALL:
+                return "MODE SMALL";
+            case MODE_LARGE:
+                return "MODE LARGE";
+            default:
+                return "unknown mode: " + mode;
+        }
+    }
+}
diff --git a/slices/view/src/main/java/androidx/app/slice/widget/SliceViewUtil.java b/slices/view/src/main/java/androidx/app/slice/widget/SliceViewUtil.java
new file mode 100644
index 0000000..12fe7c4
--- /dev/null
+++ b/slices/view/src/main/java/androidx/app/slice/widget/SliceViewUtil.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.app.slice.widget;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.support.annotation.AttrRes;
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.text.format.DateUtils;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import java.util.Calendar;
+
+/**
+ * A bunch of utilities for slice UI.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+@TargetApi(23)
+public class SliceViewUtil {
+
+    /**
+     */
+    @ColorInt
+    public static int getColorAccent(@NonNull Context context) {
+        return getColorAttr(context, android.R.attr.colorAccent);
+    }
+
+    /**
+     */
+    @ColorInt
+    public static int getColorError(@NonNull Context context) {
+        return getColorAttr(context, android.R.attr.colorError);
+    }
+
+    /**
+     */
+    @ColorInt
+    public static int getDefaultColor(@NonNull Context context, int resId) {
+        final ColorStateList list = context.getResources().getColorStateList(resId,
+                context.getTheme());
+
+        return list.getDefaultColor();
+    }
+
+    /**
+     */
+    @ColorInt
+    public static int getDisabled(@NonNull Context context, int inputColor) {
+        return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
+    }
+
+    /**
+     */
+    @ColorInt
+    public static int applyAlphaAttr(@NonNull Context context, @AttrRes int attr, int inputColor) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        float alpha = ta.getFloat(0, 0);
+        ta.recycle();
+        return applyAlpha(alpha, inputColor);
+    }
+
+    /**
+     */
+    @ColorInt
+    public static int applyAlpha(float alpha, int inputColor) {
+        alpha *= Color.alpha(inputColor);
+        return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor),
+                Color.blue(inputColor));
+    }
+
+    /**
+     */
+    @ColorInt
+    public static int getColorAttr(@NonNull Context context, @AttrRes int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        @ColorInt int colorAccent = ta.getColor(0, 0);
+        ta.recycle();
+        return colorAccent;
+    }
+
+    /**
+     */
+    public static int getThemeAttr(@NonNull Context context, @AttrRes int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        int theme = ta.getResourceId(0, 0);
+        ta.recycle();
+        return theme;
+    }
+
+    /**
+     */
+    public static Drawable getDrawable(@NonNull Context context, @AttrRes int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[] {
+                attr
+        });
+        Drawable drawable = ta.getDrawable(0);
+        ta.recycle();
+        return drawable;
+    }
+
+    /**
+     */
+    public static Icon createIconFromDrawable(Drawable d) {
+        if (d instanceof BitmapDrawable) {
+            return Icon.createWithBitmap(((BitmapDrawable) d).getBitmap());
+        }
+        Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
+                Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(b);
+        d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        d.draw(canvas);
+        return Icon.createWithBitmap(b);
+    }
+
+    /**
+     */
+    @TargetApi(28)
+    public static void createCircledIcon(@NonNull Context context, int iconSizePx,
+            Icon icon, boolean isLarge, ViewGroup parent) {
+        ImageView v = new ImageView(context);
+        v.setImageIcon(icon);
+        parent.addView(v);
+        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) v.getLayoutParams();
+        if (isLarge) {
+            // XXX better way to convert from icon -> bitmap or crop an icon (?)
+            Bitmap iconBm = Bitmap.createBitmap(iconSizePx, iconSizePx, Config.ARGB_8888);
+            Canvas iconCanvas = new Canvas(iconBm);
+            v.layout(0, 0, iconSizePx, iconSizePx);
+            v.draw(iconCanvas);
+            v.setImageBitmap(getCircularBitmap(iconBm));
+        } else {
+            v.setColorFilter(Color.WHITE);
+        }
+        lp.width = iconSizePx;
+        lp.height = iconSizePx;
+        lp.gravity = Gravity.CENTER;
+    }
+
+    /**
+     */
+    public static @NonNull Bitmap getCircularBitmap(Bitmap bitmap) {
+        Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
+                bitmap.getHeight(), Config.ARGB_8888);
+        Canvas canvas = new Canvas(output);
+        final Paint paint = new Paint();
+        final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+        paint.setAntiAlias(true);
+        canvas.drawARGB(0, 0, 0, 0);
+        canvas.drawCircle(bitmap.getWidth() / 2, bitmap.getHeight() / 2,
+                bitmap.getWidth() / 2, paint);
+        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
+        canvas.drawBitmap(bitmap, rect, rect, paint);
+        return output;
+    }
+
+    /**
+     */
+    public static CharSequence getRelativeTimeString(long time) {
+        return DateUtils.getRelativeTimeSpanString(time, Calendar.getInstance().getTimeInMillis(),
+                DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);
+    }
+}
diff --git a/slices/view/src/main/res-public/values/public_attrs.xml b/slices/view/src/main/res-public/values/public_attrs.xml
new file mode 100644
index 0000000..ad909ea
--- /dev/null
+++ b/slices/view/src/main/res-public/values/public_attrs.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Definitions of attributes to be exposed to the public -->
+<resources>
+    <public type="attr" name="titleColor" />
+    <public type="attr" name="subtitleColor" />
+    <public type="attr" name="tintColor" />
+    <public type="attr" name="headerTitleSize" />
+    <public type="attr" name="headerSubtitleSize" />
+    <public type="attr" name="titleSize" />
+    <public type="attr" name="subtitleSize" />
+    <public type="attr" name="gridTitleSize" />
+    <public type="attr" name="gridSubtitleSize" />
+    <public type="attr" name="sliceViewStyle" />
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res-public/values/public_styles.xml b/slices/view/src/main/res-public/values/public_styles.xml
new file mode 100644
index 0000000..36f3e26
--- /dev/null
+++ b/slices/view/src/main/res-public/values/public_styles.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- Definitions of styles to be exposed to the public -->
+<resources>
+    <public type="style" name="Widget.SliceView"/>
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res/drawable/abc_ic_slice_send.xml b/slices/view/src/main/res/drawable/abc_ic_slice_send.xml
new file mode 100644
index 0000000..9c18ac8
--- /dev/null
+++ b/slices/view/src/main/res/drawable/abc_ic_slice_send.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:autoMirrored="true"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M4.02,42.0L46.0,24.0 4.02,6.0 4.0,20.0l30.0,4.0 -30.0,4.0z"/>
+</vector>
\ No newline at end of file
diff --git a/slices/view/src/main/res/drawable/abc_slice_remote_input_bg.xml b/slices/view/src/main/res/drawable/abc_slice_remote_input_bg.xml
new file mode 100644
index 0000000..64ac7bf
--- /dev/null
+++ b/slices/view/src/main/res/drawable/abc_slice_remote_input_bg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#ff6c6c6c" />
+    <corners
+        android:bottomRightRadius="16dp"
+        android:bottomLeftRadius="16dp"/>
+</shape>
diff --git a/slices/view/src/main/res/drawable/abc_slice_ripple_drawable.xml b/slices/view/src/main/res/drawable/abc_slice_ripple_drawable.xml
new file mode 100644
index 0000000..22239f3
--- /dev/null
+++ b/slices/view/src/main/res/drawable/abc_slice_ripple_drawable.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:targetApi="24"
+    android:color="?android:attr/colorControlHighlight" />
diff --git a/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml b/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
new file mode 100644
index 0000000..7707dae
--- /dev/null
+++ b/slices/view/src/main/res/layout-v21/abc_slice_small_template.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/abc_slice_row_min_height"
+    android:maxHeight="@dimen/abc_slice_row_max_height"
+    android:gravity="center_vertical"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="start|center_vertical"
+        android:orientation="horizontal"
+        android:paddingEnd="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp"/>
+
+    <LinearLayout
+        android:id="@android:id/content"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:orientation="vertical">
+
+        <TextView android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxLines="2"
+            android:textAppearance="?android:attr/textAppearanceListItem" />
+
+        <TextView android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+        <SeekBar
+            android:id="@+id/seek_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone" />
+
+        <ProgressBar
+            android:id="@+id/progress_bar"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone" />
+
+    </LinearLayout>
+
+    <View
+        android:id="@+id/divider"
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp"
+        android:background="?android:attr/listDivider"
+        android:visibility="gone"/>
+
+    <LinearLayout android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="end|center_vertical"
+        android:orientation="horizontal" />
+
+</LinearLayout>
diff --git a/slices/view/src/main/res/layout/abc_slice_grid.xml b/slices/view/src/main/res/layout/abc_slice_grid.xml
new file mode 100644
index 0000000..890f77d
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_grid.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<androidx.app.slice.widget.GridRowView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/abc_slice_grid_image_only_height"
+    android:gravity="center_vertical"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:clipToPadding="false">
+</androidx.app.slice.widget.GridRowView>
diff --git a/slices/view/src/main/res/layout/abc_slice_message.xml b/slices/view/src/main/res/layout/abc_slice_message.xml
new file mode 100644
index 0000000..9e1fa62
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_message.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<androidx.app.slice.widget.MessageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="12dp"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <LinearLayout
+            android:id="@+id/abc_icon_frame"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="-4dp"
+            android:gravity="start|center_vertical"
+            android:orientation="horizontal"
+            android:paddingEnd="12dp"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp">
+            <!-- TODO: Support text source -->
+            <ImageView
+                android:id="@android:id/icon"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:maxWidth="48dp"
+                android:maxHeight="48dp" />
+        </LinearLayout>
+
+        <TextView android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:maxLines="10" />
+
+    </LinearLayout>
+</androidx.app.slice.widget.MessageView>
diff --git a/slices/view/src/main/res/layout/abc_slice_message_local.xml b/slices/view/src/main/res/layout/abc_slice_message_local.xml
new file mode 100644
index 0000000..d35bd60
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_message_local.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<androidx.app.slice.widget.MessageView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical|end"
+    android:paddingTop="12dp"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:clipToPadding="false">
+
+    <TextView android:id="@android:id/summary"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignStart="@android:id/title"
+        android:layout_gravity="end"
+        android:gravity="end"
+        android:padding="8dp"
+        android:textAppearance="?android:attr/textAppearanceListItem"
+        android:background="#ffeeeeee"
+        android:maxLines="10" />
+
+</androidx.app.slice.widget.MessageView>
diff --git a/slices/view/src/main/res/layout/abc_slice_remote_input.xml b/slices/view/src/main/res/layout/abc_slice_remote_input.xml
new file mode 100644
index 0000000..293c95a
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_remote_input.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!-- LinearLayout -->
+<androidx.app.slice.widget.RemoteInputView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/remote_input"
+        android:background="@drawable/abc_slice_remote_input_bg"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent">
+
+    <view class="androidx.app.slice.widget.RemoteInputView$RemoteEditText"
+            android:id="@+id/remote_input_text"
+            android:layout_height="match_parent"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:paddingTop="2dp"
+            android:paddingBottom="4dp"
+            android:paddingStart="16dp"
+            android:paddingEnd="12dp"
+            android:gravity="start|center_vertical"
+            android:textAppearance="?android:attr/textAppearance"
+            android:textColor="#FFFFFFFF"
+            android:textColorHint="#99ffffff"
+            android:textSize="16sp"
+            android:background="@null"
+            android:singleLine="true"
+            android:ellipsize="start"
+            android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
+            android:imeOptions="actionSend|flagNoExtractUi|flagNoFullscreen" />
+
+    <FrameLayout
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_gravity="center_vertical">
+
+        <ImageButton
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:paddingStart="12dp"
+                android:paddingEnd="24dp"
+                android:paddingTop="16dp"
+                android:paddingBottom="16dp"
+                android:id="@+id/remote_input_send"
+                android:src="@drawable/abc_ic_slice_send"
+                android:tint="#FFFFFF"
+                android:tintMode="src_in"
+                android:background="@drawable/abc_slice_ripple_drawable" />
+
+        <ProgressBar
+                android:id="@+id/remote_input_progress"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:layout_marginEnd="6dp"
+                android:layout_gravity="center"
+                android:visibility="invisible"
+                android:indeterminate="true"
+                style="?android:attr/progressBarStyleSmall" />
+
+    </FrameLayout>
+
+</androidx.app.slice.widget.RemoteInputView>
\ No newline at end of file
diff --git a/slices/view/src/main/res/layout/abc_slice_secondary_text.xml b/slices/view/src/main/res/layout/abc_slice_secondary_text.xml
new file mode 100644
index 0000000..b446ddd
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_secondary_text.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<!-- LinearLayout -->
+<TextView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorSecondary"
+        android:gravity="center"
+        android:layout_height="wrap_content"
+        android:padding="4dp"
+        android:layout_width="match_parent" />
diff --git a/slices/view/src/main/res/layout/abc_slice_small_template.xml b/slices/view/src/main/res/layout/abc_slice_small_template.xml
new file mode 100644
index 0000000..2d5e913
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_small_template.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="@dimen/abc_slice_row_min_height"
+    android:maxHeight="@dimen/abc_slice_row_max_height"
+    android:gravity="center_vertical"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="start|center_vertical"
+        android:orientation="horizontal"
+        android:paddingEnd="8dp"/>
+
+    <LinearLayout
+        android:id="@android:id/content"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:orientation="vertical">
+
+        <TextView android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxLines="2"/>
+
+        <TextView android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignStart="@android:id/title"
+            android:maxLines="10" />
+
+        <SeekBar
+            android:id="@+id/seek_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone" />
+
+        <ProgressBar
+            android:id="@+id/progress_bar"
+            style="?android:attr/progressBarStyleHorizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone" />
+
+    </LinearLayout>
+
+    <View
+        android:id="@+id/divider"
+        android:layout_width="1dp"
+        android:layout_height="match_parent"
+        android:layout_marginTop="8dp"
+        android:layout_marginBottom="8dp"
+        android:background="?android:attr/listDivider"
+        android:visibility="gone"/>
+
+    <LinearLayout android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingStart="8dp"
+        android:gravity="end|center_vertical"
+        android:orientation="horizontal" />
+
+</LinearLayout>
diff --git a/slices/view/src/main/res/layout/abc_slice_title.xml b/slices/view/src/main/res/layout/abc_slice_title.xml
new file mode 100644
index 0000000..e1bdf03
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_title.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<TextView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorPrimary"
+        android:gravity="center"
+        android:layout_height="wrap_content"
+        android:padding="4dp"
+        android:layout_width="match_parent" />
diff --git a/slices/view/src/main/res/values/attrs.xml b/slices/view/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..5779d31
--- /dev/null
+++ b/slices/view/src/main/res/values/attrs.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <declare-styleable name="SliceView">
+        <!-- Colors -->
+        <attr name="titleColor" format="color" />
+        <attr name="subtitleColor" format="color" />
+        <attr name="tintColor" format="color" />
+
+        <!-- Text sizes -->
+        <attr name="headerTitleSize" format="dimension" />
+        <attr name="headerSubtitleSize" format="dimension"/>
+        <attr name="titleSize" format="dimension" />
+        <attr name="subtitleSize" format="dimension" />
+        <attr name="gridTitleSize" format="dimension" />
+        <attr name="gridSubtitleSize" format="dimension" />
+    </declare-styleable>
+
+    <attr name="sliceViewStyle" format="reference"/>
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res/values/dimens.xml b/slices/view/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..ff2fb97
--- /dev/null
+++ b/slices/view/src/main/res/values/dimens.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <!-- General -->
+    <!-- Size of normal icons / images in a slice -->
+    <dimen name="abc_slice_icon_size">24dp</dimen>
+    <!-- Size of large icons / images in a slice -->
+    <dimen name="abc_slice_large_icon_size">48dp</dimen>
+    <!-- Standard padding used in a slice -->
+    <dimen name="abc_slice_padding">16dp</dimen>
+
+    <!-- Size of a slice shortcut view -->
+    <dimen name="abc_slice_shortcut_size">56dp</dimen>
+
+    <!-- Height of a large template -->
+    <dimen name="abc_slice_large_height">240dp</dimen>
+
+    <!-- Row view sizes-->
+    <!-- Min height of row view; default size if one line of text -->
+    <dimen name="abc_slice_row_min_height">48dp</dimen>
+    <!-- Max height of row view; default size if two lines of text -->
+    <dimen name="abc_slice_row_max_height">60dp</dimen>
+    <!-- Min height of a row showing an input field that is active -->
+    <dimen name="abc_slice_row_active_input_height">120dp</dimen>
+
+    <!-- Grid view sizes-->
+    <!-- Height of a grid row displaying only images -->
+    <dimen name="abc_slice_grid_image_only_height">86dp</dimen>
+    <!-- Height of a grid row showing text and images -->
+    <dimen name="abc_slice_grid_height">120dp</dimen>
+    <!-- Height of expanded grid row if showing a single large image -->
+    <dimen name="abc_slice_grid_big_picture_height">180dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res/values/strings.xml b/slices/view/src/main/res/values/strings.xml
new file mode 100644
index 0000000..b72c986
--- /dev/null
+++ b/slices/view/src/main/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Format string for indicating there is more content in a slice view -->
+    <string name="abc_slice_more_content">+ <xliff:g id="number" example="5">%1$d</xliff:g></string>
+</resources>
\ No newline at end of file
diff --git a/slices/view/src/main/res/values/styles.xml b/slices/view/src/main/res/values/styles.xml
new file mode 100644
index 0000000..4b27820
--- /dev/null
+++ b/slices/view/src/main/res/values/styles.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+    <style name="Widget.SliceView" parent="">
+        <item name="tintColor">@null</item>
+        <!-- Colors -->
+        <item name="titleColor">?android:attr/textColorPrimary</item>
+        <item name="subtitleColor">?android:attr/textColorSecondary</item>
+
+        <!-- Text sizes -->
+        <item name="headerTitleSize">16sp</item>
+        <item name="headerSubtitleSize">14sp</item>
+        <item name="titleSize">14sp</item>
+        <item name="subtitleSize">14sp</item>
+        <item name="gridTitleSize">12sp</item>
+        <item name="gridSubtitleSize">12sp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/slidingpanelayout/api/current.txt b/slidingpanelayout/api/current.txt
new file mode 100644
index 0000000..07e71d9
--- /dev/null
+++ b/slidingpanelayout/api/current.txt
@@ -0,0 +1,54 @@
+package android.support.v4.widget {
+
+  public class SlidingPaneLayout extends android.view.ViewGroup {
+    ctor public SlidingPaneLayout(android.content.Context);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public deprecated boolean canSlide();
+    method public boolean closePane();
+    method public int getCoveredFadeColor();
+    method public int getParallaxDistance();
+    method public int getSliderFadeColor();
+    method public boolean isOpen();
+    method public boolean isSlideable();
+    method public boolean openPane();
+    method public void setCoveredFadeColor(int);
+    method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
+    method public void setParallaxDistance(int);
+    method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
+    method public deprecated void setShadowResource(int);
+    method public void setShadowResourceLeft(int);
+    method public void setShadowResourceRight(int);
+    method public void setSliderFadeColor(int);
+    method public deprecated void smoothSlideClosed();
+    method public deprecated void smoothSlideOpen();
+  }
+
+  public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public SlidingPaneLayout.LayoutParams();
+    ctor public SlidingPaneLayout.LayoutParams(int, int);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public float weight;
+  }
+
+  public static abstract interface SlidingPaneLayout.PanelSlideListener {
+    method public abstract void onPanelClosed(android.view.View);
+    method public abstract void onPanelOpened(android.view.View);
+    method public abstract void onPanelSlide(android.view.View, float);
+  }
+
+  public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
+    ctor public SlidingPaneLayout.SimplePanelSlideListener();
+    method public void onPanelClosed(android.view.View);
+    method public void onPanelOpened(android.view.View);
+    method public void onPanelSlide(android.view.View, float);
+  }
+
+}
+
diff --git a/slidingpanelayout/build.gradle b/slidingpanelayout/build.gradle
new file mode 100644
index 0000000..d084e63
--- /dev/null
+++ b/slidingpanelayout/build.gradle
@@ -0,0 +1,21 @@
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+    api(project(":customview"))
+}
+
+supportLibrary {
+    name = "Android Support Library Sliding Pane Layout"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/slidingpanelayout/src/main/AndroidManifest.xml b/slidingpanelayout/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..0df47df
--- /dev/null
+++ b/slidingpanelayout/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.slidingpanelayout"/>
diff --git a/core-ui/src/main/java/android/support/v4/widget/SlidingPaneLayout.java b/slidingpanelayout/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
rename to slidingpanelayout/src/main/java/android/support/v4/widget/SlidingPaneLayout.java
diff --git a/swiperefreshlayout/api/current.txt b/swiperefreshlayout/api/current.txt
new file mode 100644
index 0000000..ce68f0b
--- /dev/null
+++ b/swiperefreshlayout/api/current.txt
@@ -0,0 +1,76 @@
+package android.support.v4.widget {
+
+  public class CircularProgressDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
+    ctor public CircularProgressDrawable(android.content.Context);
+    method public void draw(android.graphics.Canvas);
+    method public boolean getArrowEnabled();
+    method public float getArrowHeight();
+    method public float getArrowScale();
+    method public float getArrowWidth();
+    method public int getBackgroundColor();
+    method public float getCenterRadius();
+    method public int[] getColorSchemeColors();
+    method public float getEndTrim();
+    method public int getOpacity();
+    method public float getProgressRotation();
+    method public float getStartTrim();
+    method public android.graphics.Paint.Cap getStrokeCap();
+    method public float getStrokeWidth();
+    method public boolean isRunning();
+    method public void setAlpha(int);
+    method public void setArrowDimensions(float, float);
+    method public void setArrowEnabled(boolean);
+    method public void setArrowScale(float);
+    method public void setBackgroundColor(int);
+    method public void setCenterRadius(float);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setColorSchemeColors(int...);
+    method public void setProgressRotation(float);
+    method public void setStartEndTrim(float, float);
+    method public void setStrokeCap(android.graphics.Paint.Cap);
+    method public void setStrokeWidth(float);
+    method public void setStyle(int);
+    method public void start();
+    method public void stop();
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int LARGE = 0; // 0x0
+  }
+
+  public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+    ctor public SwipeRefreshLayout(android.content.Context);
+    ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
+    method public boolean canChildScrollUp();
+    method public int getProgressCircleDiameter();
+    method public int getProgressViewEndOffset();
+    method public int getProgressViewStartOffset();
+    method public boolean isRefreshing();
+    method public void onMeasure(int, int);
+    method public deprecated void setColorScheme(int...);
+    method public void setColorSchemeColors(int...);
+    method public void setColorSchemeResources(int...);
+    method public void setDistanceToTriggerSync(int);
+    method public void setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback);
+    method public void setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener);
+    method public deprecated void setProgressBackgroundColor(int);
+    method public void setProgressBackgroundColorSchemeColor(int);
+    method public void setProgressBackgroundColorSchemeResource(int);
+    method public void setProgressViewEndTarget(boolean, int);
+    method public void setProgressViewOffset(boolean, int, int);
+    method public void setRefreshing(boolean);
+    method public void setSize(int);
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int LARGE = 0; // 0x0
+    field protected int mFrom;
+    field protected int mOriginalOffsetTop;
+  }
+
+  public static abstract interface SwipeRefreshLayout.OnChildScrollUpCallback {
+    method public abstract boolean canChildScrollUp(android.support.v4.widget.SwipeRefreshLayout, android.view.View);
+  }
+
+  public static abstract interface SwipeRefreshLayout.OnRefreshListener {
+    method public abstract void onRefresh();
+  }
+
+}
+
diff --git a/swiperefreshlayout/build.gradle b/swiperefreshlayout/build.gradle
new file mode 100644
index 0000000..0479bbe
--- /dev/null
+++ b/swiperefreshlayout/build.gradle
@@ -0,0 +1,33 @@
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+    api(project(":interpolator"))
+
+    androidTestImplementation(JUNIT)
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(TEST_RULES)
+    androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation project(':support-testutils'), {
+        exclude group: 'com.android.support', module: 'swiperefreshlayout'
+    }
+}
+
+supportLibrary {
+    name = "Android Support Library Custom View"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/swiperefreshlayout/src/androidTest/AndroidManifest.xml b/swiperefreshlayout/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..1b84249
--- /dev/null
+++ b/swiperefreshlayout/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.swiperefreshlayout.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <application
+        android:supportsRtl="true"
+        android:theme="@style/TestActivityTheme">
+        <activity android:name="android.support.v4.widget.CircularProgressDrawableActivity"/>
+        <activity android:name="android.support.v4.widget.SwipeRefreshLayoutActivity"/>
+    </application>
+
+</manifest>
diff --git a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/CircularProgressDrawableActivity.java b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/CircularProgressDrawableActivity.java
new file mode 100644
index 0000000..3353c9f
--- /dev/null
+++ b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/CircularProgressDrawableActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.swiperefreshlayout.test.R;
+
+public class CircularProgressDrawableActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.circular_progress_drawable_activity);
+    }
+}
diff --git a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/CircularProgressDrawableTest.java b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/CircularProgressDrawableTest.java
new file mode 100644
index 0000000..2a0870e
--- /dev/null
+++ b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/CircularProgressDrawableTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyFloat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+/**
+ * Tests for CircularProgressDrawable
+ */
+@RunWith(AndroidJUnit4.class)
+public class CircularProgressDrawableTest {
+    @Rule
+    public final ActivityTestRule<CircularProgressDrawableActivity> mActivityTestRule =
+            new ActivityTestRule<>(CircularProgressDrawableActivity.class);
+
+    private CircularProgressDrawable mDrawableUnderTest;
+
+    @Mock
+    Canvas mMockCanvas;
+
+    @Before
+    public void setUp() {
+        Context context = mActivityTestRule.getActivity().getApplicationContext();
+        mMockCanvas = mock(Canvas.class);
+        mDrawableUnderTest = new CircularProgressDrawable(context);
+    }
+
+    @Test
+    @SmallTest
+    public void sizeIsSquareBasedOnSmallerEdgeWithNoCenterRadius() {
+        int width = 100;
+        int height = 50;
+        mDrawableUnderTest.setBounds(new Rect(0, 0, width, height));
+        mDrawableUnderTest.draw(mMockCanvas);
+
+        ArgumentCaptor<RectF> captor = ArgumentCaptor.forClass(RectF.class);
+        verify(mMockCanvas).drawArc(captor.capture(), anyFloat(), anyFloat(), anyBoolean(),
+                any(Paint.class));
+
+        assertTrue(captor.getValue().width() == captor.getValue().height());
+        assertTrue(captor.getValue().width() <= width);
+        assertTrue(captor.getValue().width() <= height);
+    }
+
+    @Test
+    @SmallTest
+    public void setCenterRadiusFixesSize() {
+        float radius = 10f;
+        float strokeWidth = 4f;
+        mDrawableUnderTest.setCenterRadius(radius);
+        mDrawableUnderTest.setStrokeWidth(strokeWidth);
+        mDrawableUnderTest.setBounds(new Rect(0, 0, 100, 50));
+        mDrawableUnderTest.draw(mMockCanvas);
+
+        ArgumentCaptor<RectF> boundsCaptor = ArgumentCaptor.forClass(RectF.class);
+        verify(mMockCanvas).drawArc(boundsCaptor.capture(), anyFloat(), anyFloat(), anyBoolean(),
+                any(Paint.class));
+
+        assertEquals((radius + strokeWidth / 2f) * 2, boundsCaptor.getValue().width(), 0.5);
+        assertEquals((radius + strokeWidth / 2f) * 2, boundsCaptor.getValue().height(), 0.5);
+    }
+}
diff --git a/core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutActions.java b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutActions.java
similarity index 100%
rename from core-ui/tests/java/android/support/v4/widget/SwipeRefreshLayoutActions.java
rename to swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutActions.java
diff --git a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutActivity.java b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutActivity.java
new file mode 100644
index 0000000..3d8493d
--- /dev/null
+++ b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutActivity.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.swiperefreshlayout.test.R;
+
+public class SwipeRefreshLayoutActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.swipe_refresh_layout_activity);
+    }
+}
diff --git a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
new file mode 100644
index 0000000..fe53293
--- /dev/null
+++ b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.widget;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.v4.widget.SwipeRefreshLayoutActions.setEnabled;
+import static android.support.v4.widget.SwipeRefreshLayoutActions.setRefreshing;
+import static android.support.v4.widget.SwipeRefreshLayoutActions.setSize;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.swiperefreshlayout.test.R;
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.testutils.PollingCheck;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests SwipeRefreshLayout widget.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SwipeRefreshLayoutTest {
+    @Rule
+    public final ActivityTestRule<SwipeRefreshLayoutActivity> mActivityTestRule =
+            new ActivityTestRule<>(SwipeRefreshLayoutActivity.class);
+
+    private static final long TIMEOUT = 1000;
+    private static final int INVALID_SIZE = 1000;
+
+    private SwipeRefreshLayout mSwipeRefresh;
+
+    @Before
+    public void setUp() {
+        mSwipeRefresh = mActivityTestRule.getActivity().findViewById(R.id.swipe_refresh);
+    }
+
+    @Test
+    @MediumTest
+    public void testStartAndStopRefreshing() throws Throwable {
+        SwipeRefreshLayout.OnRefreshListener mockListener =
+                mock(SwipeRefreshLayout.OnRefreshListener.class);
+        mSwipeRefresh.setOnRefreshListener(mockListener);
+
+        assertFalse(mSwipeRefresh.isRefreshing());
+        for (int i = 0; i < 5; i++) {
+            onView(withId(R.id.swipe_refresh)).perform(setRefreshing());
+            assertTrue(mSwipeRefresh.isRefreshing());
+
+            // onView(..).perform(..) does not work when views are animated.
+            // Therefore this is using a posted task to turn off refreshing.
+            mSwipeRefresh.getHandler().post(new Runnable() {
+                @Override
+                public void run() {
+                    mSwipeRefresh.setRefreshing(false);
+                }
+            });
+
+            PollingCheck.waitFor(TIMEOUT, new PollingCheck.PollingCheckCondition() {
+                @Override
+                public boolean canProceed() {
+                    return !mSwipeRefresh.isRefreshing();
+                }
+            });
+        }
+        verify(mockListener, times(0)).onRefresh();
+    }
+
+    @Test
+    @MediumTest
+    public void testSwipeDownToRefresh() throws Throwable {
+        assertFalse(mSwipeRefresh.isRefreshing());
+
+        swipeToRefreshVerifyThenStopRefreshing(true);
+    }
+
+    @Test
+    @SmallTest
+    public void testSetSize() throws Throwable {
+        float density = mSwipeRefresh.getResources().getDisplayMetrics().density;
+        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
+                mSwipeRefresh.getProgressCircleDiameter());
+        onView(withId(R.id.swipe_refresh)).perform(setSize(SwipeRefreshLayout.LARGE));
+        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER_LARGE * density),
+                mSwipeRefresh.getProgressCircleDiameter());
+        onView(withId(R.id.swipe_refresh)).perform(setSize(SwipeRefreshLayout.DEFAULT));
+        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
+                mSwipeRefresh.getProgressCircleDiameter());
+        onView(withId(R.id.swipe_refresh)).perform(setSize(SwipeRefreshLayout.DEFAULT));
+        onView(withId(R.id.swipe_refresh)).perform(setSize(INVALID_SIZE));
+        assertEquals((int) (SwipeRefreshLayout.CIRCLE_DIAMETER * density),
+                mSwipeRefresh.getProgressCircleDiameter());
+    }
+
+    @Test
+    @SmallTest
+    public void testSetOnChildScrollUpCallback() throws Throwable {
+        SwipeRefreshLayout.OnChildScrollUpCallback mockCallback =
+                mock(SwipeRefreshLayout.OnChildScrollUpCallback.class);
+        when(mockCallback.canChildScrollUp(eq(mSwipeRefresh), any(View.class)))
+                .thenReturn(true)
+                .thenReturn(true)
+                .thenReturn(false)
+                .thenReturn(false);
+        mSwipeRefresh.setOnChildScrollUpCallback(mockCallback);
+        assertTrue(mSwipeRefresh.canChildScrollUp());
+        assertTrue(mSwipeRefresh.canChildScrollUp());
+        assertFalse(mSwipeRefresh.canChildScrollUp());
+        assertFalse(mSwipeRefresh.canChildScrollUp());
+    }
+
+    @Test
+    @LargeTest
+    public void testSwipeDownToRefreshInitiallyDisabled() throws Throwable {
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivityTestRule.getActivity().setContentView(
+                        R.layout.swipe_refresh_layout_disabled_activity);
+            }
+        });
+        mSwipeRefresh = (SwipeRefreshLayout) mActivityTestRule.getActivity().findViewById(
+                R.id.swipe_refresh);
+
+        assertFalse(mSwipeRefresh.isRefreshing());
+
+        swipeToRefreshVerifyThenStopRefreshing(false);
+
+        onView(withId(R.id.swipe_refresh)).perform(setEnabled(true));
+
+        swipeToRefreshVerifyThenStopRefreshing(true);
+    }
+
+    private void swipeToRefreshVerifyThenStopRefreshing(boolean expectRefreshing) throws Throwable {
+        final CountDownLatch latch = new CountDownLatch(1);
+        SwipeRefreshLayout.OnRefreshListener listener = new SwipeRefreshLayout.OnRefreshListener() {
+            @Override
+            public void onRefresh() {
+                latch.countDown();
+                assertTrue(mSwipeRefresh.isRefreshing());
+                mSwipeRefresh.setRefreshing(false);
+            }
+        };
+        mSwipeRefresh.setOnRefreshListener(listener);
+        onView(withId(R.id.content)).perform(ViewActions.swipeDown());
+        if (expectRefreshing) {
+            assertTrue("SwipeRefreshLayout never started refreshing",
+                    latch.await(500, TimeUnit.MILLISECONDS));
+        } else {
+            assertFalse("SwipeRefreshLayout unexpectedly started refreshing",
+                    latch.await(500, TimeUnit.MILLISECONDS));
+        }
+    }
+}
diff --git a/core-ui/tests/res/layout/circular_progress_drawable_activity.xml b/swiperefreshlayout/src/androidTest/res/layout/circular_progress_drawable_activity.xml
similarity index 100%
rename from core-ui/tests/res/layout/circular_progress_drawable_activity.xml
rename to swiperefreshlayout/src/androidTest/res/layout/circular_progress_drawable_activity.xml
diff --git a/core-ui/tests/res/layout/swipe_refresh_layout_activity.xml b/swiperefreshlayout/src/androidTest/res/layout/swipe_refresh_layout_activity.xml
similarity index 100%
rename from core-ui/tests/res/layout/swipe_refresh_layout_activity.xml
rename to swiperefreshlayout/src/androidTest/res/layout/swipe_refresh_layout_activity.xml
diff --git a/core-ui/tests/res/layout/swipe_refresh_layout_disabled_activity.xml b/swiperefreshlayout/src/androidTest/res/layout/swipe_refresh_layout_disabled_activity.xml
similarity index 100%
rename from core-ui/tests/res/layout/swipe_refresh_layout_disabled_activity.xml
rename to swiperefreshlayout/src/androidTest/res/layout/swipe_refresh_layout_disabled_activity.xml
diff --git a/core-ui/tests/res/values/styles.xml b/swiperefreshlayout/src/androidTest/res/values/styles.xml
similarity index 100%
copy from core-ui/tests/res/values/styles.xml
copy to swiperefreshlayout/src/androidTest/res/values/styles.xml
diff --git a/swiperefreshlayout/src/main/AndroidManifest.xml b/swiperefreshlayout/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..abc5680
--- /dev/null
+++ b/swiperefreshlayout/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.swiperefreshlayout"/>
diff --git a/core-ui/src/main/java/android/support/v4/widget/CircleImageView.java b/swiperefreshlayout/src/main/java/android/support/v4/widget/CircleImageView.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/CircleImageView.java
rename to swiperefreshlayout/src/main/java/android/support/v4/widget/CircleImageView.java
diff --git a/core-ui/src/main/java/android/support/v4/widget/CircularProgressDrawable.java b/swiperefreshlayout/src/main/java/android/support/v4/widget/CircularProgressDrawable.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/CircularProgressDrawable.java
rename to swiperefreshlayout/src/main/java/android/support/v4/widget/CircularProgressDrawable.java
diff --git a/core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java b/swiperefreshlayout/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
rename to swiperefreshlayout/src/main/java/android/support/v4/widget/SwipeRefreshLayout.java
diff --git a/testutils/build.gradle b/testutils/build.gradle
index 6a340b0..d75b6b7 100644
--- a/testutils/build.gradle
+++ b/testutils/build.gradle
@@ -36,7 +36,3 @@
         disable 'InvalidPackage' // Lint is unhappy about junit package
     }
 }
-
-supportLibrary {
-    legacySourceLocation = true
-}
\ No newline at end of file
diff --git a/testutils/AndroidManifest.xml b/testutils/src/main/AndroidManifest.xml
similarity index 100%
rename from testutils/AndroidManifest.xml
rename to testutils/src/main/AndroidManifest.xml
diff --git a/textclassifier/OWNERS b/textclassifier/OWNERS
new file mode 100644
index 0000000..6975b76
--- /dev/null
+++ b/textclassifier/OWNERS
@@ -0,0 +1,3 @@
+clarabayarri@google.com
+toki@google.com
+jalt@google.com
diff --git a/textclassifier/api/current.txt b/textclassifier/api/current.txt
new file mode 100644
index 0000000..6dad352
--- /dev/null
+++ b/textclassifier/api/current.txt
@@ -0,0 +1,138 @@
+package androidx.view.textclassifier {
+
+  public final class TextClassification implements android.os.Parcelable {
+    method public int describeContents();
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public android.graphics.drawable.Drawable getIcon();
+    method public android.content.Intent getIntent();
+    method public java.lang.CharSequence getLabel();
+    method public int getSecondaryActionsCount();
+    method public android.graphics.drawable.Drawable getSecondaryIcon(int);
+    method public android.content.Intent getSecondaryIntent(int);
+    method public java.lang.CharSequence getSecondaryLabel(int);
+    method public java.lang.String getSignature();
+    method public java.lang.String getText();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.view.textclassifier.TextClassification> CREATOR;
+  }
+
+  public static final class TextClassification.Builder {
+    ctor public TextClassification.Builder();
+    method public androidx.view.textclassifier.TextClassification.Builder addSecondaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable);
+    method public androidx.view.textclassifier.TextClassification build();
+    method public androidx.view.textclassifier.TextClassification.Builder clearSecondaryActions();
+    method public androidx.view.textclassifier.TextClassification.Builder setEntityType(java.lang.String, float);
+    method public androidx.view.textclassifier.TextClassification.Builder setIcon(android.graphics.drawable.Drawable);
+    method public androidx.view.textclassifier.TextClassification.Builder setIntent(android.content.Intent);
+    method public androidx.view.textclassifier.TextClassification.Builder setLabel(java.lang.String);
+    method public androidx.view.textclassifier.TextClassification.Builder setPrimaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable);
+    method public androidx.view.textclassifier.TextClassification.Builder setSignature(java.lang.String);
+    method public androidx.view.textclassifier.TextClassification.Builder setText(java.lang.String);
+  }
+
+  public static final class TextClassification.Options implements android.os.Parcelable {
+    ctor public TextClassification.Options();
+    method public int describeContents();
+    method public android.support.v4.os.LocaleListCompat getDefaultLocales();
+    method public java.util.Calendar getReferenceTime();
+    method public androidx.view.textclassifier.TextClassification.Options setDefaultLocales(android.support.v4.os.LocaleListCompat);
+    method public androidx.view.textclassifier.TextClassification.Options setReferenceTime(java.util.Calendar);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.view.textclassifier.TextClassification.Options> CREATOR;
+  }
+
+  public class TextClassifier {
+    ctor public TextClassifier();
+    field public static final java.lang.String TYPE_ADDRESS = "address";
+    field public static final java.lang.String TYPE_EMAIL = "email";
+    field public static final java.lang.String TYPE_OTHER = "other";
+    field public static final java.lang.String TYPE_PHONE = "phone";
+    field public static final java.lang.String TYPE_UNKNOWN = "";
+    field public static final java.lang.String TYPE_URL = "url";
+  }
+
+  public final class TextLinks implements android.os.Parcelable {
+    method public int apply(android.text.Spannable, int, androidx.view.textclassifier.TextLinks.SpanFactory);
+    method public int describeContents();
+    method public java.util.Collection<androidx.view.textclassifier.TextLinks.TextLink> getLinks();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int APPLY_STRATEGY_IGNORE = 0; // 0x0
+    field public static final int APPLY_STRATEGY_REPLACE = 1; // 0x1
+    field public static final android.os.Parcelable.Creator<androidx.view.textclassifier.TextLinks> CREATOR;
+    field public static final int STATUS_DIFFERENT_TEXT = 3; // 0x3
+    field public static final int STATUS_LINKS_APPLIED = 0; // 0x0
+    field public static final int STATUS_NO_LINKS_APPLIED = 2; // 0x2
+    field public static final int STATUS_NO_LINKS_FOUND = 1; // 0x1
+  }
+
+  public static final class TextLinks.Builder {
+    ctor public TextLinks.Builder(java.lang.String);
+    method public androidx.view.textclassifier.TextLinks.Builder addLink(int, int, java.util.Map<java.lang.String, java.lang.Float>);
+    method public androidx.view.textclassifier.TextLinks build();
+    method public androidx.view.textclassifier.TextLinks.Builder clearTextLinks();
+  }
+
+  public static final class TextLinks.Options implements android.os.Parcelable {
+    ctor public TextLinks.Options();
+    method public int describeContents();
+    method public int getApplyStrategy();
+    method public android.support.v4.os.LocaleListCompat getDefaultLocales();
+    method public androidx.view.textclassifier.TextClassifier.EntityConfig getEntityConfig();
+    method public androidx.view.textclassifier.TextLinks.SpanFactory getSpanFactory();
+    method public androidx.view.textclassifier.TextLinks.Options setApplyStrategy(int);
+    method public androidx.view.textclassifier.TextLinks.Options setDefaultLocales(android.support.v4.os.LocaleListCompat);
+    method public androidx.view.textclassifier.TextLinks.Options setEntityConfig(androidx.view.textclassifier.TextClassifier.EntityConfig);
+    method public androidx.view.textclassifier.TextLinks.Options setSpanFactory(androidx.view.textclassifier.TextLinks.SpanFactory);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.view.textclassifier.TextLinks.Options> CREATOR;
+  }
+
+  public static final class TextLinks.TextLink implements android.os.Parcelable {
+    method public int describeContents();
+    method public float getConfidenceScore(java.lang.String);
+    method public int getEnd();
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getStart();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.view.textclassifier.TextLinks.TextLink> CREATOR;
+  }
+
+  public static class TextLinks.TextLinkSpan extends android.text.style.ClickableSpan {
+    ctor public TextLinks.TextLinkSpan(androidx.view.textclassifier.TextLinks.TextLink);
+    method public final androidx.view.textclassifier.TextLinks.TextLink getTextLink();
+    method public void onClick(android.view.View);
+  }
+
+  public final class TextSelection implements android.os.Parcelable {
+    method public int describeContents();
+    method public float getConfidenceScore(java.lang.String);
+    method public java.lang.String getEntity(int);
+    method public int getEntityCount();
+    method public int getSelectionEndIndex();
+    method public int getSelectionStartIndex();
+    method public java.lang.String getSignature();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.view.textclassifier.TextSelection> CREATOR;
+  }
+
+  public static final class TextSelection.Builder {
+    ctor public TextSelection.Builder(int, int);
+    method public androidx.view.textclassifier.TextSelection build();
+    method public androidx.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+    method public androidx.view.textclassifier.TextSelection.Builder setSignature(java.lang.String);
+  }
+
+  public static final class TextSelection.Options implements android.os.Parcelable {
+    ctor public TextSelection.Options();
+    method public int describeContents();
+    method public android.support.v4.os.LocaleListCompat getDefaultLocales();
+    method public androidx.view.textclassifier.TextSelection.Options setDefaultLocales(android.support.v4.os.LocaleListCompat);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<androidx.view.textclassifier.TextSelection.Options> CREATOR;
+  }
+
+}
+
diff --git a/textclassifier/build.gradle b/textclassifier/build.gradle
new file mode 100644
index 0000000..b01cbbf
--- /dev/null
+++ b/textclassifier/build.gradle
@@ -0,0 +1,26 @@
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":appcompat-v7"))
+    api(project(":support-annotations"))
+    api(project(":support-v4"))
+
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(ESPRESSO_CORE)
+}
+
+supportLibrary {
+    name = "Android TextClassifier Support Library"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The TextClassifier Support Library can be added to an Android application in order to use the TextClassifier API introduced in Android O on all devices with API level 14 or later."
+    minSdkVersion = 14
+}
diff --git a/textclassifier/res/values/strings.xml b/textclassifier/res/values/strings.xml
new file mode 100644
index 0000000..321190e
--- /dev/null
+++ b/textclassifier/res/values/strings.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<resources>
+</resources>
diff --git a/textclassifier/src/androidTest/AndroidManifest.xml b/textclassifier/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..0a7045c
--- /dev/null
+++ b/textclassifier/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.textclassifier.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+</manifest>
diff --git a/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextClassificationTest.java b/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextClassificationTest.java
new file mode 100644
index 0000000..8ae65ac
--- /dev/null
+++ b/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextClassificationTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.os.LocaleListCompat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/** Instrumentation unit tests for {@link TextClassification}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class TextClassificationTest {
+    public BitmapDrawable generateTestDrawable(int width, int height, int colorValue) {
+        final int numPixels = width * height;
+        final int[] colors = new int[numPixels];
+        for (int i = 0; i < numPixels; ++i) {
+            colors[i] = colorValue;
+        }
+        final Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
+        final BitmapDrawable drawable = new BitmapDrawable(null, bitmap);
+        drawable.setTargetDensity(bitmap.getDensity());
+        return drawable;
+    }
+
+    @Test
+    public void testParcel() {
+        final String text = "text";
+        final BitmapDrawable primaryIcon = generateTestDrawable(16, 16, Color.RED);
+        final String primaryLabel = "primarylabel";
+        final Intent primaryIntent = new Intent("primaryintentaction");
+        final BitmapDrawable secondaryIcon0 = generateTestDrawable(32, 288, Color.GREEN);
+        final String secondaryLabel0 = "secondarylabel0";
+        final Intent secondaryIntent0 = new Intent("secondaryintentaction0");
+        final BitmapDrawable secondaryIcon1 = generateTestDrawable(576, 288, Color.BLUE);
+        final String secondaryLabel1 = "secondaryLabel1";
+        final Intent secondaryIntent1 = null;
+        final BitmapDrawable secondaryIcon2 = null;
+        final String secondaryLabel2 = null;
+        final Intent secondaryIntent2 = new Intent("secondaryintentaction2");
+        final ColorDrawable secondaryIcon3 = new ColorDrawable(Color.CYAN);
+        final String secondaryLabel3 = null;
+        final Intent secondaryIntent3 = null;
+        final String signature = "signature";
+        final TextClassification reference = new TextClassification.Builder()
+                .setText(text)
+                .setPrimaryAction(primaryIntent, primaryLabel, primaryIcon)
+                .addSecondaryAction(null, null, null)  // ignored
+                .addSecondaryAction(secondaryIntent0, secondaryLabel0, secondaryIcon0)
+                .addSecondaryAction(secondaryIntent1, secondaryLabel1, secondaryIcon1)
+                .addSecondaryAction(secondaryIntent2, secondaryLabel2, secondaryIcon2)
+                .addSecondaryAction(secondaryIntent3, secondaryLabel3, secondaryIcon3)
+                .setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f)
+                .setEntityType(TextClassifier.TYPE_PHONE, 0.7f)
+                .setSignature(signature)
+                .build();
+
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        final TextClassification result = TextClassification.CREATOR.createFromParcel(
+                parcel);
+
+        assertEquals(text, result.getText());
+        assertEquals(signature, result.getSignature());
+        assertEquals(4, result.getSecondaryActionsCount());
+
+        // Primary action (re-use existing icon).
+        final Bitmap resPrimaryIcon = ((BitmapDrawable) result.getIcon()).getBitmap();
+        assertEquals(primaryIcon.getBitmap().getPixel(0, 0), resPrimaryIcon.getPixel(0, 0));
+        assertEquals(16, resPrimaryIcon.getWidth());
+        assertEquals(16, resPrimaryIcon.getHeight());
+        assertEquals(primaryLabel, result.getLabel());
+        assertEquals(primaryIntent.getAction(), result.getIntent().getAction());
+
+        // Secondary action 0 (scale with  height limit).
+        final Bitmap resSecondaryIcon0 = ((BitmapDrawable) result.getSecondaryIcon(0)).getBitmap();
+        assertEquals(secondaryIcon0.getBitmap().getPixel(0, 0), resSecondaryIcon0.getPixel(0, 0));
+        assertEquals(16, resSecondaryIcon0.getWidth());
+        assertEquals(144, resSecondaryIcon0.getHeight());
+        assertEquals(secondaryLabel0, result.getSecondaryLabel(0));
+        assertEquals(secondaryIntent0.getAction(), result.getSecondaryIntent(0).getAction());
+
+        // Secondary action 1 (scale with width limit).
+        final Bitmap resSecondaryIcon1 = ((BitmapDrawable) result.getSecondaryIcon(1)).getBitmap();
+        assertEquals(secondaryIcon1.getBitmap().getPixel(0, 0), resSecondaryIcon1.getPixel(0, 0));
+        assertEquals(144, resSecondaryIcon1.getWidth());
+        assertEquals(72, resSecondaryIcon1.getHeight());
+        assertEquals(secondaryLabel1, result.getSecondaryLabel(1));
+        assertEquals(null, result.getSecondaryIntent(1));
+
+        // Secondary action 2 (no icon).
+        assertEquals(null, result.getSecondaryIcon(2));
+        assertEquals(null, result.getSecondaryLabel(2));
+        assertEquals(secondaryIntent2.getAction(), result.getSecondaryIntent(2).getAction());
+
+        // Secondary action 3 (convert non-bitmap drawable with negative size).
+        final Bitmap resSecondaryIcon3 = ((BitmapDrawable) result.getSecondaryIcon(3)).getBitmap();
+        assertEquals(secondaryIcon3.getColor(), resSecondaryIcon3.getPixel(0, 0));
+        assertEquals(1, resSecondaryIcon3.getWidth());
+        assertEquals(1, resSecondaryIcon3.getHeight());
+        assertEquals(null, result.getSecondaryLabel(3));
+        assertEquals(null, result.getSecondaryIntent(3));
+
+        // Entities.
+        assertEquals(2, result.getEntityCount());
+        assertEquals(TextClassifier.TYPE_PHONE, result.getEntity(0));
+        assertEquals(TextClassifier.TYPE_ADDRESS, result.getEntity(1));
+        assertEquals(0.7f, result.getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f);
+        assertEquals(0.3f, result.getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f);
+    }
+
+    @Test
+    public void testParcelOptions() {
+        Calendar referenceTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.US);
+        referenceTime.setTimeInMillis(946684800000L);  // 2000-01-01 00:00:00
+        TextClassification.Options reference = new TextClassification.Options();
+        reference.setDefaultLocales(LocaleListCompat.forLanguageTags("en-US,de-DE"));
+        reference.setReferenceTime(referenceTime);
+
+        // Parcel and unparcel.
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        TextClassification.Options result =
+                TextClassification.Options.CREATOR.createFromParcel(parcel);
+
+        assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+        assertEquals(referenceTime, result.getReferenceTime());
+    }
+}
diff --git a/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextLinksTest.java b/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextLinksTest.java
new file mode 100644
index 0000000..dadc214
--- /dev/null
+++ b/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextLinksTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+import android.support.annotation.Nullable;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.os.LocaleListCompat;
+import android.support.v4.util.ArrayMap;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ClickableSpan;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/** Instrumentation unit tests for {@link TextLinks}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class TextLinksTest {
+
+    private static class NoOpSpan extends ClickableSpan {
+        @Override
+        public void onClick(View v) {
+            // Do nothing.
+        }
+    }
+
+    private static class CustomTextLinkSpan extends TextLinks.TextLinkSpan {
+        CustomTextLinkSpan(@Nullable TextLinks.TextLink textLink) {
+            super(textLink);
+        }
+    }
+
+    private static class CustomSpanFactory implements TextLinks.SpanFactory {
+        @Override
+        public TextLinks.TextLinkSpan createSpan(TextLinks.TextLink textLink) {
+            return new CustomTextLinkSpan(textLink);
+        }
+    }
+
+    private TextClassifier mClassifier;
+    private Map<String, Float> mDummyEntityScores;
+
+    @Before
+    public void setup() {
+        mClassifier = new TextClassifier();
+        mDummyEntityScores = new ArrayMap<>();
+        mDummyEntityScores.put(TextClassifier.TYPE_ADDRESS, 0.2f);
+        mDummyEntityScores.put(TextClassifier.TYPE_PHONE, 0.7f);
+        mDummyEntityScores.put(TextClassifier.TYPE_OTHER, 0.3f);
+    }
+
+    private Map<String, Float> getEntityScores(float address, float phone, float other) {
+        final Map<String, Float> result = new ArrayMap<>();
+        if (address > 0.f) {
+            result.put(TextClassifier.TYPE_ADDRESS, address);
+        }
+        if (phone > 0.f) {
+            result.put(TextClassifier.TYPE_PHONE, phone);
+        }
+        if (other > 0.f) {
+            result.put(TextClassifier.TYPE_OTHER, other);
+        }
+        return result;
+    }
+
+    @Test
+    public void testParcel() {
+        final String fullText = "this is just a test";
+        final TextLinks reference = new TextLinks.Builder(fullText)
+                .addLink(0, 4, getEntityScores(0.f, 0.f, 1.f))
+                .addLink(5, 12, getEntityScores(.8f, .1f, .5f))
+                .build();
+
+        // Parcel and unparcel.
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        final TextLinks result = TextLinks.CREATOR.createFromParcel(parcel);
+        final List<TextLinks.TextLink> resultList = new ArrayList<>(result.getLinks());
+
+        assertEquals(2, resultList.size());
+        assertEquals(0, resultList.get(0).getStart());
+        assertEquals(4, resultList.get(0).getEnd());
+        assertEquals(1, resultList.get(0).getEntityCount());
+        assertEquals(TextClassifier.TYPE_OTHER, resultList.get(0).getEntity(0));
+        assertEquals(1.f, resultList.get(0).getConfidenceScore(TextClassifier.TYPE_OTHER),
+                1e-7f);
+        assertEquals(5, resultList.get(1).getStart());
+        assertEquals(12, resultList.get(1).getEnd());
+        assertEquals(3, resultList.get(1).getEntityCount());
+        assertEquals(TextClassifier.TYPE_ADDRESS, resultList.get(1).getEntity(0));
+        assertEquals(TextClassifier.TYPE_OTHER, resultList.get(1).getEntity(1));
+        assertEquals(TextClassifier.TYPE_PHONE, resultList.get(1).getEntity(2));
+        assertEquals(.8f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f);
+        assertEquals(.5f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_OTHER), 1e-7f);
+        assertEquals(.1f, resultList.get(1).getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f);
+    }
+
+    @Test
+    public void testParcelOptions() {
+        TextClassifier.EntityConfig entityConfig = new TextClassifier.EntityConfig(
+                TextClassifier.ENTITY_PRESET_NONE);
+        entityConfig.includeEntities("a", "b", "c");
+        entityConfig.excludeEntities("b");
+        TextLinks.Options reference = new TextLinks.Options();
+        reference.setDefaultLocales(LocaleListCompat.forLanguageTags("en-US,de-DE"));
+        reference.setEntityConfig(entityConfig);
+        reference.setApplyStrategy(TextLinks.APPLY_STRATEGY_REPLACE);
+        reference.setSpanFactory(new CustomSpanFactory());
+
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        TextLinks.Options result = TextLinks.Options.CREATOR.createFromParcel(parcel);
+
+        assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+        assertEquals(Arrays.asList("a", "c"), result.getEntityConfig().getEntities(mClassifier));
+        assertEquals(TextLinks.APPLY_STRATEGY_REPLACE, result.getApplyStrategy());
+        assertEquals(null, result.getSpanFactory());
+    }
+
+    @Test
+    public void testApplyDifferentText() {
+        SpannableString text = new SpannableString("foo");
+        TextLinks links = new TextLinks.Builder("bar").build();
+        assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null),
+                TextLinks.STATUS_DIFFERENT_TEXT);
+    }
+
+    @Test
+    public void testApplyNoLinks() {
+        SpannableString text = new SpannableString("foo");
+        TextLinks links = new TextLinks.Builder(text.toString()).build();
+        assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null),
+                TextLinks.STATUS_NO_LINKS_FOUND);
+    }
+
+    @Test
+    public void testApplyNoApplied() {
+        SpannableString text = new SpannableString("foo");
+        text.setSpan(new NoOpSpan(), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        TextLinks links = new TextLinks.Builder(text.toString()).addLink(
+                0, 3, mDummyEntityScores).build();
+        assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, null),
+                TextLinks.STATUS_NO_LINKS_APPLIED);
+    }
+
+    @Test
+    public void testApplyAppliedDefaultSpanFactory() {
+        SpannableString text = new SpannableString("foo");
+        TextLinks links = new TextLinks.Builder(text.toString()).addLink(
+                0, 3, mDummyEntityScores).build();
+        assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, null),
+                TextLinks.STATUS_LINKS_APPLIED);
+        TextLinks.TextLinkSpan[] spans = text.getSpans(0, 3, TextLinks.TextLinkSpan.class);
+        assertEquals(spans.length, 1);
+        assertTrue(links.getLinks().contains(spans[0].getTextLink()));
+    }
+
+    @Test
+    public void testApplyAppliedDefaultSpanFactoryReplace() {
+        SpannableString text = new SpannableString("foo");
+        text.setSpan(new NoOpSpan(), 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+        TextLinks links = new TextLinks.Builder(text.toString()).addLink(
+                0, 3, mDummyEntityScores).build();
+        assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_REPLACE, null),
+                TextLinks.STATUS_LINKS_APPLIED);
+        TextLinks.TextLinkSpan[] spans = text.getSpans(0, 3, TextLinks.TextLinkSpan.class);
+        assertEquals(spans.length, 1);
+        assertTrue(links.getLinks().contains(spans[0].getTextLink()));
+    }
+
+    @Test
+    public void testApplyAppliedCustomSpanFactory() {
+        SpannableString text = new SpannableString("foo");
+        TextLinks links = new TextLinks.Builder(text.toString()).addLink(
+                0, 3, mDummyEntityScores).build();
+        assertEquals(links.apply(text, TextLinks.APPLY_STRATEGY_IGNORE, new CustomSpanFactory()),
+                TextLinks.STATUS_LINKS_APPLIED);
+        CustomTextLinkSpan[] spans = text.getSpans(0, 3, CustomTextLinkSpan.class);
+        assertEquals(spans.length, 1);
+        assertTrue(links.getLinks().contains(spans[0].getTextLink()));
+    }
+}
diff --git a/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextSelectionTest.java b/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextSelectionTest.java
new file mode 100644
index 0000000..33a227b
--- /dev/null
+++ b/textclassifier/src/androidTest/java/androidx/view/textclassifier/TextSelectionTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.os.LocaleListCompat;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Instrumentation unit tests for {@link TextSelection}. */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class TextSelectionTest {
+    @Test
+    public void testParcel() {
+        final int startIndex = 13;
+        final int endIndex = 37;
+        final String signature = "signature";
+        final TextSelection reference = new TextSelection.Builder(startIndex, endIndex)
+                .setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f)
+                .setEntityType(TextClassifier.TYPE_PHONE, 0.7f)
+                .setEntityType(TextClassifier.TYPE_URL, 0.1f)
+                .setSignature(signature)
+                .build();
+
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        final TextSelection result = TextSelection.CREATOR.createFromParcel(parcel);
+
+        assertEquals(startIndex, result.getSelectionStartIndex());
+        assertEquals(endIndex, result.getSelectionEndIndex());
+        assertEquals(signature, result.getSignature());
+
+        assertEquals(3, result.getEntityCount());
+        assertEquals(TextClassifier.TYPE_PHONE, result.getEntity(0));
+        assertEquals(TextClassifier.TYPE_ADDRESS, result.getEntity(1));
+        assertEquals(TextClassifier.TYPE_URL, result.getEntity(2));
+        assertEquals(0.7f, result.getConfidenceScore(TextClassifier.TYPE_PHONE), 1e-7f);
+        assertEquals(0.3f, result.getConfidenceScore(TextClassifier.TYPE_ADDRESS), 1e-7f);
+        assertEquals(0.1f, result.getConfidenceScore(TextClassifier.TYPE_URL), 1e-7f);
+    }
+
+    @Test
+    public void testParcelOptions() {
+        TextSelection.Options reference = new TextSelection.Options();
+        reference.setDefaultLocales(LocaleListCompat.forLanguageTags("en-US,de-DE"));
+
+        // Parcel and unparcel.
+        final Parcel parcel = Parcel.obtain();
+        reference.writeToParcel(parcel, reference.describeContents());
+        parcel.setDataPosition(0);
+        TextSelection.Options result = TextSelection.Options.CREATOR.createFromParcel(
+                parcel);
+
+        assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
+    }
+}
diff --git a/textclassifier/src/main/AndroidManifest.xml b/textclassifier/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..05029b8
--- /dev/null
+++ b/textclassifier/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="androidx.view.textclassifier"/>
diff --git a/textclassifier/src/main/java/androidx/view/textclassifier/EntityConfidence.java b/textclassifier/src/main/java/androidx/view/textclassifier/EntityConfidence.java
new file mode 100644
index 0000000..7434a20
--- /dev/null
+++ b/textclassifier/src/main/java/androidx/view/textclassifier/EntityConfidence.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.FloatRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.util.Preconditions;
+import android.support.v4.util.SimpleArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Helper object for setting and getting entity scores for classified text.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY)
+final class EntityConfidence implements Parcelable {
+
+    private final ArrayMap<String, Float> mEntityConfidence = new ArrayMap<>();
+    private final ArrayList<String> mSortedEntities = new ArrayList<>();
+
+    EntityConfidence() {}
+
+    EntityConfidence(@NonNull EntityConfidence source) {
+        Preconditions.checkNotNull(source);
+        mEntityConfidence.putAll((SimpleArrayMap<String, Float>) source.mEntityConfidence);
+        mSortedEntities.addAll(source.mSortedEntities);
+    }
+
+    /**
+     * Constructs an EntityConfidence from a map of entity to confidence.
+     *
+     * Map entries that have 0 confidence are removed, and values greater than 1 are clamped to 1.
+     *
+     * @param source a map from entity to a confidence value in the range 0 (low confidence) to
+     *               1 (high confidence).
+     */
+    EntityConfidence(@NonNull Map<String, Float> source) {
+        Preconditions.checkNotNull(source);
+
+        // Prune non-existent entities and clamp to 1.
+        mEntityConfidence.ensureCapacity(source.size());
+        for (Map.Entry<String, Float> it : source.entrySet()) {
+            if (it.getValue() <= 0) continue;
+            mEntityConfidence.put(it.getKey(), Math.min(1, it.getValue()));
+        }
+        resetSortedEntitiesFromMap();
+    }
+
+    /**
+     * Returns an immutable list of entities found in the classified text ordered from
+     * high confidence to low confidence.
+     */
+    @NonNull
+    public List<String> getEntities() {
+        return Collections.unmodifiableList(mSortedEntities);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(String entity) {
+        if (mEntityConfidence.containsKey(entity)) {
+            return mEntityConfidence.get(entity);
+        }
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return mEntityConfidence.toString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mEntityConfidence.size());
+        for (Map.Entry<String, Float> entry : mEntityConfidence.entrySet()) {
+            dest.writeString(entry.getKey());
+            dest.writeFloat(entry.getValue());
+        }
+    }
+
+    public static final Parcelable.Creator<EntityConfidence> CREATOR =
+            new Parcelable.Creator<EntityConfidence>() {
+                @Override
+                public EntityConfidence createFromParcel(Parcel in) {
+                    return new EntityConfidence(in);
+                }
+
+                @Override
+                public EntityConfidence[] newArray(int size) {
+                    return new EntityConfidence[size];
+                }
+            };
+
+    private EntityConfidence(Parcel in) {
+        final int numEntities = in.readInt();
+        mEntityConfidence.ensureCapacity(numEntities);
+        for (int i = 0; i < numEntities; ++i) {
+            mEntityConfidence.put(in.readString(), in.readFloat());
+        }
+        resetSortedEntitiesFromMap();
+    }
+
+    private void resetSortedEntitiesFromMap() {
+        mSortedEntities.clear();
+        mSortedEntities.ensureCapacity(mEntityConfidence.size());
+        mSortedEntities.addAll(mEntityConfidence.keySet());
+        Collections.sort(mSortedEntities, new EntityConfidenceComparator());
+    }
+
+    /** Helper to sort entities according to their confidence. */
+    private class EntityConfidenceComparator implements Comparator<String> {
+        @Override
+        public int compare(String e1, String e2) {
+            float score1 = mEntityConfidence.get(e1);
+            float score2 = mEntityConfidence.get(e2);
+            return Float.compare(score2, score1);
+        }
+    }
+}
diff --git a/textclassifier/src/main/java/androidx/view/textclassifier/TextClassification.java b/textclassifier/src/main/java/androidx/view/textclassifier/TextClassification.java
new file mode 100644
index 0000000..799618a
--- /dev/null
+++ b/textclassifier/src/main/java/androidx/view/textclassifier/TextClassification.java
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v4.os.LocaleListCompat;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import androidx.view.textclassifier.TextClassifier.EntityType;
+
+/**
+ * Information for generating a widget to handle classified text.
+ *
+ * <p>A TextClassification object contains icons, labels, and intents that may be used to build a
+ * widget that can be used to act on classified text. There is the concept of a <i>primary
+ * action</i> and other <i>secondary actions</i>.
+ *
+ * <p>e.g. building a view that, when clicked, shares the classified text with the preferred app:
+ *
+ * <pre>{@code
+ *   // Called preferably outside the UiThread.
+ *   TextClassification classification = textClassifier.classifyText(allText, 10, 25);
+ *
+ *   // Called on the UiThread.
+ *   Button button = new Button(context);
+ *   button.setCompoundDrawablesWithIntrinsicBounds(classification.getIcon(), null, null, null);
+ *   button.setText(classification.getLabel());
+ *   button.setOnClickListener(v -> context.startActivity(classification.getIntent()));
+ * }</pre>
+ *
+ * TODO: describe how to start action mode for classified text.
+ */
+public final class TextClassification implements Parcelable {
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    static final TextClassification EMPTY = new TextClassification.Builder().build();
+
+    // TODO: investigate a way to derive this based on device properties.
+    private static final int MAX_PRIMARY_ICON_SIZE = 192;
+    private static final int MAX_SECONDARY_ICON_SIZE = 144;
+
+    @Nullable private final String mText;
+    @Nullable private final Drawable mPrimaryIcon;
+    @Nullable private final String mPrimaryLabel;
+    @Nullable private final Intent mPrimaryIntent;
+    @NonNull private final List<Drawable> mSecondaryIcons;
+    @NonNull private final List<String> mSecondaryLabels;
+    @NonNull private final List<Intent> mSecondaryIntents;
+    @NonNull private final EntityConfidence mEntityConfidence;
+    @NonNull private final String mSignature;
+
+    private TextClassification(
+            @Nullable String text,
+            @Nullable Drawable primaryIcon,
+            @Nullable String primaryLabel,
+            @Nullable Intent primaryIntent,
+            @NonNull List<Drawable> secondaryIcons,
+            @NonNull List<String> secondaryLabels,
+            @NonNull List<Intent> secondaryIntents,
+            @NonNull Map<String, Float> entityConfidence,
+            @NonNull String signature) {
+        Preconditions.checkArgument(secondaryLabels.size() == secondaryIntents.size());
+        Preconditions.checkArgument(secondaryIcons.size() == secondaryIntents.size());
+        mText = text;
+        mPrimaryIcon = primaryIcon;
+        mPrimaryLabel = primaryLabel;
+        mPrimaryIntent = primaryIntent;
+        mSecondaryIcons = secondaryIcons;
+        mSecondaryLabels = secondaryLabels;
+        mSecondaryIntents = secondaryIntents;
+        mEntityConfidence = new EntityConfidence(entityConfidence);
+        mSignature = signature;
+    }
+
+    /**
+     * Gets the classified text.
+     */
+    @Nullable
+    public String getText() {
+        return mText;
+    }
+
+    /**
+     * Returns the number of entities found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getEntityCount() {
+        return mEntityConfidence.getEntities().size();
+    }
+
+    /**
+     * Returns the entity at the specified index. Entities are ordered from high confidence
+     * to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getEntityCount() for the number of entities available.
+     */
+    @NonNull
+    public @EntityType String getEntity(int index) {
+        return mEntityConfidence.getEntities().get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@EntityType String entity) {
+        return mEntityConfidence.getConfidenceScore(entity);
+    }
+
+    /**
+     * Returns the number of <i>secondary</i> actions that are available to act on the classified
+     * text.
+     *
+     * <p><strong>Note: </strong> that there may or may not be a <i>primary</i> action.
+     *
+     * @see #getSecondaryIntent(int)
+     * @see #getSecondaryLabel(int)
+     * @see #getSecondaryIcon(int)
+     */
+    @IntRange(from = 0)
+    public int getSecondaryActionsCount() {
+        return mSecondaryIntents.size();
+    }
+
+    /**
+     * Returns one of the <i>secondary</i> icons that maybe rendered on a widget used to act on the
+     * classified text.
+     *
+     * @param index Index of the action to get the icon for.
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getSecondaryActionsCount() for the number of actions available.
+     * @see #getSecondaryIntent(int)
+     * @see #getSecondaryLabel(int)
+     * @see #getIcon()
+     */
+    @Nullable
+    public Drawable getSecondaryIcon(int index) {
+        return mSecondaryIcons.get(index);
+    }
+
+    /**
+     * Returns an icon for the <i>primary</i> intent that may be rendered on a widget used to act
+     * on the classified text.
+     *
+     * @see #getSecondaryIcon(int)
+     */
+    @Nullable
+    public Drawable getIcon() {
+        return mPrimaryIcon;
+    }
+
+    /**
+     * Returns one of the <i>secondary</i> labels that may be rendered on a widget used to act on
+     * the classified text.
+     *
+     * @param index Index of the action to get the label for.
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getSecondaryActionsCount()
+     * @see #getSecondaryIntent(int)
+     * @see #getSecondaryIcon(int)
+     * @see #getLabel()
+     */
+    @Nullable
+    public CharSequence getSecondaryLabel(int index) {
+        return mSecondaryLabels.get(index);
+    }
+
+    /**
+     * Returns a label for the <i>primary</i> intent that may be rendered on a widget used to act
+     * on the classified text.
+     *
+     * @see #getSecondaryLabel(int)
+     */
+    @Nullable
+    public CharSequence getLabel() {
+        return mPrimaryLabel;
+    }
+
+    /**
+     * Returns one of the <i>secondary</i> intents that may be fired to act on the classified text.
+     *
+     * @param index Index of the action to get the intent for.
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getSecondaryActionsCount()
+     * @see #getSecondaryLabel(int)
+     * @see #getSecondaryIcon(int)
+     * @see #getIntent()
+     */
+    @Nullable
+    public Intent getSecondaryIntent(int index) {
+        return mSecondaryIntents.get(index);
+    }
+
+    /**
+     * Returns the <i>primary</i> intent that may be fired to act on the classified text.
+     *
+     * @see #getSecondaryIntent(int)
+     */
+    @Nullable
+    public Intent getIntent() {
+        return mPrimaryIntent;
+    }
+
+    /**
+     * Returns the signature for this object.
+     * The TextClassifier that generates this object may use it as a way to internally identify
+     * this object.
+     */
+    @NonNull
+    public String getSignature() {
+        return mSignature;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(Locale.US, "TextClassification {"
+                        + "text=%s, entities=%s, "
+                        + "primaryLabel=%s, secondaryLabels=%s, "
+                        + "primaryIntent=%s, secondaryIntents=%s, "
+                        + "signature=%s}",
+                mText, mEntityConfidence,
+                mPrimaryLabel, mSecondaryLabels,
+                mPrimaryIntent, mSecondaryIntents,
+                mSignature);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mText);
+        final Bitmap primaryIconBitmap = drawableToBitmap(mPrimaryIcon, MAX_PRIMARY_ICON_SIZE);
+        dest.writeInt(primaryIconBitmap != null ? 1 : 0);
+        if (primaryIconBitmap != null) {
+            primaryIconBitmap.writeToParcel(dest, flags);
+        }
+        dest.writeString(mPrimaryLabel);
+        dest.writeInt(mPrimaryIntent != null ? 1 : 0);
+        if (mPrimaryIntent != null) {
+            mPrimaryIntent.writeToParcel(dest, flags);
+        }
+        dest.writeTypedList(drawablesToBitmaps(mSecondaryIcons, MAX_SECONDARY_ICON_SIZE));
+        dest.writeStringList(mSecondaryLabels);
+        dest.writeTypedList(mSecondaryIntents);
+        mEntityConfidence.writeToParcel(dest, flags);
+        dest.writeString(mSignature);
+    }
+
+    public static final Parcelable.Creator<TextClassification> CREATOR =
+            new Parcelable.Creator<TextClassification>() {
+                @Override
+                public TextClassification createFromParcel(Parcel in) {
+                    return new TextClassification(in);
+                }
+
+                @Override
+                public TextClassification[] newArray(int size) {
+                    return new TextClassification[size];
+                }
+            };
+
+    private TextClassification(Parcel in) {
+        mText = in.readString();
+        mPrimaryIcon = in.readInt() == 0
+                ? null : new BitmapDrawable(null, Bitmap.CREATOR.createFromParcel(in));
+        mPrimaryLabel = in.readString();
+        mPrimaryIntent = in.readInt() == 0 ? null : Intent.CREATOR.createFromParcel(in);
+        mSecondaryIcons = bitmapsToDrawables(in.createTypedArrayList(Bitmap.CREATOR));
+        mSecondaryLabels = in.createStringArrayList();
+        mSecondaryIntents = in.createTypedArrayList(Intent.CREATOR);
+        mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
+        mSignature = in.readString();
+    }
+
+    /**
+     * Returns a Bitmap representation of the Drawable
+     *
+     * @param drawable The drawable to convert.
+     * @param maxDims The maximum edge length of the resulting bitmap (in pixels).
+     */
+    @Nullable
+    private static Bitmap drawableToBitmap(@Nullable Drawable drawable, int maxDims) {
+        if (drawable == null) {
+            return null;
+        }
+        final int actualWidth = Math.max(1, drawable.getIntrinsicWidth());
+        final int actualHeight = Math.max(1, drawable.getIntrinsicHeight());
+        final double scaleWidth = ((double) maxDims) / actualWidth;
+        final double scaleHeight = ((double) maxDims) / actualHeight;
+        final double scale = Math.min(1.0, Math.min(scaleWidth, scaleHeight));
+        final int width = (int) (actualWidth * scale);
+        final int height = (int) (actualHeight * scale);
+        if (drawable instanceof BitmapDrawable) {
+            final BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+            if (actualWidth != width || actualHeight != height) {
+                return Bitmap.createScaledBitmap(
+                        bitmapDrawable.getBitmap(), width, height, /*filter=*/false);
+            } else {
+                return bitmapDrawable.getBitmap();
+            }
+        } else {
+            final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+            final Canvas canvas = new Canvas(bitmap);
+            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+            drawable.draw(canvas);
+            return bitmap;
+        }
+    }
+
+    /**
+     * Returns a list of drawables converted to Bitmaps
+     *
+     * @param drawables The drawables to convert.
+     * @param maxDims The maximum edge length of the resulting bitmaps (in pixels).
+     */
+    private static List<Bitmap> drawablesToBitmaps(List<Drawable> drawables, int maxDims) {
+        final List<Bitmap> bitmaps = new ArrayList<>(drawables.size());
+        for (Drawable drawable : drawables) {
+            bitmaps.add(drawableToBitmap(drawable, maxDims));
+        }
+        return bitmaps;
+    }
+
+    /** Returns a list of drawable wrappers for a list of bitmaps. */
+    private static List<Drawable> bitmapsToDrawables(List<Bitmap> bitmaps) {
+        final List<Drawable> drawables = new ArrayList<>(bitmaps.size());
+        for (Bitmap bitmap : bitmaps) {
+            if (bitmap != null) {
+                drawables.add(new BitmapDrawable(null, bitmap));
+            } else {
+                drawables.add(null);
+            }
+        }
+        return drawables;
+    }
+
+    /**
+     * Builder for building {@link TextClassification} objects.
+     *
+     * <p>e.g.
+     *
+     * <pre>{@code
+     *   TextClassification classification = new TextClassification.Builder()
+     *          .setText(classifiedText)
+     *          .setEntityType(TextClassifier.TYPE_EMAIL, 0.9)
+     *          .setEntityType(TextClassifier.TYPE_OTHER, 0.1)
+     *          .setPrimaryAction(intent, label, icon)
+     *          .addSecondaryAction(intent1, label1, icon1)
+     *          .addSecondaryAction(intent2, label2, icon2)
+     *          .build();
+     * }</pre>
+     */
+    public static final class Builder {
+
+        @NonNull private String mText;
+        @NonNull private final List<Drawable> mSecondaryIcons = new ArrayList<>();
+        @NonNull private final List<String> mSecondaryLabels = new ArrayList<>();
+        @NonNull private final List<Intent> mSecondaryIntents = new ArrayList<>();
+        @NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
+        @Nullable Drawable mPrimaryIcon;
+        @Nullable String mPrimaryLabel;
+        @Nullable Intent mPrimaryIntent;
+        @NonNull private String mSignature = "";
+
+        /**
+         * Sets the classified text.
+         */
+        public Builder setText(@Nullable String text) {
+            mText = text;
+            return this;
+        }
+
+        /**
+         * Sets an entity type for the classification result and assigns a confidence score.
+         * If a confidence score had already been set for the specified entity type, this will
+         * override that score.
+         *
+         * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+         *      0 implies the entity does not exist for the classified text.
+         *      Values greater than 1 are clamped to 1.
+         */
+        public Builder setEntityType(
+                @NonNull @EntityType String type,
+                @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+            mEntityConfidence.put(type, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Adds an <i>secondary</i> action that may be performed on the classified text.
+         * Secondary actions are in addition to the <i>primary</i> action which may or may not
+         * exist.
+         *
+         * <p>The label and icon are used for rendering of widgets that offer the intent.
+         * Actions should be added in order of priority.
+         *
+         * <p><stong>Note: </stong> If all input parameters are set to null, this method will be a
+         * no-op.
+         *
+         * @see #setPrimaryAction(Intent, String, Drawable)
+         */
+        public Builder addSecondaryAction(
+                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
+            if (intent != null || label != null || icon != null) {
+                mSecondaryIntents.add(intent);
+                mSecondaryLabels.add(label);
+                mSecondaryIcons.add(icon);
+            }
+            return this;
+        }
+
+        /**
+         * Removes all the <i>secondary</i> actions.
+         */
+        public Builder clearSecondaryActions() {
+            mSecondaryIntents.clear();
+            mSecondaryLabels.clear();
+            mSecondaryIcons.clear();
+            return this;
+        }
+
+        /**
+         * Sets the <i>primary</i> action that may be performed on the classified text. This is
+         * equivalent to calling {@code setIntent(intent).setLabel(label).setIcon(icon)}.
+         *
+         * <p><strong>Note: </strong>If all input parameters are null, there will be no
+         * <i>primary</i> action but there may still be <i>secondary</i> actions.
+         *
+         * @see #addSecondaryAction(Intent, String, Drawable)
+         */
+        public Builder setPrimaryAction(
+                @Nullable Intent intent, @Nullable String label, @Nullable Drawable icon) {
+            return setIntent(intent).setLabel(label).setIcon(icon);
+        }
+
+        /**
+         * Sets the icon for the <i>primary</i> action that may be rendered on a widget used to act
+         * on the classified text.
+         *
+         * @see #setPrimaryAction(Intent, String, Drawable)
+         */
+        public Builder setIcon(@Nullable Drawable icon) {
+            mPrimaryIcon = icon;
+            return this;
+        }
+
+        /**
+         * Sets the label for the <i>primary</i> action that may be rendered on a widget used to
+         * act on the classified text.
+         *
+         * @see #setPrimaryAction(Intent, String, Drawable)
+         */
+        public Builder setLabel(@Nullable String label) {
+            mPrimaryLabel = label;
+            return this;
+        }
+
+        /**
+         * Sets the intent for the <i>primary</i> action that may be fired to act on the classified
+         * text.
+         *
+         * @see #setPrimaryAction(Intent, String, Drawable)
+         */
+        public Builder setIntent(@Nullable Intent intent) {
+            mPrimaryIntent = intent;
+            return this;
+        }
+
+        /**
+         * Sets a signature for the TextClassification object.
+         * The TextClassifier that generates the TextClassification object may use it as a way to
+         * internally identify the TextClassification object.
+         */
+        public Builder setSignature(@NonNull String signature) {
+            mSignature = Preconditions.checkNotNull(signature);
+            return this;
+        }
+
+        /**
+         * Builds and returns a {@link TextClassification} object.
+         */
+        public TextClassification build() {
+            return new TextClassification(
+                    mText,
+                    mPrimaryIcon, mPrimaryLabel, mPrimaryIntent,
+                    mSecondaryIcons, mSecondaryLabels, mSecondaryIntents,
+                    mEntityConfidence, mSignature);
+        }
+    }
+
+    /**
+     * Optional input parameters for generating TextClassification.
+     */
+    public static final class Options implements Parcelable {
+
+        private @Nullable LocaleListCompat mDefaultLocales;
+        private @Nullable Calendar mReferenceTime;
+
+        public Options() {}
+
+        /**
+         * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+         *      the provided text. If no locale preferences exist, set this to null or an empty
+         *      locale list.
+         */
+        public Options setDefaultLocales(@Nullable LocaleListCompat defaultLocales) {
+            mDefaultLocales = defaultLocales;
+            return this;
+        }
+
+        /**
+         * @param referenceTime reference time based on which relative dates (e.g. "tomorrow" should
+         *      be interpreted. This should usually be the time when the text was originally
+         *      composed. If no reference time is set, now is used.
+         */
+        public Options setReferenceTime(Calendar referenceTime) {
+            mReferenceTime = referenceTime;
+            return this;
+        }
+
+        /**
+         * @return ordered list of locale preferences that can be used to disambiguate
+         *      the provided text.
+         */
+        @Nullable
+        public LocaleListCompat getDefaultLocales() {
+            return mDefaultLocales;
+        }
+
+        /**
+         * @return reference time based on which relative dates (e.g. "tomorrow") should be
+         *      interpreted.
+         */
+        @Nullable
+        public Calendar getReferenceTime() {
+            return mReferenceTime;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mDefaultLocales != null ? 1 : 0);
+            if (mDefaultLocales != null) {
+                dest.writeString(mDefaultLocales.toLanguageTags());
+            }
+            dest.writeInt(mReferenceTime != null ? 1 : 0);
+            if (mReferenceTime != null) {
+                dest.writeSerializable(mReferenceTime);
+            }
+        }
+
+        public static final Parcelable.Creator<Options> CREATOR =
+                new Parcelable.Creator<Options>() {
+                    @Override
+                    public Options createFromParcel(Parcel in) {
+                        return new Options(in);
+                    }
+
+                    @Override
+                    public Options[] newArray(int size) {
+                        return new Options[size];
+                    }
+                };
+
+        private Options(Parcel in) {
+            if (in.readInt() > 0) {
+                mDefaultLocales = LocaleListCompat.forLanguageTags(in.readString());
+            }
+            if (in.readInt() > 0) {
+                mReferenceTime = (Calendar) in.readSerializable();
+            }
+        }
+    }
+}
diff --git a/textclassifier/src/main/java/androidx/view/textclassifier/TextClassifier.java b/textclassifier/src/main/java/androidx/view/textclassifier/TextClassifier.java
new file mode 100644
index 0000000..4dc7236
--- /dev/null
+++ b/textclassifier/src/main/java/androidx/view/textclassifier/TextClassifier.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.IntDef;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.StringDef;
+import android.support.v4.util.ArraySet;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Interface for providing text classification related features.
+ *
+ * TextClassifier acts as a proxy to either the system provided TextClassifier, or an equivalent
+ * implementation provided by an app. Each instance of the class therefore represents one connection
+ * to the classifier implementation.
+ *
+ * <p>Unless otherwise stated, methods of this interface are blocking operations.
+ * Avoid calling them on the UI thread.
+ */
+public class TextClassifier {
+
+    // TODO: describe in the class documentation how a TC implementation in chosen/located.
+
+    /** Signifies that the TextClassifier did not identify an entity. */
+    public static final String TYPE_UNKNOWN = "";
+    /** Signifies that the classifier ran, but didn't recognize a know entity. */
+    public static final String TYPE_OTHER = "other";
+    /** Identifies an e-mail address. */
+    public static final String TYPE_EMAIL = "email";
+    /** Identifies a phone number. */
+    public static final String TYPE_PHONE = "phone";
+    /** Identifies a physical address. */
+    public static final String TYPE_ADDRESS = "address";
+    /** Identifies a URL. */
+    public static final String TYPE_URL = "url";
+
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef(value = {
+            TYPE_UNKNOWN,
+            TYPE_OTHER,
+            TYPE_EMAIL,
+            TYPE_PHONE,
+            TYPE_ADDRESS,
+            TYPE_URL,
+    })
+    @interface EntityType {}
+
+    /** Designates that the TextClassifier should identify all entity types it can. **/
+    static final int ENTITY_PRESET_ALL = 0;
+    /** Designates that the TextClassifier should identify no entities. **/
+    static final int ENTITY_PRESET_NONE = 1;
+    /** Designates that the TextClassifier should identify a base set of entities determined by the
+     * TextClassifier. **/
+    static final int ENTITY_PRESET_BASE = 2;
+
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {ENTITY_PRESET_ALL, ENTITY_PRESET_NONE, ENTITY_PRESET_BASE})
+    @interface EntityPreset {}
+
+    // TODO: add constructor, suggestSelection, classifyText, generateLinks, logEvent
+
+    /**
+     * Returns a {@link Collection} of the entity types in the specified preset.
+     *
+     * @see #ENTITY_PRESET_ALL
+     * @see #ENTITY_PRESET_NONE
+     */
+    /* package */ Collection<String> getEntitiesForPreset(@EntityPreset int entityPreset) {
+        // TODO: forward call to the classifier implementation.
+        return Collections.EMPTY_LIST;
+    }
+
+    /**
+     * Configuration object for specifying what entities to identify.
+     *
+     * Configs are initially based on a predefined preset, and can be modified from there.
+     */
+    static final class EntityConfig implements Parcelable {
+        private final @EntityPreset int mEntityPreset;
+        private final Collection<String> mExcludedEntityTypes;
+        private final Collection<String> mIncludedEntityTypes;
+
+        EntityConfig(@EntityPreset int mEntityPreset) {
+            this.mEntityPreset = mEntityPreset;
+            mExcludedEntityTypes = new ArraySet<>();
+            mIncludedEntityTypes = new ArraySet<>();
+        }
+
+        /**
+         * Specifies an entity to include in addition to any specified by the enity preset.
+         *
+         * Note that if an entity has been excluded, the exclusion will take precedence.
+         */
+        public EntityConfig includeEntities(String... entities) {
+            mIncludedEntityTypes.addAll(Arrays.asList(entities));
+            return this;
+        }
+
+        /**
+         * Specifies an entity to be excluded.
+         */
+        public EntityConfig excludeEntities(String... entities) {
+            mExcludedEntityTypes.addAll(Arrays.asList(entities));
+            return this;
+        }
+
+        /**
+         * Returns an unmodifiable list of the final set of entities to find.
+         */
+        public List<String> getEntities(TextClassifier textClassifier) {
+            ArrayList<String> entities = new ArrayList<>();
+            for (String entity : textClassifier.getEntitiesForPreset(mEntityPreset)) {
+                if (!mExcludedEntityTypes.contains(entity)) {
+                    entities.add(entity);
+                }
+            }
+            for (String entity : mIncludedEntityTypes) {
+                if (!mExcludedEntityTypes.contains(entity) && !entities.contains(entity)) {
+                    entities.add(entity);
+                }
+            }
+            return Collections.unmodifiableList(entities);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mEntityPreset);
+            dest.writeStringList(new ArrayList<>(mExcludedEntityTypes));
+            dest.writeStringList(new ArrayList<>(mIncludedEntityTypes));
+        }
+
+        public static final Parcelable.Creator<EntityConfig> CREATOR =
+                new Parcelable.Creator<EntityConfig>() {
+                    @Override
+                    public EntityConfig createFromParcel(Parcel in) {
+                        return new EntityConfig(in);
+                    }
+
+                    @Override
+                    public EntityConfig[] newArray(int size) {
+                        return new EntityConfig[size];
+                    }
+                };
+
+        private EntityConfig(Parcel in) {
+            mEntityPreset = in.readInt();
+            mExcludedEntityTypes = new ArraySet<>(in.createStringArrayList());
+            mIncludedEntityTypes = new ArraySet<>(in.createStringArrayList());
+        }
+    }
+}
diff --git a/textclassifier/src/main/java/androidx/view/textclassifier/TextLinks.java b/textclassifier/src/main/java/androidx/view/textclassifier/TextLinks.java
new file mode 100644
index 0000000..79810f5
--- /dev/null
+++ b/textclassifier/src/main/java/androidx/view/textclassifier/TextLinks.java
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RestrictTo;
+import android.support.v4.os.LocaleListCompat;
+import android.support.v4.util.Preconditions;
+import android.text.Spannable;
+import android.text.style.ClickableSpan;
+import android.view.View;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import androidx.view.textclassifier.TextClassifier.EntityType;
+
+/**
+ * A collection of links, representing subsequences of text and the entity types (phone number,
+ * address, url, etc) they may be.
+ */
+public final class TextLinks implements Parcelable {
+    private final String mFullText;
+    private final List<TextLink> mLinks;
+
+    /** Links were successfully applied to the text. */
+    public static final int STATUS_LINKS_APPLIED = 0;
+    /** No links exist to apply to text. Links count is zero. */
+    public static final int STATUS_NO_LINKS_FOUND = 1;
+    /** No links applied to text. The links were filtered out. */
+    public static final int STATUS_NO_LINKS_APPLIED = 2;
+    /** The specified text does not match the text used to generate the links. */
+    public static final int STATUS_DIFFERENT_TEXT = 3;
+
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {
+            STATUS_LINKS_APPLIED,
+            STATUS_NO_LINKS_FOUND,
+            STATUS_NO_LINKS_APPLIED,
+            STATUS_DIFFERENT_TEXT
+    })
+    public @interface Status {}
+
+    /** Do not replace {@link ClickableSpan}s that exist where the {@link TextLinkSpan} needs to
+     * be applied to. Do not apply the TextLinkSpan. **/
+    public static final int APPLY_STRATEGY_IGNORE = 0;
+    /** Replace any {@link ClickableSpan}s that exist where the {@link TextLinkSpan} needs to be
+     * applied to. **/
+    public static final int APPLY_STRATEGY_REPLACE = 1;
+
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({APPLY_STRATEGY_IGNORE, APPLY_STRATEGY_REPLACE})
+    public @interface ApplyStrategy {}
+
+    private TextLinks(String fullText, ArrayList<TextLink> links) {
+        mFullText = fullText;
+        mLinks = Collections.unmodifiableList(links);
+    }
+
+    /**
+     * Returns an unmodifiable Collection of the links.
+     */
+    public Collection<TextLink> getLinks() {
+        return mLinks;
+    }
+
+    /**
+     * Annotates the given text with the generated links. It will fail if the provided text doesn't
+     * match the original text used to crete the TextLinks.
+     *
+     * @param text the text to apply the links to. Must match the original text.
+     * @param spanFactory a factory to generate spans from TextLinks. Will use a default if null.
+     *
+     * @return one of {@link #STATUS_LINKS_APPLIED}, {@link #STATUS_NO_LINKS_FOUND},
+     *      {@link #STATUS_NO_LINKS_APPLIED}, {@link #STATUS_DIFFERENT_TEXT}
+     */
+    @Status
+    public int apply(
+            @NonNull Spannable text,
+            @ApplyStrategy int applyStrategy,
+            @Nullable SpanFactory spanFactory) {
+        Preconditions.checkNotNull(text);
+        checkValidApplyStrategy(applyStrategy);
+        if (!mFullText.equals(text.toString())) {
+            return STATUS_DIFFERENT_TEXT;
+        }
+        if (mLinks.isEmpty()) {
+            return STATUS_NO_LINKS_FOUND;
+        }
+
+        if (spanFactory == null) {
+            spanFactory = DEFAULT_SPAN_FACTORY;
+        }
+        int applyCount = 0;
+        for (TextLink link : mLinks) {
+            final TextLinkSpan span = spanFactory.createSpan(link);
+            if (span != null) {
+                final ClickableSpan[] existingSpans = text.getSpans(
+                        link.getStart(), link.getEnd(), ClickableSpan.class);
+                if (existingSpans.length > 0) {
+                    if (applyStrategy == APPLY_STRATEGY_REPLACE) {
+                        for (ClickableSpan existingSpan : existingSpans) {
+                            text.removeSpan(existingSpan);
+                        }
+                        text.setSpan(span, link.getStart(), link.getEnd(),
+                                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                        applyCount++;
+                    }
+                } else {
+                    text.setSpan(span, link.getStart(), link.getEnd(),
+                            Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+                    applyCount++;
+                }
+            }
+        }
+        if (applyCount == 0) {
+            return STATUS_NO_LINKS_APPLIED;
+        }
+        return STATUS_LINKS_APPLIED;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mFullText);
+        dest.writeTypedList(mLinks);
+    }
+
+    public static final Parcelable.Creator<TextLinks> CREATOR =
+            new Parcelable.Creator<TextLinks>() {
+                @Override
+                public TextLinks createFromParcel(Parcel in) {
+                    return new TextLinks(in);
+                }
+
+                @Override
+                public TextLinks[] newArray(int size) {
+                    return new TextLinks[size];
+                }
+            };
+
+    private TextLinks(Parcel in) {
+        mFullText = in.readString();
+        mLinks = in.createTypedArrayList(TextLink.CREATOR);
+    }
+
+    /**
+     * A link, identifying a substring of text and possible entity types for it.
+     */
+    public static final class TextLink implements Parcelable {
+        private final EntityConfidence mEntityScores;
+        private final int mStart;
+        private final int mEnd;
+
+        /**
+         * Create a new TextLink.
+         *
+         * @throws IllegalArgumentException if entityScores is null or empty.
+         */
+        TextLink(int start, int end, @NonNull Map<String, Float> entityScores) {
+            Preconditions.checkNotNull(entityScores);
+            Preconditions.checkArgument(!entityScores.isEmpty());
+            Preconditions.checkArgument(start <= end);
+            mStart = start;
+            mEnd = end;
+            mEntityScores = new EntityConfidence(entityScores);
+        }
+
+        /**
+         * Returns the start index of this link in the original text.
+         *
+         * @return the start index.
+         */
+        public int getStart() {
+            return mStart;
+        }
+
+        /**
+         * Returns the end index of this link in the original text.
+         *
+         * @return the end index.
+         */
+        public int getEnd() {
+            return mEnd;
+        }
+
+        /**
+         * Returns the number of entity types that have confidence scores.
+         *
+         * @return the entity count.
+         */
+        public int getEntityCount() {
+            return mEntityScores.getEntities().size();
+        }
+
+        /**
+         * Returns the entity type at a given index. Entity types are sorted by confidence.
+         *
+         * @return the entity type at the provided index.
+         */
+        @NonNull public @EntityType String getEntity(int index) {
+            return mEntityScores.getEntities().get(index);
+        }
+
+        /**
+         * Returns the confidence score for a particular entity type.
+         *
+         * @param entityType the entity type.
+         */
+        public @FloatRange(from = 0.0, to = 1.0) float getConfidenceScore(
+                @EntityType String entityType) {
+            return mEntityScores.getConfidenceScore(entityType);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            mEntityScores.writeToParcel(dest, flags);
+            dest.writeInt(mStart);
+            dest.writeInt(mEnd);
+        }
+
+        public static final Parcelable.Creator<TextLink> CREATOR =
+                new Parcelable.Creator<TextLink>() {
+                    @Override
+                    public TextLink createFromParcel(Parcel in) {
+                        return new TextLink(in);
+                    }
+
+                    @Override
+                    public TextLink[] newArray(int size) {
+                        return new TextLink[size];
+                    }
+                };
+
+        private TextLink(Parcel in) {
+            mEntityScores = EntityConfidence.CREATOR.createFromParcel(in);
+            mStart = in.readInt();
+            mEnd = in.readInt();
+        }
+    }
+
+    /**
+     * Optional input parameters for generating TextLinks.
+     */
+    public static final class Options implements Parcelable {
+
+        private @Nullable LocaleListCompat mDefaultLocales;
+        private TextClassifier.EntityConfig mEntityConfig;
+        private @ApplyStrategy int mApplyStrategy;
+        private @Nullable SpanFactory mSpanFactory;
+
+        public Options() {}
+
+        /**
+         * @param defaultLocales ordered list of locale preferences that may be used to
+         *                       disambiguate the provided text. If no locale preferences exist,
+         *                       set this to null or an empty locale list.
+         */
+        public Options setDefaultLocales(@Nullable LocaleListCompat defaultLocales) {
+            mDefaultLocales = defaultLocales;
+            return this;
+        }
+
+        /**
+         * Sets the entity configuration to use. This determines what types of entities the
+         * TextClassifier will look for.
+         *
+         * @param entityConfig EntityConfig to use
+         */
+        public Options setEntityConfig(@Nullable TextClassifier.EntityConfig entityConfig) {
+            mEntityConfig = entityConfig;
+            return this;
+        }
+
+        /**
+         * Sets a strategy for resolving conflicts when applying generated links to text that
+         * already have links.
+         *
+         * @throws IllegalArgumentException if applyStrategy is not valid.
+         * @see #APPLY_STRATEGY_IGNORE
+         * @see #APPLY_STRATEGY_REPLACE
+         */
+        public Options setApplyStrategy(@ApplyStrategy int applyStrategy) {
+            checkValidApplyStrategy(applyStrategy);
+            mApplyStrategy = applyStrategy;
+            return this;
+        }
+
+        /**
+         * Sets a factory for converting a TextLink to a TextLinkSpan.
+         *
+         * <p><strong>Note: </strong>This is not parceled over IPC.
+         */
+        public Options setSpanFactory(@Nullable SpanFactory spanFactory) {
+            mSpanFactory = spanFactory;
+            return this;
+        }
+
+        /**
+         * @return ordered list of locale preferences that can be used to disambiguate
+         *      the provided text.
+         */
+        @Nullable
+        public LocaleListCompat getDefaultLocales() {
+            return mDefaultLocales;
+        }
+
+        /**
+         * @return The config representing the set of entities to look for.
+         * @see #setEntityConfig(TextClassifier.EntityConfig)
+         */
+        @Nullable
+        public TextClassifier.EntityConfig getEntityConfig() {
+            return mEntityConfig;
+        }
+
+        /**
+         * Returns the strategy for resolving conflicts when applying generated links to text that
+         * already have links.
+         *
+         * @see #APPLY_STRATEGY_IGNORE
+         * @see #APPLY_STRATEGY_REPLACE
+         */
+        @ApplyStrategy
+        public int getApplyStrategy() {
+            return mApplyStrategy;
+        }
+
+        /**
+         * Returns a factory for converting a TextLink to a TextLinkSpan.
+         *
+         * <p><strong>Note: </strong>This is not parcelable and will always return null if read
+         *      from a parcel
+         */
+        @Nullable
+        public SpanFactory getSpanFactory() {
+            return mSpanFactory;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mDefaultLocales != null ? 1 : 0);
+            if (mDefaultLocales != null) {
+                dest.writeString(mDefaultLocales.toLanguageTags());
+            }
+            dest.writeInt(mEntityConfig != null ? 1 : 0);
+            if (mEntityConfig != null) {
+                mEntityConfig.writeToParcel(dest, flags);
+            }
+            dest.writeInt(mApplyStrategy);
+            // mSpanFactory is not parcelable
+        }
+
+        public static final Parcelable.Creator<Options> CREATOR =
+                new Parcelable.Creator<Options>() {
+                    @Override
+                    public Options createFromParcel(Parcel in) {
+                        return new Options(in);
+                    }
+
+                    @Override
+                    public Options[] newArray(int size) {
+                        return new Options[size];
+                    }
+                };
+
+        private Options(Parcel in) {
+            if (in.readInt() > 0) {
+                mDefaultLocales = LocaleListCompat.forLanguageTags(in.readString());
+            }
+            if (in.readInt() > 0) {
+                mEntityConfig = TextClassifier.EntityConfig.CREATOR.createFromParcel(in);
+            }
+            mApplyStrategy = in.readInt();
+            // mSpanFactory is not parcelable
+        }
+    }
+
+    /**
+     * A function to create spans from TextLinks.
+     *
+     * Hidden until we convinced we want it to be part of the public API.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public interface SpanFactory {
+
+        /** Creates a span from a text link. */
+        TextLinkSpan createSpan(TextLink textLink);
+    }
+
+    /**
+     * A ClickableSpan for a TextLink.
+     */
+    public static class TextLinkSpan extends ClickableSpan {
+
+        private final TextLink mTextLink;
+
+        public TextLinkSpan(@Nullable TextLink textLink) {
+            mTextLink = textLink;
+        }
+
+        @Override
+        public void onClick(View widget) {
+            // TODO(jalt): integrate with AppCompatTextView to show action mode.
+        }
+
+        public final TextLink getTextLink() {
+            return mTextLink;
+        }
+    }
+
+    /**
+     * A builder to construct a TextLinks instance.
+     */
+    public static final class Builder {
+        private final String mFullText;
+        private final ArrayList<TextLink> mLinks;
+
+        /**
+         * Create a new TextLinks.Builder.
+         *
+         * @param fullText The full text to annotate with links.
+         */
+        public Builder(@NonNull String fullText) {
+            mFullText = Preconditions.checkNotNull(fullText);
+            mLinks = new ArrayList<>();
+        }
+
+        /**
+         * Adds a TextLink.
+         *
+         * @return this instance.
+         *
+         * @throws IllegalArgumentException if entityScores is null or empty.
+         */
+        public Builder addLink(int start, int end, @NonNull Map<String, Float> entityScores) {
+            mLinks.add(new TextLink(start, end, Preconditions.checkNotNull(entityScores)));
+            return this;
+        }
+
+        /**
+         * Removes all {@link TextLink}s.
+         */
+        public Builder clearTextLinks() {
+            mLinks.clear();
+            return this;
+        }
+
+        /**
+         * Constructs a TextLinks instance.
+         *
+         * @return the constructed TextLinks.
+         */
+        public TextLinks build() {
+            return new TextLinks(mFullText, mLinks);
+        }
+    }
+
+    /** The default span factory for TextView and AppCompatTextView. */
+    private static final SpanFactory DEFAULT_SPAN_FACTORY = new SpanFactory() {
+        @Override
+        public TextLinkSpan createSpan(TextLink textLink) {
+            return new TextLinkSpan(textLink);
+        }
+    };
+
+    /**
+     * @throws IllegalArgumentException if the value is invalid
+     */
+    private static void checkValidApplyStrategy(int applyStrategy) {
+        if (applyStrategy != APPLY_STRATEGY_IGNORE && applyStrategy != APPLY_STRATEGY_REPLACE) {
+            throw new IllegalArgumentException(
+                    "Invalid apply strategy. See TextLinks.ApplyStrategy for options.");
+        }
+    }
+}
diff --git a/textclassifier/src/main/java/androidx/view/textclassifier/TextSelection.java b/textclassifier/src/main/java/androidx/view/textclassifier/TextSelection.java
new file mode 100644
index 0000000..dbc7ecf
--- /dev/null
+++ b/textclassifier/src/main/java/androidx/view/textclassifier/TextSelection.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.view.textclassifier;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.FloatRange;
+import android.support.annotation.IntRange;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.LocaleListCompat;
+import android.support.v4.util.ArrayMap;
+import android.support.v4.util.Preconditions;
+
+import java.util.Locale;
+import java.util.Map;
+
+import androidx.view.textclassifier.TextClassifier.EntityType;
+
+/**
+ * Information about where text selection should be.
+ */
+public final class TextSelection implements Parcelable {
+
+    private final int mStartIndex;
+    private final int mEndIndex;
+    @NonNull private final EntityConfidence mEntityConfidence;
+    @NonNull private final String mSignature;
+
+    private TextSelection(
+            int startIndex, int endIndex, @NonNull Map<String, Float> entityConfidence,
+            @NonNull String signature) {
+        mStartIndex = startIndex;
+        mEndIndex = endIndex;
+        mEntityConfidence = new EntityConfidence(entityConfidence);
+        mSignature = signature;
+    }
+
+    /**
+     * Returns the start index of the text selection.
+     */
+    public int getSelectionStartIndex() {
+        return mStartIndex;
+    }
+
+    /**
+     * Returns the end index of the text selection.
+     */
+    public int getSelectionEndIndex() {
+        return mEndIndex;
+    }
+
+    /**
+     * Returns the number of entities found in the classified text.
+     */
+    @IntRange(from = 0)
+    public int getEntityCount() {
+        return mEntityConfidence.getEntities().size();
+    }
+
+    /**
+     * Returns the entity at the specified index. Entities are ordered from high confidence
+     * to low confidence.
+     *
+     * @throws IndexOutOfBoundsException if the specified index is out of range.
+     * @see #getEntityCount() for the number of entities available.
+     */
+    @NonNull
+    public @EntityType String getEntity(int index) {
+        return mEntityConfidence.getEntities().get(index);
+    }
+
+    /**
+     * Returns the confidence score for the specified entity. The value ranges from
+     * 0 (low confidence) to 1 (high confidence). 0 indicates that the entity was not found for the
+     * classified text.
+     */
+    @FloatRange(from = 0.0, to = 1.0)
+    public float getConfidenceScore(@EntityType String entity) {
+        return mEntityConfidence.getConfidenceScore(entity);
+    }
+
+    /**
+     * Returns the signature for this object.
+     * The TextClassifier that generates this object may use it as a way to internally identify
+     * this object.
+     */
+    @NonNull
+    public String getSignature() {
+        return mSignature;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+                Locale.US,
+                "TextSelection {startIndex=%d, endIndex=%d, entities=%s, signature=%s}",
+                mStartIndex, mEndIndex, mEntityConfidence, mSignature);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mStartIndex);
+        dest.writeInt(mEndIndex);
+        mEntityConfidence.writeToParcel(dest, flags);
+        dest.writeString(mSignature);
+    }
+
+    public static final Parcelable.Creator<TextSelection> CREATOR =
+            new Parcelable.Creator<TextSelection>() {
+                @Override
+                public TextSelection createFromParcel(Parcel in) {
+                    return new TextSelection(in);
+                }
+
+                @Override
+                public TextSelection[] newArray(int size) {
+                    return new TextSelection[size];
+                }
+            };
+
+    private TextSelection(Parcel in) {
+        mStartIndex = in.readInt();
+        mEndIndex = in.readInt();
+        mEntityConfidence = EntityConfidence.CREATOR.createFromParcel(in);
+        mSignature = in.readString();
+    }
+
+    /**
+     * Builder used to build {@link TextSelection} objects.
+     */
+    public static final class Builder {
+
+        private final int mStartIndex;
+        private final int mEndIndex;
+        @NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
+        @NonNull private String mSignature = "";
+
+        /**
+         * Creates a builder used to build {@link TextSelection} objects.
+         *
+         * @param startIndex the start index of the text selection.
+         * @param endIndex the end index of the text selection. Must be greater than startIndex
+         */
+        public Builder(@IntRange(from = 0) int startIndex, @IntRange(from = 0) int endIndex) {
+            Preconditions.checkArgument(startIndex >= 0);
+            Preconditions.checkArgument(endIndex > startIndex);
+            mStartIndex = startIndex;
+            mEndIndex = endIndex;
+        }
+
+        /**
+         * Sets an entity type for the classified text and assigns a confidence score.
+         *
+         * @param confidenceScore a value from 0 (low confidence) to 1 (high confidence).
+         *      0 implies the entity does not exist for the classified text.
+         *      Values greater than 1 are clamped to 1.
+         */
+        public Builder setEntityType(
+                @NonNull @EntityType String type,
+                @FloatRange(from = 0.0, to = 1.0) float confidenceScore) {
+            mEntityConfidence.put(type, confidenceScore);
+            return this;
+        }
+
+        /**
+         * Sets a signature for the TextSelection object.
+         *
+         * The TextClassifier that generates the TextSelection object may use it as a way to
+         * internally identify the TextSelection object.
+         */
+        public Builder setSignature(@NonNull String signature) {
+            mSignature = Preconditions.checkNotNull(signature);
+            return this;
+        }
+
+        /**
+         * Builds and returns {@link TextSelection} object.
+         */
+        public TextSelection build() {
+            return new TextSelection(
+                    mStartIndex, mEndIndex, mEntityConfidence, mSignature);
+        }
+    }
+
+    /**
+     * Optional input parameters for generating TextSelection.
+     */
+    public static final class Options implements Parcelable {
+
+        private @Nullable LocaleListCompat mDefaultLocales;
+
+        public Options() {}
+
+        /**
+         * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+         *      the provided text. If no locale preferences exist, set this to null or an empty
+         *      locale list.
+         */
+        public Options setDefaultLocales(@Nullable LocaleListCompat defaultLocales) {
+            mDefaultLocales = defaultLocales;
+            return this;
+        }
+
+        /**
+         * @return ordered list of locale preferences that can be used to disambiguate
+         *      the provided text.
+         */
+        @Nullable
+        public LocaleListCompat getDefaultLocales() {
+            return mDefaultLocales;
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mDefaultLocales != null ? 1 : 0);
+            if (mDefaultLocales != null) {
+                dest.writeString(mDefaultLocales.toLanguageTags());
+            }
+        }
+
+        public static final Parcelable.Creator<Options> CREATOR =
+                new Parcelable.Creator<Options>() {
+                    @Override
+                    public Options createFromParcel(Parcel in) {
+                        return new Options(in);
+                    }
+
+                    @Override
+                    public Options[] newArray(int size) {
+                        return new Options[size];
+                    }
+                };
+
+        private Options(Parcel in) {
+            if (in.readInt() > 0) {
+                mDefaultLocales = LocaleListCompat.forLanguageTags(in.readString());
+            }
+        }
+    }
+}
diff --git a/transition/Android.mk b/transition/Android.mk
deleted file mode 100644
index 466cfa8..0000000
--- a/transition/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-transition \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-transition
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v4
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --no-version-transitions --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/transition/src/androidTest/NO_DOCS b/transition/src/androidTest/NO_DOCS
deleted file mode 100644
index 092a39c..0000000
--- a/transition/src/androidTest/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/transition/src/main/AndroidManifest.xml b/transition/src/main/AndroidManifest.xml
index 40b77e2..01798f4 100644
--- a/transition/src/main/AndroidManifest.xml
+++ b/transition/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.transition">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.transition"/>
diff --git a/tv-provider/Android.mk b/tv-provider/Android.mk
deleted file mode 100644
index 2368ad3..0000000
--- a/tv-provider/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must include it with
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := android-support-tv-provider
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-tv-provider
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tv-provider/src/androidTest/NO_DOCS b/tv-provider/src/androidTest/NO_DOCS
deleted file mode 100644
index 092a39c..0000000
--- a/tv-provider/src/androidTest/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/tv-provider/src/main/AndroidManifest.xml b/tv-provider/src/main/AndroidManifest.xml
index 05af532..952c900 100644
--- a/tv-provider/src/main/AndroidManifest.xml
+++ b/tv-provider/src/main/AndroidManifest.xml
@@ -15,7 +15,6 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.media.tv">
-    <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" />
 </manifest>
diff --git a/v13/Android.mk b/v13/Android.mk
deleted file mode 100644
index d37a4d7..0000000
--- a/v13/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v13 \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v13
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-        $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-# Some projects expect to inherit android-support-v4 from
-# android-support-v13, so we need to keep it static until they can be fixed.
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-        android-support-v4
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-        android-support-v4
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-LOCAL_JAR_EXCLUDE_FILES := none
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
diff --git a/v13/src/main/AndroidManifest.xml b/v13/src/main/AndroidManifest.xml
index 164f757..9f06c87 100644
--- a/v13/src/main/AndroidManifest.xml
+++ b/v13/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v13">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.v13"/>
\ No newline at end of file
diff --git a/v14/Android.mk b/v14/Android.mk
deleted file mode 100644
index 365b3b1..0000000
--- a/v14/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/v14/preference/Android.mk b/v14/preference/Android.mk
deleted file mode 100644
index 47f1071..0000000
--- a/v14/preference/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v14-preference \
-#       android-support-v7-preference \
-#       android-support-v7-appcompat \
-#       android-support-v7-recyclerview \
-#       android-support-v4
-#
-# in their makefiles to include the resources in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v14-preference
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v7-appcompat \
-    android-support-v7-recyclerview \
-    android-support-v4
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-support-v7-preference
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v14/preference/src/main/AndroidManifest.xml b/v14/preference/src/main/AndroidManifest.xml
index 28dabea..1f79704 100644
--- a/v14/preference/src/main/AndroidManifest.xml
+++ b/v14/preference/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v14.preference">
-    <uses-sdk android:minSdkVersion="14" />
-</manifest>
+<manifest package="android.support.v14.preference"/>
diff --git a/v4/Android.mk b/v4/Android.mk
deleted file mode 100644
index d2e4565..0000000
--- a/v4/Android.mk
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v4
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-# Some projects expect to inherit android-support-annotations from
-# android-support-v4, so we need to keep it static until they can be fixed.
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_STATIC_ANDROID_LIBRARIES := \
-    android-support-compat \
-    android-support-media-compat \
-    android-support-core-utils \
-    android-support-core-ui \
-    android-support-fragment
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v4/src/main/AndroidManifest.xml b/v4/src/main/AndroidManifest.xml
index bc1ee8e..cd9b919 100644
--- a/v4/src/main/AndroidManifest.xml
+++ b/v4/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v4">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.v4"/>
diff --git a/v7/Android.mk b/v7/Android.mk
deleted file mode 100644
index 14ff0aa..0000000
--- a/v7/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/v7/appcompat/Android.mk b/v7/appcompat/Android.mk
deleted file mode 100644
index 500a2a2..0000000
--- a/v7/appcompat/Android.mk
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v7-appcompat \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v7-appcompat
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-vectordrawable \
-    android-support-animatedvectordrawable
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v4
-LOCAL_AAPT_FLAGS := --no-version-vectors
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v7/appcompat/AndroidManifest.xml b/v7/appcompat/AndroidManifest.xml
deleted file mode 100644
index 76b8a23..0000000
--- a/v7/appcompat/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.appcompat">
-    <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index 106d0aa..799b7b3 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -45,5 +45,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2011"
     description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren\'t a part of the framework APIs. Compatible on devices running API 14 or later."
-    legacySourceLocation = true
 }
diff --git a/v7/appcompat/res-public/values/public_attrs.xml b/v7/appcompat/res-public/values/public_attrs.xml
index 8c9f9e9..3b811ec 100644
--- a/v7/appcompat/res-public/values/public_attrs.xml
+++ b/v7/appcompat/res-public/values/public_attrs.xml
@@ -102,6 +102,7 @@
      <public type="attr" name="customNavigationLayout"/>
      <public type="attr" name="dialogPreferredPadding"/>
      <public type="attr" name="dialogTheme"/>
+     <public type="attr" name="dialogCornerRadius"/>
      <public type="attr" name="displayOptions"/>
      <public type="attr" name="divider"/>
      <public type="attr" name="dividerHorizontal"/>
diff --git a/v7/appcompat/res/drawable-v21/abc_dialog_material_background.xml b/v7/appcompat/res/drawable-v21/abc_dialog_material_background.xml
new file mode 100644
index 0000000..7ef438b
--- /dev/null
+++ b/v7/appcompat/res/drawable-v21/abc_dialog_material_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:insetLeft="16dp"
+       android:insetTop="16dp"
+       android:insetRight="16dp"
+       android:insetBottom="16dp">
+    <shape android:shape="rectangle">
+        <corners android:radius="?attr/dialogCornerRadius" />
+        <solid android:color="@android:color/white" />
+    </shape>
+</inset>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable-v21/abc_list_divider_material.xml b/v7/appcompat/res/drawable-v21/abc_list_divider_material.xml
new file mode 100644
index 0000000..5ed2121
--- /dev/null
+++ b/v7/appcompat/res/drawable-v21/abc_list_divider_material.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:tint="?android:attr/colorForeground">
+    <solid android:color="#1f000000" />
+    <size
+        android:height="1dp"
+        android:width="1dp" />
+</shape>
diff --git a/v7/appcompat/res/drawable/abc_dialog_material_background.xml b/v7/appcompat/res/drawable/abc_dialog_material_background.xml
index 18560fc..978565b 100644
--- a/v7/appcompat/res/drawable/abc_dialog_material_background.xml
+++ b/v7/appcompat/res/drawable/abc_dialog_material_background.xml
@@ -20,7 +20,7 @@
        android:insetRight="16dp"
        android:insetBottom="16dp">
     <shape android:shape="rectangle">
-        <corners android:radius="2dp" />
+        <corners android:radius="@dimen/abc_dialog_corner_radius_material" />
         <solid android:color="@android:color/white" />
     </shape>
 </inset>
\ No newline at end of file
diff --git a/v7/appcompat/res/drawable/abc_list_divider_material.xml b/v7/appcompat/res/drawable/abc_list_divider_material.xml
new file mode 100644
index 0000000..6739a82
--- /dev/null
+++ b/v7/appcompat/res/drawable/abc_list_divider_material.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#1f000000" />
+    <size
+        android:height="1dp"
+        android:width="1dp" />
+</shape>
diff --git a/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml b/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
index bf630ff..6df3127 100644
--- a/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
+++ b/v7/appcompat/res/layout/abc_popup_menu_item_layout.xml
@@ -17,55 +17,72 @@
 <android.support.v7.view.menu.ListMenuItemView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
-        android:layout_height="?attr/dropdownListPreferredItemHeight"
+        android:layout_height="wrap_content"
         android:minWidth="196dip"
-        style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem">
-
-    <!-- Icon will be inserted here. -->
-
-    <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
-    <RelativeLayout
-            android:layout_width="0dip"
-            android:layout_weight="1"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:duplicateParentState="true"
-            style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem.InternalGroup">
-
-        <TextView
-                android:id="@+id/title"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_alignParentTop="true"
-                android:textAppearance="?attr/textAppearanceLargePopupMenu"
-                android:singleLine="true"
-                android:duplicateParentState="true"
-                android:ellipsize="marquee"
-                android:fadingEdge="horizontal"
-                style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem.Text" />
-
-        <TextView
-                android:id="@+id/shortcut"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/title"
-                android:textAppearance="?attr/textAppearanceSmallPopupMenu"
-                android:singleLine="true"
-                android:duplicateParentState="true"
-                style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem.Text" />
-
-    </RelativeLayout>
+        android:orientation="vertical">
 
     <ImageView
-            android:id="@+id/submenuarrow"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:layout_marginStart="8dp"
-            android:layout_marginLeft="8dp"
-            android:scaleType="center"
-            android:visibility="gone" />
+        android:id="@+id/group_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dip"
+        android:layout_marginTop="4dip"
+        android:layout_marginBottom="4dip"
+        android:background="@drawable/abc_list_divider_material" />
 
-    <!-- Checkbox, and/or radio button will be inserted here. -->
+    <LinearLayout
+        android:id="@+id/content"
+        android:layout_width="match_parent"
+        android:layout_height="?attr/dropdownListPreferredItemHeight"
+        android:duplicateParentState="true"
+        style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem">
+
+        <!-- Icon will be inserted here. -->
+
+        <!-- The title and summary have some gap between them, and this 'group' should be centered
+        vertically. -->
+        <RelativeLayout
+                android:layout_width="0dip"
+                android:layout_weight="1"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical"
+                android:duplicateParentState="true"
+                style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem.InternalGroup">
+
+            <TextView
+                    android:id="@+id/title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentTop="true"
+                    android:textAppearance="?attr/textAppearanceLargePopupMenu"
+                    android:singleLine="true"
+                    android:duplicateParentState="true"
+                    android:ellipsize="marquee"
+                    android:fadingEdge="horizontal"
+                    style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem.Text" />
+
+            <TextView
+                    android:id="@+id/shortcut"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@id/title"
+                    android:textAppearance="?attr/textAppearanceSmallPopupMenu"
+                    android:singleLine="true"
+                    android:duplicateParentState="true"
+                    style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem.Text" />
+
+        </RelativeLayout>
+
+        <ImageView
+                android:id="@+id/submenuarrow"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:scaleType="center"
+                android:visibility="gone"
+                style="@style/RtlOverlay.Widget.AppCompat.PopupMenuItem.SubmenuArrow" />
+
+        <!-- Checkbox, and/or radio button will be inserted here. -->
+
+    </LinearLayout>
 
 </android.support.v7.view.menu.ListMenuItemView>
diff --git a/v7/appcompat/res/values-bs/strings.xml b/v7/appcompat/res/values-bs/strings.xml
index 3687875..07d1411 100644
--- a/v7/appcompat/res/values-bs/strings.xml
+++ b/v7/appcompat/res/values-bs/strings.xml
@@ -29,8 +29,8 @@
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"Glasovno pretraživanje"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Odaberite aplikaciju"</string>
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Prikaži sve"</string>
-    <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"Podijeli koristeći aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
-    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Podijeli sa"</string>
+    <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"Dijeli koristeći aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Dijeli sa"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"UKLJUČI"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"ISKLJUČI"</string>
     <string name="search_menu_title" msgid="146198913615257606">"Pretraži"</string>
diff --git a/v7/appcompat/res/values-hi/strings.xml b/v7/appcompat/res/values-hi/strings.xml
index 3a393c7..a31ab90 100644
--- a/v7/appcompat/res/values-hi/strings.xml
+++ b/v7/appcompat/res/values-hi/strings.xml
@@ -29,8 +29,8 @@
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"आवाज़ सर्च"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"कोई एप्‍लिकेशन चुनें"</string>
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"सभी देखें"</string>
-    <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
-    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"इसके द्वारा साझा करें"</string>
+    <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ शेयर करें"</string>
+    <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"इसके साथ शेयर करें"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"चालू"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"बंद"</string>
     <string name="search_menu_title" msgid="146198913615257606">"सर्च"</string>
diff --git a/v7/appcompat/res/values-ne/strings.xml b/v7/appcompat/res/values-ne/strings.xml
index 0d23bd7..96b1042 100644
--- a/v7/appcompat/res/values-ne/strings.xml
+++ b/v7/appcompat/res/values-ne/strings.xml
@@ -29,7 +29,7 @@
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"भ्वाइस खोजी"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"एउटा अनुप्रयोग छान्नुहोस्"</string>
     <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"सबै हेर्नुहोस्"</string>
-    <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> सँग आदान-प्रदान गर्नुहोस्"</string>
+    <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> सँग आदान प्रदान गर्नुहोस्"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"साझेदारी गर्नुहोस्..."</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"सक्रिय गर्नुहोस्"</string>
     <string name="abc_capital_off" msgid="121134116657445385">"निष्क्रिय पार्नुहोस्"</string>
diff --git a/v7/appcompat/res/values-ta/strings.xml b/v7/appcompat/res/values-ta/strings.xml
index 4a2ad2f..971a3db 100644
--- a/v7/appcompat/res/values-ta/strings.xml
+++ b/v7/appcompat/res/values-ta/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="abc_action_mode_done" msgid="4076576682505996667">"முடிந்தது"</string>
     <string name="abc_action_bar_home_description" msgid="4600421777120114993">"முகப்பிற்கு வழிசெலுத்து"</string>
-    <string name="abc_action_bar_up_description" msgid="1594238315039666878">"மேலே வழிசெலுத்து"</string>
+    <string name="abc_action_bar_up_description" msgid="1594238315039666878">"மேலே செல்"</string>
     <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"மேலும் விருப்பங்கள்"</string>
     <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"சுருக்கு"</string>
     <string name="abc_searchview_description_search" msgid="8264924765203268293">"தேடு"</string>
diff --git a/v7/appcompat/res/values-uz/strings.xml b/v7/appcompat/res/values-uz/strings.xml
index 632e0b9..0417cba 100644
--- a/v7/appcompat/res/values-uz/strings.xml
+++ b/v7/appcompat/res/values-uz/strings.xml
@@ -28,7 +28,7 @@
     <string name="abc_searchview_description_submit" msgid="8928215447528550784">"So‘rov yaratish"</string>
     <string name="abc_searchview_description_voice" msgid="893419373245838918">"Ovozli qidiruv"</string>
     <string name="abc_activitychooserview_choose_application" msgid="2031811694353399454">"Dastur tanlang"</string>
-    <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Barchasini ko‘rish"</string>
+    <string name="abc_activity_chooser_view_see_all" msgid="7468859129482906941">"Hammasi"</string>
     <string name="abc_shareactionprovider_share_with_application" msgid="3300176832234831527">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> orqali ulashish"</string>
     <string name="abc_shareactionprovider_share_with" msgid="3421042268587513524">"Ruxsat berish"</string>
     <string name="abc_capital_on" msgid="3405795526292276155">"YONIQ"</string>
diff --git a/v7/appcompat/res/values-v17/styles_rtl.xml b/v7/appcompat/res/values-v17/styles_rtl.xml
index b3753b7..68fd88f 100644
--- a/v7/appcompat/res/values-v17/styles_rtl.xml
+++ b/v7/appcompat/res/values-v17/styles_rtl.xml
@@ -70,6 +70,10 @@
         <item name="android:textAlignment">viewStart</item>
     </style>
 
+    <style name="RtlOverlay.Widget.AppCompat.PopupMenuItem.SubmenuArrow" parent="android:Widget">
+        <item name="android:layout_marginStart">8dp</item>
+    </style>
+
     <style name="RtlOverlay.Widget.AppCompat.DialogTitle.Icon" parent="android:Widget">
         <item name="android:layout_marginEnd">8dp</item>
     </style>
diff --git a/v7/appcompat/res/values-v28/themes_base.xml b/v7/appcompat/res/values-v28/themes_base.xml
new file mode 100644
index 0000000..7dea6d5
--- /dev/null
+++ b/v7/appcompat/res/values-v28/themes_base.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<resources>
+
+    <style name="Base.Theme.AppCompat" parent="Base.V28.Theme.AppCompat" />
+    <style name="Base.Theme.AppCompat.Light" parent="Base.V28.Theme.AppCompat.Light" />
+
+    <style name="Base.V28.Theme.AppCompat" parent="Base.V26.Theme.AppCompat">
+        <!-- We can use the platform styles on API 28+ -->
+        <item name="dialogCornerRadius">?android:attr/dialogCornerRadius</item>
+    </style>
+
+    <style name="Base.V28.Theme.AppCompat.Light" parent="Base.V26.Theme.AppCompat.Light">
+        <!-- We can use the platform styles on API 28+ -->
+        <item name="dialogCornerRadius">?android:attr/dialogCornerRadius</item>
+    </style>
+
+</resources>
diff --git a/v7/appcompat/res/values-vi/strings.xml b/v7/appcompat/res/values-vi/strings.xml
index 9587bed..4560b4b 100644
--- a/v7/appcompat/res/values-vi/strings.xml
+++ b/v7/appcompat/res/values-vi/strings.xml
@@ -19,7 +19,7 @@
     <string name="abc_action_mode_done" msgid="4076576682505996667">"Xong"</string>
     <string name="abc_action_bar_home_description" msgid="4600421777120114993">"Điều hướng về trang chủ"</string>
     <string name="abc_action_bar_up_description" msgid="1594238315039666878">"Điều hướng lên trên"</string>
-    <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Thêm tùy chọn"</string>
+    <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"Tùy chọn khác"</string>
     <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"Thu gọn"</string>
     <string name="abc_searchview_description_search" msgid="8264924765203268293">"Tìm kiếm"</string>
     <string name="abc_search_hint" msgid="7723749260725869598">"Tìm kiếm…"</string>
diff --git a/v7/appcompat/res/values-watch-v21/themes_base.xml b/v7/appcompat/res/values-watch-v21/themes_base.xml
new file mode 100644
index 0000000..0a6cfe8
--- /dev/null
+++ b/v7/appcompat/res/values-watch-v21/themes_base.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="Base.Theme.AppCompat.Dialog" parent="Base.V21.Theme.AppCompat.Dialog" >
+        <item name="android:windowIsFloating">false</item>
+        <item name="android:windowElevation">0dp</item>
+    </style>
+    <style name="Base.Theme.AppCompat.Light.Dialog" parent="Base.V21.Theme.AppCompat.Light.Dialog" >
+        <item name="android:windowIsFloating">false</item>
+        <item name="android:windowElevation">0dp</item>
+    </style>
+    <style name="Base.ThemeOverlay.AppCompat.Dialog" parent="Base.V21.ThemeOverlay.AppCompat.Dialog" >
+        <item name="android:windowIsFloating">false</item>
+        <item name="android:windowElevation">0dp</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values/attrs.xml b/v7/appcompat/res/values/attrs.xml
index c48b7ba..7d26a32 100644
--- a/v7/appcompat/res/values/attrs.xml
+++ b/v7/appcompat/res/values/attrs.xml
@@ -189,6 +189,8 @@
         <attr name="dialogPreferredPadding" format="dimension" />
         <!-- The list divider used in alert dialogs. -->
         <attr name="listDividerAlertDialog" format="reference" />
+        <!-- Preferred corner radius of dialogs. -->
+        <attr name="dialogCornerRadius" format="dimension" />
 
         <!-- =================== -->
         <!-- Other widget styles -->
diff --git a/v7/appcompat/res/values/colors_material.xml b/v7/appcompat/res/values/colors_material.xml
index cf21172..7d5ca2c 100644
--- a/v7/appcompat/res/values/colors_material.xml
+++ b/v7/appcompat/res/values/colors_material.xml
@@ -99,7 +99,8 @@
     <color name="primary_text_disabled_material_dark">#4Dffffff</color>
     <color name="secondary_text_disabled_material_dark">#36ffffff</color>
 
-    <color name="error_color_material">#F4511E</color>
+    <color name="error_color_material_dark">#ff7043</color><!-- deep orange 400 -->
+    <color name="error_color_material_light">#ff5722</color><!-- deep orange 500 -->
 
     <!-- Primary & accent colors -->
     <eat-comment />
diff --git a/v7/appcompat/res/values/dimens.xml b/v7/appcompat/res/values/dimens.xml
index 2623615..46b8343 100644
--- a/v7/appcompat/res/values/dimens.xml
+++ b/v7/appcompat/res/values/dimens.xml
@@ -73,6 +73,7 @@
     <dimen name="abc_dialog_title_divider_material">8dp</dimen>
     <dimen name="abc_dialog_list_padding_top_no_title">8dp</dimen>
     <dimen name="abc_dialog_list_padding_bottom_no_buttons">8dp</dimen>
+    <dimen name="abc_dialog_corner_radius_material">2dp</dimen>
 
     <!-- Dialog button bar height -->
     <dimen name="abc_alert_dialog_button_bar_height">48dp</dimen>
diff --git a/v7/appcompat/res/values/styles_rtl.xml b/v7/appcompat/res/values/styles_rtl.xml
index a70aa30..fda8f09 100644
--- a/v7/appcompat/res/values/styles_rtl.xml
+++ b/v7/appcompat/res/values/styles_rtl.xml
@@ -69,6 +69,10 @@
         <item name="android:layout_alignParentLeft">true</item>
     </style>
 
+    <style name="RtlOverlay.Widget.AppCompat.PopupMenuItem.SubmenuArrow" parent="android:Widget">
+        <item name="android:layout_marginLeft">8dp</item>
+    </style>
+
     <style name="RtlOverlay.Widget.AppCompat.DialogTitle.Icon" parent="android:Widget">
         <item name="android:layout_marginRight">8dp</item>
     </style>
diff --git a/v7/appcompat/res/values/themes_base.xml b/v7/appcompat/res/values/themes_base.xml
index 1b258e2..def6423 100644
--- a/v7/appcompat/res/values/themes_base.xml
+++ b/v7/appcompat/res/values/themes_base.xml
@@ -297,6 +297,7 @@
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>
         <item name="dialogPreferredPadding">@dimen/abc_dialog_padding_material</item>
+        <item name="dialogCornerRadius">@dimen/abc_dialog_corner_radius_material</item>
 
         <item name="alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog.Alert</item>
         <item name="alertDialogStyle">@style/AlertDialog.AppCompat</item>
@@ -315,7 +316,7 @@
         <item name="tooltipFrameBackground">@drawable/tooltip_frame_light</item>
         <item name="tooltipForegroundColor">@color/foreground_material_light</item>
 
-        <item name="colorError">@color/error_color_material</item>
+        <item name="colorError">@color/error_color_material_dark</item>
     </style>
 
     <!-- Base platform-dependent theme providing an action bar in a light-themed activity. -->
@@ -467,6 +468,7 @@
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/ThemeOverlay.AppCompat.Dialog</item>
         <item name="dialogPreferredPadding">@dimen/abc_dialog_padding_material</item>
+        <item name="dialogCornerRadius">@dimen/abc_dialog_corner_radius_material</item>
 
         <item name="alertDialogTheme">@style/ThemeOverlay.AppCompat.Dialog.Alert</item>
         <item name="alertDialogStyle">@style/AlertDialog.AppCompat.Light</item>
@@ -485,7 +487,7 @@
         <item name="tooltipFrameBackground">@drawable/tooltip_frame_dark</item>
         <item name="tooltipForegroundColor">@color/foreground_material_dark</item>
 
-        <item name="colorError">@color/error_color_material</item>
+        <item name="colorError">@color/error_color_material_light</item>
     </style>
 
     <style name="Base.Theme.AppCompat" parent="Base.V7.Theme.AppCompat">
diff --git a/v7/appcompat/tests/AndroidManifest.xml b/v7/appcompat/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from v7/appcompat/tests/AndroidManifest.xml
rename to v7/appcompat/src/androidTest/AndroidManifest.xml
diff --git a/v7/appcompat/tests/fonts_readme.txt b/v7/appcompat/src/androidTest/fonts_readme.txt
similarity index 100%
rename from v7/appcompat/tests/fonts_readme.txt
rename to v7/appcompat/src/androidTest/fonts_readme.txt
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AlertDialogCursorTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AlertDialogCursorTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AlertDialogCursorTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AlertDialogCursorTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AlertDialogTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AlertDialogTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AlertDialogTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AlertDialogTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AlertDialogTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AlertDialogTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AlertDialogTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AlertDialogTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterBadClassNameActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterBadClassNameActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterBadClassNameActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterBadClassNameActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterBadClassNameTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterBadClassNameTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterBadClassNameTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterBadClassNameTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterCustomActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterCustomActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterCustomActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterCustomActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterCustomTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterCustomTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterCustomTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterCustomTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterDefaultActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterDefaultActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterDefaultActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterDefaultActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterDefaultTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterDefaultTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterDefaultTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterDefaultTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterNullActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterNullActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterNullActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterNullActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterNullTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterNullTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterNullTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterNullTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterPassTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterPassTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatInflaterPassTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatInflaterPassTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemIconTintingTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemIconTintingTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemIconTintingTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemIconTintingTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemIconTintingTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemIconTintingTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemIconTintingTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemIconTintingTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemShortcutsTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemShortcutsTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatMenuItemShortcutsTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatVectorDrawableIntegrationActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatVectorDrawableIntegrationActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatVectorDrawableIntegrationActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatVectorDrawableIntegrationActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/AppCompatVectorDrawableIntegrationTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatVectorDrawableIntegrationTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/AppCompatVectorDrawableIntegrationTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/AppCompatVectorDrawableIntegrationTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseBasicsTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/BaseBasicsTestCase.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/BaseBasicsTestCase.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/BaseBasicsTestCase.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/BaseKeyEventsTestCase.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/BaseKeyEventsTestCase.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/BaseKeyEventsTestCase.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/BaseKeyboardShortcutsTestCase.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithToolbar.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/BasicsTestCaseWithToolbar.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithToolbar.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/BasicsTestCaseWithToolbar.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithWindowDecor.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/BasicsTestCaseWithWindowDecor.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/BasicsTestCaseWithWindowDecor.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/BasicsTestCaseWithWindowDecor.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/CustomCollapsibleView.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/CustomCollapsibleView.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/CustomCollapsibleView.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/CustomCollapsibleView.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/DialogTestCase.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/DialogTestCase.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/DialogTestCase.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerDynamicLayoutActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerDynamicLayoutActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerDynamicLayoutTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/DrawerDynamicLayoutTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerDynamicLayoutTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutDoubleActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutDoubleActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutDoubleTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutDoubleTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutDoubleTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/DrawerLayoutTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/DrawerLayoutTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/FragmentContentIdActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/FragmentContentIdActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/FragmentContentIdActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/FragmentContentIdActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/FragmentContentIdTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/FragmentContentIdTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/FragmentContentIdTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/FragmentContentIdTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/KeyEventsTestCaseWithToolbar.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/KeyEventsTestCaseWithWindowDecor.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/KeyboardShortcutsTestCaseWithToolbar.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/KeyboardShortcutsTestCaseWithWindowDecor.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/LayoutInflaterFactoryTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/LayoutInflaterFactoryTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/LayoutInflaterFactoryTestCase.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/LayoutInflaterFactoryTestCase.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/LayoutInflaterFactoryTestCase.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/MenuBuilderTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/MenuBuilderTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/MenuBuilderTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/MenuBuilderTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/NightModeActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/NightModeActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/NightModeTestCase.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/ToolbarAppCompatActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/ToolbarAppCompatActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/ToolbarAppCompatActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/WindowDecorAppCompatActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/WindowDecorAppCompatActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/WindowDecorAppCompatActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/WindowDecorAppCompatActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/inflater/CustomViewInflater.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/inflater/CustomViewInflater.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/inflater/CustomViewInflater.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/inflater/CustomViewInflater.java
diff --git a/v7/appcompat/tests/src/android/support/v7/app/inflater/MisbehavingViewInflater.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/inflater/MisbehavingViewInflater.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/app/inflater/MisbehavingViewInflater.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/app/inflater/MisbehavingViewInflater.java
diff --git a/v7/appcompat/tests/src/android/support/v7/custom/ContextWrapperFrameLayout.java b/v7/appcompat/src/androidTest/java/android/support/v7/custom/ContextWrapperFrameLayout.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/custom/ContextWrapperFrameLayout.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/custom/ContextWrapperFrameLayout.java
diff --git a/v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java b/v7/appcompat/src/androidTest/java/android/support/v7/custom/CustomDrawerLayout.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/custom/CustomDrawerLayout.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/custom/CustomDrawerLayout.java
diff --git a/v7/appcompat/tests/src/android/support/v7/custom/FitWindowsContentLayout.java b/v7/appcompat/src/androidTest/java/android/support/v7/custom/FitWindowsContentLayout.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/custom/FitWindowsContentLayout.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/custom/FitWindowsContentLayout.java
diff --git a/v7/appcompat/tests/src/android/support/v7/res/content/AppCompatResourcesTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/res/content/AppCompatResourcesTestCase.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/res/content/AppCompatResourcesTestCase.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/res/content/AppCompatResourcesTestCase.java
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/AppCompatTintableViewActions.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/testutils/AppCompatTintableViewActions.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/testutils/AppCompatTintableViewActions.java
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/BaseTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/testutils/BaseTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/DrawerLayoutActions.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/DrawerLayoutActions.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/testutils/DrawerLayoutActions.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/testutils/DrawerLayoutActions.java
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/Shakespeare.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/Shakespeare.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/testutils/Shakespeare.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/testutils/Shakespeare.java
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/TestUtils.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/testutils/TestUtils.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/testutils/TestUtils.java
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsActions.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/TestUtilsActions.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsActions.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/testutils/TestUtilsActions.java
diff --git a/v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/TestUtilsMatchers.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/testutils/TestUtilsMatchers.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/testutils/TestUtilsMatchers.java
diff --git a/v7/appcompat/tests/src/android/support/v7/view/ContextThemeWrapperTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/view/ContextThemeWrapperTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/view/ContextThemeWrapperTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/view/ContextThemeWrapperTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/view/SupportMenuInflaterTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/view/SupportMenuInflaterTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/view/SupportMenuInflaterTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/view/SupportMenuInflaterTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/view/SupportMenuInflaterTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseAutoSizeTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatBaseAutoSizeTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseAutoSizeTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatBaseAutoSizeTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseImageViewTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatBaseImageViewTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseImageViewTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatBaseImageViewTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatBaseViewTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatBaseViewTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatBaseViewTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonAutoSizeActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonAutoSizeActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonAutoSizeActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonAutoSizeActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonAutoSizeTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonAutoSizeTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonAutoSizeTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonAutoSizeTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatButtonTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatButtonTest.java
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatEditTextTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatEditTextTest.java
new file mode 100644
index 0000000..397daf6
--- /dev/null
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatEditTextTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Editable;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link AppCompatEditText} class.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class AppCompatEditTextTest {
+    @Rule
+    public final ActivityTestRule<AppCompatActivity> mActivityTestRule =
+            new ActivityTestRule<>(AppCompatActivity.class);
+
+    @Test
+    @UiThreadTest
+    public void testGetTextNonEditable() {
+        // This subclass calls getText before the object is fully constructed. This should not cause
+        // a null pointer exception.
+        GetTextEditText editText = new GetTextEditText(mActivityTestRule.getActivity());
+    }
+
+    private class GetTextEditText extends AppCompatEditText {
+
+        GetTextEditText(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void setText(CharSequence text, BufferType type) {
+            Editable currentText = getText();
+            super.setText(text, type);
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetTextBeforeConstructor() {
+        // This subclass calls getText before the TextView constructor. This should not cause
+        // a null pointer exception.
+        GetTextEditText2 editText = new GetTextEditText2(mActivityTestRule.getActivity());
+    }
+
+    private class GetTextEditText2 extends AppCompatEditText {
+
+        GetTextEditText2(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void setOverScrollMode(int overScrollMode) {
+            // This method is called by the View constructor before the TextView/EditText
+            // constructors.
+            Editable text = getText();
+        }
+    }
+}
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageButtonActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageButtonActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageButtonActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageButtonActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageButtonTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageButtonTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageButtonTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageButtonTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageViewActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageViewActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageViewTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatImageViewTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatImageViewTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatRadioButtonActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatRadioButtonActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatRadioButtonActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatRadioButtonActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatRadioButtonTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatRadioButtonTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatRadioButtonTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatRadioButtonTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatSpinnerActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatSpinnerActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatSpinnerActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatSpinnerActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatSpinnerTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatSpinnerTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatSpinnerTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatSpinnerTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewAutoSizeActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewAutoSizeActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewAutoSizeTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/AppCompatTextViewTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/AppCompatTextViewTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/ListPopupWindowTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/ListPopupWindowTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/ListPopupWindowTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/ListPopupWindowTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/PopupMenuTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/PopupTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/PopupTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/SearchViewTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchViewTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/SearchViewTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchViewTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/SearchViewTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchViewTestActivity.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/SearchViewTestActivity.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchViewTestActivity.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/SearchView_CursorTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/SearchView_CursorTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
diff --git a/v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/TintResourcesTest.java
similarity index 100%
rename from v7/appcompat/tests/src/android/support/v7/widget/TintResourcesTest.java
rename to v7/appcompat/src/androidTest/java/android/support/v7/widget/TintResourcesTest.java
diff --git a/v7/appcompat/tests/res/color-v23/color_state_list_themed_attrs.xml b/v7/appcompat/src/androidTest/res/color-v23/color_state_list_themed_attrs.xml
similarity index 100%
rename from v7/appcompat/tests/res/color-v23/color_state_list_themed_attrs.xml
rename to v7/appcompat/src/androidTest/res/color-v23/color_state_list_themed_attrs.xml
diff --git a/v7/appcompat/tests/res/color/color_state_list_emerald_translucent.xml b/v7/appcompat/src/androidTest/res/color/color_state_list_emerald_translucent.xml
similarity index 100%
rename from v7/appcompat/tests/res/color/color_state_list_emerald_translucent.xml
rename to v7/appcompat/src/androidTest/res/color/color_state_list_emerald_translucent.xml
diff --git a/v7/appcompat/tests/res/color/color_state_list_lilac.xml b/v7/appcompat/src/androidTest/res/color/color_state_list_lilac.xml
similarity index 100%
rename from v7/appcompat/tests/res/color/color_state_list_lilac.xml
rename to v7/appcompat/src/androidTest/res/color/color_state_list_lilac.xml
diff --git a/v7/appcompat/tests/res/color/color_state_list_link.xml b/v7/appcompat/src/androidTest/res/color/color_state_list_link.xml
similarity index 100%
rename from v7/appcompat/tests/res/color/color_state_list_link.xml
rename to v7/appcompat/src/androidTest/res/color/color_state_list_link.xml
diff --git a/v7/appcompat/tests/res/color/color_state_list_ocean.xml b/v7/appcompat/src/androidTest/res/color/color_state_list_ocean.xml
similarity index 100%
rename from v7/appcompat/tests/res/color/color_state_list_ocean.xml
rename to v7/appcompat/src/androidTest/res/color/color_state_list_ocean.xml
diff --git a/v7/appcompat/tests/res/color/color_state_list_sand.xml b/v7/appcompat/src/androidTest/res/color/color_state_list_sand.xml
similarity index 100%
rename from v7/appcompat/tests/res/color/color_state_list_sand.xml
rename to v7/appcompat/src/androidTest/res/color/color_state_list_sand.xml
diff --git a/v7/appcompat/tests/res/color/color_state_list_themed_attrs.xml b/v7/appcompat/src/androidTest/res/color/color_state_list_themed_attrs.xml
similarity index 100%
rename from v7/appcompat/tests/res/color/color_state_list_themed_attrs.xml
rename to v7/appcompat/src/androidTest/res/color/color_state_list_themed_attrs.xml
diff --git a/v7/appcompat/tests/res/drawable-hdpi/drawer_shadow.9.png b/v7/appcompat/src/androidTest/res/drawable-hdpi/drawer_shadow.9.png
similarity index 100%
rename from v7/appcompat/tests/res/drawable-hdpi/drawer_shadow.9.png
rename to v7/appcompat/src/androidTest/res/drawable-hdpi/drawer_shadow.9.png
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable-mdpi/drawer_shadow.9.png b/v7/appcompat/src/androidTest/res/drawable-mdpi/drawer_shadow.9.png
similarity index 100%
rename from v7/appcompat/tests/res/drawable-mdpi/drawer_shadow.9.png
rename to v7/appcompat/src/androidTest/res/drawable-mdpi/drawer_shadow.9.png
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable-mdpi/test_drawable.png b/v7/appcompat/src/androidTest/res/drawable-mdpi/test_drawable.png
similarity index 100%
rename from v7/appcompat/tests/res/drawable-mdpi/test_drawable.png
rename to v7/appcompat/src/androidTest/res/drawable-mdpi/test_drawable.png
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable-xhdpi/drawer_shadow.9.png b/v7/appcompat/src/androidTest/res/drawable-xhdpi/drawer_shadow.9.png
similarity index 100%
rename from v7/appcompat/tests/res/drawable-xhdpi/drawer_shadow.9.png
rename to v7/appcompat/src/androidTest/res/drawable-xhdpi/drawer_shadow.9.png
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable/black_rect.xml b/v7/appcompat/src/androidTest/res/drawable/black_rect.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/black_rect.xml
rename to v7/appcompat/src/androidTest/res/drawable/black_rect.xml
diff --git a/v7/appcompat/tests/res/drawable/icon_black.jpg b/v7/appcompat/src/androidTest/res/drawable/icon_black.jpg
similarity index 100%
rename from v7/appcompat/tests/res/drawable/icon_black.jpg
rename to v7/appcompat/src/androidTest/res/drawable/icon_black.jpg
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable/icon_blue.jpg b/v7/appcompat/src/androidTest/res/drawable/icon_blue.jpg
similarity index 100%
rename from v7/appcompat/tests/res/drawable/icon_blue.jpg
rename to v7/appcompat/src/androidTest/res/drawable/icon_blue.jpg
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable/icon_green.jpg b/v7/appcompat/src/androidTest/res/drawable/icon_green.jpg
similarity index 100%
rename from v7/appcompat/tests/res/drawable/icon_green.jpg
rename to v7/appcompat/src/androidTest/res/drawable/icon_green.jpg
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable/icon_red.jpg b/v7/appcompat/src/androidTest/res/drawable/icon_red.jpg
similarity index 100%
rename from v7/appcompat/tests/res/drawable/icon_red.jpg
rename to v7/appcompat/src/androidTest/res/drawable/icon_red.jpg
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable/icon_yellow.jpg b/v7/appcompat/src/androidTest/res/drawable/icon_yellow.jpg
similarity index 100%
rename from v7/appcompat/tests/res/drawable/icon_yellow.jpg
rename to v7/appcompat/src/androidTest/res/drawable/icon_yellow.jpg
Binary files differ
diff --git a/v7/appcompat/tests/res/drawable/test_background_blue.xml b/v7/appcompat/src/androidTest/res/drawable/test_background_blue.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_background_blue.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_background_blue.xml
diff --git a/v7/appcompat/tests/res/drawable/test_background_green.xml b/v7/appcompat/src/androidTest/res/drawable/test_background_green.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_background_green.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_background_green.xml
diff --git a/v7/appcompat/tests/res/drawable/test_background_red.xml b/v7/appcompat/src/androidTest/res/drawable/test_background_red.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_background_red.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_background_red.xml
diff --git a/v7/appcompat/tests/res/drawable/test_drawable_blue.xml b/v7/appcompat/src/androidTest/res/drawable/test_drawable_blue.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_drawable_blue.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_drawable_blue.xml
diff --git a/v7/appcompat/tests/res/drawable/test_drawable_green.xml b/v7/appcompat/src/androidTest/res/drawable/test_drawable_green.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_drawable_green.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_drawable_green.xml
diff --git a/v7/appcompat/tests/res/drawable/test_drawable_red.xml b/v7/appcompat/src/androidTest/res/drawable/test_drawable_red.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_drawable_red.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_drawable_red.xml
diff --git a/v7/appcompat/tests/res/drawable/test_night_color_conversion_background.xml b/v7/appcompat/src/androidTest/res/drawable/test_night_color_conversion_background.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_night_color_conversion_background.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_night_color_conversion_background.xml
diff --git a/v7/appcompat/tests/res/drawable/test_vector_left_white_right_black.xml b/v7/appcompat/src/androidTest/res/drawable/test_vector_left_white_right_black.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_vector_left_white_right_black.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_vector_left_white_right_black.xml
diff --git a/v7/appcompat/tests/res/drawable/test_vector_level.xml b/v7/appcompat/src/androidTest/res/drawable/test_vector_level.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_vector_level.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_vector_level.xml
diff --git a/v7/appcompat/tests/res/drawable/test_vector_off.xml b/v7/appcompat/src/androidTest/res/drawable/test_vector_off.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_vector_off.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_vector_off.xml
diff --git a/v7/appcompat/tests/res/drawable/test_vector_on.xml b/v7/appcompat/src/androidTest/res/drawable/test_vector_on.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_vector_on.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_vector_on.xml
diff --git a/v7/appcompat/tests/res/drawable/test_vector_state.xml b/v7/appcompat/src/androidTest/res/drawable/test_vector_state.xml
similarity index 100%
rename from v7/appcompat/tests/res/drawable/test_vector_state.xml
rename to v7/appcompat/src/androidTest/res/drawable/test_vector_state.xml
diff --git a/v7/appcompat/tests/res/font/samplefont.ttf b/v7/appcompat/src/androidTest/res/font/samplefont.ttf
similarity index 100%
rename from v7/appcompat/tests/res/font/samplefont.ttf
rename to v7/appcompat/src/androidTest/res/font/samplefont.ttf
Binary files differ
diff --git a/v7/appcompat/tests/res/font/samplefont2.ttf b/v7/appcompat/src/androidTest/res/font/samplefont2.ttf
similarity index 100%
rename from v7/appcompat/tests/res/font/samplefont2.ttf
rename to v7/appcompat/src/androidTest/res/font/samplefont2.ttf
Binary files differ
diff --git a/v7/appcompat/tests/res/font/samplefont3.ttf b/v7/appcompat/src/androidTest/res/font/samplefont3.ttf
similarity index 100%
rename from v7/appcompat/tests/res/font/samplefont3.ttf
rename to v7/appcompat/src/androidTest/res/font/samplefont3.ttf
Binary files differ
diff --git a/v7/appcompat/tests/res/font/samplefont4.ttf b/v7/appcompat/src/androidTest/res/font/samplefont4.ttf
similarity index 100%
rename from v7/appcompat/tests/res/font/samplefont4.ttf
rename to v7/appcompat/src/androidTest/res/font/samplefont4.ttf
Binary files differ
diff --git a/v7/appcompat/tests/res/font/samplexmldownloadedfont.xml b/v7/appcompat/src/androidTest/res/font/samplexmldownloadedfont.xml
similarity index 100%
rename from v7/appcompat/tests/res/font/samplexmldownloadedfont.xml
rename to v7/appcompat/src/androidTest/res/font/samplexmldownloadedfont.xml
diff --git a/v7/appcompat/tests/res/font/samplexmlfont.xml b/v7/appcompat/src/androidTest/res/font/samplexmlfont.xml
similarity index 100%
rename from v7/appcompat/tests/res/font/samplexmlfont.xml
rename to v7/appcompat/src/androidTest/res/font/samplexmlfont.xml
diff --git a/v7/appcompat/tests/res/layout/activity_night_mode.xml b/v7/appcompat/src/androidTest/res/layout/activity_night_mode.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/activity_night_mode.xml
rename to v7/appcompat/src/androidTest/res/layout/activity_night_mode.xml
diff --git a/v7/appcompat/tests/res/layout/alert_dialog_activity.xml b/v7/appcompat/src/androidTest/res/layout/alert_dialog_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/alert_dialog_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/alert_dialog_activity.xml
diff --git a/v7/appcompat/tests/res/layout/alert_dialog_custom_title.xml b/v7/appcompat/src/androidTest/res/layout/alert_dialog_custom_title.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/alert_dialog_custom_title.xml
rename to v7/appcompat/src/androidTest/res/layout/alert_dialog_custom_title.xml
diff --git a/v7/appcompat/tests/res/layout/alert_dialog_custom_view.xml b/v7/appcompat/src/androidTest/res/layout/alert_dialog_custom_view.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/alert_dialog_custom_view.xml
rename to v7/appcompat/src/androidTest/res/layout/alert_dialog_custom_view.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_button_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_button_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_button_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_button_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_button_autosize_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_button_autosize_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_button_autosize_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_button_autosize_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_imagebutton_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_imagebutton_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_imagebutton_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_imagebutton_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_imageview_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_imageview_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_imageview_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_imageview_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_inflater_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_inflater_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_inflater_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_inflater_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_radiobutton_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_radiobutton_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_radiobutton_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_radiobutton_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_searchview_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_searchview_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_searchview_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_searchview_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_spinner_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_spinner_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_spinner_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_spinner_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_textview_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_textview_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_textview_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_textview_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_textview_autosize_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_textview_autosize_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_textview_autosize_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_textview_autosize_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_toolbar_activity.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_toolbar_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_toolbar_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_toolbar_activity.xml
diff --git a/v7/appcompat/tests/res/layout/appcompat_vectordrawable_integration.xml b/v7/appcompat/src/androidTest/res/layout/appcompat_vectordrawable_integration.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/appcompat_vectordrawable_integration.xml
rename to v7/appcompat/src/androidTest/res/layout/appcompat_vectordrawable_integration.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_double_layout.xml b/v7/appcompat/src/androidTest/res/layout/drawer_double_layout.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_double_layout.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_double_layout.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_content_double_end.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_content_double_end.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_content_double_end_single_start.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end_single_start.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_content_double_end_single_start.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_end_single_start.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_content_double_start.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_content_double_start.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_content_double_start_single_end.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start_single_end.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_content_double_start_single_end.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_double_start_single_end.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_content_single_end.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_single_end.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_content_single_end.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_single_end.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_content_single_start.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_single_start.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_content_single_start.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_single_start.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_content_start_end.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_start_end.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_content_start_end.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_content_start_end.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_dynamic_layout.xml b/v7/appcompat/src/androidTest/res/layout/drawer_dynamic_layout.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_dynamic_layout.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_dynamic_layout.xml
diff --git a/v7/appcompat/tests/res/layout/drawer_layout.xml b/v7/appcompat/src/androidTest/res/layout/drawer_layout.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/drawer_layout.xml
rename to v7/appcompat/src/androidTest/res/layout/drawer_layout.xml
diff --git a/v7/appcompat/tests/res/layout/layout_actv.xml b/v7/appcompat/src/androidTest/res/layout/layout_actv.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_actv.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_actv.xml
diff --git a/v7/appcompat/tests/res/layout/layout_android_theme.xml b/v7/appcompat/src/androidTest/res/layout/layout_android_theme.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_android_theme.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_android_theme.xml
diff --git a/v7/appcompat/tests/res/layout/layout_android_theme_children.xml b/v7/appcompat/src/androidTest/res/layout/layout_android_theme_children.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_android_theme_children.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_android_theme_children.xml
diff --git a/v7/appcompat/tests/res/layout/layout_app_theme.xml b/v7/appcompat/src/androidTest/res/layout/layout_app_theme.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_app_theme.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_app_theme.xml
diff --git a/v7/appcompat/tests/res/layout/layout_button.xml b/v7/appcompat/src/androidTest/res/layout/layout_button.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_button.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_button.xml
diff --git a/v7/appcompat/tests/res/layout/layout_button_themed_onclick.xml b/v7/appcompat/src/androidTest/res/layout/layout_button_themed_onclick.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_button_themed_onclick.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_button_themed_onclick.xml
diff --git a/v7/appcompat/tests/res/layout/layout_checkbox.xml b/v7/appcompat/src/androidTest/res/layout/layout_checkbox.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_checkbox.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_checkbox.xml
diff --git a/v7/appcompat/tests/res/layout/layout_children.xml b/v7/appcompat/src/androidTest/res/layout/layout_children.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_children.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_children.xml
diff --git a/v7/appcompat/tests/res/layout/layout_contextwrapperparent_imageview_vector.xml b/v7/appcompat/src/androidTest/res/layout/layout_contextwrapperparent_imageview_vector.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_contextwrapperparent_imageview_vector.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_contextwrapperparent_imageview_vector.xml
diff --git a/v7/appcompat/tests/res/layout/layout_edittext.xml b/v7/appcompat/src/androidTest/res/layout/layout_edittext.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_edittext.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_edittext.xml
diff --git a/v7/appcompat/tests/res/layout/layout_imageview_vector.xml b/v7/appcompat/src/androidTest/res/layout/layout_imageview_vector.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_imageview_vector.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_imageview_vector.xml
diff --git a/v7/appcompat/tests/res/layout/layout_mactv.xml b/v7/appcompat/src/androidTest/res/layout/layout_mactv.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_mactv.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_mactv.xml
diff --git a/v7/appcompat/tests/res/layout/layout_radiobutton.xml b/v7/appcompat/src/androidTest/res/layout/layout_radiobutton.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_radiobutton.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_radiobutton.xml
diff --git a/v7/appcompat/tests/res/layout/layout_radiobutton_vector.xml b/v7/appcompat/src/androidTest/res/layout/layout_radiobutton_vector.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_radiobutton_vector.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_radiobutton_vector.xml
diff --git a/v7/appcompat/tests/res/layout/layout_ratingbar.xml b/v7/appcompat/src/androidTest/res/layout/layout_ratingbar.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_ratingbar.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_ratingbar.xml
diff --git a/v7/appcompat/tests/res/layout/layout_spinner.xml b/v7/appcompat/src/androidTest/res/layout/layout_spinner.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/layout_spinner.xml
rename to v7/appcompat/src/androidTest/res/layout/layout_spinner.xml
diff --git a/v7/appcompat/tests/res/layout/popup_test_activity.xml b/v7/appcompat/src/androidTest/res/layout/popup_test_activity.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/popup_test_activity.xml
rename to v7/appcompat/src/androidTest/res/layout/popup_test_activity.xml
diff --git a/v7/appcompat/tests/res/layout/popup_window_item.xml b/v7/appcompat/src/androidTest/res/layout/popup_window_item.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/popup_window_item.xml
rename to v7/appcompat/src/androidTest/res/layout/popup_window_item.xml
diff --git a/v7/appcompat/tests/res/layout/searchview_suggestion_item.xml b/v7/appcompat/src/androidTest/res/layout/searchview_suggestion_item.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/searchview_suggestion_item.xml
rename to v7/appcompat/src/androidTest/res/layout/searchview_suggestion_item.xml
diff --git a/v7/appcompat/tests/res/layout/textview_autosize_maxlines.xml b/v7/appcompat/src/androidTest/res/layout/textview_autosize_maxlines.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/textview_autosize_maxlines.xml
rename to v7/appcompat/src/androidTest/res/layout/textview_autosize_maxlines.xml
diff --git a/v7/appcompat/tests/res/layout/toolbar_decor_content.xml b/v7/appcompat/src/androidTest/res/layout/toolbar_decor_content.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/toolbar_decor_content.xml
rename to v7/appcompat/src/androidTest/res/layout/toolbar_decor_content.xml
diff --git a/v7/appcompat/tests/res/layout/window_decor_content.xml b/v7/appcompat/src/androidTest/res/layout/window_decor_content.xml
similarity index 100%
rename from v7/appcompat/tests/res/layout/window_decor_content.xml
rename to v7/appcompat/src/androidTest/res/layout/window_decor_content.xml
diff --git a/v7/appcompat/tests/res/menu/appcompat_menu_icon_tinting.xml b/v7/appcompat/src/androidTest/res/menu/appcompat_menu_icon_tinting.xml
similarity index 100%
rename from v7/appcompat/tests/res/menu/appcompat_menu_icon_tinting.xml
rename to v7/appcompat/src/androidTest/res/menu/appcompat_menu_icon_tinting.xml
diff --git a/v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml b/v7/appcompat/src/androidTest/res/menu/appcompat_menu_shortcut.xml
similarity index 100%
rename from v7/appcompat/tests/res/menu/appcompat_menu_shortcut.xml
rename to v7/appcompat/src/androidTest/res/menu/appcompat_menu_shortcut.xml
diff --git a/v7/appcompat/tests/res/menu/popup_menu.xml b/v7/appcompat/src/androidTest/res/menu/popup_menu.xml
similarity index 100%
rename from v7/appcompat/tests/res/menu/popup_menu.xml
rename to v7/appcompat/src/androidTest/res/menu/popup_menu.xml
diff --git a/v7/appcompat/tests/res/menu/sample_actions.xml b/v7/appcompat/src/androidTest/res/menu/sample_actions.xml
similarity index 100%
rename from v7/appcompat/tests/res/menu/sample_actions.xml
rename to v7/appcompat/src/androidTest/res/menu/sample_actions.xml
diff --git a/v7/appcompat/tests/res/menu/shortcut.xml b/v7/appcompat/src/androidTest/res/menu/shortcut.xml
similarity index 100%
rename from v7/appcompat/tests/res/menu/shortcut.xml
rename to v7/appcompat/src/androidTest/res/menu/shortcut.xml
diff --git a/v7/appcompat/tests/res/values-night/colors.xml b/v7/appcompat/src/androidTest/res/values-night/colors.xml
similarity index 100%
rename from v7/appcompat/tests/res/values-night/colors.xml
rename to v7/appcompat/src/androidTest/res/values-night/colors.xml
diff --git a/v7/appcompat/tests/res/values-night/strings.xml b/v7/appcompat/src/androidTest/res/values-night/strings.xml
similarity index 100%
rename from v7/appcompat/tests/res/values-night/strings.xml
rename to v7/appcompat/src/androidTest/res/values-night/strings.xml
diff --git a/v7/appcompat/tests/res/values/arrays.xml b/v7/appcompat/src/androidTest/res/values/arrays.xml
similarity index 100%
rename from v7/appcompat/tests/res/values/arrays.xml
rename to v7/appcompat/src/androidTest/res/values/arrays.xml
diff --git a/v7/appcompat/tests/res/values/colors.xml b/v7/appcompat/src/androidTest/res/values/colors.xml
similarity index 100%
rename from v7/appcompat/tests/res/values/colors.xml
rename to v7/appcompat/src/androidTest/res/values/colors.xml
diff --git a/v7/appcompat/tests/res/values/dimens.xml b/v7/appcompat/src/androidTest/res/values/dimens.xml
similarity index 100%
rename from v7/appcompat/tests/res/values/dimens.xml
rename to v7/appcompat/src/androidTest/res/values/dimens.xml
diff --git a/v7/appcompat/tests/res/values/ids.xml b/v7/appcompat/src/androidTest/res/values/ids.xml
similarity index 100%
rename from v7/appcompat/tests/res/values/ids.xml
rename to v7/appcompat/src/androidTest/res/values/ids.xml
diff --git a/v7/appcompat/tests/res/values/strings.xml b/v7/appcompat/src/androidTest/res/values/strings.xml
similarity index 100%
rename from v7/appcompat/tests/res/values/strings.xml
rename to v7/appcompat/src/androidTest/res/values/strings.xml
diff --git a/v7/appcompat/tests/res/values/styles.xml b/v7/appcompat/src/androidTest/res/values/styles.xml
similarity index 100%
rename from v7/appcompat/tests/res/values/styles.xml
rename to v7/appcompat/src/androidTest/res/values/styles.xml
diff --git a/v7/appcompat/src/main/AndroidManifest.xml b/v7/appcompat/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..039849c
--- /dev/null
+++ b/v7/appcompat/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.v7.appcompat"/>
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
index 081f304..0b5cb48 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
@@ -19,6 +19,8 @@
 import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.ViewCompat;
@@ -28,6 +30,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.AbsListView;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.ImageView;
@@ -41,7 +44,8 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
+public class ListMenuItemView extends LinearLayout
+        implements MenuView.ItemView, AbsListView.SelectionBoundsAdjuster {
     private static final String TAG = "ListMenuItemView";
     private MenuItemImpl mItemData;
 
@@ -51,12 +55,15 @@
     private CheckBox mCheckBox;
     private TextView mShortcutView;
     private ImageView mSubMenuArrowView;
+    private ImageView mGroupDivider;
+    private LinearLayout mContent;
 
     private Drawable mBackground;
     private int mTextAppearance;
     private Context mTextAppearanceContext;
     private boolean mPreserveIconSpacing;
     private Drawable mSubMenuArrow;
+    private boolean mHasListDivider;
 
     private int mMenuType;
 
@@ -82,7 +89,13 @@
         mTextAppearanceContext = context;
         mSubMenuArrow = a.getDrawable(R.styleable.MenuView_subMenuArrow);
 
+        final TypedArray b = context.getTheme()
+                .obtainStyledAttributes(null, new int[] { android.R.attr.divider },
+                        R.attr.dropDownListViewStyle, 0);
+        mHasListDivider = b.hasValue(0);
+
         a.recycle();
+        b.recycle();
     }
 
     @Override
@@ -102,6 +115,9 @@
         if (mSubMenuArrowView != null) {
             mSubMenuArrowView.setImageDrawable(mSubMenuArrow);
         }
+        mGroupDivider = findViewById(R.id.group_divider);
+
+        mContent = findViewById(R.id.content);
     }
 
     @Override
@@ -120,6 +136,18 @@
         setContentDescription(itemData.getContentDescription());
     }
 
+    private void addContentView(View v) {
+        addContentView(v, -1);
+    }
+
+    private void addContentView(View v, int index) {
+        if (mContent != null) {
+            mContent.addView(v, index);
+        } else {
+            addView(v, index);
+        }
+    }
+
     public void setForceShowIcon(boolean forceShow) {
         mPreserveIconSpacing = mForceShowIcon = forceShow;
     }
@@ -269,7 +297,7 @@
         LayoutInflater inflater = getInflater();
         mIconView = (ImageView) inflater.inflate(R.layout.abc_list_menu_item_icon,
                 this, false);
-        addView(mIconView, 0);
+        addContentView(mIconView, 0);
     }
 
     private void insertRadioButton() {
@@ -277,7 +305,7 @@
         mRadioButton =
                 (RadioButton) inflater.inflate(R.layout.abc_list_menu_item_radio,
                         this, false);
-        addView(mRadioButton);
+        addContentView(mRadioButton);
     }
 
     private void insertCheckBox() {
@@ -285,7 +313,7 @@
         mCheckBox =
                 (CheckBox) inflater.inflate(R.layout.abc_list_menu_item_checkbox,
                         this, false);
-        addView(mCheckBox);
+        addContentView(mCheckBox);
     }
 
     @Override
@@ -304,5 +332,29 @@
         }
         return mInflater;
     }
+
+    /**
+     * Enable or disable group dividers for this view.
+     */
+    public void setGroupDividerEnabled(boolean groupDividerEnabled) {
+        // If mHasListDivider is true, disabling the groupDivider.
+        // Otherwise, checking enbling it according to groupDividerEnabled flag.
+        if (mGroupDivider != null) {
+            mGroupDivider.setVisibility(!mHasListDivider
+                    && groupDividerEnabled ? View.VISIBLE : View.GONE);
+        }
+    }
+
+    @Override
+    public void adjustListItemSelectionBounds(Rect rect) {
+        if (mGroupDivider != null && mGroupDivider.getVisibility() == View.VISIBLE) {
+            // groupDivider is a part of ListMenuItemView.
+            // If ListMenuItem with divider enabled is hovered/clicked, divider also gets selected.
+            // Clipping the selector bounds from the top divider portion when divider is enabled,
+            // so that divider does not get selected on hover or click.
+            final LayoutParams lp = (LayoutParams) mGroupDivider.getLayoutParams();
+            rect.top += mGroupDivider.getHeight() + lp.topMargin + lp.bottomMargin;
+        }
+    }
 }
 
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuAdapter.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuAdapter.java
index 3d34a16..b0b5b29 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuAdapter.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuAdapter.java
@@ -93,6 +93,14 @@
             convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
         }
 
+        final int currGroupId = getItem(position).getGroupId();
+        final int prevGroupId =
+                position - 1 >= 0 ? getItem(position - 1).getGroupId() : currGroupId;
+        // Show a divider if adjacent items are in different groups.
+        ((ListMenuItemView) convertView)
+                .setGroupDividerEnabled(mAdapterMenu.isGroupDividerEnabled()
+                        && (currGroupId != prevGroupId));
+
         MenuView.ItemView itemView = (MenuView.ItemView) convertView;
         if (mForceShowIcon) {
             ((ListMenuItemView) convertView).setForceShowIcon(true);
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuBuilder.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuBuilder.java
index e6dee8d..eaa94ea 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuBuilder.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuBuilder.java
@@ -181,6 +181,11 @@
     private MenuItemImpl mExpandedItem;
 
     /**
+     * Whether group dividers are enabled.
+     */
+    private boolean mGroupDividerEnabled = false;
+
+    /**
      * Whether to override the result of {@link #hasVisibleItems()} and always return true
      */
     private boolean mOverrideVisibleItems;
@@ -505,6 +510,15 @@
     }
 
     @Override
+    public void setGroupDividerEnabled(boolean enabled) {
+        mGroupDividerEnabled = enabled;
+    }
+
+    public boolean isGroupDividerEnabled() {
+        return mGroupDividerEnabled;
+    }
+
+    @Override
     public int addIntentOptions(int group, int id, int categoryOrder, ComponentName caller,
             Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
         PackageManager pm = mContext.getPackageManager();
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopupHelper.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopupHelper.java
index 35721b8..a6ee759 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopupHelper.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/MenuPopupHelper.java
@@ -269,7 +269,7 @@
             final int hgrav = GravityCompat.getAbsoluteGravity(mDropDownGravity,
                     ViewCompat.getLayoutDirection(mAnchorView)) & Gravity.HORIZONTAL_GRAVITY_MASK;
             if (hgrav == Gravity.RIGHT) {
-                xOffset += mAnchorView.getWidth();
+                xOffset -= mAnchorView.getWidth();
             }
 
             popup.setHorizontalOffset(xOffset);
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/StandardMenuPopup.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/StandardMenuPopup.java
index d94ff72..7026959 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/StandardMenuPopup.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/StandardMenuPopup.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.Parcelable;
+import android.support.v4.view.ViewCompat;
 import android.support.v7.appcompat.R;
 import android.support.v7.widget.MenuPopupWindow;
 import android.view.Gravity;
@@ -260,7 +261,6 @@
                     mShownAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
             subPopup.setPresenterCallback(mPresenterCallback);
             subPopup.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(subMenu));
-            subPopup.setGravity(mDropDownGravity);
 
             // Pass responsibility for handling onDismiss to the submenu.
             subPopup.setOnDismissListener(mOnDismissListener);
@@ -270,8 +270,17 @@
             mMenu.close(false /* closeAllMenus */);
 
             // Show the new sub-menu popup at the same location as this popup.
-            final int horizontalOffset = mPopup.getHorizontalOffset();
+            int horizontalOffset = mPopup.getHorizontalOffset();
             final int verticalOffset = mPopup.getVerticalOffset();
+
+            // As xOffset of parent menu popup is subtracted with Anchor width for Gravity.RIGHT,
+            // So, again to display sub-menu popup in same xOffset, add the Anchor width.
+            final int hgrav = Gravity.getAbsoluteGravity(mDropDownGravity,
+                    ViewCompat.getLayoutDirection(mAnchorView)) & Gravity.HORIZONTAL_GRAVITY_MASK;
+            if (hgrav == Gravity.RIGHT) {
+                horizontalOffset += mAnchorView.getWidth();
+            }
+
             if (subPopup.tryShow(horizontalOffset, verticalOffset)) {
                 if (mPresenterCallback != null) {
                     mPresenterCallback.onOpenSubMenu(subMenu);
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuBuilder.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuBuilder.java
index 94300ed..d17ff02 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuBuilder.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/SubMenuBuilder.java
@@ -144,4 +144,14 @@
         }
         return super.getActionViewStatesKey() + ":" + itemId;
     }
+
+    @Override
+    public void setGroupDividerEnabled(boolean groupDividerEnabled) {
+        mParentMenu.setGroupDividerEnabled(groupDividerEnabled);
+    }
+
+    @Override
+    public boolean isGroupDividerEnabled() {
+        return mParentMenu.isGroupDividerEnabled();
+    }
 }
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarOverlayLayout.java b/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarOverlayLayout.java
index b5cdc7a..5841013 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarOverlayLayout.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/ActionBarOverlayLayout.java
@@ -86,7 +86,7 @@
 
     private ActionBarVisibilityCallback mActionBarVisibilityCallback;
 
-    private final int ACTION_BAR_ANIMATE_DELAY = 600; // ms
+    private static final int ACTION_BAR_ANIMATE_DELAY = 600; // ms
 
     private OverScroller mFlingEstimator;
 
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
index 6831fcb..fdda68e 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/AppCompatEditText.java
@@ -25,8 +25,10 @@
 import android.support.annotation.DrawableRes;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
+import android.support.v4.os.BuildCompat;
 import android.support.v4.view.TintableBackgroundView;
 import android.support.v7.appcompat.R;
+import android.text.Editable;
 import android.util.AttributeSet;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
@@ -71,6 +73,20 @@
         mTextHelper.applyCompoundDrawablesTints();
     }
 
+    /**
+     * Return the text that the view is displaying. If an editable text has not been set yet, this
+     * will return null.
+     */
+    @Override
+    @Nullable public Editable getText() {
+        if (BuildCompat.isAtLeastP()) {
+            return super.getText();
+        }
+        // A bug pre-P makes getText() crash if called before the first setText due to a cast, so
+        // retrieve the editable text.
+        return super.getEditableText();
+    }
+
     @Override
     public void setBackgroundResource(@DrawableRes int resId) {
         super.setBackgroundResource(resId);
diff --git a/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
index 3d3c300..8de44e6 100644
--- a/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
+++ b/v7/appcompat/src/main/java/android/support/v7/widget/TooltipCompatHandler.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.support.annotation.RestrictTo;
 import android.support.v4.view.ViewCompat;
+import android.support.v4.view.ViewConfigurationCompat;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -46,6 +47,7 @@
 
     private final View mAnchor;
     private final CharSequence mTooltipText;
+    private final int mHoverSlop;
 
     private final Runnable mShowRunnable = new Runnable() {
         @Override
@@ -82,10 +84,10 @@
     public static void setTooltipText(View view, CharSequence tooltipText) {
         // The code below is not attempting to update the tooltip text
         // for a pending or currently active tooltip, because it may lead
-        // to updating the wrong tooltipin in some rare cases (e.g. when
+        // to updating the wrong tooltip in in some rare cases (e.g. when
         // action menu item views are recycled). Instead, the tooltip is
         // canceled/hidden. This might still be the wrong tooltip,
-        // but hiding wrong tooltip is less disruptive UX.
+        // but hiding a wrong tooltip is less disruptive UX.
         if (sPendingHandler != null && sPendingHandler.mAnchor == view) {
             setPendingHandler(null);
         }
@@ -104,6 +106,9 @@
     private TooltipCompatHandler(View anchor, CharSequence tooltipText) {
         mAnchor = anchor;
         mTooltipText = tooltipText;
+        mHoverSlop = ViewConfigurationCompat.getScaledHoverSlop(
+                ViewConfiguration.get(mAnchor.getContext()));
+        clearAnchorPos();
 
         mAnchor.setOnLongClickListener(this);
         mAnchor.setOnHoverListener(this);
@@ -129,13 +134,12 @@
         }
         switch (event.getAction()) {
             case MotionEvent.ACTION_HOVER_MOVE:
-                if (mAnchor.isEnabled() && mPopup == null) {
-                    mAnchorX = (int) event.getX();
-                    mAnchorY = (int) event.getY();
+                if (mAnchor.isEnabled() && mPopup == null && updateAnchorPos(event)) {
                     setPendingHandler(this);
                 }
                 break;
             case MotionEvent.ACTION_HOVER_EXIT:
+                clearAnchorPos();
                 hide();
                 break;
         }
@@ -188,6 +192,7 @@
             if (mPopup != null) {
                 mPopup.hide();
                 mPopup = null;
+                clearAnchorPos();
                 mAnchor.removeOnAttachStateChangeListener(this);
             } else {
                 Log.e(TAG, "sActiveHandler.mPopup == null");
@@ -216,4 +221,31 @@
     private void cancelPendingShow() {
         mAnchor.removeCallbacks(mShowRunnable);
     }
+
+    /**
+     * Update the anchor position if it significantly (that is by at least mHoverSlope)
+     * different from the previously stored position. Ignoring insignificant changes
+     * filters out the jitter which is typical for such input sources as stylus.
+     *
+     * @return True if the position has been updated.
+     */
+    private boolean updateAnchorPos(MotionEvent event) {
+        final int newAnchorX = (int) event.getX();
+        final int newAnchorY = (int) event.getY();
+        if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop
+                && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) {
+            return false;
+        }
+        mAnchorX = newAnchorX;
+        mAnchorY = newAnchorY;
+        return true;
+    }
+
+    /**
+     *  Clear the anchor position to ensure that the next change is considered significant.
+     */
+    private void clearAnchorPos() {
+        mAnchorX = Integer.MAX_VALUE;
+        mAnchorY = Integer.MAX_VALUE;
+    }
 }
diff --git a/v7/appcompat/tests/NO_DOCS b/v7/appcompat/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/v7/appcompat/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/v7/cardview/Android.mk b/v7/cardview/Android.mk
deleted file mode 100644
index ae4f121..0000000
--- a/v7/cardview/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := android-support-v7-cardview
-#
-# in their makefiles to include the resources in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v7-cardview
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v7/cardview/src/main/AndroidManifest.xml b/v7/cardview/src/main/AndroidManifest.xml
index 3831492..56e5556 100644
--- a/v7/cardview/src/main/AndroidManifest.xml
+++ b/v7/cardview/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.cardview">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.v7.cardview"/>
diff --git a/v7/gridlayout/Android.mk b/v7/gridlayout/Android.mk
deleted file mode 100644
index 81791da..0000000
--- a/v7/gridlayout/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v7-gridlayout \
-#       android-support-compat \
-#       android-support-core-ui
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v7-gridlayout
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat \
-    android-support-core-ui
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
diff --git a/v7/gridlayout/AndroidManifest.xml b/v7/gridlayout/AndroidManifest.xml
deleted file mode 100644
index 288bb34..0000000
--- a/v7/gridlayout/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.gridlayout">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index ae8bac0..329cb00 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -14,12 +14,6 @@
     androidTestImplementation(ESPRESSO_CORE)
 }
 
-android {
-    sourceSets {
-        main.res.srcDir 'res'
-    }
-}
-
 supportLibrary {
     name = "Android Support Grid Layout"
     publish = true
@@ -27,5 +21,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2013"
     description = "Android Support Grid Layout"
-    legacySourceLocation = true
 }
diff --git a/v7/gridlayout/tests/AndroidManifest.xml b/v7/gridlayout/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from v7/gridlayout/tests/AndroidManifest.xml
rename to v7/gridlayout/src/androidTest/AndroidManifest.xml
diff --git a/v7/gridlayout/tests/src/android/support/v7/widget/GridLayoutTest.java b/v7/gridlayout/src/androidTest/java/android/support/v7/widget/GridLayoutTest.java
similarity index 100%
rename from v7/gridlayout/tests/src/android/support/v7/widget/GridLayoutTest.java
rename to v7/gridlayout/src/androidTest/java/android/support/v7/widget/GridLayoutTest.java
diff --git a/v7/gridlayout/tests/src/android/support/v7/widget/GridLayoutTestActivity.java b/v7/gridlayout/src/androidTest/java/android/support/v7/widget/GridLayoutTestActivity.java
similarity index 100%
rename from v7/gridlayout/tests/src/android/support/v7/widget/GridLayoutTestActivity.java
rename to v7/gridlayout/src/androidTest/java/android/support/v7/widget/GridLayoutTestActivity.java
diff --git a/v7/gridlayout/tests/res/layout/fill_horizontal_test.xml b/v7/gridlayout/src/androidTest/res/layout/fill_horizontal_test.xml
similarity index 100%
rename from v7/gridlayout/tests/res/layout/fill_horizontal_test.xml
rename to v7/gridlayout/src/androidTest/res/layout/fill_horizontal_test.xml
diff --git a/v7/gridlayout/tests/res/layout/height_wrap_content_test.xml b/v7/gridlayout/src/androidTest/res/layout/height_wrap_content_test.xml
similarity index 100%
rename from v7/gridlayout/tests/res/layout/height_wrap_content_test.xml
rename to v7/gridlayout/src/androidTest/res/layout/height_wrap_content_test.xml
diff --git a/v7/gridlayout/tests/res/layout/make_view_gone_test.xml b/v7/gridlayout/src/androidTest/res/layout/make_view_gone_test.xml
similarity index 100%
rename from v7/gridlayout/tests/res/layout/make_view_gone_test.xml
rename to v7/gridlayout/src/androidTest/res/layout/make_view_gone_test.xml
diff --git a/v7/gridlayout/tests/res/layout/use_default_margin_test.xml b/v7/gridlayout/src/androidTest/res/layout/use_default_margin_test.xml
similarity index 100%
rename from v7/gridlayout/tests/res/layout/use_default_margin_test.xml
rename to v7/gridlayout/src/androidTest/res/layout/use_default_margin_test.xml
diff --git a/v7/gridlayout/tests/res/values/colors.xml b/v7/gridlayout/src/androidTest/res/values/colors.xml
similarity index 100%
rename from v7/gridlayout/tests/res/values/colors.xml
rename to v7/gridlayout/src/androidTest/res/values/colors.xml
diff --git a/v7/gridlayout/src/main/AndroidManifest.xml b/v7/gridlayout/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a295aef
--- /dev/null
+++ b/v7/gridlayout/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.v7.gridlayout"/>
diff --git a/v7/gridlayout/res/values/attrs.xml b/v7/gridlayout/src/main/res/values/attrs.xml
similarity index 100%
rename from v7/gridlayout/res/values/attrs.xml
rename to v7/gridlayout/src/main/res/values/attrs.xml
diff --git a/v7/gridlayout/res/values/dimens.xml b/v7/gridlayout/src/main/res/values/dimens.xml
similarity index 100%
rename from v7/gridlayout/res/values/dimens.xml
rename to v7/gridlayout/src/main/res/values/dimens.xml
diff --git a/v7/gridlayout/tests/NO_DOCS b/v7/gridlayout/tests/NO_DOCS
deleted file mode 100644
index 092a39c..0000000
--- a/v7/gridlayout/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/v7/mediarouter/Android.mk b/v7/mediarouter/Android.mk
deleted file mode 100644
index 21b4a62..0000000
--- a/v7/mediarouter/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v7-mediarouter \
-#       android-support-v7-appcompat \
-#       android-support-v7-palette \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v7-mediarouter
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,jellybean) \
-    $(call all-java-files-under,jellybean-mr1) \
-    $(call all-java-files-under,jellybean-mr2) \
-    $(call all-java-files-under,api24) \
-    $(call all-java-files-under,src)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v7-appcompat \
-    android-support-v7-palette \
-    android-support-v4
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v7/mediarouter/AndroidManifest.xml b/v7/mediarouter/AndroidManifest.xml
deleted file mode 100644
index c20a5c0..0000000
--- a/v7/mediarouter/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.mediarouter">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index a3fd18e..f28938b 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -18,14 +18,12 @@
 
 android {
     sourceSets {
-        main.java.srcDirs = [
+        main.java.srcDirs += [
                 'jellybean',
                 'jellybean-mr1',
                 'jellybean-mr2',
-                'api24',
-                'src'
+                'api24'
         ]
-        main.res.srcDir 'res'
     }
 }
 
@@ -36,5 +34,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2013"
     description = "Android MediaRouter Support Library"
-    legacySourceLocation = true
 }
diff --git a/v7/mediarouter/lint-baseline.xml b/v7/mediarouter/lint-baseline.xml
index b06823b..543ac50 100644
--- a/v7/mediarouter/lint-baseline.xml
+++ b/v7/mediarouter/lint-baseline.xml
@@ -7,7 +7,7 @@
         errorLine1="    public void jumpDrawablesToCurrentState() {"
         errorLine2="                ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="src/android/support/v7/app/MediaRouteButton.java"
+            file="src/main/java/android/support/v7/app/MediaRouteButton.java"
             line="380"
             column="17"/>
     </issue>
@@ -18,7 +18,7 @@
         errorLine1="            Log.e(TAG, &quot;onCreateActionView: this ActionProvider is already associated &quot; +"
         errorLine2="                  ~~~">
         <location
-            file="src/android/support/v7/app/MediaRouteActionProvider.java"
+            file="src/main/java/android/support/v7/app/MediaRouteActionProvider.java"
             line="248"
             column="19"/>
     </issue>
diff --git a/v7/mediarouter/res/values-ar/strings.xml b/v7/mediarouter/res/values-ar/strings.xml
deleted file mode 100644
index 2cfe9e4..0000000
--- a/v7/mediarouter/res/values-ar/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"زر الإرسال"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"زر الإرسال. تم قطع الاتصال"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"زر الإرسال. جارٍ الاتصال"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"زر الإرسال. تم الاتصال"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"إرسال إلى"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"جارٍ البحث عن أجهزة"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع الاتصال"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"إيقاف الإرسال"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"إغلاق"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"تشغيل"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"إيقاف مؤقت"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"إيقاف"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"توسيع"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"تصغير"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"صورة الألبوم"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"شريط تمرير مستوى الصوت"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"لم يتم اختيار أية وسائط"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"لا تتوفر أية معلومات"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"جارٍ إرسال الشاشة"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ca/strings.xml b/v7/mediarouter/res/values-ca/strings.xml
deleted file mode 100644
index a5e5883..0000000
--- a/v7/mediarouter/res/values-ca/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Botó d\'emetre"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botó Emet. Desconnectat."</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botó Emet. S\'està connectant."</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botó Emet. Connectat."</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Emet a"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"S\'estan cercant dispositius"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconnecta"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Atura l\'emissió"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tanca"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Reprodueix"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Posa en pausa"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Atura"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Desplega"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Replega"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Imatge de l\'àlbum"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control lliscant de volum"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No s\'ha seleccionat cap fitxer multimèdia"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hi ha informació disponible"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emissió de pantalla"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-da/strings.xml b/v7/mediarouter/res/values-da/strings.xml
deleted file mode 100644
index 44da892..0000000
--- a/v7/mediarouter/res/values-da/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knap"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knap. Forbindelsen er afbrudt"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knap. Opretter forbindelse"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knap. Tilsluttet"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Finder enheder"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Afbryd"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stop med at caste"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Luk"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Afspil"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Sæt på pause"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Stop"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Udvid"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafik"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Lydstyrkeskyder"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Der er ikke valgt nogen medier"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Der er ingen tilgængelige oplysninger"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skærmen castes"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-eu/strings.xml b/v7/mediarouter/res/values-eu/strings.xml
deleted file mode 100644
index f9b9f8d..0000000
--- a/v7/mediarouter/res/values-eu/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Igorri botoia"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Igortzeko botoia. Deskonektatuta"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Igortzeko botoia. Konektatzen"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Igortzeko botoia. Konektatuta"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Igorri hona"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Gailuak bilatzen"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Deskonektatu"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Utzi igortzeari"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Itxi"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Erreproduzitu"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausatu"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Gelditu"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zabaldu"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tolestu"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumaren azala"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bolumenaren graduatzailea"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ez da hautatu multimedia-edukirik"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ez dago informaziorik"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Pantaila igortzen"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-in/strings.xml b/v7/mediarouter/res/values-in/strings.xml
deleted file mode 100644
index 5e537af..0000000
--- a/v7/mediarouter/res/values-in/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Tombol transmisi"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tombol transmisi. Terputus"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tombol transmisi. Menghubungkan"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tombol transmisi. Terhubung"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Transmisikan ke"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Hentikan cast"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Putar"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Berhenti"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Sampul album"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bilah geser volume"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tidak ada media yang dipilih"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tidak ada info yang tersedia"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmisi layar"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ml/strings.xml b/v7/mediarouter/res/values-ml/strings.xml
deleted file mode 100644
index c7b50be..0000000
--- a/v7/mediarouter/res/values-ml/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"ടാപ്പുചെയ്യുക"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"കാസ്റ്റ് ബട്ടൺ. വിച്ഛേദിച്ചു"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"കാസ്റ്റ് ബട്ടൺ. കണക്‌റ്റുചെയ്യുന്നു"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റുചെയ്തു"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"ഇതിലേക്ക് കാസ്റ്റുചെയ്യുക"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"ഉപകരണങ്ങൾ കണ്ടെത്തുന്നു"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"വിച്ഛേദിക്കുക"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"അടയ്‌ക്കുക"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"പ്ലേ ചെയ്യുക"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"തൽക്കാലം നിർത്തൂ"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"നിര്‍ത്തുക"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"വികസിപ്പിക്കുക"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ചുരുക്കുക"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"ആൽബം ആർട്ട്"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"വോളിയം സ്ലൈഡർ"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"മീഡിയയൊന്നും തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"സ്‌ക്രീൻ കാസ്റ്റുചെയ്യുന്നു"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-mr/strings.xml b/v7/mediarouter/res/values-mr/strings.xml
deleted file mode 100644
index 27923d1..0000000
--- a/v7/mediarouter/res/values-mr/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट बटण"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट बटण. डिस्कनेक्ट केले"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट बटण. कनेक्ट करीत आहे"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट बटण. कनेक्ट केले"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"यावर कास्ट करा"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"डिव्हाइसेस शोधत आहे"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्‍कनेक्‍ट करा"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"कास्ट करणे थांबवा"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"बंद करा"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"प्ले करा"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"विराम"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"थांबा"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करा"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संकुचित करा"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"अल्बम कला"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"व्हॉल्यूम स्लायडर"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"मीडिया निवडला नाही"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोणतीही माहिती उपलब्ध नाही"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्‍ट करीत आहे"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-ta/strings.xml b/v7/mediarouter/res/values-ta/strings.xml
deleted file mode 100644
index 99c6172..0000000
--- a/v7/mediarouter/res/values-ta/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"சிஸ்டம்"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"திரையிடு பட்டன்"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"அனுப்புதல் பொத்தான். துண்டிக்கப்பட்டது"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"அனுப்புதல் பொத்தான். இணைக்கிறது"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"அனுப்புதல் பொத்தான். இணைக்கப்பட்டது"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"இதில் திரையிடு"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"சாதனங்களைத் தேடுகிறது"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"தொடர்பைத் துண்டி"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"அனுப்புவதை நிறுத்து"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"மூடும்"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"இயக்கும்"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"இடைநிறுத்தும்"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"நிறுத்துவதற்கான பொத்தான்"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"விரிவாக்கு"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"சுருக்கு"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"ஆல்பம் ஆர்ட்"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ஒலியளவு ஸ்லைடர்"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"மீடியா எதுவும் தேர்ந்தெடுக்கப்படவில்லை"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"தகவல் எதுவுமில்லை"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"திரையை அனுப்புகிறீர்கள்"</string>
-</resources>
diff --git a/v7/mediarouter/res/values-tr/strings.xml b/v7/mediarouter/res/values-tr/strings.xml
deleted file mode 100644
index a0eb2e4..0000000
--- a/v7/mediarouter/res/values-tr/strings.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--  Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
-    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
-    <string name="mr_button_content_description" msgid="3698378085901466129">"Yayın düğmesi"</string>
-    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayınla düğmesi. Bağlantı kesildi"</string>
-    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayınla düğmesi. Bağlanıyor"</string>
-    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayınla düğmesi. Bağlandı"</string>
-    <string name="mr_chooser_title" msgid="414301941546135990">"Şuraya yayınla:"</string>
-    <string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar bulunuyor"</string>
-    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantıyı kes"</string>
-    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Yayını durdur"</string>
-    <string name="mr_controller_close_description" msgid="7333862312480583260">"Kapat"</string>
-    <string name="mr_controller_play" msgid="683634565969987458">"Oynat"</string>
-    <string name="mr_controller_pause" msgid="5451884435510905406">"Duraklat"</string>
-    <string name="mr_controller_stop" msgid="735874641921425123">"Durdur"</string>
-    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişlet"</string>
-    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Daralt"</string>
-    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albüm kapağı"</string>
-    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ses düzeyi kaydırma çubuğu"</string>
-    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Medya seçilmedi"</string>
-    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Bilgi yok"</string>
-    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayınlanıyor"</string>
-</resources>
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
deleted file mode 100644
index 0e0268b..0000000
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialogFragment.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.app;
-
-import android.app.Dialog;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.support.v4.app.DialogFragment;
-import android.support.v7.media.MediaRouteSelector;
-
-/**
- * Media route chooser dialog fragment.
- * <p>
- * Creates a {@link MediaRouteChooserDialog}.  The application may subclass
- * this dialog fragment to customize the media route chooser dialog.
- * </p>
- */
-public class MediaRouteChooserDialogFragment extends DialogFragment {
-    private final String ARGUMENT_SELECTOR = "selector";
-
-    private MediaRouteChooserDialog mDialog;
-    private MediaRouteSelector mSelector;
-
-    /**
-     * Creates a media route chooser dialog fragment.
-     * <p>
-     * All subclasses of this class must also possess a default constructor.
-     * </p>
-     */
-    public MediaRouteChooserDialogFragment() {
-        setCancelable(true);
-    }
-
-    /**
-     * Gets the media route selector for filtering the routes that the user can select.
-     *
-     * @return The selector, never null.
-     */
-    public MediaRouteSelector getRouteSelector() {
-        ensureRouteSelector();
-        return mSelector;
-    }
-
-    private void ensureRouteSelector() {
-        if (mSelector == null) {
-            Bundle args = getArguments();
-            if (args != null) {
-                mSelector = MediaRouteSelector.fromBundle(args.getBundle(ARGUMENT_SELECTOR));
-            }
-            if (mSelector == null) {
-                mSelector = MediaRouteSelector.EMPTY;
-            }
-        }
-    }
-
-    /**
-     * Sets the media route selector for filtering the routes that the user can select.
-     * This method must be called before the fragment is added.
-     *
-     * @param selector The selector to set.
-     */
-    public void setRouteSelector(MediaRouteSelector selector) {
-        if (selector == null) {
-            throw new IllegalArgumentException("selector must not be null");
-        }
-
-        ensureRouteSelector();
-        if (!mSelector.equals(selector)) {
-            mSelector = selector;
-
-            Bundle args = getArguments();
-            if (args == null) {
-                args = new Bundle();
-            }
-            args.putBundle(ARGUMENT_SELECTOR, selector.asBundle());
-            setArguments(args);
-
-            MediaRouteChooserDialog dialog = (MediaRouteChooserDialog)getDialog();
-            if (dialog != null) {
-                dialog.setRouteSelector(selector);
-            }
-        }
-    }
-
-    /**
-     * Called when the chooser dialog is being created.
-     * <p>
-     * Subclasses may override this method to customize the dialog.
-     * </p>
-     */
-    public MediaRouteChooserDialog onCreateChooserDialog(
-            Context context, Bundle savedInstanceState) {
-        return new MediaRouteChooserDialog(context);
-    }
-
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        mDialog = onCreateChooserDialog(getContext(), savedInstanceState);
-        mDialog.setRouteSelector(getRouteSelector());
-        return mDialog;
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        if (mDialog != null) {
-            mDialog.updateLayout();
-        }
-    }
-}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteDiscoveryFragment.java b/v7/mediarouter/src/android/support/v7/app/MediaRouteDiscoveryFragment.java
deleted file mode 100644
index 3d10b1e..0000000
--- a/v7/mediarouter/src/android/support/v7/app/MediaRouteDiscoveryFragment.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.app;
-
-import android.os.Bundle;
-import android.support.v4.app.Fragment;
-import android.support.v7.media.MediaRouter;
-import android.support.v7.media.MediaRouteSelector;
-
-/**
- * Media route discovery fragment.
- * <p>
- * This fragment takes care of registering a callback for media route discovery
- * during the {@link Fragment#onStart onStart()} phase
- * and removing it during the {@link Fragment#onStop onStop()} phase.
- * </p><p>
- * The application must supply a route selector to specify the kinds of routes
- * to discover.  The application may also override {@link #onCreateCallback} to
- * provide the {@link MediaRouter} callback to register.
- * </p><p>
- * Note that the discovery callback makes the application be connected with all the
- * {@link android.support.v7.media.MediaRouteProviderService media route provider services}
- * while it is registered.
- * </p>
- */
-public class MediaRouteDiscoveryFragment extends Fragment {
-    private final String ARGUMENT_SELECTOR = "selector";
-
-    private MediaRouter mRouter;
-    private MediaRouteSelector mSelector;
-    private MediaRouter.Callback mCallback;
-
-    public MediaRouteDiscoveryFragment() {
-    }
-
-    /**
-     * Gets the media router instance.
-     */
-    public MediaRouter getMediaRouter() {
-        ensureRouter();
-        return mRouter;
-    }
-
-    private void ensureRouter() {
-        if (mRouter == null) {
-            mRouter = MediaRouter.getInstance(getContext());
-        }
-    }
-
-    /**
-     * Gets the media route selector for filtering the routes to be discovered.
-     *
-     * @return The selector, never null.
-     */
-    public MediaRouteSelector getRouteSelector() {
-        ensureRouteSelector();
-        return mSelector;
-    }
-
-    /**
-     * Sets the media route selector for filtering the routes to be discovered.
-     * This method must be called before the fragment is added.
-     *
-     * @param selector The selector to set.
-     */
-    public void setRouteSelector(MediaRouteSelector selector) {
-        if (selector == null) {
-            throw new IllegalArgumentException("selector must not be null");
-        }
-
-        ensureRouteSelector();
-        if (!mSelector.equals(selector)) {
-            mSelector = selector;
-
-            Bundle args = getArguments();
-            if (args == null) {
-                args = new Bundle();
-            }
-            args.putBundle(ARGUMENT_SELECTOR, selector.asBundle());
-            setArguments(args);
-
-            if (mCallback != null) {
-                mRouter.removeCallback(mCallback);
-                mRouter.addCallback(mSelector, mCallback, onPrepareCallbackFlags());
-            }
-        }
-    }
-
-    private void ensureRouteSelector() {
-        if (mSelector == null) {
-            Bundle args = getArguments();
-            if (args != null) {
-                mSelector = MediaRouteSelector.fromBundle(args.getBundle(ARGUMENT_SELECTOR));
-            }
-            if (mSelector == null) {
-                mSelector = MediaRouteSelector.EMPTY;
-            }
-        }
-    }
-
-    /**
-     * Called to create the {@link android.support.v7.media.MediaRouter.Callback callback}
-     * that will be registered.
-     * <p>
-     * The default callback does nothing.  The application may override this method to
-     * supply its own callback.
-     * </p>
-     *
-     * @return The new callback, or null if no callback should be registered.
-     */
-    public MediaRouter.Callback onCreateCallback() {
-        return new MediaRouter.Callback() { };
-    }
-
-    /**
-     * Called to prepare the callback flags that will be used when the
-     * {@link android.support.v7.media.MediaRouter.Callback callback} is registered.
-     * <p>
-     * The default implementation returns {@link MediaRouter#CALLBACK_FLAG_REQUEST_DISCOVERY}.
-     * </p>
-     *
-     * @return The desired callback flags.
-     */
-    public int onPrepareCallbackFlags() {
-        return MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY;
-    }
-
-    @Override
-    public void onStart() {
-        super.onStart();
-
-        ensureRouteSelector();
-        ensureRouter();
-        mCallback = onCreateCallback();
-        if (mCallback != null) {
-            mRouter.addCallback(mSelector, mCallback, onPrepareCallbackFlags());
-        }
-    }
-
-    @Override
-    public void onStop() {
-        if (mCallback != null) {
-            mRouter.removeCallback(mCallback);
-            mCallback = null;
-        }
-
-        super.onStop();
-    }
-}
diff --git a/v7/mediarouter/tests/AndroidManifest.xml b/v7/mediarouter/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from v7/mediarouter/tests/AndroidManifest.xml
rename to v7/mediarouter/src/androidTest/AndroidManifest.xml
diff --git a/v7/mediarouter/tests/src/android/support/v7/app/MediaRouteChooserDialogTest.java b/v7/mediarouter/src/androidTest/java/android/support/v7/app/MediaRouteChooserDialogTest.java
similarity index 100%
rename from v7/mediarouter/tests/src/android/support/v7/app/MediaRouteChooserDialogTest.java
rename to v7/mediarouter/src/androidTest/java/android/support/v7/app/MediaRouteChooserDialogTest.java
diff --git a/v7/mediarouter/tests/src/android/support/v7/app/MediaRouteChooserDialogTestActivity.java b/v7/mediarouter/src/androidTest/java/android/support/v7/app/MediaRouteChooserDialogTestActivity.java
similarity index 100%
rename from v7/mediarouter/tests/src/android/support/v7/app/MediaRouteChooserDialogTestActivity.java
rename to v7/mediarouter/src/androidTest/java/android/support/v7/app/MediaRouteChooserDialogTestActivity.java
diff --git a/v7/mediarouter/tests/src/android/support/v7/media/MediaRouteProviderTest.java b/v7/mediarouter/src/androidTest/java/android/support/v7/media/MediaRouteProviderTest.java
similarity index 100%
rename from v7/mediarouter/tests/src/android/support/v7/media/MediaRouteProviderTest.java
rename to v7/mediarouter/src/androidTest/java/android/support/v7/media/MediaRouteProviderTest.java
diff --git a/v7/mediarouter/tests/src/android/support/v7/media/MediaRouterTest.java b/v7/mediarouter/src/androidTest/java/android/support/v7/media/MediaRouterTest.java
similarity index 100%
rename from v7/mediarouter/tests/src/android/support/v7/media/MediaRouterTest.java
rename to v7/mediarouter/src/androidTest/java/android/support/v7/media/MediaRouterTest.java
diff --git a/v7/mediarouter/tests/src/android/support/v7/media/TestUtils.java b/v7/mediarouter/src/androidTest/java/android/support/v7/media/TestUtils.java
similarity index 100%
rename from v7/mediarouter/tests/src/android/support/v7/media/TestUtils.java
rename to v7/mediarouter/src/androidTest/java/android/support/v7/media/TestUtils.java
diff --git a/v7/mediarouter/tests/res/layout/mr_chooser_dialog_activity.xml b/v7/mediarouter/src/androidTest/res/layout/mr_chooser_dialog_activity.xml
similarity index 100%
rename from v7/mediarouter/tests/res/layout/mr_chooser_dialog_activity.xml
rename to v7/mediarouter/src/androidTest/res/layout/mr_chooser_dialog_activity.xml
diff --git a/v7/mediarouter/tests/res/values/themes.xml b/v7/mediarouter/src/androidTest/res/values/themes.xml
similarity index 100%
rename from v7/mediarouter/tests/res/values/themes.xml
rename to v7/mediarouter/src/androidTest/res/values/themes.xml
diff --git a/v7/mediarouter/src/main/AndroidManifest.xml b/v7/mediarouter/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f9ea241
--- /dev/null
+++ b/v7/mediarouter/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.v7.mediarouter"/>
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteActionProvider.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteActionProvider.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteActionProvider.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteActionProvider.java
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteButton.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteButton.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteButton.java
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteChooserDialog.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteChooserDialog.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteChooserDialog.java
diff --git a/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteChooserDialogFragment.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteChooserDialogFragment.java
new file mode 100644
index 0000000..06772a6
--- /dev/null
+++ b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteChooserDialogFragment.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.app;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.media.MediaRouteSelector;
+
+/**
+ * Media route chooser dialog fragment.
+ * <p>
+ * Creates a {@link MediaRouteChooserDialog}.  The application may subclass
+ * this dialog fragment to customize the media route chooser dialog.
+ * </p>
+ */
+public class MediaRouteChooserDialogFragment extends DialogFragment {
+    private static final String ARGUMENT_SELECTOR = "selector";
+
+    private MediaRouteChooserDialog mDialog;
+    private MediaRouteSelector mSelector;
+
+    /**
+     * Creates a media route chooser dialog fragment.
+     * <p>
+     * All subclasses of this class must also possess a default constructor.
+     * </p>
+     */
+    public MediaRouteChooserDialogFragment() {
+        setCancelable(true);
+    }
+
+    /**
+     * Gets the media route selector for filtering the routes that the user can select.
+     *
+     * @return The selector, never null.
+     */
+    public MediaRouteSelector getRouteSelector() {
+        ensureRouteSelector();
+        return mSelector;
+    }
+
+    private void ensureRouteSelector() {
+        if (mSelector == null) {
+            Bundle args = getArguments();
+            if (args != null) {
+                mSelector = MediaRouteSelector.fromBundle(args.getBundle(ARGUMENT_SELECTOR));
+            }
+            if (mSelector == null) {
+                mSelector = MediaRouteSelector.EMPTY;
+            }
+        }
+    }
+
+    /**
+     * Sets the media route selector for filtering the routes that the user can select.
+     * This method must be called before the fragment is added.
+     *
+     * @param selector The selector to set.
+     */
+    public void setRouteSelector(MediaRouteSelector selector) {
+        if (selector == null) {
+            throw new IllegalArgumentException("selector must not be null");
+        }
+
+        ensureRouteSelector();
+        if (!mSelector.equals(selector)) {
+            mSelector = selector;
+
+            Bundle args = getArguments();
+            if (args == null) {
+                args = new Bundle();
+            }
+            args.putBundle(ARGUMENT_SELECTOR, selector.asBundle());
+            setArguments(args);
+
+            MediaRouteChooserDialog dialog = (MediaRouteChooserDialog)getDialog();
+            if (dialog != null) {
+                dialog.setRouteSelector(selector);
+            }
+        }
+    }
+
+    /**
+     * Called when the chooser dialog is being created.
+     * <p>
+     * Subclasses may override this method to customize the dialog.
+     * </p>
+     */
+    public MediaRouteChooserDialog onCreateChooserDialog(
+            Context context, Bundle savedInstanceState) {
+        return new MediaRouteChooserDialog(context);
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        mDialog = onCreateChooserDialog(getContext(), savedInstanceState);
+        mDialog.setRouteSelector(getRouteSelector());
+        return mDialog;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (mDialog != null) {
+            mDialog.updateLayout();
+        }
+    }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteControllerDialog.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialog.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteControllerDialog.java
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteControllerDialogFragment.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteControllerDialogFragment.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteControllerDialogFragment.java
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogFactory.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteDialogFactory.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteDialogFactory.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteDialogFactory.java
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteDialogHelper.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteDialogHelper.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteDialogHelper.java
diff --git a/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteDiscoveryFragment.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteDiscoveryFragment.java
new file mode 100644
index 0000000..1c7d514
--- /dev/null
+++ b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteDiscoveryFragment.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.app;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v7.media.MediaRouter;
+import android.support.v7.media.MediaRouteSelector;
+
+/**
+ * Media route discovery fragment.
+ * <p>
+ * This fragment takes care of registering a callback for media route discovery
+ * during the {@link Fragment#onStart onStart()} phase
+ * and removing it during the {@link Fragment#onStop onStop()} phase.
+ * </p><p>
+ * The application must supply a route selector to specify the kinds of routes
+ * to discover.  The application may also override {@link #onCreateCallback} to
+ * provide the {@link MediaRouter} callback to register.
+ * </p><p>
+ * Note that the discovery callback makes the application be connected with all the
+ * {@link android.support.v7.media.MediaRouteProviderService media route provider services}
+ * while it is registered.
+ * </p>
+ */
+public class MediaRouteDiscoveryFragment extends Fragment {
+    private static final String ARGUMENT_SELECTOR = "selector";
+
+    private MediaRouter mRouter;
+    private MediaRouteSelector mSelector;
+    private MediaRouter.Callback mCallback;
+
+    public MediaRouteDiscoveryFragment() {
+    }
+
+    /**
+     * Gets the media router instance.
+     */
+    public MediaRouter getMediaRouter() {
+        ensureRouter();
+        return mRouter;
+    }
+
+    private void ensureRouter() {
+        if (mRouter == null) {
+            mRouter = MediaRouter.getInstance(getContext());
+        }
+    }
+
+    /**
+     * Gets the media route selector for filtering the routes to be discovered.
+     *
+     * @return The selector, never null.
+     */
+    public MediaRouteSelector getRouteSelector() {
+        ensureRouteSelector();
+        return mSelector;
+    }
+
+    /**
+     * Sets the media route selector for filtering the routes to be discovered.
+     * This method must be called before the fragment is added.
+     *
+     * @param selector The selector to set.
+     */
+    public void setRouteSelector(MediaRouteSelector selector) {
+        if (selector == null) {
+            throw new IllegalArgumentException("selector must not be null");
+        }
+
+        ensureRouteSelector();
+        if (!mSelector.equals(selector)) {
+            mSelector = selector;
+
+            Bundle args = getArguments();
+            if (args == null) {
+                args = new Bundle();
+            }
+            args.putBundle(ARGUMENT_SELECTOR, selector.asBundle());
+            setArguments(args);
+
+            if (mCallback != null) {
+                mRouter.removeCallback(mCallback);
+                mRouter.addCallback(mSelector, mCallback, onPrepareCallbackFlags());
+            }
+        }
+    }
+
+    private void ensureRouteSelector() {
+        if (mSelector == null) {
+            Bundle args = getArguments();
+            if (args != null) {
+                mSelector = MediaRouteSelector.fromBundle(args.getBundle(ARGUMENT_SELECTOR));
+            }
+            if (mSelector == null) {
+                mSelector = MediaRouteSelector.EMPTY;
+            }
+        }
+    }
+
+    /**
+     * Called to create the {@link android.support.v7.media.MediaRouter.Callback callback}
+     * that will be registered.
+     * <p>
+     * The default callback does nothing.  The application may override this method to
+     * supply its own callback.
+     * </p>
+     *
+     * @return The new callback, or null if no callback should be registered.
+     */
+    public MediaRouter.Callback onCreateCallback() {
+        return new MediaRouter.Callback() { };
+    }
+
+    /**
+     * Called to prepare the callback flags that will be used when the
+     * {@link android.support.v7.media.MediaRouter.Callback callback} is registered.
+     * <p>
+     * The default implementation returns {@link MediaRouter#CALLBACK_FLAG_REQUEST_DISCOVERY}.
+     * </p>
+     *
+     * @return The desired callback flags.
+     */
+    public int onPrepareCallbackFlags() {
+        return MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        ensureRouteSelector();
+        ensureRouter();
+        mCallback = onCreateCallback();
+        if (mCallback != null) {
+            mRouter.addCallback(mSelector, mCallback, onPrepareCallbackFlags());
+        }
+    }
+
+    @Override
+    public void onStop() {
+        if (mCallback != null) {
+            mRouter.removeCallback(mCallback);
+            mCallback = null;
+        }
+
+        super.onStop();
+    }
+}
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteExpandCollapseButton.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteExpandCollapseButton.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteExpandCollapseButton.java
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteVolumeSlider.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouteVolumeSlider.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouteVolumeSlider.java
diff --git a/v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java b/v7/mediarouter/src/main/java/android/support/v7/app/MediaRouterThemeHelper.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/MediaRouterThemeHelper.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/MediaRouterThemeHelper.java
diff --git a/v7/mediarouter/src/android/support/v7/app/OverlayListView.java b/v7/mediarouter/src/main/java/android/support/v7/app/OverlayListView.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/app/OverlayListView.java
rename to v7/mediarouter/src/main/java/android/support/v7/app/OverlayListView.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaControlIntent.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaControlIntent.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaControlIntent.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaControlIntent.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaItemMetadata.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaItemMetadata.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaItemMetadata.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaItemMetadata.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaItemStatus.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaItemStatus.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaItemStatus.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaItemStatus.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteDescriptor.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouteDescriptor.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteDescriptor.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteDiscoveryRequest.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteDiscoveryRequest.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouteDiscoveryRequest.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteDiscoveryRequest.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteProvider.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProvider.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouteProvider.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProvider.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProviderDescriptor.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouteProviderDescriptor.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProviderDescriptor.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderProtocol.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProviderProtocol.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouteProviderProtocol.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProviderProtocol.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteProviderService.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProviderService.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouteProviderService.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteProviderService.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouteSelector.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteSelector.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouteSelector.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouteSelector.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouter.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaRouter.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaRouter.java
diff --git a/v7/mediarouter/src/android/support/v7/media/MediaSessionStatus.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaSessionStatus.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/MediaSessionStatus.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/MediaSessionStatus.java
diff --git a/v7/mediarouter/src/android/support/v7/media/RegisteredMediaRouteProvider.java b/v7/mediarouter/src/main/java/android/support/v7/media/RegisteredMediaRouteProvider.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/RegisteredMediaRouteProvider.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/RegisteredMediaRouteProvider.java
diff --git a/v7/mediarouter/src/android/support/v7/media/RegisteredMediaRouteProviderWatcher.java b/v7/mediarouter/src/main/java/android/support/v7/media/RegisteredMediaRouteProviderWatcher.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/RegisteredMediaRouteProviderWatcher.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/RegisteredMediaRouteProviderWatcher.java
diff --git a/v7/mediarouter/src/android/support/v7/media/RemoteControlClientCompat.java b/v7/mediarouter/src/main/java/android/support/v7/media/RemoteControlClientCompat.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/RemoteControlClientCompat.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/RemoteControlClientCompat.java
diff --git a/v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java b/v7/mediarouter/src/main/java/android/support/v7/media/RemotePlaybackClient.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/RemotePlaybackClient.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/RemotePlaybackClient.java
diff --git a/v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java b/v7/mediarouter/src/main/java/android/support/v7/media/SystemMediaRouteProvider.java
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/SystemMediaRouteProvider.java
rename to v7/mediarouter/src/main/java/android/support/v7/media/SystemMediaRouteProvider.java
diff --git a/v7/mediarouter/src/android/support/v7/media/package.html b/v7/mediarouter/src/main/java/android/support/v7/media/package.html
similarity index 100%
rename from v7/mediarouter/src/android/support/v7/media/package.html
rename to v7/mediarouter/src/main/java/android/support/v7/media/package.html
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_audiotrack_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_audiotrack_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_audiotrack_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_audiotrack_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_audiotrack_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_dialog_close_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_dialog_close_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_dialog_close_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_dialog_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_dialog_close_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_dialog_close_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_dialog_close_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_dialog_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_media_pause_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_media_pause_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_media_pause_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_media_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_media_pause_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_media_pause_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_media_pause_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_media_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_media_play_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_media_play_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_media_play_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_media_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_media_play_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_media_play_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_media_play_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_media_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_media_stop_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_media_stop_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_media_stop_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_media_stop_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_media_stop_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_media_stop_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_media_stop_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_media_stop_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_mr_button_disabled_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disabled_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_mr_button_disabled_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disabled_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_mr_button_disabled_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disabled_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_mr_button_disabled_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disabled_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_mr_button_disconnected_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disconnected_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_mr_button_disconnected_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disconnected_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_mr_button_disconnected_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disconnected_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_mr_button_disconnected_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_disconnected_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_mr_button_grey.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_grey.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_mr_button_grey.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_mr_button_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_group_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_group_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_group_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_group_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_group_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_group_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_vol_type_speaker_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_vol_type_tv_dark.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_tv_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_vol_type_tv_dark.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-hdpi/ic_vol_type_tv_light.png b/v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_tv_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-hdpi/ic_vol_type_tv_light.png
rename to v7/mediarouter/src/main/res/drawable-hdpi/ic_vol_type_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_audiotrack_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_audiotrack_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_audiotrack_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_audiotrack_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_audiotrack_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_dialog_close_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_dialog_close_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_dialog_close_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_dialog_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_dialog_close_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_dialog_close_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_dialog_close_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_dialog_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_media_pause_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_media_pause_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_media_pause_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_media_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_media_pause_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_media_pause_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_media_pause_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_media_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_media_play_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_media_play_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_media_play_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_media_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_media_play_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_media_play_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_media_play_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_media_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_media_stop_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_media_stop_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_media_stop_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_media_stop_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_media_stop_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_media_stop_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_media_stop_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_media_stop_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_mr_button_disabled_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disabled_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_mr_button_disabled_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disabled_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_mr_button_disabled_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disabled_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_mr_button_disabled_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disabled_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_mr_button_disconnected_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disconnected_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_mr_button_disconnected_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disconnected_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_mr_button_disconnected_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disconnected_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_mr_button_disconnected_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_disconnected_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_mr_button_grey.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_grey.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_mr_button_grey.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_mr_button_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_group_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_group_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_group_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_group_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_group_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_group_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_vol_type_speaker_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_vol_type_tv_dark.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_tv_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_vol_type_tv_dark.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-mdpi/ic_vol_type_tv_light.png b/v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_tv_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-mdpi/ic_vol_type_tv_light.png
rename to v7/mediarouter/src/main/res/drawable-mdpi/ic_vol_type_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_audiotrack_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_audiotrack_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_audiotrack_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_audiotrack_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_dialog_close_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_dialog_close_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_dialog_close_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_dialog_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_dialog_close_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_dialog_close_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_dialog_close_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_dialog_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_media_pause_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_pause_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_media_pause_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_media_pause_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_pause_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_media_pause_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_media_play_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_play_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_media_play_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_media_play_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_play_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_media_play_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_media_stop_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_stop_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_media_stop_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_stop_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_media_stop_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_stop_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_media_stop_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_media_stop_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_00_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_00_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_00_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_00_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_00_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_00_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_00_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_00_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_01_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_01_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_01_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_01_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_01_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_01_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_01_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_01_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_02_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_02_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_02_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_02_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_02_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_02_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_02_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_02_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_03_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_03_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_03_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_03_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_03_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_03_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_03_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_03_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_04_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_04_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_04_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_04_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_04_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_04_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_04_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_04_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_05_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_05_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_05_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_05_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_05_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_05_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_05_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_05_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_06_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_06_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_06_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_06_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_06_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_06_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_06_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_06_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_07_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_07_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_07_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_07_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_07_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_07_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_07_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_07_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_08_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_08_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_08_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_08_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_08_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_08_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_08_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_08_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_09_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_09_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_09_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_09_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_09_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_09_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_09_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_09_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_10_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_10_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_10_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_10_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_10_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_10_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_10_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_10_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_11_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_11_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_11_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_11_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_11_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_11_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_11_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_11_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_12_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_12_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_12_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_12_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_12_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_12_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_12_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_12_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_13_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_13_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_13_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_13_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_13_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_13_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_13_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_13_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_14_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_14_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_14_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_14_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_14_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_14_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_14_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_14_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_15_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_15_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_15_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_15_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_15_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_15_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_15_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_15_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_16_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_16_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_16_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_16_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_16_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_16_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_16_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_16_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_17_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_17_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_17_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_17_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_17_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_17_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_17_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_17_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_18_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_18_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_18_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_18_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_18_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_18_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_18_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_18_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_19_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_19_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_19_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_19_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_19_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_19_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_19_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_19_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_20_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_20_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_20_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_20_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_20_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_20_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_20_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_20_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_21_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_21_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_21_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_21_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_21_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_21_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_21_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_21_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_22_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_22_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_22_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_22_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_22_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_22_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_22_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_22_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_23_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_23_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_23_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_23_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_23_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_23_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_23_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_23_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_24_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_24_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_24_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_24_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_24_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_24_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_24_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_24_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_25_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_25_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_25_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_25_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_25_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_25_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_25_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_25_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_26_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_26_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_26_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_26_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_26_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_26_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_26_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_26_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_27_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_27_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_27_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_27_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_27_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_27_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_27_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_27_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_28_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_28_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_28_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_28_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_28_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_28_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_28_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_28_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_29_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_29_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_29_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_29_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_29_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_29_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_29_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_29_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_30_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_30_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_30_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_30_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_30_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_30_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connected_30_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connected_30_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_00_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_00_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_00_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_00_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_00_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_00_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_00_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_00_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_01_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_01_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_01_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_01_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_01_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_01_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_01_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_01_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_02_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_02_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_02_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_02_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_02_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_02_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_02_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_02_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_03_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_03_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_03_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_03_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_03_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_03_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_03_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_03_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_04_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_04_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_04_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_04_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_04_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_04_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_04_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_04_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_05_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_05_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_05_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_05_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_05_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_05_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_05_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_05_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_06_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_06_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_06_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_06_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_06_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_06_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_06_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_06_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_07_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_07_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_07_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_07_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_07_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_07_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_07_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_07_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_08_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_08_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_08_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_08_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_08_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_08_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_08_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_08_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_09_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_09_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_09_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_09_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_09_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_09_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_09_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_09_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_10_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_10_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_10_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_10_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_10_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_10_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_10_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_10_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_11_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_11_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_11_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_11_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_11_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_11_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_11_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_11_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_12_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_12_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_12_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_12_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_12_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_12_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_12_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_12_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_13_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_13_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_13_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_13_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_13_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_13_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_13_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_13_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_14_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_14_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_14_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_14_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_14_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_14_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_14_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_14_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_15_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_15_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_15_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_15_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_15_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_15_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_15_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_15_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_16_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_16_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_16_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_16_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_16_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_16_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_16_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_16_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_17_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_17_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_17_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_17_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_17_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_17_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_17_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_17_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_18_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_18_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_18_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_18_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_18_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_18_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_18_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_18_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_19_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_19_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_19_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_19_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_19_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_19_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_19_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_19_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_20_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_20_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_20_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_20_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_20_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_20_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_20_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_20_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_21_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_21_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_21_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_21_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_21_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_21_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_21_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_21_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_22_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_22_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_22_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_22_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_22_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_22_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_22_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_22_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_23_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_23_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_23_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_23_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_23_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_23_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_23_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_23_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_24_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_24_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_24_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_24_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_24_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_24_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_24_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_24_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_25_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_25_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_25_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_25_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_25_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_25_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_25_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_25_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_26_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_26_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_26_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_26_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_26_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_26_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_26_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_26_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_27_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_27_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_27_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_27_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_27_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_27_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_27_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_27_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_28_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_28_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_28_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_28_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_28_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_28_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_28_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_28_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_29_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_29_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_29_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_29_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_29_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_29_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_29_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_29_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_30_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_30_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_30_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_30_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_30_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_30_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_connecting_30_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_connecting_30_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disabled_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disabled_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disabled_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disabled_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disabled_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disabled_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disabled_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disabled_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disconnected_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disconnected_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disconnected_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disconnected_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disconnected_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disconnected_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_disconnected_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_disconnected_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_mr_button_grey.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_grey.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_mr_button_grey.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_mr_button_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_group_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_group_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_group_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_group_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_group_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_group_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_vol_type_speaker_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_vol_type_tv_dark.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_tv_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_vol_type_tv_dark.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xhdpi/ic_vol_type_tv_light.png b/v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_tv_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xhdpi/ic_vol_type_tv_light.png
rename to v7/mediarouter/src/main/res/drawable-xhdpi/ic_vol_type_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_audiotrack_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_audiotrack_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_audiotrack_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_audiotrack_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_audiotrack_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_dialog_close_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_dialog_close_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_dialog_close_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_dialog_close_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_dialog_close_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_dialog_close_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_dialog_close_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_dialog_close_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_media_pause_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_pause_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_media_pause_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_pause_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_media_pause_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_pause_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_media_pause_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_pause_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_media_play_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_play_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_media_play_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_play_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_media_play_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_play_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_media_play_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_play_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_media_stop_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_stop_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_media_stop_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_stop_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_media_stop_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_stop_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_media_stop_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_media_stop_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_00_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_00_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_00_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_00_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_00_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_00_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_00_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_00_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_01_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_01_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_01_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_01_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_01_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_01_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_01_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_01_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_02_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_02_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_02_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_02_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_02_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_02_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_02_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_02_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_03_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_03_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_03_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_03_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_03_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_03_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_03_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_03_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_04_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_04_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_04_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_04_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_04_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_04_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_04_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_04_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_05_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_05_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_05_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_05_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_05_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_05_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_05_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_05_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_06_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_06_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_06_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_06_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_06_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_06_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_06_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_06_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_07_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_07_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_07_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_07_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_07_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_07_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_07_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_07_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_08_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_08_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_08_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_08_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_08_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_08_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_08_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_08_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_09_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_09_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_09_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_09_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_09_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_09_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_09_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_09_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_10_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_10_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_10_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_10_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_10_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_10_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_10_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_10_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_11_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_11_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_11_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_11_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_11_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_11_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_11_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_11_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_12_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_12_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_12_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_12_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_12_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_12_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_12_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_12_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_13_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_13_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_13_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_13_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_13_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_13_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_13_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_13_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_14_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_14_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_14_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_14_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_14_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_14_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_14_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_14_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_15_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_15_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_15_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_15_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_15_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_15_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_15_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_15_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_16_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_16_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_16_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_16_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_16_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_16_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_16_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_16_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_17_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_17_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_17_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_17_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_17_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_17_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_17_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_17_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_18_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_18_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_18_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_18_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_18_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_18_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_18_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_18_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_19_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_19_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_19_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_19_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_19_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_19_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_19_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_19_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_20_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_20_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_20_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_20_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_20_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_20_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_20_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_20_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_21_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_21_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_21_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_21_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_21_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_21_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_21_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_21_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_22_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_22_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_22_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_22_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_22_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_22_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_22_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_22_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_23_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_23_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_23_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_23_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_23_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_23_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_23_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_23_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_24_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_24_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_24_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_24_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_24_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_24_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_24_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_24_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_25_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_25_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_25_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_25_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_25_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_25_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_25_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_25_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_26_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_26_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_26_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_26_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_26_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_26_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_26_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_26_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_27_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_27_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_27_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_27_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_27_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_27_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_27_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_27_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_28_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_28_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_28_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_28_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_28_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_28_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_28_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_28_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_29_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_29_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_29_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_29_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_29_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_29_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_29_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_29_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_30_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_30_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_30_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_30_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_30_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_30_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connected_30_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connected_30_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_00_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_00_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_00_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_00_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_00_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_00_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_00_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_00_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_01_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_01_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_01_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_01_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_01_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_01_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_01_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_01_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_02_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_02_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_02_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_02_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_02_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_02_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_02_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_02_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_03_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_03_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_03_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_03_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_03_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_03_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_03_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_03_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_04_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_04_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_04_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_04_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_04_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_04_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_04_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_04_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_05_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_05_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_05_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_05_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_05_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_05_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_05_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_05_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_06_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_06_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_06_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_06_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_06_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_06_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_06_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_06_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_07_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_07_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_07_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_07_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_07_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_07_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_07_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_07_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_08_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_08_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_08_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_08_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_08_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_08_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_08_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_08_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_09_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_09_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_09_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_09_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_09_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_09_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_09_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_09_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_10_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_10_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_10_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_10_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_10_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_10_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_10_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_10_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_11_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_11_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_11_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_11_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_11_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_11_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_11_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_11_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_12_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_12_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_12_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_12_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_12_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_12_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_12_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_12_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_13_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_13_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_13_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_13_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_13_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_13_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_13_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_13_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_14_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_14_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_14_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_14_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_14_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_14_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_14_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_14_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_15_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_15_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_15_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_15_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_15_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_15_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_15_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_15_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_16_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_16_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_16_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_16_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_16_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_16_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_16_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_16_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_17_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_17_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_17_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_17_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_17_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_17_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_17_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_17_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_18_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_18_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_18_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_18_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_18_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_18_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_18_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_18_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_19_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_19_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_19_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_19_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_19_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_19_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_19_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_19_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_20_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_20_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_20_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_20_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_20_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_20_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_20_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_20_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_21_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_21_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_21_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_21_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_21_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_21_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_21_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_21_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_22_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_22_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_22_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_22_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_22_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_22_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_22_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_22_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_23_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_23_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_23_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_23_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_23_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_23_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_23_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_23_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_24_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_24_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_24_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_24_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_24_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_24_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_24_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_24_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_25_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_25_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_25_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_25_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_25_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_25_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_25_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_25_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_26_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_26_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_26_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_26_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_26_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_26_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_26_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_26_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_27_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_27_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_27_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_27_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_27_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_27_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_27_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_27_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_28_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_28_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_28_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_28_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_28_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_28_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_28_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_28_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_29_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_29_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_29_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_29_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_29_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_29_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_29_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_29_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_30_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_30_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_30_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_30_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_30_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_30_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_connecting_30_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_connecting_30_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disabled_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disabled_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disabled_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disabled_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disabled_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disabled_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disabled_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disabled_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disconnected_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disconnected_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disconnected_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disconnected_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disconnected_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disconnected_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_disconnected_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_disconnected_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_grey.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_grey.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_mr_button_grey.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_mr_button_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_group_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_group_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_group_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_group_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_group_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_group_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_group_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_group_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_speaker_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_speaker_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_tv_dark.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_tv_dark.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_tv_dark.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_tv_dark.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_tv_light.png b/v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_tv_light.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxhdpi/ic_vol_type_tv_light.png
rename to v7/mediarouter/src/main/res/drawable-xxhdpi/ic_vol_type_tv_light.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_00.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_00.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_00.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_00.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_01.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_01.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_01.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_01.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_02.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_02.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_02.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_02.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_03.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_03.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_03.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_03.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_04.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_04.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_04.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_04.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_05.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_05.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_05.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_05.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_06.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_06.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_06.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_06.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_07.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_07.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_07.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_07.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_08.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_08.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_08.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_08.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_09.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_09.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_09.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_09.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_10.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_10.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_10.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_10.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_11.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_11.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_11.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_11.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_12.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_12.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_12.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_12.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_13.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_13.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_13.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_13.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_14.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_14.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_14.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_14.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_15.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_15.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_collapse_15.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_collapse_15.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_00.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_00.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_00.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_00.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_01.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_01.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_01.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_01.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_02.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_02.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_02.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_02.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_03.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_03.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_03.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_03.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_04.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_04.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_04.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_04.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_05.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_05.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_05.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_05.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_06.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_06.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_06.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_06.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_07.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_07.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_07.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_07.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_08.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_08.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_08.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_08.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_09.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_09.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_09.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_09.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_10.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_10.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_10.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_10.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_11.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_11.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_11.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_11.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_12.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_12.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_12.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_12.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_13.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_13.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_13.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_13.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_14.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_14.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_14.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_14.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_15.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_15.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_group_expand_15.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_group_expand_15.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable-xxxhdpi/ic_mr_button_grey.png b/v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_mr_button_grey.png
similarity index 100%
rename from v7/mediarouter/res/drawable-xxxhdpi/ic_mr_button_grey.png
rename to v7/mediarouter/src/main/res/drawable-xxxhdpi/ic_mr_button_grey.png
Binary files differ
diff --git a/v7/mediarouter/res/drawable/mr_button_connected_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_button_connected_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_button_connected_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_button_connected_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_button_connected_light.xml b/v7/mediarouter/src/main/res/drawable/mr_button_connected_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_button_connected_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_button_connected_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_button_connecting_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_button_connecting_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_button_connecting_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_button_connecting_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_button_connecting_light.xml b/v7/mediarouter/src/main/res/drawable/mr_button_connecting_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_button_connecting_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_button_connecting_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_button_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_button_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_button_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_button_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_button_light.xml b/v7/mediarouter/src/main/res/drawable/mr_button_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_button_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_button_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_dialog_close_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_dialog_close_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_dialog_close_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_dialog_close_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_dialog_close_light.xml b/v7/mediarouter/src/main/res/drawable/mr_dialog_close_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_dialog_close_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_dialog_close_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_dialog_material_background_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_dialog_material_background_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_dialog_material_background_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml b/v7/mediarouter/src/main/res/drawable/mr_dialog_material_background_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_dialog_material_background_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_dialog_material_background_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_group_collapse.xml b/v7/mediarouter/src/main/res/drawable/mr_group_collapse.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_group_collapse.xml
rename to v7/mediarouter/src/main/res/drawable/mr_group_collapse.xml
diff --git a/v7/mediarouter/res/drawable/mr_group_expand.xml b/v7/mediarouter/src/main/res/drawable/mr_group_expand.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_group_expand.xml
rename to v7/mediarouter/src/main/res/drawable/mr_group_expand.xml
diff --git a/v7/mediarouter/res/drawable/mr_media_pause_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_media_pause_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_media_pause_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_media_pause_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_media_pause_light.xml b/v7/mediarouter/src/main/res/drawable/mr_media_pause_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_media_pause_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_media_pause_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_media_play_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_media_play_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_media_play_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_media_play_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_media_play_light.xml b/v7/mediarouter/src/main/res/drawable/mr_media_play_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_media_play_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_media_play_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_media_stop_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_media_stop_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_media_stop_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_media_stop_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_media_stop_light.xml b/v7/mediarouter/src/main/res/drawable/mr_media_stop_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_media_stop_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_media_stop_light.xml
diff --git a/v7/mediarouter/res/drawable/mr_vol_type_audiotrack_dark.xml b/v7/mediarouter/src/main/res/drawable/mr_vol_type_audiotrack_dark.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_vol_type_audiotrack_dark.xml
rename to v7/mediarouter/src/main/res/drawable/mr_vol_type_audiotrack_dark.xml
diff --git a/v7/mediarouter/res/drawable/mr_vol_type_audiotrack_light.xml b/v7/mediarouter/src/main/res/drawable/mr_vol_type_audiotrack_light.xml
similarity index 100%
rename from v7/mediarouter/res/drawable/mr_vol_type_audiotrack_light.xml
rename to v7/mediarouter/src/main/res/drawable/mr_vol_type_audiotrack_light.xml
diff --git a/v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml b/v7/mediarouter/src/main/res/interpolator/mr_fast_out_slow_in.xml
similarity index 100%
rename from v7/mediarouter/res/interpolator/mr_fast_out_slow_in.xml
rename to v7/mediarouter/src/main/res/interpolator/mr_fast_out_slow_in.xml
diff --git a/v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml b/v7/mediarouter/src/main/res/interpolator/mr_linear_out_slow_in.xml
similarity index 100%
rename from v7/mediarouter/res/interpolator/mr_linear_out_slow_in.xml
rename to v7/mediarouter/src/main/res/interpolator/mr_linear_out_slow_in.xml
diff --git a/v7/mediarouter/res/layout/mr_chooser_dialog.xml b/v7/mediarouter/src/main/res/layout/mr_chooser_dialog.xml
similarity index 100%
rename from v7/mediarouter/res/layout/mr_chooser_dialog.xml
rename to v7/mediarouter/src/main/res/layout/mr_chooser_dialog.xml
diff --git a/v7/mediarouter/res/layout/mr_chooser_list_item.xml b/v7/mediarouter/src/main/res/layout/mr_chooser_list_item.xml
similarity index 100%
rename from v7/mediarouter/res/layout/mr_chooser_list_item.xml
rename to v7/mediarouter/src/main/res/layout/mr_chooser_list_item.xml
diff --git a/v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml b/v7/mediarouter/src/main/res/layout/mr_controller_material_dialog_b.xml
similarity index 100%
rename from v7/mediarouter/res/layout/mr_controller_material_dialog_b.xml
rename to v7/mediarouter/src/main/res/layout/mr_controller_material_dialog_b.xml
diff --git a/v7/mediarouter/res/layout/mr_controller_volume_item.xml b/v7/mediarouter/src/main/res/layout/mr_controller_volume_item.xml
similarity index 100%
rename from v7/mediarouter/res/layout/mr_controller_volume_item.xml
rename to v7/mediarouter/src/main/res/layout/mr_controller_volume_item.xml
diff --git a/v7/mediarouter/res/layout/mr_playback_control.xml b/v7/mediarouter/src/main/res/layout/mr_playback_control.xml
similarity index 100%
rename from v7/mediarouter/res/layout/mr_playback_control.xml
rename to v7/mediarouter/src/main/res/layout/mr_playback_control.xml
diff --git a/v7/mediarouter/res/layout/mr_volume_control.xml b/v7/mediarouter/src/main/res/layout/mr_volume_control.xml
similarity index 100%
rename from v7/mediarouter/res/layout/mr_volume_control.xml
rename to v7/mediarouter/src/main/res/layout/mr_volume_control.xml
diff --git a/v7/mediarouter/res/values-af/strings.xml b/v7/mediarouter/src/main/res/values-af/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-af/strings.xml
rename to v7/mediarouter/src/main/res/values-af/strings.xml
diff --git a/v7/mediarouter/res/values-am/strings.xml b/v7/mediarouter/src/main/res/values-am/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-am/strings.xml
rename to v7/mediarouter/src/main/res/values-am/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-ar/strings.xml b/v7/mediarouter/src/main/res/values-ar/strings.xml
new file mode 100644
index 0000000..864fb91
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ar/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"النظام"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"الأجهزة"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"زر الإرسال"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"زر الإرسال. تم قطع الاتصال"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"زر الإرسال. جارٍ الاتصال"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"زر الإرسال. تم الاتصال"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"إرسال إلى"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"جارٍ البحث عن أجهزة"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"قطع الاتصال"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"إيقاف الإرسال"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"إغلاق"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"تشغيل"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"إيقاف مؤقت"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"إيقاف"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"توسيع"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"تصغير"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"صورة الألبوم"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"شريط تمرير مستوى الصوت"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"لم يتم اختيار أي وسائط"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"لا تتوفر أي معلومات"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"جارٍ إرسال الشاشة"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-az/strings.xml b/v7/mediarouter/src/main/res/values-az/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-az/strings.xml
rename to v7/mediarouter/src/main/res/values-az/strings.xml
diff --git a/v7/mediarouter/res/values-b+sr+Latn/strings.xml b/v7/mediarouter/src/main/res/values-b+sr+Latn/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-b+sr+Latn/strings.xml
rename to v7/mediarouter/src/main/res/values-b+sr+Latn/strings.xml
diff --git a/v7/mediarouter/res/values-be/strings.xml b/v7/mediarouter/src/main/res/values-be/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-be/strings.xml
rename to v7/mediarouter/src/main/res/values-be/strings.xml
diff --git a/v7/mediarouter/res/values-bg/strings.xml b/v7/mediarouter/src/main/res/values-bg/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-bg/strings.xml
rename to v7/mediarouter/src/main/res/values-bg/strings.xml
diff --git a/v7/mediarouter/res/values-bn/strings.xml b/v7/mediarouter/src/main/res/values-bn/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-bn/strings.xml
rename to v7/mediarouter/src/main/res/values-bn/strings.xml
diff --git a/v7/mediarouter/res/values-bs/strings.xml b/v7/mediarouter/src/main/res/values-bs/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-bs/strings.xml
rename to v7/mediarouter/src/main/res/values-bs/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-ca/strings.xml b/v7/mediarouter/src/main/res/values-ca/strings.xml
new file mode 100644
index 0000000..7e01048
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ca/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Dispositius"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Botó d\'emetre"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Botó Emet. Desconnectat."</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Botó Emet. S\'està connectant."</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Botó Emet. Connectat."</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"Emet a"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"S\'estan cercant dispositius"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Desconnecta"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Atura l\'emissió"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tanca"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Reprodueix"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Posa en pausa"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"Atura"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Desplega"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Replega"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"Imatge de l\'àlbum"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Control lliscant de volum"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"No s\'han seleccionat fitxers multimèdia"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"No hi ha informació disponible"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Emissió de pantalla"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-cs/strings.xml b/v7/mediarouter/src/main/res/values-cs/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-cs/strings.xml
rename to v7/mediarouter/src/main/res/values-cs/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-da/strings.xml b/v7/mediarouter/src/main/res/values-da/strings.xml
new file mode 100644
index 0000000..d280d2c
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-da/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"System"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Enheder"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Cast-knap"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Cast-knap. Forbindelsen er afbrudt"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Cast-knap. Opretter forbindelse"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Cast-knap. Tilsluttet"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"Cast til"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"Finder enheder"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Afbryd"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Stop med at caste"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Luk"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Afspil"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Sæt på pause"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"Stop"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Udvid"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Skjul"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumgrafik"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Lydstyrkeskyder"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ingen medier er markeret"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Der er ingen tilgængelige oplysninger"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Skærmen castes"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-de/strings.xml b/v7/mediarouter/src/main/res/values-de/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-de/strings.xml
rename to v7/mediarouter/src/main/res/values-de/strings.xml
diff --git a/v7/mediarouter/res/values-el/strings.xml b/v7/mediarouter/src/main/res/values-el/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-el/strings.xml
rename to v7/mediarouter/src/main/res/values-el/strings.xml
diff --git a/v7/mediarouter/res/values-en-rAU/strings.xml b/v7/mediarouter/src/main/res/values-en-rAU/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-en-rAU/strings.xml
rename to v7/mediarouter/src/main/res/values-en-rAU/strings.xml
diff --git a/v7/mediarouter/res/values-en-rCA/strings.xml b/v7/mediarouter/src/main/res/values-en-rCA/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-en-rCA/strings.xml
rename to v7/mediarouter/src/main/res/values-en-rCA/strings.xml
diff --git a/v7/mediarouter/res/values-en-rGB/strings.xml b/v7/mediarouter/src/main/res/values-en-rGB/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-en-rGB/strings.xml
rename to v7/mediarouter/src/main/res/values-en-rGB/strings.xml
diff --git a/v7/mediarouter/res/values-en-rIN/strings.xml b/v7/mediarouter/src/main/res/values-en-rIN/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-en-rIN/strings.xml
rename to v7/mediarouter/src/main/res/values-en-rIN/strings.xml
diff --git a/v7/mediarouter/res/values-en-rXC/strings.xml b/v7/mediarouter/src/main/res/values-en-rXC/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-en-rXC/strings.xml
rename to v7/mediarouter/src/main/res/values-en-rXC/strings.xml
diff --git a/v7/mediarouter/res/values-es-rUS/strings.xml b/v7/mediarouter/src/main/res/values-es-rUS/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-es-rUS/strings.xml
rename to v7/mediarouter/src/main/res/values-es-rUS/strings.xml
diff --git a/v7/mediarouter/res/values-es/strings.xml b/v7/mediarouter/src/main/res/values-es/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-es/strings.xml
rename to v7/mediarouter/src/main/res/values-es/strings.xml
diff --git a/v7/mediarouter/res/values-et/strings.xml b/v7/mediarouter/src/main/res/values-et/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-et/strings.xml
rename to v7/mediarouter/src/main/res/values-et/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-eu/strings.xml b/v7/mediarouter/src/main/res/values-eu/strings.xml
new file mode 100644
index 0000000..11b1d00
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-eu/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistema"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Gailuak"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Igorri botoia"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Igortzeko botoia. Deskonektatuta"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Igortzeko botoia. Konektatzen"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Igortzeko botoia. Konektatuta"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"Igorri hona:"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"Gailuak bilatzen"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Deskonektatu"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Utzi igortzeari"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Itxi"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Erreproduzitu"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Pausatu"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"Gelditu"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Zabaldu"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Tolestu"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albumaren azala"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bolumenaren graduatzailea"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Ez da hautatu multimedia-edukirik"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Ez dago informaziorik"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Pantaila igortzen"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-fa/strings.xml b/v7/mediarouter/src/main/res/values-fa/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-fa/strings.xml
rename to v7/mediarouter/src/main/res/values-fa/strings.xml
diff --git a/v7/mediarouter/res/values-fi/strings.xml b/v7/mediarouter/src/main/res/values-fi/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-fi/strings.xml
rename to v7/mediarouter/src/main/res/values-fi/strings.xml
diff --git a/v7/mediarouter/res/values-fr-rCA/strings.xml b/v7/mediarouter/src/main/res/values-fr-rCA/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-fr-rCA/strings.xml
rename to v7/mediarouter/src/main/res/values-fr-rCA/strings.xml
diff --git a/v7/mediarouter/res/values-fr/strings.xml b/v7/mediarouter/src/main/res/values-fr/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-fr/strings.xml
rename to v7/mediarouter/src/main/res/values-fr/strings.xml
diff --git a/v7/mediarouter/res/values-gl/strings.xml b/v7/mediarouter/src/main/res/values-gl/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-gl/strings.xml
rename to v7/mediarouter/src/main/res/values-gl/strings.xml
diff --git a/v7/mediarouter/res/values-gu/strings.xml b/v7/mediarouter/src/main/res/values-gu/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-gu/strings.xml
rename to v7/mediarouter/src/main/res/values-gu/strings.xml
diff --git a/v7/mediarouter/res/values-hi/strings.xml b/v7/mediarouter/src/main/res/values-hi/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-hi/strings.xml
rename to v7/mediarouter/src/main/res/values-hi/strings.xml
diff --git a/v7/mediarouter/res/values-hr/strings.xml b/v7/mediarouter/src/main/res/values-hr/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-hr/strings.xml
rename to v7/mediarouter/src/main/res/values-hr/strings.xml
diff --git a/v7/mediarouter/res/values-hu/strings.xml b/v7/mediarouter/src/main/res/values-hu/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-hu/strings.xml
rename to v7/mediarouter/src/main/res/values-hu/strings.xml
diff --git a/v7/mediarouter/res/values-hy/strings.xml b/v7/mediarouter/src/main/res/values-hy/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-hy/strings.xml
rename to v7/mediarouter/src/main/res/values-hy/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-in/strings.xml b/v7/mediarouter/src/main/res/values-in/strings.xml
new file mode 100644
index 0000000..becb41e
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-in/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Perangkat"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Tombol Cast"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Tombol Cast. Terputus"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Tombol Cast. Menghubungkan"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Tombol Cast. Terhubung"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"Transmisikan ke"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"Mencari perangkat"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Putuskan sambungan"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Hentikan Transmisi"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Tutup"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Putar"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Jeda"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"Berhenti"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Luaskan"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Ciutkan"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"Sampul album"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Bilah geser volume"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Tidak ada media yang dipilih"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Tidak ada info yang tersedia"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Transmisi layar"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-is/strings.xml b/v7/mediarouter/src/main/res/values-is/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-is/strings.xml
rename to v7/mediarouter/src/main/res/values-is/strings.xml
diff --git a/v7/mediarouter/res/values-it/strings.xml b/v7/mediarouter/src/main/res/values-it/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-it/strings.xml
rename to v7/mediarouter/src/main/res/values-it/strings.xml
diff --git a/v7/mediarouter/res/values-iw/strings.xml b/v7/mediarouter/src/main/res/values-iw/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-iw/strings.xml
rename to v7/mediarouter/src/main/res/values-iw/strings.xml
diff --git a/v7/mediarouter/res/values-ja/strings.xml b/v7/mediarouter/src/main/res/values-ja/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ja/strings.xml
rename to v7/mediarouter/src/main/res/values-ja/strings.xml
diff --git a/v7/mediarouter/res/values-ka/strings.xml b/v7/mediarouter/src/main/res/values-ka/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ka/strings.xml
rename to v7/mediarouter/src/main/res/values-ka/strings.xml
diff --git a/v7/mediarouter/res/values-kk/strings.xml b/v7/mediarouter/src/main/res/values-kk/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-kk/strings.xml
rename to v7/mediarouter/src/main/res/values-kk/strings.xml
diff --git a/v7/mediarouter/res/values-km/strings.xml b/v7/mediarouter/src/main/res/values-km/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-km/strings.xml
rename to v7/mediarouter/src/main/res/values-km/strings.xml
diff --git a/v7/mediarouter/res/values-kn/strings.xml b/v7/mediarouter/src/main/res/values-kn/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-kn/strings.xml
rename to v7/mediarouter/src/main/res/values-kn/strings.xml
diff --git a/v7/mediarouter/res/values-ko/strings.xml b/v7/mediarouter/src/main/res/values-ko/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ko/strings.xml
rename to v7/mediarouter/src/main/res/values-ko/strings.xml
diff --git a/v7/mediarouter/res/values-ky/strings.xml b/v7/mediarouter/src/main/res/values-ky/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ky/strings.xml
rename to v7/mediarouter/src/main/res/values-ky/strings.xml
diff --git a/v7/mediarouter/res/values-land/dimens.xml b/v7/mediarouter/src/main/res/values-land/dimens.xml
similarity index 100%
rename from v7/mediarouter/res/values-land/dimens.xml
rename to v7/mediarouter/src/main/res/values-land/dimens.xml
diff --git a/v7/mediarouter/res/values-lo/strings.xml b/v7/mediarouter/src/main/res/values-lo/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-lo/strings.xml
rename to v7/mediarouter/src/main/res/values-lo/strings.xml
diff --git a/v7/mediarouter/res/values-lt/strings.xml b/v7/mediarouter/src/main/res/values-lt/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-lt/strings.xml
rename to v7/mediarouter/src/main/res/values-lt/strings.xml
diff --git a/v7/mediarouter/res/values-lv/strings.xml b/v7/mediarouter/src/main/res/values-lv/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-lv/strings.xml
rename to v7/mediarouter/src/main/res/values-lv/strings.xml
diff --git a/v7/mediarouter/res/values-mk/strings.xml b/v7/mediarouter/src/main/res/values-mk/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-mk/strings.xml
rename to v7/mediarouter/src/main/res/values-mk/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-ml/strings.xml b/v7/mediarouter/src/main/res/values-ml/strings.xml
new file mode 100644
index 0000000..62258fb
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ml/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"സിസ്റ്റം"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"ഉപകരണങ്ങൾ"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"ടാപ്പുചെയ്യുക"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"കാസ്റ്റ് ബട്ടൺ. വിച്ഛേദിച്ചു"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"കാസ്റ്റ് ബട്ടൺ. കണക്‌റ്റുചെയ്യുന്നു"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"കാസ്റ്റ് ബട്ടൺ. കണക്റ്റുചെയ്തു"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"ഇതിലേക്ക് കാസ്റ്റുചെയ്യുക"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"ഉപകരണങ്ങൾ കണ്ടെത്തുന്നു"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"വിച്ഛേദിക്കുക"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"കാസ്റ്റുചെയ്യൽ നിർത്തുക"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"അവസാനിപ്പിക്കുക"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"പ്ലേ ചെയ്യുക"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"തൽക്കാലം നിർത്തൂ"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"നിര്‍ത്തുക"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"വികസിപ്പിക്കുക"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"ചുരുക്കുക"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"ആൽബം ആർട്ട്"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"വോളിയം സ്ലൈഡർ"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"മീഡിയയൊന്നും തിരഞ്ഞെടുത്തിട്ടില്ല"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"വിവരങ്ങളൊന്നും ലഭ്യമല്ല"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"സ്‌ക്രീൻ കാസ്റ്റുചെയ്യുന്നു"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-mn/strings.xml b/v7/mediarouter/src/main/res/values-mn/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-mn/strings.xml
rename to v7/mediarouter/src/main/res/values-mn/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-mr/strings.xml b/v7/mediarouter/src/main/res/values-mr/strings.xml
new file mode 100644
index 0000000..596b56a
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-mr/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"सिस्टम"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"डिव्हाइसेस"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"कास्ट बटण"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"कास्ट बटण. डिस्कनेक्ट केले"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"कास्ट बटण. कनेक्ट करत आहे"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"कास्ट बटण. कनेक्ट केले"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"यावर कास्ट करा"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"डिव्हाइसेस शोधत आहे"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"डिस्‍कनेक्‍ट करा"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"कास्ट करणे थांबवा"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"बंद करा"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"प्ले करा"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"विराम"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"थांबा"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"विस्तृत करा"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"संकुचित करा"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"अल्बम कला"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"व्हॉल्यूम स्लायडर"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"मीडिया निवडला नाही"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"कोणतीही माहिती उपलब्ध नाही"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"स्क्रीन कास्‍ट करत आहे"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-ms/strings.xml b/v7/mediarouter/src/main/res/values-ms/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ms/strings.xml
rename to v7/mediarouter/src/main/res/values-ms/strings.xml
diff --git a/v7/mediarouter/res/values-my/strings.xml b/v7/mediarouter/src/main/res/values-my/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-my/strings.xml
rename to v7/mediarouter/src/main/res/values-my/strings.xml
diff --git a/v7/mediarouter/res/values-nb/strings.xml b/v7/mediarouter/src/main/res/values-nb/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-nb/strings.xml
rename to v7/mediarouter/src/main/res/values-nb/strings.xml
diff --git a/v7/mediarouter/res/values-ne/strings.xml b/v7/mediarouter/src/main/res/values-ne/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ne/strings.xml
rename to v7/mediarouter/src/main/res/values-ne/strings.xml
diff --git a/v7/mediarouter/res/values-nl/strings.xml b/v7/mediarouter/src/main/res/values-nl/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-nl/strings.xml
rename to v7/mediarouter/src/main/res/values-nl/strings.xml
diff --git a/v7/mediarouter/res/values-pa/strings.xml b/v7/mediarouter/src/main/res/values-pa/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-pa/strings.xml
rename to v7/mediarouter/src/main/res/values-pa/strings.xml
diff --git a/v7/mediarouter/res/values-pl/strings.xml b/v7/mediarouter/src/main/res/values-pl/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-pl/strings.xml
rename to v7/mediarouter/src/main/res/values-pl/strings.xml
diff --git a/v7/mediarouter/res/values-pt-rBR/strings.xml b/v7/mediarouter/src/main/res/values-pt-rBR/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-pt-rBR/strings.xml
rename to v7/mediarouter/src/main/res/values-pt-rBR/strings.xml
diff --git a/v7/mediarouter/res/values-pt-rPT/strings.xml b/v7/mediarouter/src/main/res/values-pt-rPT/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-pt-rPT/strings.xml
rename to v7/mediarouter/src/main/res/values-pt-rPT/strings.xml
diff --git a/v7/mediarouter/res/values-pt/strings.xml b/v7/mediarouter/src/main/res/values-pt/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-pt/strings.xml
rename to v7/mediarouter/src/main/res/values-pt/strings.xml
diff --git a/v7/mediarouter/res/values-ro/strings.xml b/v7/mediarouter/src/main/res/values-ro/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ro/strings.xml
rename to v7/mediarouter/src/main/res/values-ro/strings.xml
diff --git a/v7/mediarouter/res/values-ru/strings.xml b/v7/mediarouter/src/main/res/values-ru/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ru/strings.xml
rename to v7/mediarouter/src/main/res/values-ru/strings.xml
diff --git a/v7/mediarouter/res/values-si/strings.xml b/v7/mediarouter/src/main/res/values-si/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-si/strings.xml
rename to v7/mediarouter/src/main/res/values-si/strings.xml
diff --git a/v7/mediarouter/res/values-sk/strings.xml b/v7/mediarouter/src/main/res/values-sk/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-sk/strings.xml
rename to v7/mediarouter/src/main/res/values-sk/strings.xml
diff --git a/v7/mediarouter/res/values-sl/strings.xml b/v7/mediarouter/src/main/res/values-sl/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-sl/strings.xml
rename to v7/mediarouter/src/main/res/values-sl/strings.xml
diff --git a/v7/mediarouter/res/values-sq/strings.xml b/v7/mediarouter/src/main/res/values-sq/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-sq/strings.xml
rename to v7/mediarouter/src/main/res/values-sq/strings.xml
diff --git a/v7/mediarouter/res/values-sr/strings.xml b/v7/mediarouter/src/main/res/values-sr/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-sr/strings.xml
rename to v7/mediarouter/src/main/res/values-sr/strings.xml
diff --git a/v7/mediarouter/res/values-sv/strings.xml b/v7/mediarouter/src/main/res/values-sv/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-sv/strings.xml
rename to v7/mediarouter/src/main/res/values-sv/strings.xml
diff --git a/v7/mediarouter/res/values-sw/strings.xml b/v7/mediarouter/src/main/res/values-sw/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-sw/strings.xml
rename to v7/mediarouter/src/main/res/values-sw/strings.xml
diff --git a/v7/mediarouter/res/values-sw600dp/dimens.xml b/v7/mediarouter/src/main/res/values-sw600dp/dimens.xml
similarity index 100%
rename from v7/mediarouter/res/values-sw600dp/dimens.xml
rename to v7/mediarouter/src/main/res/values-sw600dp/dimens.xml
diff --git a/v7/mediarouter/res/values-sw720dp/dimens.xml b/v7/mediarouter/src/main/res/values-sw720dp/dimens.xml
similarity index 100%
rename from v7/mediarouter/res/values-sw720dp/dimens.xml
rename to v7/mediarouter/src/main/res/values-sw720dp/dimens.xml
diff --git a/v7/mediarouter/src/main/res/values-ta/strings.xml b/v7/mediarouter/src/main/res/values-ta/strings.xml
new file mode 100644
index 0000000..9888472
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-ta/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"சிஸ்டம்"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"சாதனங்கள்"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"திரையிடு பட்டன்"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"அனுப்புதல் பொத்தான். துண்டிக்கப்பட்டது"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"அனுப்புதல் பொத்தான். இணைக்கிறது"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"அனுப்புதல் பொத்தான். இணைக்கப்பட்டது"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"இதற்கு அனுப்பு"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"சாதனங்களைத் தேடுகிறது"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"தொடர்பைத் துண்டி"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"அனுப்புவதை நிறுத்து"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"மூடும்"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"இயக்கும்"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"இடைநிறுத்தும்"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"நிறுத்துவதற்கான பொத்தான்"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"விரிவாக்கு"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"சுருக்கு"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"ஆல்பம் ஆர்ட்"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"ஒலியளவு ஸ்லைடர்"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"மீடியா எதுவும் தேர்ந்தெடுக்கப்படவில்லை"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"தகவல் எதுவுமில்லை"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"திரையை அனுப்புகிறீர்கள்"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-te/strings.xml b/v7/mediarouter/src/main/res/values-te/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-te/strings.xml
rename to v7/mediarouter/src/main/res/values-te/strings.xml
diff --git a/v7/mediarouter/res/values-th/strings.xml b/v7/mediarouter/src/main/res/values-th/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-th/strings.xml
rename to v7/mediarouter/src/main/res/values-th/strings.xml
diff --git a/v7/mediarouter/res/values-tl/strings.xml b/v7/mediarouter/src/main/res/values-tl/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-tl/strings.xml
rename to v7/mediarouter/src/main/res/values-tl/strings.xml
diff --git a/v7/mediarouter/src/main/res/values-tr/strings.xml b/v7/mediarouter/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..8189092
--- /dev/null
+++ b/v7/mediarouter/src/main/res/values-tr/strings.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="mr_system_route_name" msgid="5441529851481176817">"Sistem"</string>
+    <string name="mr_user_route_category_name" msgid="7498112907524977311">"Cihazlar"</string>
+    <string name="mr_button_content_description" msgid="3698378085901466129">"Yayınla düğmesi"</string>
+    <string name="mr_cast_button_disconnected" msgid="816305490427819240">"Yayınla düğmesi. Bağlantı kesildi"</string>
+    <string name="mr_cast_button_connecting" msgid="2187642765091873834">"Yayınla düğmesi. Bağlanıyor"</string>
+    <string name="mr_cast_button_connected" msgid="5088427771788648085">"Yayınla düğmesi. Bağlandı"</string>
+    <string name="mr_chooser_title" msgid="414301941546135990">"Şuraya yayınla:"</string>
+    <string name="mr_chooser_searching" msgid="6349900579507521956">"Cihazlar bulunuyor"</string>
+    <string name="mr_controller_disconnect" msgid="1227264889412989580">"Bağlantıyı kes"</string>
+    <string name="mr_controller_stop_casting" msgid="8857886794086583226">"Yayını durdur"</string>
+    <string name="mr_controller_close_description" msgid="7333862312480583260">"Kapat"</string>
+    <string name="mr_controller_play" msgid="683634565969987458">"Oynat"</string>
+    <string name="mr_controller_pause" msgid="5451884435510905406">"Duraklat"</string>
+    <string name="mr_controller_stop" msgid="735874641921425123">"Durdur"</string>
+    <string name="mr_controller_expand_group" msgid="8062427022744266907">"Genişlet"</string>
+    <string name="mr_controller_collapse_group" msgid="7924809056904240926">"Daralt"</string>
+    <string name="mr_controller_album_art" msgid="6422801843540543585">"Albüm kapağı"</string>
+    <string name="mr_controller_volume_slider" msgid="2361785992211841709">"Ses düzeyi kaydırma çubuğu"</string>
+    <string name="mr_controller_no_media_selected" msgid="6547130360349182381">"Medya seçilmedi"</string>
+    <string name="mr_controller_no_info_available" msgid="5585418471741142924">"Bilgi yok"</string>
+    <string name="mr_controller_casting_screen" msgid="4868457957151124867">"Ekran yayınlanıyor"</string>
+</resources>
diff --git a/v7/mediarouter/res/values-uk/strings.xml b/v7/mediarouter/src/main/res/values-uk/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-uk/strings.xml
rename to v7/mediarouter/src/main/res/values-uk/strings.xml
diff --git a/v7/mediarouter/res/values-ur/strings.xml b/v7/mediarouter/src/main/res/values-ur/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-ur/strings.xml
rename to v7/mediarouter/src/main/res/values-ur/strings.xml
diff --git a/v7/mediarouter/res/values-uz/strings.xml b/v7/mediarouter/src/main/res/values-uz/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-uz/strings.xml
rename to v7/mediarouter/src/main/res/values-uz/strings.xml
diff --git a/v7/mediarouter/res/values-vi/strings.xml b/v7/mediarouter/src/main/res/values-vi/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-vi/strings.xml
rename to v7/mediarouter/src/main/res/values-vi/strings.xml
diff --git a/v7/mediarouter/res/values-zh-rCN/strings.xml b/v7/mediarouter/src/main/res/values-zh-rCN/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-zh-rCN/strings.xml
rename to v7/mediarouter/src/main/res/values-zh-rCN/strings.xml
diff --git a/v7/mediarouter/res/values-zh-rHK/strings.xml b/v7/mediarouter/src/main/res/values-zh-rHK/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-zh-rHK/strings.xml
rename to v7/mediarouter/src/main/res/values-zh-rHK/strings.xml
diff --git a/v7/mediarouter/res/values-zh-rTW/strings.xml b/v7/mediarouter/src/main/res/values-zh-rTW/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-zh-rTW/strings.xml
rename to v7/mediarouter/src/main/res/values-zh-rTW/strings.xml
diff --git a/v7/mediarouter/res/values-zu/strings.xml b/v7/mediarouter/src/main/res/values-zu/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values-zu/strings.xml
rename to v7/mediarouter/src/main/res/values-zu/strings.xml
diff --git a/v7/mediarouter/res/values/attrs.xml b/v7/mediarouter/src/main/res/values/attrs.xml
similarity index 100%
rename from v7/mediarouter/res/values/attrs.xml
rename to v7/mediarouter/src/main/res/values/attrs.xml
diff --git a/v7/mediarouter/res/values/dimens.xml b/v7/mediarouter/src/main/res/values/dimens.xml
similarity index 100%
rename from v7/mediarouter/res/values/dimens.xml
rename to v7/mediarouter/src/main/res/values/dimens.xml
diff --git a/v7/mediarouter/res/values/strings.xml b/v7/mediarouter/src/main/res/values/strings.xml
similarity index 100%
rename from v7/mediarouter/res/values/strings.xml
rename to v7/mediarouter/src/main/res/values/strings.xml
diff --git a/v7/mediarouter/res/values/styles.xml b/v7/mediarouter/src/main/res/values/styles.xml
similarity index 100%
rename from v7/mediarouter/res/values/styles.xml
rename to v7/mediarouter/src/main/res/values/styles.xml
diff --git a/v7/mediarouter/res/values/themes.xml b/v7/mediarouter/src/main/res/values/themes.xml
similarity index 100%
rename from v7/mediarouter/res/values/themes.xml
rename to v7/mediarouter/src/main/res/values/themes.xml
diff --git a/v7/mediarouter/tests/NO_DOCS b/v7/mediarouter/tests/NO_DOCS
deleted file mode 100644
index 092a39c..0000000
--- a/v7/mediarouter/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/v7/palette/Android.mk b/v7/palette/Android.mk
deleted file mode 100644
index b7dafe9..0000000
--- a/v7/palette/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v7-palette \
-#       android-support-compat \
-#       android-support-core-utils
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v7-palette
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under, src/main)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/src/main/res
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat \
-    android-support-core-utils
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v7/palette/src/androidTest/NO_DOCS b/v7/palette/src/androidTest/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/v7/palette/src/androidTest/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/v7/palette/src/main/AndroidManifest.xml b/v7/palette/src/main/AndroidManifest.xml
index 61bddd2..5aa2501 100644
--- a/v7/palette/src/main/AndroidManifest.xml
+++ b/v7/palette/src/main/AndroidManifest.xml
@@ -13,7 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.palette">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
+<manifest package="android.support.v7.palette"/>
diff --git a/v7/preference/Android.mk b/v7/preference/Android.mk
deleted file mode 100644
index 5a3f57a..0000000
--- a/v7/preference/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v7-preference \
-#       android-support-v7-appcompat \
-#       android-support-v7-recyclerview \
-#       android-support-v4
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v7-preference
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-v7-appcompat \
-    android-support-v7-recyclerview \
-    android-support-v4
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-LOCAL_EXPORT_PROGUARD_FLAG_FILES := proguard-rules.pro
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v7/preference/AndroidManifest.xml b/v7/preference/AndroidManifest.xml
deleted file mode 100644
index 3195a03..0000000
--- a/v7/preference/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.support.v7.preference">
-    <uses-sdk android:minSdkVersion="14" />
-</manifest>
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index 860679c..7707883 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -53,5 +53,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2015"
     description = "Android Support Preference v7"
-    legacySourceLocation = true
 }
diff --git a/v7/preference/tests/AndroidManifest.xml b/v7/preference/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from v7/preference/tests/AndroidManifest.xml
rename to v7/preference/src/androidTest/AndroidManifest.xml
diff --git a/v7/preference/tests/src/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/PreferenceGroupInitialExpandedChildrenCountTest.java
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/PreferenceDataStoreTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceDataStoreTest.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/tests/PreferenceDataStoreTest.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceDataStoreTest.java
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/PreferenceIconSpaceTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceIconSpaceTest.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/tests/PreferenceIconSpaceTest.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceIconSpaceTest.java
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/PreferenceParentGroupTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceParentGroupTest.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/tests/PreferenceParentGroupTest.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceParentGroupTest.java
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/PreferencePersistTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferencePersistTest.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/tests/PreferencePersistTest.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferencePersistTest.java
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/PreferenceSingleLineTitleTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceSingleLineTitleTest.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/tests/PreferenceSingleLineTitleTest.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceSingleLineTitleTest.java
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/SimplePreferenceComparisonCallbackTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/SimplePreferenceComparisonCallbackTest.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/tests/SimplePreferenceComparisonCallbackTest.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/tests/SimplePreferenceComparisonCallbackTest.java
diff --git a/v7/preference/tests/src/android/support/v7/preference/tests/helpers/PreferenceWrapper.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/helpers/PreferenceWrapper.java
similarity index 100%
rename from v7/preference/tests/src/android/support/v7/preference/tests/helpers/PreferenceWrapper.java
rename to v7/preference/src/androidTest/java/android/support/v7/preference/tests/helpers/PreferenceWrapper.java
diff --git a/v7/preference/src/main/AndroidManifest.xml b/v7/preference/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a2854fb
--- /dev/null
+++ b/v7/preference/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.v7.preference"/>
diff --git a/v7/preference/tests/NO_DOCS b/v7/preference/tests/NO_DOCS
deleted file mode 100644
index db956bc..0000000
--- a/v7/preference/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
\ No newline at end of file
diff --git a/v7/recyclerview/Android.mk b/v7/recyclerview/Android.mk
deleted file mode 100644
index a62c3cd..0000000
--- a/v7/recyclerview/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-v7-recyclerview \
-#       android-support-compat \
-#       android-support-core-ui
-#
-# in their makefiles to include the resources and their dependencies in their package.
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE := android-support-v7-recyclerview
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-compat \
-    android-support-core-ui
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-LOCAL_EXPORT_PROGUARD_FLAG_FILES := proguard-rules.pro
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/v7/recyclerview/AndroidManifest.xml b/v7/recyclerview/AndroidManifest.xml
deleted file mode 100644
index f83681e..0000000
--- a/v7/recyclerview/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.v7.recyclerview">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
diff --git a/v7/recyclerview/api/current.txt b/v7/recyclerview/api/current.txt
index cdff0f0..cd5905b 100644
--- a/v7/recyclerview/api/current.txt
+++ b/v7/recyclerview/api/current.txt
@@ -260,7 +260,6 @@
     method protected float calculateSpeedPerPixel(android.util.DisplayMetrics);
     method protected int calculateTimeForDeceleration(int);
     method protected int calculateTimeForScrolling(int);
-    method public android.graphics.PointF computeScrollVectorForPosition(int);
     method protected int getHorizontalSnapPreference();
     method protected int getVerticalSnapPreference();
     method protected void onSeekTargetStep(int, int, android.support.v7.widget.RecyclerView.State, android.support.v7.widget.RecyclerView.SmoothScroller.Action);
@@ -772,6 +771,7 @@
 
   public static abstract class RecyclerView.SmoothScroller {
     ctor public RecyclerView.SmoothScroller();
+    method public android.graphics.PointF computeScrollVectorForPosition(int);
     method public android.view.View findViewByPosition(int);
     method public int getChildCount();
     method public int getChildPosition(android.view.View);
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index b172a01..e58e5b1 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -42,5 +42,4 @@
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2014"
     description = "Android Support RecyclerView v7"
-    legacySourceLocation = true
 }
diff --git a/v7/recyclerview/tests/AndroidManifest.xml b/v7/recyclerview/src/androidTest/AndroidManifest.xml
similarity index 100%
rename from v7/recyclerview/tests/AndroidManifest.xml
rename to v7/recyclerview/src/androidTest/AndroidManifest.xml
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/recyclerview/extensions/AsyncListDifferTest.kt b/v7/recyclerview/src/androidTest/java/android/support/v7/recyclerview/extensions/AsyncListDifferTest.kt
new file mode 100644
index 0000000..2518065
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/recyclerview/extensions/AsyncListDifferTest.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.recyclerview.extensions
+
+import android.support.test.filters.SmallTest
+import android.support.v7.util.DiffUtil
+import android.support.v7.util.ListUpdateCallback
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotSame
+import org.junit.Assert.assertSame
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+import org.mockito.Mockito.verifyZeroInteractions
+import java.lang.UnsupportedOperationException
+import java.util.Collections.emptyList
+import java.util.LinkedList
+import java.util.concurrent.Executor
+
+class TestExecutor : Executor {
+    private val mTasks = LinkedList<Runnable>()
+
+    override fun execute(command: Runnable) {
+        mTasks.add(command)
+    }
+
+    fun executeAll(): Boolean {
+        val consumed = !mTasks.isEmpty()
+
+        var task = mTasks.poll()
+        while (task != null) {
+            task.run()
+            task = mTasks.poll()
+        }
+        return consumed
+    }
+}
+
+@SmallTest
+@RunWith(JUnit4::class)
+class AsyncListDifferTest {
+    private val mMainThread = TestExecutor()
+    private val mBackgroundThread = TestExecutor()
+
+    private fun <T> createHelper(listUpdateCallback: ListUpdateCallback,
+            diffCallback: DiffUtil.ItemCallback<T>): AsyncListDiffer<T> {
+        return AsyncListDiffer(listUpdateCallback,
+                AsyncDifferConfig.Builder<T>(diffCallback)
+                        .setMainThreadExecutor(mMainThread)
+                        .setBackgroundThreadExecutor(mBackgroundThread)
+                        .build())
+    }
+
+    @Test
+    fun initialState() {
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+        assertEquals(0, helper.currentList.size)
+        verifyZeroInteractions(callback)
+    }
+
+    @Test(expected = IndexOutOfBoundsException::class)
+    fun getEmpty() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.currentList[0]
+    }
+
+    @Test(expected = IndexOutOfBoundsException::class)
+    fun getNegative() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.submitList(listOf("a", "b"))
+        helper.currentList[-1]
+    }
+
+    @Test(expected = IndexOutOfBoundsException::class)
+    fun getPastEnd() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.submitList(listOf("a", "b"))
+        helper.currentList[2]
+    }
+
+    fun getCurrentList() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+
+        // null is emptyList
+        assertSame(emptyList<String>(), helper.currentList)
+
+        // other list is wrapped
+        val list = listOf("a", "b")
+        helper.submitList(list)
+        assertEquals(list, helper.currentList)
+        assertNotSame(list, helper.currentList)
+
+        // null again, empty again
+        helper.submitList(null)
+        assertSame(emptyList<String>(), helper.currentList)
+    }
+
+    @Test(expected = UnsupportedOperationException::class)
+    fun mutateCurrentListEmpty() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.currentList[0] = ""
+    }
+
+    @Test(expected = UnsupportedOperationException::class)
+    fun mutateCurrentListNonEmpty() {
+        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
+        helper.submitList(listOf("a"))
+        helper.currentList[0] = ""
+    }
+
+    @Test
+    fun submitListSimple() {
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+
+        helper.submitList(listOf("a", "b"))
+
+        assertEquals(2, helper.currentList.size)
+        assertEquals("a", helper.currentList[0])
+        assertEquals("b", helper.currentList[1])
+
+        verify(callback).onInserted(0, 2)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+    }
+
+    @Test
+    fun submitListUpdate() {
+        val callback = mock(ListUpdateCallback::class.java)
+        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
+
+        // initial list (immediate)
+        helper.submitList(listOf("a", "b"))
+        verify(callback).onInserted(0, 2)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+
+        // update (deferred)
+        helper.submitList(listOf("a", "b", "c"))
+        verifyNoMoreInteractions(callback)
+        drain()
+        verify(callback).onInserted(2, 1)
+        verifyNoMoreInteractions(callback)
+
+        // clear (immediate)
+        helper.submitList(null)
+        verify(callback).onRemoved(0, 3)
+        verifyNoMoreInteractions(callback)
+        drain()
+        verifyNoMoreInteractions(callback)
+    }
+
+    private fun drain() {
+        var executed: Boolean
+        do {
+            executed = mBackgroundThread.executeAll()
+            executed = mMainThread.executeAll() or executed
+        } while (executed)
+    }
+
+    companion object {
+        private val STRING_DIFF_CALLBACK = object : DiffUtil.ItemCallback<String>() {
+            override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
+                return oldItem == newItem
+            }
+
+            override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
+                return oldItem == newItem
+            }
+        }
+
+        private val IGNORE_CALLBACK = object : ListUpdateCallback {
+            override fun onInserted(position: Int, count: Int) {}
+
+            override fun onRemoved(position: Int, count: Int) {}
+
+            override fun onMoved(fromPosition: Int, toPosition: Int) {}
+
+            override fun onChanged(position: Int, count: Int, payload: Any?) {}
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/recyclerview/test/CustomLayoutManager.java b/v7/recyclerview/src/androidTest/java/android/support/v7/recyclerview/test/CustomLayoutManager.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/recyclerview/test/CustomLayoutManager.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/recyclerview/test/CustomLayoutManager.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/recyclerview/test/PrivateLayoutManager.java b/v7/recyclerview/src/androidTest/java/android/support/v7/recyclerview/test/PrivateLayoutManager.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/recyclerview/test/PrivateLayoutManager.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/recyclerview/test/PrivateLayoutManager.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/util/AsyncListUtilTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/util/AsyncListUtilTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/util/AsyncListUtilTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/MessageQueueTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/util/MessageQueueTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/util/MessageQueueTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/util/MessageQueueTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/util/ThreadUtilTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/util/ThreadUtilTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/util/ThreadUtilTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/TileListTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/util/TileListTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/util/TileListTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/util/TileListTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java b/v7/recyclerview/src/androidTest/java/android/support/v7/util/TouchUtils.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/util/TouchUtils.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/util/TouchUtils.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AsyncListUtilLayoutTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AsyncListUtilLayoutTest.java
new file mode 100644
index 0000000..3bfda56
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AsyncListUtilLayoutTest.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.Suppress;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.util.AsyncListUtil;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.BitSet;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class AsyncListUtilLayoutTest extends BaseRecyclerViewInstrumentationTest {
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "AsyncListUtilLayoutTest";
+
+    private static final int ITEM_COUNT = 1000;
+    private static final int TILE_SIZE = 5;
+
+    AsyncTestAdapter mAdapter;
+
+    WrappedLinearLayoutManager mLayoutManager;
+
+    private TestDataCallback mDataCallback;
+    private TestViewCallback mViewCallback;
+    private AsyncListUtil<String> mAsyncListUtil;
+
+    public int mStartPrefetch = 0;
+    public int mEndPrefetch = 0;
+
+    // Test is disabled as it is flaky.
+    @Suppress
+    @Test
+    public void asyncListUtil() throws Throwable {
+        mRecyclerView = inflateWrappedRV();
+        mRecyclerView.setHasFixedSize(true);
+
+        mAdapter = new AsyncTestAdapter();
+        mRecyclerView.setAdapter(mAdapter);
+
+        mLayoutManager = new WrappedLinearLayoutManager(
+                getActivity(), LinearLayoutManager.VERTICAL, false);
+        mRecyclerView.setLayoutManager(mLayoutManager);
+
+        mLayoutManager.expectLayouts(1);
+        setRecyclerView(mRecyclerView);
+        mLayoutManager.waitForLayout(2);
+
+        int rangeStart = 0;
+        assertEquals(rangeStart, mLayoutManager.findFirstVisibleItemPosition());
+
+        final int rangeSize = mLayoutManager.findLastVisibleItemPosition() + 1;
+        assertTrue("No visible items", rangeSize > 0);
+
+        assertEquals("All visible items must be empty at first",
+                rangeSize, getEmptyVisibleChildCount());
+
+        mDataCallback = new TestDataCallback();
+        mViewCallback = new TestViewCallback();
+
+        mDataCallback.expectTilesInRange(rangeStart, rangeSize);
+        mAdapter.expectItemsInRange(rangeStart, rangeSize);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAsyncListUtil = new AsyncListUtil<>(
+                        String.class, TILE_SIZE, mDataCallback, mViewCallback);
+            }
+        });
+
+        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                mAsyncListUtil.onRangeChanged();
+            }
+        });
+        assertAllLoaded("First load");
+
+        rangeStart = roundUp(rangeSize);
+        scrollAndAssert("Scroll with no prefetch", rangeStart, rangeSize);
+
+        rangeStart = roundUp(rangeStart + rangeSize);
+        mEndPrefetch = TILE_SIZE * 2;
+        scrollAndAssert("Scroll with prefetch", rangeStart, rangeSize);
+
+        rangeStart += mEndPrefetch;
+        mEndPrefetch = 0;
+        scrollAndAssert("Scroll a little down, no prefetch", rangeStart, 0);
+
+        rangeStart = ITEM_COUNT / 2;
+        mStartPrefetch = TILE_SIZE * 2;
+        mEndPrefetch = TILE_SIZE * 3;
+        scrollAndAssert("Scroll to middle, prefetch", rangeStart, rangeSize);
+
+        rangeStart -= mStartPrefetch;
+        mStartPrefetch = 0;
+        mEndPrefetch = 0;
+        scrollAndAssert("Scroll a little up, no prefetch", rangeStart, 0);
+
+        Thread.sleep(500);  // Wait for possible spurious messages.
+    }
+
+    private void assertAllLoaded(String context) throws InterruptedException {
+        assertTrue(context + ", timed out while waiting for items", mAdapter.waitForItems(10));
+        assertTrue(context + ", timed out while waiting for tiles", mDataCallback.waitForTiles(10));
+        assertEquals(context + ", empty child found", 0, getEmptyVisibleChildCount());
+    }
+
+    private void scrollAndAssert(String context, int rangeStart, int rangeSize) throws Throwable {
+        if (rangeSize > 0) {
+            mDataCallback.expectTilesInRange(rangeStart, rangeSize);
+        } else {
+            mDataCallback.expectNoNewTilesLoaded();
+        }
+        mAdapter.expectItemsInRange(rangeStart, rangeSize);
+        mLayoutManager.expectLayouts(1);
+        scrollToPositionWithOffset(rangeStart, 0);
+        mLayoutManager.waitForLayout(1);
+        assertAllLoaded(context);
+    }
+
+    void scrollToPositionWithOffset(final int position, final int offset) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mLayoutManager.scrollToPositionWithOffset(position, offset);
+            }
+        });
+    }
+
+    private int roundUp(int value) {
+        return value - value % TILE_SIZE + TILE_SIZE;
+    }
+
+    private int getTileCount(int start, int size) {
+        return ((start + size - 1) / TILE_SIZE) - (start / TILE_SIZE) + 1;
+    }
+
+    private int getEmptyVisibleChildCount() {
+        int emptyChildCount = 0;
+        int firstVisible = mLayoutManager.findFirstVisibleItemPosition();
+        int lastVisible = mLayoutManager.findLastVisibleItemPosition();
+        for (int i = firstVisible; i <= lastVisible; i++) {
+            View child = mLayoutManager.findViewByPosition(i);
+            assertTrue(child instanceof TextView);
+            if (((TextView) child).getText() == "") {
+                emptyChildCount++;
+            }
+        }
+        return emptyChildCount;
+    }
+
+    private class TestDataCallback extends AsyncListUtil.DataCallback<String> {
+
+        private CountDownLatch mTilesLatch;
+
+        @Override
+        public void fillData(String[] data, int startPosition, int itemCount) {
+            assertTrue("Unexpected tile load @" + startPosition, mTilesLatch.getCount() > 0);
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+            }
+            for (int i = 0; i < itemCount; i++) {
+                data[i] = "Item #" + (startPosition + i);
+            }
+            mTilesLatch.countDown();
+        }
+
+        @Override
+        public int refreshData() {
+            return ITEM_COUNT;
+        }
+
+        private void expectTiles(int count) {
+            mTilesLatch = new CountDownLatch(count);
+        }
+
+        public void expectTilesInRange(int rangeStart, int rangeSize) {
+            expectTiles(getTileCount(rangeStart - mStartPrefetch,
+                    rangeSize + mStartPrefetch + mEndPrefetch));
+        }
+
+        public void expectNoNewTilesLoaded() {
+            expectTiles(0);
+        }
+
+        public boolean waitForTiles(long timeoutInSeconds) throws InterruptedException {
+            return mTilesLatch.await(timeoutInSeconds, TimeUnit.SECONDS);
+        }
+    }
+
+    private class TestViewCallback extends AsyncListUtil.ViewCallback {
+        @Override
+        public void getItemRangeInto(int[] outRange) {
+            outRange[0] = mLayoutManager.findFirstVisibleItemPosition();
+            outRange[1] = mLayoutManager.findLastVisibleItemPosition();
+        }
+
+        @Override
+        public void extendRangeInto(int[] range, int[] outRange, int scrollHint) {
+            outRange[0] = range[0] - mStartPrefetch;
+            outRange[1] = range[1] + mEndPrefetch;
+        }
+
+        @Override
+        public void onDataRefresh() {
+            mRecyclerView.getAdapter().notifyDataSetChanged();
+        }
+
+        @Override
+        public void onItemLoaded(int position) {
+            mRecyclerView.getAdapter().notifyItemChanged(position);
+        }
+    }
+
+    private static class SimpleViewHolder extends RecyclerView.ViewHolder {
+
+        public SimpleViewHolder(Context context) {
+            super(new TextView(context));
+        }
+    }
+
+    private class AsyncTestAdapter extends RecyclerView.Adapter<SimpleViewHolder> {
+
+        private BitSet mLoadedPositions;
+        private BitSet mExpectedPositions;
+
+        private CountDownLatch mItemsLatch;
+        public AsyncTestAdapter() {
+            mLoadedPositions = new BitSet(ITEM_COUNT);
+        }
+
+        @Override
+        public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new SimpleViewHolder(parent.getContext());
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position) {
+            final String item = mAsyncListUtil == null ? null : mAsyncListUtil.getItem(position);
+            ((TextView) (holder.itemView)).setText(item == null ? "" : item);
+
+            if (item != null) {
+                mLoadedPositions.set(position);
+                if (mExpectedPositions.get(position)) {
+                    mExpectedPositions.clear(position);
+                    if (mExpectedPositions.cardinality() == 0) {
+                        mItemsLatch.countDown();
+                    }
+                }
+            }
+        }
+
+        @Override
+        public int getItemCount() {
+            return ITEM_COUNT;
+        }
+
+        private void expectItemsInRange(int rangeStart, int rangeSize) {
+            mExpectedPositions = new BitSet(rangeStart + rangeSize);
+            for (int i = 0; i < rangeSize; i++) {
+                if (!mLoadedPositions.get(rangeStart + i)) {
+                    mExpectedPositions.set(rangeStart + i);
+                }
+            }
+            mItemsLatch = new CountDownLatch(1);
+            if (mExpectedPositions.cardinality() == 0) {
+                mItemsLatch.countDown();
+            }
+        }
+
+        public boolean waitForItems(long timeoutInSeconds) throws InterruptedException {
+            return mItemsLatch.await(timeoutInSeconds, TimeUnit.SECONDS);
+        }
+    }
+
+    class WrappedLinearLayoutManager extends LinearLayoutManager {
+
+        CountDownLatch mLayoutLatch;
+
+        public WrappedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
+            super(context, orientation, reverseLayout);
+        }
+
+        public void expectLayouts(int count) {
+            mLayoutLatch = new CountDownLatch(count);
+        }
+
+        public void waitForLayout(int seconds) throws Throwable {
+            mLayoutLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+            checkForMainThreadException();
+            MatcherAssert.assertThat("all layouts should complete on time",
+                    mLayoutLatch.getCount(), CoreMatchers.is(0L));
+            // use a runnable to ensure RV layout is finished
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            try {
+                super.onLayoutChildren(recycler, state);
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+            mLayoutLatch.countDown();
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AttachDetachCollector.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AttachDetachCollector.java
new file mode 100644
index 0000000..dbd157e
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/AttachDetachCollector.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.widget;
+
+
+import android.support.annotation.NonNull;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Simple class that can collect list of view attach and detach events so that we can assert on them
+ */
+public class AttachDetachCollector implements RecyclerView.OnChildAttachStateChangeListener {
+    private final List<View> mAttached = new ArrayList<>();
+    private final List<View> mDetached = new ArrayList<>();
+
+    public AttachDetachCollector(RecyclerView recyclerView) {
+        recyclerView.addOnChildAttachStateChangeListener(this);
+    }
+
+    @Override
+    public void onChildViewAttachedToWindow(@NonNull View view) {
+        mAttached.add(view);
+    }
+
+    @Override
+    public void onChildViewDetachedFromWindow(@NonNull View view) {
+        mDetached.add(view);
+    }
+
+    public void reset() {
+        mAttached.clear();
+        mDetached.clear();
+    }
+
+    public List<View> getAttached() {
+        return mAttached;
+    }
+
+    public List<View> getDetached() {
+        return mDetached;
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseGridLayoutManagerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BaseGridLayoutManagerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseGridLayoutManagerTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseLinearLayoutManagerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BaseLinearLayoutManagerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseLinearLayoutManagerTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewAnimationsTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
new file mode 100644
index 0000000..e47a480
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -0,0 +1,1312 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.app.Instrumentation;
+import android.graphics.Rect;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.testutils.PollingCheck;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.recyclerview.test.R;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+abstract public class BaseRecyclerViewInstrumentationTest {
+
+    private static final String TAG = "RecyclerViewTest";
+
+    private boolean mDebug;
+
+    protected RecyclerView mRecyclerView;
+
+    protected AdapterHelper mAdapterHelper;
+
+    private Throwable mMainThreadException;
+
+    private boolean mIgnoreMainThreadException = false;
+
+    Thread mInstrumentationThread;
+
+    @Rule
+    public ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule(TestActivity.class);
+
+    public BaseRecyclerViewInstrumentationTest() {
+        this(false);
+    }
+
+    public BaseRecyclerViewInstrumentationTest(boolean debug) {
+        mDebug = debug;
+    }
+
+    void checkForMainThreadException() throws Throwable {
+        if (!mIgnoreMainThreadException && mMainThreadException != null) {
+            throw mMainThreadException;
+        }
+    }
+
+    public void setIgnoreMainThreadException(boolean ignoreMainThreadException) {
+        mIgnoreMainThreadException = ignoreMainThreadException;
+    }
+
+    public Throwable getMainThreadException() {
+        return mMainThreadException;
+    }
+
+    protected TestActivity getActivity() {
+        return mActivityRule.getActivity();
+    }
+
+    @Before
+    public final void setUpInsThread() throws Exception {
+        mInstrumentationThread = Thread.currentThread();
+        Item.idCounter.set(0);
+    }
+
+    void setHasTransientState(final View view, final boolean value) {
+        try {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    ViewCompat.setHasTransientState(view, value);
+                }
+            });
+        } catch (Throwable throwable) {
+            Log.e(TAG, "", throwable);
+        }
+    }
+
+    public boolean canReUseActivity() {
+        return true;
+    }
+
+    protected void enableAccessibility()
+            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+        Method getUIAutomation = Instrumentation.class.getMethod("getUiAutomation");
+        getUIAutomation.invoke(InstrumentationRegistry.getInstrumentation());
+    }
+
+    void setAdapter(final RecyclerView.Adapter adapter) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setAdapter(adapter);
+            }
+        });
+    }
+
+    public View focusSearch(final View focused, final int direction) throws Throwable {
+        return focusSearch(focused, direction, false);
+    }
+
+    public View focusSearch(final View focused, final int direction, boolean waitForScroll)
+            throws Throwable {
+        final View[] result = new View[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View view = focused.focusSearch(direction);
+                if (view != null && view != focused) {
+                    view.requestFocus();
+                }
+                result[0] = view;
+            }
+        });
+        if (waitForScroll && (result[0] != null)) {
+            waitForIdleScroll(mRecyclerView);
+        }
+        return result[0];
+    }
+
+    protected WrappedRecyclerView inflateWrappedRV() {
+        return (WrappedRecyclerView)
+                LayoutInflater.from(getActivity()).inflate(R.layout.wrapped_test_rv,
+                        getRecyclerViewContainer(), false);
+    }
+
+    void swapAdapter(final RecyclerView.Adapter adapter,
+            final boolean removeAndRecycleExistingViews) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mRecyclerView.swapAdapter(adapter, removeAndRecycleExistingViews);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        });
+        checkForMainThreadException();
+    }
+
+    void postExceptionToInstrumentation(Throwable t) {
+        if (mInstrumentationThread == Thread.currentThread()) {
+            throw new RuntimeException(t);
+        }
+        if (mMainThreadException != null) {
+            Log.e(TAG, "receiving another main thread exception. dropping.", t);
+        } else {
+            Log.e(TAG, "captured exception on main thread", t);
+            mMainThreadException = t;
+        }
+
+        if (mRecyclerView != null && mRecyclerView
+                .getLayoutManager() instanceof TestLayoutManager) {
+            TestLayoutManager lm = (TestLayoutManager) mRecyclerView.getLayoutManager();
+            // finish all layouts so that we get the correct exception
+            if (lm.layoutLatch != null) {
+                while (lm.layoutLatch.getCount() > 0) {
+                    lm.layoutLatch.countDown();
+                }
+            }
+        }
+    }
+
+    public Instrumentation getInstrumentation() {
+        return InstrumentationRegistry.getInstrumentation();
+    }
+
+    @After
+    public final void tearDown() throws Exception {
+        if (mRecyclerView != null) {
+            try {
+                removeRecyclerView();
+            } catch (Throwable throwable) {
+                throwable.printStackTrace();
+            }
+        }
+        getInstrumentation().waitForIdleSync();
+
+        try {
+            checkForMainThreadException();
+        } catch (Exception e) {
+            throw e;
+        } catch (Throwable throwable) {
+            throw new Exception(Log.getStackTraceString(throwable));
+        }
+    }
+
+    public Rect getDecoratedRecyclerViewBounds() {
+        return new Rect(
+                mRecyclerView.getPaddingLeft(),
+                mRecyclerView.getPaddingTop(),
+                mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(),
+                mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom()
+        );
+    }
+
+    public void removeRecyclerView() throws Throwable {
+        if (mRecyclerView == null) {
+            return;
+        }
+        if (!isMainThread()) {
+            getInstrumentation().waitForIdleSync();
+        }
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    // do not run validation if we already have an error
+                    if (mMainThreadException == null) {
+                        final RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
+                        if (adapter instanceof AttachDetachCountingAdapter) {
+                            ((AttachDetachCountingAdapter) adapter).getCounter()
+                                    .validateRemaining(mRecyclerView);
+                        }
+                    }
+                    getActivity().getContainer().removeAllViews();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        });
+        mRecyclerView = null;
+    }
+
+    void waitForAnimations(int seconds) throws Throwable {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.mItemAnimator
+                        .isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
+                            @Override
+                            public void onAnimationsFinished() {
+                                latch.countDown();
+                            }
+                        });
+            }
+        });
+
+        assertTrue("animations didn't finish on expected time of " + seconds + " seconds",
+                latch.await(seconds, TimeUnit.SECONDS));
+    }
+
+    public void waitForIdleScroll(final RecyclerView recyclerView) throws Throwable {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                RecyclerView.OnScrollListener listener = new RecyclerView.OnScrollListener() {
+                    @Override
+                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                        if (newState == SCROLL_STATE_IDLE) {
+                            latch.countDown();
+                            recyclerView.removeOnScrollListener(this);
+                        }
+                    }
+                };
+                if (recyclerView.getScrollState() == SCROLL_STATE_IDLE) {
+                    latch.countDown();
+                } else {
+                    recyclerView.addOnScrollListener(listener);
+                }
+            }
+        });
+        assertTrue("should go idle in 10 seconds", latch.await(10, TimeUnit.SECONDS));
+    }
+
+    public boolean requestFocus(final View view, boolean waitForScroll) throws Throwable {
+        final boolean[] result = new boolean[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = view.requestFocus();
+            }
+        });
+        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return view.hasFocus();
+            }
+        });
+        if (waitForScroll && result[0]) {
+            waitForIdleScroll(mRecyclerView);
+        }
+        return result[0];
+    }
+
+    public void setRecyclerView(final RecyclerView recyclerView) throws Throwable {
+        setRecyclerView(recyclerView, true);
+    }
+    public void setRecyclerView(final RecyclerView recyclerView, boolean assignDummyPool)
+            throws Throwable {
+        setRecyclerView(recyclerView, assignDummyPool, true);
+    }
+    public void setRecyclerView(final RecyclerView recyclerView, boolean assignDummyPool,
+            boolean addPositionCheckItemAnimator)
+            throws Throwable {
+        mRecyclerView = recyclerView;
+        if (assignDummyPool) {
+            RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool() {
+                @Override
+                public RecyclerView.ViewHolder getRecycledView(int viewType) {
+                    RecyclerView.ViewHolder viewHolder = super.getRecycledView(viewType);
+                    if (viewHolder == null) {
+                        return null;
+                    }
+                    viewHolder.addFlags(RecyclerView.ViewHolder.FLAG_BOUND);
+                    viewHolder.mPosition = 200;
+                    viewHolder.mOldPosition = 300;
+                    viewHolder.mPreLayoutPosition = 500;
+                    return viewHolder;
+                }
+
+                @Override
+                public void putRecycledView(RecyclerView.ViewHolder scrap) {
+                    assertNull(scrap.mOwnerRecyclerView);
+                    super.putRecycledView(scrap);
+                }
+            };
+            mRecyclerView.setRecycledViewPool(pool);
+        }
+        if (addPositionCheckItemAnimator) {
+            mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
+                @Override
+                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                        RecyclerView.State state) {
+                    RecyclerView.ViewHolder vh = parent.getChildViewHolder(view);
+                    if (!vh.isRemoved()) {
+                        assertNotSame("If getItemOffsets is called, child should have a valid"
+                                        + " adapter position unless it is removed : " + vh,
+                                vh.getAdapterPosition(), RecyclerView.NO_POSITION);
+                    }
+                }
+            });
+        }
+        mAdapterHelper = recyclerView.mAdapterHelper;
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().addView(recyclerView);
+            }
+        });
+    }
+
+    protected FrameLayout getRecyclerViewContainer() {
+        return getActivity().getContainer();
+    }
+
+    protected void requestLayoutOnUIThread(final View view) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                view.requestLayout();
+            }
+        });
+    }
+
+    protected void scrollBy(final int dt) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mRecyclerView.getLayoutManager().canScrollHorizontally()) {
+                    mRecyclerView.scrollBy(dt, 0);
+                } else {
+                    mRecyclerView.scrollBy(0, dt);
+                }
+
+            }
+        });
+    }
+
+    protected void smoothScrollBy(final int dt) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mRecyclerView.getLayoutManager().canScrollHorizontally()) {
+                    mRecyclerView.smoothScrollBy(dt, 0);
+                } else {
+                    mRecyclerView.smoothScrollBy(0, dt);
+                }
+
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+    }
+
+    void scrollToPosition(final int position) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.getLayoutManager().scrollToPosition(position);
+            }
+        });
+    }
+
+    void smoothScrollToPosition(final int position) throws Throwable {
+        smoothScrollToPosition(position, true);
+    }
+
+    void smoothScrollToPosition(final int position, boolean assertArrival) throws Throwable {
+        if (mDebug) {
+            Log.d(TAG, "SMOOTH scrolling to " + position);
+        }
+        final CountDownLatch viewAdded = new CountDownLatch(1);
+        final RecyclerView.OnChildAttachStateChangeListener listener =
+                new RecyclerView.OnChildAttachStateChangeListener() {
+                    @Override
+                    public void onChildViewAttachedToWindow(@NonNull View view) {
+                        if (position == mRecyclerView.getChildAdapterPosition(view)) {
+                            viewAdded.countDown();
+                        }
+                    }
+                    @Override
+                    public void onChildViewDetachedFromWindow(@NonNull View view) {
+                    }
+                };
+        final AtomicBoolean addedListener = new AtomicBoolean(false);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                RecyclerView.ViewHolder viewHolderForAdapterPosition =
+                        mRecyclerView.findViewHolderForAdapterPosition(position);
+                if (viewHolderForAdapterPosition != null) {
+                    viewAdded.countDown();
+                } else {
+                    mRecyclerView.addOnChildAttachStateChangeListener(listener);
+                    addedListener.set(true);
+                }
+
+            }
+        });
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.smoothScrollToPosition(position);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        assertThat("should be able to scroll in 10 seconds", !assertArrival ||
+                        viewAdded.await(10, TimeUnit.SECONDS),
+                CoreMatchers.is(true));
+        waitForIdleScroll(mRecyclerView);
+        if (mDebug) {
+            Log.d(TAG, "SMOOTH scrolling done");
+        }
+        if (addedListener.get()) {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    mRecyclerView.removeOnChildAttachStateChangeListener(listener);
+                }
+            });
+        }
+        getInstrumentation().waitForIdleSync();
+    }
+
+    void freezeLayout(final boolean freeze) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setLayoutFrozen(freeze);
+            }
+        });
+    }
+
+    public void setVisibility(final View view, final int visibility) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                view.setVisibility(visibility);
+            }
+        });
+    }
+
+    public class TestViewHolder extends RecyclerView.ViewHolder {
+
+        Item mBoundItem;
+        Object mData;
+
+        public TestViewHolder(View itemView) {
+            super(itemView);
+            itemView.setFocusable(true);
+        }
+
+        @Override
+        public String toString() {
+            return super.toString() + " item:" + mBoundItem + ", data:" + mData;
+        }
+
+        public Object getData() {
+            return mData;
+        }
+
+        public void setData(Object data) {
+            mData = data;
+        }
+    }
+    class DumbLayoutManager extends TestLayoutManager {
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            detachAndScrapAttachedViews(recycler);
+            layoutRange(recycler, 0, state.getItemCount());
+            if (layoutLatch != null) {
+                layoutLatch.countDown();
+            }
+        }
+    }
+
+    public class TestLayoutManager extends RecyclerView.LayoutManager {
+        int mScrollVerticallyAmount;
+        int mScrollHorizontallyAmount;
+        protected CountDownLatch layoutLatch;
+        private boolean mSupportsPredictive = false;
+
+        public void expectLayouts(int count) {
+            layoutLatch = new CountDownLatch(count);
+        }
+
+        public void waitForLayout(int seconds) throws Throwable {
+            layoutLatch.await(seconds * (mDebug ? 1000 : 1), SECONDS);
+            checkForMainThreadException();
+            MatcherAssert.assertThat("all layouts should complete on time",
+                    layoutLatch.getCount(), CoreMatchers.is(0L));
+            // use a runnable to ensure RV layout is finished
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+
+        public boolean isSupportsPredictive() {
+            return mSupportsPredictive;
+        }
+
+        public void setSupportsPredictive(boolean supportsPredictive) {
+            mSupportsPredictive = supportsPredictive;
+        }
+
+        @Override
+        public boolean supportsPredictiveItemAnimations() {
+            return mSupportsPredictive;
+        }
+
+        public void assertLayoutCount(int count, String msg, long timeout) throws Throwable {
+            layoutLatch.await(timeout, TimeUnit.SECONDS);
+            assertEquals(msg, count, layoutLatch.getCount());
+        }
+
+        public void assertNoLayout(String msg, long timeout) throws Throwable {
+            layoutLatch.await(timeout, TimeUnit.SECONDS);
+            assertFalse(msg, layoutLatch.getCount() == 0);
+        }
+
+        @Override
+        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        void assertVisibleItemPositions() {
+            int i = getChildCount();
+            TestAdapter testAdapter = (TestAdapter) mRecyclerView.getAdapter();
+            while (i-- > 0) {
+                View view = getChildAt(i);
+                RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
+                Item item = ((TestViewHolder) lp.mViewHolder).mBoundItem;
+                if (mDebug) {
+                    Log.d(TAG, "testing item " + i);
+                }
+                if (!lp.isItemRemoved()) {
+                    RecyclerView.ViewHolder vh = mRecyclerView.getChildViewHolder(view);
+                    assertSame("item position in LP should match adapter value :" + vh,
+                            testAdapter.mItems.get(vh.mPosition), item);
+                }
+            }
+        }
+
+        RecyclerView.LayoutParams getLp(View v) {
+            return (RecyclerView.LayoutParams) v.getLayoutParams();
+        }
+
+        protected void layoutRange(RecyclerView.Recycler recycler, int start, int end) {
+            assertScrap(recycler);
+            if (mDebug) {
+                Log.d(TAG, "will layout items from " + start + " to " + end);
+            }
+            int diff = end > start ? 1 : -1;
+            int top = 0;
+            for (int i = start; i != end; i+=diff) {
+                if (mDebug) {
+                    Log.d(TAG, "laying out item " + i);
+                }
+                View view = recycler.getViewForPosition(i);
+                assertNotNull("view should not be null for valid position. "
+                        + "got null view at position " + i, view);
+                if (!mRecyclerView.mState.isPreLayout()) {
+                    RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view
+                            .getLayoutParams();
+                    assertFalse("In post layout, getViewForPosition should never return a view "
+                            + "that is removed", layoutParams != null
+                            && layoutParams.isItemRemoved());
+
+                }
+                assertEquals("getViewForPosition should return correct position",
+                        i, getPosition(view));
+                addView(view);
+                measureChildWithMargins(view, 0, 0);
+                if (getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL) {
+                    layoutDecorated(view, getWidth() - getDecoratedMeasuredWidth(view), top,
+                            getWidth(), top + getDecoratedMeasuredHeight(view));
+                } else {
+                    layoutDecorated(view, 0, top, getDecoratedMeasuredWidth(view)
+                            , top + getDecoratedMeasuredHeight(view));
+                }
+
+                top += view.getMeasuredHeight();
+            }
+        }
+
+        private void assertScrap(RecyclerView.Recycler recycler) {
+            if (mRecyclerView.getAdapter() != null &&
+                    !mRecyclerView.getAdapter().hasStableIds()) {
+                for (RecyclerView.ViewHolder viewHolder : recycler.getScrapList()) {
+                    assertFalse("Invalid scrap should be no kept", viewHolder.isInvalid());
+                }
+            }
+        }
+
+        @Override
+        public boolean canScrollHorizontally() {
+            return true;
+        }
+
+        @Override
+        public boolean canScrollVertically() {
+            return true;
+        }
+
+        @Override
+        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            mScrollHorizontallyAmount += dx;
+            return dx;
+        }
+
+        @Override
+        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            mScrollVerticallyAmount += dy;
+            return dy;
+        }
+
+        // START MOCKITO OVERRIDES
+        // We override package protected methods to make them public. This is necessary to run
+        // mockito on Kitkat
+        @Override
+        public void setRecyclerView(RecyclerView recyclerView) {
+            super.setRecyclerView(recyclerView);
+        }
+
+        @Override
+        public void dispatchAttachedToWindow(RecyclerView view) {
+            super.dispatchAttachedToWindow(view);
+        }
+
+        @Override
+        public void dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+            super.dispatchDetachedFromWindow(view, recycler);
+        }
+
+        @Override
+        public void setExactMeasureSpecsFrom(RecyclerView recyclerView) {
+            super.setExactMeasureSpecsFrom(recyclerView);
+        }
+
+        @Override
+        public void setMeasureSpecs(int wSpec, int hSpec) {
+            super.setMeasureSpecs(wSpec, hSpec);
+        }
+
+        @Override
+        public void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
+            super.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
+        }
+
+        @Override
+        public boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec,
+                RecyclerView.LayoutParams lp) {
+            return super.shouldReMeasureChild(child, widthSpec, heightSpec, lp);
+        }
+
+        @Override
+        public boolean shouldMeasureChild(View child, int widthSpec, int heightSpec,
+                RecyclerView.LayoutParams lp) {
+            return super.shouldMeasureChild(child, widthSpec, heightSpec, lp);
+        }
+
+        @Override
+        public void removeAndRecycleScrapInt(RecyclerView.Recycler recycler) {
+            super.removeAndRecycleScrapInt(recycler);
+        }
+
+        @Override
+        public void stopSmoothScroller() {
+            super.stopSmoothScroller();
+        }
+
+        // END MOCKITO OVERRIDES
+    }
+
+    static class Item {
+        final static AtomicInteger idCounter = new AtomicInteger(0);
+        final public int mId = idCounter.incrementAndGet();
+
+        int mAdapterIndex;
+
+        String mText;
+        int mType = 0;
+        boolean mFocusable;
+
+        Item(int adapterIndex, String text) {
+            mAdapterIndex = adapterIndex;
+            mText = text;
+            mFocusable = true;
+        }
+
+        public boolean isFocusable() {
+            return mFocusable;
+        }
+
+        public void setFocusable(boolean mFocusable) {
+            this.mFocusable = mFocusable;
+        }
+
+        @Override
+        public String toString() {
+            return "Item{" +
+                    "mId=" + mId +
+                    ", originalIndex=" + mAdapterIndex +
+                    ", text='" + mText + '\'' +
+                    '}';
+        }
+    }
+
+    public class FocusableAdapter extends RecyclerView.Adapter<TestViewHolder> {
+
+        private int mCount;
+
+        FocusableAdapter(int count) {
+            mCount = count;
+        }
+
+        @Override
+        public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            final TextView textView = new TextView(parent.getContext());
+            textView.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+            textView.setFocusable(true);
+            textView.setBackgroundResource(R.drawable.item_bg);
+            return new TestViewHolder(textView);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+            ((TextView) holder.itemView).setText("Item " + position);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mCount;
+        }
+    }
+
+    public class TestAdapter extends RecyclerView.Adapter<TestViewHolder>
+            implements AttachDetachCountingAdapter {
+
+        public static final String DEFAULT_ITEM_PREFIX = "Item ";
+
+        ViewAttachDetachCounter mAttachmentCounter = new ViewAttachDetachCounter();
+        List<Item> mItems;
+        final @Nullable RecyclerView.LayoutParams mLayoutParams;
+
+        public TestAdapter(int count) {
+            this(count, null);
+        }
+
+        public TestAdapter(int count, @Nullable RecyclerView.LayoutParams layoutParams) {
+            mItems = new ArrayList<Item>(count);
+            addItems(0, count, DEFAULT_ITEM_PREFIX);
+            mLayoutParams = layoutParams;
+        }
+
+        void addItems(int pos, int count, String prefix) {
+            for (int i = 0; i < count; i++, pos++) {
+                mItems.add(pos, new Item(pos, prefix));
+            }
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            return getItemAt(position).mType;
+        }
+
+        @Override
+        public void onViewAttachedToWindow(TestViewHolder holder) {
+            super.onViewAttachedToWindow(holder);
+            mAttachmentCounter.onViewAttached(holder);
+        }
+
+        @Override
+        public void onViewDetachedFromWindow(TestViewHolder holder) {
+            super.onViewDetachedFromWindow(holder);
+            mAttachmentCounter.onViewDetached(holder);
+        }
+
+        @Override
+        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+            super.onAttachedToRecyclerView(recyclerView);
+            mAttachmentCounter.onAttached(recyclerView);
+        }
+
+        @Override
+        public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
+            super.onDetachedFromRecyclerView(recyclerView);
+            mAttachmentCounter.onDetached(recyclerView);
+        }
+
+        @Override
+        public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                int viewType) {
+            TextView itemView = new TextView(parent.getContext());
+            itemView.setFocusableInTouchMode(true);
+            itemView.setFocusable(true);
+            return new TestViewHolder(itemView);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+            assertNotNull(holder.mOwnerRecyclerView);
+            assertEquals(position, holder.getAdapterPosition());
+            final Item item = mItems.get(position);
+            ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mId + ")");
+            holder.mBoundItem = item;
+            if (mLayoutParams != null) {
+                holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(mLayoutParams));
+            }
+        }
+
+        public Item getItemAt(int position) {
+            return mItems.get(position);
+        }
+
+        @Override
+        public void onViewRecycled(@NonNull TestViewHolder holder) {
+            super.onViewRecycled(holder);
+            final int adapterPosition = holder.getAdapterPosition();
+            final boolean shouldHavePosition = !holder.isRemoved() && holder.isBound() &&
+                    !holder.isAdapterPositionUnknown() && !holder.isInvalid();
+            String log = "Position check for " + holder.toString();
+            assertEquals(log, shouldHavePosition, adapterPosition != RecyclerView.NO_POSITION);
+            if (shouldHavePosition) {
+                assertTrue(log, mItems.size() > adapterPosition);
+                // TODO: fix b/36042615 getAdapterPosition() is wrong in
+                // consumePendingUpdatesInOnePass where it applies pending change to already
+                // modified position.
+                if (holder.mPreLayoutPosition == RecyclerView.NO_POSITION) {
+                    assertSame(log, holder.mBoundItem, mItems.get(adapterPosition));
+                }
+            }
+        }
+
+        public void deleteAndNotify(final int start, final int count) throws Throwable {
+            deleteAndNotify(new int[]{start, count});
+        }
+
+        /**
+         * Deletes items in the given ranges.
+         * <p>
+         * Note that each operation affects the one after so you should offset them properly.
+         * <p>
+         * For example, if adapter has 5 items (A,B,C,D,E), and then you call this method with
+         * <code>[1, 2],[2, 1]</code>, it will first delete items B,C and the new adapter will be
+         * A D E. Then it will delete 2,1 which means it will delete E.
+         */
+        public void deleteAndNotify(final int[]... startCountTuples) throws Throwable {
+            for (int[] tuple : startCountTuples) {
+                tuple[1] = -tuple[1];
+            }
+            mActivityRule.runOnUiThread(new AddRemoveRunnable(startCountTuples));
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return hasStableIds() ? mItems.get(position).mId : super.getItemId(position);
+        }
+
+        public void offsetOriginalIndices(int start, int offset) {
+            for (int i = start; i < mItems.size(); i++) {
+                mItems.get(i).mAdapterIndex += offset;
+            }
+        }
+
+        /**
+         * @param start inclusive
+         * @param end exclusive
+         * @param offset
+         */
+        public void offsetOriginalIndicesBetween(int start, int end, int offset) {
+            for (int i = start; i < end && i < mItems.size(); i++) {
+                mItems.get(i).mAdapterIndex += offset;
+            }
+        }
+
+        public void addAndNotify(final int count) throws Throwable {
+            assertEquals(0, mItems.size());
+            mActivityRule.runOnUiThread(
+                    new AddRemoveRunnable(DEFAULT_ITEM_PREFIX, new int[]{0, count}));
+        }
+
+        public void resetItemsTo(final List<Item> testItems) throws Throwable {
+            if (!mItems.isEmpty()) {
+                deleteAndNotify(0, mItems.size());
+            }
+            mItems = testItems;
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    notifyItemRangeInserted(0, testItems.size());
+                }
+            });
+        }
+
+        public void addAndNotify(final int start, final int count) throws Throwable {
+            addAndNotify(new int[]{start, count});
+        }
+
+        public void addAndNotify(final int[]... startCountTuples) throws Throwable {
+            mActivityRule.runOnUiThread(new AddRemoveRunnable(startCountTuples));
+        }
+
+        public void dispatchDataSetChanged() throws Throwable {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    notifyDataSetChanged();
+                }
+            });
+        }
+
+        public void changeAndNotify(final int start, final int count) throws Throwable {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    notifyItemRangeChanged(start, count);
+                }
+            });
+        }
+
+        public void changeAndNotifyWithPayload(final int start, final int count,
+                final Object payload) throws Throwable {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    notifyItemRangeChanged(start, count, payload);
+                }
+            });
+        }
+
+        public void changePositionsAndNotify(final int... positions) throws Throwable {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    for (int i = 0; i < positions.length; i += 1) {
+                        TestAdapter.super.notifyItemRangeChanged(positions[i], 1);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Similar to other methods but negative count means delete and position count means add.
+         * <p>
+         * For instance, calling this method with <code>[1,1], [2,-1]</code> it will first add an
+         * item to index 1, then remove an item from index 2 (updated index 2)
+         */
+        public void addDeleteAndNotify(final int[]... startCountTuples) throws Throwable {
+            mActivityRule.runOnUiThread(new AddRemoveRunnable(startCountTuples));
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItems.size();
+        }
+
+        /**
+         * Uses notifyDataSetChanged
+         */
+        public void moveItems(boolean notifyChange, int[]... fromToTuples) throws Throwable {
+            for (int i = 0; i < fromToTuples.length; i += 1) {
+                int[] tuple = fromToTuples[i];
+                moveItem(tuple[0], tuple[1], false);
+            }
+            if (notifyChange) {
+                dispatchDataSetChanged();
+            }
+        }
+
+        /**
+         * Uses notifyDataSetChanged
+         */
+        public void moveItem(final int from, final int to, final boolean notifyChange)
+                throws Throwable {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    moveInUIThread(from, to);
+                    if (notifyChange) {
+                        notifyDataSetChanged();
+                    }
+                }
+            });
+        }
+
+        /**
+         * Uses notifyItemMoved
+         */
+        public void moveAndNotify(final int from, final int to) throws Throwable {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    moveInUIThread(from, to);
+                    notifyItemMoved(from, to);
+                }
+            });
+        }
+
+        void changeAllItemsAndNotifyDataSetChanged(int count) {
+            assertEquals("clearOnUIThread called from a wrong thread",
+                    Looper.getMainLooper(), Looper.myLooper());
+            mItems = new ArrayList<>();
+            addItems(0, count, DEFAULT_ITEM_PREFIX);
+            notifyDataSetChanged();
+        }
+
+        public void clearOnUIThread() {
+            changeAllItemsAndNotifyDataSetChanged(0);
+        }
+
+        protected void moveInUIThread(int from, int to) {
+            Item item = mItems.remove(from);
+            offsetOriginalIndices(from, -1);
+            mItems.add(to, item);
+            offsetOriginalIndices(to + 1, 1);
+            item.mAdapterIndex = to;
+        }
+
+
+        @Override
+        public ViewAttachDetachCounter getCounter() {
+            return mAttachmentCounter;
+        }
+
+        private class AddRemoveRunnable implements Runnable {
+            final String mNewItemPrefix;
+            final int[][] mStartCountTuples;
+
+            public AddRemoveRunnable(String newItemPrefix, int[]... startCountTuples) {
+                mNewItemPrefix = newItemPrefix;
+                mStartCountTuples = startCountTuples;
+            }
+
+            public AddRemoveRunnable(int[][] startCountTuples) {
+                this("new item ", startCountTuples);
+            }
+
+            @Override
+            public void run() {
+                for (int[] tuple : mStartCountTuples) {
+                    if (tuple[1] < 0) {
+                        delete(tuple);
+                    } else {
+                        add(tuple);
+                    }
+                }
+            }
+
+            private void add(int[] tuple) {
+                // offset others
+                offsetOriginalIndices(tuple[0], tuple[1]);
+                addItems(tuple[0], tuple[1], mNewItemPrefix);
+                notifyItemRangeInserted(tuple[0], tuple[1]);
+            }
+
+            private void delete(int[] tuple) {
+                final int count = -tuple[1];
+                offsetOriginalIndices(tuple[0] + count, tuple[1]);
+                for (int i = 0; i < count; i++) {
+                    mItems.remove(tuple[0]);
+                }
+                notifyItemRangeRemoved(tuple[0], count);
+            }
+        }
+    }
+
+    public boolean isMainThread() {
+        return Looper.myLooper() == Looper.getMainLooper();
+    }
+
+    static class TargetTuple {
+
+        final int mPosition;
+
+        final int mLayoutDirection;
+
+        TargetTuple(int position, int layoutDirection) {
+            this.mPosition = position;
+            this.mLayoutDirection = layoutDirection;
+        }
+
+        @Override
+        public String toString() {
+            return "TargetTuple{" +
+                    "mPosition=" + mPosition +
+                    ", mLayoutDirection=" + mLayoutDirection +
+                    '}';
+        }
+    }
+
+    public interface AttachDetachCountingAdapter {
+
+        ViewAttachDetachCounter getCounter();
+    }
+
+    public class ViewAttachDetachCounter {
+
+        Set<RecyclerView.ViewHolder> mAttachedSet = new HashSet<RecyclerView.ViewHolder>();
+
+        public void validateRemaining(RecyclerView recyclerView) {
+            final int childCount = recyclerView.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View view = recyclerView.getChildAt(i);
+                RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
+                assertTrue("remaining view should be in attached set " + vh,
+                        mAttachedSet.contains(vh));
+            }
+            assertEquals("there should not be any views left in attached set",
+                    childCount, mAttachedSet.size());
+        }
+
+        public void onViewDetached(RecyclerView.ViewHolder viewHolder) {
+            try {
+                assertTrue("view holder should be in attached set",
+                        mAttachedSet.remove(viewHolder));
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+        }
+
+        public void onViewAttached(RecyclerView.ViewHolder viewHolder) {
+            try {
+                assertTrue("view holder should not be in attached set",
+                        mAttachedSet.add(viewHolder));
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+        }
+
+        public void onAttached(RecyclerView recyclerView) {
+            // when a new RV is attached, clear the set and add all view holders
+            mAttachedSet.clear();
+            final int childCount = recyclerView.getChildCount();
+            for (int i = 0; i < childCount; i ++) {
+                View view = recyclerView.getChildAt(i);
+                mAttachedSet.add(recyclerView.getChildViewHolder(view));
+            }
+        }
+
+        public void onDetached(RecyclerView recyclerView) {
+            validateRemaining(recyclerView);
+        }
+    }
+
+
+    public static View findFirstFullyVisibleChild(RecyclerView parent) {
+        for (int i = 0; i < parent.getChildCount(); i++) {
+            View child = parent.getChildAt(i);
+            if (isViewFullyInBound(parent, child)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    public static View findLastFullyVisibleChild(RecyclerView parent) {
+        for (int i = parent.getChildCount() - 1; i >= 0; i--) {
+            View child = parent.getChildAt(i);
+            if (isViewFullyInBound(parent, child)) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns whether a child of RecyclerView is partially in bound. A child is
+     * partially in-bounds if it's either fully or partially visible on the screen.
+     * @param parent The RecyclerView holding the child.
+     * @param child The child view to be checked whether is partially (or fully) within RV's bounds.
+     * @return True if the child view is partially (or fully) visible; false otherwise.
+     */
+    public static boolean isViewPartiallyInBound(RecyclerView parent, View child) {
+        if (child == null) {
+            return false;
+        }
+        final int parentLeft = parent.getPaddingLeft();
+        final int parentTop = parent.getPaddingTop();
+        final int parentRight = parent.getWidth() - parent.getPaddingRight();
+        final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
+
+        final int childLeft = child.getLeft() - child.getScrollX();
+        final int childTop = child.getTop() - child.getScrollY();
+        final int childRight = child.getRight() - child.getScrollX();
+        final int childBottom = child.getBottom() - child.getScrollY();
+
+        if (childLeft >= parentRight || childRight <= parentLeft
+                || childTop >= parentBottom || childBottom <= parentTop) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns whether a child of RecyclerView is fully in-bounds, that is it's fully visible
+     * on the screen.
+     * @param parent The RecyclerView holding the child.
+     * @param child The child view to be checked whether is fully within RV's bounds.
+     * @return True if the child view is fully visible; false otherwise.
+     */
+    public static boolean isViewFullyInBound(RecyclerView parent, View child) {
+        if (child == null) {
+            return false;
+        }
+        final int parentLeft = parent.getPaddingLeft();
+        final int parentTop = parent.getPaddingTop();
+        final int parentRight = parent.getWidth() - parent.getPaddingRight();
+        final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
+
+        final int childLeft = child.getLeft() - child.getScrollX();
+        final int childTop = child.getTop() - child.getScrollY();
+        final int childRight = child.getRight() - child.getScrollX();
+        final int childBottom = child.getBottom() - child.getScrollY();
+
+        if (childLeft >= parentLeft && childRight <= parentRight
+                && childTop >= parentTop && childBottom <= parentBottom) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
new file mode 100644
index 0000000..2aa8b8b
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
@@ -0,0 +1,928 @@
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LayoutState.LAYOUT_END;
+import static android.support.v7.widget.LayoutState.LAYOUT_START;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
+import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
+import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+abstract class BaseStaggeredGridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest {
+
+    protected static final boolean DEBUG = false;
+    protected static final int AVG_ITEM_PER_VIEW = 3;
+    protected static final String TAG = "SGLM_TEST";
+    volatile WrappedLayoutManager mLayoutManager;
+    GridTestAdapter mAdapter;
+
+    protected static List<Config> createBaseVariations() {
+        List<Config> variations = new ArrayList<>();
+        for (int orientation : new int[]{VERTICAL, HORIZONTAL}) {
+            for (boolean reverseLayout : new boolean[]{false, true}) {
+                for (int spanCount : new int[]{1, 3}) {
+                    for (int gapStrategy : new int[]{GAP_HANDLING_NONE,
+                            GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}) {
+                        for (boolean wrap : new boolean[]{true, false}) {
+                            variations.add(new Config(orientation, reverseLayout, spanCount,
+                                    gapStrategy).wrap(wrap));
+                        }
+
+                    }
+                }
+            }
+        }
+        return variations;
+    }
+
+    protected static List<Config> addConfigVariation(List<Config> base, String fieldName,
+            Object... variations)
+            throws CloneNotSupportedException, NoSuchFieldException, IllegalAccessException {
+        List<Config> newConfigs = new ArrayList<Config>();
+        Field field = Config.class.getDeclaredField(fieldName);
+        for (Config config : base) {
+            for (Object variation : variations) {
+                Config newConfig = (Config) config.clone();
+                field.set(newConfig, variation);
+                newConfigs.add(newConfig);
+            }
+        }
+        return newConfigs;
+    }
+
+    void setupByConfig(Config config) throws Throwable {
+        setupByConfig(config, new GridTestAdapter(config.mItemCount, config.mOrientation));
+    }
+
+    void setupByConfig(Config config, GridTestAdapter adapter) throws Throwable {
+        mAdapter = adapter;
+        mRecyclerView = new WrappedRecyclerView(getActivity());
+        mRecyclerView.setAdapter(mAdapter);
+        mRecyclerView.setHasFixedSize(true);
+        mLayoutManager = new WrappedLayoutManager(config.mSpanCount, config.mOrientation);
+        mLayoutManager.setGapStrategy(config.mGapStrategy);
+        mLayoutManager.setReverseLayout(config.mReverseLayout);
+        mRecyclerView.setLayoutManager(mLayoutManager);
+        mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
+            @Override
+            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                    RecyclerView.State state) {
+                try {
+                    StaggeredGridLayoutManager.LayoutParams
+                            lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
+                    assertNotNull("view should have layout params assigned", lp);
+                    assertNotNull("when item offsets are requested, view should have a valid span",
+                            lp.mSpan);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        });
+    }
+
+    StaggeredGridLayoutManager.LayoutParams getLp(View view) {
+        return (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
+    }
+
+    void waitFirstLayout() throws Throwable {
+        mLayoutManager.expectLayouts(1);
+        setRecyclerView(mRecyclerView);
+        mLayoutManager.waitForLayout(3);
+        getInstrumentation().waitForIdleSync();
+    }
+
+    /**
+     * enqueues an empty runnable to main thread so that we can be assured it did run
+     *
+     * @param count Number of times to run
+     */
+    protected void waitForMainThread(int count) throws Throwable {
+        final AtomicInteger i = new AtomicInteger(count);
+        while (i.get() > 0) {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    i.decrementAndGet();
+                }
+            });
+        }
+    }
+
+    public void assertRectSetsNotEqual(String message, Map<Item, Rect> before,
+            Map<Item, Rect> after) {
+        Throwable throwable = null;
+        try {
+            assertRectSetsEqual("NOT " + message, before, after);
+        } catch (Throwable t) {
+            throwable = t;
+        }
+        assertNotNull(message + " two layout should be different", throwable);
+    }
+
+    public void assertRectSetsEqual(String message, Map<Item, Rect> before, Map<Item, Rect> after) {
+        assertRectSetsEqual(message, before, after, true);
+    }
+
+    public void assertRectSetsEqual(String message, Map<Item, Rect> before, Map<Item, Rect> after,
+            boolean strictItemEquality) {
+        StringBuilder log = new StringBuilder();
+        if (DEBUG) {
+            log.append("checking rectangle equality.\n");
+            log.append("total space:" + mLayoutManager.mPrimaryOrientation.getTotalSpace());
+            log.append("before:");
+            for (Map.Entry<Item, Rect> entry : before.entrySet()) {
+                log.append("\n").append(entry.getKey().mAdapterIndex).append(":")
+                        .append(entry.getValue());
+            }
+            log.append("\nafter:");
+            for (Map.Entry<Item, Rect> entry : after.entrySet()) {
+                log.append("\n").append(entry.getKey().mAdapterIndex).append(":")
+                        .append(entry.getValue());
+            }
+            message += "\n\n" + log.toString();
+        }
+        assertEquals(message + ": item counts should be equal", before.size()
+                , after.size());
+        for (Map.Entry<Item, Rect> entry : before.entrySet()) {
+            final Item beforeItem = entry.getKey();
+            Rect afterRect = null;
+            if (strictItemEquality) {
+                afterRect = after.get(beforeItem);
+                assertNotNull(message + ": Same item should be visible after simple re-layout",
+                        afterRect);
+            } else {
+                for (Map.Entry<Item, Rect> afterEntry : after.entrySet()) {
+                    final Item afterItem = afterEntry.getKey();
+                    if (afterItem.mAdapterIndex == beforeItem.mAdapterIndex) {
+                        afterRect = afterEntry.getValue();
+                        break;
+                    }
+                }
+                assertNotNull(message + ": Item with same adapter index should be visible " +
+                                "after simple re-layout",
+                        afterRect);
+            }
+            assertEquals(message + ": Item should be laid out at the same coordinates",
+                    entry.getValue(),
+                    afterRect);
+        }
+    }
+
+    protected void assertViewPositions(Config config) {
+        ArrayList<ArrayList<View>> viewsBySpan = mLayoutManager.collectChildrenBySpan();
+        OrientationHelper orientationHelper = OrientationHelper
+                .createOrientationHelper(mLayoutManager, config.mOrientation);
+        for (ArrayList<View> span : viewsBySpan) {
+            // validate all children's order. first child should have min start mPosition
+            final int count = span.size();
+            for (int i = 0, j = 1; j < count; i++, j++) {
+                View prev = span.get(i);
+                View next = span.get(j);
+                assertTrue(config + " prev item should be above next item",
+                        orientationHelper.getDecoratedEnd(prev) <= orientationHelper
+                                .getDecoratedStart(next)
+                );
+
+            }
+        }
+    }
+
+    protected TargetTuple findInvisibleTarget(Config config) {
+        int minPosition = Integer.MAX_VALUE, maxPosition = Integer.MIN_VALUE;
+        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
+            View child = mLayoutManager.getChildAt(i);
+            int position = mRecyclerView.getChildLayoutPosition(child);
+            if (position < minPosition) {
+                minPosition = position;
+            }
+            if (position > maxPosition) {
+                maxPosition = position;
+            }
+        }
+        final int tailTarget = maxPosition + (mAdapter.getItemCount() - maxPosition) / 2;
+        final int headTarget = minPosition / 2;
+        final int target;
+        // where will the child come from ?
+        final int itemLayoutDirection;
+        if (Math.abs(tailTarget - maxPosition) > Math.abs(headTarget - minPosition)) {
+            target = tailTarget;
+            itemLayoutDirection = config.mReverseLayout ? LAYOUT_START : LAYOUT_END;
+        } else {
+            target = headTarget;
+            itemLayoutDirection = config.mReverseLayout ? LAYOUT_END : LAYOUT_START;
+        }
+        if (DEBUG) {
+            Log.d(TAG,
+                    config + " target:" + target + " min:" + minPosition + ", max:" + maxPosition);
+        }
+        return new TargetTuple(target, itemLayoutDirection);
+    }
+
+    protected void scrollToPositionWithOffset(final int position, final int offset)
+            throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mLayoutManager.scrollToPositionWithOffset(position, offset);
+            }
+        });
+    }
+
+    static class OnLayoutListener {
+
+        void before(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        }
+
+        void after(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        }
+    }
+
+    static class VisibleChildren {
+
+        int[] firstVisiblePositions;
+
+        int[] firstFullyVisiblePositions;
+
+        int[] lastVisiblePositions;
+
+        int[] lastFullyVisiblePositions;
+
+        View findFirstPartialVisibleClosestToStart;
+        View findFirstPartialVisibleClosestToEnd;
+
+        VisibleChildren(int spanCount) {
+            firstFullyVisiblePositions = new int[spanCount];
+            firstVisiblePositions = new int[spanCount];
+            lastVisiblePositions = new int[spanCount];
+            lastFullyVisiblePositions = new int[spanCount];
+            for (int i = 0; i < spanCount; i++) {
+                firstFullyVisiblePositions[i] = RecyclerView.NO_POSITION;
+                firstVisiblePositions[i] = RecyclerView.NO_POSITION;
+                lastVisiblePositions[i] = RecyclerView.NO_POSITION;
+                lastFullyVisiblePositions[i] = RecyclerView.NO_POSITION;
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            VisibleChildren that = (VisibleChildren) o;
+
+            if (!Arrays.equals(firstFullyVisiblePositions, that.firstFullyVisiblePositions)) {
+                return false;
+            }
+            if (findFirstPartialVisibleClosestToStart
+                    != null ? !findFirstPartialVisibleClosestToStart
+                    .equals(that.findFirstPartialVisibleClosestToStart)
+                    : that.findFirstPartialVisibleClosestToStart != null) {
+                return false;
+            }
+            if (!Arrays.equals(firstVisiblePositions, that.firstVisiblePositions)) {
+                return false;
+            }
+            if (!Arrays.equals(lastFullyVisiblePositions, that.lastFullyVisiblePositions)) {
+                return false;
+            }
+            if (findFirstPartialVisibleClosestToEnd != null ? !findFirstPartialVisibleClosestToEnd
+                    .equals(that.findFirstPartialVisibleClosestToEnd)
+                    : that.findFirstPartialVisibleClosestToEnd
+                            != null) {
+                return false;
+            }
+            if (!Arrays.equals(lastVisiblePositions, that.lastVisiblePositions)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = Arrays.hashCode(firstVisiblePositions);
+            result = 31 * result + Arrays.hashCode(firstFullyVisiblePositions);
+            result = 31 * result + Arrays.hashCode(lastVisiblePositions);
+            result = 31 * result + Arrays.hashCode(lastFullyVisiblePositions);
+            result = 31 * result + (findFirstPartialVisibleClosestToStart != null
+                    ? findFirstPartialVisibleClosestToStart
+                    .hashCode() : 0);
+            result = 31 * result + (findFirstPartialVisibleClosestToEnd != null
+                    ? findFirstPartialVisibleClosestToEnd
+                    .hashCode()
+                    : 0);
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return "VisibleChildren{" +
+                    "firstVisiblePositions=" + Arrays.toString(firstVisiblePositions) +
+                    ", firstFullyVisiblePositions=" + Arrays.toString(firstFullyVisiblePositions) +
+                    ", lastVisiblePositions=" + Arrays.toString(lastVisiblePositions) +
+                    ", lastFullyVisiblePositions=" + Arrays.toString(lastFullyVisiblePositions) +
+                    ", findFirstPartialVisibleClosestToStart=" +
+                    viewToString(findFirstPartialVisibleClosestToStart) +
+                    ", findFirstPartialVisibleClosestToEnd=" +
+                    viewToString(findFirstPartialVisibleClosestToEnd) +
+                    '}';
+        }
+
+        private String viewToString(View view) {
+            if (view == null) {
+                return null;
+            }
+            ViewGroup.LayoutParams lp = view.getLayoutParams();
+            if (lp instanceof RecyclerView.LayoutParams == false) {
+                return System.identityHashCode(view) + "(?)";
+            }
+            RecyclerView.LayoutParams rvlp = (RecyclerView.LayoutParams) lp;
+            return System.identityHashCode(view) + "(" + rvlp.getViewAdapterPosition() + ")";
+        }
+    }
+
+    abstract static class OnBindCallback {
+
+        abstract void onBoundItem(TestViewHolder vh, int position);
+
+        boolean assignRandomSize() {
+            return true;
+        }
+
+        void onCreatedViewHolder(TestViewHolder vh) {
+        }
+    }
+
+    static class Config implements Cloneable {
+
+        static final int DEFAULT_ITEM_COUNT = 300;
+
+        int mOrientation = OrientationHelper.VERTICAL;
+
+        boolean mReverseLayout = false;
+
+        int mSpanCount = 3;
+
+        int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
+
+        int mItemCount = DEFAULT_ITEM_COUNT;
+
+        boolean mWrap = false;
+
+        Config(int orientation, boolean reverseLayout, int spanCount, int gapStrategy) {
+            mOrientation = orientation;
+            mReverseLayout = reverseLayout;
+            mSpanCount = spanCount;
+            mGapStrategy = gapStrategy;
+        }
+
+        public Config() {
+
+        }
+
+        Config orientation(int orientation) {
+            mOrientation = orientation;
+            return this;
+        }
+
+        Config reverseLayout(boolean reverseLayout) {
+            mReverseLayout = reverseLayout;
+            return this;
+        }
+
+        Config spanCount(int spanCount) {
+            mSpanCount = spanCount;
+            return this;
+        }
+
+        Config gapStrategy(int gapStrategy) {
+            mGapStrategy = gapStrategy;
+            return this;
+        }
+
+        public Config itemCount(int itemCount) {
+            mItemCount = itemCount;
+            return this;
+        }
+
+        public Config wrap(boolean wrap) {
+            mWrap = wrap;
+            return this;
+        }
+
+        @Override
+        public String toString() {
+            return "[CONFIG:"
+                    + "span:" + mSpanCount
+                    + ",orientation:" + (mOrientation == HORIZONTAL ? "horz," : "vert,")
+                    + ",reverse:" + (mReverseLayout ? "T" : "F")
+                    + ",itemCount:" + mItemCount
+                    + ",wrapContent:" + mWrap
+                    + ",gap_strategy:" + gapStrategyName(mGapStrategy);
+        }
+
+        protected static String gapStrategyName(int gapStrategy) {
+            switch (gapStrategy) {
+                case GAP_HANDLING_NONE:
+                    return "none";
+                case GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS:
+                    return "move_spans";
+            }
+            return "gap_strategy:unknown";
+        }
+
+        @Override
+        public Object clone() throws CloneNotSupportedException {
+            return super.clone();
+        }
+    }
+
+    class WrappedLayoutManager extends StaggeredGridLayoutManager {
+
+        CountDownLatch layoutLatch;
+        CountDownLatch prefetchLatch;
+        OnLayoutListener mOnLayoutListener;
+        // gradle does not yet let us customize manifest for tests which is necessary to test RTL.
+        // until bug is fixed, we'll fake it.
+        // public issue id: 57819
+        Boolean mFakeRTL;
+        CountDownLatch mSnapLatch;
+
+        @Override
+        boolean isLayoutRTL() {
+            return mFakeRTL == null ? super.isLayoutRTL() : mFakeRTL;
+        }
+
+        public void expectLayouts(int count) {
+            layoutLatch = new CountDownLatch(count);
+        }
+
+        public void waitForLayout(int seconds) throws Throwable {
+            layoutLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+            checkForMainThreadException();
+            MatcherAssert.assertThat("all layouts should complete on time",
+                    layoutLatch.getCount(), CoreMatchers.is(0L));
+            // use a runnable to ensure RV layout is finished
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+
+        public void expectPrefetch(int count) {
+            prefetchLatch = new CountDownLatch(count);
+        }
+
+        public void waitForPrefetch(int seconds) throws Throwable {
+            prefetchLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+            checkForMainThreadException();
+            MatcherAssert.assertThat("all prefetches should complete on time",
+                    prefetchLatch.getCount(), CoreMatchers.is(0L));
+            // use a runnable to ensure RV layout is finished
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+
+        public void expectIdleState(int count) {
+            mSnapLatch = new CountDownLatch(count);
+            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+                @Override
+                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                    super.onScrollStateChanged(recyclerView, newState);
+                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+                        mSnapLatch.countDown();
+                        if (mSnapLatch.getCount() == 0L) {
+                            mRecyclerView.removeOnScrollListener(this);
+                        }
+                    }
+                }
+            });
+        }
+
+        public void waitForSnap(int seconds) throws Throwable {
+            mSnapLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
+            checkForMainThreadException();
+            MatcherAssert.assertThat("all scrolling should complete on time",
+                    mSnapLatch.getCount(), CoreMatchers.is(0L));
+            // use a runnable to ensure RV layout is finished
+            getInstrumentation().runOnMainSync(new Runnable() {
+                @Override
+                public void run() {
+                }
+            });
+        }
+
+        public void assertNoLayout(String msg, long timeout) throws Throwable {
+            layoutLatch.await(timeout, TimeUnit.SECONDS);
+            assertFalse(msg, layoutLatch.getCount() == 0);
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            String before;
+            if (DEBUG) {
+                before = layoutToString("before");
+            } else {
+                before = "enable DEBUG";
+            }
+            try {
+                if (mOnLayoutListener != null) {
+                    mOnLayoutListener.before(recycler, state);
+                }
+                super.onLayoutChildren(recycler, state);
+                if (mOnLayoutListener != null) {
+                    mOnLayoutListener.after(recycler, state);
+                }
+                validateChildren(before);
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+
+            layoutLatch.countDown();
+        }
+
+        @Override
+        int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) {
+            try {
+                int result = super.scrollBy(dt, recycler, state);
+                validateChildren();
+                return result;
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+
+            return 0;
+        }
+
+        View findFirstVisibleItemClosestToCenter() {
+            final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
+            final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
+            final int boundsCenter = (boundsStart + boundsEnd) / 2;
+            final Rect childBounds = new Rect();
+            int minDist = Integer.MAX_VALUE;
+            View closestChild = null;
+            for (int i = getChildCount() - 1; i >= 0; i--) {
+                final View child = getChildAt(i);
+                childBounds.setEmpty();
+                getDecoratedBoundsWithMargins(child, childBounds);
+                int childCenter = canScrollHorizontally()
+                        ? childBounds.centerX() : childBounds.centerY();
+                int dist = Math.abs(boundsCenter - childCenter);
+                if (dist < minDist) {
+                    minDist = dist;
+                    closestChild = child;
+                }
+            }
+            return closestChild;
+        }
+
+        public WrappedLayoutManager(int spanCount, int orientation) {
+            super(spanCount, orientation);
+        }
+
+        ArrayList<ArrayList<View>> collectChildrenBySpan() {
+            ArrayList<ArrayList<View>> viewsBySpan = new ArrayList<ArrayList<View>>();
+            for (int i = 0; i < getSpanCount(); i++) {
+                viewsBySpan.add(new ArrayList<View>());
+            }
+            for (int i = 0; i < getChildCount(); i++) {
+                View view = getChildAt(i);
+                LayoutParams lp
+                        = (LayoutParams) view
+                        .getLayoutParams();
+                viewsBySpan.get(lp.mSpan.mIndex).add(view);
+            }
+            return viewsBySpan;
+        }
+
+        @Nullable
+        @Override
+        public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            View result = null;
+            try {
+                result = super.onFocusSearchFailed(focused, direction, recycler, state);
+                validateChildren();
+            } catch (Throwable t) {
+                postExceptionToInstrumentation(t);
+            }
+            return result;
+        }
+
+        Rect getViewBounds(View view) {
+            if (getOrientation() == HORIZONTAL) {
+                return new Rect(
+                        mPrimaryOrientation.getDecoratedStart(view),
+                        mSecondaryOrientation.getDecoratedStart(view),
+                        mPrimaryOrientation.getDecoratedEnd(view),
+                        mSecondaryOrientation.getDecoratedEnd(view));
+            } else {
+                return new Rect(
+                        mSecondaryOrientation.getDecoratedStart(view),
+                        mPrimaryOrientation.getDecoratedStart(view),
+                        mSecondaryOrientation.getDecoratedEnd(view),
+                        mPrimaryOrientation.getDecoratedEnd(view));
+            }
+        }
+
+        public String getBoundsLog() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("view bounds:[start:").append(mPrimaryOrientation.getStartAfterPadding())
+                    .append(",").append(" end").append(mPrimaryOrientation.getEndAfterPadding());
+            sb.append("\nchildren bounds\n");
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                sb.append("child (ind:").append(i).append(", pos:").append(getPosition(child))
+                        .append("[").append("start:").append(
+                        mPrimaryOrientation.getDecoratedStart(child)).append(", end:")
+                        .append(mPrimaryOrientation.getDecoratedEnd(child)).append("]\n");
+            }
+            return sb.toString();
+        }
+
+        public VisibleChildren traverseAndFindVisibleChildren() {
+            int childCount = getChildCount();
+            final VisibleChildren visibleChildren = new VisibleChildren(getSpanCount());
+            final int start = mPrimaryOrientation.getStartAfterPadding();
+            final int end = mPrimaryOrientation.getEndAfterPadding();
+            for (int i = 0; i < childCount; i++) {
+                View child = getChildAt(i);
+                final int childStart = mPrimaryOrientation.getDecoratedStart(child);
+                final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
+                final boolean fullyVisible = childStart >= start && childEnd <= end;
+                final boolean hidden = childEnd <= start || childStart >= end;
+                if (hidden) {
+                    continue;
+                }
+                final int position = getPosition(child);
+                final int span = getLp(child).getSpanIndex();
+                if (fullyVisible) {
+                    if (position < visibleChildren.firstFullyVisiblePositions[span] ||
+                            visibleChildren.firstFullyVisiblePositions[span]
+                                    == RecyclerView.NO_POSITION) {
+                        visibleChildren.firstFullyVisiblePositions[span] = position;
+                    }
+
+                    if (position > visibleChildren.lastFullyVisiblePositions[span]) {
+                        visibleChildren.lastFullyVisiblePositions[span] = position;
+                    }
+                }
+
+                if (position < visibleChildren.firstVisiblePositions[span] ||
+                        visibleChildren.firstVisiblePositions[span] == RecyclerView.NO_POSITION) {
+                    visibleChildren.firstVisiblePositions[span] = position;
+                }
+
+                if (position > visibleChildren.lastVisiblePositions[span]) {
+                    visibleChildren.lastVisiblePositions[span] = position;
+                }
+                if (visibleChildren.findFirstPartialVisibleClosestToStart == null) {
+                    visibleChildren.findFirstPartialVisibleClosestToStart = child;
+                }
+                visibleChildren.findFirstPartialVisibleClosestToEnd = child;
+            }
+            return visibleChildren;
+        }
+
+        Map<Item, Rect> collectChildCoordinates() throws Throwable {
+            final Map<Item, Rect> items = new LinkedHashMap<Item, Rect>();
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    final int start = mPrimaryOrientation.getStartAfterPadding();
+                    final int end = mPrimaryOrientation.getEndAfterPadding();
+                    final int childCount = getChildCount();
+                    for (int i = 0; i < childCount; i++) {
+                        View child = getChildAt(i);
+                        // ignore child if it fits the recycling constraints
+                        if (mPrimaryOrientation.getDecoratedStart(child) >= end
+                                || mPrimaryOrientation.getDecoratedEnd(child) < start) {
+                            continue;
+                        }
+                        LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                        TestViewHolder vh = (TestViewHolder) lp.mViewHolder;
+                        items.put(vh.mBoundItem, getViewBounds(child));
+                    }
+                }
+            });
+            return items;
+        }
+
+
+        public void setFakeRtl(Boolean fakeRtl) {
+            mFakeRTL = fakeRtl;
+            try {
+                requestLayoutOnUIThread(mRecyclerView);
+            } catch (Throwable throwable) {
+                postExceptionToInstrumentation(throwable);
+            }
+        }
+
+        String layoutToString(String hint) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("LAYOUT POSITIONS AND INDICES ").append(hint).append("\n");
+            for (int i = 0; i < getChildCount(); i++) {
+                final View view = getChildAt(i);
+                final LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
+                sb.append(String.format("index: %d pos: %d top: %d bottom: %d span: %d isFull:%s",
+                        i, getPosition(view),
+                        mPrimaryOrientation.getDecoratedStart(view),
+                        mPrimaryOrientation.getDecoratedEnd(view),
+                        layoutParams.getSpanIndex(), layoutParams.isFullSpan())).append("\n");
+            }
+            return sb.toString();
+        }
+
+        protected void validateChildren() {
+            validateChildren(null);
+        }
+
+        private void validateChildren(String msg) {
+            if (getChildCount() == 0 || mRecyclerView.mState.isPreLayout()) {
+                return;
+            }
+            final int dir = mShouldReverseLayout ? -1 : 1;
+            int i = 0;
+            int pos = -1;
+            while (i < getChildCount()) {
+                LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+                if (lp.isItemRemoved()) {
+                    i++;
+                    continue;
+                }
+                pos = getPosition(getChildAt(i));
+                break;
+            }
+            if (pos == -1) {
+                return;
+            }
+            while (++i < getChildCount()) {
+                LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+                if (lp.isItemRemoved()) {
+                    continue;
+                }
+                pos += dir;
+                if (getPosition(getChildAt(i)) != pos) {
+                    throw new RuntimeException("INVALID POSITION FOR CHILD " + i + "\n" +
+                            layoutToString("ERROR") + "\n msg:" + msg);
+                }
+            }
+        }
+
+        @Override
+        public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
+                LayoutPrefetchRegistry layoutPrefetchRegistry) {
+            if (prefetchLatch != null) prefetchLatch.countDown();
+            super.collectAdjacentPrefetchPositions(dx, dy, state, layoutPrefetchRegistry);
+        }
+    }
+
+    class GridTestAdapter extends TestAdapter {
+
+        int mOrientation;
+        int mRecyclerViewWidth;
+        int mRecyclerViewHeight;
+        Integer mSizeReference = null;
+
+        // original ids of items that should be full span
+        HashSet<Integer> mFullSpanItems = new HashSet<Integer>();
+
+        protected boolean mViewsHaveEqualSize = false; // size in the scrollable direction
+
+        protected OnBindCallback mOnBindCallback;
+
+        GridTestAdapter(int count, int orientation) {
+            super(count);
+            mOrientation = orientation;
+        }
+
+        @NonNull
+        @Override
+        public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                int viewType) {
+            mRecyclerViewWidth = parent.getWidth();
+            mRecyclerViewHeight = parent.getHeight();
+            TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
+            if (mOnBindCallback != null) {
+                mOnBindCallback.onCreatedViewHolder(vh);
+            }
+            return vh;
+        }
+
+        @Override
+        public void offsetOriginalIndices(int start, int offset) {
+            if (mFullSpanItems.size() > 0) {
+                HashSet<Integer> old = mFullSpanItems;
+                mFullSpanItems = new HashSet<Integer>();
+                for (Integer i : old) {
+                    if (i < start) {
+                        mFullSpanItems.add(i);
+                    } else if (offset > 0 || (start + Math.abs(offset)) <= i) {
+                        mFullSpanItems.add(i + offset);
+                    } else if (DEBUG) {
+                        Log.d(TAG, "removed full span item " + i);
+                    }
+                }
+            }
+            super.offsetOriginalIndices(start, offset);
+        }
+
+        @Override
+        protected void moveInUIThread(int from, int to) {
+            boolean setAsFullSpanAgain = mFullSpanItems.contains(from);
+            super.moveInUIThread(from, to);
+            if (setAsFullSpanAgain) {
+                mFullSpanItems.add(to);
+            }
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull TestViewHolder holder,
+                int position) {
+            if (mSizeReference == null) {
+                mSizeReference = mOrientation == OrientationHelper.HORIZONTAL ? mRecyclerViewWidth
+                        / AVG_ITEM_PER_VIEW : mRecyclerViewHeight / AVG_ITEM_PER_VIEW;
+            }
+            super.onBindViewHolder(holder, position);
+
+            Item item = mItems.get(position);
+            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
+                    .getLayoutParams();
+            if (lp instanceof StaggeredGridLayoutManager.LayoutParams) {
+                ((StaggeredGridLayoutManager.LayoutParams) lp)
+                        .setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
+            } else {
+                StaggeredGridLayoutManager.LayoutParams slp
+                    = (StaggeredGridLayoutManager.LayoutParams) mLayoutManager
+                    .generateDefaultLayoutParams();
+                holder.itemView.setLayoutParams(slp);
+                slp.setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
+                lp = slp;
+            }
+
+            if (mOnBindCallback == null || mOnBindCallback.assignRandomSize()) {
+                final int minSize = mViewsHaveEqualSize ? mSizeReference :
+                        mSizeReference + 20 * (item.mId % 10);
+                if (mOrientation == OrientationHelper.HORIZONTAL) {
+                    holder.itemView.setMinimumWidth(minSize);
+                } else {
+                    holder.itemView.setMinimumHeight(minSize);
+                }
+                lp.topMargin = 3;
+                lp.leftMargin = 5;
+                lp.rightMargin = 7;
+                lp.bottomMargin = 9;
+            }
+            // Good to have colors for debugging
+            StateListDrawable stl = new StateListDrawable();
+            stl.addState(new int[]{android.R.attr.state_focused},
+                    new ColorDrawable(Color.RED));
+            stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+            //noinspection deprecation using this for kitkat tests
+            holder.itemView.setBackgroundDrawable(stl);
+            if (mOnBindCallback != null) {
+                mOnBindCallback.onBoundItem(holder, position);
+            }
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentTest.java
new file mode 100644
index 0000000..3cbe96f
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentTest.java
@@ -0,0 +1,557 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.widget;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.LongSparseArray;
+import android.support.v7.widget.TestedFrameLayout.FullControlLayoutParams;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.hamcrest.CoreMatchers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class to test any generic wrap content behavior.
+ * It does so by running the same view scenario twice. Once with match parent setup to record all
+ * dimensions and once with wrap_content setup. Then compares all child locations & ids +
+ * RecyclerView size.
+ */
+abstract public class BaseWrapContentTest extends BaseRecyclerViewInstrumentationTest {
+
+    static final boolean DEBUG = false;
+    static final String TAG = "WrapContentTest";
+    RecyclerView.LayoutManager mLayoutManager;
+
+    TestAdapter mTestAdapter;
+
+    LoggingItemAnimator mLoggingItemAnimator;
+
+    boolean mIsWrapContent;
+
+    protected final WrapContentConfig mWrapContentConfig;
+
+    public BaseWrapContentTest(WrapContentConfig config) {
+        mWrapContentConfig = config;
+    }
+
+    abstract RecyclerView.LayoutManager createLayoutManager();
+
+    void unspecifiedWithHintTest(boolean horizontal) throws Throwable {
+        final int itemHeight = 20;
+        final int itemWidth = 15;
+        RecyclerView.LayoutManager layoutManager = createLayoutManager();
+        WrappedRecyclerView rv = createRecyclerView(getActivity());
+        TestAdapter testAdapter = new TestAdapter(20) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                holder.itemView.setLayoutParams(new ViewGroup.LayoutParams(itemWidth, itemHeight));
+            }
+        };
+        rv.setLayoutManager(layoutManager);
+        rv.setAdapter(testAdapter);
+        TestedFrameLayout.FullControlLayoutParams lp =
+                new TestedFrameLayout.FullControlLayoutParams(0, 0);
+        if (horizontal) {
+            lp.wSpec = View.MeasureSpec.makeMeasureSpec(25, View.MeasureSpec.UNSPECIFIED);
+            lp.hSpec = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST);
+        } else {
+            lp.hSpec = View.MeasureSpec.makeMeasureSpec(25, View.MeasureSpec.UNSPECIFIED);
+            lp.wSpec = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST);
+        }
+        rv.setLayoutParams(lp);
+        setRecyclerView(rv);
+        rv.waitUntilLayout();
+
+        // we don't assert against the given size hint because LM will still ask for more if it
+        // lays out more children. This is the correct behavior because the spec is not AT_MOST,
+        // it is UNSPECIFIED.
+        if (horizontal) {
+            int expectedWidth = rv.getPaddingLeft() + rv.getPaddingRight() + itemWidth;
+            while (expectedWidth < 25) {
+                expectedWidth += itemWidth;
+            }
+            assertThat(rv.getWidth(), CoreMatchers.is(expectedWidth));
+        } else {
+            int expectedHeight = rv.getPaddingTop() + rv.getPaddingBottom() + itemHeight;
+            while (expectedHeight < 25) {
+                expectedHeight += itemHeight;
+            }
+            assertThat(rv.getHeight(), CoreMatchers.is(expectedHeight));
+        }
+    }
+
+    protected void testScenerio(Scenario scenario) throws Throwable {
+        FullControlLayoutParams matchParent = new FullControlLayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT);
+        FullControlLayoutParams wrapContent = new FullControlLayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        if (mWrapContentConfig.isUnlimitedHeight()) {
+            wrapContent.hSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+        }
+        if (mWrapContentConfig.isUnlimitedWidth()) {
+            wrapContent.wSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+        }
+
+        mIsWrapContent = false;
+        List<Snapshot> s1 = runScenario(scenario, matchParent, null);
+        mIsWrapContent = true;
+
+        List<Snapshot> s2 = runScenario(scenario, wrapContent, s1);
+        assertEquals("test sanity", s1.size(), s2.size());
+
+        for (int i = 0; i < s1.size(); i++) {
+            Snapshot step1 = s1.get(i);
+            Snapshot step2 = s2.get(i);
+            step1.assertSame(step2, i);
+        }
+    }
+
+    public List<Snapshot> runScenario(Scenario scenario, ViewGroup.LayoutParams lp,
+            @Nullable List<Snapshot> compareWith)
+            throws Throwable {
+        removeRecyclerView();
+        Item.idCounter.set(0);
+        List<Snapshot> result = new ArrayList<>();
+        RecyclerView.LayoutManager layoutManager = scenario.createLayoutManager();
+        WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity());
+        recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
+        recyclerView.setLayoutManager(layoutManager);
+        recyclerView.setLayoutParams(lp);
+        mLayoutManager = layoutManager;
+        mTestAdapter = new TestAdapter(scenario.getSeedAdapterSize());
+        recyclerView.setAdapter(mTestAdapter);
+        mLoggingItemAnimator = new LoggingItemAnimator();
+        recyclerView.setItemAnimator(mLoggingItemAnimator);
+        setRecyclerView(recyclerView);
+        recyclerView.waitUntilLayout();
+        int stepIndex = 0;
+        for (Step step : scenario.mStepList) {
+            mLoggingItemAnimator.reset();
+            step.onRun();
+            recyclerView.waitUntilLayout();
+            recyclerView.waitUntilAnimations();
+            Snapshot snapshot = takeSnapshot();
+            if (mIsWrapContent) {
+                snapshot.assertRvSize();
+            }
+            result.add(snapshot);
+            if (compareWith != null) {
+                compareWith.get(stepIndex).assertSame(snapshot, stepIndex);
+            }
+            stepIndex++;
+        }
+        recyclerView.waitUntilLayout();
+        recyclerView.waitUntilAnimations();
+        Snapshot snapshot = takeSnapshot();
+        if (mIsWrapContent) {
+            snapshot.assertRvSize();
+        }
+        result.add(snapshot);
+        if (compareWith != null) {
+            compareWith.get(stepIndex).assertSame(snapshot, stepIndex);
+        }
+        return result;
+    }
+
+    protected WrappedRecyclerView createRecyclerView(Activity activity) {
+        return new WrappedRecyclerView(getActivity());
+    }
+
+    void layoutAndCheck(TestedFrameLayout.FullControlLayoutParams lp,
+            BaseWrapContentWithAspectRatioTest.WrapContentAdapter adapter, Rect[] expected,
+            int width, int height) throws Throwable {
+        WrappedRecyclerView recyclerView = createRecyclerView(getActivity());
+        recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
+        recyclerView.setLayoutManager(createLayoutManager());
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutParams(lp);
+        Rect padding = mWrapContentConfig.padding;
+        recyclerView.setPadding(padding.left, padding.top, padding.right, padding.bottom);
+        setRecyclerView(recyclerView);
+        recyclerView.waitUntilLayout();
+        Snapshot snapshot = takeSnapshot();
+        int index = 0;
+        Rect tmp = new Rect();
+        for (BaseWrapContentWithAspectRatioTest.MeasureBehavior behavior : adapter.behaviors) {
+            tmp.set(expected[index]);
+            tmp.offset(padding.left, padding.top);
+            assertThat("behavior " + index, snapshot.mChildCoordinates.get(behavior.getId()),
+                    is(tmp));
+            index ++;
+        }
+        Rect boundingBox = new Rect(0, 0, 0, 0);
+        for (Rect rect : expected) {
+            boundingBox.union(rect);
+        }
+        assertThat(recyclerView.getWidth(), is(width + padding.left + padding.right));
+        assertThat(recyclerView.getHeight(), is(height + padding.top + padding.bottom));
+    }
+
+
+    abstract protected int getVerticalGravity(RecyclerView.LayoutManager layoutManager);
+
+    abstract protected int getHorizontalGravity(RecyclerView.LayoutManager layoutManager);
+
+    protected Snapshot takeSnapshot() throws Throwable {
+        Snapshot snapshot = new Snapshot(mRecyclerView, mLoggingItemAnimator,
+                getHorizontalGravity(mLayoutManager), getVerticalGravity(mLayoutManager));
+        return snapshot;
+    }
+
+    abstract class Scenario {
+
+        ArrayList<Step> mStepList = new ArrayList<>();
+
+        public Scenario(Step... steps) {
+            Collections.addAll(mStepList, steps);
+        }
+
+        public int getSeedAdapterSize() {
+            return 10;
+        }
+
+        public RecyclerView.LayoutManager createLayoutManager() {
+            return BaseWrapContentTest.this.createLayoutManager();
+        }
+    }
+
+    abstract static class Step {
+
+        abstract void onRun() throws Throwable;
+    }
+
+    class Snapshot {
+
+        Rect mRawChildrenBox = new Rect();
+
+        Rect mRvSize = new Rect();
+
+        Rect mRvPadding = new Rect();
+
+        Rect mRvParentSize = new Rect();
+
+        LongSparseArray<Rect> mChildCoordinates = new LongSparseArray<>();
+
+        LongSparseArray<String> mAppear = new LongSparseArray<>();
+
+        LongSparseArray<String> mDisappear = new LongSparseArray<>();
+
+        LongSparseArray<String> mPersistent = new LongSparseArray<>();
+
+        LongSparseArray<String> mChanged = new LongSparseArray<>();
+
+        int mVerticalGravity;
+
+        int mHorizontalGravity;
+
+        int mOffsetX, mOffsetY;// how much we should offset children
+
+        public Snapshot(RecyclerView recyclerView, LoggingItemAnimator loggingItemAnimator,
+                int horizontalGravity, int verticalGravity)
+                throws Throwable {
+            mRvSize = getViewBounds(recyclerView);
+            mRvParentSize = getViewBounds((View) recyclerView.getParent());
+            mRvPadding = new Rect(recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(),
+                    recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
+            mVerticalGravity = verticalGravity;
+            mHorizontalGravity = horizontalGravity;
+            if (mVerticalGravity == Gravity.TOP) {
+                mOffsetY = 0;
+            } else {
+                mOffsetY = mRvParentSize.bottom - mRvSize.bottom;
+            }
+
+            if (mHorizontalGravity == Gravity.LEFT) {
+                mOffsetX = 0;
+            } else {
+                mOffsetX = mRvParentSize.right - mRvSize.right;
+            }
+            collectChildCoordinates(recyclerView);
+            if (loggingItemAnimator != null) {
+                collectInto(mAppear, loggingItemAnimator.mAnimateAppearanceList);
+                collectInto(mDisappear, loggingItemAnimator.mAnimateDisappearanceList);
+                collectInto(mPersistent, loggingItemAnimator.mAnimatePersistenceList);
+                collectInto(mChanged, loggingItemAnimator.mAnimateChangeList);
+            }
+        }
+
+        public boolean doesChildrenFitVertically() {
+            return mRawChildrenBox.top >= mRvPadding.top
+                    && mRawChildrenBox.bottom <= mRvSize.bottom - mRvPadding.bottom;
+        }
+
+        public boolean doesChildrenFitHorizontally() {
+            return mRawChildrenBox.left >= mRvPadding.left
+                    && mRawChildrenBox.right <= mRvSize.right - mRvPadding.right;
+        }
+
+        public void assertSame(Snapshot other, int step) {
+            if (mWrapContentConfig.isUnlimitedHeight() &&
+                    (!doesChildrenFitVertically() || !other.doesChildrenFitVertically())) {
+                if (DEBUG) {
+                    Log.d(TAG, "cannot assert coordinates because it does not fit vertically");
+                }
+                return;
+            }
+            if (mWrapContentConfig.isUnlimitedWidth() &&
+                    (!doesChildrenFitHorizontally() || !other.doesChildrenFitHorizontally())) {
+                if (DEBUG) {
+                    Log.d(TAG, "cannot assert coordinates because it does not fit horizontally");
+                }
+                return;
+            }
+            assertMap("child coordinates. step:" + step, mChildCoordinates,
+                    other.mChildCoordinates);
+            if (mWrapContentConfig.isUnlimitedHeight() || mWrapContentConfig.isUnlimitedWidth()) {
+                return;//cannot assert animatinos in unlimited size
+            }
+            assertMap("appearing step:" + step, mAppear, other.mAppear);
+            assertMap("disappearing step:" + step, mDisappear, other.mDisappear);
+            assertMap("persistent step:" + step, mPersistent, other.mPersistent);
+            assertMap("changed step:" + step, mChanged, other.mChanged);
+        }
+
+        private void assertMap(String prefix, LongSparseArray<?> map1, LongSparseArray<?> map2) {
+            StringBuilder logBuilder = new StringBuilder();
+            logBuilder.append(prefix).append("\n");
+            logBuilder.append("map1").append("\n");
+            logInto(map1, logBuilder);
+            logBuilder.append("map2").append("\n");
+            logInto(map2, logBuilder);
+            final String log = logBuilder.toString();
+            assertEquals(log + " same size", map1.size(), map2.size());
+            for (int i = 0; i < map1.size(); i++) {
+                assertAtIndex(log, map1, map2, i);
+            }
+        }
+
+        private void assertAtIndex(String prefix, LongSparseArray<?> map1, LongSparseArray<?> map2,
+                int index) {
+            long key1 = map1.keyAt(index);
+            long key2 = map2.keyAt(index);
+            assertEquals(prefix + "key mismatch at index " + index, key1, key2);
+            Object value1 = map1.valueAt(index);
+            Object value2 = map2.valueAt(index);
+            assertEquals(prefix + " value mismatch at index " + index, value1, value2);
+        }
+
+        private void logInto(LongSparseArray<?> map, StringBuilder sb) {
+            for (int i = 0; i < map.size(); i++) {
+                long key = map.keyAt(i);
+                Object value = map.valueAt(i);
+                sb.append(key).append(" : ").append(value).append("\n");
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder("Snapshot{\n");
+            sb.append("child coordinates:\n");
+            logInto(mChildCoordinates, sb);
+            sb.append("appear animations:\n");
+            logInto(mAppear, sb);
+            sb.append("disappear animations:\n");
+            logInto(mDisappear, sb);
+            sb.append("change animations:\n");
+            logInto(mChanged, sb);
+            sb.append("persistent animations:\n");
+            logInto(mPersistent, sb);
+            sb.append("}");
+            return sb.toString();
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mChildCoordinates.hashCode();
+            result = 31 * result + mAppear.hashCode();
+            result = 31 * result + mDisappear.hashCode();
+            result = 31 * result + mPersistent.hashCode();
+            result = 31 * result + mChanged.hashCode();
+            return result;
+        }
+
+        private void collectInto(
+                LongSparseArray<String> target,
+                List<? extends BaseRecyclerViewAnimationsTest.AnimateLogBase> list) {
+            for (BaseRecyclerViewAnimationsTest.AnimateLogBase base : list) {
+                long id = getItemId(base.viewHolder);
+                assertNull(target.get(id));
+                target.put(id, log(base));
+            }
+        }
+
+        private String log(BaseRecyclerViewAnimationsTest.AnimateLogBase base) {
+            return base.getClass().getSimpleName() +
+                    ((TextView) base.viewHolder.itemView).getText() + ": " +
+                    "[pre:" + log(base.postInfo) +
+                    ", post:" + log(base.postInfo) + "]";
+        }
+
+        private String log(BaseRecyclerViewAnimationsTest.LoggingInfo postInfo) {
+            if (postInfo == null) {
+                return "?";
+            }
+            return "PI[flags: " + postInfo.changeFlags
+                    + ",l:" + (postInfo.left + mOffsetX)
+                    + ",t:" + (postInfo.top + mOffsetY)
+                    + ",r:" + (postInfo.right + mOffsetX)
+                    + ",b:" + (postInfo.bottom + mOffsetY) + "]";
+        }
+
+        void collectChildCoordinates(RecyclerView recyclerView) throws Throwable {
+            mRawChildrenBox = new Rect(0, 0, 0, 0);
+            final int childCount = recyclerView.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                View child = recyclerView.getChildAt(i);
+                Rect childBounds = getChildBounds(recyclerView, child, true);
+                mRawChildrenBox.union(getChildBounds(recyclerView, child, false));
+                RecyclerView.ViewHolder childViewHolder = recyclerView.getChildViewHolder(child);
+                mChildCoordinates.put(getItemId(childViewHolder), childBounds);
+            }
+        }
+
+        private Rect getViewBounds(View view) {
+            return new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+        }
+
+        private Rect getChildBounds(RecyclerView recyclerView, View child, boolean offset) {
+            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
+            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
+            Rect rect = new Rect(layoutManager.getDecoratedLeft(child) - lp.leftMargin,
+                    layoutManager.getDecoratedTop(child) - lp.topMargin,
+                    layoutManager.getDecoratedRight(child) + lp.rightMargin,
+                    layoutManager.getDecoratedBottom(child) + lp.bottomMargin);
+            if (offset) {
+                rect.offset(mOffsetX, mOffsetY);
+            }
+            return rect;
+        }
+
+        private long getItemId(RecyclerView.ViewHolder vh) {
+            if (vh instanceof TestViewHolder) {
+                return ((TestViewHolder) vh).mBoundItem.mId;
+            } else if (vh instanceof BaseWrapContentWithAspectRatioTest.WrapContentViewHolder) {
+                BaseWrapContentWithAspectRatioTest.WrapContentViewHolder casted =
+                        (BaseWrapContentWithAspectRatioTest.WrapContentViewHolder) vh;
+                return casted.mView.mBehavior.getId();
+            } else {
+                throw new IllegalArgumentException("i don't support any VH");
+            }
+        }
+
+        public void assertRvSize() {
+            if (shouldWrapContentHorizontally()) {
+                int expectedW = mRawChildrenBox.width() + mRvPadding.left + mRvPadding.right;
+                assertTrue(mRvSize.width() + " <= " + expectedW, mRvSize.width() <= expectedW);
+            }
+            if (shouldWrapContentVertically()) {
+                int expectedH = mRawChildrenBox.height() + mRvPadding.top + mRvPadding.bottom;
+                assertTrue(mRvSize.height() + "<=" + expectedH, mRvSize.height() <= expectedH);
+            }
+        }
+    }
+
+    protected boolean shouldWrapContentHorizontally() {
+        return true;
+    }
+
+    protected boolean shouldWrapContentVertically() {
+        return true;
+    }
+
+    static class WrapContentConfig {
+
+        public boolean unlimitedWidth;
+        public boolean unlimitedHeight;
+        public Rect padding = new Rect(0, 0, 0, 0);
+
+        public WrapContentConfig(boolean unlimitedWidth, boolean unlimitedHeight) {
+            this.unlimitedWidth = unlimitedWidth;
+            this.unlimitedHeight = unlimitedHeight;
+        }
+
+        public WrapContentConfig(boolean unlimitedWidth, boolean unlimitedHeight, Rect padding) {
+            this.unlimitedWidth = unlimitedWidth;
+            this.unlimitedHeight = unlimitedHeight;
+            this.padding.set(padding);
+        }
+
+        public boolean isUnlimitedWidth() {
+            return unlimitedWidth;
+        }
+
+        public WrapContentConfig setUnlimitedWidth(boolean unlimitedWidth) {
+            this.unlimitedWidth = unlimitedWidth;
+            return this;
+        }
+
+        public boolean isUnlimitedHeight() {
+            return unlimitedHeight;
+        }
+
+        public WrapContentConfig setUnlimitedHeight(boolean unlimitedHeight) {
+            this.unlimitedHeight = unlimitedHeight;
+            return this;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(32);
+            sb.append("Rect("); sb.append(padding.left); sb.append(",");
+            sb.append(padding.top); sb.append("-"); sb.append(padding.right);
+            sb.append(","); sb.append(padding.bottom); sb.append(")");
+            return "WrapContentConfig{"
+                    + "unlimitedWidth=" + unlimitedWidth
+                    + ",unlimitedHeight=" + unlimitedHeight
+                    + ",padding=" + sb.toString()
+                    + '}';
+        }
+
+        public TestedFrameLayout.FullControlLayoutParams toLayoutParams(int wDim, int hDim) {
+            TestedFrameLayout.FullControlLayoutParams
+                    lp = new TestedFrameLayout.FullControlLayoutParams(
+                    wDim, hDim);
+            if (unlimitedWidth) {
+                lp.wSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+            }
+            if (unlimitedHeight) {
+                lp.hSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+            }
+            return lp;
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java
new file mode 100644
index 0000000..0f2fbad
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.annotation.NonNull;
+import android.support.v4.util.Pair;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+abstract public class BaseWrapContentWithAspectRatioTest extends BaseRecyclerViewInstrumentationTest {
+    final BaseWrapContentTest.WrapContentConfig mWrapContentConfig;
+
+    protected BaseWrapContentWithAspectRatioTest(
+            BaseWrapContentTest.WrapContentConfig wrapContentConfig) {
+        mWrapContentConfig = wrapContentConfig;
+    }
+
+    int getSize(View view, int orientation) {
+        if (orientation == VERTICAL) {
+            return view.getHeight();
+        }
+        return view.getWidth();
+    }
+
+    static class LoggingView extends View {
+
+        MeasureBehavior mBehavior;
+
+        public void setBehavior(MeasureBehavior behavior) {
+            mBehavior = behavior;
+        }
+
+        public LoggingView(Context context) {
+            super(context);
+        }
+
+        public LoggingView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public LoggingView(Context context, AttributeSet attrs, int defStyleAttr) {
+            super(context, attrs, defStyleAttr);
+        }
+
+        public LoggingView(Context context, AttributeSet attrs, int defStyleAttr,
+                int defStyleRes) {
+            super(context, attrs, defStyleAttr, defStyleRes);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            mBehavior.onMeasure(this, widthMeasureSpec, heightMeasureSpec);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            super.onLayout(changed, left, top, right, bottom);
+            mBehavior.onLayout(changed, left, top, right, bottom);
+        }
+
+        public void setMeasured(int w, int h) {
+            setMeasuredDimension(w, h);
+        }
+
+        public void prepareLayoutParams() {
+            mBehavior.setLayoutParams(this);
+        }
+    }
+
+    static class AspectRatioMeasureBehavior extends MeasureBehavior {
+
+        Float ratio;
+        int control;
+
+        public AspectRatioMeasureBehavior(int desiredW, int desiredH, int wMode, int hMode) {
+            super(desiredW, desiredH, wMode, hMode);
+        }
+
+        public AspectRatioMeasureBehavior aspectRatio(int control, float ratio) {
+            this.control = control;
+            this.ratio = ratio;
+            return this;
+        }
+
+        @Override
+        public void onMeasure(LoggingView view, int wSpec,
+                int hSpec) {
+            super.onMeasure(view, wSpec, hSpec);
+            if (control == VERTICAL) {
+                view.setMeasured(getSecondary(view.getMeasuredHeight()),
+                        view.getMeasuredHeight());
+            } else if (control == HORIZONTAL) {
+                view.setMeasured(view.getMeasuredWidth(),
+                        getSecondary(view.getMeasuredWidth()));
+            }
+        }
+
+        public int getSecondary(int controlSize) {
+            return (int) (controlSize * ratio);
+        }
+    }
+
+    static class MeasureBehavior {
+        private static final AtomicLong idCounter = new AtomicLong(0);
+        public List<Pair<Integer, Integer>> measureSpecs = new ArrayList<>();
+        public List<Pair<Integer, Integer>> layouts = new ArrayList<>();
+        int desiredW, desiredH;
+        final long mId = idCounter.incrementAndGet();
+
+        ViewGroup.MarginLayoutParams layoutParams;
+
+        public MeasureBehavior(int desiredW, int desiredH, int wMode, int hMode) {
+            this.desiredW = desiredW;
+            this.desiredH = desiredH;
+            layoutParams = new ViewGroup.MarginLayoutParams(
+                    wMode, hMode
+            );
+        }
+
+        public MeasureBehavior withMargins(int left, int top, int right, int bottom) {
+            layoutParams.leftMargin = left;
+            layoutParams.topMargin = top;
+            layoutParams.rightMargin = right;
+            layoutParams.bottomMargin = bottom;
+            return this;
+        }
+
+        public long getId() {
+            return mId;
+        }
+
+        public void onMeasure(LoggingView view, int wSpec, int hSpec) {
+            measureSpecs.add(new Pair<>(wSpec, hSpec));
+            view.setMeasured(
+                    RecyclerView.LayoutManager.chooseSize(wSpec, desiredW, 0),
+                    RecyclerView.LayoutManager.chooseSize(hSpec, desiredH, 0));
+        }
+
+        public int getSpec(int position, int orientation) {
+            if (orientation == VERTICAL) {
+                return measureSpecs.get(position).second;
+            } else {
+                return measureSpecs.get(position).first;
+            }
+        }
+
+        public void setLayoutParams(LoggingView view) {
+            view.setLayoutParams(layoutParams);
+        }
+
+        public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            if (changed) {
+                layouts.add(new Pair<>(right - left, bottom - top));
+            }
+        }
+    }
+
+
+    static class WrapContentViewHolder extends RecyclerView.ViewHolder {
+
+        LoggingView mView;
+
+        public WrapContentViewHolder(ViewGroup parent) {
+            super(new LoggingView(parent.getContext()));
+            mView = (LoggingView) itemView;
+            mView.setBackgroundColor(Color.GREEN);
+        }
+    }
+
+    static class WrapContentAdapter extends RecyclerView.Adapter<WrapContentViewHolder> {
+
+        List<MeasureBehavior> behaviors = new ArrayList<>();
+
+        public WrapContentAdapter(MeasureBehavior... behaviors) {
+            Collections.addAll(this.behaviors, behaviors);
+        }
+
+        @Override
+        public WrapContentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new WrapContentViewHolder(parent);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull WrapContentViewHolder holder, int position) {
+            holder.mView.setBehavior(behaviors.get(position));
+            holder.mView.prepareLayoutParams();
+        }
+
+        @Override
+        public int getItemCount() {
+            return behaviors.size();
+        }
+    }
+
+    static class MeasureSpecMatcher extends BaseMatcher<Integer> {
+
+        private boolean checkSize = false;
+        private boolean checkMode = false;
+        private int mSize;
+        private int mMode;
+
+        public static MeasureSpecMatcher is(int size, int mode) {
+            MeasureSpecMatcher matcher = new MeasureSpecMatcher(size, mode);
+            matcher.checkSize = true;
+            matcher.checkMode = true;
+            return matcher;
+        }
+
+        public static MeasureSpecMatcher size(int size) {
+            MeasureSpecMatcher matcher = new MeasureSpecMatcher(size, 0);
+            matcher.checkSize = true;
+            matcher.checkMode = false;
+            return matcher;
+        }
+
+        public static MeasureSpecMatcher mode(int mode) {
+            MeasureSpecMatcher matcher = new MeasureSpecMatcher(0, mode);
+            matcher.checkSize = false;
+            matcher.checkMode = true;
+            return matcher;
+        }
+
+        private MeasureSpecMatcher(int size, int mode) {
+            mSize = size;
+            mMode = mode;
+
+        }
+
+        @Override
+        public boolean matches(Object item) {
+            if (item == null) {
+                return false;
+            }
+            Integer intValue = (Integer) item;
+            final int size = View.MeasureSpec.getSize(intValue);
+            final int mode = View.MeasureSpec.getMode(intValue);
+            if (checkSize && size != mSize) {
+                return false;
+            }
+            if (checkMode && mode != mMode) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public void describeMismatch(Object item, Description description) {
+            Integer intValue = (Integer) item;
+            final int size = View.MeasureSpec.getSize(intValue);
+            final int mode = View.MeasureSpec.getMode(intValue);
+            if (checkSize && size != mSize) {
+                description.appendText(" Expected size was ").appendValue(mSize)
+                        .appendText(" but received size is ").appendValue(size);
+            }
+            if (checkMode && mode != mMode) {
+                description.appendText(" Expected mode was ").appendValue(modeName(mMode))
+                        .appendText(" but received mode is ").appendValue(modeName(mode));
+            }
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            if (checkSize) {
+                description.appendText(" Measure spec size:").appendValue(mSize);
+            }
+            if (checkMode) {
+                description.appendText(" Measure spec mode:").appendValue(modeName(mMode));
+            }
+        }
+
+        private static String modeName(int mode) {
+            switch (mode) {
+                case View.MeasureSpec.AT_MOST:
+                    return "at most";
+                case View.MeasureSpec.EXACTLY:
+                    return "exactly";
+                default:
+                    return "unspecified";
+            }
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BucketTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BucketTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/BucketTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/BucketTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/CacheUtils.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/CacheUtils.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/CacheUtils.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/CacheUtils.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/ChildHelperTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/ChildHelperTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/ChildHelperTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/CustomEdgeEffectTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/CustomEdgeEffectTest.java
new file mode 100644
index 0000000..adc7125
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/CustomEdgeEffectTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+
+import static android.support.v7.widget.RecyclerView.EdgeEffectFactory;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.InputDeviceCompat;
+import android.support.v7.util.TouchUtils;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.EdgeEffect;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests custom edge effect are properly applied when scrolling.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class CustomEdgeEffectTest extends BaseRecyclerViewInstrumentationTest {
+
+    private static final int NUM_ITEMS = 10;
+
+    private LinearLayoutManager mLayoutManager;
+    private RecyclerView mRecyclerView;
+
+    @Before
+    public void setup() throws Throwable {
+        mLayoutManager = new LinearLayoutManager(getActivity());
+        mLayoutManager.ensureLayoutState();
+
+        mRecyclerView = new RecyclerView(getActivity());
+        mRecyclerView.setLayoutManager(mLayoutManager);
+        mRecyclerView.setAdapter(new TestAdapter(NUM_ITEMS) {
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                TestViewHolder holder = super.onCreateViewHolder(parent, viewType);
+                holder.itemView.setMinimumHeight(mRecyclerView.getMeasuredHeight() * 2 / NUM_ITEMS);
+                return holder;
+            }
+        });
+        setRecyclerView(mRecyclerView);
+        getInstrumentation().waitForIdleSync();
+        assertThat("Test sanity", mRecyclerView.getChildCount() > 0, is(true));
+    }
+
+    @Test
+    public void testEdgeEffectDirections() throws Throwable {
+        TestEdgeEffectFactory factory = new TestEdgeEffectFactory();
+        mRecyclerView.setEdgeEffectFactory(factory);
+        scrollToPosition(0);
+        waitForIdleScroll(mRecyclerView);
+        scrollViewBy(3);
+        assertNull(factory.mBottom);
+        assertNotNull(factory.mTop);
+        assertTrue(factory.mTop.mPullDistance > 0);
+
+        scrollToPosition(NUM_ITEMS - 1);
+        waitForIdleScroll(mRecyclerView);
+        scrollViewBy(-3);
+
+        assertNotNull(factory.mBottom);
+        assertTrue(factory.mBottom.mPullDistance > 0);
+    }
+
+    @Test
+    public void testEdgeEffectReplaced() throws Throwable {
+        TestEdgeEffectFactory factory1 = new TestEdgeEffectFactory();
+        mRecyclerView.setEdgeEffectFactory(factory1);
+        scrollToPosition(0);
+        waitForIdleScroll(mRecyclerView);
+
+        scrollViewBy(3);
+        assertNotNull(factory1.mTop);
+        float oldPullDistance = factory1.mTop.mPullDistance;
+
+        waitForIdleScroll(mRecyclerView);
+        TestEdgeEffectFactory factory2 = new TestEdgeEffectFactory();
+        mRecyclerView.setEdgeEffectFactory(factory2);
+        scrollViewBy(30);
+        assertNotNull(factory2.mTop);
+
+        assertTrue(factory2.mTop.mPullDistance > oldPullDistance);
+        assertEquals(oldPullDistance, factory1.mTop.mPullDistance, 0.1f);
+    }
+
+    private void scrollViewBy(final int value) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TouchUtils.scrollView(MotionEvent.AXIS_VSCROLL, value,
+                        InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView);
+            }
+        });
+    }
+
+    private class TestEdgeEffectFactory extends EdgeEffectFactory {
+
+        TestEdgeEffect mTop, mBottom;
+
+        @NonNull
+        @Override
+        protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
+            TestEdgeEffect effect = new TestEdgeEffect(view.getContext());
+            if (direction == EdgeEffectFactory.DIRECTION_TOP) {
+                mTop = effect;
+            } else if (direction == EdgeEffectFactory.DIRECTION_BOTTOM) {
+                mBottom = effect;
+            }
+            return effect;
+        }
+    }
+
+    private class TestEdgeEffect extends EdgeEffect {
+
+        private float mPullDistance;
+
+        TestEdgeEffect(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onPull(float deltaDistance, float displacement) {
+            onPull(deltaDistance);
+        }
+
+        @Override
+        public void onPull(float deltaDistance) {
+            mPullDistance = deltaDistance;
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DefaultItemAnimatorTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DefaultItemAnimatorTest.java
new file mode 100644
index 0000000..1ea1675
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DefaultItemAnimatorTest.java
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.support.annotation.NonNull;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class DefaultItemAnimatorTest extends BaseRecyclerViewInstrumentationTest {
+
+    private static final String TAG = "DefaultItemAnimatorTest";
+    Throwable mainThreadException;
+
+    DefaultItemAnimator mAnimator;
+    Adapter mAdapter;
+    ViewGroup mDummyParent;
+    List<RecyclerView.ViewHolder> mExpectedItems = new ArrayList<RecyclerView.ViewHolder>();
+
+    Set<RecyclerView.ViewHolder> mRemoveFinished = new HashSet<RecyclerView.ViewHolder>();
+    Set<RecyclerView.ViewHolder> mAddFinished = new HashSet<RecyclerView.ViewHolder>();
+    Set<RecyclerView.ViewHolder> mMoveFinished = new HashSet<RecyclerView.ViewHolder>();
+    Set<RecyclerView.ViewHolder> mChangeFinished = new HashSet<RecyclerView.ViewHolder>();
+
+    Semaphore mExpectedItemCount = new Semaphore(0);
+
+    @Before
+    public void setUp() throws Exception {
+        mAnimator = new DefaultItemAnimator() {
+            @Override
+            public void onRemoveFinished(RecyclerView.ViewHolder item) {
+                try {
+                    assertTrue(mRemoveFinished.add(item));
+                    onFinished(item);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+
+            @Override
+            public void onAddFinished(RecyclerView.ViewHolder item) {
+                try {
+                    assertTrue(mAddFinished.add(item));
+                    onFinished(item);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+
+            @Override
+            public void onMoveFinished(RecyclerView.ViewHolder item) {
+                try {
+                    assertTrue(mMoveFinished.add(item));
+                    onFinished(item);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+
+            @Override
+            public void onChangeFinished(RecyclerView.ViewHolder item, boolean oldItem) {
+                try {
+                    assertTrue(mChangeFinished.add(item));
+                    onFinished(item);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+
+            private void onFinished(RecyclerView.ViewHolder item) {
+                assertNotNull(mExpectedItems.remove(item));
+                mExpectedItemCount.release(1);
+            }
+        };
+        mAdapter = new Adapter(20);
+        mDummyParent = getActivity().getContainer();
+    }
+
+    @Override
+    void checkForMainThreadException() throws Throwable {
+        if (mainThreadException != null) {
+            throw mainThreadException;
+        }
+    }
+
+    @Test
+    public void reUseWithPayload() {
+        RecyclerView.ViewHolder vh = new ViewHolder(new TextView(getActivity()));
+        assertFalse(mAnimator.canReuseUpdatedViewHolder(vh, new ArrayList<>()));
+        assertTrue(mAnimator.canReuseUpdatedViewHolder(vh, Arrays.asList((Object) "a")));
+    }
+
+    void expectItems(RecyclerView.ViewHolder... viewHolders) {
+        mExpectedItems.addAll(Arrays.asList(viewHolders));
+    }
+
+    void runAndWait(int itemCount, int seconds) throws Throwable {
+        runAndWait(itemCount, seconds, null);
+    }
+
+    void runAndWait(int itemCount, int seconds, final ThrowingRunnable postRun) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAnimator.runPendingAnimations();
+                if (postRun != null) {
+                    try {
+                        postRun.run();
+                    } catch (Throwable e) {
+                        throw new RuntimeException(e);
+                    }
+                }
+            }
+        });
+        waitForItems(itemCount, seconds);
+        checkForMainThreadException();
+    }
+
+    void waitForItems(int itemCount, int seconds) throws InterruptedException {
+        assertTrue("all vh animations should end",
+                mExpectedItemCount.tryAcquire(itemCount, seconds, TimeUnit.SECONDS));
+        assertEquals("all expected finish events should happen", 0, mExpectedItems.size());
+        // wait one more second for unwanted
+        assertFalse("should not receive any more permits",
+                mExpectedItemCount.tryAcquire(1, 2, TimeUnit.SECONDS));
+    }
+
+    @Test
+    public void animateAdd() throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateAdd(vh));
+        assertTrue(mAnimator.isRunning());
+        runAndWait(1, 1);
+    }
+
+    @Test
+    public void animateRemove() throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateRemove(vh));
+        assertTrue(mAnimator.isRunning());
+        runAndWait(1, 1);
+    }
+
+    @Test
+    public void animateMove() throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateMove(vh, 0, 0, 100, 100));
+        assertTrue(mAnimator.isRunning());
+        runAndWait(1, 1);
+    }
+
+    @Test
+    public void animateChange() throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        ViewHolder vh2 = createViewHolder(2);
+        expectItems(vh, vh2);
+        assertTrue(animateChange(vh, vh2, 0, 0, 100, 100));
+        assertTrue(mAnimator.isRunning());
+        runAndWait(2, 1);
+    }
+
+    public void cancelBefore(int count, final RecyclerView.ViewHolder... toCancel)
+            throws Throwable {
+        cancelTest(true, count, toCancel);
+    }
+
+    public void cancelAfter(int count, final RecyclerView.ViewHolder... toCancel)
+            throws Throwable {
+        cancelTest(false, count, toCancel);
+    }
+
+    public void cancelTest(boolean before, int count, final RecyclerView.ViewHolder... toCancel) throws Throwable {
+        if (before) {
+            endAnimations(toCancel);
+            runAndWait(count, 1);
+        } else {
+            runAndWait(count, 1, new ThrowingRunnable() {
+                @Override
+                public void run() throws Throwable {
+                    endAnimations(toCancel);
+                }
+            });
+        }
+    }
+
+    @Test
+    public void cancelAddBefore() throws Throwable {
+        final ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateAdd(vh));
+        cancelBefore(1, vh);
+    }
+
+    @Test
+    public void cancelAddAfter() throws Throwable {
+        final ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateAdd(vh));
+        cancelAfter(1, vh);
+    }
+
+    @Test
+    public void cancelMoveBefore() throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateMove(vh, 10, 10, 100, 100));
+        cancelBefore(1, vh);
+    }
+
+    @Test
+    public void cancelMoveAfter() throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateMove(vh, 10, 10, 100, 100));
+        cancelAfter(1, vh);
+    }
+
+    @Test
+    public void cancelRemove() throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        expectItems(vh);
+        assertTrue(animateRemove(vh));
+        endAnimations(vh);
+        runAndWait(1, 1);
+    }
+
+    @Test
+    public void cancelChangeOldBefore() throws Throwable {
+        cancelChangeOldTest(true);
+    }
+    @Test
+    public void cancelChangeOldAfter() throws Throwable {
+        cancelChangeOldTest(false);
+    }
+
+    public void cancelChangeOldTest(boolean before) throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        ViewHolder vh2 = createViewHolder(1);
+        expectItems(vh, vh2);
+        assertTrue(animateChange(vh, vh2, 20, 20, 100, 100));
+        cancelTest(before, 2, vh);
+    }
+
+    @Test
+    public void cancelChangeNewBefore() throws Throwable {
+        cancelChangeNewTest(true);
+    }
+
+    @Test
+    public void cancelChangeNewAfter() throws Throwable {
+        cancelChangeNewTest(false);
+    }
+
+    public void cancelChangeNewTest(boolean before) throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        ViewHolder vh2 = createViewHolder(1);
+        expectItems(vh, vh2);
+        assertTrue(animateChange(vh, vh2, 20, 20, 100, 100));
+        cancelTest(before, 2, vh2);
+    }
+
+    @Test
+    public void cancelChangeBothBefore() throws Throwable {
+        cancelChangeBothTest(true);
+    }
+
+    @Test
+    public void cancelChangeBothAfter() throws Throwable {
+        cancelChangeBothTest(false);
+    }
+
+    public void cancelChangeBothTest(boolean before) throws Throwable {
+        ViewHolder vh = createViewHolder(1);
+        ViewHolder vh2 = createViewHolder(1);
+        expectItems(vh, vh2);
+        assertTrue(animateChange(vh, vh2, 20, 20, 100, 100));
+        cancelTest(before, 2, vh, vh2);
+    }
+
+    void endAnimations(final RecyclerView.ViewHolder... vhs) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (RecyclerView.ViewHolder vh : vhs) {
+                    mAnimator.endAnimation(vh);
+                }
+            }
+        });
+    }
+
+    boolean animateAdd(final RecyclerView.ViewHolder vh) throws Throwable {
+        final boolean[] result = new boolean[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = mAnimator.animateAdd(vh);
+            }
+        });
+        return result[0];
+    }
+
+    boolean animateRemove(final RecyclerView.ViewHolder vh) throws Throwable {
+        final boolean[] result = new boolean[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = mAnimator.animateRemove(vh);
+            }
+        });
+        return result[0];
+    }
+
+    boolean animateMove(final RecyclerView.ViewHolder vh, final int fromX, final int fromY,
+            final int toX, final int toY) throws Throwable {
+        final boolean[] result = new boolean[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = mAnimator.animateMove(vh, fromX, fromY, toX, toY);
+            }
+        });
+        return result[0];
+    }
+
+    boolean animateChange(final RecyclerView.ViewHolder oldHolder,
+            final RecyclerView.ViewHolder newHolder,
+            final int fromX, final int fromY, final int toX, final int toY) throws Throwable {
+        final boolean[] result = new boolean[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = mAnimator.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
+            }
+        });
+        return result[0];
+    }
+
+    private ViewHolder createViewHolder(final int pos) throws Throwable {
+        final ViewHolder vh = mAdapter.createViewHolder(mDummyParent, 1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAdapter.bindViewHolder(vh, pos);
+                mDummyParent.addView(vh.itemView);
+            }
+        });
+
+        return vh;
+    }
+
+    @Override
+    void postExceptionToInstrumentation(Throwable t) {
+        if (mainThreadException == null) {
+            mainThreadException = t;
+        } else {
+            Log.e(TAG, "skipping secondary main thread exception", t);
+        }
+    }
+
+
+    private class Adapter extends RecyclerView.Adapter<ViewHolder> {
+
+        List<String> mItems;
+
+        private Adapter(int count) {
+            mItems = new ArrayList<>();
+            for (int i = 0; i < count; i++) {
+                mItems.add("item-" + i);
+            }
+        }
+
+        @Override
+        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new ViewHolder(new TextView(parent.getContext()));
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+            holder.bind(mItems.get(position));
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItems.size();
+        }
+    }
+
+    private class ViewHolder extends RecyclerView.ViewHolder {
+
+        String mBindedText;
+
+        public ViewHolder(View itemView) {
+            super(itemView);
+        }
+
+        public void bind(String text) {
+            mBindedText = text;
+            ((TextView) itemView).setText(text);
+        }
+    }
+
+    private interface ThrowingRunnable {
+        void run() throws Throwable;
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultMeasureSpecTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DefaultMeasureSpecTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/DefaultMeasureSpecTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/DefaultMeasureSpecTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DividerItemDecorationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DividerItemDecorationTest.java
new file mode 100644
index 0000000..5effd32
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DividerItemDecorationTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.recyclerview.test.R;
+import android.view.ContextThemeWrapper;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link DividerItemDecoration}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DividerItemDecorationTest {
+    private static final String[] STRINGS = {"Foo", "Bar", "Great"};
+
+    @Test
+    public void testNullListDivider() {
+        final Context context = InstrumentationRegistry.getContext();
+        RecyclerView rv = new RecyclerView(context);
+        rv.setLayoutManager(new LinearLayoutManager(context));
+        rv.setAdapter(new MyAdapter(STRINGS));
+        DividerItemDecoration decoration = new DividerItemDecoration(
+                new ContextThemeWrapper(context, R.style.nullListDivider),
+                DividerItemDecoration.HORIZONTAL);
+        rv.addItemDecoration(decoration);
+        rv.layout(0, 0, 1000, 1000);
+        decoration.onDraw(new Canvas(), rv, null);
+    }
+
+    private static class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
+        private String[] mDataset;
+
+        public static class ViewHolder extends RecyclerView.ViewHolder {
+            TextView mTextView;
+            ViewHolder(TextView v) {
+                super(v);
+                mTextView = v;
+            }
+        }
+
+        MyAdapter(String[] myDataset) {
+            mDataset = myDataset;
+        }
+
+        @Override
+        public MyAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new ViewHolder(new TextView(parent.getContext()));
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+            holder.mTextView.setText(mDataset[position]);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mDataset.length;
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DummyItemAnimator.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/DummyItemAnimator.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/DummyItemAnimator.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/DummyItemAnimator.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/FocusSearchNavigationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/FocusSearchNavigationTest.java
new file mode 100644
index 0000000..c954811
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/FocusSearchNavigationTest.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+
+import static android.support.v7.widget.RecyclerView.HORIZONTAL;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static android.support.v7.widget.RecyclerView.VERTICAL;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.recyclerview.test.R;
+import android.support.v7.widget.test.RecyclerViewTestActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.LinearLayout;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Description;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This class tests RecyclerView focus search failure handling by using a real LayoutManager.
+ */
+@LargeTest
+@RunWith(Parameterized.class)
+public class FocusSearchNavigationTest {
+    @Rule
+    public ActivityTestRule<RecyclerViewTestActivity> mActivityRule =
+            new ActivityTestRule<>(RecyclerViewTestActivity.class);
+
+    private final int mOrientation;
+    private final int mLayoutDir;
+
+    public FocusSearchNavigationTest(int orientation, int layoutDir) {
+        mOrientation = orientation;
+        mLayoutDir = layoutDir;
+    }
+
+    @Parameterized.Parameters(name = "orientation:{0},layoutDir:{1}")
+    public static List<Object[]> params() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return Arrays.asList(
+                    new Object[]{VERTICAL, ViewCompat.LAYOUT_DIRECTION_LTR},
+                    new Object[]{HORIZONTAL, ViewCompat.LAYOUT_DIRECTION_LTR},
+                    new Object[]{HORIZONTAL, ViewCompat.LAYOUT_DIRECTION_RTL}
+            );
+        } else {
+            // Do not test RTL before API 17
+            return Arrays.asList(
+                    new Object[]{VERTICAL, ViewCompat.LAYOUT_DIRECTION_LTR},
+                    new Object[]{HORIZONTAL, ViewCompat.LAYOUT_DIRECTION_LTR}
+            );
+        }
+    }
+
+    private Activity mActivity;
+    private RecyclerView mRecyclerView;
+    private View mBefore;
+    private View mAfter;
+
+    private void setup(final int itemCount) throws Throwable {
+        mActivity = mActivityRule.getActivity();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mActivity.setContentView(R.layout.focus_search_activity);
+                ViewCompat.setLayoutDirection(mActivity.getWindow().getDecorView(), mLayoutDir);
+                LinearLayout linearLayout = (LinearLayout) mActivity.findViewById(R.id.root);
+                linearLayout.setOrientation(mOrientation);
+                mRecyclerView = (RecyclerView) mActivity.findViewById(R.id.recycler_view);
+                ViewCompat.setLayoutDirection(mRecyclerView, mLayoutDir);
+                LinearLayoutManager layout = new LinearLayoutManager(mActivity.getBaseContext());
+                layout.setOrientation(mOrientation);
+                mRecyclerView.setLayoutManager(layout);
+                mRecyclerView.setAdapter(new FocusSearchAdapter(itemCount, mOrientation));
+                if (mOrientation == VERTICAL) {
+                    mRecyclerView.setLayoutParams(new LinearLayout.LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT, 250));
+                } else {
+                    mRecyclerView.setLayoutParams(new LinearLayout.LayoutParams(
+                            250, ViewGroup.LayoutParams.MATCH_PARENT));
+                }
+
+                mBefore = mActivity.findViewById(R.id.before);
+                mAfter = mActivity.findViewById(R.id.after);
+            }
+        });
+        waitForIdleSync();
+        assertThat("test sanity", mRecyclerView.getLayoutManager().getLayoutDirection(),
+                is(mLayoutDir));
+        assertThat("test sanity", ViewCompat.getLayoutDirection(mRecyclerView), is(mLayoutDir));
+    }
+
+    @Test
+    public void focusSearchForward() throws Throwable {
+        setup(20);
+        requestFocus(mBefore);
+        assertThat(mBefore, hasFocus());
+        View focused = mBefore;
+        for (int i = 0; i < 20; i++) {
+            focusSearchAndGive(focused, View.FOCUS_FORWARD);
+            RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertThat("vh at " + i, viewHolder, hasFocus());
+            focused = viewHolder.itemView;
+        }
+        focusSearchAndGive(focused, View.FOCUS_FORWARD);
+        assertThat(mAfter, hasFocus());
+        focusSearchAndGive(mAfter, View.FOCUS_FORWARD);
+        assertThat(mBefore, hasFocus());
+        focusSearchAndGive(mBefore, View.FOCUS_FORWARD);
+        focused = mActivity.getCurrentFocus();
+        //noinspection ConstantConditions
+        assertThat(focused.getParent(), CoreMatchers.<ViewParent>sameInstance(mRecyclerView));
+    }
+
+    @Test
+    public void focusSearchBackwards() throws Throwable {
+        setup(20);
+        requestFocus(mAfter);
+        assertThat(mAfter, hasFocus());
+        View focused = mAfter;
+        RecyclerView.ViewHolder lastViewHolder = null;
+        int i = 20;
+        while(lastViewHolder == null) {
+            lastViewHolder = mRecyclerView.findViewHolderForAdapterPosition(--i);
+        }
+        assertThat(lastViewHolder, notNullValue());
+
+        while(i >= 0) {
+            focusSearchAndGive(focused, View.FOCUS_BACKWARD);
+            RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertThat("vh at " + i, viewHolder, hasFocus());
+            focused = viewHolder.itemView;
+            i--;
+        }
+        focusSearchAndGive(focused, View.FOCUS_BACKWARD);
+        assertThat(mBefore, hasFocus());
+        focusSearchAndGive(mBefore, View.FOCUS_BACKWARD);
+        assertThat(mAfter, hasFocus());
+    }
+
+    private View focusSearchAndGive(final View view, final int focusDir) throws Throwable {
+        View next = focusSearch(view, focusDir);
+        if (next != null && next != view) {
+            requestFocus(next);
+            return next;
+        }
+        return null;
+    }
+
+    private View focusSearch(final View view, final int focusDir) throws Throwable {
+        final View[] result = new View[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = view.focusSearch(focusDir);
+            }
+        });
+        waitForIdleSync();
+        return result[0];
+    }
+
+    private void waitForIdleSync() throws Throwable {
+        waitForIdleScroll(mRecyclerView);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    private void requestFocus(final View view) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                view.requestFocus();
+            }
+        });
+        waitForIdleSync();
+    }
+
+    public void waitForIdleScroll(final RecyclerView recyclerView) throws Throwable {
+        final CountDownLatch latch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                RecyclerView.OnScrollListener listener = new RecyclerView.OnScrollListener() {
+                    @Override
+                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                        if (newState == SCROLL_STATE_IDLE) {
+                            latch.countDown();
+                            recyclerView.removeOnScrollListener(this);
+                        }
+                    }
+                };
+                if (recyclerView.getScrollState() == SCROLL_STATE_IDLE) {
+                    latch.countDown();
+                } else {
+                    recyclerView.addOnScrollListener(listener);
+                }
+            }
+        });
+        assertTrue("should go idle in 10 seconds", latch.await(10, TimeUnit.SECONDS));
+    }
+
+    static class FocusSearchAdapter extends RecyclerView.Adapter {
+        private int mItemCount;
+        private int mOrientation;
+        public FocusSearchAdapter(int itemCount, int orientation) {
+            mItemCount = itemCount;
+            mOrientation = orientation;
+        }
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+        int viewType) {
+            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view,
+                    parent, false);
+            if (mOrientation == VERTICAL) {
+                view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                        50));
+            } else {
+                view.setLayoutParams(new ViewGroup.LayoutParams(50,
+                        ViewGroup.LayoutParams.MATCH_PARENT));
+            }
+            return new RecyclerView.ViewHolder(view) {};
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+            holder.itemView.setTag("pos " + position);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItemCount;
+        }
+    }
+
+    static HasFocusMatcher hasFocus() {
+        return new HasFocusMatcher();
+    }
+
+    static class HasFocusMatcher extends BaseMatcher<Object> {
+        @Override
+        public boolean matches(Object item) {
+            if (item instanceof RecyclerView.ViewHolder) {
+                item = ((RecyclerView.ViewHolder) item).itemView;
+            }
+            return item instanceof View && ((View) item).hasFocus();
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("view has focus");
+        }
+
+        private String objectToLog(Object item) {
+            if (item instanceof RecyclerView.ViewHolder) {
+                RecyclerView.ViewHolder vh = (RecyclerView.ViewHolder) item;
+                return vh.toString();
+            }
+            if (item instanceof View) {
+                final Object tag = ((View) item).getTag();
+                return tag == null ? item.toString() : tag.toString();
+            }
+            final String classLog = item == null ? "null" : item.getClass().getSimpleName();
+            return classLog;
+        }
+
+        @Override
+        public void describeMismatch(Object item, Description description) {
+            String noun = objectToLog(item);
+            description.appendText(noun + " does not have focus");
+            Context context = null;
+            if (item instanceof RecyclerView.ViewHolder) {
+                context = ((RecyclerView.ViewHolder)item).itemView.getContext();
+            } else  if (item instanceof View) {
+                context = ((View) item).getContext();
+            }
+            if (context instanceof Activity) {
+                View currentFocus = ((Activity) context).getWindow().getCurrentFocus();
+                description.appendText(". Current focus is in " + objectToLog(currentFocus));
+            }
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GapWorkerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GapWorkerTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GapWorkerTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GapWorkerTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerBaseConfigSetTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerBaseConfigSetTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerBaseConfigSetTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCacheTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCacheTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCacheTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCachedBordersTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCachedBordersTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCachedBordersTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCachedBordersTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
new file mode 100644
index 0000000..5c351eb
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.test.filters.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@MediumTest
+@RunWith(Parameterized.class)
+public class GridLayoutManagerCustomSizeInScrollDirectionTest extends BaseGridLayoutManagerTest {
+    @Parameterized.Parameters(name = "addDecorOffsets:{1},addMargins:{2},config:{0}")
+    public static List<Object[]> getParams() {
+        List<Object[]> params = new ArrayList<>();
+        Boolean[] options = new Boolean[]{true, false};
+        for (boolean addMargins : options) {
+            for (boolean addDecorOffsets : options) {
+                params.add(new Object[] {
+                        new Config(3, HORIZONTAL, false), addDecorOffsets, addMargins});
+                params.add(new Object[] {
+                        new Config(3, VERTICAL, false), addDecorOffsets, addMargins});
+            }
+        }
+        return params;
+    }
+
+    private final boolean mAddDecorOffsets;
+    private final boolean mAddMargins;
+    private final Config mConfig;
+
+    public GridLayoutManagerCustomSizeInScrollDirectionTest(Config config, boolean addDecorOffsets,
+            boolean addMargins) {
+        mConfig = config;
+        mAddDecorOffsets = addDecorOffsets;
+        mAddMargins = addMargins;
+    }
+
+    @Test
+    public void customSizeInScrollDirectionTest() throws Throwable {
+        final int decorOffset = mAddDecorOffsets ? 7 : 0;
+        final int margin = mAddMargins ? 11 : 0;
+        final int[] sizePerPosition = new int[]{3, 5, 9, 21, 3, 5, 9, 6, 9, 1};
+        final int[] expectedSizePerPosition = new int[]{9, 9, 9, 21, 3, 5, 9, 9, 9, 1};
+
+        final GridTestAdapter testAdapter = new GridTestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)
+                        holder.itemView.getLayoutParams();
+                if (layoutParams == null) {
+                    layoutParams = new ViewGroup.MarginLayoutParams(
+                            ViewGroup.LayoutParams.WRAP_CONTENT,
+                            ViewGroup.LayoutParams.WRAP_CONTENT);
+                    holder.itemView.setLayoutParams(layoutParams);
+                }
+                final int size = sizePerPosition[position];
+                if (mConfig.mOrientation == HORIZONTAL) {
+                    layoutParams.width = size;
+                    layoutParams.leftMargin = margin;
+                    layoutParams.rightMargin = margin;
+                } else {
+                    layoutParams.height = size;
+                    layoutParams.topMargin = margin;
+                    layoutParams.bottomMargin = margin;
+                }
+            }
+        };
+        testAdapter.setFullSpan(3, 5);
+        final RecyclerView rv = setupBasic(mConfig, testAdapter);
+        if (mAddDecorOffsets) {
+            rv.addItemDecoration(new RecyclerView.ItemDecoration() {
+                @Override
+                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                        RecyclerView.State state) {
+                    if (mConfig.mOrientation == HORIZONTAL) {
+                        outRect.set(decorOffset, 0, decorOffset, 0);
+                    } else {
+                        outRect.set(0, decorOffset, 0, decorOffset);
+                    }
+                }
+            });
+        }
+        waitForFirstLayout(rv);
+
+        assertTrue("[test sanity] some views should be laid out",
+                mRecyclerView.getChildCount() > 0);
+        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
+            View child = mRecyclerView.getChildAt(i);
+            final int size = mConfig.mOrientation == HORIZONTAL ? child.getWidth()
+                    : child.getHeight();
+            assertEquals("child " + i + " should have the size specified in its layout params",
+                    expectedSizePerPosition[i], size);
+        }
+        checkForMainThreadException();
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerNoOpUpdateTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerRtlTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerRtlTest.java
new file mode 100644
index 0000000..430622f
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerRtlTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.support.annotation.NonNull;
+import android.support.test.filters.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@MediumTest
+@RunWith(Parameterized.class)
+public class GridLayoutManagerRtlTest extends BaseGridLayoutManagerTest {
+
+    public GridLayoutManagerRtlTest(Config config, boolean changeRtlAfter, boolean oneLine,
+            boolean itemsWrapContent) {
+        mConfig = config;
+        mChangeRtlAfter = changeRtlAfter;
+        mOneLine = oneLine;
+        mItemsWrapContent = itemsWrapContent;
+    }
+
+    @Parameterized.Parameters(name = "conf:{0},changeRl:{1},oneLine:{2},itemsWrap:{3}")
+    public static List<Object[]> params() {
+        List<Object[]> result = new ArrayList<>();
+        for (boolean changeRtlAfter : new boolean[]{false, true}) {
+            for (boolean oneLine : new boolean[]{false, true}) {
+                for (boolean itemsWrapContent : new boolean[]{false, true}) {
+                    for (Config config : createBaseVariations()) {
+                        result.add(new Object[] {
+                                config,
+                                changeRtlAfter,
+                                oneLine,
+                                itemsWrapContent
+                        });
+                    }
+                }
+            }
+        }
+        return result;
+    }
+    final Config mConfig;
+    final boolean mChangeRtlAfter;
+    final boolean mOneLine;
+    final boolean mItemsWrapContent;
+
+
+    @Test
+    public void rtlTest() throws Throwable {
+        if (mOneLine && mConfig.mOrientation != VERTICAL) {
+            return;// nothing to test
+        }
+        if (mConfig.mSpanCount == 1) {
+            mConfig.mSpanCount = 2;
+        }
+        String logPrefix = mConfig + ", changeRtlAfterLayout:" + mChangeRtlAfter + ","
+                + "oneLine:" + mOneLine + " itemsWrap:" + mItemsWrapContent;
+        mConfig.mItemCount = 5;
+        if (mOneLine) {
+            mConfig.mSpanCount = mConfig.mItemCount + 1;
+        } else {
+            mConfig.mSpanCount = Math.min(mConfig.mItemCount - 1, mConfig.mSpanCount);
+        }
+
+        RecyclerView rv = setupBasic(mConfig, new GridTestAdapter(mConfig.mItemCount) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (mItemsWrapContent) {
+                    ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+                    if (lp == null) {
+                        lp = mGlm.generateDefaultLayoutParams();
+                    }
+                    if (mConfig.mOrientation == HORIZONTAL) {
+                        lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+                    } else {
+                        lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
+                    }
+                }
+            }
+        });
+        if (mChangeRtlAfter) {
+            waitForFirstLayout(rv);
+            mGlm.expectLayout(1);
+            mGlm.setFakeRtl(true);
+            mGlm.waitForLayout(2);
+        } else {
+            mGlm.mFakeRTL = true;
+            waitForFirstLayout(rv);
+        }
+
+        assertEquals("view should become rtl", true, mGlm.isLayoutRTL());
+        OrientationHelper helper = OrientationHelper.createHorizontalHelper(mGlm);
+        View child0 = mGlm.findViewByPosition(0);
+        final int secondChildPos = mConfig.mOrientation == VERTICAL ? 1
+                : mConfig.mSpanCount;
+        View child1 = mGlm.findViewByPosition(secondChildPos);
+        assertNotNull(logPrefix + " child position 0 should be laid out", child0);
+        assertNotNull(
+                logPrefix + " second child position " + (secondChildPos) + " should be laid out",
+                child1);
+        if (mConfig.mOrientation == VERTICAL || !mConfig.mReverseLayout) {
+            assertTrue(logPrefix + " second child should be to the left of first child",
+                    helper.getDecoratedStart(child0) >= helper.getDecoratedEnd(child1));
+            assertEquals(logPrefix + " first child should be right aligned",
+                    helper.getDecoratedEnd(child0), helper.getEndAfterPadding());
+        } else {
+            assertTrue(logPrefix + " first child should be to the left of second child",
+                    helper.getDecoratedStart(child1) >= helper.getDecoratedEnd(child0));
+            assertEquals(logPrefix + " first child should be left aligned",
+                    helper.getDecoratedStart(child0), helper.getStartAfterPadding());
+        }
+        checkForMainThreadException();
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerSnappingTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerSnappingTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerSnappingTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerTest.java
new file mode 100644
index 0000000..5fdb656
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerTest.java
@@ -0,0 +1,1306 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.util.SparseIntArray;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class GridLayoutManagerTest extends BaseGridLayoutManagerTest {
+
+    @Test
+    public void focusSearchFailureUp() throws Throwable {
+        focusSearchFailure(false);
+    }
+
+    @Test
+    public void focusSearchFailureDown() throws Throwable {
+        focusSearchFailure(true);
+    }
+
+    @Test
+    public void scrollToBadOffset() throws Throwable {
+        scrollToBadOffset(false);
+    }
+
+    @Test
+    public void scrollToBadOffsetReverse() throws Throwable {
+        scrollToBadOffset(true);
+    }
+
+    private void scrollToBadOffset(boolean reverseLayout) throws Throwable {
+        final int w = 500;
+        final int h = 1000;
+        RecyclerView recyclerView = setupBasic(new Config(2, 100).reverseLayout(reverseLayout),
+                new GridTestAdapter(100) {
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+                        if (lp == null) {
+                            lp = new ViewGroup.LayoutParams(w / 2, h / 2);
+                            holder.itemView.setLayoutParams(lp);
+                        } else {
+                            lp.width = w / 2;
+                            lp.height = h / 2;
+                            holder.itemView.setLayoutParams(lp);
+                        }
+                    }
+                });
+        TestedFrameLayout.FullControlLayoutParams lp
+                = new TestedFrameLayout.FullControlLayoutParams(w, h);
+        recyclerView.setLayoutParams(lp);
+        waitForFirstLayout(recyclerView);
+        mGlm.expectLayout(1);
+        scrollToPosition(11);
+        mGlm.waitForLayout(2);
+        // assert spans and position etc
+        for (int i = 0; i < mGlm.getChildCount(); i++) {
+            View child = mGlm.getChildAt(i);
+            GridLayoutManager.LayoutParams params = (GridLayoutManager.LayoutParams) child
+                    .getLayoutParams();
+            assertThat("span index for child at " + i + " with position " + params
+                            .getViewAdapterPosition(),
+                    params.getSpanIndex(), CoreMatchers.is(params.getViewAdapterPosition() % 2));
+        }
+        // assert spans and positions etc.
+        int lastVisible = mGlm.findLastVisibleItemPosition();
+        // this should be the scrolled child
+        assertThat(lastVisible, CoreMatchers.is(11));
+    }
+
+    private void focusSearchFailure(boolean scrollDown) throws Throwable {
+        final RecyclerView recyclerView = setupBasic(new Config(3, 31).reverseLayout(!scrollDown)
+                , new GridTestAdapter(31, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        testViewHolder.itemView.setFocusable(true);
+                        testViewHolder.itemView.setFocusableInTouchMode(true);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation using this for kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / 3);
+                    }
+                });
+        waitForFirstLayout(recyclerView);
+
+        View viewToFocus = recyclerView.findViewHolderForAdapterPosition(1).itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, recyclerView.getFocusedChild());
+        int pos = 1;
+        View focusedView = viewToFocus;
+        while (pos < 31) {
+            focusSearch(focusedView, scrollDown ? View.FOCUS_DOWN : View.FOCUS_UP);
+            waitForIdleScroll(recyclerView);
+            focusedView = recyclerView.getFocusedChild();
+            assertEquals(Math.min(pos + 3, mAdapter.getItemCount() - 1),
+                    recyclerView.getChildViewHolder(focusedView).getAdapterPosition());
+            pos += 3;
+        }
+    }
+
+    /**
+     * Tests that the GridLayoutManager retains the focused element after multiple measure
+     * calls to the RecyclerView.  There was a bug where the focused view was lost when the soft
+     * keyboard opened.  This test simulates the measure/layout events triggered by the opening
+     * of the soft keyboard by making two calls to measure.  A simulation was done because using
+     * the soft keyboard in the test caused many issues on API levels 15, 17 and 19.
+     */
+    @Test
+    public void focusedChildStaysInViewWhenRecyclerViewShrinks() throws Throwable {
+
+        // Arrange.
+
+        final int spanCount = 3;
+        final int itemCount = 100;
+
+        final RecyclerView recyclerView = inflateWrappedRV();
+        ViewGroup.LayoutParams lp = recyclerView.getLayoutParams();
+        lp.height = WRAP_CONTENT;
+        lp.width = MATCH_PARENT;
+
+        Config config = new Config(spanCount, itemCount);
+        mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation,
+                config.mReverseLayout);
+        recyclerView.setLayoutManager(mGlm);
+
+        GridFocusableAdapter gridFocusableAdapter = new GridFocusableAdapter(itemCount);
+        gridFocusableAdapter.assignSpanSizeLookup(mGlm);
+        recyclerView.setAdapter(gridFocusableAdapter);
+
+        mGlm.expectLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().addView(recyclerView);
+            }
+        });
+        mGlm.waitForLayout(3);
+
+        int width = recyclerView.getWidth();
+        int height = recyclerView.getHeight();
+        final int widthMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+        final int fullHeightMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+        // "MinusOne" so that a measure call will appropriately trigger onMeasure after RecyclerView
+        // was previously laid out with the full height version.
+        final int fullHeightMinusOneMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(height - 1, View.MeasureSpec.AT_MOST);
+        final int halfHeightMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(height / 2, View.MeasureSpec.AT_MOST);
+
+        // Act 1.
+
+        // First focus on the last fully visible child located at span index #1.
+        View toFocus = findLastFullyVisibleChild(recyclerView);
+        int focusIndex = recyclerView.getChildAdapterPosition(toFocus);
+        focusIndex = (focusIndex / spanCount) * spanCount + 1;
+        toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
+        assertTrue(focusIndex >= 1 && focusIndex < itemCount);
+
+        requestFocus(toFocus, false);
+
+        mGlm.expectLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+                recyclerView.layout(
+                        0,
+                        0,
+                        recyclerView.getMeasuredWidth(),
+                        recyclerView.getMeasuredHeight());
+            }
+        });
+        mGlm.waitForLayout(3);
+
+        // Assert 1.
+
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.hasFocus(), is(true));
+        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
+                isViewPartiallyInBound(recyclerView, toFocus));
+
+        // Act 2.
+
+        mGlm.expectLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.measure(widthMeasureSpec, fullHeightMeasureSpec);
+                recyclerView.layout(
+                        0,
+                        0,
+                        recyclerView.getMeasuredWidth(),
+                        recyclerView.getMeasuredHeight());
+            }
+        });
+        mGlm.waitForLayout(3);
+
+        // Assert 2.
+
+        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
+                isViewPartiallyInBound(recyclerView, toFocus));
+
+        // Act 3.
+
+        // Now focus on the first fully visible EditText located at the last span index.
+        toFocus = findFirstFullyVisibleChild(recyclerView);
+        focusIndex = recyclerView.getChildAdapterPosition(toFocus);
+        focusIndex = (focusIndex / spanCount) * spanCount + (spanCount - 1);
+        toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
+
+        requestFocus(toFocus, false);
+
+        mGlm.expectLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+                recyclerView.layout(
+                        0,
+                        0,
+                        recyclerView.getMeasuredWidth(),
+                        recyclerView.getMeasuredHeight());
+            }
+        });
+        mGlm.waitForLayout(3);
+
+        // Assert 3.
+
+        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
+                isViewPartiallyInBound(recyclerView, toFocus));
+    }
+
+    @Test
+    public void topUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of rows that can be fully in-bounds of RV.
+        final int visibleRowCount = 5;
+        final int spanCount = 3;
+        final int consecutiveFocusableRowsCount = 4;
+        final int consecutiveUnFocusableRowsCount = 8;
+        final int itemCount = (consecutiveFocusableRowsCount + consecutiveUnFocusableRowsCount)
+                * spanCount;
+
+        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
+                        .reverseLayout(true),
+                new GridTestAdapter(itemCount, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation using this for kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        if (position < spanCount * consecutiveFocusableRowsCount) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
+                    }
+                });
+        waitForFirstLayout(recyclerView);
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, recyclerView.getFocusedChild());
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = focusIndex;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        int maxFocusIndex = (consecutiveFocusableRowsCount - 1) * spanCount + focusIndex;
+        int maxVisibleIndex = (consecutiveFocusableRowsCount + visibleRowCount - 2)
+                * spanCount + visibleIndex;
+
+        // Navigate up through the focusable and unfocusable rows. The focusable rows should
+        // become focused one by one until hitting the last focusable row, at which point,
+        // unfocusable rows should become visible on the screen until the currently focused row
+        // stays on the screen.
+        int pos = focusIndex + spanCount;
+        while (pos < itemCount) {
+            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_UP, true);
+            waitForIdleScroll(recyclerView);
+            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
+            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
+            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(recyclerView, toVisible.itemView));
+            pos += spanCount;
+        }
+    }
+
+    @Test
+    public void bottomUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of rows that can be fully in-bounds of RV.
+        final int visibleRowCount = 5;
+        final int spanCount = 3;
+        final int consecutiveFocusableRowsCount = 4;
+        final int consecutiveUnFocusableRowsCount = 8;
+        final int itemCount = (consecutiveFocusableRowsCount + consecutiveUnFocusableRowsCount)
+                * spanCount;
+
+        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
+                        .reverseLayout(false),
+                new GridTestAdapter(itemCount, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation using this for kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        if (position < spanCount * consecutiveFocusableRowsCount) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
+                    }
+                });
+        waitForFirstLayout(recyclerView);
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, recyclerView.getFocusedChild());
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = focusIndex;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        int maxFocusIndex = (consecutiveFocusableRowsCount - 1) * spanCount + focusIndex;
+        int maxVisibleIndex = (consecutiveFocusableRowsCount + visibleRowCount - 2)
+                * spanCount + visibleIndex;
+
+        // Navigate down through the focusable and unfocusable rows. The focusable rows should
+        // become focused one by one until hitting the last focusable row, at which point,
+        // unfocusable rows should become visible on the screen until the currently focused row
+        // stays on the screen.
+        int pos = focusIndex + spanCount;
+        while (pos < itemCount) {
+            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
+            waitForIdleScroll(recyclerView);
+            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
+            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
+            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(recyclerView, toVisible.itemView));
+            pos += spanCount;
+        }
+    }
+
+    @Test
+    public void leftUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of columns that can be fully in-bounds of RV.
+        final int visibleColCount = 5;
+        final int spanCount = 3;
+        final int consecutiveFocusableColsCount = 4;
+        final int consecutiveUnFocusableColsCount = 8;
+        final int itemCount = (consecutiveFocusableColsCount + consecutiveUnFocusableColsCount)
+                * spanCount;
+
+        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
+                        .orientation(HORIZONTAL).reverseLayout(true),
+                new GridTestAdapter(itemCount, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation using this for kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        if (position < spanCount * consecutiveFocusableColsCount) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
+                    }
+                });
+        waitForFirstLayout(recyclerView);
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, recyclerView.getFocusedChild());
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = focusIndex;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        int maxFocusIndex = (consecutiveFocusableColsCount - 1) * spanCount + focusIndex;
+        int maxVisibleIndex = (consecutiveFocusableColsCount + visibleColCount - 2)
+                * spanCount + visibleIndex;
+
+        // Navigate left through the focusable and unfocusable columns. The focusable columns should
+        // become focused one by one until hitting the last focusable column, at which point,
+        // unfocusable columns should become visible on the screen until the currently focused
+        // column stays on the screen.
+        int pos = focusIndex + spanCount;
+        while (pos < itemCount) {
+            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_LEFT, true);
+            waitForIdleScroll(recyclerView);
+            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
+            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
+            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(recyclerView, toVisible.itemView));
+            pos += spanCount;
+        }
+    }
+
+    @Test
+    public void rightUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of columns that can be fully in-bounds of RV.
+        final int visibleColCount = 5;
+        final int spanCount = 3;
+        final int consecutiveFocusableColsCount = 4;
+        final int consecutiveUnFocusableColsCount = 8;
+        final int itemCount = (consecutiveFocusableColsCount + consecutiveUnFocusableColsCount)
+                * spanCount;
+
+        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
+                        .orientation(HORIZONTAL).reverseLayout(false),
+                new GridTestAdapter(itemCount, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation using this for kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        if (position < spanCount * consecutiveFocusableColsCount) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
+                    }
+                });
+        waitForFirstLayout(recyclerView);
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, recyclerView.getFocusedChild());
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = focusIndex;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        int maxFocusIndex = (consecutiveFocusableColsCount - 1) * spanCount + focusIndex;
+        int maxVisibleIndex = (consecutiveFocusableColsCount + visibleColCount - 2)
+                * spanCount + visibleIndex;
+
+        // Navigate right through the focusable and unfocusable columns. The focusable columns
+        // should become focused one by one until hitting the last focusable column, at which point,
+        // unfocusable columns should become visible on the screen until the currently focused
+        // column stays on the screen.
+        int pos = focusIndex + spanCount;
+        while (pos < itemCount) {
+            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_RIGHT, true);
+            waitForIdleScroll(recyclerView);
+            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
+            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
+            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(recyclerView, toVisible.itemView));
+            pos += spanCount;
+        }
+    }
+
+    @UiThreadTest
+    @Test
+    public void scrollWithoutLayout() throws Throwable {
+        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
+        mGlm.expectLayout(1);
+        setRecyclerView(recyclerView);
+        mGlm.setSpanCount(5);
+        recyclerView.scrollBy(0, 10);
+    }
+
+    @Test
+    public void scrollWithoutLayoutAfterInvalidate() throws Throwable {
+        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
+        waitForFirstLayout(recyclerView);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGlm.setSpanCount(5);
+                recyclerView.scrollBy(0, 10);
+            }
+        });
+    }
+
+    @Test
+    public void predictiveSpanLookup1() throws Throwable {
+        predictiveSpanLookupTest(0, false);
+    }
+
+    @Test
+    public void predictiveSpanLookup2() throws Throwable {
+        predictiveSpanLookupTest(0, true);
+    }
+
+    @Test
+    public void predictiveSpanLookup3() throws Throwable {
+        predictiveSpanLookupTest(1, false);
+    }
+
+    @Test
+    public void predictiveSpanLookup4() throws Throwable {
+        predictiveSpanLookupTest(1, true);
+    }
+
+    public void predictiveSpanLookupTest(int remaining, boolean removeFromStart) throws Throwable {
+        RecyclerView recyclerView = setupBasic(new Config(3, 10));
+        mGlm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                if (position < 0 || position >= mAdapter.getItemCount()) {
+                    postExceptionToInstrumentation(new AssertionError("position is not within " +
+                            "adapter range. pos:" + position + ", adapter size:" +
+                            mAdapter.getItemCount()));
+                }
+                return 1;
+            }
+
+            @Override
+            public int getSpanIndex(int position, int spanCount) {
+                if (position < 0 || position >= mAdapter.getItemCount()) {
+                    postExceptionToInstrumentation(new AssertionError("position is not within " +
+                            "adapter range. pos:" + position + ", adapter size:" +
+                            mAdapter.getItemCount()));
+                }
+                return super.getSpanIndex(position, spanCount);
+            }
+        });
+        waitForFirstLayout(recyclerView);
+        checkForMainThreadException();
+        assertTrue("test sanity", mGlm.supportsPredictiveItemAnimations());
+        mGlm.expectLayout(2);
+        int deleteCnt = 10 - remaining;
+        int deleteStart = removeFromStart ? 0 : remaining;
+        mAdapter.deleteAndNotify(deleteStart, deleteCnt);
+        mGlm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void movingAGroupOffScreenForAddedItems() throws Throwable {
+        final RecyclerView rv = setupBasic(new Config(3, 100));
+        final int[] maxId = new int[1];
+        maxId[0] = -1;
+        final SparseIntArray spanLookups = new SparseIntArray();
+        final AtomicBoolean enableSpanLookupLogging = new AtomicBoolean(false);
+        mGlm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                if (maxId[0] > 0 && mAdapter.getItemAt(position).mId > maxId[0]) {
+                    return 1;
+                } else if (enableSpanLookupLogging.get() && !rv.mState.isPreLayout()) {
+                    spanLookups.put(position, spanLookups.get(position, 0) + 1);
+                }
+                return 3;
+            }
+        });
+        ((SimpleItemAnimator) rv.getItemAnimator()).setSupportsChangeAnimations(true);
+        waitForFirstLayout(rv);
+        View lastView = rv.getChildAt(rv.getChildCount() - 1);
+        final int lastPos = rv.getChildAdapterPosition(lastView);
+        maxId[0] = mAdapter.getItemAt(mAdapter.getItemCount() - 1).mId;
+        // now add a lot of items below this and those new views should have span size 3
+        enableSpanLookupLogging.set(true);
+        mGlm.expectLayout(2);
+        mAdapter.addAndNotify(lastPos - 2, 30);
+        mGlm.waitForLayout(2);
+        checkForMainThreadException();
+
+        assertEquals("last items span count should be queried twice", 2,
+                spanLookups.get(lastPos + 30));
+
+    }
+
+    @Test
+    public void layoutParams() throws Throwable {
+        layoutParamsTest(GridLayoutManager.HORIZONTAL);
+        removeRecyclerView();
+        layoutParamsTest(GridLayoutManager.VERTICAL);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    public void horizontalAccessibilitySpanIndices() throws Throwable {
+        accessibilitySpanIndicesTest(HORIZONTAL);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    public void verticalAccessibilitySpanIndices() throws Throwable {
+        accessibilitySpanIndicesTest(VERTICAL);
+    }
+
+    public void accessibilitySpanIndicesTest(int orientation) throws Throwable {
+        final RecyclerView recyclerView = setupBasic(new Config(3, orientation, false));
+        waitForFirstLayout(recyclerView);
+        final AccessibilityDelegateCompat delegateCompat = mRecyclerView
+                .getCompatAccessibilityDelegate().getItemDelegate();
+        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
+        final View chosen = recyclerView.getChildAt(recyclerView.getChildCount() - 2);
+        final int position = recyclerView.getChildLayoutPosition(chosen);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityNodeInfo(chosen, info);
+            }
+        });
+        GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup;
+        AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo = info
+                .getCollectionItemInfo();
+        assertNotNull(itemInfo);
+        assertEquals("result should have span group position",
+                ssl.getSpanGroupIndex(position, mGlm.getSpanCount()),
+                orientation == HORIZONTAL ? itemInfo.getColumnIndex() : itemInfo.getRowIndex());
+        assertEquals("result should have span index",
+                ssl.getSpanIndex(position, mGlm.getSpanCount()),
+                orientation == HORIZONTAL ? itemInfo.getRowIndex() : itemInfo.getColumnIndex());
+        assertEquals("result should have span size",
+                ssl.getSpanSize(position),
+                orientation == HORIZONTAL ? itemInfo.getRowSpan() : itemInfo.getColumnSpan());
+    }
+
+    public GridLayoutManager.LayoutParams ensureGridLp(View view) {
+        ViewGroup.LayoutParams lp = view.getLayoutParams();
+        GridLayoutManager.LayoutParams glp;
+        if (lp instanceof GridLayoutManager.LayoutParams) {
+            glp = (GridLayoutManager.LayoutParams) lp;
+        } else if (lp == null) {
+            glp = (GridLayoutManager.LayoutParams) mGlm
+                    .generateDefaultLayoutParams();
+            view.setLayoutParams(glp);
+        } else {
+            glp = (GridLayoutManager.LayoutParams) mGlm.generateLayoutParams(lp);
+            view.setLayoutParams(glp);
+        }
+        return glp;
+    }
+
+    public void layoutParamsTest(final int orientation) throws Throwable {
+        final RecyclerView rv = setupBasic(new Config(3, 100).orientation(orientation),
+                new GridTestAdapter(100) {
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView);
+                        int val = 0;
+                        switch (position % 5) {
+                            case 0:
+                                val = 10;
+                                break;
+                            case 1:
+                                val = 30;
+                                break;
+                            case 2:
+                                val = GridLayoutManager.LayoutParams.WRAP_CONTENT;
+                                break;
+                            case 3:
+                                val = GridLayoutManager.LayoutParams.MATCH_PARENT;
+                                break;
+                            case 4:
+                                val = 200;
+                                break;
+                        }
+                        if (orientation == GridLayoutManager.VERTICAL) {
+                            glp.height = val;
+                        } else {
+                            glp.width = val;
+                        }
+                        holder.itemView.setLayoutParams(glp);
+                    }
+                });
+        waitForFirstLayout(rv);
+        final OrientationHelper helper = mGlm.mOrientationHelper;
+        final int firstRowSize = Math.max(30, getSize(mGlm.findViewByPosition(2)));
+        assertEquals(firstRowSize,
+                helper.getDecoratedMeasurement(mGlm.findViewByPosition(0)));
+        assertEquals(firstRowSize,
+                helper.getDecoratedMeasurement(mGlm.findViewByPosition(1)));
+        assertEquals(firstRowSize,
+                helper.getDecoratedMeasurement(mGlm.findViewByPosition(2)));
+        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(0)));
+        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(1)));
+        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(2)));
+
+        final int secondRowSize = Math.max(200, getSize(mGlm.findViewByPosition(3)));
+        assertEquals(secondRowSize,
+                helper.getDecoratedMeasurement(mGlm.findViewByPosition(3)));
+        assertEquals(secondRowSize,
+                helper.getDecoratedMeasurement(mGlm.findViewByPosition(4)));
+        assertEquals(secondRowSize,
+                helper.getDecoratedMeasurement(mGlm.findViewByPosition(5)));
+        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(3)));
+        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(4)));
+        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(5)));
+    }
+
+    @Test
+    public void anchorUpdate() throws InterruptedException {
+        GridLayoutManager glm = new GridLayoutManager(getActivity(), 11);
+        final GridLayoutManager.SpanSizeLookup spanSizeLookup
+                = new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                if (position > 200) {
+                    return 100;
+                }
+                if (position > 20) {
+                    return 2;
+                }
+                return 1;
+            }
+        };
+        glm.setSpanSizeLookup(spanSizeLookup);
+        glm.mAnchorInfo.mPosition = 11;
+        RecyclerView.State state = new RecyclerView.State();
+        mRecyclerView = new RecyclerView(getActivity());
+        state.mItemCount = 1000;
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
+        assertEquals("gm should keep anchor in first span", 11, glm.mAnchorInfo.mPosition);
+
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
+        assertEquals("gm should keep anchor in last span in the row", 20,
+                glm.mAnchorInfo.mPosition);
+
+        glm.mAnchorInfo.mPosition = 5;
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
+        assertEquals("gm should keep anchor in last span in the row", 10,
+                glm.mAnchorInfo.mPosition);
+
+        glm.mAnchorInfo.mPosition = 13;
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
+        assertEquals("gm should move anchor to first span", 11, glm.mAnchorInfo.mPosition);
+
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
+        assertEquals("gm should keep anchor in last span in the row", 20,
+                glm.mAnchorInfo.mPosition);
+
+        glm.mAnchorInfo.mPosition = 23;
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
+        assertEquals("gm should move anchor to first span", 21, glm.mAnchorInfo.mPosition);
+
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
+        assertEquals("gm should keep anchor in last span in the row", 25,
+                glm.mAnchorInfo.mPosition);
+
+        glm.mAnchorInfo.mPosition = 35;
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
+        assertEquals("gm should move anchor to first span", 31, glm.mAnchorInfo.mPosition);
+        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
+                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
+        assertEquals("gm should keep anchor in last span in the row", 35,
+                glm.mAnchorInfo.mPosition);
+    }
+
+    @Test
+    public void spanLookup() {
+        spanLookupTest(false);
+    }
+
+    @Test
+    public void spanLookupWithCache() {
+        spanLookupTest(true);
+    }
+
+    @Test
+    public void spanLookupCache() {
+        final GridLayoutManager.SpanSizeLookup ssl
+                = new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                if (position > 6) {
+                    return 2;
+                }
+                return 1;
+            }
+        };
+        ssl.setSpanIndexCacheEnabled(true);
+        assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(2));
+        ssl.getCachedSpanIndex(4, 5);
+        assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(3));
+        // this should not happen and if happens, it is better to return -1
+        assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4));
+        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(5));
+        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(100));
+        ssl.getCachedSpanIndex(6, 5);
+        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7));
+        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(6));
+        assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4));
+        ssl.getCachedSpanIndex(12, 5);
+        assertEquals("reference child before", 12, ssl.findReferenceIndexFromCache(13));
+        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(12));
+        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7));
+        for (int i = 0; i < 6; i++) {
+            ssl.getCachedSpanIndex(i, 5);
+        }
+
+        for (int i = 1; i < 7; i++) {
+            assertEquals("reference child right before " + i, i - 1,
+                    ssl.findReferenceIndexFromCache(i));
+        }
+        assertEquals("reference child before 0 ", -1, ssl.findReferenceIndexFromCache(0));
+    }
+
+    public void spanLookupTest(boolean enableCache) {
+        final GridLayoutManager.SpanSizeLookup ssl
+                = new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                if (position > 200) {
+                    return 100;
+                }
+                if (position > 6) {
+                    return 2;
+                }
+                return 1;
+            }
+        };
+        ssl.setSpanIndexCacheEnabled(enableCache);
+        assertEquals(0, ssl.getCachedSpanIndex(0, 5));
+        assertEquals(4, ssl.getCachedSpanIndex(4, 5));
+        assertEquals(0, ssl.getCachedSpanIndex(5, 5));
+        assertEquals(1, ssl.getCachedSpanIndex(6, 5));
+        assertEquals(2, ssl.getCachedSpanIndex(7, 5));
+        assertEquals(2, ssl.getCachedSpanIndex(9, 5));
+        assertEquals(0, ssl.getCachedSpanIndex(8, 5));
+    }
+
+    @Test
+    public void removeAnchorItem() throws Throwable {
+        removeAnchorItemTest(
+                new Config(3, 0).orientation(VERTICAL).reverseLayout(false), 100, 0);
+    }
+
+    @Test
+    public void removeAnchorItemReverse() throws Throwable {
+        removeAnchorItemTest(
+                new Config(3, 0).orientation(VERTICAL).reverseLayout(true), 100,
+                0);
+    }
+
+    @Test
+    public void removeAnchorItemHorizontal() throws Throwable {
+        removeAnchorItemTest(
+                new Config(3, 0).orientation(HORIZONTAL).reverseLayout(
+                        false), 100, 0);
+    }
+
+    @Test
+    public void removeAnchorItemReverseHorizontal() throws Throwable {
+        removeAnchorItemTest(
+                new Config(3, 0).orientation(HORIZONTAL).reverseLayout(true),
+                100, 0);
+    }
+
+    /**
+     * This tests a regression where predictive animations were not working as expected when the
+     * first item is removed and there aren't any more items to add from that direction.
+     * First item refers to the default anchor item.
+     */
+    public void removeAnchorItemTest(final Config config, int adapterSize,
+            final int removePos) throws Throwable {
+        GridTestAdapter adapter = new GridTestAdapter(adapterSize) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+                if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
+                    lp = new ViewGroup.MarginLayoutParams(0, 0);
+                    holder.itemView.setLayoutParams(lp);
+                }
+                ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
+                final int maxSize;
+                if (config.mOrientation == HORIZONTAL) {
+                    maxSize = mRecyclerView.getWidth();
+                    mlp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+                } else {
+                    maxSize = mRecyclerView.getHeight();
+                    mlp.width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+                }
+
+                final int desiredSize;
+                if (position == removePos) {
+                    // make it large
+                    desiredSize = maxSize / 4;
+                } else {
+                    // make it small
+                    desiredSize = maxSize / 8;
+                }
+                if (config.mOrientation == HORIZONTAL) {
+                    mlp.width = desiredSize;
+                } else {
+                    mlp.height = desiredSize;
+                }
+            }
+        };
+        RecyclerView recyclerView = setupBasic(config, adapter);
+        waitForFirstLayout(recyclerView);
+        final int childCount = mGlm.getChildCount();
+        RecyclerView.ViewHolder toBeRemoved = null;
+        List<RecyclerView.ViewHolder> toBeMoved = new ArrayList<RecyclerView.ViewHolder>();
+        for (int i = 0; i < childCount; i++) {
+            View child = mGlm.getChildAt(i);
+            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
+            if (holder.getAdapterPosition() == removePos) {
+                toBeRemoved = holder;
+            } else {
+                toBeMoved.add(holder);
+            }
+        }
+        assertNotNull("test sanity", toBeRemoved);
+        assertEquals("test sanity", childCount - 1, toBeMoved.size());
+        LoggingItemAnimator loggingItemAnimator = new LoggingItemAnimator();
+        mRecyclerView.setItemAnimator(loggingItemAnimator);
+        loggingItemAnimator.reset();
+        loggingItemAnimator.expectRunPendingAnimationsCall(1);
+        mGlm.expectLayout(2);
+        adapter.deleteAndNotify(removePos, 1);
+        mGlm.waitForLayout(1);
+        loggingItemAnimator.waitForPendingAnimationsCall(2);
+        assertTrue("removed child should receive remove animation",
+                loggingItemAnimator.mRemoveVHs.contains(toBeRemoved));
+        for (RecyclerView.ViewHolder vh : toBeMoved) {
+            assertTrue("view holder should be in moved list",
+                    loggingItemAnimator.mMoveVHs.contains(vh));
+        }
+        List<RecyclerView.ViewHolder> newHolders = new ArrayList<RecyclerView.ViewHolder>();
+        for (int i = 0; i < mGlm.getChildCount(); i++) {
+            View child = mGlm.getChildAt(i);
+            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
+            if (toBeRemoved != holder && !toBeMoved.contains(holder)) {
+                newHolders.add(holder);
+            }
+        }
+        assertTrue("some new children should show up for the new space", newHolders.size() > 0);
+        assertEquals("no items should receive animate add since they are not new", 0,
+                loggingItemAnimator.mAddVHs.size());
+        for (RecyclerView.ViewHolder holder : newHolders) {
+            assertTrue("new holder should receive a move animation",
+                    loggingItemAnimator.mMoveVHs.contains(holder));
+        }
+        // for removed view, 3 for new row
+        assertTrue("control against adding too many children due to bad layout state preparation."
+                        + " initial:" + childCount + ", current:" + mRecyclerView.getChildCount(),
+                mRecyclerView.getChildCount() <= childCount + 1 + 3);
+    }
+
+    @Test
+    public void spanGroupIndex() {
+        final GridLayoutManager.SpanSizeLookup ssl
+                = new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                if (position > 200) {
+                    return 100;
+                }
+                if (position > 6) {
+                    return 2;
+                }
+                return 1;
+            }
+        };
+        assertEquals(0, ssl.getSpanGroupIndex(0, 5));
+        assertEquals(0, ssl.getSpanGroupIndex(4, 5));
+        assertEquals(1, ssl.getSpanGroupIndex(5, 5));
+        assertEquals(1, ssl.getSpanGroupIndex(6, 5));
+        assertEquals(1, ssl.getSpanGroupIndex(7, 5));
+        assertEquals(2, ssl.getSpanGroupIndex(9, 5));
+        assertEquals(2, ssl.getSpanGroupIndex(8, 5));
+    }
+
+    @Test
+    public void notifyDataSetChange() throws Throwable {
+        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
+        final GridLayoutManager.SpanSizeLookup ssl = mGlm.getSpanSizeLookup();
+        ssl.setSpanIndexCacheEnabled(true);
+        waitForFirstLayout(recyclerView);
+        assertTrue("some positions should be cached", ssl.mSpanIndexCache.size() > 0);
+        final Callback callback = new Callback() {
+            @Override
+            public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                if (!state.isPreLayout()) {
+                    assertEquals("cache should be empty", 0, ssl.mSpanIndexCache.size());
+                }
+            }
+
+            @Override
+            public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                if (!state.isPreLayout()) {
+                    assertTrue("some items should be cached", ssl.mSpanIndexCache.size() > 0);
+                }
+            }
+        };
+        mGlm.mCallbacks.add(callback);
+        mGlm.expectLayout(2);
+        mAdapter.deleteAndNotify(2, 3);
+        mGlm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void unevenHeights() throws Throwable {
+        final Map<Integer, RecyclerView.ViewHolder> viewHolderMap =
+                new HashMap<Integer, RecyclerView.ViewHolder>();
+        RecyclerView recyclerView = setupBasic(new Config(3, 3), new GridTestAdapter(3) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView);
+                glp.height = 50 + position * 50;
+                viewHolderMap.put(position, holder);
+            }
+        });
+        waitForFirstLayout(recyclerView);
+        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
+            assertEquals("all items should get max height", 150,
+                    vh.itemView.getHeight());
+        }
+
+        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
+            assertEquals("all items should have measured the max height", 150,
+                    vh.itemView.getMeasuredHeight());
+        }
+    }
+
+    @Test
+    public void unevenWidths() throws Throwable {
+        final Map<Integer, RecyclerView.ViewHolder> viewHolderMap =
+                new HashMap<Integer, RecyclerView.ViewHolder>();
+        RecyclerView recyclerView = setupBasic(new Config(3, HORIZONTAL, false),
+                new GridTestAdapter(3) {
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView);
+                        glp.width = 50 + position * 50;
+                        viewHolderMap.put(position, holder);
+                    }
+                });
+        waitForFirstLayout(recyclerView);
+        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
+            assertEquals("all items should get max width", 150,
+                    vh.itemView.getWidth());
+        }
+
+        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
+            assertEquals("all items should have measured the max width", 150,
+                    vh.itemView.getMeasuredWidth());
+        }
+    }
+
+    @Test
+    public void spanSizeChange() throws Throwable {
+        final RecyclerView rv = setupBasic(new Config(3, 100));
+        waitForFirstLayout(rv);
+        assertTrue(mGlm.supportsPredictiveItemAnimations());
+        mGlm.expectLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mGlm.setSpanCount(5);
+                assertFalse(mGlm.supportsPredictiveItemAnimations());
+            }
+        });
+        mGlm.waitForLayout(2);
+        mGlm.expectLayout(2);
+        mAdapter.deleteAndNotify(3, 2);
+        mGlm.waitForLayout(2);
+        assertTrue(mGlm.supportsPredictiveItemAnimations());
+    }
+
+    @Test
+    public void cacheSpanIndices() throws Throwable {
+        final RecyclerView rv = setupBasic(new Config(3, 100));
+        mGlm.mSpanSizeLookup.setSpanIndexCacheEnabled(true);
+        waitForFirstLayout(rv);
+        GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup;
+        assertTrue("cache should be filled", mGlm.mSpanSizeLookup.mSpanIndexCache.size() > 0);
+        assertEquals("item index 5 should be in span 2", 2,
+                getLp(mGlm.findViewByPosition(5)).getSpanIndex());
+        mGlm.expectLayout(2);
+        mAdapter.mFullSpanItems.add(4);
+        mAdapter.changeAndNotify(4, 1);
+        mGlm.waitForLayout(2);
+        assertEquals("item index 5 should be in span 2", 0,
+                getLp(mGlm.findViewByPosition(5)).getSpanIndex());
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerWrapContentTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/GridLayoutManagerWrapContentWithAspectRatioTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/InfoStoreTrojan.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/InfoStoreTrojan.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/InfoStoreTrojan.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/ItemAnimatorV2ApiTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/ItemAnimatorV2ApiTest.java
new file mode 100644
index 0000000..7769168
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/ItemAnimatorV2ApiTest.java
@@ -0,0 +1,712 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.widget;
+
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_CHANGED;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_MOVED;
+import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_REMOVED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Includes tests for the new RecyclerView animations API (v2).
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ItemAnimatorV2ApiTest extends BaseRecyclerViewAnimationsTest {
+    @Override
+    protected RecyclerView.ItemAnimator createItemAnimator() {
+        return mAnimator;
+    }
+
+    @Test
+    public void changeMovedOutside() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder target = mRecyclerView.findViewHolderForAdapterPosition(9);
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+        mTestAdapter.changeAndNotify(9, 1);
+        mLayoutManager.waitForLayout(2);
+        // changed item should not be laid out and should just receive disappear
+        LoggingInfo pre = mAnimator.preLayoutInfoMap.get(target);
+        assertNotNull("test sanity", pre);
+        assertNull("test sanity", mAnimator.postLayoutInfoMap.get(target));
+        assertTrue(mAnimator.animateChangeList.isEmpty());
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+        assertEquals(new AnimateDisappearance(target, pre, null),
+                mAnimator.animateDisappearanceList.get(0));
+        // This is kind of problematic because layout manager will never layout the updated
+        // version of this view since it went out of bounds and it won't show up in scrap.
+        // I don't think we can do much better since other option is to bind a fresh view
+    }
+
+    @Test
+    public void changeMovedOutsideWithPredictiveAndTwoViewHolders() throws Throwable {
+        final RecyclerView.ViewHolder[] targets = new RecyclerView.ViewHolder[2];
+
+        setupBasic(10, 0, 10, new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (position == 0) {
+                    if (targets[0] == null) {
+                        targets[0] = holder;
+                    } else {
+                        assertThat(targets[1], CoreMatchers.nullValue());
+                        targets[1] = holder;
+                    }
+                }
+            }
+        });
+        final RecyclerView.ViewHolder singleItemTarget =
+                mRecyclerView.findViewHolderForAdapterPosition(1);
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
+                return viewHolder == singleItemTarget;
+            }
+        };
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void onLayoutChildren(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager lm, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, lm, state);
+                if (!state.isPreLayout()) {
+                    mLayoutManager.addDisappearingView(recycler.getViewForPosition(0));
+                    mLayoutManager.addDisappearingView(recycler.getScrapList().get(0).itemView);
+                }
+            }
+        };
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 2;
+        mTestAdapter.changeAndNotify(0, 2);
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        final RecyclerView.ViewHolder oldTarget = targets[0];
+        final RecyclerView.ViewHolder newTarget = targets[1];
+        assertNotNull("test sanity", targets[0]);
+        assertNotNull("test sanity", targets[1]);
+        // changed item should not be laid out and should just receive disappear
+        LoggingInfo pre = mAnimator.preLayoutInfoMap.get(oldTarget);
+        assertNotNull("test sanity", pre);
+        assertNull("test sanity", mAnimator.postLayoutInfoMap.get(oldTarget));
+
+        assertNull("test sanity", mAnimator.preLayoutInfoMap.get(newTarget));
+        LoggingInfo post = mAnimator.postLayoutInfoMap.get(newTarget);
+        assertNotNull("test sanity", post);
+        assertEquals(1, mAnimator.animateChangeList.size());
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+
+        assertEquals(new AnimateChange(oldTarget, newTarget, pre, post),
+                mAnimator.animateChangeList.get(0));
+
+        LoggingInfo singleItemPre = mAnimator.preLayoutInfoMap.get(singleItemTarget);
+        assertNotNull("test sanity", singleItemPre);
+        LoggingInfo singleItemPost = mAnimator.postLayoutInfoMap.get(singleItemTarget);
+        assertNotNull("test sanity", singleItemPost);
+
+        assertEquals(new AnimateDisappearance(singleItemTarget, singleItemPre, singleItemPost),
+                mAnimator.animateDisappearanceList.get(0));
+    }
+    @Test
+    public void changeMovedOutsideWithPredictive() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder target = mRecyclerView.findViewHolderForAdapterPosition(0);
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void onLayoutChildren(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager lm, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, lm, state);
+                List<RecyclerView.ViewHolder> scrapList = recycler.getScrapList();
+                assertThat(scrapList.size(), CoreMatchers.is(2));
+                mLayoutManager.addDisappearingView(scrapList.get(0).itemView);
+                mLayoutManager.addDisappearingView(scrapList.get(0).itemView);
+            }
+        };
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 2;
+        mTestAdapter.changeAndNotify(0, 2);
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        // changed item should not be laid out and should just receive disappear
+        LoggingInfo pre = mAnimator.preLayoutInfoMap.get(target);
+        assertNotNull("test sanity", pre);
+        LoggingInfo postInfo = mAnimator.postLayoutInfoMap.get(target);
+        assertNotNull("test sanity", postInfo);
+        assertTrue(mAnimator.animateChangeList.isEmpty());
+        assertEquals(2, mAnimator.animateDisappearanceList.size());
+        try {
+            assertEquals(new AnimateDisappearance(target, pre, postInfo),
+                    mAnimator.animateDisappearanceList.get(0));
+        } catch (Throwable t) {
+            assertEquals(new AnimateDisappearance(target, pre, postInfo),
+                    mAnimator.animateDisappearanceList.get(1));
+        }
+
+    }
+
+    @Test
+    public void simpleAdd() throws Throwable {
+        setupBasic(10);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.addAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        assertEquals(1, mAnimator.animateAppearanceList.size());
+        AnimateAppearance log = mAnimator.animateAppearanceList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertNull(log.preInfo);
+        assertEquals(0, log.postInfo.changeFlags);
+        // the first two should not receive anything
+        for (int i = 0; i < 2; i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void simpleRemove() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_REMOVED, log.preInfo.changeFlags);
+        // the first two should not receive anything
+        for (int i = 0; i < 2; i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void simpleUpdate() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        assertEquals(1, mAnimator.animateChangeList.size());
+        AnimateChange log = mAnimator.animateChangeList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertSame(vh, log.newHolder);
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, log.postInfo.changeFlags);
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void updateWithDuplicateViewHolder() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
+                assertSame(viewHolder, vh);
+                return false;
+            }
+        };
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        assertNotSame(vh, newVh);
+        assertEquals(1, mAnimator.animateChangeList.size());
+        AnimateChange log = mAnimator.animateChangeList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertSame(newVh, log.newHolder);
+        assertNull(vh.itemView.getParent());
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, log.postInfo.changeFlags);
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void updateWithOneDuplicateAndOneInPlace() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder replaced = mRecyclerView.findViewHolderForAdapterPosition(2);
+        final RecyclerView.ViewHolder reused = mRecyclerView.findViewHolderForAdapterPosition(3);
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
+                if (viewHolder == replaced) {
+                    return false;
+                } else if (viewHolder == reused) {
+                    return true;
+                }
+                fail("unpexpected view");
+                return false;
+            }
+        };
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(2, 2);
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+
+        assertNotSame(replaced, newVh);
+        assertSame(reused, mRecyclerView.findViewHolderForAdapterPosition(3));
+
+        assertEquals(2, mAnimator.animateChangeList.size());
+        AnimateChange logReplaced = null, logReused = null;
+        for (AnimateChange change : mAnimator.animateChangeList) {
+            if (change.newHolder == change.viewHolder) {
+                logReused = change;
+            } else {
+                logReplaced = change;
+            }
+        }
+        assertNotNull(logReplaced);
+        assertNotNull(logReused);
+        assertSame(replaced, logReplaced.viewHolder);
+        assertSame(newVh, logReplaced.newHolder);
+        assertSame(reused, logReused.viewHolder);
+        assertSame(reused, logReused.newHolder);
+
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(replaced));
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(reused));
+
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(reused));
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(replaced));
+
+        assertEquals(FLAG_CHANGED, logReplaced.preInfo.changeFlags);
+        assertEquals(FLAG_CHANGED, logReused.preInfo.changeFlags);
+
+        assertEquals(0, logReplaced.postInfo.changeFlags);
+        assertEquals(0, logReused.postInfo.changeFlags);
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2 || i == 3) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void changeToDisappear() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(9);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(9, 1);
+        mLayoutManager.waitForLayout(2);
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(9, mAnimator.animatePersistenceList.size());
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void changeToDisappearFromHead() throws Throwable {
+        setupBasic(10);
+        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(0);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(0, 1);
+        mLayoutManager.waitForLayout(2);
+        assertEquals(1, mAnimator.animateDisappearanceList.size());
+        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(9, mAnimator.animatePersistenceList.size());
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void updatePayload() throws Throwable {
+        setupBasic(10);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        final Object payload = new Object();
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
+                assertSame(vh, viewHolder);
+                assertEquals(1, payloads.size());
+                assertSame(payload, payloads.get(0));
+                return true;
+            }
+        };
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotifyWithPayload(2, 1, payload);
+        mLayoutManager.waitForLayout(2);
+        assertEquals(1, mAnimator.animateChangeList.size());
+        AnimateChange log = mAnimator.animateChangeList.get(0);
+        assertSame(vh, log.viewHolder);
+        assertSame(vh, log.newHolder);
+        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
+        assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
+        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
+        assertEquals(0, log.postInfo.changeFlags);
+        assertNotNull(log.preInfo.payloads);
+        assertTrue(log.preInfo.payloads.contains(payload));
+        //others should not receive anything
+        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
+            if (i == 2) {
+                continue;
+            }
+            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
+            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void notifyDataSetChanged() throws Throwable {
+        TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        mTestAdapter.dispatchDataSetChanged();
+        mLayoutManager.waitForLayout(2);
+        assertEquals(10, mAnimator.animateChangeList.size());
+        for (AnimateChange change : mAnimator.animateChangeList) {
+            assertNotNull(change.preInfo);
+            assertNotNull(change.postInfo);
+            assertSame(change.preInfo.viewHolder, change.postInfo.viewHolder);
+        }
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+    }
+
+    @Test
+    public void notifyDataSetChangedWithoutStableIds() throws Throwable {
+        TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(false);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        mTestAdapter.dispatchDataSetChanged();
+        mLayoutManager.waitForLayout(2);
+        assertEquals(0, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+    }
+
+    @Test
+    public void notifyDataSetChangedWithAppearing() throws Throwable {
+        notifyDataSetChangedWithAppearing(false);
+    }
+
+    @Test
+    public void notifyDataSetChangedWithAppearingNotifyBoth() throws Throwable {
+        notifyDataSetChangedWithAppearing(true);
+    }
+
+    private void notifyDataSetChangedWithAppearing(final boolean notifyBoth) throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (notifyBoth) {
+                        adapter.addAndNotify(2, 2);
+                    } else {
+                        adapter.mItems.add(2, new Item(2, "custom 1"));
+                        adapter.mItems.add(3, new Item(3, "custom 2"));
+                    }
+
+                    adapter.notifyDataSetChanged();
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        assertEquals(10, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(2, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+    }
+
+    @Test
+    public void notifyDataSetChangedWithDispappearing() throws Throwable {
+        notifyDataSetChangedWithDispappearing(false);
+    }
+
+    @Test
+    public void notifyDataSetChangedWithDispappearingNotifyBoth() throws Throwable {
+        notifyDataSetChangedWithDispappearing(true);
+    }
+
+    private void notifyDataSetChangedWithDispappearing(final boolean notifyBoth) throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    if (notifyBoth) {
+                        adapter.deleteAndNotify(2, 2);
+                    } else {
+                        adapter.mItems.remove(2);
+                        adapter.mItems.remove(2);
+                    }
+                    adapter.notifyDataSetChanged();
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        assertEquals(8, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(0, mAnimator.animateAppearanceList.size());
+        assertEquals(2, mAnimator.animateDisappearanceList.size());
+    }
+
+    @Test
+    public void notifyUpdateWithChangedAdapterType() throws Throwable {
+        final AtomicInteger itemType = new AtomicInteger(1);
+        final TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public int getItemViewType(int position) {
+                return position == 2 ? itemType.get() : 20;
+            }
+        };
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
+
+        mAnimator.canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
+                return viewHolder != vh;
+            }
+        };
+
+        mLayoutManager.expectLayouts(1);
+        itemType.set(3);
+        adapter.dispatchDataSetChanged();
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
+        // TODO we should be able to map old type to the new one but doing that change has some
+        // recycling side effects.
+        assertEquals(9, mAnimator.animateChangeList.size());
+        assertEquals(0, mAnimator.animatePersistenceList.size());
+        assertEquals(1, mAnimator.animateAppearanceList.size());
+        assertEquals(0, mAnimator.animateDisappearanceList.size());
+        assertNotSame(vh, newVh);
+        for (AnimateChange change : mAnimator.animateChangeList) {
+            if (change.viewHolder == vh) {
+                assertSame(change.newHolder, newVh);
+                assertSame(change.viewHolder, vh);
+            } else {
+                assertSame(change.newHolder, change.viewHolder);
+            }
+        }
+    }
+
+    LoggingV2Animator mAnimator = new LoggingV2Animator();
+
+    class LoggingV2Animator extends RecyclerView.ItemAnimator {
+
+        CanReUseCallback canReUseCallback = new CanReUseCallback() {
+            @Override
+            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
+                return true;
+            }
+        };
+        Map<RecyclerView.ViewHolder, LoggingInfo> preLayoutInfoMap = new HashMap<>();
+        Map<RecyclerView.ViewHolder, LoggingInfo> postLayoutInfoMap = new HashMap<>();
+
+        List<AnimateAppearance> animateAppearanceList = new ArrayList<>();
+        List<AnimateDisappearance> animateDisappearanceList = new ArrayList<>();
+        List<AnimatePersistence> animatePersistenceList = new ArrayList<>();
+        List<AnimateChange> animateChangeList = new ArrayList<>();
+
+        @Override
+        public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder,
+                List<Object> payloads) {
+            return canReUseCallback.canReUse(viewHolder, payloads);
+        }
+
+        @NonNull
+        @Override
+        public ItemHolderInfo recordPreLayoutInformation(@NonNull RecyclerView.State state,
+                @NonNull RecyclerView.ViewHolder viewHolder,
+                @AdapterChanges int changeFlags, @NonNull List<Object> payloads) {
+            LoggingInfo loggingInfo = new LoggingInfo(viewHolder, changeFlags, payloads);
+            preLayoutInfoMap.put(viewHolder, loggingInfo);
+            return loggingInfo;
+        }
+
+        @NonNull
+        @Override
+        public ItemHolderInfo recordPostLayoutInformation(@NonNull RecyclerView.State state,
+                @NonNull RecyclerView.ViewHolder viewHolder) {
+            LoggingInfo loggingInfo = new LoggingInfo(viewHolder, 0, null);
+            postLayoutInfoMap.put(viewHolder, loggingInfo);
+            return loggingInfo;
+        }
+
+        @Override
+        public boolean animateDisappearance(@NonNull RecyclerView.ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preLayoutInfo,
+                @Nullable ItemHolderInfo postLayoutInfo) {
+            animateDisappearanceList.add(new AnimateDisappearance(viewHolder,
+                    (LoggingInfo) preLayoutInfo, (LoggingInfo) postLayoutInfo));
+            assertSame(preLayoutInfoMap.get(viewHolder), preLayoutInfo);
+            assertSame(postLayoutInfoMap.get(viewHolder), postLayoutInfo);
+            dispatchAnimationFinished(viewHolder);
+
+            return false;
+        }
+
+        @Override
+        public boolean animateAppearance(@NonNull RecyclerView.ViewHolder viewHolder,
+                ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+            animateAppearanceList.add(
+                    new AnimateAppearance(viewHolder, (LoggingInfo) preInfo, (LoggingInfo) postInfo));
+            assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
+            assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
+            dispatchAnimationFinished(viewHolder);
+            return false;
+        }
+
+        @Override
+        public boolean animatePersistence(@NonNull RecyclerView.ViewHolder viewHolder,
+                @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+            animatePersistenceList.add(new AnimatePersistence(viewHolder, (LoggingInfo) preInfo,
+                    (LoggingInfo) postInfo));
+            dispatchAnimationFinished(viewHolder);
+            assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
+            assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
+            return false;
+        }
+
+        @Override
+        public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder,
+                @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo,
+                @NonNull ItemHolderInfo postInfo) {
+            animateChangeList.add(new AnimateChange(oldHolder, newHolder, (LoggingInfo) preInfo,
+                    (LoggingInfo) postInfo));
+            if (oldHolder != null) {
+                dispatchAnimationFinished(oldHolder);
+                assertSame(preLayoutInfoMap.get(oldHolder), preInfo);
+            }
+            if (newHolder != null && oldHolder != newHolder) {
+                dispatchAnimationFinished(newHolder);
+                assertSame(postLayoutInfoMap.get(newHolder), postInfo);
+            }
+
+            return false;
+        }
+
+        @Override
+        public void runPendingAnimations() {
+
+        }
+
+        @Override
+        public void endAnimation(RecyclerView.ViewHolder item) {
+        }
+
+        @Override
+        public void endAnimations() {
+
+        }
+
+        @Override
+        public boolean isRunning() {
+            return false;
+        }
+    }
+
+    interface CanReUseCallback {
+
+        boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads);
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
new file mode 100644
index 0000000..0293646
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LayoutState.LAYOUT_END;
+import static android.support.v7.widget.LayoutState.LAYOUT_START;
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.test.filters.LargeTest;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewParent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests that rely on the basic configuration and does not do any additions / removals
+ */
+@RunWith(Parameterized.class)
+@LargeTest
+public class LinearLayoutManagerBaseConfigSetTest extends BaseLinearLayoutManagerTest {
+
+    private final Config mConfig;
+
+    public LinearLayoutManagerBaseConfigSetTest(Config config) {
+        mConfig = config;
+    }
+
+
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Config> configs() throws CloneNotSupportedException {
+        List<Config> result = new ArrayList<>();
+        for (Config config : createBaseVariations()) {
+            result.add(config);
+        }
+        return result;
+    }
+
+    @Test
+    public void scrollToPositionWithOffsetTest() throws Throwable {
+        Config config = ((Config) mConfig.clone()).itemCount(300);
+        setupByConfig(config, true);
+        OrientationHelper orientationHelper = OrientationHelper
+                .createOrientationHelper(mLayoutManager, config.mOrientation);
+        Rect layoutBounds = getDecoratedRecyclerViewBounds();
+        // try scrolling towards head, should not affect anything
+        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
+        if (config.mStackFromEnd) {
+            scrollToPositionWithOffset(mTestAdapter.getItemCount() - 1,
+                    mLayoutManager.mOrientationHelper.getEnd() - 500);
+        } else {
+            scrollToPositionWithOffset(0, 20);
+        }
+        assertRectSetsEqual(config + " trying to over scroll with offset should be no-op",
+                before, mLayoutManager.collectChildCoordinates());
+        // try offsetting some visible children
+        int testCount = 10;
+        while (testCount-- > 0) {
+            // get middle child
+            final View child = mLayoutManager.getChildAt(mLayoutManager.getChildCount() / 2);
+            final int position = mRecyclerView.getChildLayoutPosition(child);
+            final int startOffset = config.mReverseLayout ?
+                    orientationHelper.getEndAfterPadding() - orientationHelper
+                            .getDecoratedEnd(child)
+                    : orientationHelper.getDecoratedStart(child) - orientationHelper
+                            .getStartAfterPadding();
+            final int scrollOffset = config.mStackFromEnd ? startOffset + startOffset / 2
+                    : startOffset / 2;
+            mLayoutManager.expectLayouts(1);
+            scrollToPositionWithOffset(position, scrollOffset);
+            mLayoutManager.waitForLayout(2);
+            final int finalOffset = config.mReverseLayout ?
+                    orientationHelper.getEndAfterPadding() - orientationHelper
+                            .getDecoratedEnd(child)
+                    : orientationHelper.getDecoratedStart(child) - orientationHelper
+                            .getStartAfterPadding();
+            assertEquals(config + " scroll with offset on a visible child should work fine " +
+                            " offset:" + finalOffset + " , existing offset:" + startOffset + ", "
+                            + "child " + position,
+                    scrollOffset, finalOffset);
+        }
+
+        // try scrolling to invisible children
+        testCount = 10;
+        // we test above and below, one by one
+        int offsetMultiplier = -1;
+        while (testCount-- > 0) {
+            final TargetTuple target = findInvisibleTarget(config);
+            final String logPrefix = config + " " + target;
+            mLayoutManager.expectLayouts(1);
+            final int offset = offsetMultiplier
+                    * orientationHelper.getDecoratedMeasurement(mLayoutManager.getChildAt(0)) / 3;
+            scrollToPositionWithOffset(target.mPosition, offset);
+            mLayoutManager.waitForLayout(2);
+            final View child = mLayoutManager.findViewByPosition(target.mPosition);
+            assertNotNull(logPrefix + " scrolling to a mPosition with offset " + offset
+                    + " should layout it", child);
+            final Rect bounds = mLayoutManager.getViewBounds(child);
+            if (DEBUG) {
+                Log.d(TAG, logPrefix + " post scroll to invisible mPosition " + bounds + " in "
+                        + layoutBounds + " with offset " + offset);
+            }
+
+            if (config.mReverseLayout) {
+                assertEquals(logPrefix + " when scrolling with offset to an invisible in reverse "
+                                + "layout, its end should align with recycler view's end - offset",
+                        orientationHelper.getEndAfterPadding() - offset,
+                        orientationHelper.getDecoratedEnd(child)
+                );
+            } else {
+                assertEquals(
+                        logPrefix + " when scrolling with offset to an invisible child in normal"
+                                + " layout its start should align with recycler view's start + "
+                                + "offset",
+                        orientationHelper.getStartAfterPadding() + offset,
+                        orientationHelper.getDecoratedStart(child)
+                );
+            }
+            offsetMultiplier *= -1;
+        }
+    }
+
+    @Test
+    public void getFirstLastChildrenTest() throws Throwable {
+        final Config config = ((Config) mConfig.clone()).itemCount(300);
+        setupByConfig(config, true);
+        Runnable viewInBoundsTest = new Runnable() {
+            @Override
+            public void run() {
+                VisibleChildren visibleChildren = mLayoutManager.traverseAndFindVisibleChildren();
+                final String boundsLog = mLayoutManager.getBoundsLog();
+                assertEquals(config + ":\nfirst visible child should match traversal result\n"
+                                + boundsLog, visibleChildren.firstVisiblePosition,
+                        mLayoutManager.findFirstVisibleItemPosition()
+                );
+                assertEquals(
+                        config + ":\nfirst fully visible child should match traversal result\n"
+                                + boundsLog, visibleChildren.firstFullyVisiblePosition,
+                        mLayoutManager.findFirstCompletelyVisibleItemPosition()
+                );
+
+                assertEquals(config + ":\nlast visible child should match traversal result\n"
+                                + boundsLog, visibleChildren.lastVisiblePosition,
+                        mLayoutManager.findLastVisibleItemPosition()
+                );
+                assertEquals(
+                        config + ":\nlast fully visible child should match traversal result\n"
+                                + boundsLog, visibleChildren.lastFullyVisiblePosition,
+                        mLayoutManager.findLastCompletelyVisibleItemPosition()
+                );
+            }
+        };
+        mActivityRule.runOnUiThread(viewInBoundsTest);
+        // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching
+        // case
+        final int scrollPosition = config.mStackFromEnd ? 0 : mTestAdapter.getItemCount();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.smoothScrollToPosition(scrollPosition);
+            }
+        });
+        while (mLayoutManager.isSmoothScrolling() ||
+                mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
+            mActivityRule.runOnUiThread(viewInBoundsTest);
+            Thread.sleep(400);
+        }
+        // delete all items
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(0, mTestAdapter.getItemCount());
+        mLayoutManager.waitForLayout(2);
+        // test empty case
+        mActivityRule.runOnUiThread(viewInBoundsTest);
+        // set a new adapter with huge items to test full bounds check
+        mLayoutManager.expectLayouts(1);
+        final int totalSpace = mLayoutManager.mOrientationHelper.getTotalSpace();
+        final TestAdapter newAdapter = new TestAdapter(100) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (config.mOrientation == HORIZONTAL) {
+                    holder.itemView.setMinimumWidth(totalSpace + 5);
+                } else {
+                    holder.itemView.setMinimumHeight(totalSpace + 5);
+                }
+            }
+        };
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setAdapter(newAdapter);
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        mActivityRule.runOnUiThread(viewInBoundsTest);
+    }
+
+    @Test
+    public void dontRecycleViewsTranslatedOutOfBoundsFromStart() throws Throwable {
+        final Config config = ((Config) mConfig.clone()).itemCount(1000);
+        setupByConfig(config, true);
+        mLayoutManager.expectLayouts(1);
+        scrollToPosition(500);
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(500);
+        OrientationHelper helper = mLayoutManager.mOrientationHelper;
+        int gap = helper.getDecoratedStart(vh.itemView);
+        scrollBy(gap);
+        gap = helper.getDecoratedStart(vh.itemView);
+        assertThat("test sanity", gap, is(0));
+
+        final int size = helper.getDecoratedMeasurement(vh.itemView);
+        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mConfig.mOrientation == HORIZONTAL) {
+                    vh.itemView.setTranslationX(size * 2);
+                } else {
+                    vh.itemView.setTranslationY(size * 2);
+                }
+            }
+        });
+        scrollBy(size * 2);
+        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
+        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
+        assertThat(vh.getAdapterPosition(), is(500));
+        scrollBy(size * 2);
+        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
+    }
+
+    @Test
+    public void dontRecycleViewsTranslatedOutOfBoundsFromEnd() throws Throwable {
+        final Config config = ((Config) mConfig.clone()).itemCount(1000);
+        setupByConfig(config, true);
+        mLayoutManager.expectLayouts(1);
+        scrollToPosition(500);
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(500);
+        OrientationHelper helper = mLayoutManager.mOrientationHelper;
+        int gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
+        scrollBy(-gap);
+        gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
+        assertThat("test sanity", gap, is(0));
+
+        final int size = helper.getDecoratedMeasurement(vh.itemView);
+        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mConfig.mOrientation == HORIZONTAL) {
+                    vh.itemView.setTranslationX(-size * 2);
+                } else {
+                    vh.itemView.setTranslationY(-size * 2);
+                }
+            }
+        });
+        scrollBy(-size * 2);
+        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
+        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
+        assertThat(vh.getAdapterPosition(), is(500));
+        scrollBy(-size * 2);
+        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
+    }
+
+    private TargetTuple findInvisibleTarget(Config config) {
+        int minPosition = Integer.MAX_VALUE, maxPosition = Integer.MIN_VALUE;
+        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
+            View child = mLayoutManager.getChildAt(i);
+            int position = mRecyclerView.getChildLayoutPosition(child);
+            if (position < minPosition) {
+                minPosition = position;
+            }
+            if (position > maxPosition) {
+                maxPosition = position;
+            }
+        }
+        final int tailTarget = maxPosition +
+                (mRecyclerView.getAdapter().getItemCount() - maxPosition) / 2;
+        final int headTarget = minPosition / 2;
+        final int target;
+        // where will the child come from ?
+        final int itemLayoutDirection;
+        if (Math.abs(tailTarget - maxPosition) > Math.abs(headTarget - minPosition)) {
+            target = tailTarget;
+            itemLayoutDirection = config.mReverseLayout ? LAYOUT_START : LAYOUT_END;
+        } else {
+            target = headTarget;
+            itemLayoutDirection = config.mReverseLayout ? LAYOUT_END : LAYOUT_START;
+        }
+        if (DEBUG) {
+            Log.d(TAG,
+                    config + " target:" + target + " min:" + minPosition + ", max:" + maxPosition);
+        }
+        return new TargetTuple(target, itemLayoutDirection);
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerCacheTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerCacheTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerCacheTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
new file mode 100644
index 0000000..6aa26b8
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import android.support.annotation.NonNull;
+import android.support.test.filters.MediumTest;
+import android.view.View;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public class LinearLayoutManagerPrepareForDropTest extends BaseLinearLayoutManagerTest {
+
+    final BaseLinearLayoutManagerTest.Config mConfig;
+    final SelectTargetChildren mSelectTargetChildren;
+
+    public LinearLayoutManagerPrepareForDropTest(
+            Config config, SelectTargetChildren selectTargetChildren) {
+        mConfig = config;
+        mSelectTargetChildren = selectTargetChildren;
+    }
+
+    @Parameterized.Parameters(name = "{0},selectTargetChildren:{1}")
+    public static Iterable<Object[]> params() {
+        SelectTargetChildren[] selectors
+                = new SelectTargetChildren[]{
+                new SelectTargetChildren() {
+                    @Override
+                    public int[] selectTargetChildren(int childCount) {
+                        return new int[]{1, 0};
+                    }
+                    @Override
+                    public String toString() {
+                        return "{1,0}";
+                    }
+                },
+                new SelectTargetChildren() {
+                    @Override
+                    public int[] selectTargetChildren(int childCount) {
+                        return new int[]{0, 1};
+                    }
+                    @Override
+                    public String toString() {
+                        return "{0,1}";
+                    }
+                },
+                new SelectTargetChildren() {
+                    @Override
+                    public int[] selectTargetChildren(int childCount) {
+                        return new int[]{childCount - 1, childCount - 2};
+                    }
+                    @Override
+                    public String toString() {
+                        return "{childCount-1,childCount-2}";
+                    }
+                },
+                new SelectTargetChildren() {
+                    @Override
+                    public int[] selectTargetChildren(int childCount) {
+                        return new int[]{childCount - 2, childCount - 1};
+                    }
+                    @Override
+                    public String toString() {
+                        return "{childCount-2,childCount-1}";
+                    }
+                },
+                new SelectTargetChildren() {
+                    @Override
+                    public int[] selectTargetChildren(int childCount) {
+                        return new int[]{childCount / 2, childCount / 2 + 1};
+                    }
+                    @Override
+                    public String toString() {
+                        return "{childCount/2,childCount/2+1}";
+                    }
+                },
+                new SelectTargetChildren() {
+                    @Override
+                    public int[] selectTargetChildren(int childCount) {
+                        return new int[]{childCount / 2 + 1, childCount / 2};
+                    }
+                    @Override
+                    public String toString() {
+                        return "{childCount/2+1,childCount/2}";
+                    }
+                }
+        };
+        List<Object[]> variations = new ArrayList<>();
+        for (SelectTargetChildren selector : selectors) {
+            for (BaseLinearLayoutManagerTest.Config config : createBaseVariations()) {
+                variations.add(new Object[]{config, selector});
+            }
+        }
+        return variations;
+    }
+
+    @Test
+    @MediumTest
+    public void prepareForDropTest()
+            throws Throwable {
+        final Config config = (Config) mConfig.clone();
+        config.mTestAdapter = new BaseRecyclerViewInstrumentationTest.TestAdapter(100) {
+            @Override
+            public void onBindViewHolder(
+                    @NonNull BaseRecyclerViewInstrumentationTest.TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (config.mOrientation == HORIZONTAL) {
+                    final int base = mLayoutManager.getWidth() / 5;
+                    final int itemRand = holder.mBoundItem.mText.hashCode() % base;
+                    holder.itemView.setMinimumWidth(base + itemRand);
+                } else {
+                    final int base = mLayoutManager.getHeight() / 5;
+                    final int itemRand = holder.mBoundItem.mText.hashCode() % base;
+                    holder.itemView.setMinimumHeight(base + itemRand);
+                }
+            }
+        };
+        setupByConfig(config, true);
+        mLayoutManager.expectLayouts(1);
+        scrollToPosition(mTestAdapter.getItemCount() / 2);
+        mLayoutManager.waitForLayout(1);
+        int[] positions = mSelectTargetChildren.selectTargetChildren(mRecyclerView.getChildCount());
+        final View fromChild = mLayoutManager.getChildAt(positions[0]);
+        final int fromPos = mLayoutManager.getPosition(fromChild);
+        final View onChild = mLayoutManager.getChildAt(positions[1]);
+        final int toPos = mLayoutManager.getPosition(onChild);
+        final OrientationHelper helper = mLayoutManager.mOrientationHelper;
+        final int dragCoordinate;
+        final boolean towardsHead = toPos < fromPos;
+        final int referenceLine;
+        if (config.mReverseLayout == towardsHead) {
+            referenceLine = helper.getDecoratedEnd(onChild);
+            dragCoordinate = referenceLine + 3 -
+                    helper.getDecoratedMeasurement(fromChild);
+        } else {
+            referenceLine = helper.getDecoratedStart(onChild);
+            dragCoordinate = referenceLine - 3;
+        }
+        mLayoutManager.expectLayouts(2);
+
+        final int x, y;
+        if (config.mOrientation == HORIZONTAL) {
+            x = dragCoordinate;
+            y = fromChild.getTop();
+        } else {
+            y = dragCoordinate;
+            x = fromChild.getLeft();
+        }
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTestAdapter.moveInUIThread(fromPos, toPos);
+                mTestAdapter.notifyItemMoved(fromPos, toPos);
+                mLayoutManager.prepareForDrop(fromChild, onChild, x, y);
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+
+        assertSame(fromChild, mRecyclerView.findViewHolderForAdapterPosition(toPos).itemView);
+        // make sure it has the position we wanted
+        if (config.mReverseLayout == towardsHead) {
+            assertEquals(referenceLine, helper.getDecoratedEnd(fromChild));
+        } else {
+            assertEquals(referenceLine, helper.getDecoratedStart(fromChild));
+        }
+    }
+
+    protected interface SelectTargetChildren {
+        int[] selectTargetChildren(int childCount);
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerResizeTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerResizeTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerResizeTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerResizeTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerSavedStateTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerSnappingTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerTest.java
new file mode 100644
index 0000000..d04d8cc
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerTest.java
@@ -0,0 +1,1259 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.support.v4.view.ViewCompat;
+import android.util.Log;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+/**
+ * Includes tests for {@link LinearLayoutManager}.
+ * <p>
+ * Since most UI tests are not practical, these tests are focused on internal data representation
+ * and stability of LinearLayoutManager in response to different events (state change, scrolling
+ * etc) where it is very hard to do manual testing.
+ */
+@LargeTest
+public class LinearLayoutManagerTest extends BaseLinearLayoutManagerTest {
+
+    /**
+     * Tests that the LinearLayoutManager retains the focused element after multiple measure
+     * calls to the RecyclerView.  There was a bug where the focused view was lost when the soft
+     * keyboard opened.  This test simulates the measure/layout events triggered by the opening
+     * of the soft keyboard by making two calls to measure.  A simulation was done because using
+     * the soft keyboard in the test caused many issues on API levels 15, 17 and 19.
+     */
+    @Test
+    public void focusedChildStaysInViewWhenRecyclerViewShrinks() throws Throwable {
+
+        // Arrange.
+
+        final RecyclerView recyclerView = inflateWrappedRV();
+        ViewGroup.LayoutParams lp = recyclerView.getLayoutParams();
+        lp.height = WRAP_CONTENT;
+        lp.width = MATCH_PARENT;
+        recyclerView.setHasFixedSize(true);
+
+        final FocusableAdapter focusableAdapter =
+                new FocusableAdapter(50);
+        recyclerView.setAdapter(focusableAdapter);
+
+        mLayoutManager = new WrappedLinearLayoutManager(getActivity(), VERTICAL, false);
+        recyclerView.setLayoutManager(mLayoutManager);
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().addView(recyclerView);
+            }
+        });
+        mLayoutManager.waitForLayout(3);
+
+        int width = recyclerView.getWidth();
+        int height = recyclerView.getHeight();
+        final int widthMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
+        final int fullHeightMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
+        // "MinusOne" so that a measure call will appropriately trigger onMeasure after RecyclerView
+        // was previously laid out with the full height version.
+        final int fullHeightMinusOneMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(height - 1, View.MeasureSpec.AT_MOST);
+        final int halfHeightMeasureSpec =
+                View.MeasureSpec.makeMeasureSpec(height / 2, View.MeasureSpec.AT_MOST);
+
+        // Act 1.
+
+        View toFocus = findLastFullyVisibleChild(recyclerView);
+        int focusIndex = recyclerView.getChildAdapterPosition(toFocus);
+
+        requestFocus(toFocus, false);
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+                recyclerView.layout(
+                        0,
+                        0,
+                        recyclerView.getMeasuredWidth(),
+                        recyclerView.getMeasuredHeight());
+            }
+        });
+        mLayoutManager.waitForLayout(3);
+
+        // Verify 1.
+
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.hasFocus(), is(true));
+        // Testing for partial visibility instead of full visibility since TextView calls
+        // requestRectangleOnScreen (inside bringPointIntoView) for the focused view with a rect
+        // containing the content area. This rect is guaranteed to be fully visible whereas a
+        // portion of TextView could be out of bounds.
+        assertThat("Child view at adapter pos " + focusIndex + " should be fully visible.",
+                isViewPartiallyInBound(recyclerView, toFocus), is(true));
+
+        // Act 2.
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.measure(widthMeasureSpec, fullHeightMeasureSpec);
+                recyclerView.layout(
+                        0,
+                        0,
+                        recyclerView.getMeasuredWidth(),
+                        recyclerView.getMeasuredHeight());
+            }
+        });
+        mLayoutManager.waitForLayout(3);
+
+        // Verify 2.
+
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.hasFocus(), is(true));
+        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
+                isViewPartiallyInBound(recyclerView, toFocus));
+
+        // Act 3.
+
+        // Now focus on the first fully visible EditText.
+        toFocus = findFirstFullyVisibleChild(recyclerView);
+        focusIndex = recyclerView.getChildAdapterPosition(toFocus);
+
+        requestFocus(toFocus, false);
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
+                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
+                recyclerView.layout(
+                        0,
+                        0,
+                        recyclerView.getMeasuredWidth(),
+                        recyclerView.getMeasuredHeight());
+            }
+        });
+        mLayoutManager.waitForLayout(3);
+
+        // Assert 3.
+
+        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
+                isViewPartiallyInBound(recyclerView, toFocus));
+    }
+
+    @Test
+    public void topUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of child views that can be visible at any time.
+        final int visibleChildCount = 5;
+        final int consecutiveFocusablesCount = 2;
+        final int consecutiveUnFocusablesCount = 18;
+        final TestAdapter adapter = new TestAdapter(
+                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
+            RecyclerView mAttachedRv;
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                // Good to have colors for debugging
+                StateListDrawable stl = new StateListDrawable();
+                stl.addState(new int[]{android.R.attr.state_focused},
+                        new ColorDrawable(Color.RED));
+                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                //noinspection deprecation used to support kitkat tests
+                testViewHolder.itemView.setBackgroundDrawable(stl);
+                return testViewHolder;
+            }
+
+            @Override
+            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                mAttachedRv = recyclerView;
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (position < consecutiveFocusablesCount) {
+                    holder.itemView.setFocusable(true);
+                    holder.itemView.setFocusableInTouchMode(true);
+                } else {
+                    holder.itemView.setFocusable(false);
+                    holder.itemView.setFocusableInTouchMode(false);
+                }
+                // This height ensures that some portion of #visibleChildCount'th child is
+                // off-bounds, creating more interesting test scenario.
+                holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
+                        + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
+            }
+        };
+        setupByConfig(new Config(VERTICAL, false, false).adapter(adapter).reverseLayout(true),
+                false);
+        waitForFirstLayout();
+
+        // adapter position of the currently focused item.
+        int focusIndex = 0;
+        View newFocused = mRecyclerView.getChildAt(focusIndex);
+        requestFocus(newFocused, true);
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.itemView.hasFocus(), is(true));
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = 0;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        // Navigate up through the focusable and unfocusable chunks. The focusable items should
+        // become focused one by one until hitting the last focusable item, at which point,
+        // unfocusable items should become visible on the screen until the currently focused item
+        // stays on the screen.
+        for (int i = 0; i < adapter.getItemCount(); i++) {
+            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_UP, true);
+            // adapter position of the currently focused item.
+            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
+            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
+                    (visibleIndex + 1));
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    @Test
+    public void bottomUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of child views that can be visible at any time.
+        final int visibleChildCount = 5;
+        final int consecutiveFocusablesCount = 2;
+        final int consecutiveUnFocusablesCount = 18;
+        final TestAdapter adapter = new TestAdapter(
+                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
+            RecyclerView mAttachedRv;
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                // Good to have colors for debugging
+                StateListDrawable stl = new StateListDrawable();
+                stl.addState(new int[]{android.R.attr.state_focused},
+                        new ColorDrawable(Color.RED));
+                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                //noinspection deprecation used to support kitkat tests
+                testViewHolder.itemView.setBackgroundDrawable(stl);
+                return testViewHolder;
+            }
+
+            @Override
+            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                mAttachedRv = recyclerView;
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (position < consecutiveFocusablesCount) {
+                    holder.itemView.setFocusable(true);
+                    holder.itemView.setFocusableInTouchMode(true);
+                } else {
+                    holder.itemView.setFocusable(false);
+                    holder.itemView.setFocusableInTouchMode(false);
+                }
+                // This height ensures that some portion of #visibleChildCount'th child is
+                // off-bounds, creating more interesting test scenario.
+                holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
+                        + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
+            }
+        };
+        setupByConfig(new Config(VERTICAL, false, false).adapter(adapter), false);
+        waitForFirstLayout();
+
+        // adapter position of the currently focused item.
+        int focusIndex = 0;
+        View newFocused = mRecyclerView.getChildAt(focusIndex);
+        requestFocus(newFocused, true);
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.itemView.hasFocus(), is(true));
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = 0;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        // Navigate down through the focusable and unfocusable chunks. The focusable items should
+        // become focused one by one until hitting the last focusable item, at which point,
+        // unfocusable items should become visible on the screen until the currently focused item
+        // stays on the screen.
+        for (int i = 0; i < adapter.getItemCount(); i++) {
+            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
+            // adapter position of the currently focused item.
+            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
+            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
+                    (visibleIndex + 1));
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    @Test
+    public void leftUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of child views that can be visible at any time.
+        final int visibleChildCount = 5;
+        final int consecutiveFocusablesCount = 2;
+        final int consecutiveUnFocusablesCount = 18;
+        final TestAdapter adapter = new TestAdapter(
+                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
+            RecyclerView mAttachedRv;
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                // Good to have colors for debugging
+                StateListDrawable stl = new StateListDrawable();
+                stl.addState(new int[]{android.R.attr.state_focused},
+                        new ColorDrawable(Color.RED));
+                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                //noinspection deprecation used to support kitkat tests
+                testViewHolder.itemView.setBackgroundDrawable(stl);
+                return testViewHolder;
+            }
+
+            @Override
+            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                mAttachedRv = recyclerView;
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (position < consecutiveFocusablesCount) {
+                    holder.itemView.setFocusable(true);
+                    holder.itemView.setFocusableInTouchMode(true);
+                } else {
+                    holder.itemView.setFocusable(false);
+                    holder.itemView.setFocusableInTouchMode(false);
+                }
+                // This width ensures that some portion of #visibleChildCount'th child is
+                // off-bounds, creating more interesting test scenario.
+                holder.itemView.setMinimumWidth((mAttachedRv.getWidth()
+                        + mAttachedRv.getWidth() / (2 * visibleChildCount)) / visibleChildCount);
+            }
+        };
+        setupByConfig(new Config(HORIZONTAL, false, false).adapter(adapter).reverseLayout(true),
+                false);
+        waitForFirstLayout();
+
+        // adapter position of the currently focused item.
+        int focusIndex = 0;
+        View newFocused = mRecyclerView.getChildAt(focusIndex);
+        requestFocus(newFocused, true);
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.itemView.hasFocus(), is(true));
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = 0;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        // Navigate left through the focusable and unfocusable chunks. The focusable items should
+        // become focused one by one until hitting the last focusable item, at which point,
+        // unfocusable items should become visible on the screen until the currently focused item
+        // stays on the screen.
+        for (int i = 0; i < adapter.getItemCount(); i++) {
+            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_LEFT, true);
+            // adapter position of the currently focused item.
+            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
+            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
+                    (visibleIndex + 1));
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    @Test
+    public void rightUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of child views that can be visible at any time.
+        final int visibleChildCount = 5;
+        final int consecutiveFocusablesCount = 2;
+        final int consecutiveUnFocusablesCount = 18;
+        final TestAdapter adapter = new TestAdapter(
+                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
+            RecyclerView mAttachedRv;
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                // Good to have colors for debugging
+                StateListDrawable stl = new StateListDrawable();
+                stl.addState(new int[]{android.R.attr.state_focused},
+                        new ColorDrawable(Color.RED));
+                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                //noinspection deprecation used to support kitkat tests
+                testViewHolder.itemView.setBackgroundDrawable(stl);
+                return testViewHolder;
+            }
+
+            @Override
+            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                mAttachedRv = recyclerView;
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (position < consecutiveFocusablesCount) {
+                    holder.itemView.setFocusable(true);
+                    holder.itemView.setFocusableInTouchMode(true);
+                } else {
+                    holder.itemView.setFocusable(false);
+                    holder.itemView.setFocusableInTouchMode(false);
+                }
+                // This width ensures that some portion of #visibleChildCount'th child is
+                // off-bounds, creating more interesting test scenario.
+                holder.itemView.setMinimumWidth((mAttachedRv.getWidth()
+                        + mAttachedRv.getWidth() / (2 * visibleChildCount)) / visibleChildCount);
+            }
+        };
+        setupByConfig(new Config(HORIZONTAL, false, false).adapter(adapter), false);
+        waitForFirstLayout();
+
+        // adapter position of the currently focused item.
+        int focusIndex = 0;
+        View newFocused = mRecyclerView.getChildAt(focusIndex);
+        requestFocus(newFocused, true);
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.itemView.hasFocus(), is(true));
+
+        // adapter position of the item (whether focusable or not) that just becomes fully
+        // visible after focusSearch.
+        int visibleIndex = 0;
+        // The VH of the above adapter position
+        RecyclerView.ViewHolder toVisible = null;
+
+        // Navigate right through the focusable and unfocusable chunks. The focusable items should
+        // become focused one by one until hitting the last focusable item, at which point,
+        // unfocusable items should become visible on the screen until the currently focused item
+        // stays on the screen.
+        for (int i = 0; i < adapter.getItemCount(); i++) {
+            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_RIGHT, true);
+            // adapter position of the currently focused item.
+            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
+            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
+            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
+                    (visibleIndex + 1));
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
+
+            assertThat("Child at position " + focusIndex + " should be focused",
+                    toFocus.itemView.hasFocus(), is(true));
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
+            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    // Run this test on Jelly Bean and newer because clearFocus on API 15 will call
+    // requestFocus in ViewRootImpl when clearChildFocus is called. Whereas, in API 16 and above,
+    // this call is delayed until after onFocusChange callback is called. Thus on API 16+, there's a
+    // transient state of no child having focus during which onFocusChange is executed. This
+    // transient state does not exist on API 15-.
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+    @Test
+    public void unfocusableScrollingWhenFocusCleared() throws Throwable {
+        // The maximum number of child views that can be visible at any time.
+        final int visibleChildCount = 5;
+        final int consecutiveFocusablesCount = 2;
+        final int consecutiveUnFocusablesCount = 18;
+        final TestAdapter adapter = new TestAdapter(
+                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
+            RecyclerView mAttachedRv;
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                // Good to have colors for debugging
+                StateListDrawable stl = new StateListDrawable();
+                stl.addState(new int[]{android.R.attr.state_focused},
+                        new ColorDrawable(Color.RED));
+                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                //noinspection deprecation used to support kitkat tests
+                testViewHolder.itemView.setBackgroundDrawable(stl);
+                return testViewHolder;
+            }
+
+            @Override
+            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                mAttachedRv = recyclerView;
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (position < consecutiveFocusablesCount) {
+                    holder.itemView.setFocusable(true);
+                    holder.itemView.setFocusableInTouchMode(true);
+                } else {
+                    holder.itemView.setFocusable(false);
+                    holder.itemView.setFocusableInTouchMode(false);
+                }
+                // This height ensures that some portion of #visibleChildCount'th child is
+                // off-bounds, creating more interesting test scenario.
+                holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
+                        + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
+            }
+        };
+        setupByConfig(new Config(VERTICAL, false, false).adapter(adapter), false);
+        waitForFirstLayout();
+
+        // adapter position of the currently focused item.
+        int focusIndex = 0;
+        View newFocused = mRecyclerView.getChildAt(focusIndex);
+        requestFocus(newFocused, true);
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        assertThat("Child at position " + focusIndex + " should be focused",
+                toFocus.itemView.hasFocus(), is(true));
+
+        final View nextView = focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
+        focusIndex++;
+        assertThat("Child at position " + focusIndex + " should be focused",
+                mRecyclerView.findViewHolderForAdapterPosition(focusIndex).itemView.hasFocus(),
+                is(true));
+        final CountDownLatch focusLatch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                nextView.setOnFocusChangeListener(new View.OnFocusChangeListener(){
+                    @Override
+                    public void onFocusChange(View v, boolean hasFocus) {
+                        assertNull("Focus just got cleared and no children should be holding"
+                                + " focus now.", mRecyclerView.getFocusedChild());
+                        try {
+                            // Calling focusSearch should be a no-op here since even though there
+                            // are unfocusable views down to scroll to, none of RV's children hold
+                            // focus at this stage.
+                            View focusedChild  = focusSearch(v, View.FOCUS_DOWN, true);
+                            assertNull("Calling focusSearch should be no-op when no children hold"
+                                    + "focus", focusedChild);
+                            // No scrolling should have happened, so any unfocusables that were
+                            // invisible should still be invisible.
+                            RecyclerView.ViewHolder unforcusablePartiallyVisibleChild =
+                                    mRecyclerView.findViewHolderForAdapterPosition(
+                                            visibleChildCount - 1);
+                            assertFalse("Child view at adapter pos " + (visibleChildCount - 1)
+                                            + " should not be fully visible.",
+                                    isViewFullyInBound(mRecyclerView,
+                                            unforcusablePartiallyVisibleChild.itemView));
+                        } catch (Throwable t) {
+                            postExceptionToInstrumentation(t);
+                        }
+                    }
+                });
+                nextView.clearFocus();
+                focusLatch.countDown();
+            }
+        });
+        assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
+        assertThat("Child at position " + focusIndex + " should no longer be focused",
+                mRecyclerView.findViewHolderForAdapterPosition(focusIndex).itemView.hasFocus(),
+                is(false));
+    }
+
+    @Test
+    public void removeAnchorItem() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(VERTICAL).stackFromBottom(false).reverseLayout(
+                        false), 100, 0);
+    }
+
+    @Test
+    public void removeAnchorItemReverse() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(VERTICAL).stackFromBottom(false).reverseLayout(true), 100,
+                0);
+    }
+
+    @Test
+    public void removeAnchorItemStackFromEnd() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(VERTICAL).stackFromBottom(true).reverseLayout(false), 100,
+                99);
+    }
+
+    @Test
+    public void removeAnchorItemStackFromEndAndReverse() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(VERTICAL).stackFromBottom(true).reverseLayout(true), 100,
+                99);
+    }
+
+    @Test
+    public void removeAnchorItemHorizontal() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(HORIZONTAL).stackFromBottom(false).reverseLayout(
+                        false), 100, 0);
+    }
+
+    @Test
+    public void removeAnchorItemReverseHorizontal() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(HORIZONTAL).stackFromBottom(false).reverseLayout(true),
+                100, 0);
+    }
+
+    @Test
+    public void removeAnchorItemStackFromEndHorizontal() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(HORIZONTAL).stackFromBottom(true).reverseLayout(false),
+                100, 99);
+    }
+
+    @Test
+    public void removeAnchorItemStackFromEndAndReverseHorizontal() throws Throwable {
+        removeAnchorItemTest(
+                new Config().orientation(HORIZONTAL).stackFromBottom(true).reverseLayout(true), 100,
+                99);
+    }
+
+    /**
+     * This tests a regression where predictive animations were not working as expected when the
+     * first item is removed and there aren't any more items to add from that direction.
+     * First item refers to the default anchor item.
+     */
+    public void removeAnchorItemTest(final Config config, int adapterSize,
+            final int removePos) throws Throwable {
+        config.adapter(new TestAdapter(adapterSize) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+                if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
+                    lp = new ViewGroup.MarginLayoutParams(0, 0);
+                    holder.itemView.setLayoutParams(lp);
+                }
+                ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
+                final int maxSize;
+                if (config.mOrientation == HORIZONTAL) {
+                    maxSize = mRecyclerView.getWidth();
+                    mlp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+                } else {
+                    maxSize = mRecyclerView.getHeight();
+                    mlp.width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+                }
+
+                final int desiredSize;
+                if (position == removePos) {
+                    // make it large
+                    desiredSize = maxSize / 4;
+                } else {
+                    // make it small
+                    desiredSize = maxSize / 8;
+                }
+                if (config.mOrientation == HORIZONTAL) {
+                    mlp.width = desiredSize;
+                } else {
+                    mlp.height = desiredSize;
+                }
+            }
+        });
+        setupByConfig(config, true);
+        final int childCount = mLayoutManager.getChildCount();
+        RecyclerView.ViewHolder toBeRemoved = null;
+        List<RecyclerView.ViewHolder> toBeMoved = new ArrayList<RecyclerView.ViewHolder>();
+        for (int i = 0; i < childCount; i++) {
+            View child = mLayoutManager.getChildAt(i);
+            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
+            if (holder.getAdapterPosition() == removePos) {
+                toBeRemoved = holder;
+            } else {
+                toBeMoved.add(holder);
+            }
+        }
+        assertNotNull("test sanity", toBeRemoved);
+        assertEquals("test sanity", childCount - 1, toBeMoved.size());
+        LoggingItemAnimator loggingItemAnimator = new LoggingItemAnimator();
+        mRecyclerView.setItemAnimator(loggingItemAnimator);
+        loggingItemAnimator.reset();
+        loggingItemAnimator.expectRunPendingAnimationsCall(1);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(removePos, 1);
+        mLayoutManager.waitForLayout(1);
+        loggingItemAnimator.waitForPendingAnimationsCall(2);
+        assertTrue("removed child should receive remove animation",
+                loggingItemAnimator.mRemoveVHs.contains(toBeRemoved));
+        for (RecyclerView.ViewHolder vh : toBeMoved) {
+            assertTrue("view holder should be in moved list",
+                    loggingItemAnimator.mMoveVHs.contains(vh));
+        }
+        List<RecyclerView.ViewHolder> newHolders = new ArrayList<RecyclerView.ViewHolder>();
+        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
+            View child = mLayoutManager.getChildAt(i);
+            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
+            if (toBeRemoved != holder && !toBeMoved.contains(holder)) {
+                newHolders.add(holder);
+            }
+        }
+        assertTrue("some new children should show up for the new space", newHolders.size() > 0);
+        assertEquals("no items should receive animate add since they are not new", 0,
+                loggingItemAnimator.mAddVHs.size());
+        for (RecyclerView.ViewHolder holder : newHolders) {
+            assertTrue("new holder should receive a move animation",
+                    loggingItemAnimator.mMoveVHs.contains(holder));
+        }
+        assertTrue("control against adding too many children due to bad layout state preparation."
+                        + " initial:" + childCount + ", current:" + mRecyclerView.getChildCount(),
+                mRecyclerView.getChildCount() <= childCount + 3 /*1 for removed view, 2 for its size*/);
+    }
+
+    void waitOneCycle() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+            }
+        });
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    @Test
+    public void hiddenNoneRemoveViewAccessibility() throws Throwable {
+        final Config config = new Config();
+        int adapterSize = 1000;
+        final boolean[] firstItemSpecialSize = new boolean[] {false};
+        TestAdapter adapter = new TestAdapter(adapterSize) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+                if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
+                    lp = new ViewGroup.MarginLayoutParams(0, 0);
+                    holder.itemView.setLayoutParams(lp);
+                }
+                ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
+                final int maxSize;
+                if (config.mOrientation == HORIZONTAL) {
+                    maxSize = mRecyclerView.getWidth();
+                    mlp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+                } else {
+                    maxSize = mRecyclerView.getHeight();
+                    mlp.width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
+                }
+
+                final int desiredSize;
+                if (position == 0 && firstItemSpecialSize[0]) {
+                    desiredSize = maxSize / 3;
+                } else {
+                    desiredSize = maxSize / 8;
+                }
+                if (config.mOrientation == HORIZONTAL) {
+                    mlp.width = desiredSize;
+                } else {
+                    mlp.height = desiredSize;
+                }
+            }
+
+            @Override
+            public void onBindViewHolder(TestViewHolder holder,
+                    int position, List<Object> payloads) {
+                onBindViewHolder(holder, position);
+            }
+        };
+        adapter.setHasStableIds(false);
+        config.adapter(adapter);
+        setupByConfig(config, true);
+        final DummyItemAnimator itemAnimator = new DummyItemAnimator();
+        mRecyclerView.setItemAnimator(itemAnimator);
+
+        // push last item out by increasing first item's size
+        final int childBeingPushOut = mLayoutManager.getChildCount() - 1;
+        RecyclerView.ViewHolder itemViewHolder = mRecyclerView
+                .findViewHolderForAdapterPosition(childBeingPushOut);
+        final int originalAccessibility = ViewCompat.getImportantForAccessibility(
+                itemViewHolder.itemView);
+        assertTrue(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO == originalAccessibility
+                || ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES == originalAccessibility);
+
+        itemAnimator.expect(DummyItemAnimator.MOVE_START, 1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                firstItemSpecialSize[0] = true;
+                mTestAdapter.notifyItemChanged(0, "XXX");
+            }
+        });
+        // wait till itemAnimator starts which will block itemView's accessibility
+        itemAnimator.waitFor(DummyItemAnimator.MOVE_START);
+        // RV Changes accessiblity after onMoveStart, so wait one more cycle.
+        waitOneCycle();
+        assertTrue(itemAnimator.getMovesAnimations().contains(itemViewHolder));
+        assertEquals(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+                ViewCompat.getImportantForAccessibility(itemViewHolder.itemView));
+
+        // notify Change again to run predictive animation.
+        mLayoutManager.expectLayouts(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTestAdapter.notifyItemChanged(0, "XXX");
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                itemAnimator.endAnimations();
+            }
+        });
+        // scroll to the view being pushed out, it should get same view from cache as the item
+        // in adapter does not change.
+        smoothScrollToPosition(childBeingPushOut);
+        RecyclerView.ViewHolder itemViewHolder2 = mRecyclerView
+                .findViewHolderForAdapterPosition(childBeingPushOut);
+        assertSame(itemViewHolder, itemViewHolder2);
+        // the important for accessibility should be reset to YES/AUTO:
+        final int newAccessibility = ViewCompat.getImportantForAccessibility(
+                itemViewHolder.itemView);
+        assertTrue(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO == newAccessibility
+                || ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES == newAccessibility);
+    }
+
+    @Test
+    public void layoutFrozenBug70402422() throws Throwable {
+        final Config config = new Config();
+        TestAdapter adapter = new TestAdapter(2);
+        adapter.setHasStableIds(false);
+        config.adapter(adapter);
+        setupByConfig(config, true);
+        final DummyItemAnimator itemAnimator = new DummyItemAnimator();
+        mRecyclerView.setItemAnimator(itemAnimator);
+
+        final View firstItemView = mRecyclerView
+                .findViewHolderForAdapterPosition(0).itemView;
+
+        itemAnimator.expect(DummyItemAnimator.REMOVE_START, 1);
+        mTestAdapter.deleteAndNotify(1, 1);
+        itemAnimator.waitFor(DummyItemAnimator.REMOVE_START);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setLayoutFrozen(true);
+            }
+        });
+        // requestLayout during item animation, which should be eaten by setLayoutFrozen(true)
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                firstItemView.requestLayout();
+            }
+        });
+        assertTrue(firstItemView.isLayoutRequested());
+        assertFalse(mRecyclerView.isLayoutRequested());
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                itemAnimator.endAnimations();
+            }
+        });
+        // When setLayoutFrozen(false), the firstItemView should run a layout pass and clear
+        // isLayoutRequested() flag.
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setLayoutFrozen(false);
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        assertFalse(firstItemView.isLayoutRequested());
+        assertFalse(mRecyclerView.isLayoutRequested());
+    }
+
+    @Test
+    public void keepFocusOnRelayout() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, false).itemCount(500), true);
+        int center = (mLayoutManager.findLastVisibleItemPosition()
+                - mLayoutManager.findFirstVisibleItemPosition()) / 2;
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(center);
+        final int top = mLayoutManager.mOrientationHelper.getDecoratedStart(vh.itemView);
+        requestFocus(vh.itemView, true);
+        assertTrue("view should have the focus", vh.itemView.hasFocus());
+        // add a bunch of items right before that view, make sure it keeps its position
+        mLayoutManager.expectLayouts(2);
+        final int childCountToAdd = mRecyclerView.getChildCount() * 2;
+        mTestAdapter.addAndNotify(center, childCountToAdd);
+        center += childCountToAdd; // offset item
+        mLayoutManager.waitForLayout(2);
+        mLayoutManager.waitForAnimationsToEnd(20);
+        final RecyclerView.ViewHolder postVH = mRecyclerView.findViewHolderForLayoutPosition(center);
+        assertNotNull("focused child should stay in layout", postVH);
+        assertSame("same view holder should be kept for unchanged child", vh, postVH);
+        assertEquals("focused child's screen position should stay unchanged", top,
+                mLayoutManager.mOrientationHelper.getDecoratedStart(postVH.itemView));
+    }
+
+    @Test
+    public void keepFullFocusOnResize() throws Throwable {
+        keepFocusOnResizeTest(new Config(VERTICAL, false, false).itemCount(500), true);
+    }
+
+    @Test
+    public void keepPartialFocusOnResize() throws Throwable {
+        keepFocusOnResizeTest(new Config(VERTICAL, false, false).itemCount(500), false);
+    }
+
+    @Test
+    public void keepReverseFullFocusOnResize() throws Throwable {
+        keepFocusOnResizeTest(new Config(VERTICAL, true, false).itemCount(500), true);
+    }
+
+    @Test
+    public void keepReversePartialFocusOnResize() throws Throwable {
+        keepFocusOnResizeTest(new Config(VERTICAL, true, false).itemCount(500), false);
+    }
+
+    @Test
+    public void keepStackFromEndFullFocusOnResize() throws Throwable {
+        keepFocusOnResizeTest(new Config(VERTICAL, false, true).itemCount(500), true);
+    }
+
+    @Test
+    public void keepStackFromEndPartialFocusOnResize() throws Throwable {
+        keepFocusOnResizeTest(new Config(VERTICAL, false, true).itemCount(500), false);
+    }
+
+    public void keepFocusOnResizeTest(final Config config, boolean fullyVisible) throws Throwable {
+        setupByConfig(config, true);
+        final int targetPosition;
+        if (config.mStackFromEnd) {
+            targetPosition = mLayoutManager.findFirstVisibleItemPosition();
+        } else {
+            targetPosition = mLayoutManager.findLastVisibleItemPosition();
+        }
+        final OrientationHelper helper = mLayoutManager.mOrientationHelper;
+        final RecyclerView.ViewHolder vh = mRecyclerView
+                .findViewHolderForLayoutPosition(targetPosition);
+
+        // scroll enough to offset the child
+        int startMargin = helper.getDecoratedStart(vh.itemView) -
+                helper.getStartAfterPadding();
+        int endMargin = helper.getEndAfterPadding() -
+                helper.getDecoratedEnd(vh.itemView);
+        Log.d(TAG, "initial start margin " + startMargin + " , end margin:" + endMargin);
+        requestFocus(vh.itemView, true);
+        assertTrue("view should gain the focus", vh.itemView.hasFocus());
+        // scroll enough to offset the child
+        startMargin = helper.getDecoratedStart(vh.itemView) -
+                helper.getStartAfterPadding();
+        endMargin = helper.getEndAfterPadding() -
+                helper.getDecoratedEnd(vh.itemView);
+
+        Log.d(TAG, "start margin " + startMargin + " , end margin:" + endMargin);
+        assertTrue("View should become fully visible", startMargin >= 0 && endMargin >= 0);
+
+        int expectedOffset = 0;
+        boolean offsetAtStart = false;
+        if (!fullyVisible) {
+            // move it a bit such that it is no more fully visible
+            final int childSize = helper
+                    .getDecoratedMeasurement(vh.itemView);
+            expectedOffset = childSize / 3;
+            if (startMargin < endMargin) {
+                scrollBy(expectedOffset);
+                offsetAtStart = true;
+            } else {
+                scrollBy(-expectedOffset);
+                offsetAtStart = false;
+            }
+            startMargin = helper.getDecoratedStart(vh.itemView) -
+                    helper.getStartAfterPadding();
+            endMargin = helper.getEndAfterPadding() -
+                    helper.getDecoratedEnd(vh.itemView);
+            assertTrue("test sanity, view should not be fully visible", startMargin < 0
+                    || endMargin < 0);
+        }
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final ViewGroup.LayoutParams layoutParams = mRecyclerView.getLayoutParams();
+                if (config.mOrientation == HORIZONTAL) {
+                    layoutParams.width = mRecyclerView.getWidth() / 2;
+                } else {
+                    layoutParams.height = mRecyclerView.getHeight() / 2;
+                }
+                mRecyclerView.setLayoutParams(layoutParams);
+            }
+        });
+        Thread.sleep(100);
+        // add a bunch of items right before that view, make sure it keeps its position
+        mLayoutManager.waitForLayout(2);
+        mLayoutManager.waitForAnimationsToEnd(20);
+        assertTrue("view should preserve the focus", vh.itemView.hasFocus());
+        final RecyclerView.ViewHolder postVH = mRecyclerView
+                .findViewHolderForLayoutPosition(targetPosition);
+        assertNotNull("focused child should stay in layout", postVH);
+        assertSame("same view holder should be kept for unchanged child", vh, postVH);
+        View focused = postVH.itemView;
+
+        startMargin = helper.getDecoratedStart(focused) - helper.getStartAfterPadding();
+        endMargin = helper.getEndAfterPadding() - helper.getDecoratedEnd(focused);
+
+        assertTrue("focused child should be somewhat visible",
+                helper.getDecoratedStart(focused) < helper.getEndAfterPadding()
+                        && helper.getDecoratedEnd(focused) > helper.getStartAfterPadding());
+        if (fullyVisible) {
+            assertTrue("focused child end should stay fully visible",
+                    endMargin >= 0);
+            assertTrue("focused child start should stay fully visible",
+                    startMargin >= 0);
+        } else {
+            if (offsetAtStart) {
+                assertTrue("start should preserve its offset", startMargin < 0);
+                assertTrue("end should be visible", endMargin >= 0);
+            } else {
+                assertTrue("end should preserve its offset", endMargin < 0);
+                assertTrue("start should be visible", startMargin >= 0);
+            }
+        }
+    }
+
+    @Test
+    public void scrollToPositionWithPredictive() throws Throwable {
+        scrollToPositionWithPredictive(0, LinearLayoutManager.INVALID_OFFSET);
+        removeRecyclerView();
+        scrollToPositionWithPredictive(3, 20);
+        removeRecyclerView();
+        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2,
+                LinearLayoutManager.INVALID_OFFSET);
+        removeRecyclerView();
+        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2, 10);
+    }
+
+    @Test
+    public void recycleDuringAnimations() throws Throwable {
+        final AtomicInteger childCount = new AtomicInteger(0);
+        final TestAdapter adapter = new TestAdapter(300) {
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                final int cnt = childCount.incrementAndGet();
+                final TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                if (DEBUG) {
+                    Log.d(TAG, "CHILD_CNT(create):" + cnt + ", " + testViewHolder);
+                }
+                return testViewHolder;
+            }
+        };
+        setupByConfig(new Config(VERTICAL, false, false).itemCount(300)
+                .adapter(adapter), true);
+
+        final RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool() {
+            @Override
+            public void putRecycledView(RecyclerView.ViewHolder scrap) {
+                super.putRecycledView(scrap);
+                int cnt = childCount.decrementAndGet();
+                if (DEBUG) {
+                    Log.d(TAG, "CHILD_CNT(put):" + cnt + ", " + scrap);
+                }
+            }
+
+            @Override
+            public RecyclerView.ViewHolder getRecycledView(int viewType) {
+                final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType);
+                if (recycledView != null) {
+                    final int cnt = childCount.incrementAndGet();
+                    if (DEBUG) {
+                        Log.d(TAG, "CHILD_CNT(get):" + cnt + ", " + recycledView);
+                    }
+                }
+                return recycledView;
+            }
+        };
+        pool.setMaxRecycledViews(mTestAdapter.getItemViewType(0), 500);
+        mRecyclerView.setRecycledViewPool(pool);
+
+
+        // now keep adding children to trigger more children being created etc.
+        for (int i = 0; i < 100; i ++) {
+            adapter.addAndNotify(15, 1);
+            Thread.sleep(15);
+        }
+        getInstrumentation().waitForIdleSync();
+        waitForAnimations(2);
+        assertEquals("Children count should add up", childCount.get(),
+                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
+
+        // now trigger lots of add again, followed by a scroll to position
+        for (int i = 0; i < 100; i ++) {
+            adapter.addAndNotify(5 + (i % 3) * 3, 1);
+            Thread.sleep(25);
+        }
+        smoothScrollToPosition(mLayoutManager.findLastVisibleItemPosition() + 20);
+        waitForAnimations(2);
+        getInstrumentation().waitForIdleSync();
+        assertEquals("Children count should add up", childCount.get(),
+                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
+    }
+
+
+    @Test
+    public void dontRecycleChildrenOnDetach() throws Throwable {
+        setupByConfig(new Config().recycleChildrenOnDetach(false), true);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                int recyclerSize = mRecyclerView.mRecycler.getRecycledViewPool().size();
+                ((ViewGroup)mRecyclerView.getParent()).removeView(mRecyclerView);
+                assertEquals("No views are recycled", recyclerSize,
+                        mRecyclerView.mRecycler.getRecycledViewPool().size());
+            }
+        });
+    }
+
+    @Test
+    public void recycleChildrenOnDetach() throws Throwable {
+        setupByConfig(new Config().recycleChildrenOnDetach(true), true);
+        final int childCount = mLayoutManager.getChildCount();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                int recyclerSize = mRecyclerView.mRecycler.getRecycledViewPool().size();
+                mRecyclerView.mRecycler.getRecycledViewPool().setMaxRecycledViews(
+                        mTestAdapter.getItemViewType(0), recyclerSize + childCount);
+                ((ViewGroup)mRecyclerView.getParent()).removeView(mRecyclerView);
+                assertEquals("All children should be recycled", childCount + recyclerSize,
+                        mRecyclerView.mRecycler.getRecycledViewPool().size());
+            }
+        });
+    }
+
+    @Test
+    public void scrollAndClear() throws Throwable {
+        setupByConfig(new Config(), true);
+
+        assertTrue("Children not laid out", mLayoutManager.collectChildCoordinates().size() > 0);
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mLayoutManager.scrollToPositionWithOffset(1, 0);
+                mTestAdapter.clearOnUIThread();
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+
+        assertEquals("Remaining children", 0, mLayoutManager.collectChildCoordinates().size());
+    }
+
+
+    @Test
+    public void accessibilityPositions() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, false), true);
+        final AccessibilityDelegateCompat delegateCompat = mRecyclerView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityEvent event = AccessibilityEvent.obtain();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityEvent(mRecyclerView, event);
+            }
+        });
+        assertEquals("result should have first position",
+                event.getFromIndex(),
+                mLayoutManager.findFirstVisibleItemPosition());
+        assertEquals("result should have last position",
+                event.getToIndex(),
+                mLayoutManager.findLastVisibleItemPosition());
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerWrapContentTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LinearLayoutManagerWrapContentWithAspectRatioTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/LoggingItemAnimator.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/LoggingItemAnimator.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/LoggingItemAnimator.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
new file mode 100644
index 0000000..ee08e98
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+@RunWith(AndroidJUnit4.class)
+public class MultiRecyclerViewPrefetchTest {
+    private RecyclerView.RecycledViewPool mRecycledViewPool;
+    private ArrayList<RecyclerView> mViews = new ArrayList<>();
+
+    private long mMockNanoTime = 0;
+
+    @Before
+    public void setup() throws Exception {
+        GapWorker gapWorker = GapWorker.sGapWorker.get();
+        if (gapWorker != null) {
+            assertTrue(gapWorker.mRecyclerViews.isEmpty());
+        }
+        mMockNanoTime = 0;
+        mRecycledViewPool = new RecyclerView.RecycledViewPool();
+    }
+
+    @After
+    public void teardown() {
+        for (RecyclerView rv : mViews) {
+            if (rv.isAttachedToWindow()) {
+                // ensure we detach views, so ThreadLocal GapWorker's list is cleared
+                rv.onDetachedFromWindow();
+            }
+        }
+        GapWorker gapWorker = GapWorker.sGapWorker.get();
+        if (gapWorker != null) {
+            assertTrue(gapWorker.mRecyclerViews.isEmpty());
+        }
+        mViews.clear();
+    }
+
+    private RecyclerView createRecyclerView() {
+        RecyclerView rv = new RecyclerView(getContext()) {
+            @Override
+            long getNanoTime() {
+                return mMockNanoTime;
+            }
+
+            @Override
+            public int getWindowVisibility() {
+                // Pretend to be visible to avoid being filtered out
+                return View.VISIBLE;
+            }
+        };
+
+        // shared stats + enable clearing of pool
+        rv.setRecycledViewPool(mRecycledViewPool);
+
+        // enable GapWorker
+        rv.onAttachedToWindow();
+        mViews.add(rv);
+
+        return rv;
+    }
+
+    public void registerTimePassingMs(long ms) {
+        mMockNanoTime += TimeUnit.MILLISECONDS.toNanos(ms);
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+
+    private void clearCachesAndPool() {
+        for (RecyclerView rv : mViews) {
+            rv.mRecycler.recycleAndClearCachedViews();
+        }
+        mRecycledViewPool.clear();
+    }
+
+    @Test
+    public void prefetchOrdering() throws Throwable {
+        for (int i = 0; i < 3; i++) {
+            RecyclerView rv = createRecyclerView();
+
+            // first view 50x100 pixels, rest are 100x100 so second column is offset
+            rv.setAdapter(new RecyclerView.Adapter() {
+                @NonNull
+                @Override
+                public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                        int viewType) {
+                    registerTimePassingMs(5);
+                    return new RecyclerView.ViewHolder(new View(parent.getContext())) {};
+                }
+
+                @Override
+                public void onBindViewHolder(
+                        @NonNull RecyclerView.ViewHolder holder, int position) {
+                    registerTimePassingMs(5);
+                    holder.itemView.setMinimumWidth(100);
+                    holder.itemView.setMinimumHeight(position == 0 ? 50 : 100);
+                }
+
+                @Override
+                public int getItemCount() {
+                    return 100;
+                }
+            });
+            rv.setLayoutManager(
+                    new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
+
+            // Attach, position 200x200 view at 100 scroll offset, with an empty cache.
+            rv.measure(View.MeasureSpec.AT_MOST | 200, View.MeasureSpec.AT_MOST | 200);
+            rv.layout(0, 0, 200, 200);
+            rv.scrollBy(0, 100);
+
+            rv.setTranslationX(100 * i);
+        }
+
+        GapWorker worker = GapWorker.sGapWorker.get();
+        assertNotNull(worker);
+
+        /* Each row is 50 pixels:
+         * ------------- *
+         *   0   |   1   *
+         *___2___|___1___*
+         *   2   |   3   *
+         *   4   |   3   *
+         *   4   |   5   *
+         *___6___|___5___*
+         *   6   |   7   *
+         *   8   |   7   *
+         *      ...      *
+         */
+
+        mViews.get(0).mPrefetchRegistry.setPrefetchVector(0, 10);
+        mViews.get(1).mPrefetchRegistry.setPrefetchVector(0, -11);
+        mViews.get(2).mPrefetchRegistry.setPrefetchVector(0, 60);
+
+        // prefetch with deadline that has passed - only demand-loaded views
+        clearCachesAndPool();
+        worker.prefetch(0);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(0), 7);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(1), 1);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(2), 7, 8);
+
+
+        // prefetch with 54ms - should load demand-loaded views (taking 40ms) + one more
+        clearCachesAndPool();
+        worker.prefetch(mMockNanoTime + TimeUnit.MILLISECONDS.toNanos(54));
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(0), 7);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(1), 0, 1);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(2), 7, 8);
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/PagerSnapHelperTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/PagerSnapHelperTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/PagerSnapHelperTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/PagerSnapHelperTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecycledViewPoolTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecycledViewPoolTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecycledViewPoolTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecycledViewPoolTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
new file mode 100644
index 0000000..b746092
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewAccessibilityLifecycleTest extends BaseRecyclerViewInstrumentationTest {
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+    @Test
+    public void dontDispatchChangeDuringLayout() throws Throwable {
+        LayoutAllLayoutManager lm = new LayoutAllLayoutManager();
+        final AtomicBoolean calledA11DuringLayout = new AtomicBoolean(false);
+        final List<Integer> invocations = new ArrayList<>();
+
+        final WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity()) {
+            @Override
+            boolean isAccessibilityEnabled() {
+                return true;
+            }
+
+            @Override
+            public boolean setChildImportantForAccessibilityInternal(ViewHolder viewHolder,
+                    int importantForAccessibilityBeforeHidden) {
+                invocations.add(importantForAccessibilityBeforeHidden);
+                boolean notified = super.setChildImportantForAccessibilityInternal(viewHolder,
+                        importantForAccessibilityBeforeHidden);
+                if (notified && mRecyclerView.isComputingLayout()) {
+                    calledA11DuringLayout.set(true);
+                }
+                return notified;
+            }
+        };
+        TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
+                ViewCompat.setImportantForAccessibility(vh.itemView,
+                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+                return vh;
+            }
+        };
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(1);
+        assertThat(calledA11DuringLayout.get(), is(false));
+        lm.expectLayouts(1);
+        adapter.deleteAndNotify(2, 2);
+        lm.waitForLayout(2);
+        recyclerView.waitUntilAnimations();
+        assertThat(invocations, is(Arrays.asList(
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES)));
+
+        assertThat(calledA11DuringLayout.get(), is(false));
+    }
+
+    @LargeTest
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+    @Test
+    public void processAllViewHolders() {
+        RecyclerView rv = new RecyclerView(getActivity());
+        rv.setLayoutManager(new LinearLayoutManager(getActivity()));
+        View itemView1 = spy(new View(getActivity()));
+        View itemView2 = spy(new View(getActivity()));
+        View itemView3 = spy(new View(getActivity()));
+
+        rv.addView(itemView1);
+        // do not add 2
+        rv.addView(itemView3);
+
+        RecyclerView.ViewHolder vh1 = new RecyclerView.ViewHolder(itemView1) {};
+        vh1.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+        RecyclerView.ViewHolder vh2 = new RecyclerView.ViewHolder(itemView2) {};
+        vh2.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+        RecyclerView.ViewHolder vh3 = new RecyclerView.ViewHolder(itemView3) {};
+        vh3.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+
+        rv.mPendingAccessibilityImportanceChange.add(vh1);
+        rv.mPendingAccessibilityImportanceChange.add(vh2);
+        rv.mPendingAccessibilityImportanceChange.add(vh3);
+        rv.dispatchPendingImportantForAccessibilityChanges();
+
+        verify(itemView1).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        //noinspection WrongConstant
+        verify(itemView2, never()).setImportantForAccessibility(anyInt());
+        verify(itemView3).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+        assertThat(rv.mPendingAccessibilityImportanceChange.size(), is(0));
+    }
+
+    public class LayoutAllLayoutManager extends TestLayoutManager {
+        private final boolean mAllowNullLayoutLatch;
+
+        public LayoutAllLayoutManager() {
+            // by default, we don't allow unexpected layouts.
+            this(false);
+        }
+        LayoutAllLayoutManager(boolean allowNullLayoutLatch) {
+            mAllowNullLayoutLatch = allowNullLayoutLatch;
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            detachAndScrapAttachedViews(recycler);
+            layoutRange(recycler, 0, state.getItemCount());
+            if (!mAllowNullLayoutLatch || layoutLatch != null) {
+                layoutLatch.countDown();
+            }
+        }
+    }
+
+    @Test
+    public void notClearCustomViewDelegate() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity()) {
+            @Override
+            boolean isAccessibilityEnabled() {
+                return true;
+            }
+        };
+        final int[] layoutStart = new int[] {0};
+        final int layoutCount = 5;
+        final TestLayoutManager layoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                removeAndRecycleScrapInt(recycler);
+                layoutRange(recycler, layoutStart[0], layoutStart[0] + layoutCount);
+                if (layoutLatch != null) {
+                    layoutLatch.countDown();
+                }
+            }
+        };
+        final AccessibilityDelegateCompat delegateCompat = new AccessibilityDelegateCompat() {
+            @Override
+            public void onInitializeAccessibilityNodeInfo(View host,
+                    AccessibilityNodeInfoCompat info) {
+                super.onInitializeAccessibilityNodeInfo(host, info);
+                info.setChecked(true);
+            }
+        };
+        final TestAdapter adapter = new TestAdapter(100) {
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
+                ViewCompat.setAccessibilityDelegate(vh.itemView, delegateCompat);
+                return vh;
+            }
+        };
+        layoutManager.expectLayouts(1);
+        recyclerView.getRecycledViewPool().setMaxRecycledViews(0, 100);
+        recyclerView.setItemViewCacheSize(0); // no cache, directly goes to pool
+        recyclerView.setLayoutManager(layoutManager);
+        setRecyclerView(recyclerView);
+         mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.setAdapter(adapter);
+            }
+        });
+        layoutManager.waitForLayout(1);
+
+        assertEquals(layoutCount, recyclerView.getChildCount());
+        final ArrayList<View> children = new ArrayList();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < recyclerView.getChildCount(); i++) {
+                    View view = recyclerView.getChildAt(i);
+                    assertEquals(layoutStart[0] + i,
+                            recyclerView.getChildAdapterPosition(view));
+                    AccessibilityNodeInfo info = recyclerView.getChildAt(i)
+                            .createAccessibilityNodeInfo();
+                    assertTrue("custom delegate sets isChecked", info.isChecked());
+                    assertFalse(recyclerView.findContainingViewHolder(view).hasAnyOfTheFlags(
+                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
+                    assertTrue(ViewCompat.hasAccessibilityDelegate(view));
+                    children.add(view);
+                }
+            }
+        });
+
+        // invalidate and start layout at 50, all existing views will goes to recycler and
+        // being reused.
+        layoutStart[0] = 50;
+        layoutManager.expectLayouts(1);
+        adapter.dispatchDataSetChanged();
+        layoutManager.waitForLayout(1);
+        assertEquals(layoutCount, recyclerView.getChildCount());
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < recyclerView.getChildCount(); i++) {
+                    View view = recyclerView.getChildAt(i);
+                    assertEquals(layoutStart[0] + i,
+                            recyclerView.getChildAdapterPosition(view));
+                    assertTrue(children.contains(view));
+                    AccessibilityNodeInfo info = view.createAccessibilityNodeInfo();
+                    assertTrue("custom delegate sets isChecked", info.isChecked());
+                    assertFalse(recyclerView.findContainingViewHolder(view).hasAnyOfTheFlags(
+                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
+                    assertTrue(ViewCompat.hasAccessibilityDelegate(view));
+                }
+            }
+        });
+    }
+
+    @Test
+    public void clearItemDelegateWhenGoesToPool() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity()) {
+            @Override
+            boolean isAccessibilityEnabled() {
+                return true;
+            }
+        };
+        final int firstPassLayoutCount = 5;
+        final int[] layoutCount = new int[] {firstPassLayoutCount};
+        final TestLayoutManager layoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                removeAndRecycleScrapInt(recycler);
+                layoutRange(recycler, 0, layoutCount[0]);
+                if (layoutLatch != null) {
+                    layoutLatch.countDown();
+                }
+            }
+        };
+        final TestAdapter adapter = new TestAdapter(100);
+        layoutManager.expectLayouts(1);
+        recyclerView.getRecycledViewPool().setMaxRecycledViews(0, 100);
+        recyclerView.setItemViewCacheSize(0); // no cache, directly goes to pool
+        recyclerView.setLayoutManager(layoutManager);
+        setRecyclerView(recyclerView);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.setAdapter(adapter);
+            }
+        });
+        layoutManager.waitForLayout(1);
+
+        assertEquals(firstPassLayoutCount, recyclerView.getChildCount());
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < recyclerView.getChildCount(); i++) {
+                    View view = recyclerView.getChildAt(i);
+                    assertEquals(i, recyclerView.getChildAdapterPosition(view));
+                    assertTrue(recyclerView.findContainingViewHolder(view).hasAnyOfTheFlags(
+                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
+                    assertTrue(ViewCompat.hasAccessibilityDelegate(view));
+                    AccessibilityNodeInfo info = view.createAccessibilityNodeInfo();
+                    if (Build.VERSION.SDK_INT >= 19) {
+                        assertNotNull(info.getCollectionItemInfo());
+                    }
+                }
+            }
+        });
+
+        // let all items go to recycler pool
+        layoutManager.expectLayouts(1);
+        layoutCount[0] = 0;
+        adapter.resetItemsTo(new ArrayList());
+        layoutManager.waitForLayout(1);
+        assertEquals(0, recyclerView.getChildCount());
+        assertEquals(firstPassLayoutCount, recyclerView.getRecycledViewPool()
+                .getRecycledViewCount(0));
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < firstPassLayoutCount; i++) {
+                    RecyclerView.ViewHolder vh = recyclerView.getRecycledViewPool()
+                            .getRecycledView(0);
+                    View view = vh.itemView;
+                    assertEquals(RecyclerView.NO_POSITION,
+                            recyclerView.getChildAdapterPosition(view));
+                    assertFalse(vh.hasAnyOfTheFlags(
+                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
+                    assertFalse(ViewCompat.hasAccessibilityDelegate(view));
+                }
+            }
+        });
+
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAccessibilityTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAccessibilityTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAnimationsTest.java
new file mode 100644
index 0000000..de31415
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewAnimationsTest.java
@@ -0,0 +1,1772 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.graphics.Rect;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.ViewCompat;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Tests for {@link SimpleItemAnimator} API.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest {
+
+    final List<TestViewHolder> recycledVHs = new ArrayList<>();
+
+    @Test
+    public void keepFocusAfterChangeAnimation() throws Throwable {
+        setupBasic(10, 0, 5, new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                holder.itemView.setFocusableInTouchMode(true);
+            }
+        });
+        ((SimpleItemAnimator)(mRecyclerView.getItemAnimator())).setSupportsChangeAnimations(true);
+
+        final RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForAdapterPosition(3);
+        assertNotNull("test sanity", oldVh);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                oldVh.itemView.requestFocus();
+            }
+        });
+        assertTrue("test sanity", oldVh.itemView.hasFocus());
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.changeAndNotify(3, 1);
+        mLayoutManager.waitForLayout(2);
+
+        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3);
+        assertNotNull("test sanity", newVh);
+        assertNotSame(oldVh, newVh);
+        assertFalse(oldVh.itemView.hasFocus());
+        assertTrue(newVh.itemView.hasFocus());
+    }
+
+    @Test
+    public void changeAndDisappearDontReUseViewHolder() throws Throwable {
+        changeAndDisappearTest(false, false);
+    }
+
+    @Test
+    public void changeAndDisappearReUseViewHolder() throws Throwable {
+        changeAndDisappearTest(true, false);
+    }
+
+    @Test
+    public void changeAndDisappearReUseWithScrapViewHolder() throws Throwable {
+        changeAndDisappearTest(true, true);
+    }
+
+    public void changeAndDisappearTest(final boolean reUse, final boolean useScrap)
+            throws Throwable {
+        final List<RecyclerView.ViewHolder> mRecycled = new ArrayList<>();
+        final TestAdapter adapter = new TestAdapter(1) {
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                super.onViewRecycled(holder);
+                mRecycled.add(holder);
+            }
+        };
+        setupBasic(1, 0, 1, adapter);
+        RecyclerView.ViewHolder vh = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(0));
+        LoggingItemAnimator animator = new LoggingItemAnimator() {
+            @Override
+            public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
+                                                     @NonNull List<Object> payloads) {
+                return reUse;
+            }
+        };
+        mRecyclerView.setItemAnimator(animator);
+        mLayoutManager.expectLayouts(2);
+        final RecyclerView.ViewHolder[] updatedVH = new RecyclerView.ViewHolder[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.notifyItemChanged(0);
+                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+                    @Override
+                    void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
+                                  RecyclerView.State state) {
+                        if (state.isPreLayout()) {
+                            super.doLayout(recycler, lm, state);
+                        } else {
+                            lm.detachAndScrapAttachedViews(recycler);
+                            final View view;
+                            if (reUse && useScrap) {
+                                view = recycler.getScrapViewAt(0);
+                            } else {
+                                view = recycler.getViewForPosition(0);
+                            }
+                            updatedVH[0] = RecyclerView.getChildViewHolderInt(view);
+                            lm.addDisappearingView(view);
+                        }
+                    }
+                };
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+
+        MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateDisappearanceList),
+                CoreMatchers.is(reUse));
+        MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateChangeList),
+                CoreMatchers.is(!reUse));
+        MatcherAssert.assertThat(animator.contains(updatedVH[0], animator.mAnimateChangeList),
+                CoreMatchers.is(!reUse));
+        MatcherAssert.assertThat(animator.contains(updatedVH[0],
+                animator.mAnimateDisappearanceList), CoreMatchers.is(reUse));
+        waitForAnimations(10);
+        MatcherAssert.assertThat(mRecyclerView.getChildCount(), CoreMatchers.is(0));
+        if (useScrap || !reUse) {
+            MatcherAssert.assertThat(mRecycled.contains(vh), CoreMatchers.is(true));
+        } else {
+            MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(vh),
+                    CoreMatchers.is(true));
+        }
+
+        if (!reUse) {
+            MatcherAssert.assertThat(mRecycled.contains(updatedVH[0]), CoreMatchers.is(false));
+            MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(updatedVH[0]),
+                    CoreMatchers.is(true));
+        }
+    }
+
+    @Test
+    public void detectStableIdError() throws Throwable {
+        setIgnoreMainThreadException(true);
+        final AtomicBoolean useBadIds = new AtomicBoolean(false);
+        TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public long getItemId(int position) {
+                if (useBadIds.get() && position == 5) {
+                    return super.getItemId(position) - 1;
+                }
+                return super.getItemId(position);
+            }
+
+            @Override
+            public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
+                // ignore validation
+            }
+        };
+        adapter.setHasStableIds(true);
+        setupBasic(10, 0, 10, adapter);
+        mLayoutManager.expectLayouts(2);
+        useBadIds.set(true);
+        adapter.changeAndNotify(4, 2);
+        mLayoutManager.waitForLayout(2);
+        assertTrue(getMainThreadException() instanceof IllegalStateException);
+        assertTrue(getMainThreadException().getMessage()
+                .contains("Two different ViewHolders have the same stable ID."));
+        // TODO don't use this after moving this class to Junit 4
+        try {
+            removeRecyclerView();
+        } catch (Throwable t){}
+    }
+
+
+    @Test
+    public void dontLayoutReusedViewWithoutPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    final TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+                    @Override
+                    void beforePreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager lm, RecyclerView.State state) {
+                        fail("pre layout is not expected");
+                    }
+
+                    @Override
+                    void beforePostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        mLayoutItemCount = 7;
+                        View targetView = recycler
+                                .getViewForPosition(target.getAdapterPosition());
+                        assertSame(targetView, target.itemView);
+                        super.beforePostLayout(recycler, layoutManager, state);
+                    }
+
+                    @Override
+                    void afterPostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        super.afterPostLayout(recycler, layoutManager, state);
+                        assertNull("test sanity. this view should not be re-laid out in post "
+                                + "layout", target.itemView.getParent());
+                    }
+                };
+                mLayoutManager.expectLayouts(1);
+                mLayoutManager.requestSimpleAnimationsInNextLayout();
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+                checkForMainThreadException();
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                // This is a LayoutManager problem if it asked for the view but didn't properly
+                // lay it out. It will move to disappearance
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                waitForAnimations(5);
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    @Test
+    public void dontLayoutReusedViewWithPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    final TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+                    @Override
+                    void beforePreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager lm, RecyclerView.State state) {
+                        mLayoutItemCount = 9;
+                        super.beforePreLayout(recycler, lm, state);
+                    }
+
+                    @Override
+                    void beforePostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        mLayoutItemCount = 7;
+                        super.beforePostLayout(recycler, layoutManager, state);
+                    }
+
+                    @Override
+                    void afterPostLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        super.afterPostLayout(recycler, layoutManager, state);
+                        assertNull("test sanity. this view should not be re-laid out in post "
+                                + "layout", target.itemView.getParent());
+                    }
+                };
+                mLayoutManager.expectLayouts(2);
+                mTestAdapter.deleteAndNotify(1, 1);
+                mLayoutManager.waitForLayout(2);
+                checkForMainThreadException();
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                // This is a LayoutManager problem if it asked for the view but didn't properly
+                // lay it out. It will move to disappearance.
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                waitForAnimations(5);
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    @Test
+    public void reuseHiddenViewWithoutPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                mLayoutManager.requestSimpleAnimationsInNextLayout();
+                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    @Test
+    public void reuseHiddenViewWithoutAnimations() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    @Test
+    public void reuseHiddenViewWithPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(2);
+                mTestAdapter.deleteAndNotify(2, 1);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                // This LM does not layout the additional item so it does predictive wrong.
+                // We should still handle it and animate persistence for this item
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(itemAnimator.mMoveVHs.contains(target));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    @Test
+    public void reuseHiddenViewWithProperPredictive() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+                    @Override
+                    void beforePreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager lm, RecyclerView.State state) {
+                        mLayoutItemCount = 9;
+                        super.beforePreLayout(recycler, lm, state);
+                    }
+
+                    @Override
+                    void afterPreLayout(RecyclerView.Recycler recycler,
+                            AnimationLayoutManager layoutManager,
+                            RecyclerView.State state) {
+                        mLayoutItemCount = 8;
+                        super.afterPreLayout(recycler, layoutManager, state);
+                    }
+                };
+
+                mLayoutManager.expectLayouts(2);
+                mTestAdapter.deleteAndNotify(2, 1);
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                // This LM implements predictive animations properly by requesting target view
+                // in pre-layout.
+                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(itemAnimator.mMoveVHs.contains(target));
+                assertFalse(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    // Disable this test on ICS because it causes testing devices to freeze.
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+    @Test
+    public void dontReuseHiddenViewOnInvalidate() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                mTestAdapter.dispatchDataSetChanged();
+                mLayoutManager.waitForLayout(2);
+                waitForAnimations(5);
+                assertFalse(mRecyclerView.getItemAnimator().isRunning());
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    @Test
+    public void dontReuseOnTypeChange() throws Throwable {
+        reuseHiddenViewTest(new ReuseTestCallback() {
+            @Override
+            public void postSetup(List<TestViewHolder> recycledList,
+                    TestViewHolder target) throws Throwable {
+                // it should move to change scrap and then show up from there
+                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
+                        .getItemAnimator();
+                itemAnimator.reset();
+                mLayoutManager.expectLayouts(1);
+                target.mBoundItem.mType += 2;
+                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
+                mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1);
+                requestLayoutOnUIThread(mRecyclerView);
+                mLayoutManager.waitForLayout(2);
+
+                assertTrue(itemAnimator.mChangeOldVHs.contains(target));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
+                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
+                assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView));
+                assertFalse(recycledVHs.contains(target));
+                waitForAnimations(5);
+                assertTrue(recycledVHs.contains(target));
+            }
+        });
+    }
+
+    interface ReuseTestCallback {
+
+        void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable;
+    }
+
+    @Override
+    protected RecyclerView.ItemAnimator createItemAnimator() {
+        return new LoggingItemAnimator();
+    }
+
+    public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable {
+        TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                super.onViewRecycled(holder);
+                recycledVHs.add(holder);
+            }
+        };
+        setupBasic(10, 0, 10, adapter);
+        mRecyclerView.setItemViewCacheSize(0);
+        TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9);
+        mRecyclerView.getItemAnimator().setAddDuration(1000);
+        mRecyclerView.getItemAnimator().setRemoveDuration(1000);
+        mRecyclerView.getItemAnimator().setChangeDuration(1000);
+        mRecyclerView.getItemAnimator().setMoveDuration(1000);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
+        mLayoutManager.expectLayouts(2);
+        adapter.deleteAndNotify(2, 1);
+        mLayoutManager.waitForLayout(2);
+        // test sanity, make sure target is hidden now
+        assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView));
+        callback.postSetup(recycledVHs, target);
+        // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN
+        // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED
+        // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION
+
+    }
+
+    @Test
+    public void detachBeforeAnimations() throws Throwable {
+        setupBasic(10, 0, 5);
+        final RecyclerView rv = mRecyclerView;
+        waitForAnimations(2);
+        final DefaultItemAnimator animator = new DefaultItemAnimator() {
+            @Override
+            public void runPendingAnimations() {
+                super.runPendingAnimations();
+            }
+        };
+        rv.setItemAnimator(animator);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(3, 4);
+        mLayoutManager.waitForLayout(2);
+        removeRecyclerView();
+        assertNull("test sanity check RV should be removed", rv.getParent());
+        assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size());
+        assertFalse("there should not be any animations running", animator.isRunning());
+    }
+
+    @Test
+    public void moveDeleted() throws Throwable {
+        setupBasic(4, 0, 3);
+        waitForAnimations(2);
+        final View[] targetChild = new View[1];
+        final LoggingItemAnimator animator = new LoggingItemAnimator();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setItemAnimator(animator);
+                targetChild[0] = mRecyclerView.getChildAt(1);
+            }
+        });
+
+        assertNotNull("test sanity", targetChild);
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
+                    @Override
+                    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                            RecyclerView.State state) {
+                        if (view == targetChild[0]) {
+                            outRect.set(10, 20, 30, 40);
+                        } else {
+                            outRect.set(0, 0, 0, 0);
+                        }
+                    }
+                });
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+
+        // now delete that item.
+        mLayoutManager.expectLayouts(2);
+        RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]);
+        targetChild[0] = null;
+        mTestAdapter.deleteAndNotify(1, 1);
+        mLayoutManager.waitForLayout(2);
+        assertFalse("if deleted view moves, it should not be in move animations",
+                animator.mMoveVHs.contains(targetVH));
+        assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size());
+        assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH
+        ));
+    }
+
+    private void runTestImportantForAccessibilityWhileDeteling(
+            final int boundImportantForAccessibility,
+            final int expectedImportantForAccessibility) throws Throwable {
+        // Adapter binding the item to the initial accessibility option.
+        // RecyclerView is expected to change it to 'expectedImportantForAccessibility'.
+        TestAdapter adapter = new TestAdapter(1) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+                super.onBindViewHolder(holder, position);
+                ViewCompat.setImportantForAccessibility(
+                        holder.itemView, boundImportantForAccessibility);
+            }
+        };
+
+        // Set up with 1 item.
+        setupBasic(1, 0, 1, adapter);
+        waitForAnimations(2);
+        final View[] targetChild = new View[1];
+        final LoggingItemAnimator animator = new LoggingItemAnimator();
+        animator.setRemoveDuration(500);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setItemAnimator(animator);
+                targetChild[0] = mRecyclerView.getChildAt(0);
+                assertEquals(
+                        expectedImportantForAccessibility,
+                        ViewCompat.getImportantForAccessibility(targetChild[0]));
+            }
+        });
+
+        assertNotNull("test sanity", targetChild[0]);
+
+        // now delete that item.
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(0, 1);
+
+        mLayoutManager.waitForLayout(2);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // The view is still a child of mRecyclerView, and is invisible for accessibility.
+                assertTrue(targetChild[0].getParent() == mRecyclerView);
+                assertEquals(
+                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+                        ViewCompat.getImportantForAccessibility(targetChild[0]));
+            }
+        });
+
+        waitForAnimations(2);
+
+        // Delete animation is now complete.
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // The view is in recycled state, and back to the expected accessibility.
+                assertTrue(targetChild[0].getParent() == null);
+                assertEquals(
+                        expectedImportantForAccessibility,
+                        ViewCompat.getImportantForAccessibility(targetChild[0]));
+            }
+        });
+
+        // Add 1 element, which should use same view.
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.addAndNotify(1);
+        mLayoutManager.waitForLayout(2);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // The view should be reused, and have the expected accessibility.
+                assertTrue(
+                        "the item must be reused", targetChild[0] == mRecyclerView.getChildAt(0));
+                assertEquals(
+                        expectedImportantForAccessibility,
+                        ViewCompat.getImportantForAccessibility(targetChild[0]));
+            }
+        });
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    public void importantForAccessibilityWhileDetelingAuto() throws Throwable {
+        runTestImportantForAccessibilityWhileDeteling(
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    public void importantForAccessibilityWhileDetelingNo() throws Throwable {
+        runTestImportantForAccessibilityWhileDeteling(
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable {
+        runTestImportantForAccessibilityWhileDeteling(
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
+    public void importantForAccessibilityWhileDetelingYes() throws Throwable {
+        runTestImportantForAccessibilityWhileDeteling(
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
+                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
+    }
+
+    @Test
+    public void preLayoutPositionCleanup() throws Throwable {
+        setupBasic(4, 0, 4);
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void beforePreLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager lm, RecyclerView.State state) {
+                mLayoutMin = 0;
+                mLayoutItemCount = 3;
+            }
+
+            @Override
+            void beforePostLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager layoutManager,
+                    RecyclerView.State state) {
+                mLayoutMin = 0;
+                mLayoutItemCount = 4;
+            }
+        };
+        mTestAdapter.addAndNotify(0, 1);
+        mLayoutManager.waitForLayout(2);
+
+
+    }
+
+    @Test
+    public void addRemoveSamePass() throws Throwable {
+        final List<RecyclerView.ViewHolder> mRecycledViews
+                = new ArrayList<RecyclerView.ViewHolder>();
+        TestAdapter adapter = new TestAdapter(50) {
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                super.onViewRecycled(holder);
+                mRecycledViews.add(holder);
+            }
+        };
+        adapter.setHasStableIds(true);
+        setupBasic(50, 3, 5, adapter);
+        mRecyclerView.setItemViewCacheSize(0);
+        final ArrayList<RecyclerView.ViewHolder> addVH
+                = new ArrayList<RecyclerView.ViewHolder>();
+        final ArrayList<RecyclerView.ViewHolder> removeVH
+                = new ArrayList<RecyclerView.ViewHolder>();
+
+        final ArrayList<RecyclerView.ViewHolder> moveVH
+                = new ArrayList<RecyclerView.ViewHolder>();
+
+        final View[] testView = new View[1];
+        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
+            @Override
+            public boolean animateAdd(RecyclerView.ViewHolder holder) {
+                addVH.add(holder);
+                return true;
+            }
+
+            @Override
+            public boolean animateRemove(RecyclerView.ViewHolder holder) {
+                removeVH.add(holder);
+                return true;
+            }
+
+            @Override
+            public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY,
+                    int toX, int toY) {
+                moveVH.add(holder);
+                return true;
+            }
+        });
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void afterPreLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager layoutManager,
+                    RecyclerView.State state) {
+                super.afterPreLayout(recycler, layoutManager, state);
+                testView[0] = recycler.getViewForPosition(45);
+                testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST),
+                        View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST));
+                testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(),
+                        10 + testView[0].getMeasuredHeight());
+                layoutManager.addView(testView[0], 4);
+            }
+
+            @Override
+            void afterPostLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager layoutManager,
+                    RecyclerView.State state) {
+                super.afterPostLayout(recycler, layoutManager, state);
+                testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(),
+                        50 + testView[0].getMeasuredHeight());
+                layoutManager.addDisappearingView(testView[0], 4);
+            }
+        };
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5;
+        mRecycledViews.clear();
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(3, 1);
+        mLayoutManager.waitForLayout(2);
+
+        for (RecyclerView.ViewHolder vh : addVH) {
+            assertNotSame("add-remove item should not animate add", testView[0], vh.itemView);
+        }
+        for (RecyclerView.ViewHolder vh : moveVH) {
+            assertNotSame("add-remove item should not animate move", testView[0], vh.itemView);
+        }
+        for (RecyclerView.ViewHolder vh : removeVH) {
+            assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView);
+        }
+        boolean found = false;
+        for (RecyclerView.ViewHolder vh : mRecycledViews) {
+            found |= vh.itemView == testView[0];
+        }
+        assertTrue("added-removed view should be recycled", found);
+    }
+
+    @Test
+    public void tmpRemoveMe() throws Throwable {
+        changeAnimTest(false, false, true, false);
+    }
+
+    @Test
+    public void changeAnimations() throws Throwable {
+        final boolean[] booleans = {true, false};
+        for (boolean supportsChange : booleans) {
+            for (boolean changeType : booleans) {
+                for (boolean hasStableIds : booleans) {
+                    for (boolean deleteSomeItems : booleans) {
+                        changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems);
+                    }
+                    removeRecyclerView();
+                }
+            }
+        }
+    }
+
+    public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType,
+            final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable {
+        final int changedIndex = 3;
+        final int defaultType = 1;
+        final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType);
+        final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim +
+                ", change view type:" + changeType +
+                ", has stable ids:" + hasStableIds +
+                ", delete some items:" + deleteSomeItems;
+        TestAdapter testAdapter = new TestAdapter(10) {
+            @Override
+            public int getItemViewType(int position) {
+                return position == changedIndex ? changedIndexNewType.get() : defaultType;
+            }
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
+                if (DEBUG) {
+                    Log.d(TAG, logPrefix + " onCreateVH" + vh.toString());
+                }
+                return vh;
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (DEBUG) {
+                    Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString());
+                }
+            }
+        };
+        testAdapter.setHasStableIds(hasStableIds);
+        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
+        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
+                supportsChangeAnim);
+
+        final RecyclerView.ViewHolder toBeChangedVH =
+                mRecyclerView.findViewHolderForLayoutPosition(changedIndex);
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void afterPreLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager layoutManager,
+                    RecyclerView.State state) {
+                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
+                        changedIndex);
+                assertTrue(logPrefix + " changed view holder should have correct flag"
+                        , vh.isUpdated());
+            }
+
+            @Override
+            void afterPostLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager layoutManager, RecyclerView.State state) {
+                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
+                        changedIndex);
+                if (supportsChangeAnim) {
+                    assertNotSame(logPrefix + "a new VH should be given if change is supported",
+                            toBeChangedVH, vh);
+                } else if (!changeType && hasStableIds) {
+                    assertSame(logPrefix + "if change animations are not supported but we have "
+                            + "stable ids, same view holder should be returned", toBeChangedVH, vh);
+                }
+                super.beforePostLayout(recycler, layoutManager, state);
+            }
+        };
+        mLayoutManager.expectLayouts(1);
+        if (changeType) {
+            changedIndexNewType.set(defaultType + 1);
+        }
+        if (deleteSomeItems) {
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        mTestAdapter.deleteAndNotify(changedIndex + 2, 1);
+                        mTestAdapter.notifyItemChanged(3);
+                    } catch (Throwable throwable) {
+                        throwable.printStackTrace();
+                    }
+
+                }
+            });
+        } else {
+            mTestAdapter.changeAndNotify(3, 1);
+        }
+
+        mLayoutManager.waitForLayout(2);
+    }
+
+    private void testChangeWithPayload(final boolean supportsChangeAnim,
+            final boolean canReUse, Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind)
+            throws Throwable {
+        final List<Object> expectedPayloads = new ArrayList<Object>();
+        final int changedIndex = 3;
+        TestAdapter testAdapter = new TestAdapter(10) {
+            @Override
+            public int getItemViewType(int position) {
+                return 1;
+            }
+
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
+                if (DEBUG) {
+                    Log.d(TAG, " onCreateVH" + vh.toString());
+                }
+                return vh;
+            }
+
+            @Override
+            public void onBindViewHolder(TestViewHolder holder,
+                    int position, List<Object> payloads) {
+                super.onBindViewHolder(holder, position);
+                if (DEBUG) {
+                    Log.d(TAG, " onBind to " + position + "" + holder.toString());
+                }
+                assertEquals(expectedPayloads, payloads);
+            }
+        };
+        testAdapter.setHasStableIds(false);
+        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
+        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
+            @Override
+            public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
+                    @NonNull List<Object> payloads) {
+                return canReUse && super.canReuseUpdatedViewHolder(viewHolder, payloads);
+            }
+        });
+        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
+                supportsChangeAnim);
+
+        int numTests = notifyPayloads.length;
+        for (int i = 0; i < numTests; i++) {
+            mLayoutManager.expectLayouts(1);
+            expectedPayloads.clear();
+            for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) {
+                expectedPayloads.add(expectedPayloadsInOnBind[i][j]);
+            }
+            final Object[] payloadsToSend = notifyPayloads[i];
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    for (int j = 0; j < payloadsToSend.length; j++) {
+                        mTestAdapter.notifyItemChanged(changedIndex, payloadsToSend[j]);
+                    }
+                }
+            });
+            mLayoutManager.waitForLayout(2);
+            checkForMainThreadException();
+        }
+    }
+
+    @Test
+    public void crossFadingChangeAnimationWithPayload() throws Throwable {
+        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
+        testChangeWithPayload(true, true,
+                new Object[][]{
+                        new Object[]{"abc"},
+                        new Object[]{"abc", null, "cdf"},
+                        new Object[]{"abc", null},
+                        new Object[]{null, "abc"},
+                        new Object[]{"abc", "cdf"}
+                },
+                new Object[][]{
+                        new Object[]{"abc"},
+                        new Object[0],
+                        new Object[0],
+                        new Object[0],
+                        new Object[]{"abc", "cdf"}
+                });
+    }
+
+    @Test
+    public void crossFadingChangeAnimationWithPayloadWithoutReuse() throws Throwable {
+        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
+        testChangeWithPayload(true, false,
+                new Object[][]{
+                        new Object[]{"abc"},
+                        new Object[]{"abc", null, "cdf"},
+                        new Object[]{"abc", null},
+                        new Object[]{null, "abc"},
+                        new Object[]{"abc", "cdf"}
+                },
+                new Object[][]{
+                        new Object[0],
+                        new Object[0],
+                        new Object[0],
+                        new Object[0],
+                        new Object[0]
+                });
+    }
+
+    @Test
+    public void noChangeAnimationWithPayload() throws Throwable {
+        // for Change Animation disabled, payload should match the payloads unless
+        // null payload is fired.
+        testChangeWithPayload(false, true,
+                new Object[][]{
+                        new Object[]{"abc"},
+                        new Object[]{"abc", null, "cdf"},
+                        new Object[]{"abc", null},
+                        new Object[]{null, "abc"},
+                        new Object[]{"abc", "cdf"}
+                },
+                new Object[][]{
+                        new Object[]{"abc"},
+                        new Object[0],
+                        new Object[0],
+                        new Object[0],
+                        new Object[]{"abc", "cdf"}
+                });
+    }
+
+    @Test
+    public void recycleDuringAnimations() throws Throwable {
+        final AtomicInteger childCount = new AtomicInteger(0);
+        final TestAdapter adapter = new TestAdapter(1000) {
+            @Override
+            public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                childCount.incrementAndGet();
+                return super.onCreateViewHolder(parent, viewType);
+            }
+        };
+        setupBasic(1000, 10, 20, adapter);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20;
+
+        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
+            @Override
+            public void putRecycledView(RecyclerView.ViewHolder scrap) {
+                super.putRecycledView(scrap);
+                childCount.decrementAndGet();
+            }
+
+            @Override
+            public RecyclerView.ViewHolder getRecycledView(int viewType) {
+                final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType);
+                if (recycledView != null) {
+                    childCount.incrementAndGet();
+                }
+                return recycledView;
+            }
+        });
+
+        // now keep adding children to trigger more children being created etc.
+        for (int i = 0; i < 100; i++) {
+            adapter.addAndNotify(15, 1);
+            Thread.sleep(50);
+        }
+        getInstrumentation().waitForIdleSync();
+        waitForAnimations(2);
+        assertEquals("Children count should add up", childCount.get(),
+                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
+    }
+
+    @Test
+    public void notifyDataSetChanged() throws Throwable {
+        setupBasic(10, 3, 4);
+        int layoutCount = mLayoutManager.mTotalLayoutCount;
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mTestAdapter.deleteAndNotify(4, 1);
+                    mTestAdapter.dispatchDataSetChanged();
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        getInstrumentation().waitForIdleSync();
+        assertEquals("on notify data set changed, predictive animations should not run",
+                layoutCount + 1, mLayoutManager.mTotalLayoutCount);
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.addAndNotify(4, 2);
+        // make sure animations recover
+        mLayoutManager.waitForLayout(2);
+    }
+
+    @Test
+    public void stableIdNotifyDataSetChanged() throws Throwable {
+        final int itemCount = 20;
+        List<Item> initialSet = new ArrayList<Item>();
+        final TestAdapter adapter = new TestAdapter(itemCount) {
+            @Override
+            public long getItemId(int position) {
+                return mItems.get(position).mId;
+            }
+        };
+        adapter.setHasStableIds(true);
+        initialSet.addAll(adapter.mItems);
+        positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() {
+                    @Override
+                    void onRun(TestAdapter testAdapter) throws Throwable {
+                        Item item5 = adapter.mItems.get(5);
+                        Item item6 = adapter.mItems.get(6);
+                        item5.mAdapterIndex = 6;
+                        item6.mAdapterIndex = 5;
+                        adapter.mItems.remove(5);
+                        adapter.mItems.add(6, item5);
+                        adapter.dispatchDataSetChanged();
+                        //hacky, we support only 1 layout pass
+                        mLayoutManager.layoutLatch.countDown();
+                    }
+                }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
+                PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8),
+                PositionConstraint.scrap(9, -1, 9));
+        // now mix items.
+    }
+
+
+    @Test
+    public void getItemForDeletedView() throws Throwable {
+        getItemForDeletedViewTest(false);
+        getItemForDeletedViewTest(true);
+    }
+
+    public void getItemForDeletedViewTest(boolean stableIds) throws Throwable {
+        final Set<Integer> itemViewTypeQueries = new HashSet<Integer>();
+        final Set<Integer> itemIdQueries = new HashSet<Integer>();
+        TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public int getItemViewType(int position) {
+                itemViewTypeQueries.add(position);
+                return super.getItemViewType(position);
+            }
+
+            @Override
+            public long getItemId(int position) {
+                itemIdQueries.add(position);
+                return mItems.get(position).mId;
+            }
+        };
+        adapter.setHasStableIds(stableIds);
+        setupBasic(10, 0, 10, adapter);
+        assertEquals("getItemViewType for all items should be called", 10,
+                itemViewTypeQueries.size());
+        if (adapter.hasStableIds()) {
+            assertEquals("getItemId should be called when adapter has stable ids", 10,
+                    itemIdQueries.size());
+        } else {
+            assertEquals("getItemId should not be called when adapter does not have stable ids", 0,
+                    itemIdQueries.size());
+        }
+        itemViewTypeQueries.clear();
+        itemIdQueries.clear();
+        mLayoutManager.expectLayouts(2);
+        // delete last two
+        final int deleteStart = 8;
+        final int deleteCount = adapter.getItemCount() - deleteStart;
+        adapter.deleteAndNotify(deleteStart, deleteCount);
+        mLayoutManager.waitForLayout(2);
+        for (int i = 0; i < deleteStart; i++) {
+            assertTrue("getItemViewType for existing item " + i + " should be called",
+                    itemViewTypeQueries.contains(i));
+            if (adapter.hasStableIds()) {
+                assertTrue("getItemId for existing item " + i
+                                + " should be called when adapter has stable ids",
+                        itemIdQueries.contains(i));
+            }
+        }
+        for (int i = deleteStart; i < deleteStart + deleteCount; i++) {
+            assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called",
+                    itemViewTypeQueries.contains(i));
+            if (adapter.hasStableIds()) {
+                assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called",
+                        itemIdQueries.contains(i));
+            }
+        }
+    }
+
+    @Test
+    public void deleteInvisibleMultiStep() throws Throwable {
+        setupBasic(1000, 1, 7);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
+        mLayoutManager.expectLayouts(1);
+        // try to trigger race conditions
+        int targetItemCount = mTestAdapter.getItemCount();
+        for (int i = 0; i < 100; i++) {
+            mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});
+            checkForMainThreadException();
+            targetItemCount -= 2;
+        }
+        // wait until main thread runnables are consumed
+        while (targetItemCount != mTestAdapter.getItemCount()) {
+            Thread.sleep(100);
+        }
+        mLayoutManager.waitForLayout(2);
+    }
+
+    @Test
+    public void addManyMultiStep() throws Throwable {
+        setupBasic(10, 1, 7);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
+        mLayoutManager.expectLayouts(1);
+        // try to trigger race conditions
+        int targetItemCount = mTestAdapter.getItemCount();
+        for (int i = 0; i < 100; i++) {
+            checkForMainThreadException();
+            mTestAdapter.addAndNotify(0, 1);
+            checkForMainThreadException();
+            mTestAdapter.addAndNotify(7, 1);
+            targetItemCount += 2;
+        }
+        checkForMainThreadException();
+        // wait until main thread runnables are consumed
+        while (targetItemCount != mTestAdapter.getItemCount()) {
+            Thread.sleep(100);
+            checkForMainThreadException();
+        }
+        mLayoutManager.waitForLayout(2);
+    }
+
+    @Test
+    public void basicDelete() throws Throwable {
+        setupBasic(10);
+        final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() {
+            @Override
+            public void postDispatchLayout() {
+                // verify this only in first layout
+                assertEquals("deleted views should still be children of RV",
+                        mLayoutManager.getChildCount() + mDeletedViewCount
+                        , mRecyclerView.getChildCount());
+            }
+
+            @Override
+            void afterPreLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager layoutManager,
+                    RecyclerView.State state) {
+                super.afterPreLayout(recycler, layoutManager, state);
+                mLayoutItemCount = 3;
+                mLayoutMin = 0;
+            }
+        };
+        callbacks.mLayoutItemCount = 10;
+        callbacks.setExpectedItemCounts(10, 3);
+        mLayoutManager.setOnLayoutCallbacks(callbacks);
+
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(0, 7);
+        mLayoutManager.waitForLayout(2);
+        callbacks.reset();// when animations end another layout will happen
+    }
+
+
+    @Test
+    public void adapterChangeDuringScrolling() throws Throwable {
+        setupBasic(10);
+        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
+        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
+
+        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
+            @Override
+            void onLayoutChildren(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager lm, RecyclerView.State state) {
+                onLayoutItemCount.set(state.getItemCount());
+                super.onLayoutChildren(recycler, lm, state);
+            }
+
+            @Override
+            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
+                onScrollItemCount.set(state.getItemCount());
+                super.onScroll(dx, recycler, state);
+            }
+        });
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTestAdapter.mItems.remove(5);
+                mTestAdapter.notifyItemRangeRemoved(5, 1);
+                mRecyclerView.scrollBy(0, 100);
+                assertTrue("scrolling while there are pending adapter updates should "
+                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
+                assertEquals("scroll by should be called w/ updated adapter count",
+                        mTestAdapter.mItems.size(), onScrollItemCount.get());
+
+            }
+        });
+    }
+
+    @Test
+    public void notifyDataSetChangedDuringScroll() throws Throwable {
+        setupBasic(10);
+        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
+        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
+
+        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
+            @Override
+            void onLayoutChildren(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager lm, RecyclerView.State state) {
+                onLayoutItemCount.set(state.getItemCount());
+                super.onLayoutChildren(recycler, lm, state);
+            }
+
+            @Override
+            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
+                onScrollItemCount.set(state.getItemCount());
+                super.onScroll(dx, recycler, state);
+            }
+        });
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTestAdapter.mItems.remove(5);
+                mTestAdapter.notifyDataSetChanged();
+                mRecyclerView.scrollBy(0, 100);
+                assertTrue("scrolling while there are pending adapter updates should "
+                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
+                assertEquals("scroll by should be called w/ updated adapter count",
+                        mTestAdapter.mItems.size(), onScrollItemCount.get());
+
+            }
+        });
+    }
+
+    @Test
+    public void addInvisibleAndVisible() throws Throwable {
+        setupBasic(10, 1, 7);
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
+        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible
+        mLayoutManager.waitForLayout(2);
+    }
+
+    @Test
+    public void addInvisible() throws Throwable {
+        setupBasic(10, 1, 7);
+        mLayoutManager.expectLayouts(1);
+        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
+        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0
+        mLayoutManager.waitForLayout(2);
+    }
+
+    @Test
+    public void basicAdd() throws Throwable {
+        setupBasic(10);
+        mLayoutManager.expectLayouts(2);
+        setExpectedItemCounts(10, 13);
+        mTestAdapter.addAndNotify(2, 3);
+        mLayoutManager.waitForLayout(2);
+    }
+
+    // Run this test on Jelly Bean and newer because hasTransientState was introduced in API 16.
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+    @Test
+    public void appCancelAnimationInDetach() throws Throwable {
+        final View[] addedView = new View[2];
+        TestAdapter adapter = new TestAdapter(1) {
+            @Override
+            public void onViewDetachedFromWindow(TestViewHolder holder) {
+                if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView)
+                        && ViewCompat.hasTransientState(holder.itemView)) {
+                    holder.itemView.animate().cancel();
+                }
+                super.onViewDetachedFromWindow(holder);
+            }
+        };
+        // original 1 item
+        setupBasic(1, 0, 1, adapter);
+        mRecyclerView.getItemAnimator().setAddDuration(10000);
+        mLayoutManager.expectLayouts(2);
+        // add 2 items
+        setExpectedItemCounts(1, 3);
+        mTestAdapter.addAndNotify(0, 2);
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        // wait till "add animation" starts
+        int limit = 200;
+        while (addedView[0] == null || addedView[1] == null) {
+            Thread.sleep(100);
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (mRecyclerView.getChildCount() == 3) {
+                        View view = mRecyclerView.getChildAt(0);
+                        if (ViewCompat.hasTransientState(view)) {
+                            addedView[0] = view;
+                        }
+                        view = mRecyclerView.getChildAt(1);
+                        if (ViewCompat.hasTransientState(view)) {
+                            addedView[1] = view;
+                        }
+                    }
+                }
+            });
+            assertTrue("add should start on time", --limit > 0);
+        }
+
+        // Layout from item2, exclude the current adding items
+        mLayoutManager.expectLayouts(1);
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void beforePostLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager layoutManager,
+                    RecyclerView.State state) {
+                mLayoutMin = 2;
+                mLayoutItemCount = 1;
+            }
+        };
+        requestLayoutOnUIThread(mRecyclerView);
+        mLayoutManager.waitForLayout(2);
+    }
+
+    @Test
+    public void adapterChangeFrozen() throws Throwable {
+        setupBasic(10, 1, 7);
+        assertTrue(mRecyclerView.getChildCount() == 7);
+
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
+        freezeLayout(true);
+        mTestAdapter.addAndNotify(0, 1);
+
+        mLayoutManager.assertNoLayout("RV should keep old child during frozen", 2);
+        assertEquals(7, mRecyclerView.getChildCount());
+
+        freezeLayout(false);
+        mLayoutManager.waitForLayout(2);
+        assertEquals("RV should get updated after waken from frozen",
+                8, mRecyclerView.getChildCount());
+    }
+
+    @Test
+    public void removeScrapInvalidate() throws Throwable {
+        setupBasic(10);
+        TestRecyclerView testRecyclerView = getTestRecyclerView();
+        mLayoutManager.expectLayouts(1);
+        testRecyclerView.expectDraw(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTestAdapter.mItems.clear();
+                mTestAdapter.notifyDataSetChanged();
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        testRecyclerView.waitForDraw(2);
+    }
+
+    @Test
+    public void deleteVisibleAndInvisible() throws Throwable {
+        setupBasic(11, 3, 5); //layout items  3 4 5 6 7
+        mLayoutManager.expectLayouts(2);
+        setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list
+        setExpectedItemCounts(9, 8);
+        mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9
+        mLayoutManager.waitForLayout(2);
+    }
+
+    @Test
+    public void findPositionOffset() throws Throwable {
+        setupBasic(10);
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void beforePreLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager lm, RecyclerView.State state) {
+                super.beforePreLayout(recycler, lm, state);
+                // [0,2,4]
+                assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0));
+                assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2));
+                assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4));
+            }
+        };
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    // delete 1
+                    mTestAdapter.deleteAndNotify(1, 1);
+                    // delete 3
+                    mTestAdapter.deleteAndNotify(2, 1);
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+    }
+
+    private void setLayoutRange(int start, int count) {
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count;
+    }
+
+    private void setExpectedItemCounts(int preLayout, int postLayout) {
+        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout);
+    }
+
+    @Test
+    public void deleteInvisible() throws Throwable {
+        setupBasic(10, 1, 7);
+        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
+        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
+        mLayoutManager.expectLayouts(1);
+        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8);
+        mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8
+        mLayoutManager.waitForLayout(2);
+    }
+
+    private CollectPositionResult findByPos(RecyclerView recyclerView,
+            RecyclerView.Recycler recycler, RecyclerView.State state, int position) {
+        View view = recycler.getViewForPosition(position, true);
+        RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
+        if (vh.wasReturnedFromScrap()) {
+            vh.clearReturnedFromScrapFlag(); //keep data consistent.
+            return CollectPositionResult.fromScrap(vh);
+        } else {
+            return CollectPositionResult.fromAdapter(vh);
+        }
+    }
+
+    public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView,
+            RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) {
+        Map<Integer, CollectPositionResult> positionToAdapterMapping
+                = new HashMap<Integer, CollectPositionResult>();
+        for (int position : positions) {
+            if (position < 0) {
+                continue;
+            }
+            positionToAdapterMapping.put(position,
+                    findByPos(recyclerView, recycler, state, position));
+        }
+        return positionToAdapterMapping;
+    }
+
+    @Test
+    public void addDelete2() throws Throwable {
+        positionStatesTest(5, 0, 5, new AdapterOps() {
+                    // 0 1 2 3 4
+                    // 0 1 2 a b 3 4
+                    // 0 1 b 3 4
+                    // pre: 0 1 2 3 4
+                    // pre w/ adap: 0 1 2 b 3 4
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
+                    }
+                }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
+                PositionConstraint.scrap(3, 3, 3)
+        );
+    }
+
+    @Test
+    public void addDelete1() throws Throwable {
+        positionStatesTest(5, 0, 5, new AdapterOps() {
+                    // 0 1 2 3 4
+                    // 0 1 2 a b 3 4
+                    // 0 2 a b 3 4
+                    // 0 c d 2 a b 3 4
+                    // 0 c d 2 a 4
+                    // c d 2 a 4
+                    // pre: 0 1 2 3 4
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
+                                new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
+                    }
+                }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
+                PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1),
+                PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0),
+                PositionConstraint.adapter(1), PositionConstraint.adapter(3)
+        );
+    }
+
+    @Test
+    public void addSameIndexTwice() throws Throwable {
+        positionStatesTest(12, 2, 7, new AdapterOps() {
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
+                                new int[]{11, 1});
+                    }
+                }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
+                PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7),
+                PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12),
+                PositionConstraint.scrap(8, 8, 13)
+        );
+    }
+
+    @Test
+    public void deleteTwice() throws Throwable {
+        positionStatesTest(12, 2, 7, new AdapterOps() {
+                    @Override
+                    void onRun(TestAdapter adapter) throws Throwable {
+                        adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
+                                new int[]{0, 1});// delete item ids 0,2,9,1
+                    }
+                }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
+                PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2),
+                PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5),
+                PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7)
+        );
+    }
+
+
+    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
+            int firstLayoutItemCount, AdapterOps adapterChanges,
+            final PositionConstraint... constraints) throws Throwable {
+        positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null,
+                adapterChanges, constraints);
+    }
+
+    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
+            int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges,
+            final PositionConstraint... constraints) throws Throwable {
+        setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter);
+        mLayoutManager.expectLayouts(2);
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
+                    RecyclerView.State state) {
+                super.beforePreLayout(recycler, lm, state);
+                //harmless
+                lm.detachAndScrapAttachedViews(recycler);
+                final int[] ids = new int[constraints.length];
+                for (int i = 0; i < constraints.length; i++) {
+                    ids[i] = constraints[i].mPreLayoutPos;
+                }
+                Map<Integer, CollectPositionResult> positions
+                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
+                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
+                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
+                    positionLog.append(entry.getKey()).append(":").append(entry.getValue())
+                            .append("\n");
+                }
+                for (PositionConstraint constraint : constraints) {
+                    if (constraint.mPreLayoutPos != -1) {
+                        constraint.validate(state, positions.get(constraint.mPreLayoutPos),
+                                lm.getLog() + positionLog);
+                    }
+                }
+            }
+
+            @Override
+            void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
+                    RecyclerView.State state) {
+                super.beforePostLayout(recycler, lm, state);
+                lm.detachAndScrapAttachedViews(recycler);
+                final int[] ids = new int[constraints.length];
+                for (int i = 0; i < constraints.length; i++) {
+                    ids[i] = constraints[i].mPostLayoutPos;
+                }
+                Map<Integer, CollectPositionResult> positions
+                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
+                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
+                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
+                    positionLog.append(entry.getKey()).append(":")
+                            .append(entry.getValue()).append("\n");
+                }
+                for (PositionConstraint constraint : constraints) {
+                    if (constraint.mPostLayoutPos >= 0) {
+                        constraint.validate(state, positions.get(constraint.mPostLayoutPos),
+                                lm.getLog() + positionLog);
+                    }
+                }
+            }
+        };
+        adapterChanges.run(mTestAdapter);
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        for (PositionConstraint constraint : constraints) {
+            constraint.assertValidate();
+        }
+    }
+
+    @Test
+    public void addThenRecycleRemovedView() throws Throwable {
+        setupBasic(10);
+        final AtomicInteger step = new AtomicInteger(0);
+        final List<RecyclerView.ViewHolder> animateRemoveList
+                = new ArrayList<RecyclerView.ViewHolder>();
+        DefaultItemAnimator animator = new DefaultItemAnimator() {
+            @Override
+            public boolean animateRemove(RecyclerView.ViewHolder holder) {
+                animateRemoveList.add(holder);
+                return super.animateRemove(holder);
+            }
+        };
+        mRecyclerView.setItemAnimator(animator);
+        final List<RecyclerView.ViewHolder> pooledViews = new ArrayList<RecyclerView.ViewHolder>();
+        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
+            @Override
+            public void putRecycledView(RecyclerView.ViewHolder scrap) {
+                pooledViews.add(scrap);
+                super.putRecycledView(scrap);
+            }
+        });
+        final RecyclerView.ViewHolder[] targetVh = new RecyclerView.ViewHolder[1];
+        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
+            @Override
+            void doLayout(RecyclerView.Recycler recycler,
+                    AnimationLayoutManager lm, RecyclerView.State state) {
+                switch (step.get()) {
+                    case 1:
+                        super.doLayout(recycler, lm, state);
+                        if (state.isPreLayout()) {
+                            View view = mLayoutManager.getChildAt(1);
+                            RecyclerView.ViewHolder holder =
+                                    mRecyclerView.getChildViewHolderInt(view);
+                            targetVh[0] = holder;
+                            assertTrue("test sanity", holder.isRemoved());
+                            mLayoutManager.removeAndRecycleView(view, recycler);
+                        }
+                        break;
+                }
+            }
+        };
+        step.set(1);
+        animateRemoveList.clear();
+        mLayoutManager.expectLayouts(2);
+        mTestAdapter.deleteAndNotify(1, 1);
+        mLayoutManager.waitForLayout(2);
+        assertTrue("test sanity, view should be recycled", pooledViews.contains(targetVh[0]));
+        assertTrue("since LM force recycled a view, animate disappearance should not be called",
+                animateRemoveList.isEmpty());
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewBasicTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewBasicTest.java
new file mode 100644
index 0000000..4f29ad3
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewBasicTest.java
@@ -0,0 +1,833 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.recyclerview.test.R;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewBasicTest {
+
+    RecyclerView mRecyclerView;
+
+    @Before
+    public void setUp() throws Exception {
+        mRecyclerView = new RecyclerView(getContext());
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getTargetContext();
+    }
+
+    @Test
+    public void measureWithoutLayoutManager() {
+        measure();
+    }
+
+    private void measure() {
+        mRecyclerView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240);
+    }
+
+    private void layout() {
+        mRecyclerView.layout(0, 0, 320, 320);
+    }
+
+    private void focusSearch() {
+        mRecyclerView.focusSearch(1);
+    }
+
+    @Test
+    public void layoutWithoutAdapter() throws InterruptedException {
+        MockLayoutManager layoutManager = new MockLayoutManager();
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+        assertEquals("layout manager should not be called if there is no adapter attached",
+                0, layoutManager.mLayoutCount);
+    }
+
+    public void setScrollContainer() {
+        assertEquals("RecyclerView should announce itself as scroll container for the IME to "
+                + "handle it properly", true, mRecyclerView.isScrollContainer());
+    }
+
+    @Test
+    public void layoutWithoutLayoutManager() throws InterruptedException {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+    }
+
+    @Test
+    public void focusWithoutLayoutManager() throws InterruptedException {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+        focusSearch();
+    }
+
+    @Test
+    public void scrollWithoutLayoutManager() throws InterruptedException {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+        mRecyclerView.scrollBy(10, 10);
+    }
+
+    @Test
+    public void smoothScrollWithoutLayoutManager() throws InterruptedException {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+        mRecyclerView.smoothScrollBy(10, 10);
+    }
+
+    @Test
+    public void scrollToPositionWithoutLayoutManager() throws InterruptedException {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+        mRecyclerView.scrollToPosition(5);
+    }
+
+    @Test
+    public void smoothScrollToPositionWithoutLayoutManager() throws InterruptedException {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+        mRecyclerView.smoothScrollToPosition(5);
+    }
+
+    @Test
+    public void interceptTouchWithoutLayoutManager() {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+        assertFalse(mRecyclerView.onInterceptTouchEvent(
+                MotionEvent.obtain(SystemClock.uptimeMillis(),
+                        SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10, 10, 0)));
+    }
+
+    @Test
+    public void onTouchWithoutLayoutManager() {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        measure();
+        layout();
+        assertFalse(mRecyclerView.onTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10, 10, 0)));
+    }
+
+    @Test
+    public void layoutSimple() throws InterruptedException {
+        MockLayoutManager layoutManager = new MockLayoutManager();
+        mRecyclerView.setLayoutManager(layoutManager);
+        mRecyclerView.setAdapter(new MockAdapter(3));
+        layout();
+        assertEquals("when both layout manager and activity is set, recycler view should call"
+                + " layout manager's layout method", 1, layoutManager.mLayoutCount);
+    }
+
+    @Test
+    public void observingAdapters() {
+        MockAdapter adapterOld = new MockAdapter(1);
+        mRecyclerView.setAdapter(adapterOld);
+        assertTrue("attached adapter should have observables", adapterOld.hasObservers());
+
+        MockAdapter adapterNew = new MockAdapter(2);
+        mRecyclerView.setAdapter(adapterNew);
+        assertFalse("detached adapter should lose observable", adapterOld.hasObservers());
+        assertTrue("new adapter should have observers", adapterNew.hasObservers());
+
+        mRecyclerView.setAdapter(null);
+        assertNull("adapter should be removed successfully", mRecyclerView.getAdapter());
+        assertFalse("when adapter is removed, observables should be removed too",
+                adapterNew.hasObservers());
+    }
+
+    @Test
+    public void adapterChangeCallbacks() {
+        MockLayoutManager layoutManager = new MockLayoutManager();
+        mRecyclerView.setLayoutManager(layoutManager);
+        MockAdapter adapterOld = new MockAdapter(1);
+        mRecyclerView.setAdapter(adapterOld);
+        layoutManager.assertPrevNextAdapters(null, adapterOld);
+
+        MockAdapter adapterNew = new MockAdapter(2);
+        mRecyclerView.setAdapter(adapterNew);
+        layoutManager.assertPrevNextAdapters("switching adapters should trigger correct callbacks"
+                , adapterOld, adapterNew);
+
+        mRecyclerView.setAdapter(null);
+        layoutManager.assertPrevNextAdapters(
+                "Setting adapter null should trigger correct callbacks",
+                adapterNew, null);
+    }
+
+    @Test
+    public void recyclerOffsetsOnMove() {
+        MockLayoutManager  layoutManager = new MockLayoutManager();
+        final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>();
+        mRecyclerView.setLayoutManager(layoutManager);
+        MockAdapter adapter = new MockAdapter(100) {
+            @Override
+            public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
+                super.onViewRecycled(holder);
+                recycledVhs.add(holder);
+            }
+        };
+        MockViewHolder mvh = new MockViewHolder(new TextView(getContext()));
+        mRecyclerView.setAdapter(adapter);
+        adapter.bindViewHolder(mvh, 20);
+        mRecyclerView.mRecycler.mCachedViews.add(mvh);
+        mRecyclerView.offsetPositionRecordsForRemove(10, 9, false);
+
+        mRecyclerView.offsetPositionRecordsForRemove(11, 1, false);
+        assertEquals(1, recycledVhs.size());
+        assertSame(mvh, recycledVhs.get(0));
+    }
+
+    @Test
+    public void recyclerOffsetsOnAdd() {
+        MockLayoutManager  layoutManager = new MockLayoutManager();
+        final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>();
+        mRecyclerView.setLayoutManager(layoutManager);
+        MockAdapter adapter = new MockAdapter(100) {
+            @Override
+            public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
+                super.onViewRecycled(holder);
+                recycledVhs.add(holder);
+            }
+        };
+        MockViewHolder mvh = new MockViewHolder(new TextView(getContext()));
+        mRecyclerView.setAdapter(adapter);
+        adapter.bindViewHolder(mvh, 20);
+        mRecyclerView.mRecycler.mCachedViews.add(mvh);
+        mRecyclerView.offsetPositionRecordsForRemove(10, 9, false);
+
+        mRecyclerView.offsetPositionRecordsForInsert(15, 10);
+        assertEquals(11, mvh.mPosition);
+    }
+
+    @Test
+    public void savedStateWithStatelessLayoutManager() throws InterruptedException {
+        mRecyclerView.setLayoutManager(new MockLayoutManager() {
+            @Override
+            public Parcelable onSaveInstanceState() {
+                return null;
+            }
+        });
+        mRecyclerView.setAdapter(new MockAdapter(3));
+        Parcel parcel = Parcel.obtain();
+        String parcelSuffix = UUID.randomUUID().toString();
+        Parcelable savedState = mRecyclerView.onSaveInstanceState();
+        savedState.writeToParcel(parcel, 0);
+        parcel.writeString(parcelSuffix);
+
+        // reset position for reading
+        parcel.setDataPosition(0);
+        RecyclerView restored = new RecyclerView(getContext());
+        restored.setLayoutManager(new MockLayoutManager());
+        mRecyclerView.setAdapter(new MockAdapter(3));
+        // restore
+        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
+        restored.onRestoreInstanceState(savedState);
+
+        assertEquals("Parcel reading should not go out of bounds", parcelSuffix,
+                parcel.readString());
+        assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail());
+
+    }
+
+    @Test
+    public void savedState() throws InterruptedException {
+        MockLayoutManager mlm = new MockLayoutManager();
+        mRecyclerView.setLayoutManager(mlm);
+        mRecyclerView.setAdapter(new MockAdapter(3));
+        layout();
+        Parcelable savedState = mRecyclerView.onSaveInstanceState();
+        // we append a suffix to the parcelable to test out of bounds
+        String parcelSuffix = UUID.randomUUID().toString();
+        Parcel parcel = Parcel.obtain();
+        savedState.writeToParcel(parcel, 0);
+        parcel.writeString(parcelSuffix);
+
+        // reset for reading
+        parcel.setDataPosition(0);
+        // re-create
+        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
+
+        RecyclerView restored = new RecyclerView(getContext());
+        MockLayoutManager mlmRestored = new MockLayoutManager();
+        restored.setLayoutManager(mlmRestored);
+        restored.setAdapter(new MockAdapter(3));
+        restored.onRestoreInstanceState(savedState);
+
+        assertEquals("Parcel reading should not go out of bounds", parcelSuffix,
+                parcel.readString());
+        assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail());
+        assertEquals("uuid in layout manager should be preserved properly", mlm.mUuid,
+                mlmRestored.mUuid);
+        assertNotSame("stateless parameter should not be preserved", mlm.mLayoutCount,
+                mlmRestored.mLayoutCount);
+        layout();
+    }
+
+    @Test
+    public void dontSaveChildrenState() throws InterruptedException {
+        MockLayoutManager mlm = new MockLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                View view = recycler.getViewForPosition(0);
+                addView(view);
+                measureChildWithMargins(view, 0, 0);
+                view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
+            }
+        };
+        mRecyclerView.setLayoutManager(mlm);
+        mRecyclerView.setAdapter(new MockAdapter(3) {
+            @NonNull
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                final LoggingView itemView = new LoggingView(parent.getContext());
+                //noinspection ResourceType
+                itemView.setId(3);
+                return new MockViewHolder(itemView);
+            }
+        });
+        measure();
+        layout();
+        View view = mRecyclerView.getChildAt(0);
+        assertNotNull("test sanity", view);
+        LoggingView loggingView = (LoggingView) view;
+        SparseArray<Parcelable> container = new SparseArray<Parcelable>();
+        mRecyclerView.saveHierarchyState(container);
+        assertEquals("children's save state method should not be called", 0,
+                loggingView.getOnSavedInstanceCnt());
+    }
+
+    @Test
+    public void smoothScrollWithCustomInterpolator() {
+        mRecyclerView.setLayoutManager(new MockLayoutManager());
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        Interpolator interpolator = new LinearInterpolator();
+        mRecyclerView.smoothScrollBy(0, 100, interpolator);
+        assertSame(interpolator, mRecyclerView.mViewFlinger.mInterpolator);
+
+        mRecyclerView.smoothScrollBy(0, -100);
+        assertSame(RecyclerView.sQuinticInterpolator, mRecyclerView.mViewFlinger.mInterpolator);
+    }
+
+    @Test
+    public void createAttachedException() {
+        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
+            @NonNull
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                View view = LayoutInflater.from(parent.getContext())
+                        .inflate(R.layout.item_view, parent, true)
+                        .findViewById(R.id.item_view); // find child, since parent is returned
+                return new RecyclerView.ViewHolder(view) {};
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+                fail("shouldn't get here, should throw during create");
+            }
+
+            @Override
+            public int getItemCount() {
+                return 1;
+            }
+        });
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+
+        try {
+            measure();
+            //layout();
+            fail("IllegalStateException expected");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void prefetchChangesCacheSize() {
+        mRecyclerView.setAdapter(new MockAdapter(20));
+        MockLayoutManager mlm = new MockLayoutManager() {
+            @Override
+            public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
+                    RecyclerView.LayoutManager.LayoutPrefetchRegistry prefetchManager) {
+                prefetchManager.addPosition(0, 0);
+                prefetchManager.addPosition(1, 0);
+                prefetchManager.addPosition(2, 0);
+            }
+        };
+
+        RecyclerView.Recycler recycler = mRecyclerView.mRecycler;
+        assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
+        mRecyclerView.setLayoutManager(mlm);
+        assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // layout, so prefetches can occur
+            mRecyclerView.measure(View.MeasureSpec.EXACTLY | 100, View.MeasureSpec.EXACTLY | 100);
+            mRecyclerView.layout(0, 0, 100, 100);
+
+            // prefetch gets 3 items, so expands cache by 3
+            mRecyclerView.mPrefetchRegistry.collectPrefetchPositionsFromView(mRecyclerView, false);
+            assertEquals(3, mRecyclerView.mPrefetchRegistry.mCount);
+            assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax);
+
+            // Reset to default by removing layout
+            mRecyclerView.setLayoutManager(null);
+            assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
+
+            // And restore by restoring layout
+            mRecyclerView.setLayoutManager(mlm);
+            assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax);
+        }
+    }
+
+    @Test
+    public void getNanoTime() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // check that it looks vaguely time-ish
+            long time = mRecyclerView.getNanoTime();
+            assertNotEquals(0, time);
+            assertNotEquals(time, mRecyclerView.getNanoTime());
+        } else {
+            // expect to avoid cost of system.nanoTime on older platforms that don't do prefetch
+            assertEquals(0, mRecyclerView.getNanoTime());
+        }
+    }
+
+    @Test
+    public void findNestedRecyclerView() {
+        RecyclerView recyclerView = new RecyclerView(getContext());
+        assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(recyclerView));
+
+        ViewGroup parent = new FrameLayout(getContext());
+        assertEquals(null, RecyclerView.findNestedRecyclerView(parent));
+        parent.addView(recyclerView);
+        assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(parent));
+
+        ViewGroup grandParent = new FrameLayout(getContext());
+        assertEquals(null, RecyclerView.findNestedRecyclerView(grandParent));
+        grandParent.addView(parent);
+        assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(grandParent));
+    }
+
+    @Test
+    public void clearNestedRecyclerViewIfNotNested() {
+        RecyclerView recyclerView = new RecyclerView(getContext());
+        ViewGroup parent = new FrameLayout(getContext());
+        parent.addView(recyclerView);
+        ViewGroup grandParent = new FrameLayout(getContext());
+        grandParent.addView(parent);
+
+        // verify trivial noop case
+        RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(recyclerView) {};
+        holder.mNestedRecyclerView = new WeakReference<>(recyclerView);
+        RecyclerView.clearNestedRecyclerViewIfNotNested(holder);
+        assertEquals(recyclerView, holder.mNestedRecyclerView.get());
+
+        // verify clear case
+        holder = new RecyclerView.ViewHolder(new View(getContext())) {};
+        holder.mNestedRecyclerView = new WeakReference<>(recyclerView);
+        RecyclerView.clearNestedRecyclerViewIfNotNested(holder);
+        assertNull(holder.mNestedRecyclerView);
+
+        // verify more deeply nested case
+        holder = new RecyclerView.ViewHolder(grandParent) {};
+        holder.mNestedRecyclerView = new WeakReference<>(recyclerView);
+        RecyclerView.clearNestedRecyclerViewIfNotNested(holder);
+        assertEquals(recyclerView, holder.mNestedRecyclerView.get());
+    }
+
+    @Test
+    public void exceptionContainsClasses() {
+        RecyclerView first = new RecyclerView(getContext());
+        first.setLayoutManager(new LinearLayoutManager(getContext()));
+        first.setAdapter(new MockAdapter(10));
+
+        RecyclerView second = new RecyclerView(getContext());
+        try {
+            second.setLayoutManager(first.getLayoutManager());
+            fail("exception expected");
+        } catch (IllegalArgumentException e) {
+            // Note: exception contains first RV
+            String m = e.getMessage();
+            assertTrue("must contain RV class", m.contains(RecyclerView.class.getName()));
+            assertTrue("must contain Adapter class", m.contains(MockAdapter.class.getName()));
+            assertTrue("must contain LM class", m.contains(LinearLayoutManager.class.getName()));
+            assertTrue("must contain ctx class", m.contains(getContext().getClass().getName()));
+        }
+    }
+
+    @Test
+    public void focusOrderTest() {
+        FocusOrderAdapter focusAdapter = new FocusOrderAdapter(getContext());
+        mRecyclerView.setAdapter(focusAdapter);
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        measure();
+        layout();
+
+        boolean isIcsOrLower = Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;
+
+        // On API 15 and lower, focus forward get's translated to focus down.
+        View expected = isIcsOrLower ? focusAdapter.mBottomRight : focusAdapter.mBottomLeft;
+        assertEquals(expected, focusAdapter.mTopRight.focusSearch(View.FOCUS_FORWARD));
+
+        // On API 15 and lower, focus forward get's translated to focus down, which in this case
+        // runs out of the RecyclerView, thus returning null.
+        expected = isIcsOrLower ? null : focusAdapter.mBottomRight;
+        assertSame(expected, focusAdapter.mBottomLeft.focusSearch(View.FOCUS_FORWARD));
+
+        // we don't want looping within RecyclerView
+        assertNull(focusAdapter.mBottomRight.focusSearch(View.FOCUS_FORWARD));
+        assertNull(focusAdapter.mTopLeft.focusSearch(View.FOCUS_BACKWARD));
+    }
+
+    @Test
+    public void setAdapter_callsCorrectLmMethods() throws Throwable {
+        MockLayoutManager mockLayoutManager = new MockLayoutManager();
+        MockAdapter mockAdapter = new MockAdapter(1);
+        mRecyclerView.setLayoutManager(mockLayoutManager);
+
+        mRecyclerView.setAdapter(mockAdapter);
+        layout();
+
+        assertEquals(1, mockLayoutManager.mAdapterChangedCount);
+        assertEquals(0, mockLayoutManager.mItemsChangedCount);
+    }
+
+    @Test
+    public void swapAdapter_callsCorrectLmMethods() throws Throwable {
+        MockLayoutManager mockLayoutManager = new MockLayoutManager();
+        MockAdapter mockAdapter = new MockAdapter(1);
+        mRecyclerView.setLayoutManager(mockLayoutManager);
+
+        mRecyclerView.swapAdapter(mockAdapter, true);
+        layout();
+
+        assertEquals(1, mockLayoutManager.mAdapterChangedCount);
+        assertEquals(1, mockLayoutManager.mItemsChangedCount);
+    }
+
+    @Test
+    public void notifyDataSetChanged_callsCorrectLmMethods() throws Throwable {
+        MockLayoutManager mockLayoutManager = new MockLayoutManager();
+        MockAdapter mockAdapter = new MockAdapter(1);
+        mRecyclerView.setLayoutManager(mockLayoutManager);
+        mRecyclerView.setAdapter(mockAdapter);
+        mockLayoutManager.mAdapterChangedCount = 0;
+        mockLayoutManager.mItemsChangedCount = 0;
+
+        mockAdapter.notifyDataSetChanged();
+        layout();
+
+        assertEquals(0, mockLayoutManager.mAdapterChangedCount);
+        assertEquals(1, mockLayoutManager.mItemsChangedCount);
+    }
+
+    static class MockLayoutManager extends RecyclerView.LayoutManager {
+
+        int mLayoutCount = 0;
+
+        int mAdapterChangedCount = 0;
+        int mItemsChangedCount = 0;
+
+        RecyclerView.Adapter mPrevAdapter;
+
+        RecyclerView.Adapter mNextAdapter;
+
+        String mUuid = UUID.randomUUID().toString();
+
+        @Override
+        public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
+                RecyclerView.Adapter newAdapter) {
+            super.onAdapterChanged(oldAdapter, newAdapter);
+            mPrevAdapter = oldAdapter;
+            mNextAdapter = newAdapter;
+            mAdapterChangedCount++;
+        }
+
+        @Override
+        public void onItemsChanged(RecyclerView recyclerView) {
+            mItemsChangedCount++;
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            mLayoutCount += 1;
+        }
+
+        @Override
+        public Parcelable onSaveInstanceState() {
+            LayoutManagerSavedState lss = new LayoutManagerSavedState();
+            lss.mUuid = mUuid;
+            return lss;
+        }
+
+        @Override
+        public void onRestoreInstanceState(Parcelable state) {
+            super.onRestoreInstanceState(state);
+            if (state instanceof LayoutManagerSavedState) {
+                mUuid = ((LayoutManagerSavedState) state).mUuid;
+            }
+        }
+
+        @Override
+        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        public void assertPrevNextAdapters(String message, RecyclerView.Adapter prevAdapter,
+                RecyclerView.Adapter nextAdapter) {
+            assertSame(message, prevAdapter, mPrevAdapter);
+            assertSame(message, nextAdapter, mNextAdapter);
+        }
+
+        public void assertPrevNextAdapters(RecyclerView.Adapter prevAdapter,
+                RecyclerView.Adapter nextAdapter) {
+            assertPrevNextAdapters("Adapters from onAdapterChanged callback should match",
+                    prevAdapter, nextAdapter);
+        }
+
+        @Override
+        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            return dx;
+        }
+
+        @Override
+        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            return dy;
+        }
+
+        @Override
+        public boolean canScrollHorizontally() {
+            return true;
+        }
+
+        @Override
+        public boolean canScrollVertically() {
+            return true;
+        }
+    }
+
+    static class LayoutManagerSavedState implements Parcelable {
+
+        String mUuid;
+
+        public LayoutManagerSavedState(Parcel in) {
+            mUuid = in.readString();
+        }
+
+        public LayoutManagerSavedState() {
+
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(mUuid);
+        }
+
+        public static final Parcelable.Creator<LayoutManagerSavedState> CREATOR
+                = new Parcelable.Creator<LayoutManagerSavedState>() {
+            @Override
+            public LayoutManagerSavedState createFromParcel(Parcel in) {
+                return new LayoutManagerSavedState(in);
+            }
+
+            @Override
+            public LayoutManagerSavedState[] newArray(int size) {
+                return new LayoutManagerSavedState[size];
+            }
+        };
+    }
+
+    static class MockAdapter extends RecyclerView.Adapter {
+
+        private int mCount = 0;
+
+
+        MockAdapter(int count) {
+            this.mCount = count;
+        }
+
+        @NonNull
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new MockViewHolder(new TextView(parent.getContext()));
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+
+        }
+
+        @Override
+        public int getItemCount() {
+            return mCount;
+        }
+
+        void removeItems(int start, int count) {
+            mCount -= count;
+            notifyItemRangeRemoved(start, count);
+        }
+
+        void addItems(int start, int count) {
+            mCount += count;
+            notifyItemRangeInserted(start, count);
+        }
+    }
+
+    static class MockViewHolder extends RecyclerView.ViewHolder {
+        public Object mItem;
+        public MockViewHolder(View itemView) {
+            super(itemView);
+        }
+    }
+
+    static class LoggingView extends TextView {
+        private int mOnSavedInstanceCnt = 0;
+
+        public LoggingView(Context context) {
+            super(context);
+        }
+
+        public LoggingView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public LoggingView(Context context, AttributeSet attrs, int defStyleAttr) {
+            super(context, attrs, defStyleAttr);
+        }
+
+        @Override
+        public Parcelable onSaveInstanceState() {
+            mOnSavedInstanceCnt ++;
+            return super.onSaveInstanceState();
+        }
+
+        public int getOnSavedInstanceCnt() {
+            return mOnSavedInstanceCnt;
+        }
+    }
+
+    static class FocusOrderAdapter extends RecyclerView.Adapter {
+        TextView mTopLeft;
+        TextView mTopRight;
+        TextView mBottomLeft;
+        TextView mBottomRight;
+
+        FocusOrderAdapter(Context context) {
+            mTopLeft = new TextView(context);
+            mTopRight = new TextView(context);
+            mBottomLeft = new TextView(context);
+            mBottomRight = new TextView(context);
+            for (TextView tv : new TextView[]{mTopLeft, mTopRight, mBottomLeft, mBottomRight}) {
+                tv.setFocusableInTouchMode(true);
+                tv.setLayoutParams(new LinearLayout.LayoutParams(100, 100));
+            }
+            // create a scenario where the "first" focusable is to the right of the last one
+            mTopLeft.setFocusable(false);
+            mTopRight.getLayoutParams().width = 101;
+            mTopLeft.getLayoutParams().width = 101;
+        }
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            LinearLayout holder = new LinearLayout(parent.getContext());
+            holder.setOrientation(LinearLayout.HORIZONTAL);
+            return new MockViewHolder(holder);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+            LinearLayout l = (LinearLayout) holder.itemView;
+            l.removeAllViews();
+            if (position == 0) {
+                l.addView(mTopLeft);
+                l.addView(mTopRight);
+            } else {
+                l.addView(mBottomLeft);
+                l.addView(mBottomRight);
+            }
+        }
+
+        @Override
+        public int getItemCount() {
+            return 2;
+        }
+
+        void removeItems(int start, int count) {
+        }
+
+        void addItems(int start, int count) {
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewCacheTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewCacheTest.java
new file mode 100644
index 0000000..b38c794
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewCacheTest.java
@@ -0,0 +1,1306 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Build;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewCacheTest {
+    TimeMockingRecyclerView mRecyclerView;
+    RecyclerView.Recycler mRecycler;
+
+    private class TimeMockingRecyclerView extends RecyclerView {
+        private long mMockNanoTime = 0;
+
+        TimeMockingRecyclerView(Context context) {
+            super(context);
+        }
+
+        public void registerTimePassingMs(long ms) {
+            mMockNanoTime += TimeUnit.MILLISECONDS.toNanos(ms);
+        }
+
+        @Override
+        long getNanoTime() {
+            return mMockNanoTime;
+        }
+
+        @Override
+        public int getWindowVisibility() {
+            // Pretend to be visible to avoid being filtered out
+            return View.VISIBLE;
+        }
+    }
+
+    @Before
+    public void setup() throws Exception {
+        mRecyclerView = new TimeMockingRecyclerView(getContext());
+        mRecyclerView.onAttachedToWindow();
+        mRecycler = mRecyclerView.mRecycler;
+    }
+
+    @After
+    public void teardown() throws Exception {
+        if (mRecyclerView.isAttachedToWindow()) {
+            mRecyclerView.onDetachedFromWindow();
+        }
+        GapWorker gapWorker = GapWorker.sGapWorker.get();
+        if (gapWorker != null) {
+            assertTrue(gapWorker.mRecyclerViews.isEmpty());
+        }
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+
+    private void layout(int width, int height) {
+        mRecyclerView.measure(
+                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+        mRecyclerView.layout(0, 0, width, height);
+    }
+
+    @Test
+    public void prefetchReusesCacheItems() {
+        RecyclerView.LayoutManager prefetchingLayoutManager = new RecyclerView.LayoutManager() {
+            @Override
+            public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+                return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+            }
+
+            @Override
+            public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
+                    LayoutPrefetchRegistry prefetchManager) {
+                prefetchManager.addPosition(0, 0);
+                prefetchManager.addPosition(1, 0);
+                prefetchManager.addPosition(2, 0);
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            }
+        };
+        mRecyclerView.setLayoutManager(prefetchingLayoutManager);
+
+        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
+        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
+                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
+                    @Override
+                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
+                            throws Throwable {
+                        return new RecyclerView.ViewHolder(new View(getContext())) {};
+                    }
+                });
+        when(mockAdapter.getItemCount()).thenReturn(10);
+        mRecyclerView.setAdapter(mockAdapter);
+
+        layout(320, 320);
+
+        verify(mockAdapter, never()).onCreateViewHolder(any(ViewGroup.class), anyInt());
+        verify(mockAdapter, never()).onBindViewHolder(
+                any(RecyclerView.ViewHolder.class), anyInt(), any(List.class));
+        assertTrue(mRecycler.mCachedViews.isEmpty());
+
+        // Prefetch multiple times...
+        for (int i = 0; i < 4; i++) {
+            mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+            // ...but should only see the same three items fetched/bound once each
+            verify(mockAdapter, times(3)).onCreateViewHolder(any(ViewGroup.class), anyInt());
+            verify(mockAdapter, times(3)).onBindViewHolder(
+                    any(RecyclerView.ViewHolder.class), anyInt(), any(List.class));
+
+            assertTrue(mRecycler.mCachedViews.size() == 3);
+            CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 0, 1, 2);
+        }
+    }
+
+    @Test
+    public void prefetchItemsNotEvictedWithInserts() {
+        mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
+
+        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
+        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
+                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
+                    @Override
+                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
+                            throws Throwable {
+                        View view = new View(getContext());
+                        view.setMinimumWidth(100);
+                        view.setMinimumHeight(100);
+                        return new RecyclerView.ViewHolder(view) {};
+                    }
+                });
+        when(mockAdapter.getItemCount()).thenReturn(100);
+        mRecyclerView.setAdapter(mockAdapter);
+
+        layout(300, 100);
+
+        assertEquals(2, mRecyclerView.mRecycler.mViewCacheMax);
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        assertEquals(5, mRecyclerView.mRecycler.mViewCacheMax);
+
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 3, 4, 5);
+
+        // further views recycled, as though from scrolling, shouldn't evict prefetched views:
+        mRecycler.recycleView(mRecycler.getViewForPosition(10));
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 10);
+
+        mRecycler.recycleView(mRecycler.getViewForPosition(20));
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 10, 20);
+
+        mRecycler.recycleView(mRecycler.getViewForPosition(30));
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 20, 30);
+
+        mRecycler.recycleView(mRecycler.getViewForPosition(40));
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 30, 40);
+
+        // After clearing the cache, the prefetch priorities should be cleared as well:
+        mRecyclerView.mRecycler.recycleAndClearCachedViews();
+        for (int i : new int[] {3, 4, 5, 50, 60, 70, 80, 90}) {
+            mRecycler.recycleView(mRecycler.getViewForPosition(i));
+        }
+
+        // cache only contains most recent positions, no priority for previous prefetches:
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 50, 60, 70, 80, 90);
+    }
+
+    @Test
+    public void prefetchItemsNotEvictedOnScroll() {
+        mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
+
+        // 100x100 pixel views
+        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
+        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
+                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
+                    @Override
+                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
+                            throws Throwable {
+                        View view = new View(getContext());
+                        view.setMinimumWidth(100);
+                        view.setMinimumHeight(100);
+                        return new RecyclerView.ViewHolder(view) {};
+                    }
+                });
+        when(mockAdapter.getItemCount()).thenReturn(100);
+        mRecyclerView.setAdapter(mockAdapter);
+
+        // NOTE: requested cache size must be smaller than span count so two rows cannot fit
+        mRecyclerView.setItemViewCacheSize(2);
+
+        layout(300, 150);
+        mRecyclerView.scrollBy(0, 75);
+        assertTrue(mRecycler.mCachedViews.isEmpty());
+
+        // rows 0, 1, and 2 are all attached and visible. Prefetch row 3:
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        // row 3 is cached:
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 9, 10, 11);
+        assertTrue(mRecycler.mCachedViews.size() == 3);
+
+        // Scroll so 1 falls off (though 3 is still not on screen)
+        mRecyclerView.scrollBy(0, 50);
+
+        // row 3 is still cached, with a couple other recycled views:
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 9, 10, 11);
+        assertTrue(mRecycler.mCachedViews.size() == 5);
+    }
+
+    @Test
+    public void prefetchIsComputingLayout() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+
+        // 100x100 pixel views
+        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
+        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
+                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
+                    @Override
+                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
+                            throws Throwable {
+                        View view = new View(getContext());
+                        view.setMinimumWidth(100);
+                        view.setMinimumHeight(100);
+                        assertTrue(mRecyclerView.isComputingLayout());
+                        return new RecyclerView.ViewHolder(view) {};
+                    }
+                });
+        when(mockAdapter.getItemCount()).thenReturn(100);
+        mRecyclerView.setAdapter(mockAdapter);
+
+        layout(100, 100);
+
+        verify(mockAdapter, times(1)).onCreateViewHolder(mRecyclerView, 0);
+
+        // prefetch an item, should still observe isComputingLayout in that create
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        verify(mockAdapter, times(2)).onCreateViewHolder(mRecyclerView, 0);
+    }
+
+    @Test
+    public void prefetchAfterOrientationChange() {
+        LinearLayoutManager layout = new LinearLayoutManager(getContext(),
+                LinearLayoutManager.VERTICAL, false);
+        mRecyclerView.setLayoutManager(layout);
+
+        // 100x100 pixel views
+        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
+            @NonNull
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                View view = new View(getContext());
+                view.setMinimumWidth(100);
+                view.setMinimumHeight(100);
+                assertTrue(mRecyclerView.isComputingLayout());
+                return new RecyclerView.ViewHolder(view) {};
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {}
+
+            @Override
+            public int getItemCount() {
+                return 100;
+            }
+        });
+
+        layout(100, 100);
+
+        layout.setOrientation(LinearLayoutManager.HORIZONTAL);
+
+        // Prefetch an item after changing orientation, before layout - shouldn't crash
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(1, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+    }
+
+    @Test
+    public void prefetchDrag() {
+        // event dispatch requires a parent
+        ViewGroup parent = new FrameLayout(getContext());
+        parent.addView(mRecyclerView);
+
+
+        mRecyclerView.setLayoutManager(
+                new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
+
+        // 1000x1000 pixel views
+        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                mRecyclerView.registerTimePassingMs(5);
+                View view = new View(getContext());
+                view.setMinimumWidth(1000);
+                view.setMinimumHeight(1000);
+                return new RecyclerView.ViewHolder(view) {};
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+                mRecyclerView.registerTimePassingMs(5);
+            }
+
+            @Override
+            public int getItemCount() {
+                return 100;
+            }
+        };
+        mRecyclerView.setAdapter(adapter);
+
+        layout(1000, 1000);
+
+        long time = SystemClock.uptimeMillis();
+        mRecyclerView.onTouchEvent(
+                MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 500, 1000, 0));
+
+        assertEquals(0, mRecyclerView.mPrefetchRegistry.mPrefetchDx);
+        assertEquals(0, mRecyclerView.mPrefetchRegistry.mPrefetchDy);
+
+        // Consume slop
+        mRecyclerView.onTouchEvent(
+                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 50, 500, 0));
+
+        // move by 0,30
+        mRecyclerView.onTouchEvent(
+                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 50, 470, 0));
+        assertEquals(0, mRecyclerView.mPrefetchRegistry.mPrefetchDx);
+        assertEquals(30, mRecyclerView.mPrefetchRegistry.mPrefetchDy);
+
+        // move by 10,15
+        mRecyclerView.onTouchEvent(
+                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 40, 455, 0));
+        assertEquals(10, mRecyclerView.mPrefetchRegistry.mPrefetchDx);
+        assertEquals(15, mRecyclerView.mPrefetchRegistry.mPrefetchDy);
+
+        // move by 0,0 - IGNORED
+        mRecyclerView.onTouchEvent(
+                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 40, 455, 0));
+        assertEquals(10, mRecyclerView.mPrefetchRegistry.mPrefetchDx); // same as prev
+        assertEquals(15, mRecyclerView.mPrefetchRegistry.mPrefetchDy); // same as prev
+    }
+
+    @Test
+    public void prefetchItemsRespectDeadline() {
+        mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
+
+        // 100x100 pixel views
+        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                mRecyclerView.registerTimePassingMs(5);
+                View view = new View(getContext());
+                view.setMinimumWidth(100);
+                view.setMinimumHeight(100);
+                return new RecyclerView.ViewHolder(view) {};
+            }
+
+            @Override
+            public void onBindViewHolder(
+                    @NonNull RecyclerView.ViewHolder holder, int position) {
+                mRecyclerView.registerTimePassingMs(5);
+            }
+
+            @Override
+            public int getItemCount() {
+                return 100;
+            }
+        };
+        mRecyclerView.setAdapter(adapter);
+
+        layout(300, 300);
+
+        // offset scroll so that no prefetch-able views are directly adjacent to viewport
+        mRecyclerView.scrollBy(0, 50);
+
+        assertTrue(mRecycler.mCachedViews.size() == 0);
+        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 0);
+
+        // Should take 15 ms to inflate, bind, inflate, so give 19 to be safe
+        final long deadlineNs = mRecyclerView.getNanoTime() + TimeUnit.MILLISECONDS.toNanos(19);
+
+        // Timed prefetch
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(deadlineNs);
+
+        // will have enough time to inflate/bind one view, and inflate another
+        assertTrue(mRecycler.mCachedViews.size() == 1);
+        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 1);
+        // Note: order/view below is an implementation detail
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 12);
+
+
+        // Unbounded prefetch this time
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        // Should finish all work
+        assertTrue(mRecycler.mCachedViews.size() == 3);
+        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 0);
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 12, 13, 14);
+    }
+
+    @Test
+    public void partialPrefetchAvoidsViewRecycledCallback() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+
+        // 100x100 pixel views
+        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                mRecyclerView.registerTimePassingMs(5);
+                View view = new View(getContext());
+                view.setMinimumWidth(100);
+                view.setMinimumHeight(100);
+                return new RecyclerView.ViewHolder(view) {};
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+                mRecyclerView.registerTimePassingMs(5);
+            }
+
+            @Override
+            public int getItemCount() {
+                return 100;
+            }
+
+            @Override
+            public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
+                // verify unbound view doesn't get
+                assertNotEquals(RecyclerView.NO_POSITION, holder.getAdapterPosition());
+            }
+        };
+        mRecyclerView.setAdapter(adapter);
+
+        layout(100, 300);
+
+        // offset scroll so that no prefetch-able views are directly adjacent to viewport
+        mRecyclerView.scrollBy(0, 50);
+
+        assertTrue(mRecycler.mCachedViews.size() == 0);
+        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 0);
+
+        // Should take 10 ms to inflate + bind, so just give it 9 so it doesn't have time to bind
+        final long deadlineNs = mRecyclerView.getNanoTime() + TimeUnit.MILLISECONDS.toNanos(9);
+
+        // Timed prefetch
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(deadlineNs);
+
+        // will have enough time to inflate but not bind one view
+        assertTrue(mRecycler.mCachedViews.size() == 0);
+        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 1);
+        RecyclerView.ViewHolder pooledHolder = mRecyclerView.getRecycledViewPool()
+                .mScrap.get(0).mScrapHeap.get(0);
+        assertEquals(RecyclerView.NO_POSITION, pooledHolder.getAdapterPosition());
+    }
+
+    @Test
+    public void prefetchStaggeredItemsPriority() {
+        StaggeredGridLayoutManager sglm =
+                new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
+        mRecyclerView.setLayoutManager(sglm);
+
+        // first view 50x100 pixels, rest are 100x100 so second column is offset
+        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
+            @NonNull
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                return new RecyclerView.ViewHolder(new View(getContext())) {};
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+                holder.itemView.setMinimumWidth(100);
+                holder.itemView.setMinimumHeight(position == 0 ? 50 : 100);
+            }
+
+            @Override
+            public int getItemCount() {
+                return 100;
+            }
+        });
+
+        layout(200, 200);
+
+        /* Each row is 50 pixels:
+         * ------------- *
+         *   0   |   1   *
+         *   2   |   1   *
+         *   2   |   3   *
+         *___4___|___3___*
+         *   4   |   5   *
+         *   6   |   5   *
+         *      ...      *
+         */
+        assertEquals(5, mRecyclerView.getChildCount());
+        assertEquals(0, sglm.getFirstChildPosition());
+        assertEquals(4, sglm.getLastChildPosition());
+
+        // prefetching down shows 5 at 0 pixels away, 6 at 50 pixels away
+        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, 10,
+                new Integer[] {5, 0}, new Integer[] {6, 50});
+
+        // Prefetch upward shows nothing
+        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, -10);
+
+        mRecyclerView.scrollBy(0, 100);
+
+        /* Each row is 50 pixels:
+         * ------------- *
+         *   0   |   1   *
+         *___2___|___1___*
+         *   2   |   3   *
+         *   4   |   3   *
+         *   4   |   5   *
+         *___6___|___5___*
+         *   6   |   7   *
+         *   8   |   7   *
+         *      ...      *
+         */
+
+        assertEquals(5, mRecyclerView.getChildCount());
+        assertEquals(2, sglm.getFirstChildPosition());
+        assertEquals(6, sglm.getLastChildPosition());
+
+        // prefetching down shows 7 at 0 pixels away, 8 at 50 pixels away
+        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, 10,
+                new Integer[] {7, 0}, new Integer[] {8, 50});
+
+        // prefetching up shows 1 is 0 pixels away, 0 at 50 pixels away
+        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, -10,
+                new Integer[] {1, 0}, new Integer[] {0, 50});
+    }
+
+    @Test
+    public void prefetchStaggeredPastBoundary() {
+        StaggeredGridLayoutManager sglm =
+                new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
+        mRecyclerView.setLayoutManager(sglm);
+        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
+            @NonNull
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                return new RecyclerView.ViewHolder(new View(getContext())) {};
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+                holder.itemView.setMinimumWidth(100);
+                holder.itemView.setMinimumHeight(position == 0 ? 100 : 200);
+            }
+
+            @Override
+            public int getItemCount() {
+                return 2;
+            }
+        });
+
+        layout(200, 100);
+        mRecyclerView.scrollBy(0, 50);
+
+        /* Each row is 50 pixels:
+         * ------------- *
+         *___0___|___1___*
+         *   0   |   1   *
+         *_______|___1___*
+         *       |   1   *
+         */
+        assertEquals(2, mRecyclerView.getChildCount());
+        assertEquals(0, sglm.getFirstChildPosition());
+        assertEquals(1, sglm.getLastChildPosition());
+
+        // prefetch upward gets nothing
+        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, -10);
+
+        // prefetch downward gets nothing (and doesn't crash...)
+        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, 10);
+    }
+
+    @Test
+    public void prefetchItemsSkipAnimations() {
+        LinearLayoutManager llm = new LinearLayoutManager(getContext());
+        mRecyclerView.setLayoutManager(llm);
+        final int[] expandedPosition = new int[] {-1};
+
+        final RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                return new RecyclerView.ViewHolder(new View(parent.getContext())) {};
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+                int height = expandedPosition[0] == position ? 400 : 100;
+                holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(200, height));
+            }
+
+            @Override
+            public int getItemCount() {
+                return 10;
+            }
+        };
+
+        // make move duration long enough to be able to see the effects
+        RecyclerView.ItemAnimator itemAnimator = mRecyclerView.getItemAnimator();
+        itemAnimator.setMoveDuration(10000);
+        mRecyclerView.setAdapter(adapter);
+
+        layout(200, 400);
+
+        expandedPosition[0] = 1;
+        // insert payload to avoid creating a new view
+        adapter.notifyItemChanged(1, new Object());
+
+        layout(200, 400);
+        layout(200, 400);
+
+        assertTrue(itemAnimator.isRunning());
+        assertEquals(2, llm.getChildCount());
+        assertEquals(4, mRecyclerView.getChildCount());
+
+        // animating view should be observable as hidden, uncached...
+        CacheUtils.verifyCacheDoesNotContainPositions(mRecyclerView, 2);
+        assertNotNull("Animating view should be found, hidden",
+                mRecyclerView.mChildHelper.findHiddenNonRemovedView(2));
+        assertTrue(GapWorker.isPrefetchPositionAttached(mRecyclerView, 2));
+
+        // ...but must not be removed for prefetch
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        assertEquals("Prefetch must target one view", 1, mRecyclerView.mPrefetchRegistry.mCount);
+        int prefetchTarget = mRecyclerView.mPrefetchRegistry.mPrefetchArray[0];
+        assertEquals("Prefetch must target view 2", 2, prefetchTarget);
+
+        // animating view still observable as hidden, uncached
+        CacheUtils.verifyCacheDoesNotContainPositions(mRecyclerView, 2);
+        assertNotNull("Animating view should be found, hidden",
+                mRecyclerView.mChildHelper.findHiddenNonRemovedView(2));
+        assertTrue(GapWorker.isPrefetchPositionAttached(mRecyclerView, 2));
+
+        assertTrue(itemAnimator.isRunning());
+        assertEquals(2, llm.getChildCount());
+        assertEquals(4, mRecyclerView.getChildCount());
+    }
+
+    @Test
+    public void viewHolderFindsNestedRecyclerViews() {
+        LinearLayoutManager llm = new LinearLayoutManager(getContext());
+        mRecyclerView.setLayoutManager(llm);
+
+        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
+        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
+                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
+                    @Override
+                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
+                            throws Throwable {
+                        View view = new RecyclerView(getContext());
+                        view.setLayoutParams(new RecyclerView.LayoutParams(100, 100));
+                        return new RecyclerView.ViewHolder(view) {};
+                    }
+                });
+        when(mockAdapter.getItemCount()).thenReturn(100);
+        mRecyclerView.setAdapter(mockAdapter);
+
+        layout(100, 200);
+
+        verify(mockAdapter, times(2)).onCreateViewHolder(any(ViewGroup.class), anyInt());
+        verify(mockAdapter, times(2)).onBindViewHolder(
+                argThat(new ArgumentMatcher<RecyclerView.ViewHolder>() {
+                    @Override
+                    public boolean matches(RecyclerView.ViewHolder holder) {
+                        return holder.itemView == holder.mNestedRecyclerView.get();
+                    }
+                }),
+                anyInt(),
+                any(List.class));
+    }
+
+    class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.ViewHolder> {
+        private static final int INNER_ITEM_COUNT = 20;
+        int mItemsBound = 0;
+
+        class ViewHolder extends RecyclerView.ViewHolder {
+            ViewHolder(View itemView) {
+                super(itemView);
+            }
+        }
+
+        InnerAdapter() {}
+
+        @Override
+        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            mRecyclerView.registerTimePassingMs(5);
+            View view = new View(parent.getContext());
+            view.setLayoutParams(new RecyclerView.LayoutParams(100, 100));
+            return new ViewHolder(view);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+            mRecyclerView.registerTimePassingMs(5);
+            mItemsBound++;
+        }
+
+        @Override
+        public int getItemCount() {
+            return INNER_ITEM_COUNT;
+        }
+    }
+
+    class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.ViewHolder> {
+
+        private boolean mReverseInner;
+
+        class ViewHolder extends RecyclerView.ViewHolder {
+            private final RecyclerView mRecyclerView;
+            ViewHolder(RecyclerView itemView) {
+                super(itemView);
+                mRecyclerView = itemView;
+            }
+        }
+
+        ArrayList<InnerAdapter> mAdapters = new ArrayList<>();
+        ArrayList<Parcelable> mSavedStates = new ArrayList<>();
+        RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool();
+
+        OuterAdapter() {
+            this(false);
+        }
+
+        OuterAdapter(boolean reverseInner) {
+            this(reverseInner, 10);
+        }
+
+        OuterAdapter(boolean reverseInner, int itemCount) {
+            mReverseInner = reverseInner;
+            for (int i = 0; i < itemCount; i++) {
+                mAdapters.add(new InnerAdapter());
+                mSavedStates.add(null);
+            }
+        }
+
+        void addItem() {
+            int index = getItemCount();
+            mAdapters.add(new InnerAdapter());
+            mSavedStates.add(null);
+            notifyItemInserted(index);
+        }
+
+        @Override
+        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            mRecyclerView.registerTimePassingMs(5);
+
+            RecyclerView rv = new RecyclerView(parent.getContext()) {
+                @Override
+                public int getWindowVisibility() {
+                    // Pretend to be visible to avoid being filtered out
+                    return View.VISIBLE;
+                }
+            };
+            rv.setLayoutManager(new LinearLayoutManager(parent.getContext(),
+                    LinearLayoutManager.HORIZONTAL, mReverseInner));
+            rv.setRecycledViewPool(mSharedPool);
+            rv.setLayoutParams(new RecyclerView.LayoutParams(200, 100));
+            return new ViewHolder(rv);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+            mRecyclerView.registerTimePassingMs(5);
+
+            // Tests may rely on bound holders not being shared between inner adapters,
+            // since we force recycle here
+            holder.mRecyclerView.swapAdapter(mAdapters.get(position), true);
+
+            Parcelable savedState = mSavedStates.get(position);
+            if (savedState != null) {
+                holder.mRecyclerView.getLayoutManager().onRestoreInstanceState(savedState);
+                mSavedStates.set(position, null);
+            }
+        }
+
+        @Override
+        public void onViewRecycled(@NonNull ViewHolder holder) {
+            mSavedStates.set(holder.getAdapterPosition(),
+                    holder.mRecyclerView.getLayoutManager().onSaveInstanceState());
+        }
+
+        @Override
+        public int getItemCount() {
+            return mAdapters.size();
+        }
+    }
+
+    @Test
+    public void nestedPrefetchSimple() {
+        LinearLayoutManager llm = new LinearLayoutManager(getContext());
+        assertEquals(2, llm.getInitialPrefetchItemCount());
+
+        mRecyclerView.setLayoutManager(llm);
+        mRecyclerView.setAdapter(new OuterAdapter());
+
+        layout(200, 200);
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+
+        // prefetch 2 (default)
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
+        assertNotNull(holder);
+        assertNotNull(holder.mNestedRecyclerView);
+        RecyclerView innerView = holder.mNestedRecyclerView.get();
+        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1);
+
+        // prefetch 4
+        ((LinearLayoutManager) innerView.getLayoutManager())
+                .setInitialPrefetchItemCount(4);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1, 2, 3);
+    }
+
+    @Test
+    public void nestedPrefetchNotClearInnerStructureChangeFlag() {
+        LinearLayoutManager llm = new LinearLayoutManager(getContext());
+        assertEquals(2, llm.getInitialPrefetchItemCount());
+
+        mRecyclerView.setLayoutManager(llm);
+        mRecyclerView.setAdapter(new OuterAdapter());
+
+        layout(200, 200);
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+
+        // prefetch 2 (default)
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
+        assertNotNull(holder);
+        assertNotNull(holder.mNestedRecyclerView);
+        RecyclerView innerView = holder.mNestedRecyclerView.get();
+        RecyclerView.Adapter innerAdapter = innerView.getAdapter();
+        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1);
+        // mStructureChanged is initially true before first layout pass.
+        assertTrue(innerView.mState.mStructureChanged);
+        assertTrue(innerView.hasPendingAdapterUpdates());
+
+        // layout position 2 and clear mStructureChanged
+        mRecyclerView.scrollToPosition(2);
+        layout(200, 200);
+        mRecyclerView.scrollToPosition(0);
+        layout(200, 200);
+        assertFalse(innerView.mState.mStructureChanged);
+        assertFalse(innerView.hasPendingAdapterUpdates());
+
+        // notify change on the cached innerView.
+        innerAdapter.notifyDataSetChanged();
+        assertTrue(innerView.mState.mStructureChanged);
+        assertTrue(innerView.hasPendingAdapterUpdates());
+
+        // prefetch again
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        ((LinearLayoutManager) innerView.getLayoutManager())
+                .setInitialPrefetchItemCount(2);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1);
+
+        // The re-prefetch is not necessary get the same inner view but we will get same Adapter
+        holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
+        innerView = holder.mNestedRecyclerView.get();
+        assertSame(innerAdapter, innerView.getAdapter());
+        // prefetch shouldn't clear the mStructureChanged flag
+        assertTrue(innerView.mState.mStructureChanged);
+        assertTrue(innerView.hasPendingAdapterUpdates());
+    }
+
+    @Test
+    public void nestedPrefetchReverseInner() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        mRecyclerView.setAdapter(new OuterAdapter(/* reverseInner = */ true));
+
+        layout(200, 200);
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
+
+        // anchor from right side, should see last two positions
+        CacheUtils.verifyCacheContainsPrefetchedPositions(holder.mNestedRecyclerView.get(), 18, 19);
+    }
+
+    @Test
+    public void nestedPrefetchOffset() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        mRecyclerView.setAdapter(new OuterAdapter());
+
+        layout(200, 200);
+
+        // Scroll top row by 5.5 items, verify positions 5, 6, 7 showing
+        RecyclerView inner = (RecyclerView) mRecyclerView.getChildAt(0);
+        inner.scrollBy(550, 0);
+        assertEquals(5, RecyclerView.getChildViewHolderInt(inner.getChildAt(0)).mPosition);
+        assertEquals(6, RecyclerView.getChildViewHolderInt(inner.getChildAt(1)).mPosition);
+        assertEquals(7, RecyclerView.getChildViewHolderInt(inner.getChildAt(2)).mPosition);
+
+        // scroll down 4 rows, up 3 so row 0 is adjacent but uncached
+        mRecyclerView.scrollBy(0, 400);
+        mRecyclerView.scrollBy(0, -300);
+
+        // top row no longer present
+        CacheUtils.verifyCacheDoesNotContainPositions(mRecyclerView, 0);
+
+        // prefetch upward, and validate that we've gotten the top row with correct offsets
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, -1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        inner = (RecyclerView) CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 0).itemView;
+        CacheUtils.verifyCacheContainsPrefetchedPositions(inner, 5, 6);
+
+        // prefetch 4
+        ((LinearLayoutManager) inner.getLayoutManager()).setInitialPrefetchItemCount(4);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(inner, 5, 6, 7, 8);
+    }
+
+    @Test
+    public void nestedPrefetchNotReset() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        OuterAdapter outerAdapter = new OuterAdapter();
+        mRecyclerView.setAdapter(outerAdapter);
+
+        layout(200, 200);
+
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+
+        // prefetch row 2, items 0 & 1
+        assertEquals(0, outerAdapter.mAdapters.get(2).mItemsBound);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
+        RecyclerView innerRecyclerView = holder.mNestedRecyclerView.get();
+
+        assertNotNull(innerRecyclerView);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(innerRecyclerView, 0, 1);
+        assertEquals(2, outerAdapter.mAdapters.get(2).mItemsBound);
+
+        // new row comes on, triggers layout...
+        mRecyclerView.scrollBy(0, 50);
+
+        // ... which shouldn't require new items to be bound,
+        // as prefetch has already done that work
+        assertEquals(2, outerAdapter.mAdapters.get(2).mItemsBound);
+    }
+
+    static void validateRvChildrenValid(RecyclerView recyclerView, int childCount) {
+        ChildHelper childHelper = recyclerView.mChildHelper;
+
+        assertEquals(childCount, childHelper.getUnfilteredChildCount());
+        for (int i = 0; i < childHelper.getUnfilteredChildCount(); i++) {
+            assertFalse(recyclerView.getChildViewHolder(
+                    childHelper.getUnfilteredChildAt(i)).isInvalid());
+        }
+    }
+
+    @Test
+    public void nestedPrefetchCacheNotTouched() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        OuterAdapter outerAdapter = new OuterAdapter();
+        mRecyclerView.setAdapter(outerAdapter);
+
+        layout(200, 200);
+        mRecyclerView.scrollBy(0, 100);
+
+        // item 0 is cached
+        assertEquals(2, outerAdapter.mAdapters.get(0).mItemsBound);
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 0);
+        validateRvChildrenValid(holder.mNestedRecyclerView.get(), 2);
+
+        // try and prefetch it
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, -1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        // make sure cache's inner items aren't rebound unnecessarily
+        assertEquals(2, outerAdapter.mAdapters.get(0).mItemsBound);
+        validateRvChildrenValid(holder.mNestedRecyclerView.get(), 2);
+    }
+
+    @Test
+    public void nestedRemoveAnimatingView() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        OuterAdapter outerAdapter = new OuterAdapter(false, 1);
+        mRecyclerView.setAdapter(outerAdapter);
+        mRecyclerView.getItemAnimator().setAddDuration(TimeUnit.MILLISECONDS.toNanos(30));
+
+        layout(200, 200);
+
+        // Insert 3 items - only first one in viewport, so only it animates
+        for (int i = 0; i < 3; i++) {
+            outerAdapter.addItem();
+        }
+        layout(200, 200); // layout again to kick off animation
+
+
+        // item 1 is animating, so scroll it out of viewport
+        mRecyclerView.scrollBy(0, 200);
+
+        // 2 items attached, 1 cached (pos 0), but item animating pos 1 not accounted for...
+        assertEquals(2, mRecyclerView.mChildHelper.getUnfilteredChildCount());
+        assertEquals(1, mRecycler.mCachedViews.size());
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 0);
+        assertEquals(0, mRecyclerView.getRecycledViewPool().getRecycledViewCount(0));
+
+        // until animation ends
+        mRecyclerView.getItemAnimator().endAnimations();
+        assertEquals(2, mRecyclerView.mChildHelper.getUnfilteredChildCount());
+        assertEquals(2, mRecycler.mCachedViews.size());
+        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 0, 1);
+        assertEquals(0, mRecyclerView.getRecycledViewPool().getRecycledViewCount(0));
+
+        for (RecyclerView.ViewHolder viewHolder : mRecycler.mCachedViews) {
+            assertNotNull(viewHolder.mNestedRecyclerView);
+        }
+    }
+
+    @Test
+    public void nestedExpandCacheCorrectly() {
+        final int DEFAULT_CACHE_SIZE = RecyclerView.Recycler.DEFAULT_CACHE_SIZE;
+
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        OuterAdapter outerAdapter = new OuterAdapter();
+        mRecyclerView.setAdapter(outerAdapter);
+
+        layout(200, 200);
+
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        // after initial prefetch, view cache max expanded by number of inner items prefetched (2)
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
+        RecyclerView innerView = holder.mNestedRecyclerView.get();
+        assertTrue(innerView.getLayoutManager().mPrefetchMaxObservedInInitialPrefetch);
+        assertEquals(2, innerView.getLayoutManager().mPrefetchMaxCountObserved);
+        assertEquals(2 + DEFAULT_CACHE_SIZE, innerView.mRecycler.mViewCacheMax);
+
+        try {
+            // Note: As a hack, we not only must manually dispatch attachToWindow(), but we
+            // also have to be careful to call innerView.mGapWorker below. mRecyclerView.mGapWorker
+            // is registered to the wrong thread, since @setup is called on a different thread
+            // from @Test. Assert this, so this test can be fixed when setup == test thread.
+            assertEquals(1, mRecyclerView.mGapWorker.mRecyclerViews.size());
+            assertFalse(innerView.isAttachedToWindow());
+            innerView.onAttachedToWindow();
+
+            // bring prefetch view into viewport, at which point it shouldn't have cache expanded...
+            mRecyclerView.scrollBy(0, 100);
+            assertFalse(innerView.getLayoutManager().mPrefetchMaxObservedInInitialPrefetch);
+            assertEquals(0, innerView.getLayoutManager().mPrefetchMaxCountObserved);
+            assertEquals(DEFAULT_CACHE_SIZE, innerView.mRecycler.mViewCacheMax);
+
+            // until a valid horizontal prefetch caches an item, and expands view count by one
+            innerView.mPrefetchRegistry.setPrefetchVector(1, 0);
+            innerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS); // NB: must be innerView.mGapWorker
+            assertFalse(innerView.getLayoutManager().mPrefetchMaxObservedInInitialPrefetch);
+            assertEquals(1, innerView.getLayoutManager().mPrefetchMaxCountObserved);
+            assertEquals(1 + DEFAULT_CACHE_SIZE, innerView.mRecycler.mViewCacheMax);
+        } finally {
+            if (innerView.isAttachedToWindow()) {
+                innerView.onDetachedFromWindow();
+            }
+        }
+    }
+
+    /**
+     * Similar to OuterAdapter above, but uses notifyDataSetChanged() instead of set/swapAdapter
+     * to update data for the inner RecyclerViews when containing ViewHolder is bound.
+     */
+    class OuterNotifyAdapter extends RecyclerView.Adapter<OuterNotifyAdapter.ViewHolder> {
+        private static final int OUTER_ITEM_COUNT = 10;
+
+        private boolean mReverseInner;
+
+        class ViewHolder extends RecyclerView.ViewHolder {
+            private final RecyclerView mRecyclerView;
+            private final InnerAdapter mAdapter;
+            ViewHolder(RecyclerView itemView) {
+                super(itemView);
+                mRecyclerView = itemView;
+                mAdapter = new InnerAdapter();
+                mRecyclerView.setAdapter(mAdapter);
+            }
+        }
+
+        ArrayList<Parcelable> mSavedStates = new ArrayList<>();
+        RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool();
+
+        OuterNotifyAdapter() {
+            this(false);
+        }
+
+        OuterNotifyAdapter(boolean reverseInner) {
+            mReverseInner = reverseInner;
+            for (int i = 0; i <= OUTER_ITEM_COUNT; i++) {
+                mSavedStates.add(null);
+            }
+        }
+
+        @NonNull
+        @Override
+        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            mRecyclerView.registerTimePassingMs(5);
+            RecyclerView rv = new RecyclerView(parent.getContext());
+            rv.setLayoutManager(new LinearLayoutManager(parent.getContext(),
+                    LinearLayoutManager.HORIZONTAL, mReverseInner));
+            rv.setRecycledViewPool(mSharedPool);
+            rv.setLayoutParams(new RecyclerView.LayoutParams(200, 100));
+            return new ViewHolder(rv);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+            mRecyclerView.registerTimePassingMs(5);
+            // if we had actual data to put into our adapter, this is where we'd do it...
+
+            // ... then notify the adapter that it has new content:
+            holder.mAdapter.notifyDataSetChanged();
+
+            Parcelable savedState = mSavedStates.get(position);
+            if (savedState != null) {
+                holder.mRecyclerView.getLayoutManager().onRestoreInstanceState(savedState);
+                mSavedStates.set(position, null);
+            }
+        }
+
+        @Override
+        public void onViewRecycled(@NonNull ViewHolder holder) {
+            if (holder.getAdapterPosition() >= 0) {
+                mSavedStates.set(holder.getAdapterPosition(),
+                        holder.mRecyclerView.getLayoutManager().onSaveInstanceState());
+            }
+        }
+
+        @Override
+        public int getItemCount() {
+            return OUTER_ITEM_COUNT;
+        }
+    }
+
+    @Test
+    public void nestedPrefetchDiscardStaleChildren() {
+        LinearLayoutManager llm = new LinearLayoutManager(getContext());
+        assertEquals(2, llm.getInitialPrefetchItemCount());
+
+        mRecyclerView.setLayoutManager(llm);
+        OuterNotifyAdapter outerAdapter = new OuterNotifyAdapter();
+        mRecyclerView.setAdapter(outerAdapter);
+
+        // zero cache, so item we prefetch can't already be ready
+        mRecyclerView.setItemViewCacheSize(0);
+
+        // layout 3 items, then resize to 2...
+        layout(200, 300);
+        layout(200, 200);
+
+        // so 1 item is evicted into the RecycledViewPool (bypassing cache)
+        assertEquals(1, mRecycler.mRecyclerPool.getRecycledViewCount(0));
+        assertEquals(0, mRecycler.mCachedViews.size());
+
+        // This is a simple imitation of other behavior (namely, varied types in the outer adapter)
+        // that results in the same initial state to test: items in the pool with attached children
+        for (RecyclerView.ViewHolder holder : mRecycler.mRecyclerPool.mScrap.get(0).mScrapHeap) {
+            // verify that children are attached and valid, since the RVs haven't been rebound
+            assertNotNull(holder.mNestedRecyclerView);
+            assertFalse(holder.mNestedRecyclerView.get().mDataSetHasChangedAfterLayout);
+            validateRvChildrenValid(holder.mNestedRecyclerView.get(), 2);
+        }
+
+        // prefetch the outer item bind, but without enough time to do any inner binds
+        final long deadlineNs = mRecyclerView.getNanoTime() + TimeUnit.MILLISECONDS.toNanos(9);
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(deadlineNs);
+
+        // 2 is prefetched without children
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 2);
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
+        assertNotNull(holder);
+        assertNotNull(holder.mNestedRecyclerView);
+        assertEquals(0, holder.mNestedRecyclerView.get().mChildHelper.getUnfilteredChildCount());
+        assertEquals(0, holder.mNestedRecyclerView.get().mRecycler.mCachedViews.size());
+
+        // but if we give it more time to bind items, it'll now acquire its inner items
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+        CacheUtils.verifyCacheContainsPrefetchedPositions(holder.mNestedRecyclerView.get(), 0, 1);
+    }
+
+
+    @Test
+    public void nestedPrefetchDiscardStalePrefetch() {
+        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
+        OuterNotifyAdapter outerAdapter = new OuterNotifyAdapter();
+        mRecyclerView.setAdapter(outerAdapter);
+
+        // zero cache, so item we prefetch can't already be ready
+        mRecyclerView.setItemViewCacheSize(0);
+
+        // layout as 2x2, starting on row index 2, with empty cache
+        layout(200, 200);
+        mRecyclerView.scrollBy(0, 200);
+
+        // no views cached, or previously used (so we can trust number in mItemsBound)
+        mRecycler.mRecyclerPool.clear();
+        assertEquals(0, mRecycler.mRecyclerPool.getRecycledViewCount(0));
+        assertEquals(0, mRecycler.mCachedViews.size());
+
+        // prefetch the outer item and its inner children
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        // 4 is prefetched with 2 inner children, first two binds
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 4);
+        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 4);
+        assertNotNull(holder);
+        assertNotNull(holder.mNestedRecyclerView);
+        RecyclerView innerRecyclerView = holder.mNestedRecyclerView.get();
+        assertEquals(0, innerRecyclerView.mChildHelper.getUnfilteredChildCount());
+        assertEquals(2, innerRecyclerView.mRecycler.mCachedViews.size());
+        assertEquals(2, ((InnerAdapter) innerRecyclerView.getAdapter()).mItemsBound);
+
+        // notify data set changed, so any previously prefetched items invalid, and re-prefetch
+        innerRecyclerView.getAdapter().notifyDataSetChanged();
+        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
+        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
+
+        // 4 is prefetched again...
+        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 4);
+
+        // reusing the same instance with 2 inner children...
+        assertSame(holder, CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 4));
+        assertSame(innerRecyclerView, holder.mNestedRecyclerView.get());
+        assertEquals(0, innerRecyclerView.mChildHelper.getUnfilteredChildCount());
+        assertEquals(2, innerRecyclerView.mRecycler.mCachedViews.size());
+
+        // ... but there should be two new binds
+        assertEquals(4, ((InnerAdapter) innerRecyclerView.getAdapter()).mItemsBound);
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFastScrollerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFastScrollerTest.java
new file mode 100644
index 0000000..4361c93
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFastScrollerTest.java
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.RecyclerView.VERTICAL;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.StateListDrawable;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.recyclerview.R;
+import android.support.v7.util.TouchUtils;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.TextView;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewFastScrollerTest extends BaseRecyclerViewInstrumentationTest {
+    private static final int FLAG_HORIZONTAL = 1;
+    private static final int FLAG_VERTICAL = 1 << 1;
+    private int mScrolledByY = -1000;
+    private int mScrolledByX = -1000;
+    private FastScroller mScroller;
+    private boolean mHide;
+
+    private void setContentView(final int layoutId) throws Throwable {
+        final Activity activity = mActivityRule.getActivity();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.setContentView(layoutId);
+            }
+        });
+    }
+
+    @Test
+    public void xml_fastScrollEnabled_startsInvisibleAndAtTop() throws Throwable {
+        arrangeWithXml();
+
+        assertTrue("Expected centerY to start == 0", mScroller.mVerticalThumbCenterY == 0);
+        assertFalse("Expected thumb to start invisible", mScroller.isVisible());
+    }
+
+    @Test
+    public void scrollBy_displaysAndMovesFastScrollerThumb() throws Throwable {
+        arrangeWithXml();
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.scrollBy(0, 400);
+            }
+        });
+
+        assertTrue("Expected centerY to be > 0" + mScroller.mVerticalThumbCenterY,
+                mScroller.mVerticalThumbCenterY > 0);
+        assertTrue("Expected thumb to be visible", mScroller.isVisible());
+    }
+
+    @Test
+    public void ui_dragsThumb_scrollsRecyclerView() throws Throwable {
+        arrangeWithXml();
+
+        // RecyclerView#scrollBy(int, int) used to cause the scroller thumb to show up.
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.scrollBy(0, 1);
+                mRecyclerView.scrollBy(0, -1);
+            }
+        });
+        int[] absoluteCoords = new int[2];
+        mRecyclerView.getLocationOnScreen(absoluteCoords);
+        TouchUtils.drag(InstrumentationRegistry.getInstrumentation(), mRecyclerView.getWidth() - 10,
+                mRecyclerView.getWidth() - 10, mScroller.mVerticalThumbCenterY + absoluteCoords[1],
+                mRecyclerView.getHeight() + absoluteCoords[1], 100);
+
+        assertTrue("Expected dragging thumb to move recyclerView",
+                mRecyclerView.computeVerticalScrollOffset() > 0);
+    }
+
+    @Test
+    public void properCleanUp() throws Throwable {
+        mRecyclerView = new RecyclerView(getActivity());
+        final Activity activity = mActivityRule.getActivity();
+        final CountDownLatch latch = new CountDownLatch(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.setContentView(
+                        android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
+                mRecyclerView = (RecyclerView) activity.findViewById(
+                        android.support.v7.recyclerview.test.R.id.recycler_view);
+                LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext());
+                layout.setOrientation(VERTICAL);
+                mRecyclerView.setLayoutManager(layout);
+                mRecyclerView.setAdapter(new TestAdapter(50));
+                Resources res = getActivity().getResources();
+                mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
+                        res.getDrawable(
+                                android.support.v7.recyclerview.test.R.drawable
+                                        .fast_scroll_track_drawable),
+                        (StateListDrawable) res.getDrawable(
+                                android.support.v7.recyclerview.test.R.drawable
+                                        .fast_scroll_thumb_drawable),
+                        res.getDrawable(
+                                android.support.v7.recyclerview.test.R.drawable
+                                        .fast_scroll_track_drawable),
+                        res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
+                        res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
+                        res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) {
+                    @Override
+                    public void show() {
+                        // Overriden to avoid animation calls in instrumentation thread
+                    }
+
+                    @Override
+                    public void hide(int duration) {
+                        latch.countDown();
+                        mHide = true;
+                    }
+                };
+
+            }
+        });
+        waitForIdleScroll(mRecyclerView);
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.scrollBy(0, 400);
+                mScroller.attachToRecyclerView(new RecyclerView(getActivity()));
+            }
+        });
+        assertFalse(latch.await(2, TimeUnit.SECONDS));
+        assertFalse(mHide);
+    }
+
+    @Test
+    public void inflationTest() throws Throwable {
+        setContentView(android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
+        getInstrumentation().waitForIdleSync();
+        RecyclerView view = (RecyclerView) getActivity().findViewById(
+                android.support.v7.recyclerview.test.R.id.recycler_view);
+        assertTrue(view.getItemDecorationCount() == 1);
+        assertTrue(view.getItemDecorationAt(0) instanceof FastScroller);
+        FastScroller scroller = (FastScroller) view.getItemDecorationAt(0);
+        assertNotNull(scroller.getHorizontalThumbDrawable());
+        assertNotNull(scroller.getHorizontalTrackDrawable());
+        assertNotNull(scroller.getVerticalThumbDrawable());
+        assertNotNull(scroller.getVerticalTrackDrawable());
+    }
+
+    @Test
+    public void removeFastScrollerSuccessful() throws Throwable {
+        setContentView(android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
+        getInstrumentation().waitForIdleSync();
+        final RecyclerView view = (RecyclerView) getActivity().findViewById(
+                android.support.v7.recyclerview.test.R.id.recycler_view);
+        assertTrue(view.getItemDecorationCount() == 1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                view.removeItemDecorationAt(0);
+                assertTrue(view.getItemDecorationCount() == 0);
+            }
+        });
+    }
+
+    @UiThreadTest
+    @Test
+    public void initWithBadDrawables() throws Throwable {
+        arrangeWithCode();
+
+        Throwable exception = null;
+        try {
+            mRecyclerView.initFastScroller(null, null, null, null);
+        } catch (Throwable t) {
+            exception = t;
+        }
+        assertTrue(exception instanceof IllegalArgumentException);
+    }
+
+    @Test
+    public void verticalScrollUpdatesFastScrollThumb() throws Throwable {
+        scrollUpdatesFastScrollThumb(FLAG_VERTICAL);
+    }
+
+    @Test
+    public void horizontalScrollUpdatesFastScrollThumb() throws Throwable {
+        scrollUpdatesFastScrollThumb(FLAG_HORIZONTAL);
+    }
+
+    private void scrollUpdatesFastScrollThumb(int direction) throws Throwable {
+        arrangeWithCode();
+        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250,
+                direction == FLAG_VERTICAL ? 250 : 0);
+        if (direction == FLAG_VERTICAL) {
+            assertTrue("Expected 250 for centerY, got " + mScroller.mVerticalThumbCenterY,
+                    mScroller.mVerticalThumbCenterY == 250);
+            assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight,
+                    mScroller.mVerticalThumbHeight == 250);
+        } else if (direction == FLAG_HORIZONTAL) {
+            assertTrue("Expected 250 for centerX, got " + mScroller.mHorizontalThumbCenterX,
+                    mScroller.mHorizontalThumbCenterX == 250);
+            assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth,
+                    mScroller.mHorizontalThumbWidth == 250);
+        }
+        assertTrue(mScroller.isVisible());
+
+        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 42,
+                direction == FLAG_VERTICAL ? 42 : 0);
+        if (direction == FLAG_VERTICAL) {
+            assertTrue("Expected 146 for centerY, got " + mScroller.mVerticalThumbCenterY,
+                    mScroller.mVerticalThumbCenterY == 146);
+            assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight,
+                    mScroller.mVerticalThumbHeight == 250);
+        } else if (direction == FLAG_HORIZONTAL) {
+            assertTrue("Expected 146 for centerX, got " + mScroller.mHorizontalThumbCenterX,
+                    mScroller.mHorizontalThumbCenterX == 146);
+            assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth,
+                    mScroller.mHorizontalThumbWidth == 250);
+        }
+        assertTrue(mScroller.isVisible());
+    }
+
+    @Test
+    public void draggingDoesNotTriggerFastScrollIfNotInThumb() throws Throwable {
+        arrangeWithCode();
+        mScroller.updateScrollPosition(0, 250);
+        final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN, 250, 250,
+                0);
+        assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent));
+        final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE, 250, 275,
+                0);
+        assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, moveEvent));
+    }
+
+    @Test
+    public void verticalDraggingFastScrollThumbDoesActualScrolling() throws Throwable {
+        draggingFastScrollThumbDoesActualScrolling(FLAG_VERTICAL);
+    }
+
+    @Test
+    public void horizontalDraggingFastScrollThumbDoesActualScrolling() throws Throwable {
+        draggingFastScrollThumbDoesActualScrolling(FLAG_HORIZONTAL);
+    }
+
+    private void draggingFastScrollThumbDoesActualScrolling(int direction) throws Throwable {
+        arrangeWithCode();
+        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250,
+                direction == FLAG_VERTICAL ? 250 : 0);
+        final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN,
+                direction == FLAG_VERTICAL ? 500 : 250, direction == FLAG_VERTICAL ? 250 : 500, 0);
+        assertTrue(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent));
+        assertTrue(mScroller.isDragging());
+        final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE,
+                direction == FLAG_VERTICAL ? 500 : 221, direction == FLAG_VERTICAL ? 221 : 500, 0);
+        mScroller.onTouchEvent(mRecyclerView, moveEvent);
+        if (direction == FLAG_VERTICAL) {
+            assertTrue("Expected to get -29, but got " + mScrolledByY, mScrolledByY == -29);
+        } else {
+            assertTrue("Expected to get -29, but got " + mScrolledByX, mScrolledByX == -29);
+        }
+    }
+
+    private void arrangeWithXml() throws Throwable {
+
+        final TestActivity activity = mActivityRule.getActivity();
+        final TestedFrameLayout testedFrameLayout = activity.getContainer();
+
+        RecyclerView recyclerView = (RecyclerView) LayoutInflater.from(activity).inflate(
+                android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv,
+                testedFrameLayout,
+                false);
+
+        LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext());
+        layout.setOrientation(VERTICAL);
+        recyclerView.setLayoutManager(layout);
+
+        recyclerView.setAdapter(new TestAdapter(50));
+
+        mScroller = (FastScroller) recyclerView.getItemDecorationAt(0);
+
+        testedFrameLayout.expectLayouts(1);
+        testedFrameLayout.expectDraws(1);
+        setRecyclerView(recyclerView);
+        testedFrameLayout.waitForLayout(2);
+        testedFrameLayout.waitForDraw(2);
+    }
+
+    private void arrangeWithCode() throws Exception {
+        final int width = 500;
+        final int height = 500;
+
+        mRecyclerView = new RecyclerView(getActivity()) {
+            @Override
+            public int computeVerticalScrollRange() {
+                return 1000;
+            }
+
+            @Override
+            public int computeVerticalScrollExtent() {
+                return 500;
+            }
+
+            @Override
+            public int computeVerticalScrollOffset() {
+                return 250;
+            }
+
+            @Override
+            public int computeHorizontalScrollRange() {
+                return 1000;
+            }
+
+            @Override
+            public int computeHorizontalScrollExtent() {
+                return 500;
+            }
+
+            @Override
+            public int computeHorizontalScrollOffset() {
+                return 250;
+            }
+
+            @Override
+            public void scrollBy(int x, int y) {
+                mScrolledByY = y;
+                mScrolledByX = x;
+            }
+        };
+        mRecyclerView.setAdapter(new TestAdapter(50));
+        mRecyclerView.measure(
+                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
+                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
+        mRecyclerView.layout(0, 0, width, height);
+
+        Resources res = getActivity().getResources();
+        mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable(
+                android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
+                res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_track_drawable),
+                (StateListDrawable) res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
+                res.getDrawable(
+                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_track_drawable),
+                res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
+                res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
+                res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) {
+            @Override
+            public void show() {
+                // Overriden to avoid animation calls in instrumentation thread
+            }
+
+            @Override
+            public void hide(int duration) {
+                mHide = true;
+            }
+        };
+        mRecyclerView.mEnableFastScroller = true;
+
+        // Draw it once so height/width gets updated
+        mScroller.onDrawOver(null, mRecyclerView, null);
+    }
+
+    private static class TestAdapter extends RecyclerView.Adapter {
+        private int mItemCount;
+
+        public static class ViewHolder extends RecyclerView.ViewHolder {
+            public TextView mTextView;
+
+            ViewHolder(TextView v) {
+                super(v);
+                mTextView = v;
+            }
+
+            @Override
+            public String toString() {
+                return super.toString() + " '" + mTextView.getText();
+            }
+        }
+
+        TestAdapter(int itemCount) {
+            mItemCount = itemCount;
+        }
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                int viewType) {
+            final ViewHolder h = new ViewHolder(new TextView(parent.getContext()));
+            h.mTextView.setMinimumHeight(128);
+            h.mTextView.setPadding(20, 0, 20, 0);
+            h.mTextView.setFocusable(true);
+            h.mTextView.setBackgroundColor(Color.BLUE);
+            RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
+                    LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+            lp.leftMargin = 10;
+            lp.rightMargin = 5;
+            lp.topMargin = 20;
+            lp.bottomMargin = 15;
+            h.mTextView.setLayoutParams(lp);
+            return h;
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+            holder.itemView.setTag("pos " + position);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItemCount;
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
new file mode 100644
index 0000000..0c7a54f
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
@@ -0,0 +1,933 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v7.widget;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.filters.MediumTest;
+import android.support.v7.recyclerview.test.R;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * This class only tests the RV's focus recovery logic as focus moves between two views that
+ * represent the same item in the adapter. Keeping a focused view visible is up-to-the
+ * LayoutManager and all FW LayoutManagers already have tests for it.
+ */
+@MediumTest
+@RunWith(Parameterized.class)
+public class RecyclerViewFocusRecoveryTest extends BaseRecyclerViewInstrumentationTest {
+    TestLayoutManager mLayoutManager;
+    TestAdapter mAdapter;
+    int mChildCount = 10;
+
+    // Parameter indicating whether RV's children are simple views (false) or ViewGroups (true).
+    private final boolean mFocusOnChild;
+    // Parameter indicating whether RV recovers focus after layout is finished.
+    private final boolean mDisableRecovery;
+    // Parameter indicating whether animation is enabled for the ViewHolder items.
+    private final boolean mDisableAnimation;
+
+    @Parameterized.Parameters(name = "focusSubChild:{0},disableRecovery:{1},"
+            + "disableAnimation:{2}")
+    public static List<Object[]> getParams() {
+        return Arrays.asList(
+                new Object[]{false, false, true},
+                new Object[]{true, false, true},
+                new Object[]{false, true, true},
+                new Object[]{true, true, true},
+                new Object[]{false, false, false},
+                new Object[]{true, false, false},
+                new Object[]{false, true, false},
+                new Object[]{true, true, false}
+        );
+    }
+
+    public RecyclerViewFocusRecoveryTest(boolean focusOnChild, boolean disableRecovery,
+                                         boolean disableAnimation) {
+        super(false);
+        mFocusOnChild = focusOnChild;
+        mDisableRecovery = disableRecovery;
+        mDisableAnimation = disableAnimation;
+    }
+
+    void setupBasic() throws Throwable {
+        setupBasic(false);
+    }
+
+    void setupBasic(boolean hasStableIds) throws Throwable {
+        TestAdapter adapter = new FocusTestAdapter(mChildCount);
+        adapter.setHasStableIds(hasStableIds);
+        setupBasic(adapter, null);
+    }
+
+    void setupBasic(TestLayoutManager layoutManager) throws Throwable {
+        setupBasic(null, layoutManager);
+    }
+
+    void setupBasic(TestAdapter adapter) throws Throwable {
+        setupBasic(adapter, null);
+    }
+
+    void setupBasic(@Nullable TestAdapter adapter, @Nullable TestLayoutManager layoutManager)
+            throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        if (layoutManager == null) {
+            layoutManager = new FocusLayoutManager();
+        }
+
+        if (adapter == null) {
+            adapter = new FocusTestAdapter(mChildCount);
+        }
+        mLayoutManager = layoutManager;
+        mAdapter = adapter;
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(mLayoutManager);
+        recyclerView.setPreserveFocusAfterLayout(!mDisableRecovery);
+        if (mDisableAnimation) {
+            recyclerView.setItemAnimator(null);
+        }
+        mLayoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        mLayoutManager.waitForLayout(1);
+    }
+
+    @Test
+    public void testFocusRecoveryInChange() throws Throwable {
+        setupBasic();
+        mLayoutManager.setSupportsPredictive(true);
+        final RecyclerView.ViewHolder oldVh = focusVh(3);
+
+        mLayoutManager.expectLayouts(mDisableAnimation ? 1 : 2);
+        mAdapter.changeAndNotify(3, 1);
+        mLayoutManager.waitForLayout(2);
+        if (!mDisableAnimation) {
+            // waiting for RV's ItemAnimator to finish the animation of the removed item
+            waitForAnimations(2);
+        }
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3);
+                assertFocusTransition(oldVh, newVh, false);
+
+            }
+        });
+    }
+
+    @Test
+    public void testFocusRecoveryAfterRemovingFocusedChild() throws Throwable {
+        setupBasic(true);
+        FocusViewHolder fvh = cast(focusVh(4));
+
+        assertThat("test sanity", fvh, notNullValue());
+        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
+
+        assertThat("RV should pass the focus down to its children",
+                mRecyclerView.isFocused(), is(false));
+        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
+                is(true));
+        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
+                is(true));
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // removing focused child
+                mAdapter.mItems.remove(4);
+                mAdapter.notifyItemRemoved(4);
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        if (!mDisableAnimation) {
+            // waiting for RV's ItemAnimator to finish the animation of the removed item
+            waitForAnimations(2);
+        }
+        assertThat("RV should have " + (mChildCount - 1) + " instead of "
+                        + mRecyclerView.getChildCount() + " children",
+                mChildCount - 1, is(mRecyclerView.getChildCount()));
+        assertFocusAfterLayout(4, 0);
+    }
+
+    @Test
+    public void testFocusRecoveryAfterMovingFocusedChild() throws Throwable {
+        setupBasic(true);
+        FocusViewHolder fvh = cast(focusVh(3));
+
+        assertThat("test sanity", fvh, notNullValue());
+        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
+
+        assertThat("RV should pass the focus down to its children",
+                mRecyclerView.isFocused(), is(false));
+        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
+                is(true));
+        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
+                is(true));
+
+        mLayoutManager.expectLayouts(1);
+        mAdapter.moveAndNotify(3, 1);
+        mLayoutManager.waitForLayout(1);
+        if (!mDisableAnimation) {
+            // waiting for RV's ItemAnimator to finish the animation of the removed item
+            waitForAnimations(2);
+        }
+        assertFocusAfterLayout(1, 1);
+    }
+
+    @Test
+    public void testFocusRecoveryAfterRemovingLastChild() throws Throwable {
+        mChildCount = 1;
+        setupBasic(true);
+        FocusViewHolder fvh = cast(focusVh(0));
+
+        assertThat("test sanity", fvh, notNullValue());
+        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
+
+        assertThat("RV should pass the focus down to its children",
+                mRecyclerView.isFocused(), is(false));
+        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
+                is(true));
+        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
+                is(true));
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // removing focused child
+                mAdapter.mItems.remove(0);
+                mAdapter.notifyDataSetChanged();
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        if (!mDisableAnimation) {
+            // waiting for RV's ItemAnimator to finish the animation of the removed item
+            waitForAnimations(2);
+        }
+        assertThat("RV should have " + (mChildCount - 1) + " instead of "
+                        + mRecyclerView.getChildCount() + " children",
+                mChildCount - 1, is(mRecyclerView.getChildCount()));
+        assertFocusAfterLayout(-1, -1);
+    }
+
+    @Test
+    public void testFocusRecoveryAfterAddingFirstChild() throws Throwable {
+        mChildCount = 0;
+        setupBasic(true);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                requestFocusOnRV();
+            }
+        });
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // adding first child
+                mAdapter.mItems.add(0, new Item(0, TestAdapter.DEFAULT_ITEM_PREFIX));
+                mAdapter.notifyDataSetChanged();
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        if (!mDisableAnimation) {
+            // waiting for RV's ItemAnimator to finish the animation of the removed item
+            waitForAnimations(2);
+        }
+        assertFocusAfterLayout(0, -1);
+    }
+
+    @Test
+    public void testFocusRecoveryAfterChangingFocusableFlag() throws Throwable {
+        setupBasic(true);
+        FocusViewHolder fvh = cast(focusVh(6));
+
+        assertThat("test sanity", fvh, notNullValue());
+        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
+
+        assertThat("RV should pass the focus down to its children",
+                mRecyclerView.isFocused(), is(false));
+        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
+                is(true));
+        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
+                is(true));
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Item item = mAdapter.mItems.get(6);
+                item.setFocusable(false);
+                mAdapter.notifyItemChanged(6);
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        if (!mDisableAnimation) {
+            waitForAnimations(2);
+        }
+        FocusViewHolder newVh = cast(mRecyclerView.findViewHolderForAdapterPosition(6));
+        assertThat("VH should no longer be focusable", newVh.getViewToFocus().isFocusable(),
+                is(false));
+        assertFocusAfterLayout(7, 0);
+    }
+
+    @Test
+    public void testFocusRecoveryBeforeLayoutWithFocusBefore() throws Throwable {
+        testFocusRecoveryBeforeLayout(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+    }
+
+    @Test
+    public void testFocusRecoveryBeforeLayoutWithFocusAfter() throws Throwable {
+        testFocusRecoveryBeforeLayout(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+    }
+
+    @Test
+    public void testFocusRecoveryBeforeLayoutWithFocusBlocked() throws Throwable {
+        testFocusRecoveryBeforeLayout(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+    }
+
+    @Test
+    public void testFocusRecoveryDuringLayoutWithFocusBefore() throws Throwable {
+        testFocusRecoveryDuringLayout(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+    }
+
+    @Test
+    public void testFocusRecoveryDuringLayoutWithFocusAfter() throws Throwable {
+        testFocusRecoveryDuringLayout(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+    }
+
+    @Test
+    public void testFocusRecoveryDuringLayoutWithFocusBlocked() throws Throwable {
+        testFocusRecoveryDuringLayout(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+    }
+
+    /**
+     * Tests whether the focus is correctly recovered when requestFocus on RV is called before
+     * laying out the children.
+     * @throws Throwable
+     */
+    private void testFocusRecoveryBeforeLayout(int descendantFocusability) throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setDescendantFocusability(descendantFocusability);
+        mLayoutManager = new FocusLayoutManager();
+        mAdapter = new FocusTestAdapter(10);
+        recyclerView.setLayoutManager(mLayoutManager);
+        recyclerView.setPreserveFocusAfterLayout(!mDisableRecovery);
+        if (mDisableAnimation) {
+            recyclerView.setItemAnimator(null);
+        }
+        setRecyclerView(recyclerView);
+        assertThat("RV should always be focusable", mRecyclerView.isFocusable(), is(true));
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                requestFocusOnRV();
+                mRecyclerView.setAdapter(mAdapter);
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        assertFocusAfterLayout(0, -1);
+    }
+
+    /**
+     * Tests whether the focus is correctly recovered when requestFocus on RV is called during
+     * laying out the children.
+     * @throws Throwable
+     */
+    private void testFocusRecoveryDuringLayout(int descendantFocusability) throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setDescendantFocusability(descendantFocusability);
+        mLayoutManager = new FocusLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                requestFocusOnRV();
+            }
+        };
+        mAdapter = new FocusTestAdapter(10);
+        recyclerView.setAdapter(mAdapter);
+        recyclerView.setLayoutManager(mLayoutManager);
+        if (mDisableAnimation) {
+            recyclerView.setItemAnimator(null);
+        }
+        recyclerView.setPreserveFocusAfterLayout(!mDisableRecovery);
+        mLayoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        mLayoutManager.waitForLayout(1);
+        assertFocusAfterLayout(0, -1);
+    }
+
+    private void requestFocusOnRV() {
+        assertThat("RV initially has no focus", mRecyclerView.hasFocus(), is(false));
+        assertThat("RV initially is not focused", mRecyclerView.isFocused(), is(false));
+        mRecyclerView.requestFocus();
+        String msg = !mRecyclerView.isComputingLayout() ? " before laying out the children"
+                : " during laying out the children";
+        assertThat("RV should have focus after calling requestFocus()" + msg,
+                mRecyclerView.hasFocus(), is(true));
+        assertThat("RV after calling requestFocus() should become focused" + msg,
+                mRecyclerView.isFocused(), is(true));
+    }
+
+    /**
+     * Asserts whether RV and one of its children have the correct focus flags after the layout is
+     * complete. This is normally called once the RV layout is complete after initiating
+     * notifyItemChanged.
+     * @param focusedChildIndexWhenRecoveryEnabled
+     * This index is relevant when mDisableRecovery is false. In that case, it refers to the index
+     * of the child that should have focus if the ancestors allow passing down the focus. -1
+     * indicates none of the children can receive focus even if the ancestors don't block focus, in
+     * which case RV holds and becomes focused.
+     * @param focusedChildIndexWhenRecoveryDisabled
+     * This index is relevant when mDisableRecovery is true. In that case, it refers to the index
+     * of the child that should have focus if the ancestors allow passing down the focus. -1
+     * indicates none of the children can receive focus even if the ancestors don't block focus, in
+     * which case RV holds and becomes focused.
+     */
+    private void assertFocusAfterLayout(int focusedChildIndexWhenRecoveryEnabled,
+                                        int focusedChildIndexWhenRecoveryDisabled) {
+        if (mDisableAnimation && mDisableRecovery) {
+            // This case is not quite handled properly at the moment. For now, RV may become focused
+            // without re-delivering the focus down to the children. Skip the checks for now.
+            return;
+        }
+        if (mRecyclerView.getChildCount() == 0) {
+            assertThat("RV should have focus when it has no children",
+                    mRecyclerView.hasFocus(), is(true));
+            assertThat("RV should be focused when it has no children",
+                    mRecyclerView.isFocused(), is(true));
+            return;
+        }
+
+        assertThat("RV should still have focus after layout", mRecyclerView.hasFocus(), is(true));
+        if ((mDisableRecovery && focusedChildIndexWhenRecoveryDisabled == -1)
+                || (!mDisableRecovery && focusedChildIndexWhenRecoveryEnabled == -1)
+                || mRecyclerView.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS
+                || mRecyclerView.getDescendantFocusability()
+                == ViewGroup.FOCUS_BEFORE_DESCENDANTS) {
+            FocusViewHolder fvh = cast(mRecyclerView.findViewHolderForAdapterPosition(0));
+            String msg1 = " when focus recovery is disabled";
+            String msg2 = " when descendant focusability is FOCUS_BLOCK_DESCENDANTS";
+            String msg3 = " when descendant focusability is FOCUS_BEFORE_DESCENDANTS";
+
+            assertThat("RV should not pass the focus down to its children"
+                            + (mDisableRecovery ? msg1 : (mRecyclerView.getDescendantFocusability()
+                                    == ViewGroup.FOCUS_BLOCK_DESCENDANTS ? msg2 : msg3)),
+                    mRecyclerView.isFocused(), is(true));
+            assertThat("RV's first child should not have focus"
+                            + (mDisableRecovery ? msg1 : (mRecyclerView.getDescendantFocusability()
+                                    == ViewGroup.FOCUS_BLOCK_DESCENDANTS ? msg2 : msg3)),
+                    fvh.itemView.hasFocus(), is(false));
+            assertThat("RV's first child should not be focused"
+                            + (mDisableRecovery ? msg1 : (mRecyclerView.getDescendantFocusability()
+                                    == ViewGroup.FOCUS_BLOCK_DESCENDANTS ? msg2 : msg3)),
+                    fvh.getViewToFocus().isFocused(), is(false));
+        } else {
+            FocusViewHolder fvh = mDisableRecovery
+                    ? cast(mRecyclerView.findViewHolderForAdapterPosition(
+                            focusedChildIndexWhenRecoveryDisabled)) :
+                    (focusedChildIndexWhenRecoveryEnabled != -1
+                            ? cast(mRecyclerView.findViewHolderForAdapterPosition(
+                                    focusedChildIndexWhenRecoveryEnabled)) :
+                    cast(mRecyclerView.findViewHolderForAdapterPosition(0)));
+
+            assertThat("test sanity", fvh, notNullValue());
+            assertThat("RV's first child should be focusable", fvh.getViewToFocus().isFocusable(),
+                    is(true));
+            String msg = " when descendant focusability is FOCUS_AFTER_DESCENDANTS";
+            assertThat("RV should pass the focus down to its children after layout" + msg,
+                    mRecyclerView.isFocused(), is(false));
+            assertThat("RV's child #" + focusedChildIndexWhenRecoveryEnabled + " should have focus"
+                            + " after layout" + msg,
+                    fvh.itemView.hasFocus(), is(true));
+            if (mFocusOnChild) {
+                assertThat("Either the ViewGroup or the TextView within the first child of RV"
+                                + "should be focused after layout" + msg,
+                        fvh.itemView.isFocused() || fvh.getViewToFocus().isFocused(), is(true));
+            } else {
+                assertThat("RV's first child should be focused after layout" + msg,
+                        fvh.getViewToFocus().isFocused(), is(true));
+            }
+
+        }
+    }
+
+    private void assertFocusTransition(RecyclerView.ViewHolder oldVh,
+            RecyclerView.ViewHolder newVh, boolean typeChanged) {
+        if (mDisableRecovery) {
+            if (mDisableAnimation) {
+                return;
+            }
+            assertFocus(newVh, false);
+            return;
+        }
+        assertThat("test sanity", newVh, notNullValue());
+        if (!typeChanged && mDisableAnimation) {
+            assertThat(oldVh, sameInstance(newVh));
+        } else {
+            assertThat(oldVh, not(sameInstance(newVh)));
+            assertFocus(oldVh, false);
+        }
+        assertFocus(newVh, true);
+    }
+
+    @Test
+    public void testFocusRecoveryInTypeChangeWithPredictive() throws Throwable {
+        testFocusRecoveryInTypeChange(true);
+    }
+
+    @Test
+    public void testFocusRecoveryInTypeChangeWithoutPredictive() throws Throwable {
+        testFocusRecoveryInTypeChange(false);
+    }
+
+    private void testFocusRecoveryInTypeChange(boolean withAnimation) throws Throwable {
+        setupBasic();
+        if (!mDisableAnimation) {
+            ((SimpleItemAnimator) (mRecyclerView.getItemAnimator()))
+                    .setSupportsChangeAnimations(true);
+        }
+        mLayoutManager.setSupportsPredictive(withAnimation);
+        final RecyclerView.ViewHolder oldVh = focusVh(3);
+        mLayoutManager.expectLayouts(!mDisableAnimation && withAnimation ? 2 : 1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Item item = mAdapter.mItems.get(3);
+                item.mType += 2;
+                mAdapter.notifyItemChanged(3);
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+
+        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3);
+        assertFocusTransition(oldVh, newVh, true);
+        assertThat("test sanity", oldVh.getItemViewType(), not(newVh.getItemViewType()));
+    }
+
+    @Test
+    public void testRecoverAdapterChangeViaStableIdOnDataSetChanged() throws Throwable {
+        recoverAdapterChangeViaStableId(false, false);
+    }
+
+    @Test
+    public void testRecoverAdapterChangeViaStableIdOnSwap() throws Throwable {
+        recoverAdapterChangeViaStableId(true, false);
+    }
+
+    @Test
+    public void testRecoverAdapterChangeViaStableIdOnDataSetChangedWithTypeChange()
+            throws Throwable {
+        recoverAdapterChangeViaStableId(false, true);
+    }
+
+    @Test
+    public void testRecoverAdapterChangeViaStableIdOnSwapWithTypeChange() throws Throwable {
+        recoverAdapterChangeViaStableId(true, true);
+    }
+
+    private void recoverAdapterChangeViaStableId(final boolean swap, final boolean changeType)
+            throws Throwable {
+        setupBasic(true);
+        RecyclerView.ViewHolder oldVh = focusVh(4);
+        long itemId = oldVh.getItemId();
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Item item = mAdapter.mItems.get(4);
+                if (changeType) {
+                    item.mType += 2;
+                }
+                if (swap) {
+                    mAdapter = new FocusTestAdapter(8);
+                    mAdapter.setHasStableIds(true);
+                    mAdapter.mItems.add(2, item);
+                    mRecyclerView.swapAdapter(mAdapter, false);
+                } else {
+                    mAdapter.mItems.remove(0);
+                    mAdapter.mItems.remove(0);
+                    mAdapter.notifyDataSetChanged();
+                }
+            }
+        });
+        mLayoutManager.waitForLayout(1);
+        if (!mDisableAnimation) {
+            waitForAnimations(2);
+        }
+
+        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForItemId(itemId);
+        if (changeType) {
+            assertFocusTransition(oldVh, newVh, true);
+        } else {
+            // in this case we should use the same VH because we have stable ids
+            assertThat(oldVh, sameInstance(newVh));
+            assertFocus(newVh, true);
+        }
+    }
+
+    @Test
+    public void testDoNotRecoverViaPositionOnSetAdapter() throws Throwable {
+        testDoNotRecoverViaPositionOnNewDataSet(new RecyclerViewLayoutTest.AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                mRecyclerView.setAdapter(new FocusTestAdapter(10));
+            }
+        });
+    }
+
+    @Test
+    public void testDoNotRecoverViaPositionOnSwapAdapterWithRecycle() throws Throwable {
+        testDoNotRecoverViaPositionOnNewDataSet(new RecyclerViewLayoutTest.AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                mRecyclerView.swapAdapter(new FocusTestAdapter(10), true);
+            }
+        });
+    }
+
+    @Test
+    public void testDoNotRecoverViaPositionOnSwapAdapterWithoutRecycle() throws Throwable {
+        testDoNotRecoverViaPositionOnNewDataSet(new RecyclerViewLayoutTest.AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                mRecyclerView.swapAdapter(new FocusTestAdapter(10), false);
+            }
+        });
+    }
+
+    public void testDoNotRecoverViaPositionOnNewDataSet(
+            final RecyclerViewLayoutTest.AdapterRunnable runnable) throws Throwable {
+        setupBasic(false);
+        assertThat("test sanity", mAdapter.hasStableIds(), is(false));
+        focusVh(4);
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    runnable.run(mAdapter);
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+
+        mLayoutManager.waitForLayout(1);
+        RecyclerView.ViewHolder otherVh = mRecyclerView.findViewHolderForAdapterPosition(4);
+        checkForMainThreadException();
+        // even if the VH is re-used, it will be removed-reAdded so focus will go away from it.
+        assertFocus("should not recover focus if data set is badly invalid", otherVh, false);
+
+    }
+
+    @Test
+    public void testDoNotRecoverIfReplacementIsNotFocusable() throws Throwable {
+        final int TYPE_NO_FOCUS = 1001;
+        TestAdapter adapter = new FocusTestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (holder.getItemViewType() == TYPE_NO_FOCUS) {
+                    cast(holder).setFocusable(false);
+                }
+            }
+        };
+        adapter.setHasStableIds(true);
+        setupBasic(adapter);
+        RecyclerView.ViewHolder oldVh = focusVh(3);
+        final long itemId = oldVh.getItemId();
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAdapter.mItems.get(3).mType = TYPE_NO_FOCUS;
+                mAdapter.notifyDataSetChanged();
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        if (!mDisableAnimation) {
+            waitForAnimations(2);
+        }
+        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForItemId(itemId);
+        assertFocus(newVh, false);
+    }
+
+    @NonNull
+    private RecyclerView.ViewHolder focusVh(int pos) throws Throwable {
+        final RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForAdapterPosition(pos);
+        assertThat("test sanity", oldVh, notNullValue());
+        requestFocus(oldVh);
+        assertFocus("test sanity", oldVh, true);
+        getInstrumentation().waitForIdleSync();
+        return oldVh;
+    }
+
+    @Test
+    public void testDoNotOverrideAdapterRequestedFocus() throws Throwable {
+        final AtomicLong toFocusId = new AtomicLong(-1);
+
+        FocusTestAdapter adapter = new FocusTestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (holder.getItemId() == toFocusId.get()) {
+                    try {
+                        requestFocus(holder);
+                    } catch (Throwable throwable) {
+                        postExceptionToInstrumentation(throwable);
+                    }
+                }
+            }
+        };
+        adapter.setHasStableIds(true);
+        toFocusId.set(adapter.mItems.get(3).mId);
+        long firstFocusId = toFocusId.get();
+        setupBasic(adapter);
+        RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForItemId(toFocusId.get());
+        assertFocus(oldVh, true);
+        toFocusId.set(mAdapter.mItems.get(5).mId);
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAdapter.mItems.get(3).mType += 2;
+                mAdapter.mItems.get(5).mType += 2;
+                mAdapter.notifyDataSetChanged();
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        if (!mDisableAnimation) {
+            waitForAnimations(2);
+        }
+        RecyclerView.ViewHolder requested = mRecyclerView.findViewHolderForItemId(toFocusId.get());
+        assertFocus(oldVh, false);
+        assertFocus(requested, true);
+        RecyclerView.ViewHolder oldReplacement = mRecyclerView
+                .findViewHolderForItemId(firstFocusId);
+        assertFocus(oldReplacement, false);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void testDoNotOverrideLayoutManagerRequestedFocus() throws Throwable {
+        final AtomicLong toFocusId = new AtomicLong(-1);
+        FocusTestAdapter adapter = new FocusTestAdapter(10);
+        adapter.setHasStableIds(true);
+
+        FocusLayoutManager lm = new FocusLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, state.getItemCount());
+                RecyclerView.ViewHolder toFocus = mRecyclerView
+                        .findViewHolderForItemId(toFocusId.get());
+                if (toFocus != null) {
+                    try {
+                        requestFocus(toFocus);
+                    } catch (Throwable throwable) {
+                        postExceptionToInstrumentation(throwable);
+                    }
+                }
+                layoutLatch.countDown();
+            }
+        };
+
+        toFocusId.set(adapter.mItems.get(3).mId);
+        long firstFocusId = toFocusId.get();
+        setupBasic(adapter, lm);
+
+        RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForItemId(toFocusId.get());
+        assertFocus(oldVh, true);
+        toFocusId.set(mAdapter.mItems.get(5).mId);
+        mLayoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(mRecyclerView);
+        mLayoutManager.waitForLayout(2);
+        RecyclerView.ViewHolder requested = mRecyclerView.findViewHolderForItemId(toFocusId.get());
+        assertFocus(oldVh, false);
+        assertFocus(requested, true);
+        RecyclerView.ViewHolder oldReplacement = mRecyclerView
+                .findViewHolderForItemId(firstFocusId);
+        assertFocus(oldReplacement, false);
+        checkForMainThreadException();
+    }
+
+    private void requestFocus(RecyclerView.ViewHolder viewHolder) throws Throwable {
+        FocusViewHolder fvh = cast(viewHolder);
+        requestFocus(fvh.getViewToFocus(), false);
+    }
+
+    private void assertFocus(RecyclerView.ViewHolder viewHolder, boolean hasFocus) {
+        assertFocus("", viewHolder, hasFocus);
+    }
+
+    private void assertFocus(String msg, RecyclerView.ViewHolder vh, boolean hasFocus) {
+        FocusViewHolder fvh = cast(vh);
+        assertThat(msg, fvh.getViewToFocus().hasFocus(), is(hasFocus));
+    }
+
+    private <T extends FocusViewHolder> T cast(RecyclerView.ViewHolder vh) {
+        assertThat(vh, instanceOf(FocusViewHolder.class));
+        //noinspection unchecked
+        return (T) vh;
+    }
+
+    private class FocusTestAdapter extends TestAdapter {
+
+        public FocusTestAdapter(int count) {
+            super(count);
+        }
+
+        @Override
+        public FocusViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                int viewType) {
+            final FocusViewHolder fvh;
+            if (mFocusOnChild) {
+                fvh = new FocusViewHolderWithChildren(
+                        LayoutInflater.from(parent.getContext())
+                                .inflate(R.layout.focus_test_item_view, parent, false));
+            } else {
+                fvh = new SimpleFocusViewHolder(new TextView(parent.getContext()));
+            }
+            fvh.setFocusable(true);
+            return fvh;
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+            cast(holder).bindTo(mItems.get(position));
+        }
+    }
+
+    private class FocusLayoutManager extends TestLayoutManager {
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            detachAndScrapAttachedViews(recycler);
+            layoutRange(recycler, 0, state.getItemCount());
+            layoutLatch.countDown();
+        }
+    }
+
+    private class FocusViewHolderWithChildren extends FocusViewHolder {
+        public final ViewGroup root;
+        public final ViewGroup parent1;
+        public final ViewGroup parent2;
+        public final TextView textView;
+
+        public FocusViewHolderWithChildren(View view) {
+            super(view);
+            root = (ViewGroup) view;
+            parent1 = (ViewGroup) root.findViewById(R.id.parent1);
+            parent2 = (ViewGroup) root.findViewById(R.id.parent2);
+            textView = (TextView) root.findViewById(R.id.text_view);
+
+        }
+
+        @Override
+        void setFocusable(boolean focusable) {
+            parent1.setFocusableInTouchMode(focusable);
+            parent2.setFocusableInTouchMode(focusable);
+            textView.setFocusableInTouchMode(focusable);
+            root.setFocusableInTouchMode(focusable);
+
+            parent1.setFocusable(focusable);
+            parent2.setFocusable(focusable);
+            textView.setFocusable(focusable);
+            root.setFocusable(focusable);
+        }
+
+        @Override
+        void onBind(Item item) {
+            textView.setText(getText(item));
+        }
+
+        @Override
+        View getViewToFocus() {
+            return textView;
+        }
+    }
+
+    private class SimpleFocusViewHolder extends FocusViewHolder {
+
+        public SimpleFocusViewHolder(View itemView) {
+            super(itemView);
+        }
+
+        @Override
+        void setFocusable(boolean focusable) {
+            itemView.setFocusableInTouchMode(focusable);
+            itemView.setFocusable(focusable);
+        }
+
+        @Override
+        View getViewToFocus() {
+            return itemView;
+        }
+
+        @Override
+        void onBind(Item item) {
+            ((TextView) (itemView)).setText(getText(item));
+        }
+    }
+
+    private abstract class FocusViewHolder extends TestViewHolder {
+
+        public FocusViewHolder(View itemView) {
+            super(itemView);
+        }
+
+        protected String getText(Item item) {
+            return item.mText + "(" + item.mId + ")";
+        }
+
+        abstract void setFocusable(boolean focusable);
+
+        abstract View getViewToFocus();
+
+        abstract void onBind(Item item);
+
+        final void bindTo(Item item) {
+            mBoundItem = item;
+            setFocusable(item.isFocusable());
+            onBind(item);
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewLayoutTest.java
new file mode 100644
index 0000000..b70fa28
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -0,0 +1,5344 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.RecyclerView.NO_POSITION;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;
+import static android.support.v7.widget.RecyclerView.getChildViewHolderInt;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.SystemClock;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.Suppress;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.NestedScrollingParent2;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.util.TouchUtils;
+import android.support.v7.widget.test.NestedScrollingParent2Adapter;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest {
+    private static final int FLAG_HORIZONTAL = 1;
+    private static final int FLAG_VERTICAL = 1 << 1;
+    private static final int FLAG_FLING = 1 << 2;
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "RecyclerViewLayoutTest";
+
+    public RecyclerViewLayoutTest() {
+        super(DEBUG);
+    }
+
+    @Test
+    public void triggerFocusSearchInOnRecycledCallback() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity()) {
+            @Override
+            void consumePendingUpdateOperations() {
+                try {
+                    super.consumePendingUpdateOperations();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        };
+        final AtomicBoolean receivedOnRecycled = new AtomicBoolean(false);
+        final TestAdapter adapter = new TestAdapter(20) {
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                super.onViewRecycled(holder);
+                if (receivedOnRecycled.getAndSet(true)) {
+                    return;
+                }
+                rv.focusSearch(rv.getChildAt(0), View.FOCUS_FORWARD);
+            }
+        };
+        final AtomicInteger layoutCnt = new AtomicInteger(5);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, layoutCnt.get());
+                layoutLatch.countDown();
+            }
+        };
+        rv.setLayoutManager(tlm);
+        rv.setAdapter(adapter);
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(2);
+
+        layoutCnt.set(4);
+        tlm.expectLayouts(1);
+        requestLayoutOnUIThread(rv);
+        tlm.waitForLayout(1);
+
+        assertThat("test sanity", rv.mRecycler.mCachedViews.size(), is(1));
+        tlm.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.notifyItemChanged(4);
+                rv.smoothScrollBy(0, 1);
+            }
+        });
+        checkForMainThreadException();
+        tlm.waitForLayout(2);
+        assertThat("test sanity", rv.mRecycler.mCachedViews.size(), is(0));
+        assertThat(receivedOnRecycled.get(), is(true));
+    }
+
+    @Test
+    public void detachAttachGetReadyWithoutChanges() throws Throwable {
+        detachAttachGetReady(false, false, false);
+    }
+
+    @Test
+    public void detachAttachGetReadyRequireLayout() throws Throwable {
+        detachAttachGetReady(true, false, false);
+    }
+
+    @Test
+    public void detachAttachGetReadyRemoveAdapter() throws Throwable {
+        detachAttachGetReady(false, true, false);
+    }
+
+    @Test
+    public void detachAttachGetReadyRemoveLayoutManager() throws Throwable {
+        detachAttachGetReady(false, false, true);
+    }
+
+    private void detachAttachGetReady(final boolean requestLayoutOnDetach,
+            final boolean removeAdapter, final boolean removeLayoutManager) throws Throwable {
+        final LinearLayout ll1 = new LinearLayout(getActivity());
+        final LinearLayout ll2 = new LinearLayout(getActivity());
+        final LinearLayout ll3 = new LinearLayout(getActivity());
+
+        final RecyclerView rv = new RecyclerView(getActivity());
+        ll1.addView(ll2);
+        ll2.addView(ll3);
+        ll3.addView(rv);
+        TestLayoutManager layoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutCompleted(RecyclerView.State state) {
+                super.onLayoutCompleted(state);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+                super.onDetachedFromWindow(view, recycler);
+                if (requestLayoutOnDetach) {
+                    view.requestLayout();
+                }
+            }
+        };
+        rv.setLayoutManager(layoutManager);
+        rv.setAdapter(new TestAdapter(10));
+        layoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().addView(ll1);
+            }
+        });
+        layoutManager.waitForLayout(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ll1.removeView(ll2);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+        if (removeLayoutManager) {
+            rv.setLayoutManager(null);
+            rv.setLayoutManager(layoutManager);
+        }
+        if (removeAdapter) {
+            rv.setAdapter(null);
+            rv.setAdapter(new TestAdapter(10));
+        }
+        final boolean requireLayout = requestLayoutOnDetach || removeAdapter || removeLayoutManager;
+        layoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ll1.addView(ll2);
+                if (requireLayout) {
+                    assertTrue(rv.hasPendingAdapterUpdates());
+                    assertFalse(rv.mFirstLayoutComplete);
+                } else {
+                    assertFalse(rv.hasPendingAdapterUpdates());
+                    assertTrue(rv.mFirstLayoutComplete);
+                }
+            }
+        });
+        if (requireLayout) {
+            layoutManager.waitForLayout(2);
+        } else {
+            layoutManager.assertNoLayout("nothing is invalid, layout should not happen", 2);
+        }
+    }
+
+    @Test
+    public void setAdapter_afterSwapAdapter_callsCorrectLmMethods() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        final TestAdapter testAdapter = new TestAdapter(1);
+
+        lm.expectLayouts(1);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        setAdapter(testAdapter);
+        lm.waitForLayout(2);
+
+        lm.onAdapterChagnedCallCount = 0;
+        lm.onItemsChangedCallCount = 0;
+
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        rv.swapAdapter(testAdapter, true);
+                        rv.setAdapter(testAdapter);
+                    }
+                });
+        lm.waitForLayout(2);
+
+        assertEquals(2, lm.onAdapterChagnedCallCount);
+        assertEquals(1, lm.onItemsChangedCallCount);
+    }
+
+    @Test
+    public void setAdapter_afterNotifyDataSetChanged_callsCorrectLmMethods() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        final TestAdapter testAdapter = new TestAdapter(1);
+
+        lm.expectLayouts(1);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        setAdapter(testAdapter);
+        lm.waitForLayout(2);
+
+        lm.onAdapterChagnedCallCount = 0;
+        lm.onItemsChangedCallCount = 0;
+
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        testAdapter.notifyDataSetChanged();
+                        rv.setAdapter(testAdapter);
+                    }
+                });
+        lm.waitForLayout(2);
+
+        assertEquals(1, lm.onAdapterChagnedCallCount);
+        assertEquals(1, lm.onItemsChangedCallCount);
+    }
+
+    @Test
+    public void notifyDataSetChanged_afterSetAdapter_callsCorrectLmMethods() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        final TestAdapter testAdapter = new TestAdapter(1);
+
+        lm.expectLayouts(1);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        setAdapter(testAdapter);
+        lm.waitForLayout(2);
+
+        lm.onAdapterChagnedCallCount = 0;
+        lm.onItemsChangedCallCount = 0;
+
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        rv.setAdapter(testAdapter);
+                        testAdapter.notifyDataSetChanged();
+                    }
+                });
+        lm.waitForLayout(2);
+
+        assertEquals(1, lm.onAdapterChagnedCallCount);
+        assertEquals(1, lm.onItemsChangedCallCount);
+    }
+
+    @Test
+    public void notifyDataSetChanged_afterSwapAdapter_callsCorrectLmMethods() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        final TestAdapter testAdapter = new TestAdapter(1);
+
+        lm.expectLayouts(1);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        setAdapter(testAdapter);
+        lm.waitForLayout(2);
+
+        lm.onAdapterChagnedCallCount = 0;
+        lm.onItemsChangedCallCount = 0;
+
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        rv.swapAdapter(testAdapter, true);
+                        testAdapter.notifyDataSetChanged();
+                    }
+                });
+        lm.waitForLayout(2);
+
+        assertEquals(1, lm.onAdapterChagnedCallCount);
+        assertEquals(1, lm.onItemsChangedCallCount);
+    }
+
+    @Test
+    public void swapAdapter_afterSetAdapter_callsCorrectLmMethods() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        final TestAdapter testAdapter = new TestAdapter(1);
+
+        lm.expectLayouts(1);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        setAdapter(testAdapter);
+        lm.waitForLayout(2);
+
+        lm.onAdapterChagnedCallCount = 0;
+        lm.onItemsChangedCallCount = 0;
+
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        rv.setAdapter(testAdapter);
+                        rv.swapAdapter(testAdapter, true);
+                    }
+                });
+        lm.waitForLayout(2);
+
+        assertEquals(2, lm.onAdapterChagnedCallCount);
+        assertEquals(1, lm.onItemsChangedCallCount);
+    }
+
+    @Test
+    public void swapAdapter_afterNotifyDataSetChanged_callsCorrectLmMethods() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        final TestAdapter testAdapter = new TestAdapter(1);
+
+        lm.expectLayouts(1);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        setAdapter(testAdapter);
+        lm.waitForLayout(2);
+
+        lm.onAdapterChagnedCallCount = 0;
+        lm.onItemsChangedCallCount = 0;
+
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        testAdapter.notifyDataSetChanged();
+                        rv.swapAdapter(testAdapter, true);
+                    }
+                });
+        lm.waitForLayout(2);
+
+        assertEquals(1, lm.onAdapterChagnedCallCount);
+        assertEquals(1, lm.onItemsChangedCallCount);
+    }
+
+    @Test
+    public void setAdapterNotifyItemRangeInsertedCrashTest() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final TestLayoutManager lm = new LayoutAllLayoutManager(true);
+        lm.setSupportsPredictive(true);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        lm.expectLayouts(1);
+        setAdapter(new TestAdapter(1));
+        lm.waitForLayout(2);
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final TestAdapter adapter2 = new TestAdapter(0);
+                rv.setAdapter(adapter2);
+                adapter2.addItems(0, 1, "1");
+                adapter2.notifyItemRangeInserted(0, 1);
+            }
+        });
+        lm.waitForLayout(2);
+    }
+
+    @Test
+    public void swapAdapterNotifyItemRangeInsertedCrashTest() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final TestLayoutManager lm = new LayoutAllLayoutManager(true);
+        lm.setSupportsPredictive(true);
+        rv.setLayoutManager(lm);
+        setRecyclerView(rv);
+        lm.expectLayouts(1);
+        setAdapter(new TestAdapter(1));
+        lm.waitForLayout(2);
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final TestAdapter adapter2 = new TestAdapter(0);
+                rv.swapAdapter(adapter2, true);
+                adapter2.addItems(0, 1, "1");
+                adapter2.notifyItemRangeInserted(0, 1);
+            }
+        });
+        lm.waitForLayout(2);
+    }
+
+    @Test
+    public void onDataSetChanged_doesntHaveStableIds_cachedViewHasNoPosition() throws Throwable {
+        onDataSetChanged_handleCachedViews(false);
+    }
+
+    @Test
+    public void onDataSetChanged_hasStableIds_noCachedViewsAreRecycled() throws Throwable {
+        onDataSetChanged_handleCachedViews(true);
+    }
+
+    /**
+     * If Adapter#setHasStableIds(boolean) is false, cached ViewHolders should be recycled in
+     * response to RecyclerView.Adapter#notifyDataSetChanged() and should report a position of
+     * RecyclerView#NO_POSITION inside of
+     * RecyclerView.Adapter#onViewRecycled(RecyclerView.ViewHolder).
+     *
+     * If Adapter#setHasStableIds(boolean) is true, cached Views/ViewHolders should not be recycled.
+     */
+    public void onDataSetChanged_handleCachedViews(boolean hasStableIds) throws Throwable {
+        final AtomicInteger cachedRecycleCount = new AtomicInteger(0);
+
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setItemViewCacheSize(1);
+
+        final TestAdapter adapter = new TestAdapter(2) {
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                // If the recycled holder is currently in the cache, then it's position in the
+                // adapter should be RecyclerView.NO_POSITION.
+                if (mRecyclerView.mRecycler.mCachedViews.contains(holder)) {
+                    assertThat("ViewHolder's getAdapterPosition should be "
+                                    + "RecyclerView.NO_POSITION",
+                            holder.getAdapterPosition(),
+                            is(RecyclerView.NO_POSITION));
+                    cachedRecycleCount.incrementAndGet();
+                }
+                super.onViewRecycled(holder);
+            }
+        };
+        adapter.setHasStableIds(hasStableIds);
+        recyclerView.setAdapter(adapter);
+
+        final AtomicInteger numItemsToLayout = new AtomicInteger(2);
+
+        TestLayoutManager layoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    detachAndScrapAttachedViews(recycler);
+                    layoutRange(recycler, 0, numItemsToLayout.get());
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    this.layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return false;
+            }
+        };
+        recyclerView.setLayoutManager(layoutManager);
+
+        // Layout 2 items and sanity check that no items are in the recycler's cache.
+        numItemsToLayout.set(2);
+        layoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView, true, false);
+        layoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        assertThat("Sanity check, no views should be cached at this time",
+                mRecyclerView.mRecycler.mCachedViews.size(),
+                is(0));
+
+        // Now only layout 1 item and assert that 1 item is cached.
+        numItemsToLayout.set(1);
+        layoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(mRecyclerView);
+        layoutManager.waitForLayout(1);
+        checkForMainThreadException();
+        assertThat("One view should be cached.",
+                mRecyclerView.mRecycler.mCachedViews.size(),
+                is(1));
+
+        // Notify data set has changed then final assert.
+        layoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.notifyDataSetChanged();
+            }
+        });
+        layoutManager.waitForLayout(1);
+        checkForMainThreadException();
+        // If hasStableIds, then no cached views should be recycled, otherwise just 1 should have
+        // been recycled.
+        assertThat(cachedRecycleCount.get(), is(hasStableIds ? 0 : 1));
+    }
+
+    @Test
+    public void notifyDataSetChanged_hasStableIds_cachedViewsAreReusedForSamePositions()
+            throws Throwable {
+        final Map<Integer, TestViewHolder> positionToViewHolderMap = new HashMap<>();
+        final AtomicInteger layoutItemCount = new AtomicInteger();
+        final AtomicBoolean inFirstBindViewHolderPass = new AtomicBoolean();
+
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setItemViewCacheSize(5);
+
+        final TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+                // Only track the top 5 positions that are going to be cached and then reused.
+                if (position >= 5) {
+                    // If we are in the first phase, put the items in the map, if we are in the
+                    // second phase, remove each one at the position and verify that it matches the
+                    // provided ViewHolder.
+                    if (inFirstBindViewHolderPass.get()) {
+                        positionToViewHolderMap.put(position, holder);
+                    } else {
+                        TestViewHolder testViewHolder = positionToViewHolderMap.get(position);
+                        assertThat(holder, is(testViewHolder));
+                        positionToViewHolderMap.remove(position);
+                    }
+                }
+                super.onBindViewHolder(holder, position);
+            }
+        };
+        adapter.setHasStableIds(true);
+        recyclerView.setAdapter(adapter);
+
+        TestLayoutManager testLayoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    detachAndScrapAttachedViews(recycler);
+                    layoutRange(recycler, 0, layoutItemCount.get());
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return false;
+            }
+        };
+        recyclerView.setLayoutManager(testLayoutManager);
+
+        // First layout 10 items, then verify that the map has all 5 ViewHolders in it that will
+        // be cached, and sanity check that the cache is empty.
+        inFirstBindViewHolderPass.set(true);
+        layoutItemCount.set(10);
+        testLayoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView, true, false);
+        testLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        for (int i = 5; i < 10; i++) {
+            assertThat(positionToViewHolderMap.get(i), notNullValue());
+        }
+        assertThat(mRecyclerView.mRecycler.mCachedViews.size(), is(0));
+
+        // Now only layout the first 5 items and verify that the cache has 5 items in it.
+        layoutItemCount.set(5);
+        testLayoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(mRecyclerView);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+        assertThat(mRecyclerView.mRecycler.mCachedViews.size(), is(5));
+
+        // Trigger notifyDataSetChanged and wait for layout.
+        testLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.notifyDataSetChanged();
+            }
+        });
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+
+        // Layout 10 items again, via the onBindViewholder method, check that each one of the views
+        // returned from the recycler for positions >= 5 was in our cache of views, and verify that
+        // all 5 cached views were returned.
+        inFirstBindViewHolderPass.set(false);
+        layoutItemCount.set(10);
+        testLayoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(mRecyclerView);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+        assertThat(positionToViewHolderMap.size(), is(0));
+    }
+
+    @Test
+    public void predictiveMeasuredCrashTest() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true) {
+            @Override
+            public void onAttachedToWindow(RecyclerView view) {
+                super.onAttachedToWindow(view);
+                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
+            }
+
+            @Override
+            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+                super.onDetachedFromWindow(view, recycler);
+                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
+            }
+
+            @Override
+            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
+                    int widthSpec,
+                    int heightSpec) {
+                if (state.getItemCount() > 0) {
+                    // A typical LayoutManager will use a child view to measure the size.
+                    View v = recycler.getViewForPosition(0);
+                }
+                super.onMeasure(recycler, state, widthSpec, heightSpec);
+            }
+
+            @Override
+            public boolean isAutoMeasureEnabled() {
+                return false;
+            }
+        };
+        lm.setSupportsPredictive(true);
+        rv.setHasFixedSize(false);
+        final TestAdapter adapter = new TestAdapter(0);
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(rv);
+        lm.waitForLayout(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ViewGroup parent = (ViewGroup) rv.getParent();
+                parent.removeView(rv);
+                // setting RV as child of LinearLayout using MATCH_PARENT will cause
+                // RV.onMeasure() being called twice before layout(). This may cause crash.
+                LinearLayout linearLayout = new LinearLayout(parent.getContext());
+                linearLayout.setOrientation(LinearLayout.VERTICAL);
+                parent.addView(linearLayout,
+                        ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+                linearLayout.addView(rv, ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+
+            }
+        });
+
+        lm.expectLayouts(1);
+        adapter.addAndNotify(1);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void detachRvAndLayoutManagerProperly() throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true) {
+            @Override
+            public void onAttachedToWindow(RecyclerView view) {
+                super.onAttachedToWindow(view);
+                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
+            }
+
+            @Override
+            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+                super.onDetachedFromWindow(view, recycler);
+                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
+            }
+        };
+        final Runnable check = new Runnable() {
+            @Override
+            public void run() {
+                assertThat("bound between the RV and the LM should be disconnected at the"
+                        + " same time", rv.mLayout == lm, is(lm.mRecyclerView == rv));
+            }
+        };
+        final AtomicInteger detachCounter = new AtomicInteger(0);
+        rv.setAdapter(new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                holder.itemView.setFocusable(true);
+                holder.itemView.setFocusableInTouchMode(true);
+            }
+
+            @Override
+            public void onViewDetachedFromWindow(TestViewHolder holder) {
+                super.onViewDetachedFromWindow(holder);
+                detachCounter.incrementAndGet();
+                check.run();
+            }
+
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                super.onViewRecycled(holder);
+                check.run();
+            }
+        });
+        rv.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(rv);
+        lm.waitForLayout(2);
+        assertThat("test sanity", rv.getChildCount(), is(10));
+
+        final TestLayoutManager replacement = new LayoutAllLayoutManager(true);
+        replacement.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rv.setLayoutManager(replacement);
+            }
+        });
+        replacement.waitForLayout(2);
+        assertThat("test sanity", rv.getChildCount(), is(10));
+        assertThat("all initial views should be detached", detachCounter.get(), is(10));
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void focusSearchWithOtherFocusables() throws Throwable {
+        final LinearLayout container = new LinearLayout(getActivity());
+        container.setOrientation(LinearLayout.VERTICAL);
+        RecyclerView rv = new RecyclerView(getActivity());
+        mRecyclerView = rv;
+        rv.setAdapter(new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                holder.itemView.setFocusableInTouchMode(true);
+                holder.itemView.setLayoutParams(
+                        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                                ViewGroup.LayoutParams.WRAP_CONTENT));
+            }
+        });
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, 1);
+                layoutLatch.countDown();
+            }
+
+            @Nullable
+            @Override
+            public View onFocusSearchFailed(View focused, int direction,
+                    RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                int expectedDir = Build.VERSION.SDK_INT <= 15 ? View.FOCUS_DOWN :
+                        View.FOCUS_FORWARD;
+                assertEquals(expectedDir, direction);
+                assertEquals(1, getChildCount());
+                View child0 = getChildAt(0);
+                View view = recycler.getViewForPosition(1);
+                addView(view);
+                measureChild(view, 0, 0);
+                layoutDecorated(view, 0, child0.getBottom(), getDecoratedMeasuredWidth(view),
+                        child0.getBottom() + getDecoratedMeasuredHeight(view));
+                return view;
+            }
+
+            @Override
+            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                super.scrollHorizontallyBy(dx, recycler, state);
+                // offset by -dx because the views translate opposite of the scrolling direction
+                mRecyclerView.offsetChildrenHorizontal(-dx);
+                return dx;
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                super.scrollVerticallyBy(dy, recycler, state);
+                // offset by -dy because the views translate opposite of the scrolling direction
+                mRecyclerView.offsetChildrenVertical(-dy);
+                return dy;
+            }
+
+            @Override
+            public boolean isAutoMeasureEnabled() {
+                return true;
+            }
+        };
+        rv.setLayoutManager(tlm);
+        TextView viewAbove = new TextView(getActivity());
+        viewAbove.setText("view above");
+        viewAbove.setFocusableInTouchMode(true);
+        container.addView(viewAbove);
+        container.addView(rv);
+        TextView viewBelow = new TextView(getActivity());
+        viewBelow.setText("view below");
+        viewBelow.setFocusableInTouchMode(true);
+        container.addView(viewBelow);
+        tlm.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().addView(container);
+            }
+        });
+
+        tlm.waitForLayout(2);
+        requestFocus(viewAbove, true);
+        assertTrue(viewAbove.hasFocus());
+        View newFocused = focusSearch(viewAbove, View.FOCUS_FORWARD);
+        assertThat(newFocused, sameInstance(rv.getChildAt(0)));
+        newFocused = focusSearch(rv.getChildAt(0), View.FOCUS_FORWARD);
+        assertThat(newFocused, sameInstance(rv.getChildAt(1)));
+    }
+
+    @Test
+    public void boundingBoxNoTranslation() throws Throwable {
+        transformedBoundingBoxTest(new ViewRunnable() {
+            @Override
+            public void run(View view) throws RuntimeException {
+                view.layout(10, 10, 30, 50);
+                assertThat(getTransformedBoundingBox(view), is(new Rect(10, 10, 30, 50)));
+            }
+        });
+    }
+
+    @Test
+    public void boundingBoxTranslateX() throws Throwable {
+        transformedBoundingBoxTest(new ViewRunnable() {
+            @Override
+            public void run(View view) throws RuntimeException {
+                view.layout(10, 10, 30, 50);
+                view.setTranslationX(10);
+                assertThat(getTransformedBoundingBox(view), is(new Rect(20, 10, 40, 50)));
+            }
+        });
+    }
+
+    @Test
+    public void boundingBoxTranslateY() throws Throwable {
+        transformedBoundingBoxTest(new ViewRunnable() {
+            @Override
+            public void run(View view) throws RuntimeException {
+                view.layout(10, 10, 30, 50);
+                view.setTranslationY(10);
+                assertThat(getTransformedBoundingBox(view), is(new Rect(10, 20, 30, 60)));
+            }
+        });
+    }
+
+    @Test
+    public void boundingBoxScaleX() throws Throwable {
+        transformedBoundingBoxTest(new ViewRunnable() {
+            @Override
+            public void run(View view) throws RuntimeException {
+                view.layout(10, 10, 30, 50);
+                view.setScaleX(2);
+                assertThat(getTransformedBoundingBox(view), is(new Rect(0, 10, 40, 50)));
+            }
+        });
+    }
+
+    @Test
+    public void boundingBoxScaleY() throws Throwable {
+        transformedBoundingBoxTest(new ViewRunnable() {
+            @Override
+            public void run(View view) throws RuntimeException {
+                view.layout(10, 10, 30, 50);
+                view.setScaleY(2);
+                assertThat(getTransformedBoundingBox(view), is(new Rect(10, -10, 30, 70)));
+            }
+        });
+    }
+
+    @Test
+    public void boundingBoxRotated() throws Throwable {
+        transformedBoundingBoxTest(new ViewRunnable() {
+            @Override
+            public void run(View view) throws RuntimeException {
+                view.layout(10, 10, 30, 50);
+                view.setRotation(90);
+                assertThat(getTransformedBoundingBox(view), is(new Rect(0, 20, 40, 40)));
+            }
+        });
+    }
+
+    @Test
+    public void boundingBoxRotatedWithDecorOffsets() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final TestAdapter adapter = new TestAdapter(1);
+        recyclerView.setAdapter(adapter);
+        recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
+            @Override
+            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                    RecyclerView.State state) {
+                outRect.set(1, 2, 3, 4);
+            }
+        });
+        TestLayoutManager layoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                View view = recycler.getViewForPosition(0);
+                addView(view);
+                view.measure(
+                        View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY),
+                        View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY)
+                );
+                // trigger decor offsets calculation
+                calculateItemDecorationsForChild(view, new Rect());
+                view.layout(10, 10, 30, 50);
+                view.setRotation(90);
+                assertThat(RecyclerViewLayoutTest.this.getTransformedBoundingBox(view),
+                        is(new Rect(-4, 19, 42, 43)));
+
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setLayoutManager(layoutManager);
+        layoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        layoutManager.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    private Rect getTransformedBoundingBox(View child) {
+        Rect rect = new Rect();
+        mRecyclerView.getLayoutManager().getTransformedBoundingBox(child, true, rect);
+        return rect;
+    }
+
+    public void transformedBoundingBoxTest(final ViewRunnable layout) throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final TestAdapter adapter = new TestAdapter(1);
+        recyclerView.setAdapter(adapter);
+        TestLayoutManager layoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                View view = recycler.getViewForPosition(0);
+                addView(view);
+                view.measure(
+                        View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY),
+                        View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY)
+                );
+                layout.run(view);
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setLayoutManager(layoutManager);
+        layoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        layoutManager.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void flingFrozen() throws Throwable {
+        testScrollFrozen(true);
+    }
+
+    @Test
+    public void dragFrozen() throws Throwable {
+        testScrollFrozen(false);
+    }
+
+    @Test
+    public void requestRectOnScreenWithScrollOffset() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final LayoutAllLayoutManager tlm = spy(new LayoutAllLayoutManager());
+        final int scrollY = 50;
+        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
+            @Override
+            public RecyclerView.ViewHolder onCreateViewHolder(
+                    @NonNull ViewGroup parent, int viewType) {
+                View view = new View(parent.getContext());
+                view.setScrollY(scrollY);
+                return new RecyclerView.ViewHolder(view) {};
+            }
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {}
+            @Override
+            public int getItemCount() {
+                return 1;
+            }
+        };
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        final View child = recyclerView.getChildAt(0);
+        assertThat(child.getScrollY(), CoreMatchers.is(scrollY));
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.requestChildRectangleOnScreen(child, new Rect(3, 4, 5, 6), true);
+                verify(tlm, times(1)).scrollVerticallyBy(eq(-46), any(RecyclerView.Recycler.class),
+                        any(RecyclerView.State.class));
+            }
+        });
+    }
+
+    @Test
+    public void reattachAndScrollCrash() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final TestLayoutManager tlm = new TestLayoutManager() {
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, Math.min(state.getItemCount(), 10));
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                // Access views in the state (that might have been deleted).
+                for (int  i = 10; i < state.getItemCount(); i++) {
+                    recycler.getViewForPosition(i);
+                }
+                return dy;
+            }
+        };
+
+        final TestAdapter adapter = new TestAdapter(12);
+
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+
+        setRecyclerView(recyclerView);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().removeView(recyclerView);
+                getActivity().getContainer().addView(recyclerView);
+                try {
+                    adapter.deleteAndNotify(1, adapter.getItemCount() - 1);
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+                recyclerView.scrollBy(0, 10);
+            }
+        });
+    }
+
+    private void testScrollFrozen(boolean fling) throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+
+        final int horizontalScrollCount = 3;
+        final int verticalScrollCount = 3;
+        final int horizontalVelocity = 1000;
+        final int verticalVelocity = 1000;
+        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
+        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public boolean canScrollHorizontally() {
+                return true;
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, 10);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                if (verticalCounter.get() > 0) {
+                    verticalCounter.decrementAndGet();
+                    return dy;
+                }
+                return 0;
+            }
+
+            @Override
+            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                if (horizontalCounter.get() > 0) {
+                    horizontalCounter.decrementAndGet();
+                    return dx;
+                }
+                return 0;
+            }
+        };
+        TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(2);
+
+        freezeLayout(true);
+
+        if (fling) {
+            assertFalse("fling should be blocked", fling(horizontalVelocity, verticalVelocity));
+        } else { // drag
+            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
+                    Gravity.LEFT | Gravity.TOP,
+                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
+        }
+        assertEquals("rv's horizontal scroll cb must not run", horizontalScrollCount,
+                horizontalCounter.get());
+        assertEquals("rv's vertical scroll cb must not run", verticalScrollCount,
+                verticalCounter.get());
+
+        freezeLayout(false);
+
+        if (fling) {
+            assertTrue("fling should be started", fling(horizontalVelocity, verticalVelocity));
+        } else { // drag
+            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
+                    Gravity.LEFT | Gravity.TOP,
+                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
+        }
+        assertEquals("rv's horizontal scroll cb must finishes", 0, horizontalCounter.get());
+        assertEquals("rv's vertical scroll cb must finishes", 0, verticalCounter.get());
+    }
+
+    @Test
+    public void testFocusSearchAfterChangedData() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, 2);
+                layoutLatch.countDown();
+            }
+
+            @Nullable
+            @Override
+            public View onFocusSearchFailed(View focused, int direction,
+                    RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                try {
+                    recycler.getViewForPosition(state.getItemCount() - 1);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+                return null;
+            }
+        };
+        recyclerView.setLayoutManager(tlm);
+        final TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+                super.onBindViewHolder(holder, position);
+                holder.itemView.setFocusable(false);
+                holder.itemView.setFocusableInTouchMode(false);
+            }
+        };
+        recyclerView.setAdapter(adapter);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.mItems.remove(9);
+                adapter.notifyItemRemoved(9);
+                recyclerView.focusSearch(recyclerView.getChildAt(1), View.FOCUS_DOWN);
+            }
+        });
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void testFocusSearchWithRemovedFocusedItem() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setItemAnimator(null);
+        TestLayoutManager tlm = new LayoutAllLayoutManager();
+        recyclerView.setLayoutManager(tlm);
+        final TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+                super.onBindViewHolder(holder, position);
+                holder.itemView.setFocusable(true);
+                holder.itemView.setFocusableInTouchMode(true);
+            }
+        };
+        recyclerView.setAdapter(adapter);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        final RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(9);
+        requestFocus(toFocus.itemView, true);
+        assertThat("test sanity", toFocus.itemView.hasFocus(), is(true));
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.mItems.remove(9);
+                adapter.notifyItemRemoved(9);
+                recyclerView.focusSearch(toFocus.itemView, View.FOCUS_DOWN);
+            }
+        });
+        checkForMainThreadException();
+    }
+
+
+    @Test
+    public void  testFocusSearchFailFrozen() throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        final CountDownLatch focusLatch = new CountDownLatch(1);
+        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public boolean canScrollHorizontally() {
+                return true;
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, 10);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public View onFocusSearchFailed(View focused, int direction,
+                    RecyclerView.Recycler recycler, RecyclerView.State state) {
+                focusSearchCalled.addAndGet(1);
+                focusLatch.countDown();
+                return null;
+            }
+        };
+        TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(2);
+        final View c = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
+        assertTrue("test sanity", requestFocus(c, true));
+        assertTrue("test sanity", c.hasFocus());
+        freezeLayout(true);
+        focusSearch(recyclerView, c, View.FOCUS_DOWN);
+        assertEquals("onFocusSearchFailed should not be called when layout is frozen",
+                0, focusSearchCalled.get());
+        freezeLayout(false);
+        focusSearch(c, View.FOCUS_DOWN);
+        assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
+        assertEquals(1, focusSearchCalled.get());
+    }
+
+    public View focusSearch(final ViewGroup parent, final View focused, final int direction)
+            throws Throwable {
+        final View[] result = new View[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                result[0] = parent.focusSearch(focused, direction);
+            }
+        });
+        return result[0];
+    }
+
+    @Test
+    public void frozenAndChangeAdapter() throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+
+        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public boolean canScrollHorizontally() {
+                return true;
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, 10);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                focusSearchCalled.addAndGet(1);
+                return null;
+            }
+        };
+        TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(2);
+
+        freezeLayout(true);
+        TestAdapter adapter2 = new TestAdapter(1000);
+        setAdapter(adapter2);
+        assertFalse(recyclerView.isLayoutFrozen());
+        assertSame(adapter2, recyclerView.getAdapter());
+
+        freezeLayout(true);
+        TestAdapter adapter3 = new TestAdapter(1000);
+        swapAdapter(adapter3, true);
+        assertFalse(recyclerView.isLayoutFrozen());
+        assertSame(adapter3, recyclerView.getAdapter());
+    }
+
+    @Test
+    public void moveAndUpdateCachedViews() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setItemViewCacheSize(3);
+        recyclerView.setItemAnimator(null);
+        final TestAdapter adapter = new TestAdapter(1000);
+        final CountDownLatch layoutLatch = new CountDownLatch(1);
+        LinearLayoutManager tlm = new LinearLayoutManager(recyclerView.getContext()) {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutLatch.countDown();
+            }
+        };
+        tlm.setItemPrefetchEnabled(false);
+        recyclerView.setLayoutManager(tlm);
+        recyclerView.setAdapter(adapter);
+        setRecyclerView(recyclerView);
+        // wait first layout pass
+        layoutLatch.await();
+        // scroll and hide 0 and 1
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.smoothScrollBy(0, recyclerView.getChildAt(2).getTop() + 5);
+            }
+        });
+        waitForIdleScroll(recyclerView);
+        assertNull(recyclerView.findViewHolderForAdapterPosition(0));
+        assertNull(recyclerView.findViewHolderForAdapterPosition(1));
+        // swap 1 and 0 and update 0
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    // swap 1 and 0
+                    adapter.moveInUIThread(1, 0);
+                    adapter.notifyItemMoved(1, 0);
+                    // update 0
+                    adapter.mItems.get(0).mText = "updated";
+                    adapter.notifyItemChanged(0);
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+        // scroll back to 0
+        smoothScrollToPosition(0);
+        waitForIdleScroll(recyclerView);
+        TestViewHolder vh = (TestViewHolder) recyclerView.findViewHolderForAdapterPosition(0);
+        // assert updated right item
+        assertTrue((((TextView) (vh.itemView)).getText()).toString().contains("updated"));
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void noLayoutIf0ItemsAreChanged() throws Throwable {
+        unnecessaryNotifyEvents(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.notifyItemRangeChanged(3, 0);
+            }
+        });
+    }
+
+    @Test
+    public void noLayoutIf0ItemsAreChangedWithPayload() throws Throwable {
+        unnecessaryNotifyEvents(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.notifyItemRangeChanged(0, 0, new Object());
+            }
+        });
+    }
+
+    @Test
+    public void noLayoutIf0ItemsAreAdded() throws Throwable {
+        unnecessaryNotifyEvents(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.notifyItemRangeInserted(3, 0);
+            }
+        });
+    }
+
+    @Test
+    public void noLayoutIf0ItemsAreRemoved() throws Throwable {
+        unnecessaryNotifyEvents(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.notifyItemRangeRemoved(3, 0);
+            }
+        });
+    }
+
+    @Test
+    public void noLayoutIfItemMovedIntoItsOwnPlace() throws Throwable {
+        unnecessaryNotifyEvents(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.notifyItemMoved(3, 3);
+            }
+        });
+    }
+
+    public void unnecessaryNotifyEvents(final AdapterRunnable action) throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final TestAdapter adapter = new TestAdapter(5);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setLayoutManager(tlm);
+        recyclerView.setAdapter(adapter);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        // ready
+        tlm.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    action.run(adapter);
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+        tlm.assertNoLayout("dummy event should not trigger a layout", 1);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void scrollToPositionCallback() throws Throwable {
+
+        class TestRecyclerView extends RecyclerView {
+
+            private CountDownLatch mDrawLatch;
+
+            TestRecyclerView(Context context) {
+                super(context);
+            }
+
+            public void expectDraws(int count) {
+                mDrawLatch = new CountDownLatch(count);
+            }
+
+            public void waitForDraw(int seconds) throws InterruptedException {
+                mDrawLatch.await(seconds, TimeUnit.SECONDS);
+            }
+
+            @Override
+            public void onDraw(Canvas c) {
+                super.onDraw(c);
+                if (mDrawLatch != null) {
+                    mDrawLatch.countDown();
+                }
+            }
+        }
+
+        TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
+        TestLayoutManager tlm = new TestLayoutManager() {
+            int scrollPos = RecyclerView.NO_POSITION;
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutLatch.countDown();
+                if (scrollPos == RecyclerView.NO_POSITION) {
+                    layoutRange(recycler, 0, 10);
+                } else {
+                    layoutRange(recycler, scrollPos, scrollPos + 10);
+                }
+            }
+
+            @Override
+            public void scrollToPosition(int position) {
+                scrollPos = position;
+                requestLayout();
+            }
+        };
+        recyclerView.setLayoutManager(tlm);
+        TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        final AtomicInteger rvCounter = new AtomicInteger(0);
+        final AtomicInteger viewGroupCounter = new AtomicInteger(0);
+
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                rvCounter.incrementAndGet();
+            }
+        });
+
+        getRecyclerViewContainer().getViewTreeObserver().addOnScrollChangedListener(
+                new ViewTreeObserver.OnScrollChangedListener() {
+                    @Override
+                    public void onScrollChanged() {
+                        viewGroupCounter.incrementAndGet();
+                    }
+                });
+
+        recyclerView.expectDraws(1);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(2);
+        recyclerView.waitForDraw(2);
+        assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get());
+        assertEquals("VTO on scroll should be called for initialization", 1,
+                viewGroupCounter.get());
+
+        recyclerView.expectDraws(1);
+        tlm.expectLayouts(1);
+        freezeLayout(true);
+        scrollToPosition(3);
+        tlm.assertNoLayout("scrollToPosition should be ignored", 2);
+        freezeLayout(false);
+        scrollToPosition(3);
+        tlm.waitForLayout(2);
+        recyclerView.waitForDraw(2);
+        assertEquals("RV on scroll should be called", 2, rvCounter.get());
+        assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get());
+
+        recyclerView.expectDraws(1);
+        tlm.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        tlm.waitForLayout(2);
+        recyclerView.waitForDraw(2);
+        assertEquals("on scroll should NOT be called", 2, rvCounter.get());
+        assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get());
+    }
+
+    @Test
+    public void scrollCallbackFromEmptyToSome() throws Throwable {
+        scrollCallbackOnVisibleRangeChange(1, new int[]{0, 0}, new int[]{0, 1});
+    }
+
+    @Test
+    public void scrollCallbackOnVisibleRangeExpand() throws Throwable {
+        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{3, 6});
+    }
+
+    @Test
+    public void scrollCallbackOnVisibleRangeShrink() throws Throwable {
+        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{3, 5});
+    }
+
+    @Test
+    public void scrollCallbackOnVisibleRangeExpand2() throws Throwable {
+        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{2, 5});
+    }
+
+    @Test
+    public void scrollCallbackOnVisibleRangeShrink2() throws Throwable {
+        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{2, 6});
+    }
+
+    private void scrollCallbackOnVisibleRangeChange(int itemCount, final int[] beforeRange,
+            final int[] afterRange) throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity()) {
+            @Override
+            void dispatchLayout() {
+                super.dispatchLayout();
+                ((TestLayoutManager) getLayoutManager()).layoutLatch.countDown();
+            }
+        };
+        final AtomicBoolean beforeState = new AtomicBoolean(true);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                int[] range = beforeState.get() ? beforeRange : afterRange;
+                layoutRange(recycler, range[0], range[1]);
+            }
+        };
+        recyclerView.setLayoutManager(tlm);
+        final TestAdapter adapter = new TestAdapter(itemCount);
+        recyclerView.setAdapter(adapter);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+
+        RecyclerView.OnScrollListener mockListener = mock(RecyclerView.OnScrollListener.class);
+        recyclerView.addOnScrollListener(mockListener);
+        verify(mockListener, never()).onScrolled(any(RecyclerView.class), anyInt(), anyInt());
+
+        tlm.expectLayouts(1);
+        beforeState.set(false);
+        requestLayoutOnUIThread(recyclerView);
+        tlm.waitForLayout(2);
+        checkForMainThreadException();
+        verify(mockListener).onScrolled(recyclerView, 0, 0);
+    }
+
+    @Test
+    public void addItemOnScroll() throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        final AtomicInteger start = new AtomicInteger(0);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, start.get(), start.get() + 10);
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setLayoutManager(tlm);
+        final TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        final Throwable[] error = new Throwable[1];
+        final AtomicBoolean calledOnScroll = new AtomicBoolean(false);
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+                super.onScrolled(recyclerView, dx, dy);
+                calledOnScroll.set(true);
+                try {
+                    adapter.addAndNotify(5, 20);
+                } catch (Throwable throwable) {
+                    error[0] = throwable;
+                }
+            }
+        });
+        start.set(4);
+        MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(false));
+        tlm.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        tlm.waitForLayout(2);
+        checkForMainThreadException();
+        MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(true));
+        MatcherAssert.assertThat(error[0], CoreMatchers.nullValue());
+    }
+
+    @Test
+    public void scrollInBothDirectionEqual() throws Throwable {
+        scrollInBothDirection(3, 3, 1000, 1000);
+    }
+
+    @Test
+    public void scrollInBothDirectionMoreVertical() throws Throwable {
+        scrollInBothDirection(2, 3, 1000, 1000);
+    }
+
+    @Test
+    public void scrollInBothDirectionMoreHorizontal() throws Throwable {
+        scrollInBothDirection(3, 2, 1000, 1000);
+    }
+
+    @Test
+    public void scrollHorizontalOnly() throws Throwable {
+        scrollInBothDirection(3, 0, 1000, 0);
+    }
+
+    @Test
+    public void scrollVerticalOnly() throws Throwable {
+        scrollInBothDirection(0, 3, 0, 1000);
+    }
+
+    @Test
+    public void scrollInBothDirectionEqualReverse() throws Throwable {
+        scrollInBothDirection(3, 3, -1000, -1000);
+    }
+
+    @Test
+    public void scrollInBothDirectionMoreVerticalReverse() throws Throwable {
+        scrollInBothDirection(2, 3, -1000, -1000);
+    }
+
+    @Test
+    public void scrollInBothDirectionMoreHorizontalReverse() throws Throwable {
+        scrollInBothDirection(3, 2, -1000, -1000);
+    }
+
+    @Test
+    public void scrollHorizontalOnlyReverse() throws Throwable {
+        scrollInBothDirection(3, 0, -1000, 0);
+    }
+
+    @Test
+    public void scrollVerticalOnlyReverse() throws Throwable {
+        scrollInBothDirection(0, 3, 0, -1000);
+    }
+
+    public void scrollInBothDirection(int horizontalScrollCount, int verticalScrollCount,
+            int horizontalVelocity, int verticalVelocity)
+            throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
+        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public boolean canScrollHorizontally() {
+                return true;
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, 10);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                if (verticalCounter.get() > 0) {
+                    verticalCounter.decrementAndGet();
+                    return dy;
+                }
+                return 0;
+            }
+
+            @Override
+            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                if (horizontalCounter.get() > 0) {
+                    horizontalCounter.decrementAndGet();
+                    return dx;
+                }
+                return 0;
+            }
+        };
+        TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(2);
+        assertTrue("test sanity, fling must run", fling(horizontalVelocity, verticalVelocity));
+        assertEquals("rv's horizontal scroll cb must run " + horizontalScrollCount + " times'", 0,
+                horizontalCounter.get());
+        assertEquals("rv's vertical scroll cb must run " + verticalScrollCount + " times'", 0,
+                verticalCounter.get());
+    }
+
+    @Test
+    public void dragHorizontal() throws Throwable {
+        scrollInOtherOrientationTest(FLAG_HORIZONTAL);
+    }
+
+    @Test
+    public void dragVertical() throws Throwable {
+        scrollInOtherOrientationTest(FLAG_VERTICAL);
+    }
+
+    @Test
+    public void flingHorizontal() throws Throwable {
+        scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING);
+    }
+
+    @Test
+    public void flingVertical() throws Throwable {
+        scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING);
+    }
+
+    @SuppressWarnings("WrongConstant")
+    @Test
+    public void nestedDragVertical() throws Throwable {
+        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
+        getActivity().getContainer().setNestedScrollingDelegate(nsp);
+        // Scroll and expect the RV to not scroll
+        scrollInOtherOrientationTest(FLAG_VERTICAL, 0);
+
+        // Verify that the touch nested scroll was started and finished
+        verify(nsp, atLeastOnce()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, atLeastOnce()).onStopNestedScroll(eq(mRecyclerView), eq(ViewCompat.TYPE_TOUCH));
+
+        // Verify that the non-touch events were dispatched by the fling settle
+        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
+    }
+
+    @SuppressWarnings("WrongConstant")
+    @Test
+    public void nestedDragHorizontal() throws Throwable {
+        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
+        getActivity().getContainer().setNestedScrollingDelegate(nsp);
+        // Scroll and expect the RV to not scroll
+        scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0);
+
+        // Verify that the touch nested scroll was started and finished
+        verify(nsp, atLeastOnce()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, atLeastOnce()).onStopNestedScroll(eq(mRecyclerView), eq(ViewCompat.TYPE_TOUCH));
+
+        // Verify that the non-touch events were dispatched by the fling settle
+        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
+    }
+
+    @SuppressWarnings("WrongConstant")
+    @Test
+    public void nestedFlingVertical() throws Throwable {
+        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
+        getActivity().getContainer().setNestedScrollingDelegate(nsp);
+        // Fling and expect the RV to not scroll
+        scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING, FLAG_FLING);
+
+        // Verify that the touch nested scroll was not started
+        verify(nsp, never()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, never()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, never()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, never()).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_TOUCH);
+
+        // Verify that the non-touch nested scroll was started and finished
+        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, times(1)).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_NON_TOUCH);
+    }
+
+    @SuppressWarnings("WrongConstant")
+    @Test
+    public void nestedFlingHorizontal() throws Throwable {
+        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
+        getActivity().getContainer().setNestedScrollingDelegate(nsp);
+        // Fling and expect the RV to not scroll
+        scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING, FLAG_FLING);
+
+        // Verify that the touch nested scroll was not started
+        verify(nsp, never()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, never()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, never()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
+        verify(nsp, never()).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_TOUCH);
+
+        // Verify that the non-touch nested scroll was started and finished
+        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
+                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
+                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
+        verify(nsp, times(1)).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_NON_TOUCH);
+    }
+
+    private void scrollInOtherOrientationTest(int flags)
+            throws Throwable {
+        scrollInOtherOrientationTest(flags, flags);
+    }
+
+    private void scrollInOtherOrientationTest(final int flags, int expectedFlags) throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        final AtomicBoolean scrolledHorizontal = new AtomicBoolean(false);
+        final AtomicBoolean scrolledVertical = new AtomicBoolean(false);
+
+        final TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public boolean canScrollHorizontally() {
+                return (flags & FLAG_HORIZONTAL) != 0;
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return (flags & FLAG_VERTICAL) != 0;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, 10);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                scrolledVertical.set(true);
+                return super.scrollVerticallyBy(dy, recycler, state);
+            }
+
+            @Override
+            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                scrolledHorizontal.set(true);
+                return super.scrollHorizontallyBy(dx, recycler, state);
+            }
+        };
+        TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(2);
+        if ( (flags & FLAG_FLING) != 0 ) {
+            int flingVelocity = (mRecyclerView.getMaxFlingVelocity() +
+                    mRecyclerView.getMinFlingVelocity()) / 2;
+            assertEquals("fling started", (expectedFlags & FLAG_FLING) != 0,
+                    fling(flingVelocity, flingVelocity));
+        } else { // drag
+            TouchUtils.dragViewTo(getInstrumentation(), recyclerView, Gravity.LEFT | Gravity.TOP,
+                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
+        }
+        assertEquals("horizontally scrolled: " + tlm.mScrollHorizontallyAmount,
+                (expectedFlags & FLAG_HORIZONTAL) != 0, scrolledHorizontal.get());
+        assertEquals("vertically scrolled: " + tlm.mScrollVerticallyAmount,
+                (expectedFlags & FLAG_VERTICAL) != 0, scrolledVertical.get());
+    }
+
+    private boolean fling(final int velocityX, final int velocityY) throws Throwable {
+        final AtomicBoolean didStart = new AtomicBoolean(false);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                boolean result = mRecyclerView.fling(velocityX, velocityY);
+                didStart.set(result);
+            }
+        });
+        if (!didStart.get()) {
+            return false;
+        }
+        waitForIdleScroll(mRecyclerView);
+        return true;
+    }
+
+    private void assertPendingUpdatesAndLayoutTest(final AdapterRunnable runnable) throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        TestLayoutManager layoutManager = new DumbLayoutManager();
+        final TestAdapter testAdapter = new TestAdapter(10);
+        setupBasic(recyclerView, layoutManager, testAdapter, false);
+        layoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    runnable.run(testAdapter);
+                } catch (Throwable throwable) {
+                    fail("runnable has thrown an exception");
+                }
+                assertTrue(mRecyclerView.hasPendingAdapterUpdates());
+            }
+        });
+        layoutManager.waitForLayout(1);
+        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
+        checkForMainThreadException();
+    }
+
+    private void setupBasic(RecyclerView recyclerView, TestLayoutManager tlm,
+            TestAdapter adapter, boolean waitForFirstLayout) throws Throwable {
+        recyclerView.setLayoutManager(tlm);
+        recyclerView.setAdapter(adapter);
+        if (waitForFirstLayout) {
+            tlm.expectLayouts(1);
+            setRecyclerView(recyclerView);
+            tlm.waitForLayout(1);
+        } else {
+            setRecyclerView(recyclerView);
+        }
+    }
+
+    @Suppress
+    @FlakyTest(bugId = 33949798)
+    @Test
+    @LargeTest
+    public void hasPendingUpdatesBeforeFirstLayout() throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        TestLayoutManager layoutManager = new DumbLayoutManager();
+        TestAdapter testAdapter = new TestAdapter(10);
+        setupBasic(recyclerView, layoutManager, testAdapter, false);
+        assertTrue(mRecyclerView.hasPendingAdapterUpdates());
+    }
+
+    @Test
+    public void noPendingUpdatesAfterLayout() throws Throwable {
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        TestLayoutManager layoutManager = new DumbLayoutManager();
+        TestAdapter testAdapter = new TestAdapter(10);
+        setupBasic(recyclerView, layoutManager, testAdapter, true);
+        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
+    }
+
+    @Test
+    public void hasPendingUpdatesAfterItemIsRemoved() throws Throwable {
+        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter testAdapter) throws Throwable {
+                testAdapter.deleteAndNotify(1, 1);
+            }
+        });
+    }
+    @Test
+    public void hasPendingUpdatesAfterItemIsInserted() throws Throwable {
+        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter testAdapter) throws Throwable {
+                testAdapter.addAndNotify(2, 1);
+            }
+        });
+    }
+    @Test
+    public void hasPendingUpdatesAfterItemIsMoved() throws Throwable {
+        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter testAdapter) throws Throwable {
+                testAdapter.moveItem(2, 3, true);
+            }
+        });
+    }
+    @Test
+    public void hasPendingUpdatesAfterItemIsChanged() throws Throwable {
+        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter testAdapter) throws Throwable {
+                testAdapter.changeAndNotify(2, 1);
+            }
+        });
+    }
+    @Test
+    public void hasPendingUpdatesAfterDataSetIsChanged() throws Throwable {
+        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter testAdapter) {
+                mRecyclerView.getAdapter().notifyDataSetChanged();
+            }
+        });
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+    @Test
+    public void transientStateRecycleViaAdapter() throws Throwable {
+        transientStateRecycleTest(true, false);
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+    @Test
+    public void transientStateRecycleViaTransientStateCleanup() throws Throwable {
+        transientStateRecycleTest(false, true);
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
+    @Test
+    public void transientStateDontRecycle() throws Throwable {
+        transientStateRecycleTest(false, false);
+    }
+
+    public void transientStateRecycleTest(final boolean succeed, final boolean unsetTransientState)
+            throws Throwable {
+        final List<View> failedToRecycle = new ArrayList<>();
+        final List<View> recycled = new ArrayList<>();
+        TestAdapter testAdapter = new TestAdapter(10) {
+            @Override
+            public boolean onFailedToRecycleView(@NonNull TestViewHolder holder) {
+                failedToRecycle.add(holder.itemView);
+                if (unsetTransientState) {
+                    setHasTransientState(holder.itemView, false);
+                }
+                return succeed;
+            }
+
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                recycled.add(holder.itemView);
+                super.onViewRecycled(holder);
+            }
+        };
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                if (getChildCount() == 0) {
+                    detachAndScrapAttachedViews(recycler);
+                    layoutRange(recycler, 0, 5);
+                } else {
+                    removeAndRecycleAllViews(recycler);
+                }
+                if (layoutLatch != null) {
+                    layoutLatch.countDown();
+                }
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(tlm);
+        recyclerView.setItemAnimator(null);
+        setRecyclerView(recyclerView);
+        getInstrumentation().waitForIdleSync();
+        // make sure we have enough views after this position so that we'll receive the on recycled
+        // callback
+        View view = recyclerView.getChildAt(3);//this has to be greater than def cache size.
+        setHasTransientState(view, true);
+        tlm.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        tlm.waitForLayout(2);
+
+        assertTrue(failedToRecycle.contains(view));
+        assertEquals(succeed || unsetTransientState, recycled.contains(view));
+    }
+
+    @Test
+    public void adapterPositionInvalidation() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final TestAdapter adapter = new TestAdapter(10);
+        final TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, state.getItemCount());
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 0; i < tlm.getChildCount(); i++) {
+                    assertNotSame("adapter positions should not be undefined",
+                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
+                            RecyclerView.NO_POSITION);
+                }
+                adapter.notifyDataSetChanged();
+                for (int i = 0; i < tlm.getChildCount(); i++) {
+                    assertSame("adapter positions should be undefined",
+                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
+                            RecyclerView.NO_POSITION);
+                }
+            }
+        });
+    }
+
+    @Test
+    public void adapterPositionsBasic() throws Throwable {
+        adapterPositionsTest(null);
+    }
+
+    @Test
+    public void adapterPositionsRemoveItems() throws Throwable {
+        adapterPositionsTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.deleteAndNotify(3, 4);
+            }
+        });
+    }
+
+    @Test
+    public void adapterPositionsRemoveItemsBefore() throws Throwable {
+        adapterPositionsTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.deleteAndNotify(0, 1);
+            }
+        });
+    }
+
+    @Test
+    public void adapterPositionsAddItemsBefore() throws Throwable {
+        adapterPositionsTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.addAndNotify(0, 5);
+            }
+        });
+    }
+
+    @Test
+    public void adapterPositionsAddItemsInside() throws Throwable {
+        adapterPositionsTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.addAndNotify(3, 2);
+            }
+        });
+    }
+
+    @Test
+    public void adapterPositionsMoveItems() throws Throwable {
+        adapterPositionsTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.moveAndNotify(3, 5);
+            }
+        });
+    }
+
+    @Test
+    public void adapterPositionsNotifyDataSetChanged() throws Throwable {
+        adapterPositionsTest(new AdapterRunnable() {
+            @Override
+            public void run(TestAdapter adapter) throws Throwable {
+                adapter.mItems.clear();
+                for (int i = 0; i < 20; i++) {
+                    adapter.mItems.add(new Item(i, "added item"));
+                }
+                adapter.notifyDataSetChanged();
+            }
+        });
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN) // transientState is API 16
+    @Test
+    public void avoidLeakingRecyclerViewIfViewIsNotRecycled() throws Throwable {
+        final AtomicBoolean failedToRecycle = new AtomicBoolean(false);
+        final AtomicInteger recycledViewCount = new AtomicInteger(0);
+        RecyclerView rv = new RecyclerView(getActivity());
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, state.getItemCount());
+                layoutLatch.countDown();
+            }
+        };
+        TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public boolean onFailedToRecycleView(
+                    @NonNull TestViewHolder holder) {
+                failedToRecycle.set(true);
+                return false;
+            }
+
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder holder) {
+                recycledViewCount.incrementAndGet();
+                super.onViewRecycled(holder);
+            }
+        };
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(1);
+        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                ViewCompat.setHasTransientState(vh.itemView, true);
+            }
+        });
+        tlm.expectLayouts(1);
+        adapter.deleteAndNotify(0, 10);
+        tlm.waitForLayout(2);
+        final CountDownLatch animationsLatch = new CountDownLatch(1);
+        rv.getItemAnimator().isRunning(
+                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
+                    @Override
+                    public void onAnimationsFinished() {
+                        animationsLatch.countDown();
+                    }
+                });
+        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
+        assertThat(recycledViewCount.get(), is(9));
+        assertTrue(failedToRecycle.get());
+        assertNull(vh.mOwnerRecyclerView);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void avoidLeakingRecyclerViewViaViewHolder() throws Throwable {
+        RecyclerView rv = new RecyclerView(getActivity());
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, state.getItemCount());
+                layoutLatch.countDown();
+            }
+        };
+        TestAdapter adapter = new TestAdapter(10);
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(1);
+        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
+        tlm.expectLayouts(1);
+        adapter.deleteAndNotify(0, 10);
+        tlm.waitForLayout(2);
+        final CountDownLatch animationsLatch = new CountDownLatch(1);
+        rv.getItemAnimator().isRunning(
+                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
+                    @Override
+                    public void onAnimationsFinished() {
+                        animationsLatch.countDown();
+                    }
+                });
+        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
+        assertNull(vh.mOwnerRecyclerView);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void duplicateAdapterPositionTest() throws Throwable {
+        final TestAdapter testAdapter = new TestAdapter(10);
+        final TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, state.getItemCount());
+                if (!state.isPreLayout()) {
+                    while (!recycler.getScrapList().isEmpty()) {
+                        RecyclerView.ViewHolder viewHolder = recycler.getScrapList().get(0);
+                        addDisappearingView(viewHolder.itemView, 0);
+                    }
+                }
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return true;
+            }
+        };
+        final DefaultItemAnimator animator = new DefaultItemAnimator();
+        animator.setSupportsChangeAnimations(true);
+        animator.setChangeDuration(10000);
+        testAdapter.setHasStableIds(true);
+        final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
+        recyclerView.setLayoutManager(tlm);
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setItemAnimator(animator);
+
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(2);
+
+        tlm.expectLayouts(2);
+        testAdapter.mItems.get(2).mType += 2;
+        final int itemId = testAdapter.mItems.get(2).mId;
+        testAdapter.changeAndNotify(2, 1);
+        tlm.waitForLayout(2);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertThat("test sanity", recyclerView.getChildCount(), CoreMatchers.is(11));
+                // now mangle the order and run the test
+                RecyclerView.ViewHolder hidden = null;
+                RecyclerView.ViewHolder updated = null;
+                for (int i = 0; i < recyclerView.getChildCount(); i ++) {
+                    View view = recyclerView.getChildAt(i);
+                    RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
+                    if (vh.getAdapterPosition() == 2) {
+                        if (mRecyclerView.mChildHelper.isHidden(view)) {
+                            assertThat(hidden, CoreMatchers.nullValue());
+                            hidden = vh;
+                        } else {
+                            assertThat(updated, CoreMatchers.nullValue());
+                            updated = vh;
+                        }
+                    }
+                }
+                assertThat(hidden, CoreMatchers.notNullValue());
+                assertThat(updated, CoreMatchers.notNullValue());
+
+                mRecyclerView.startInterceptRequestLayout();
+
+                // first put the hidden child back
+                int index1 = mRecyclerView.indexOfChild(hidden.itemView);
+                int index2 = mRecyclerView.indexOfChild(updated.itemView);
+                if (index1 < index2) {
+                    // swap views
+                    swapViewsAtIndices(recyclerView, index1, index2);
+                }
+                assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView));
+
+                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
+                        CoreMatchers.sameInstance(updated));
+                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
+                        CoreMatchers.sameInstance(updated));
+                assertThat(recyclerView.findViewHolderForItemId(itemId),
+                        CoreMatchers.sameInstance(updated));
+
+                // now swap back
+                swapViewsAtIndices(recyclerView, index1, index2);
+
+                assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView));
+                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
+                        CoreMatchers.sameInstance(updated));
+                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
+                        CoreMatchers.sameInstance(updated));
+                assertThat(recyclerView.findViewHolderForItemId(itemId),
+                        CoreMatchers.sameInstance(updated));
+
+                // now remove updated. re-assert fallback to the hidden one
+                tlm.removeView(updated.itemView);
+
+                assertThat(tlm.findViewByPosition(2), CoreMatchers.nullValue());
+                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
+                        CoreMatchers.sameInstance(hidden));
+                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
+                        CoreMatchers.sameInstance(hidden));
+                assertThat(recyclerView.findViewHolderForItemId(itemId),
+                        CoreMatchers.sameInstance(hidden));
+            }
+        });
+
+    }
+
+    private void swapViewsAtIndices(TestRecyclerView recyclerView, int index1, int index2) {
+        if (index1 == index2) {
+            return;
+        }
+        if (index2 < index1) {
+            int tmp = index1;
+            index1 = index2;
+            index2 = tmp;
+        }
+        final View v1 = recyclerView.getChildAt(index1);
+        final View v2 = recyclerView.getChildAt(index2);
+        boolean v1Hidden = recyclerView.mChildHelper.isHidden(v1);
+        boolean v2Hidden = recyclerView.mChildHelper.isHidden(v2);
+        // must un-hide before swap otherwise bucket indices will become invalid.
+        if (v1Hidden) {
+            mRecyclerView.mChildHelper.unhide(v1);
+        }
+        if (v2Hidden) {
+            mRecyclerView.mChildHelper.unhide(v2);
+        }
+        recyclerView.detachViewFromParent(index2);
+        recyclerView.attachViewToParent(v2, index1, v2.getLayoutParams());
+        recyclerView.detachViewFromParent(index1 + 1);
+        recyclerView.attachViewToParent(v1, index2, v1.getLayoutParams());
+
+        if (v1Hidden) {
+            mRecyclerView.mChildHelper.hide(v1);
+        }
+        if (v2Hidden) {
+            mRecyclerView.mChildHelper.hide(v2);
+        }
+    }
+
+    public void adapterPositionsTest(final AdapterRunnable adapterChanges) throws Throwable {
+        final TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    layoutRange(recycler, Math.min(state.getItemCount(), 2)
+                            , Math.min(state.getItemCount(), 7));
+                    layoutLatch.countDown();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        };
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setLayoutManager(tlm);
+        recyclerView.setAdapter(testAdapter);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    final int count = recyclerView.getChildCount();
+                    Map<View, Integer> layoutPositions = new HashMap<>();
+                    assertTrue("test sanity", count > 0);
+                    for (int i = 0; i < count; i++) {
+                        View view = recyclerView.getChildAt(i);
+                        TestViewHolder vh = (TestViewHolder) recyclerView.getChildViewHolder(view);
+                        int index = testAdapter.mItems.indexOf(vh.mBoundItem);
+                        assertEquals("should be able to find VH with adapter position " + index, vh,
+                                recyclerView.findViewHolderForAdapterPosition(index));
+                        assertEquals("get adapter position should return correct index", index,
+                                vh.getAdapterPosition());
+                        layoutPositions.put(view, vh.mPosition);
+                    }
+                    if (adapterChanges != null) {
+                        adapterChanges.run(testAdapter);
+                        for (int i = 0; i < count; i++) {
+                            View view = recyclerView.getChildAt(i);
+                            TestViewHolder vh = (TestViewHolder) recyclerView
+                                    .getChildViewHolder(view);
+                            int index = testAdapter.mItems.indexOf(vh.mBoundItem);
+                            if (index >= 0) {
+                                assertEquals("should be able to find VH with adapter position "
+                                                + index, vh,
+                                        recyclerView.findViewHolderForAdapterPosition(index));
+                            }
+                            assertSame("get adapter position should return correct index", index,
+                                    vh.getAdapterPosition());
+                            assertSame("should be able to find view with layout position",
+                                    vh, mRecyclerView.findViewHolderForLayoutPosition(
+                                            layoutPositions.get(view)));
+                        }
+
+                    }
+
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        });
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void scrollStateForSmoothScroll() throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager tlm = new TestLayoutManager();
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(tlm);
+        setRecyclerView(recyclerView);
+        getInstrumentation().waitForIdleSync();
+        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
+        final int[] stateCnts = new int[10];
+        final CountDownLatch latch = new CountDownLatch(2);
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                stateCnts[newState] = stateCnts[newState] + 1;
+                latch.countDown();
+            }
+        });
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.smoothScrollBy(0, 500);
+            }
+        });
+        latch.await(5, TimeUnit.SECONDS);
+        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
+        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
+        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
+    }
+
+    @Test
+    public void scrollStateForSmoothScrollWithStop() throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager tlm = new TestLayoutManager();
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(tlm);
+        setRecyclerView(recyclerView);
+        getInstrumentation().waitForIdleSync();
+        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
+        final int[] stateCnts = new int[10];
+        final CountDownLatch latch = new CountDownLatch(1);
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                stateCnts[newState] = stateCnts[newState] + 1;
+                latch.countDown();
+            }
+        });
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.smoothScrollBy(0, 500);
+            }
+        });
+        latch.await(5, TimeUnit.SECONDS);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.stopScroll();
+            }
+        });
+        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
+        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
+        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
+        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
+    }
+
+    @Test
+    public void scrollStateForFling() throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager tlm = new TestLayoutManager();
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(tlm);
+        setRecyclerView(recyclerView);
+        getInstrumentation().waitForIdleSync();
+        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
+        final int[] stateCnts = new int[10];
+        final CountDownLatch latch = new CountDownLatch(2);
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                stateCnts[newState] = stateCnts[newState] + 1;
+                latch.countDown();
+            }
+        });
+        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
+        final float fling = vc.getScaledMinimumFlingVelocity()
+                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .1f;
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.fling(0, Math.round(fling));
+            }
+        });
+        latch.await(5, TimeUnit.SECONDS);
+        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
+        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
+        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
+    }
+
+    @Test
+    public void scrollStateForFlingWithStop() throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager tlm = new TestLayoutManager();
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(tlm);
+        setRecyclerView(recyclerView);
+        getInstrumentation().waitForIdleSync();
+        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
+        final int[] stateCnts = new int[10];
+        final CountDownLatch latch = new CountDownLatch(1);
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                stateCnts[newState] = stateCnts[newState] + 1;
+                latch.countDown();
+            }
+        });
+        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
+        final float fling = vc.getScaledMinimumFlingVelocity()
+                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .8f;
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.fling(0, Math.round(fling));
+            }
+        });
+        latch.await(5, TimeUnit.SECONDS);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.stopScroll();
+            }
+        });
+        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
+        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
+        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
+        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
+    }
+
+    @Test
+    public void scrollStateDrag() throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager tlm = new TestLayoutManager();
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(tlm);
+        setRecyclerView(recyclerView);
+        getInstrumentation().waitForIdleSync();
+        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
+        final int[] stateCnts = new int[10];
+        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                stateCnts[newState] = stateCnts[newState] + 1;
+            }
+        });
+        drag(mRecyclerView, 0, 0, 0, 500, 5);
+        assertEquals(0, stateCnts[SCROLL_STATE_SETTLING]);
+        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
+        assertEquals(1, stateCnts[SCROLL_STATE_DRAGGING]);
+    }
+
+    public void drag(ViewGroup view, float fromX, float toX, float fromY, float toY,
+            int stepCount) throws Throwable {
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+
+        float y = fromY;
+        float x = fromX;
+
+        float yStep = (toY - fromY) / stepCount;
+        float xStep = (toX - fromX) / stepCount;
+
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
+                MotionEvent.ACTION_DOWN, x, y, 0);
+        sendTouch(view, event);
+        for (int i = 0; i < stepCount; ++i) {
+            y += yStep;
+            x += xStep;
+            eventTime = SystemClock.uptimeMillis();
+            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
+            sendTouch(view, event);
+        }
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        sendTouch(view, event);
+        getInstrumentation().waitForIdleSync();
+    }
+
+    private void sendTouch(final ViewGroup view, final MotionEvent event) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (view.onInterceptTouchEvent(event)) {
+                    view.onTouchEvent(event);
+                }
+            }
+        });
+    }
+
+    @Test
+    public void recycleScrap() throws Throwable {
+        recycleScrapTest(false);
+        removeRecyclerView();
+        recycleScrapTest(true);
+    }
+
+    public void recycleScrapTest(final boolean useRecycler) throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        final AtomicBoolean test = new AtomicBoolean(false);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                ViewInfoStore infoStore = mRecyclerView.mViewInfoStore;
+                if (test.get()) {
+                    try {
+                        detachAndScrapAttachedViews(recycler);
+                        for (int i = recycler.getScrapList().size() - 1; i >= 0; i--) {
+                            if (useRecycler) {
+                                recycler.recycleView(recycler.getScrapList().get(i).itemView);
+                            } else {
+                                removeAndRecycleView(recycler.getScrapList().get(i).itemView,
+                                        recycler);
+                            }
+                        }
+                        if (infoStore.mOldChangedHolders != null) {
+                            for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) {
+                                if (useRecycler) {
+                                    recycler.recycleView(
+                                            infoStore.mOldChangedHolders.valueAt(i).itemView);
+                                } else {
+                                    removeAndRecycleView(
+                                            infoStore.mOldChangedHolders.valueAt(i).itemView,
+                                            recycler);
+                                }
+                            }
+                        }
+                        assertEquals("no scrap should be left over", 0, recycler.getScrapCount());
+                        assertEquals("pre layout map should be empty", 0,
+                                InfoStoreTrojan.sizeOfPreLayout(infoStore));
+                        assertEquals("post layout map should be empty", 0,
+                                InfoStoreTrojan.sizeOfPostLayout(infoStore));
+                        if (infoStore.mOldChangedHolders != null) {
+                            assertEquals("post old change map should be empty", 0,
+                                    infoStore.mOldChangedHolders.size());
+                        }
+                    } catch (Throwable t) {
+                        postExceptionToInstrumentation(t);
+                    }
+
+                }
+                layoutRange(recycler, 0, 5);
+                layoutLatch.countDown();
+                super.onLayoutChildren(recycler, state);
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(lm);
+        ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        test.set(true);
+        lm.expectLayouts(1);
+        testAdapter.changeAndNotify(3, 1);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void aAccessRecyclerOnOnMeasureWithPredictive() throws Throwable {
+        accessRecyclerOnOnMeasureTest(true);
+    }
+
+    @Test
+    public void accessRecyclerOnOnMeasureWithoutPredictive() throws Throwable {
+        accessRecyclerOnOnMeasureTest(false);
+    }
+
+    @Test
+    public void smoothScrollWithRemovedItemsAndRemoveItem() throws Throwable {
+        smoothScrollTest(true);
+    }
+
+    @Test
+    public void smoothScrollWithRemovedItems() throws Throwable {
+        smoothScrollTest(false);
+    }
+
+    public void smoothScrollTest(final boolean removeItem) throws Throwable {
+        final LinearSmoothScroller[] lss = new LinearSmoothScroller[1];
+        final CountDownLatch calledOnStart = new CountDownLatch(1);
+        final CountDownLatch calledOnStop = new CountDownLatch(1);
+        final int visibleChildCount = 10;
+        TestLayoutManager lm = new TestLayoutManager() {
+            int start = 0;
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutRange(recycler, start, visibleChildCount);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                start++;
+                if (DEBUG) {
+                    Log.d(TAG, "on scroll, remove and recycling. start:" + start + ", cnt:"
+                            + visibleChildCount);
+                }
+                removeAndRecycleAllViews(recycler);
+                layoutRange(recycler, start,
+                        Math.max(state.getItemCount(), start + visibleChildCount));
+                return dy;
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
+                    int position) {
+                LinearSmoothScroller linearSmoothScroller =
+                        new LinearSmoothScroller(recyclerView.getContext()) {
+                            @Override
+                            public PointF computeScrollVectorForPosition(int targetPosition) {
+                                return new PointF(0, 1);
+                            }
+
+                            @Override
+                            protected void onStart() {
+                                super.onStart();
+                                calledOnStart.countDown();
+                            }
+
+                            @Override
+                            protected void onStop() {
+                                super.onStop();
+                                calledOnStop.countDown();
+                            }
+                        };
+                linearSmoothScroller.setTargetPosition(position);
+                lss[0] = linearSmoothScroller;
+                startSmoothScroll(linearSmoothScroller);
+            }
+        };
+        final RecyclerView rv = new RecyclerView(getActivity());
+        TestAdapter testAdapter = new TestAdapter(500);
+        rv.setLayoutManager(lm);
+        rv.setAdapter(testAdapter);
+        lm.expectLayouts(1);
+        setRecyclerView(rv);
+        lm.waitForLayout(1);
+        // regular scroll
+        final int targetPosition = visibleChildCount * (removeItem ? 30 : 4);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rv.smoothScrollToPosition(targetPosition);
+            }
+        });
+        if (DEBUG) {
+            Log.d(TAG, "scrolling to target position " + targetPosition);
+        }
+        assertTrue("on start should be called very soon", calledOnStart.await(2, TimeUnit.SECONDS));
+        if (removeItem) {
+            final int newTarget = targetPosition - 10;
+            testAdapter.deleteAndNotify(newTarget + 1, testAdapter.getItemCount() - newTarget - 1);
+            final CountDownLatch targetCheck = new CountDownLatch(1);
+            mActivityRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    ViewCompat.postOnAnimationDelayed(rv, new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                assertEquals("scroll position should be updated to next available",
+                                        newTarget, lss[0].getTargetPosition());
+                            } catch (Throwable t) {
+                                postExceptionToInstrumentation(t);
+                            }
+                            targetCheck.countDown();
+                        }
+                    }, 50);
+                }
+            });
+            assertTrue("target position should be checked on time ",
+                    targetCheck.await(10, TimeUnit.SECONDS));
+            checkForMainThreadException();
+            assertTrue("on stop should be called", calledOnStop.await(30, TimeUnit.SECONDS));
+            checkForMainThreadException();
+            assertNotNull("should scroll to new target " + newTarget
+                    , rv.findViewHolderForLayoutPosition(newTarget));
+            if (DEBUG) {
+                Log.d(TAG, "on stop has been called on time");
+            }
+        } else {
+            assertTrue("on stop should be called eventually",
+                    calledOnStop.await(30, TimeUnit.SECONDS));
+            assertNotNull("scroll to position should succeed",
+                    rv.findViewHolderForLayoutPosition(targetPosition));
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void smoothScrollToPosition_targetNotFoundSeekInXAndY_scrollsLayoutManagerBy1InXAndY()
+            throws Throwable {
+        smoothScrollToPosition_initialScroll(
+                15,
+                10,
+                9432,
+                1239,
+                1,
+                1,
+                2);
+    }
+
+    @Test
+    public void smoothScrollToPosition_targetNotFoundSeekNegative_scrollsLayoutManagerByMinus1()
+            throws Throwable {
+        smoothScrollToPosition_initialScroll(
+                15,
+                10,
+                -9432,
+                -1239,
+                -1,
+                -1,
+                2);
+    }
+
+    @Test
+    public void smoothScrollToPosition_targetNotFoundSeekInX_scrollsLayoutManagerBy1InX()
+            throws Throwable {
+        smoothScrollToPosition_initialScroll(
+                15,
+                10,
+                0,
+                1239,
+                0,
+                1,
+                1);
+    }
+
+    @Test
+    public void smoothScrollToPosition_targetNotFoundSeekInY_scrollsLayoutManagerBy1InY()
+            throws Throwable {
+        smoothScrollToPosition_initialScroll(
+                15,
+                10,
+                0,
+                1239,
+                0,
+                1,
+                1);
+    }
+
+    @Test
+    public void smoothScrollToPosition_targetFound_doesNotScrollLayoutManager()
+            throws Throwable {
+        smoothScrollToPosition_initialScroll(
+                5,
+                10,
+                9432,
+                1239,
+                0,
+                0,
+                1);
+    }
+
+    @SuppressWarnings("SameParameterValue")
+    private void smoothScrollToPosition_initialScroll(
+            final int targetItemPosition,
+            final int itemLayoutCount,
+            final int dxIncrement,
+            final int dyIncrement,
+            final int expectedInitialScrollDx,
+            final int expectedInitialScrollDy,
+            final int eventCount)
+            throws Throwable {
+        final RecyclerView rv = new RecyclerView(getActivity());
+        rv.setLayoutParams(
+                new ViewGroup.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT,
+                        ViewGroup.LayoutParams.MATCH_PARENT));
+
+        TestAdapter testAdapter = new TestAdapter(itemLayoutCount * 2);
+        rv.setAdapter(testAdapter);
+
+        final CountDownLatch countDownLatch = new CountDownLatch(eventCount);
+        final AtomicInteger actualInitialScrollDx = new AtomicInteger(0);
+        final AtomicInteger actualInitialScrollDy = new AtomicInteger(0);
+
+        TestLayoutManager testLayoutManager = new TestLayoutManager() {
+            @Override
+            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
+                    int position) {
+                RecyclerView.SmoothScroller scroller = new RecyclerView.SmoothScroller() {
+                    @Override
+                    protected void onStart() {
+
+                    }
+
+                    @Override
+                    protected void onStop() {
+
+                    }
+
+                    @Override
+                    protected void onSeekTargetStep(int dx, int dy, RecyclerView.State state,
+                            Action action) {
+                    }
+
+                    @Override
+                    protected void onTargetFound(View targetView, RecyclerView.State state,
+                            Action action) {
+                        countDownLatch.countDown();
+                    }
+
+                    @Nullable
+                    @Override
+                    public PointF computeScrollVectorForPosition(int targetPosition) {
+                        return new PointF(dxIncrement, dyIncrement);
+                    }
+                };
+                scroller.setTargetPosition(position);
+                startSmoothScroll(scroller);
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, itemLayoutCount);
+            }
+
+            @Override
+            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                actualInitialScrollDx.set(dx);
+                countDownLatch.countDown();
+                return 0;
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                actualInitialScrollDy.set(dy);
+                countDownLatch.countDown();
+                return 0;
+            }
+        };
+
+        rv.setLayoutManager(testLayoutManager);
+
+        getActivity().getContainer().expectLayouts(1);
+        setRecyclerView(rv);
+        getActivity().getContainer().waitForLayout(2);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rv.smoothScrollToPosition(targetItemPosition);
+            }
+        });
+        assertTrue(countDownLatch.await(2, TimeUnit.SECONDS));
+
+        assertThat(actualInitialScrollDx.get(), equalTo(expectedInitialScrollDx));
+        assertThat(actualInitialScrollDy.get(), equalTo(expectedInitialScrollDy));
+    }
+
+    @Test
+    public void consecutiveSmoothScroll() throws Throwable {
+        final AtomicInteger visibleChildCount = new AtomicInteger(10);
+        final AtomicInteger totalScrolled = new AtomicInteger(0);
+        final TestLayoutManager lm = new TestLayoutManager() {
+            int start = 0;
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutRange(recycler, start, visibleChildCount.get());
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                totalScrolled.set(totalScrolled.get() + dy);
+                return dy;
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+        };
+        final RecyclerView rv = new RecyclerView(getActivity());
+        TestAdapter testAdapter = new TestAdapter(500);
+        rv.setLayoutManager(lm);
+        rv.setAdapter(testAdapter);
+        lm.expectLayouts(1);
+        setRecyclerView(rv);
+        lm.waitForLayout(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rv.smoothScrollBy(0, 2000);
+            }
+        });
+        Thread.sleep(250);
+        final AtomicInteger scrollAmt = new AtomicInteger();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final int soFar = totalScrolled.get();
+                scrollAmt.set(soFar);
+                rv.smoothScrollBy(0, 5000 - soFar);
+            }
+        });
+        while (rv.getScrollState() != SCROLL_STATE_IDLE) {
+            Thread.sleep(100);
+        }
+        final int soFar = totalScrolled.get();
+        assertEquals("second scroll should be competed properly", 5000, soFar);
+    }
+
+    public void accessRecyclerOnOnMeasureTest(final boolean enablePredictiveAnimations)
+            throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        final AtomicInteger expectedOnMeasureStateCount = new AtomicInteger(10);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                try {
+                    layoutRange(recycler, 0, state.getItemCount());
+                    layoutLatch.countDown();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
+                    int widthSpec, int heightSpec) {
+                try {
+                    // make sure we access all views
+                    for (int i = 0; i < state.getItemCount(); i++) {
+                        View view = recycler.getViewForPosition(i);
+                        assertNotNull(view);
+                        assertEquals(i, getPosition(view));
+                    }
+                    if (!state.isPreLayout()) {
+                        assertEquals(state.toString(),
+                                expectedOnMeasureStateCount.get(), state.getItemCount());
+                    }
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+                super.onMeasure(recycler, state, widthSpec, heightSpec);
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return enablePredictiveAnimations;
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+        lm.expectLayouts(1);
+        if (!enablePredictiveAnimations) {
+            expectedOnMeasureStateCount.set(15);
+        }
+        testAdapter.addAndNotify(4, 5);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void setCompatibleAdapter() throws Throwable {
+        compatibleAdapterTest(true, true);
+        removeRecyclerView();
+        compatibleAdapterTest(false, true);
+        removeRecyclerView();
+        compatibleAdapterTest(true, false);
+        removeRecyclerView();
+        compatibleAdapterTest(false, false);
+        removeRecyclerView();
+    }
+
+    private void compatibleAdapterTest(boolean useCustomPool, boolean removeAndRecycleExistingViews)
+            throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        final AtomicInteger recycledViewCount = new AtomicInteger();
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    layoutRange(recycler, 0, state.getItemCount());
+                    layoutLatch.countDown();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() {
+            @Override
+            public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
+                recycledViewCount.incrementAndGet();
+            }
+        });
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView, !useCustomPool);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+        lm.expectLayouts(1);
+        swapAdapter(new TestAdapter(10), removeAndRecycleExistingViews);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+        if (removeAndRecycleExistingViews) {
+            assertTrue("Previous views should be recycled", recycledViewCount.get() > 0);
+        } else {
+            assertEquals("No views should be recycled if adapters are compatible and developer "
+                    + "did not request a recycle", 0, recycledViewCount.get());
+        }
+    }
+
+    @Test
+    public void setIncompatibleAdapter() throws Throwable {
+        incompatibleAdapterTest(true);
+        incompatibleAdapterTest(false);
+    }
+
+    public void incompatibleAdapterTest(boolean useCustomPool) throws Throwable {
+        TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                try {
+                    layoutRange(recycler, 0, state.getItemCount());
+                    layoutLatch.countDown();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView, !useCustomPool);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+        lm.expectLayouts(1);
+        setAdapter(new TestAdapter2(10));
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void recycleIgnored() throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        final TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                layoutRange(recycler, 0, 5);
+                layoutLatch.countDown();
+            }
+        };
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View child1 = lm.findViewByPosition(0);
+                View child2 = lm.findViewByPosition(1);
+                lm.ignoreView(child1);
+                lm.ignoreView(child2);
+
+                lm.removeAndRecycleAllViews(recyclerView.mRecycler);
+                assertEquals("ignored child should not be recycled or removed", 2,
+                        lm.getChildCount());
+
+                Throwable[] throwables = new Throwable[1];
+                try {
+                    lm.removeAndRecycleView(child1, mRecyclerView.mRecycler);
+                } catch (Throwable t) {
+                    throwables[0] = t;
+                }
+                assertTrue("Trying to recycle an ignored view should throw IllegalArgException "
+                        , throwables[0] instanceof IllegalArgumentException);
+                lm.removeAllViews();
+                assertEquals("ignored child should be removed as well ", 0, lm.getChildCount());
+            }
+        });
+    }
+
+    @Test
+    public void findIgnoredByPosition() throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        final TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, 5);
+                layoutLatch.countDown();
+            }
+        };
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        Thread.sleep(5000);
+        final int pos = 1;
+        final View[] ignored = new View[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View child = lm.findViewByPosition(pos);
+                lm.ignoreView(child);
+                ignored[0] = child;
+            }
+        });
+        assertNotNull("ignored child should not be null", ignored[0]);
+        assertNull("find view by position should not return ignored child",
+                lm.findViewByPosition(pos));
+        lm.expectLayouts(1);
+        requestLayoutOnUIThread(mRecyclerView);
+        lm.waitForLayout(1);
+        assertEquals("child count should be ", 6, lm.getChildCount());
+        View replacement = lm.findViewByPosition(pos);
+        assertNotNull("re-layout should replace ignored child w/ another one", replacement);
+        assertNotSame("replacement should be a different view", replacement, ignored[0]);
+    }
+
+    @Test
+    public void itemDecorsWithPredictive() throws Throwable {
+        LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
+        lm.setSupportsPredictive(true);
+        final Object changePayload = new Object();
+        final TestAdapter adapter = new TestAdapter(10) {
+            @Override
+            public void onBindViewHolder(TestViewHolder holder,
+                    int position, List<Object> payloads) {
+                super.onBindViewHolder(holder, position);
+                holder.setData(payloads.isEmpty() ? null : payloads.get(0));
+            }
+        };
+        final Map<Integer, Object> preLayoutData = new HashMap<>();
+        final Map<Integer, Object> postLayoutData = new HashMap<>();
+
+        final RecyclerView.ItemDecoration decoration = new RecyclerView.ItemDecoration() {
+            @Override
+            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                    RecyclerView.State state) {
+                try {
+                    TestViewHolder tvh = (TestViewHolder) parent.getChildViewHolder(view);
+                    Object data = tvh.getData();
+                    int adapterPos = tvh.getAdapterPosition();
+                    assertThat(adapterPos, is(not(NO_POSITION)));
+                    if (state.isPreLayout()) {
+                        preLayoutData.put(adapterPos, data);
+                    } else {
+                        postLayoutData.put(adapterPos, data);
+                    }
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+
+            }
+        };
+        RecyclerView rv = new RecyclerView(getActivity());
+        rv.addItemDecoration(decoration);
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(rv);
+        lm.waitForLayout(2);
+
+        preLayoutData.clear();
+        postLayoutData.clear();
+        lm.expectLayouts(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                adapter.notifyItemChanged(3, changePayload);
+            }
+        });
+        lm.waitForLayout(2);
+        assertThat(preLayoutData.containsKey(3), is(false));
+        assertThat(postLayoutData.get(3), is(changePayload));
+        assertThat(preLayoutData.size(), is(0));
+        assertThat(postLayoutData.size(), is(1));
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void invalidateAllDecorOffsets() throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final AtomicBoolean invalidatedOffsets = new AtomicBoolean(true);
+        recyclerView.setAdapter(adapter);
+        final AtomicInteger layoutCount = new AtomicInteger(4);
+        final RecyclerView.ItemDecoration dummyItemDecoration = new RecyclerView.ItemDecoration() {
+        };
+        TestLayoutManager testLayoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    // test
+                    for (int i = 0; i < getChildCount(); i++) {
+                        View child = getChildAt(i);
+                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
+                                child.getLayoutParams();
+                        assertEquals(
+                                "Decor insets validation for VH should have expected value.",
+                                invalidatedOffsets.get(), lp.mInsetsDirty);
+                    }
+                    for (RecyclerView.ViewHolder vh : mRecyclerView.mRecycler.mCachedViews) {
+                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
+                                vh.itemView.getLayoutParams();
+                        assertEquals(
+                                "Decor insets invalidation in cache for VH should have expected "
+                                        + "value.",
+                                invalidatedOffsets.get(), lp.mInsetsDirty);
+                    }
+                    detachAndScrapAttachedViews(recycler);
+                    layoutRange(recycler, 0, layoutCount.get());
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return false;
+            }
+        };
+        // first layout
+        recyclerView.setItemViewCacheSize(5);
+        recyclerView.setLayoutManager(testLayoutManager);
+        testLayoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView, true, false);
+        testLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+
+        // re-layout w/o any change
+        invalidatedOffsets.set(false);
+        testLayoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+
+        // invalidate w/o an item decorator
+
+        invalidateDecorOffsets(recyclerView);
+        testLayoutManager.expectLayouts(1);
+        invalidateDecorOffsets(recyclerView);
+        testLayoutManager.assertNoLayout("layout should not happen", 2);
+        checkForMainThreadException();
+
+        // set item decorator, should invalidate
+        invalidatedOffsets.set(true);
+        testLayoutManager.expectLayouts(1);
+        addItemDecoration(mRecyclerView, dummyItemDecoration);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+
+        // re-layout w/o any change
+        invalidatedOffsets.set(false);
+        testLayoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+
+        // invalidate w/ item decorator
+        invalidatedOffsets.set(true);
+        invalidateDecorOffsets(recyclerView);
+        testLayoutManager.expectLayouts(1);
+        invalidateDecorOffsets(recyclerView);
+        testLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+
+        // trigger cache.
+        layoutCount.set(3);
+        invalidatedOffsets.set(false);
+        testLayoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(mRecyclerView);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+        assertEquals("a view should be cached", 1, mRecyclerView.mRecycler.mCachedViews.size());
+
+        layoutCount.set(5);
+        invalidatedOffsets.set(true);
+        testLayoutManager.expectLayouts(1);
+        invalidateDecorOffsets(recyclerView);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+
+        // remove item decorator
+        invalidatedOffsets.set(true);
+        testLayoutManager.expectLayouts(1);
+        removeItemDecoration(mRecyclerView, dummyItemDecoration);
+        testLayoutManager.waitForLayout(1);
+        checkForMainThreadException();
+    }
+
+    public void addItemDecoration(final RecyclerView recyclerView, final
+    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.addItemDecoration(itemDecoration);
+            }
+        });
+    }
+
+    public void removeItemDecoration(final RecyclerView recyclerView, final
+    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.removeItemDecoration(itemDecoration);
+            }
+        });
+    }
+
+    public void invalidateDecorOffsets(final RecyclerView recyclerView) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.invalidateItemDecorations();
+            }
+        });
+    }
+
+    @Test
+    public void invalidateDecorOffsets() throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        adapter.setHasStableIds(true);
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(adapter);
+
+        final Map<Long, Boolean> changes = new HashMap<>();
+
+        TestLayoutManager testLayoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    if (changes.size() > 0) {
+                        // test
+                        for (int i = 0; i < getChildCount(); i++) {
+                            View child = getChildAt(i);
+                            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
+                                    child.getLayoutParams();
+                            RecyclerView.ViewHolder vh = lp.mViewHolder;
+                            if (!changes.containsKey(vh.getItemId())) {
+                                continue; //nothing to test
+                            }
+                            assertEquals(
+                                    "Decor insets validation for VH should have expected value.",
+                                    changes.get(vh.getItemId()), lp.mInsetsDirty);
+                        }
+                    }
+                    detachAndScrapAttachedViews(recycler);
+                    layoutRange(recycler, 0, state.getItemCount());
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return false;
+            }
+        };
+        recyclerView.setLayoutManager(testLayoutManager);
+        testLayoutManager.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        testLayoutManager.waitForLayout(2);
+        int itemAddedTo = 5;
+        for (int i = 0; i < itemAddedTo; i++) {
+            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
+        }
+        for (int i = itemAddedTo; i < mRecyclerView.getChildCount(); i++) {
+            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
+        }
+        testLayoutManager.expectLayouts(1);
+        adapter.addAndNotify(5, 1);
+        testLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+
+        changes.clear();
+        int[] changedItems = new int[]{3, 5, 6};
+        for (int i = 0; i < adapter.getItemCount(); i++) {
+            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
+        }
+        for (int changedItem : changedItems) {
+            changes.put(mRecyclerView.findViewHolderForLayoutPosition(changedItem).getItemId(),
+                    true);
+        }
+        testLayoutManager.expectLayouts(1);
+        adapter.changePositionsAndNotify(changedItems);
+        testLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+
+        for (int i = 0; i < adapter.getItemCount(); i++) {
+            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
+        }
+        testLayoutManager.expectLayouts(1);
+        adapter.dispatchDataSetChanged();
+        testLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void movingViaStableIds() throws Throwable {
+        stableIdsMoveTest(true);
+        removeRecyclerView();
+        stableIdsMoveTest(false);
+        removeRecyclerView();
+    }
+
+    public void stableIdsMoveTest(final boolean supportsPredictive) throws Throwable {
+        final TestAdapter testAdapter = new TestAdapter(10);
+        testAdapter.setHasStableIds(true);
+        final AtomicBoolean test = new AtomicBoolean(false);
+        final int movedViewFromIndex = 3;
+        final int movedViewToIndex = 6;
+        final View[] movedView = new View[1];
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                try {
+                    if (test.get()) {
+                        if (state.isPreLayout()) {
+                            View view = recycler.getViewForPosition(movedViewFromIndex, true);
+                            assertSame("In pre layout, should be able to get moved view w/ old "
+                                    + "position", movedView[0], view);
+                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
+                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
+                            // clear scrap flag
+                            holder.clearReturnedFromScrapFlag();
+                        } else {
+                            View view = recycler.getViewForPosition(movedViewToIndex, true);
+                            assertSame("In post layout, should be able to get moved view w/ new "
+                                    + "position", movedView[0], view);
+                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
+                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
+                            // clear scrap flag
+                            holder.clearReturnedFromScrapFlag();
+                        }
+                    }
+                    layoutRange(recycler, 0, state.getItemCount());
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+
+
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return supportsPredictive;
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(this.getActivity());
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(1);
+
+        movedView[0] = recyclerView.getChildAt(movedViewFromIndex);
+        test.set(true);
+        lm.expectLayouts(supportsPredictive ? 2 : 1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Item item = testAdapter.mItems.remove(movedViewFromIndex);
+                testAdapter.mItems.add(movedViewToIndex, item);
+                testAdapter.notifyItemRemoved(movedViewFromIndex);
+                testAdapter.notifyItemInserted(movedViewToIndex);
+            }
+        });
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void adapterChangeDuringLayout() throws Throwable {
+        adapterChangeInMainThreadTest("notifyDataSetChanged", new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.getAdapter().notifyDataSetChanged();
+            }
+        });
+
+        adapterChangeInMainThreadTest("notifyItemChanged", new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.getAdapter().notifyItemChanged(2);
+            }
+        });
+
+        adapterChangeInMainThreadTest("notifyItemInserted", new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.getAdapter().notifyItemInserted(2);
+            }
+        });
+        adapterChangeInMainThreadTest("notifyItemRemoved", new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.getAdapter().notifyItemRemoved(2);
+            }
+        });
+    }
+
+    public void adapterChangeInMainThreadTest(String msg,
+            final Runnable onLayoutRunnable) throws Throwable {
+        setIgnoreMainThreadException(true);
+        final AtomicBoolean doneFirstLayout = new AtomicBoolean(false);
+        TestAdapter testAdapter = new TestAdapter(10);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                try {
+                    layoutRange(recycler, 0, state.getItemCount());
+                    if (doneFirstLayout.get()) {
+                        onLayoutRunnable.run();
+                    }
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setAdapter(testAdapter);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        doneFirstLayout.set(true);
+        lm.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        lm.waitForLayout(2);
+        removeRecyclerView();
+        assertTrue("Invalid data updates should be caught:" + msg,
+                getMainThreadException() instanceof IllegalStateException);
+    }
+
+    @Test
+    public void adapterChangeDuringScroll() throws Throwable {
+        for (int orientation : new int[]{OrientationHelper.HORIZONTAL,
+                OrientationHelper.VERTICAL}) {
+            adapterChangeDuringScrollTest("notifyDataSetChanged", orientation,
+                    new Runnable() {
+                        @Override
+                        public void run() {
+                            mRecyclerView.getAdapter().notifyDataSetChanged();
+                        }
+                    });
+            adapterChangeDuringScrollTest("notifyItemChanged", orientation, new Runnable() {
+                @Override
+                public void run() {
+                    mRecyclerView.getAdapter().notifyItemChanged(2);
+                }
+            });
+
+            adapterChangeDuringScrollTest("notifyItemInserted", orientation, new Runnable() {
+                @Override
+                public void run() {
+                    mRecyclerView.getAdapter().notifyItemInserted(2);
+                }
+            });
+            adapterChangeDuringScrollTest("notifyItemRemoved", orientation, new Runnable() {
+                @Override
+                public void run() {
+                    mRecyclerView.getAdapter().notifyItemRemoved(2);
+                }
+            });
+        }
+    }
+
+    public void adapterChangeDuringScrollTest(String msg, final int orientation,
+            final Runnable onScrollRunnable) throws Throwable {
+        setIgnoreMainThreadException(true);
+        TestAdapter testAdapter = new TestAdapter(100);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                try {
+                    layoutRange(recycler, 0, 10);
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return orientation == OrientationHelper.VERTICAL;
+            }
+
+            @Override
+            public boolean canScrollHorizontally() {
+                return orientation == OrientationHelper.HORIZONTAL;
+            }
+
+            public int mockScroll() {
+                try {
+                    onScrollRunnable.run();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+                return 0;
+            }
+
+            @Override
+            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                return mockScroll();
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                return mockScroll();
+            }
+        };
+        RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setAdapter(testAdapter);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        lm.expectLayouts(1);
+        scrollBy(200);
+        lm.waitForLayout(2);
+        removeRecyclerView();
+        assertTrue("Invalid data updates should be caught:" + msg,
+                getMainThreadException() instanceof IllegalStateException);
+    }
+
+    @Test
+    public void recycleOnDetach() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final TestAdapter testAdapter = new TestAdapter(10);
+        final AtomicBoolean didRunOnDetach = new AtomicBoolean(false);
+        final TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutRange(recycler, 0, state.getItemCount() - 1);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+                super.onDetachedFromWindow(view, recycler);
+                didRunOnDetach.set(true);
+                removeAndRecycleAllViews(recycler);
+            }
+        };
+        recyclerView.setAdapter(testAdapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        removeRecyclerView();
+        assertTrue("When recycler view is removed, detach should run", didRunOnDetach.get());
+        assertEquals("All children should be recycled", recyclerView.getChildCount(), 0);
+    }
+
+    @Test
+    public void updatesWhileDetached() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final int initialAdapterSize = 20;
+        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
+        final AtomicInteger layoutCount = new AtomicInteger(0);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutRange(recycler, 0, 5);
+                layoutCount.incrementAndGet();
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setHasFixedSize(true);
+        lm.expectLayouts(1);
+        adapter.addAndNotify(4, 5);
+        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
+    }
+
+    @Test
+    public void updatesAfterDetach() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final int initialAdapterSize = 20;
+        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
+        final AtomicInteger layoutCount = new AtomicInteger(0);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                layoutRange(recycler, 0, 5);
+                layoutCount.incrementAndGet();
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        recyclerView.setHasFixedSize(true);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        lm.expectLayouts(1);
+        final int prevLayoutCount = layoutCount.get();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    adapter.addAndNotify(4, 5);
+                    removeRecyclerView();
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+        checkForMainThreadException();
+
+        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
+        assertEquals("No extra layout should happen when detached", prevLayoutCount,
+                layoutCount.get());
+    }
+
+    @Test
+    public void notifyDataSetChangedWithStableIds() throws Throwable {
+        final Map<Integer, Integer> oldPositionToNewPositionMapping = new HashMap<>();
+        final TestAdapter adapter = new TestAdapter(100) {
+            @Override
+            public long getItemId(int position) {
+                return mItems.get(position).mId;
+            }
+        };
+        adapter.setHasStableIds(true);
+        final ArrayList<Item> previousItems = new ArrayList<>();
+        previousItems.addAll(adapter.mItems);
+
+        final AtomicInteger layoutStart = new AtomicInteger(50);
+        final AtomicBoolean validate = new AtomicBoolean(false);
+        final int childCount = 10;
+        final TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    super.onLayoutChildren(recycler, state);
+                    if (validate.get()) {
+                        assertEquals("Cached views should be kept", 5, recycler
+                                .mCachedViews.size());
+                        for (RecyclerView.ViewHolder vh : recycler.mCachedViews) {
+                            TestViewHolder tvh = (TestViewHolder) vh;
+                            assertTrue("view holder should be marked for update",
+                                    tvh.needsUpdate());
+                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
+                        }
+                    }
+                    detachAndScrapAttachedViews(recycler);
+                    if (validate.get()) {
+                        assertEquals("cache size should stay the same", 5,
+                                recycler.mCachedViews.size());
+                        assertEquals("all views should be scrapped", childCount,
+                                recycler.getScrapList().size());
+                        for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
+                            // TODO create test case for type change
+                            TestViewHolder tvh = (TestViewHolder) vh;
+                            assertTrue("view holder should be marked for update",
+                                    tvh.needsUpdate());
+                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
+                        }
+                    }
+                    layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
+                    if (validate.get()) {
+                        for (int i = 0; i < getChildCount(); i++) {
+                            View view = getChildAt(i);
+                            TestViewHolder tvh = (TestViewHolder) mRecyclerView
+                                    .getChildViewHolder(view);
+                            final int oldPos = previousItems.indexOf(tvh.mBoundItem);
+                            assertEquals("view holder's position should be correct",
+                                    oldPositionToNewPositionMapping.get(oldPos).intValue(),
+                                    tvh.getLayoutPosition());
+                        }
+                    }
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+        };
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setItemAnimator(null);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setItemViewCacheSize(10);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+        getInstrumentation().waitForIdleSync();
+        layoutStart.set(layoutStart.get() + 5);//55
+        lm.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        lm.waitForLayout(2);
+        validate.set(true);
+        lm.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    adapter.moveItems(false,
+                            new int[]{50, 56}, new int[]{51, 1}, new int[]{52, 2},
+                            new int[]{53, 54}, new int[]{60, 61}, new int[]{62, 64},
+                            new int[]{75, 58});
+                    for (int i = 0; i < previousItems.size(); i++) {
+                        Item item = previousItems.get(i);
+                        oldPositionToNewPositionMapping.put(i, adapter.mItems.indexOf(item));
+                    }
+                    adapter.dispatchDataSetChanged();
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void callbacksDuringAdapterSwap() throws Throwable {
+        callbacksDuringAdapterChange(true);
+    }
+
+    @Test
+    public void callbacksDuringAdapterSet() throws Throwable {
+        callbacksDuringAdapterChange(false);
+    }
+
+    public void callbacksDuringAdapterChange(boolean swap) throws Throwable {
+        final TestAdapter2 adapter1 = swap ? createBinderCheckingAdapter()
+                : createOwnerCheckingAdapter();
+        final TestAdapter2 adapter2 = swap ? createBinderCheckingAdapter()
+                : createOwnerCheckingAdapter();
+
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    layoutRange(recycler, 0, state.getItemCount());
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+                layoutLatch.countDown();
+            }
+        };
+        RecyclerView rv = new RecyclerView(getActivity());
+        rv.setAdapter(adapter1);
+        rv.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(1);
+        checkForMainThreadException();
+        tlm.expectLayouts(1);
+        if (swap) {
+            swapAdapter(adapter2, true);
+        } else {
+            setAdapter(adapter2);
+        }
+        checkForMainThreadException();
+        tlm.waitForLayout(1);
+        checkForMainThreadException();
+    }
+
+    private TestAdapter2 createOwnerCheckingAdapter() {
+        return new TestAdapter2(10) {
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder2 holder) {
+                assertSame("on recycled should be called w/ the creator adapter", this,
+                        holder.mData);
+                super.onViewRecycled(holder);
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder2 holder, int position) {
+                super.onBindViewHolder(holder, position);
+                assertSame("on bind should be called w/ the creator adapter", this, holder.mData);
+            }
+
+            @Override
+            public TestViewHolder2 onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                final TestViewHolder2 vh = super.onCreateViewHolder(parent, viewType);
+                vh.mData = this;
+                return vh;
+            }
+        };
+    }
+
+    private TestAdapter2 createBinderCheckingAdapter() {
+        return new TestAdapter2(10) {
+            @Override
+            public void onViewRecycled(@NonNull TestViewHolder2 holder) {
+                assertSame("on recycled should be called w/ the creator adapter", this,
+                        holder.mData);
+                holder.mData = null;
+                super.onViewRecycled(holder);
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder2 holder, int position) {
+                super.onBindViewHolder(holder, position);
+                holder.mData = this;
+            }
+        };
+    }
+
+    @Test
+    public void findViewById() throws Throwable {
+        findViewByIdTest(false);
+        removeRecyclerView();
+        findViewByIdTest(true);
+    }
+
+    public void findViewByIdTest(final boolean supportPredictive) throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final int initialAdapterSize = 20;
+        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
+        final int deleteStart = 6;
+        final int deleteCount = 5;
+        recyclerView.setAdapter(adapter);
+        final AtomicBoolean assertPositions = new AtomicBoolean(false);
+        TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                if (assertPositions.get()) {
+                    if (state.isPreLayout()) {
+                        for (int i = 0; i < deleteStart; i++) {
+                            View view = findViewByPosition(i);
+                            assertNotNull("find view by position for existing items should work "
+                                    + "fine", view);
+                            assertFalse("view should not be marked as removed",
+                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
+                                            .isItemRemoved());
+                        }
+                        for (int i = 0; i < deleteCount; i++) {
+                            View view = findViewByPosition(i + deleteStart);
+                            assertNotNull("find view by position should work fine for removed "
+                                    + "views in pre-layout", view);
+                            assertTrue("view should be marked as removed",
+                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
+                                            .isItemRemoved());
+                        }
+                        for (int i = deleteStart + deleteCount; i < 20; i++) {
+                            View view = findViewByPosition(i);
+                            assertNotNull(view);
+                            assertFalse("view should not be marked as removed",
+                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
+                                            .isItemRemoved());
+                        }
+                    } else {
+                        for (int i = 0; i < initialAdapterSize - deleteCount; i++) {
+                            View view = findViewByPosition(i);
+                            assertNotNull("find view by position for existing item " + i +
+                                    " should work fine. child count:" + getChildCount(), view);
+                            TestViewHolder viewHolder =
+                                    (TestViewHolder) mRecyclerView.getChildViewHolder(view);
+                            assertSame("should be the correct item " + viewHolder
+                                    , viewHolder.mBoundItem,
+                                    adapter.mItems.get(viewHolder.mPosition));
+                            assertFalse("view should not be marked as removed",
+                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
+                                            .isItemRemoved());
+                        }
+                    }
+                }
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, state.getItemCount() - 1, -1);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return supportPredictive;
+            }
+        };
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        getInstrumentation().waitForIdleSync();
+
+        assertPositions.set(true);
+        lm.expectLayouts(supportPredictive ? 2 : 1);
+        adapter.deleteAndNotify(new int[]{deleteStart, deleteCount - 1}, new int[]{deleteStart, 1});
+        lm.waitForLayout(2);
+    }
+
+    @Test
+    public void typeForCache() throws Throwable {
+        final AtomicInteger viewType = new AtomicInteger(1);
+        final TestAdapter adapter = new TestAdapter(100) {
+            @Override
+            public int getItemViewType(int position) {
+                return viewType.get();
+            }
+
+            @Override
+            public long getItemId(int position) {
+                return mItems.get(position).mId;
+            }
+        };
+        adapter.setHasStableIds(true);
+        final AtomicInteger layoutStart = new AtomicInteger(2);
+        final int childCount = 10;
+        final TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
+                layoutLatch.countDown();
+            }
+        };
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setItemAnimator(null);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        recyclerView.setItemViewCacheSize(10);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        getInstrumentation().waitForIdleSync();
+        layoutStart.set(4); // trigger a cache for 3,4
+        lm.expectLayouts(1);
+        requestLayoutOnUIThread(recyclerView);
+        lm.waitForLayout(2);
+        //
+        viewType.incrementAndGet();
+        layoutStart.set(2); // go back to bring views from cache
+        lm.expectLayouts(1);
+        adapter.mItems.remove(1);
+        adapter.dispatchDataSetChanged();
+        lm.waitForLayout(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                for (int i = 2; i < 4; i++) {
+                    RecyclerView.ViewHolder vh = recyclerView.findViewHolderForLayoutPosition(i);
+                    assertEquals("View holder's type should match latest type", viewType.get(),
+                            vh.getItemViewType());
+                }
+            }
+        });
+    }
+
+    @Test
+    public void typeForExistingViews() throws Throwable {
+        final AtomicInteger viewType = new AtomicInteger(1);
+        final int invalidatedCount = 2;
+        final int layoutStart = 2;
+        final TestAdapter adapter = new TestAdapter(100) {
+            @Override
+            public int getItemViewType(int position) {
+                return viewType.get();
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (position >= layoutStart && position < invalidatedCount + layoutStart) {
+                    try {
+                        assertEquals("holder type should match current view type at position " +
+                                position, viewType.get(), holder.getItemViewType());
+                    } catch (Throwable t) {
+                        postExceptionToInstrumentation(t);
+                    }
+                }
+            }
+
+            @Override
+            public long getItemId(int position) {
+                return mItems.get(position).mId;
+            }
+        };
+        adapter.setHasStableIds(true);
+
+        final int childCount = 10;
+        final TestLayoutManager lm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, layoutStart, layoutStart + childCount);
+                layoutLatch.countDown();
+            }
+        };
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(lm);
+        lm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        lm.waitForLayout(2);
+        getInstrumentation().waitForIdleSync();
+        viewType.incrementAndGet();
+        lm.expectLayouts(1);
+        adapter.changeAndNotify(layoutStart, invalidatedCount);
+        lm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+
+    @Test
+    public void state() throws Throwable {
+        final TestAdapter adapter = new TestAdapter(10);
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        recyclerView.setAdapter(adapter);
+        recyclerView.setItemAnimator(null);
+        final AtomicInteger itemCount = new AtomicInteger();
+        final AtomicBoolean structureChanged = new AtomicBoolean();
+        TestLayoutManager testLayoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, state.getItemCount());
+                itemCount.set(state.getItemCount());
+                structureChanged.set(state.didStructureChange());
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.setLayoutManager(testLayoutManager);
+        testLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().addView(recyclerView);
+            }
+        });
+        testLayoutManager.waitForLayout(2);
+
+        assertEquals("item count in state should be correct", adapter.getItemCount()
+                , itemCount.get());
+        assertEquals("structure changed should be true for first layout", true,
+                structureChanged.get());
+        Thread.sleep(1000); //wait for other layouts.
+        testLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.requestLayout();
+            }
+        });
+        testLayoutManager.waitForLayout(2);
+        assertEquals("in second layout,structure changed should be false", false,
+                structureChanged.get());
+        testLayoutManager.expectLayouts(1); //
+        adapter.deleteAndNotify(3, 2);
+        testLayoutManager.waitForLayout(2);
+        assertEquals("when items are removed, item count in state should be updated",
+                adapter.getItemCount(),
+                itemCount.get());
+        assertEquals("structure changed should be true when items are removed", true,
+                structureChanged.get());
+        testLayoutManager.expectLayouts(1);
+        adapter.addAndNotify(2, 5);
+        testLayoutManager.waitForLayout(2);
+
+        assertEquals("when items are added, item count in state should be updated",
+                adapter.getItemCount(),
+                itemCount.get());
+        assertEquals("structure changed should be true when items are removed", true,
+                structureChanged.get());
+    }
+
+    @Test
+    public void detachWithoutLayoutManager() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    setRecyclerView(recyclerView);
+                    removeRecyclerView();
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        });
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void updateHiddenView() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final int[] preLayoutRange = new int[]{0, 10};
+        final int[] postLayoutRange = new int[]{0, 10};
+        final AtomicBoolean enableGetViewTest = new AtomicBoolean(false);
+        final List<Integer> disappearingPositions = new ArrayList<>();
+        final TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return true;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    final int[] layoutRange = state.isPreLayout() ? preLayoutRange
+                            : postLayoutRange;
+                    detachAndScrapAttachedViews(recycler);
+                    layoutRange(recycler, layoutRange[0], layoutRange[1]);
+                    if (!state.isPreLayout()) {
+                        for (Integer position : disappearingPositions) {
+                            // test sanity.
+                            assertNull(findViewByPosition(position));
+                            final View view = recycler.getViewForPosition(position);
+                            assertNotNull(view);
+                            addDisappearingView(view);
+                            measureChildWithMargins(view, 0, 0);
+                            // position item out of bounds.
+                            view.layout(0, -500, view.getMeasuredWidth(),
+                                    -500 + view.getMeasuredHeight());
+                        }
+                    }
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+                layoutLatch.countDown();
+            }
+        };
+        recyclerView.getItemAnimator().setMoveDuration(4000);
+        recyclerView.getItemAnimator().setRemoveDuration(4000);
+        final TestAdapter adapter = new TestAdapter(100);
+        recyclerView.setAdapter(adapter);
+        recyclerView.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(recyclerView);
+        tlm.waitForLayout(1);
+        checkForMainThreadException();
+        // now, a child disappears
+        disappearingPositions.add(0);
+        // layout one shifted
+        postLayoutRange[0] = 1;
+        postLayoutRange[1] = 11;
+        tlm.expectLayouts(2);
+        adapter.addAndNotify(8, 1);
+        tlm.waitForLayout(2);
+        checkForMainThreadException();
+
+        tlm.expectLayouts(2);
+        disappearingPositions.clear();
+        // now that item should be moving, invalidate it and delete it.
+        enableGetViewTest.set(true);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    assertThat("test sanity, should still be animating",
+                            mRecyclerView.isAnimating(), CoreMatchers.is(true));
+                    adapter.changeAndNotify(0, 1);
+                    adapter.deleteAndNotify(0, 1);
+                } catch (Throwable throwable) {
+                    fail(throwable.getMessage());
+                }
+            }
+        });
+        tlm.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void focusBigViewOnTop() throws Throwable {
+        focusTooBigViewTest(Gravity.TOP);
+    }
+
+    @Test
+    public void focusBigViewOnLeft() throws Throwable {
+        focusTooBigViewTest(Gravity.LEFT);
+    }
+
+    @Test
+    public void focusBigViewOnRight() throws Throwable {
+        focusTooBigViewTest(Gravity.RIGHT);
+    }
+
+    @Test
+    public void focusBigViewOnBottom() throws Throwable {
+        focusTooBigViewTest(Gravity.BOTTOM);
+    }
+
+    @Test
+    public void focusBigViewOnLeftRTL() throws Throwable {
+        focusTooBigViewTest(Gravity.LEFT, true);
+        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
+                mRecyclerView.getLayoutManager().getLayoutDirection());
+    }
+
+    @Test
+    public void focusBigViewOnRightRTL() throws Throwable {
+        focusTooBigViewTest(Gravity.RIGHT, true);
+        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
+                mRecyclerView.getLayoutManager().getLayoutDirection());
+    }
+
+    public void focusTooBigViewTest(final int gravity) throws Throwable {
+        focusTooBigViewTest(gravity, false);
+    }
+
+    public void focusTooBigViewTest(final int gravity, final boolean rtl) throws Throwable {
+        RecyclerView rv = new RecyclerView(getActivity());
+        if (rtl) {
+            ViewCompat.setLayoutDirection(rv, ViewCompat.LAYOUT_DIRECTION_RTL);
+        }
+        final AtomicInteger vScrollDist = new AtomicInteger(0);
+        final AtomicInteger hScrollDist = new AtomicInteger(0);
+        final AtomicInteger vDesiredDist = new AtomicInteger(0);
+        final AtomicInteger hDesiredDist = new AtomicInteger(0);
+        TestLayoutManager tlm = new TestLayoutManager() {
+
+            @Override
+            public int getLayoutDirection() {
+                return rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
+            }
+
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                final View view = recycler.getViewForPosition(0);
+                addView(view);
+                int left = 0, top = 0;
+                view.setBackgroundColor(Color.rgb(0, 0, 255));
+                switch (gravity) {
+                    case Gravity.LEFT:
+                    case Gravity.RIGHT:
+                        view.measure(
+                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * 1.5),
+                                        View.MeasureSpec.EXACTLY),
+                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * .9),
+                                        View.MeasureSpec.AT_MOST));
+                        left = gravity == Gravity.LEFT ? getWidth() - view.getMeasuredWidth() - 80
+                                : 90;
+                        top = 0;
+                        if (ViewCompat.LAYOUT_DIRECTION_RTL == getLayoutDirection()) {
+                            hDesiredDist.set((left + view.getMeasuredWidth()) - getWidth());
+                        } else {
+                            hDesiredDist.set(left);
+                        }
+                        break;
+                    case Gravity.TOP:
+                    case Gravity.BOTTOM:
+                        view.measure(
+                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * .9),
+                                        View.MeasureSpec.AT_MOST),
+                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * 1.5),
+                                        View.MeasureSpec.EXACTLY));
+                        top = gravity == Gravity.TOP ? getHeight() - view.getMeasuredHeight() -
+                                80 : 90;
+                        left = 0;
+                        vDesiredDist.set(top);
+                        break;
+                }
+
+                view.layout(left, top, left + view.getMeasuredWidth(),
+                        top + view.getMeasuredHeight());
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public boolean canScrollHorizontally() {
+                return super.canScrollHorizontally();
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                vScrollDist.addAndGet(dy);
+                getChildAt(0).offsetTopAndBottom(-dy);
+                return dy;
+            }
+
+            @Override
+            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                hScrollDist.addAndGet(dx);
+                getChildAt(0).offsetLeftAndRight(-dx);
+                return dx;
+            }
+        };
+        TestAdapter adapter = new TestAdapter(10);
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(2);
+        View view = rv.getChildAt(0);
+        assertTrue("test sanity", requestFocus(view, true));
+        assertTrue("test sanity", view.hasFocus());
+        assertEquals(vDesiredDist.get(), vScrollDist.get());
+        assertEquals(hDesiredDist.get(), hScrollDist.get());
+        assertEquals(mRecyclerView.getPaddingTop(), view.getTop());
+        if (rtl) {
+            assertEquals(mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(),
+                    view.getRight());
+        } else {
+            assertEquals(mRecyclerView.getPaddingLeft(), view.getLeft());
+        }
+    }
+
+    @Test
+    public void firstLayoutWithAdapterChanges() throws Throwable {
+        final TestAdapter adapter = new TestAdapter(0);
+        final RecyclerView rv = new RecyclerView(getActivity());
+        setVisibility(rv, View.GONE);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                try {
+                    super.onLayoutChildren(recycler, state);
+                    layoutRange(recycler, 0, state.getItemCount());
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                } finally {
+                    layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return true;
+            }
+        };
+        rv.setLayoutManager(tlm);
+        rv.setAdapter(adapter);
+        rv.setHasFixedSize(true);
+        setRecyclerView(rv);
+        tlm.expectLayouts(1);
+        tlm.assertNoLayout("test sanity, layout should not run", 1);
+        getInstrumentation().waitForIdleSync();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    adapter.addAndNotify(2);
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+                rv.setVisibility(View.VISIBLE);
+            }
+        });
+        checkForMainThreadException();
+        tlm.waitForLayout(2);
+        assertEquals(2, rv.getChildCount());
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void computeScrollOffsetWithoutLayoutManager() throws Throwable {
+        RecyclerView rv = new RecyclerView(getActivity());
+        rv.setAdapter(new TestAdapter(10));
+        setRecyclerView(rv);
+        assertEquals(0, rv.computeHorizontalScrollExtent());
+        assertEquals(0, rv.computeHorizontalScrollOffset());
+        assertEquals(0, rv.computeHorizontalScrollRange());
+
+        assertEquals(0, rv.computeVerticalScrollExtent());
+        assertEquals(0, rv.computeVerticalScrollOffset());
+        assertEquals(0, rv.computeVerticalScrollRange());
+    }
+
+    @Test
+    public void computeScrollOffsetWithoutAdapter() throws Throwable {
+        RecyclerView rv = new RecyclerView(getActivity());
+        rv.setLayoutManager(new TestLayoutManager());
+        setRecyclerView(rv);
+        assertEquals(0, rv.computeHorizontalScrollExtent());
+        assertEquals(0, rv.computeHorizontalScrollOffset());
+        assertEquals(0, rv.computeHorizontalScrollRange());
+
+        assertEquals(0, rv.computeVerticalScrollExtent());
+        assertEquals(0, rv.computeVerticalScrollOffset());
+        assertEquals(0, rv.computeVerticalScrollRange());
+    }
+
+    @Test
+    public void focusRectOnScreenWithDecorOffsets() throws Throwable {
+        focusRectOnScreenTest(true);
+    }
+
+    @Test
+    public void focusRectOnScreenWithout() throws Throwable {
+        focusRectOnScreenTest(false);
+    }
+
+    public void focusRectOnScreenTest(boolean addItemDecors) throws Throwable {
+        RecyclerView rv = new RecyclerView(getActivity());
+        final AtomicInteger scrollDist = new AtomicInteger(0);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                final View view = recycler.getViewForPosition(0);
+                addView(view);
+                measureChildWithMargins(view, 0, 0);
+                view.layout(0, -20, view.getWidth(),
+                        -20 + view.getHeight());// ignore decors on purpose
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                scrollDist.addAndGet(dy);
+                return dy;
+            }
+        };
+        TestAdapter adapter = new TestAdapter(10);
+        if (addItemDecors) {
+            rv.addItemDecoration(new RecyclerView.ItemDecoration() {
+                @Override
+                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
+                        RecyclerView.State state) {
+                    outRect.set(0, 10, 0, 10);
+                }
+            });
+        }
+        rv.setAdapter(adapter);
+        rv.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(2);
+
+        View view = rv.getChildAt(0);
+        requestFocus(view, true);
+        assertEquals(addItemDecors ? -30 : -20, scrollDist.get());
+    }
+
+    @Test
+    public void unimplementedSmoothScroll() throws Throwable {
+        final AtomicInteger receivedScrollToPosition = new AtomicInteger(-1);
+        final AtomicInteger receivedSmoothScrollToPosition = new AtomicInteger(-1);
+        final CountDownLatch cbLatch = new CountDownLatch(2);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, 10);
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
+                    int position) {
+                assertEquals(-1, receivedSmoothScrollToPosition.get());
+                receivedSmoothScrollToPosition.set(position);
+                RecyclerView.SmoothScroller ss =
+                        new LinearSmoothScroller(recyclerView.getContext()) {
+                            @Override
+                            public PointF computeScrollVectorForPosition(int targetPosition) {
+                                return null;
+                            }
+                        };
+                ss.setTargetPosition(position);
+                startSmoothScroll(ss);
+                cbLatch.countDown();
+            }
+
+            @Override
+            public void scrollToPosition(int position) {
+                assertEquals(-1, receivedScrollToPosition.get());
+                receivedScrollToPosition.set(position);
+                cbLatch.countDown();
+            }
+        };
+        RecyclerView rv = new RecyclerView(getActivity());
+        rv.setAdapter(new TestAdapter(100));
+        rv.setLayoutManager(tlm);
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(2);
+        freezeLayout(true);
+        smoothScrollToPosition(35, false);
+        assertEquals("smoothScrollToPosition should be ignored when frozen",
+                -1, receivedSmoothScrollToPosition.get());
+        freezeLayout(false);
+        smoothScrollToPosition(35, false);
+        assertTrue("both scrolls should be called", cbLatch.await(3, TimeUnit.SECONDS));
+        checkForMainThreadException();
+        assertEquals(35, receivedSmoothScrollToPosition.get());
+        assertEquals(35, receivedScrollToPosition.get());
+    }
+
+    @Test
+    public void jumpingJackSmoothScroller() throws Throwable {
+        jumpingJackSmoothScrollerTest(true);
+    }
+
+    @Test
+    public void jumpingJackSmoothScrollerGoesIdle() throws Throwable {
+        jumpingJackSmoothScrollerTest(false);
+    }
+
+    @Test
+    public void testScrollByBeforeFirstLayout() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        TestAdapter adapter = new TestAdapter(10);
+        recyclerView.setLayoutManager(new TestLayoutManager() {
+            AtomicBoolean didLayout = new AtomicBoolean(false);
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                super.onLayoutChildren(recycler, state);
+                didLayout.set(true);
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                assertThat("should run layout before scroll",
+                        didLayout.get(), CoreMatchers.is(true));
+                return super.scrollVerticallyBy(dy, recycler, state);
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+        });
+        recyclerView.setAdapter(adapter);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    setRecyclerView(recyclerView);
+                    recyclerView.scrollBy(10, 19);
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+
+        checkForMainThreadException();
+    }
+
+    private void jumpingJackSmoothScrollerTest(final boolean succeed) throws Throwable {
+        final List<Integer> receivedScrollToPositions = new ArrayList<>();
+        final TestAdapter testAdapter = new TestAdapter(200);
+        final AtomicBoolean mTargetFound = new AtomicBoolean(false);
+        TestLayoutManager tlm = new TestLayoutManager() {
+            int pendingScrollPosition = -1;
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                final int pos = pendingScrollPosition < 0 ? 0: pendingScrollPosition;
+                layoutRange(recycler, pos, pos + 10);
+                if (layoutLatch != null) {
+                    layoutLatch.countDown();
+                }
+            }
+
+            @Override
+            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
+                    final int position) {
+                RecyclerView.SmoothScroller ss =
+                        new LinearSmoothScroller(recyclerView.getContext()) {
+                            @Override
+                            public PointF computeScrollVectorForPosition(int targetPosition) {
+                                return new PointF(0, 1);
+                            }
+
+                            @Override
+                            protected void onTargetFound(View targetView, RecyclerView.State state,
+                                    Action action) {
+                                super.onTargetFound(targetView, state, action);
+                                mTargetFound.set(true);
+                            }
+
+                            @Override
+                            protected void updateActionForInterimTarget(Action action) {
+                                int limit = succeed ? getTargetPosition() : 100;
+                                if (pendingScrollPosition + 2 < limit) {
+                                    if (pendingScrollPosition != NO_POSITION) {
+                                        assertEquals(pendingScrollPosition,
+                                                getChildViewHolderInt(getChildAt(0))
+                                                        .getAdapterPosition());
+                                    }
+                                    action.jumpTo(pendingScrollPosition + 2);
+                                }
+                            }
+                        };
+                ss.setTargetPosition(position);
+                startSmoothScroll(ss);
+            }
+
+            @Override
+            public void scrollToPosition(int position) {
+                receivedScrollToPositions.add(position);
+                pendingScrollPosition = position;
+                requestLayout();
+            }
+        };
+        final RecyclerView rv = new RecyclerView(getActivity());
+        rv.setAdapter(testAdapter);
+        rv.setLayoutManager(tlm);
+
+        tlm.expectLayouts(1);
+        setRecyclerView(rv);
+        tlm.waitForLayout(2);
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                rv.smoothScrollToPosition(150);
+            }
+        });
+        int limit = 100;
+        while (rv.getLayoutManager().isSmoothScrolling() && --limit > 0) {
+            Thread.sleep(200);
+            checkForMainThreadException();
+        }
+        checkForMainThreadException();
+        assertTrue(limit > 0);
+        for (int i = 1; i < 100; i+=2) {
+            assertTrue("scroll positions must include " + i, receivedScrollToPositions.contains(i));
+        }
+
+        assertEquals(succeed, mTargetFound.get());
+
+    }
+
+    private static class TestViewHolder2 extends RecyclerView.ViewHolder {
+
+        Object mData;
+
+        public TestViewHolder2(View itemView) {
+            super(itemView);
+        }
+    }
+
+    private static class TestAdapter2 extends RecyclerView.Adapter<TestViewHolder2> {
+
+        List<Item> mItems;
+
+        private TestAdapter2(int count) {
+            mItems = new ArrayList<>(count);
+            for (int i = 0; i < count; i++) {
+                mItems.add(new Item(i, "Item " + i));
+            }
+        }
+
+        @Override
+        public TestViewHolder2 onCreateViewHolder(@NonNull ViewGroup parent,
+                int viewType) {
+            return new TestViewHolder2(new TextView(parent.getContext()));
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull TestViewHolder2 holder, int position) {
+            final Item item = mItems.get(position);
+            ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mAdapterIndex + ")");
+        }
+
+        @Override
+        public int getItemCount() {
+            return mItems.size();
+        }
+    }
+
+    public interface AdapterRunnable {
+
+        void run(TestAdapter adapter) throws Throwable;
+    }
+
+    public class LayoutAllLayoutManager extends TestLayoutManager {
+        private final boolean mAllowNullLayoutLatch;
+        public int onItemsChangedCallCount = 0;
+        public int onAdapterChagnedCallCount = 0;
+
+        public LayoutAllLayoutManager() {
+            // by default, we don't allow unexpected layouts.
+            this(false);
+        }
+        public LayoutAllLayoutManager(boolean allowNullLayoutLatch) {
+            mAllowNullLayoutLatch = allowNullLayoutLatch;
+        }
+
+        @Override
+        public void onItemsChanged(RecyclerView recyclerView) {
+            super.onItemsChanged(recyclerView);
+            onItemsChangedCallCount++;
+        }
+
+        @Override
+        public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
+                RecyclerView.Adapter newAdapter) {
+            super.onAdapterChanged(oldAdapter, newAdapter);
+            onAdapterChagnedCallCount++;
+        }
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+            detachAndScrapAttachedViews(recycler);
+            layoutRange(recycler, 0, state.getItemCount());
+            if (!mAllowNullLayoutLatch || layoutLatch != null) {
+                layoutLatch.countDown();
+            }
+        }
+    }
+
+    /**
+     * Proxy class to make protected methods public
+     */
+    public static class TestRecyclerView extends RecyclerView {
+
+        public TestRecyclerView(Context context) {
+            super(context);
+        }
+
+        public TestRecyclerView(Context context, @Nullable AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public TestRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
+            super(context, attrs, defStyle);
+        }
+
+        @Override
+        public void detachViewFromParent(int index) {
+            super.detachViewFromParent(index);
+        }
+
+        @Override
+        public void attachViewToParent(View child, int index, ViewGroup.LayoutParams params) {
+            super.attachViewToParent(child, index, params);
+        }
+    }
+
+    private interface ViewRunnable {
+        void run(View view) throws RuntimeException;
+    }
+
+    public static class FullyConsumingNestedScroller extends NestedScrollingParent2Adapter {
+        @Override
+        public boolean onStartNestedScroll(@NonNull View child, @NonNull View target,
+                @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
+            // Always start regardless of type
+            return true;
+        }
+
+        @Override
+        public void onNestedPreScroll(@NonNull View target, int dx, int dy,
+                @NonNull int[] consumed, @ViewCompat.NestedScrollType int type) {
+            // Consume everything!
+            consumed[0] = dx;
+            consumed[1] = dy;
+        }
+
+        @Override
+        public int getNestedScrollAxes() {
+            return ViewCompat.SCROLL_AXIS_VERTICAL | ViewCompat.SCROLL_AXIS_HORIZONTAL;
+        }
+
+        @Override
+        public void onStopNestedScroll(View target) {
+            super.onStopNestedScroll(target);
+        }
+
+        @Override
+        public void onStopNestedScroll(@NonNull View target,
+                @ViewCompat.NestedScrollType int type) {
+            super.onStopNestedScroll(target, type);
+        }
+    }
+
+    @Test
+    public void testRemainingScrollInLayout() throws Throwable {
+        final RecyclerView recyclerView = new RecyclerView(getActivity());
+        final TestAdapter adapter = new TestAdapter(100);
+
+        final CountDownLatch firstScrollDone = new CountDownLatch(1);
+        final CountDownLatch scrollFinished = new CountDownLatch(1);
+        final int[] totalScrollDistance = new int[] {0};
+        recyclerView.setLayoutManager(new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                if (firstScrollDone.getCount() < 1 && scrollFinished.getCount() == 1) {
+                    try {
+                        assertTrue("layout pass has remaining scroll",
+                                state.getRemainingScrollVertical() != 0);
+                        assertEquals("layout pass has remaining scroll",
+                                1000 - totalScrollDistance[0], state.getRemainingScrollVertical());
+                    } catch (Throwable throwable) {
+                        postExceptionToInstrumentation(throwable);
+                    }
+                }
+                super.onLayoutChildren(recycler, state);
+            }
+
+            @Override
+            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                    RecyclerView.State state) {
+                firstScrollDone.countDown();
+                totalScrollDistance[0] += dy;
+                if (state.getRemainingScrollVertical() == 0) {
+                    // the last scroll pass will have remaining 0
+                    scrollFinished.countDown();
+                }
+                return super.scrollVerticallyBy(dy, recycler, state);
+            }
+
+            @Override
+            public boolean canScrollVertically() {
+                return true;
+            }
+        });
+        recyclerView.setAdapter(adapter);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    setRecyclerView(recyclerView);
+                    recyclerView.smoothScrollBy(0, 1000);
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+
+        firstScrollDone.await(1, TimeUnit.SECONDS);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    recyclerView.requestLayout();
+                } catch (Throwable throwable) {
+                    postExceptionToInstrumentation(throwable);
+                }
+            }
+        });
+        waitForIdleScroll(recyclerView);
+        assertTrue(scrollFinished.getCount() < 1);
+        assertEquals(totalScrollDistance[0], 1000);
+    }
+
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java
new file mode 100644
index 0000000..19e838e
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.view.InputDeviceCompat;
+import android.support.v4.view.ViewConfigurationCompat;
+import android.support.v7.util.TouchUtils;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RecyclerViewOnGenericMotionEventTest {
+
+    TestRecyclerView mRecyclerView;
+
+    @Before
+    public void setUp() throws Exception {
+        mRecyclerView = new TestRecyclerView(getContext());
+    }
+
+    private Context getContext() {
+        return InstrumentationRegistry.getContext();
+    }
+
+    private void layout() {
+        mRecyclerView.layout(0, 0, 320, 320);
+    }
+
+    @Test
+    public void rotaryEncoderVerticalScroll() {
+        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()));
+    }
+
+    @Test
+    public void rotaryEncoderHorizontalScroll() {
+        // The encoder is one-dimensional, and can only scroll horizontally if vertical scrolling
+        // is not enabled.
+        MockLayoutManager layoutManager = new MockLayoutManager(true, false);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
+        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0);
+    }
+
+    @Test
+    public void pointerVerticalScroll() {
+        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_VSCROLL, 2, InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView);
+        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()));
+    }
+
+    @Test
+    public void pointerHorizontalScroll() {
+        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
+        mRecyclerView.setLayoutManager(layoutManager);
+        layout();
+        TouchUtils.scrollView(
+                MotionEvent.AXIS_HSCROLL, 2, InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView);
+        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0);
+    }
+
+    @Test
+    public void nonZeroScaledVerticalScrollFactor() {
+        assertNotEquals(0, getScaledVerticalScrollFactor());
+    }
+
+    @Test
+    public void nonZeroScaledHorizontalScrollFactor() {
+        assertNotEquals(0, getScaledHorizontalScrollFactor());
+    }
+
+    private void assertTotalScroll(int x, int y) {
+        assertEquals("x total scroll", x, mRecyclerView.mTotalX);
+        assertEquals("y total scroll", y, mRecyclerView.mTotalY);
+    }
+
+    private static MotionEvent obtainScrollMotionEvent(int axis, int axisValue, int inputDevice) {
+        MotionEvent.PointerProperties[] pointerProperties = { new MotionEvent.PointerProperties() };
+        MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
+        coords.setAxisValue(axis, axisValue);
+        MotionEvent.PointerCoords[] pointerCoords = { coords };
+        float xPrecision = 1;
+        float yPrecision = 1;
+        int deviceId = 0;
+        int edgeFlags = 0;
+        int flags = 0;
+        return MotionEvent.obtain(0, System.currentTimeMillis(), MotionEvent.ACTION_SCROLL,
+                1, pointerProperties, pointerCoords, 0, 0, xPrecision, yPrecision, deviceId,
+                edgeFlags, inputDevice, flags);
+    }
+
+    private float getScaledVerticalScrollFactor() {
+        return ViewConfigurationCompat.getScaledVerticalScrollFactor(
+                ViewConfiguration.get(getContext()), getContext());
+    }
+
+    private float getScaledHorizontalScrollFactor() {
+        return ViewConfigurationCompat.getScaledHorizontalScrollFactor(
+                ViewConfiguration.get(getContext()), getContext());
+    }
+
+    static class MockLayoutManager extends RecyclerView.LayoutManager {
+
+        private final boolean mCanScrollHorizontally;
+
+        private final boolean mCanScrollVertically;
+
+        MockLayoutManager(boolean canScrollHorizontally, boolean canScrollVertically) {
+            mCanScrollHorizontally = canScrollHorizontally;
+            mCanScrollVertically = canScrollVertically;
+        }
+
+        @Override
+        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        @Override
+        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            return dx;
+        }
+
+        @Override
+        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+                RecyclerView.State state) {
+            return dy;
+        }
+
+        @Override
+        public boolean canScrollHorizontally() {
+            return mCanScrollHorizontally;
+        }
+
+        @Override
+        public boolean canScrollVertically() {
+            return mCanScrollVertically;
+        }
+    }
+
+    static class MockAdapter extends RecyclerView.Adapter {
+
+        private int mCount = 0;
+
+        MockAdapter(int count) {
+            this.mCount = count;
+        }
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new MockViewHolder(new TextView(parent.getContext()));
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+
+        }
+
+        @Override
+        public int getItemCount() {
+            return mCount;
+        }
+    }
+
+    static class MockViewHolder extends RecyclerView.ViewHolder {
+        MockViewHolder(View itemView) {
+            super(itemView);
+        }
+    }
+
+    private static class TestRecyclerView extends RecyclerView {
+        int mTotalX = 0;
+        int mTotalY = 0;
+
+        TestRecyclerView(Context context) {
+            super(context);
+        }
+
+        boolean scrollByInternal(int x, int y, MotionEvent ev) {
+            mTotalX += x;
+            mTotalY += y;
+            return super.scrollByInternal(x, y, ev);
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewPrefetchTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewPrefetchTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/RecyclerViewPrefetchTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ScrollToPositionWithAutoMeasure.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/ScrollToPositionWithAutoMeasure.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/ScrollToPositionWithAutoMeasure.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/ScrollToPositionWithAutoMeasure.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
new file mode 100644
index 0000000..4197df3
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
@@ -0,0 +1,851 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LayoutState.LAYOUT_START;
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Rect;
+import android.os.Looper;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.Suppress;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewParent;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+@RunWith(Parameterized.class)
+@LargeTest
+public class StaggeredGridLayoutManagerBaseConfigSetTest
+        extends BaseStaggeredGridLayoutManagerTest {
+
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Config> getParams() {
+        return createBaseVariations();
+    }
+
+    private final Config mConfig;
+
+    public StaggeredGridLayoutManagerBaseConfigSetTest(Config config)
+            throws CloneNotSupportedException {
+        mConfig = (Config) config.clone();
+    }
+
+    @Test
+    public void rTL() throws Throwable {
+        rtlTest(false, false);
+    }
+
+    @Test
+    public void rTLChangeAfter() throws Throwable {
+        rtlTest(true, false);
+    }
+
+    @Test
+    public void rTLItemWrapContent() throws Throwable {
+        rtlTest(false, true);
+    }
+
+    @Test
+    public void rTLChangeAfterItemWrapContent() throws Throwable {
+        rtlTest(true, true);
+    }
+
+    void rtlTest(boolean changeRtlAfter, final boolean wrapContent) throws Throwable {
+        if (mConfig.mSpanCount == 1) {
+            mConfig.mSpanCount = 2;
+        }
+        String logPrefix = mConfig + ", changeRtlAfterLayout:" + changeRtlAfter;
+        setupByConfig(mConfig.itemCount(5),
+                new GridTestAdapter(mConfig.mItemCount, mConfig.mOrientation) {
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        if (wrapContent) {
+                            if (mOrientation == HORIZONTAL) {
+                                holder.itemView.getLayoutParams().height
+                                        = RecyclerView.LayoutParams.WRAP_CONTENT;
+                            } else {
+                                holder.itemView.getLayoutParams().width
+                                        = RecyclerView.LayoutParams.MATCH_PARENT;
+                            }
+                        }
+                    }
+                });
+        if (changeRtlAfter) {
+            waitFirstLayout();
+            mLayoutManager.expectLayouts(1);
+            mLayoutManager.setFakeRtl(true);
+            mLayoutManager.waitForLayout(2);
+        } else {
+            mLayoutManager.mFakeRTL = true;
+            waitFirstLayout();
+        }
+
+        assertEquals("view should become rtl", true, mLayoutManager.isLayoutRTL());
+        OrientationHelper helper = OrientationHelper.createHorizontalHelper(mLayoutManager);
+        View child0 = mLayoutManager.findViewByPosition(0);
+        View child1 = mLayoutManager.findViewByPosition(mConfig.mOrientation == VERTICAL ? 1
+                : mConfig.mSpanCount);
+        assertNotNull(logPrefix + " child position 0 should be laid out", child0);
+        assertNotNull(logPrefix + " child position 0 should be laid out", child1);
+        logPrefix += " child1 pos:" + mLayoutManager.getPosition(child1);
+        if (mConfig.mOrientation == VERTICAL || !mConfig.mReverseLayout) {
+            assertTrue(logPrefix + " second child should be to the left of first child",
+                    helper.getDecoratedEnd(child0) > helper.getDecoratedEnd(child1));
+            assertEquals(logPrefix + " first child should be right aligned",
+                    helper.getDecoratedEnd(child0), helper.getEndAfterPadding());
+        } else {
+            assertTrue(logPrefix + " first child should be to the left of second child",
+                    helper.getDecoratedStart(child1) >= helper.getDecoratedStart(child0));
+            assertEquals(logPrefix + " first child should be left aligned",
+                    helper.getDecoratedStart(child0), helper.getStartAfterPadding());
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void scrollBackAndPreservePositions() throws Throwable {
+        scrollBackAndPreservePositionsTest(false);
+    }
+
+    @Test
+    public void scrollBackAndPreservePositionsWithRestore() throws Throwable {
+        scrollBackAndPreservePositionsTest(true);
+    }
+
+    public void scrollBackAndPreservePositionsTest(final boolean saveRestoreInBetween)
+            throws Throwable {
+        setupByConfig(mConfig);
+        mAdapter.mOnBindCallback = new OnBindCallback() {
+            @Override
+            public void onBoundItem(TestViewHolder vh, int position) {
+                StaggeredGridLayoutManager.LayoutParams
+                        lp = (StaggeredGridLayoutManager.LayoutParams) vh.itemView
+                        .getLayoutParams();
+                lp.setFullSpan((position * 7) % (mConfig.mSpanCount + 1) == 0);
+            }
+        };
+        waitFirstLayout();
+        final int[] globalPositions = new int[mAdapter.getItemCount()];
+        Arrays.fill(globalPositions, Integer.MIN_VALUE);
+        final int scrollStep = (mLayoutManager.mPrimaryOrientation.getTotalSpace() / 10)
+                * (mConfig.mReverseLayout ? -1 : 1);
+
+        final int[] globalPos = new int[1];
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                int globalScrollPosition = 0;
+                while (globalPositions[mAdapter.getItemCount() - 1] == Integer.MIN_VALUE) {
+                    for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
+                        View child = mRecyclerView.getChildAt(i);
+                        final int pos = mRecyclerView.getChildLayoutPosition(child);
+                        if (globalPositions[pos] != Integer.MIN_VALUE) {
+                            continue;
+                        }
+                        if (mConfig.mReverseLayout) {
+                            globalPositions[pos] = globalScrollPosition +
+                                    mLayoutManager.mPrimaryOrientation.getDecoratedEnd(child);
+                        } else {
+                            globalPositions[pos] = globalScrollPosition +
+                                    mLayoutManager.mPrimaryOrientation.getDecoratedStart(child);
+                        }
+                    }
+                    globalScrollPosition += mLayoutManager.scrollBy(scrollStep,
+                            mRecyclerView.mRecycler, mRecyclerView.mState);
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions));
+                }
+                globalPos[0] = globalScrollPosition;
+            }
+        });
+        checkForMainThreadException();
+
+        if (saveRestoreInBetween) {
+            saveRestore(mConfig);
+        }
+
+        checkForMainThreadException();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                int globalScrollPosition = globalPos[0];
+                // now scroll back and make sure global positions match
+                BitSet shouldTest = new BitSet(mAdapter.getItemCount());
+                shouldTest.set(0, mAdapter.getItemCount() - 1, true);
+                String assertPrefix = mConfig + ", restored in between:" + saveRestoreInBetween
+                        + " global pos must match when scrolling in reverse for position ";
+                int scrollAmount = Integer.MAX_VALUE;
+                while (!shouldTest.isEmpty() && scrollAmount != 0) {
+                    for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
+                        View child = mRecyclerView.getChildAt(i);
+                        int pos = mRecyclerView.getChildLayoutPosition(child);
+                        if (!shouldTest.get(pos)) {
+                            continue;
+                        }
+                        shouldTest.clear(pos);
+                        int globalPos;
+                        if (mConfig.mReverseLayout) {
+                            globalPos = globalScrollPosition +
+                                    mLayoutManager.mPrimaryOrientation.getDecoratedEnd(child);
+                        } else {
+                            globalPos = globalScrollPosition +
+                                    mLayoutManager.mPrimaryOrientation.getDecoratedStart(child);
+                        }
+                        assertEquals(assertPrefix + pos,
+                                globalPositions[pos], globalPos);
+                    }
+                    scrollAmount = mLayoutManager.scrollBy(-scrollStep,
+                            mRecyclerView.mRecycler, mRecyclerView.mState);
+                    globalScrollPosition += scrollAmount;
+                }
+                assertTrue("all views should be seen", shouldTest.isEmpty());
+            }
+        });
+        checkForMainThreadException();
+    }
+
+    private void saveRestore(final Config config) throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    Parcelable savedState = mRecyclerView.onSaveInstanceState();
+                    // we append a suffix to the parcelable to test out of bounds
+                    String parcelSuffix = UUID.randomUUID().toString();
+                    Parcel parcel = Parcel.obtain();
+                    savedState.writeToParcel(parcel, 0);
+                    parcel.writeString(parcelSuffix);
+                    removeRecyclerView();
+                    // reset for reading
+                    parcel.setDataPosition(0);
+                    // re-create
+                    savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
+                    RecyclerView restored = new RecyclerView(getActivity());
+                    mLayoutManager = new WrappedLayoutManager(config.mSpanCount,
+                            config.mOrientation);
+                    mLayoutManager.setGapStrategy(config.mGapStrategy);
+                    restored.setLayoutManager(mLayoutManager);
+                    // use the same adapter for Rect matching
+                    restored.setAdapter(mAdapter);
+                    restored.onRestoreInstanceState(savedState);
+                    if (Looper.myLooper() == Looper.getMainLooper()) {
+                        mLayoutManager.expectLayouts(1);
+                        setRecyclerView(restored);
+                    } else {
+                        mLayoutManager.expectLayouts(1);
+                        setRecyclerView(restored);
+                        mLayoutManager.waitForLayout(2);
+                    }
+                } catch (Throwable t) {
+                    postExceptionToInstrumentation(t);
+                }
+            }
+        });
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void getFirstLastChildrenTest() throws Throwable {
+        getFirstLastChildrenTest(false);
+    }
+
+    @Test
+    public void getFirstLastChildrenTestProvideArray() throws Throwable {
+        getFirstLastChildrenTest(true);
+    }
+
+    public void getFirstLastChildrenTest(final boolean provideArr) throws Throwable {
+        setupByConfig(mConfig);
+        waitFirstLayout();
+        Runnable viewInBoundsTest = new Runnable() {
+            @Override
+            public void run() {
+                VisibleChildren visibleChildren = mLayoutManager.traverseAndFindVisibleChildren();
+                final String boundsLog = mLayoutManager.getBoundsLog();
+                VisibleChildren queryResult = new VisibleChildren(mLayoutManager.getSpanCount());
+                queryResult.findFirstPartialVisibleClosestToStart = mLayoutManager
+                        .findFirstVisibleItemClosestToStart(false);
+                queryResult.findFirstPartialVisibleClosestToEnd = mLayoutManager
+                        .findFirstVisibleItemClosestToEnd(false);
+                queryResult.firstFullyVisiblePositions = mLayoutManager
+                        .findFirstCompletelyVisibleItemPositions(
+                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
+                queryResult.firstVisiblePositions = mLayoutManager
+                        .findFirstVisibleItemPositions(
+                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
+                queryResult.lastFullyVisiblePositions = mLayoutManager
+                        .findLastCompletelyVisibleItemPositions(
+                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
+                queryResult.lastVisiblePositions = mLayoutManager
+                        .findLastVisibleItemPositions(
+                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
+                assertEquals(mConfig + ":\nfirst visible child should match traversal result\n"
+                        + "traversed:" + visibleChildren + "\n"
+                        + "queried:" + queryResult + "\n"
+                        + boundsLog, visibleChildren, queryResult
+                );
+            }
+        };
+        mActivityRule.runOnUiThread(viewInBoundsTest);
+        // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching
+        // case
+        final int scrollPosition = mAdapter.getItemCount();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.smoothScrollToPosition(scrollPosition);
+            }
+        });
+        while (mLayoutManager.isSmoothScrolling() ||
+                mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
+            mActivityRule.runOnUiThread(viewInBoundsTest);
+            checkForMainThreadException();
+            Thread.sleep(400);
+        }
+        // delete all items
+        mLayoutManager.expectLayouts(2);
+        mAdapter.deleteAndNotify(0, mAdapter.getItemCount());
+        mLayoutManager.waitForLayout(2);
+        // test empty case
+        mActivityRule.runOnUiThread(viewInBoundsTest);
+        // set a new adapter with huge items to test full bounds check
+        mLayoutManager.expectLayouts(1);
+        final int totalSpace = mLayoutManager.mPrimaryOrientation.getTotalSpace();
+        final TestAdapter newAdapter = new TestAdapter(100) {
+            @Override
+            public void onBindViewHolder(@NonNull TestViewHolder holder,
+                    int position) {
+                super.onBindViewHolder(holder, position);
+                if (mConfig.mOrientation == LinearLayoutManager.HORIZONTAL) {
+                    holder.itemView.setMinimumWidth(totalSpace + 100);
+                } else {
+                    holder.itemView.setMinimumHeight(totalSpace + 100);
+                }
+            }
+        };
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mRecyclerView.setAdapter(newAdapter);
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        mActivityRule.runOnUiThread(viewInBoundsTest);
+        checkForMainThreadException();
+
+        // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching
+        // case
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                final int diff;
+                if (mConfig.mReverseLayout) {
+                    diff = -1;
+                } else {
+                    diff = 1;
+                }
+                final int distance = diff * 10;
+                if (mConfig.mOrientation == HORIZONTAL) {
+                    mRecyclerView.scrollBy(distance, 0);
+                } else {
+                    mRecyclerView.scrollBy(0, distance);
+                }
+            }
+        });
+        mActivityRule.runOnUiThread(viewInBoundsTest);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void viewSnapTest() throws Throwable {
+        final Config config = ((Config) mConfig.clone()).itemCount(mConfig.mSpanCount + 1);
+        setupByConfig(config);
+        mAdapter.mOnBindCallback = new OnBindCallback() {
+            @Override
+            void onBoundItem(TestViewHolder vh, int position) {
+                StaggeredGridLayoutManager.LayoutParams
+                        lp = (StaggeredGridLayoutManager.LayoutParams) vh.itemView
+                        .getLayoutParams();
+                if (config.mOrientation == HORIZONTAL) {
+                    lp.width = mRecyclerView.getWidth() / 3;
+                } else {
+                    lp.height = mRecyclerView.getHeight() / 3;
+                }
+            }
+
+            @Override
+            boolean assignRandomSize() {
+                return false;
+            }
+        };
+        waitFirstLayout();
+        // run these tests twice. once initial layout, once after scroll
+        String logSuffix = "";
+        for (int i = 0; i < 2; i++) {
+            Map<Item, Rect> itemRectMap = mLayoutManager.collectChildCoordinates();
+            Rect recyclerViewBounds = getDecoratedRecyclerViewBounds();
+            // workaround for SGLM's span distribution issue. Right now, it may leave gaps so we
+            // avoid it by setting its layout params directly
+            if (config.mOrientation == HORIZONTAL) {
+                recyclerViewBounds.bottom -= recyclerViewBounds.height() % config.mSpanCount;
+            } else {
+                recyclerViewBounds.right -= recyclerViewBounds.width() % config.mSpanCount;
+            }
+
+            Rect usedLayoutBounds = new Rect();
+            for (Rect rect : itemRectMap.values()) {
+                usedLayoutBounds.union(rect);
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "testing view snapping (" + logSuffix + ") for config " + config);
+            }
+            if (config.mOrientation == VERTICAL) {
+                assertEquals(config + " there should be no gap on left" + logSuffix,
+                        usedLayoutBounds.left, recyclerViewBounds.left);
+                assertEquals(config + " there should be no gap on right" + logSuffix,
+                        usedLayoutBounds.right, recyclerViewBounds.right);
+                if (config.mReverseLayout) {
+                    assertEquals(config + " there should be no gap on bottom" + logSuffix,
+                            usedLayoutBounds.bottom, recyclerViewBounds.bottom);
+                    assertTrue(config + " there should be some gap on top" + logSuffix,
+                            usedLayoutBounds.top > recyclerViewBounds.top);
+                } else {
+                    assertEquals(config + " there should be no gap on top" + logSuffix,
+                            usedLayoutBounds.top, recyclerViewBounds.top);
+                    assertTrue(config + " there should be some gap at the bottom" + logSuffix,
+                            usedLayoutBounds.bottom < recyclerViewBounds.bottom);
+                }
+            } else {
+                assertEquals(config + " there should be no gap on top" + logSuffix,
+                        usedLayoutBounds.top, recyclerViewBounds.top);
+                assertEquals(config + " there should be no gap at the bottom" + logSuffix,
+                        usedLayoutBounds.bottom, recyclerViewBounds.bottom);
+                if (config.mReverseLayout) {
+                    assertEquals(config + " there should be no on right" + logSuffix,
+                            usedLayoutBounds.right, recyclerViewBounds.right);
+                    assertTrue(config + " there should be some gap on left" + logSuffix,
+                            usedLayoutBounds.left > recyclerViewBounds.left);
+                } else {
+                    assertEquals(config + " there should be no gap on left" + logSuffix,
+                            usedLayoutBounds.left, recyclerViewBounds.left);
+                    assertTrue(config + " there should be some gap on right" + logSuffix,
+                            usedLayoutBounds.right < recyclerViewBounds.right);
+                }
+            }
+            final int scroll = config.mReverseLayout ? -500 : 500;
+            scrollBy(scroll);
+            logSuffix = " scrolled " + scroll;
+        }
+    }
+
+    @Test
+    public void scrollToPositionWithOffsetTest() throws Throwable {
+        setupByConfig(mConfig);
+        waitFirstLayout();
+        OrientationHelper orientationHelper = OrientationHelper
+                .createOrientationHelper(mLayoutManager, mConfig.mOrientation);
+        Rect layoutBounds = getDecoratedRecyclerViewBounds();
+        // try scrolling towards head, should not affect anything
+        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
+        scrollToPositionWithOffset(0, 20);
+        assertRectSetsEqual(mConfig + " trying to over scroll with offset should be no-op",
+                before, mLayoutManager.collectChildCoordinates());
+        // try offsetting some visible children
+        int testCount = 10;
+        while (testCount-- > 0) {
+            // get middle child
+            final View child = mLayoutManager.getChildAt(mLayoutManager.getChildCount() / 2);
+            final int position = mRecyclerView.getChildLayoutPosition(child);
+            final int startOffset = mConfig.mReverseLayout ?
+                    orientationHelper.getEndAfterPadding() - orientationHelper
+                            .getDecoratedEnd(child)
+                    : orientationHelper.getDecoratedStart(child) - orientationHelper
+                            .getStartAfterPadding();
+            final int scrollOffset = startOffset / 2;
+            mLayoutManager.expectLayouts(1);
+            scrollToPositionWithOffset(position, scrollOffset);
+            mLayoutManager.waitForLayout(2);
+            final int finalOffset = mConfig.mReverseLayout ?
+                    orientationHelper.getEndAfterPadding() - orientationHelper
+                            .getDecoratedEnd(child)
+                    : orientationHelper.getDecoratedStart(child) - orientationHelper
+                            .getStartAfterPadding();
+            assertEquals(mConfig + " scroll with offset on a visible child should work fine",
+                    scrollOffset, finalOffset);
+        }
+
+        // try scrolling to invisible children
+        testCount = 10;
+        // we test above and below, one by one
+        int offsetMultiplier = -1;
+        while (testCount-- > 0) {
+            final TargetTuple target = findInvisibleTarget(mConfig);
+            mLayoutManager.expectLayouts(1);
+            final int offset = offsetMultiplier
+                    * orientationHelper.getDecoratedMeasurement(mLayoutManager.getChildAt(0)) / 3;
+            scrollToPositionWithOffset(target.mPosition, offset);
+            mLayoutManager.waitForLayout(2);
+            final View child = mLayoutManager.findViewByPosition(target.mPosition);
+            assertNotNull(mConfig + " scrolling to a mPosition with offset " + offset
+                    + " should layout it", child);
+            final Rect bounds = mLayoutManager.getViewBounds(child);
+            if (DEBUG) {
+                Log.d(TAG, mConfig + " post scroll to invisible mPosition " + bounds + " in "
+                        + layoutBounds + " with offset " + offset);
+            }
+
+            if (mConfig.mReverseLayout) {
+                assertEquals(mConfig + " when scrolling with offset to an invisible in reverse "
+                                + "layout, its end should align with recycler view's end - offset",
+                        orientationHelper.getEndAfterPadding() - offset,
+                        orientationHelper.getDecoratedEnd(child)
+                );
+            } else {
+                assertEquals(mConfig + " when scrolling with offset to an invisible child in normal"
+                                + " layout its start should align with recycler view's start + "
+                                + "offset",
+                        orientationHelper.getStartAfterPadding() + offset,
+                        orientationHelper.getDecoratedStart(child)
+                );
+            }
+            offsetMultiplier *= -1;
+        }
+    }
+
+    @Test
+    public void scrollToPositionTest() throws Throwable {
+        setupByConfig(mConfig);
+        waitFirstLayout();
+        OrientationHelper orientationHelper = OrientationHelper
+                .createOrientationHelper(mLayoutManager, mConfig.mOrientation);
+        Rect layoutBounds = getDecoratedRecyclerViewBounds();
+        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
+            View view = mLayoutManager.getChildAt(i);
+            Rect bounds = mLayoutManager.getViewBounds(view);
+            if (layoutBounds.contains(bounds)) {
+                Map<Item, Rect> initialBounds = mLayoutManager.collectChildCoordinates();
+                final int position = mRecyclerView.getChildLayoutPosition(view);
+                StaggeredGridLayoutManager.LayoutParams layoutParams
+                        = (StaggeredGridLayoutManager.LayoutParams) (view.getLayoutParams());
+                TestViewHolder vh = (TestViewHolder) layoutParams.mViewHolder;
+                assertEquals("recycler view mPosition should match adapter mPosition", position,
+                        vh.mBoundItem.mAdapterIndex);
+                if (DEBUG) {
+                    Log.d(TAG, "testing scroll to visible mPosition at " + position
+                            + " " + bounds + " inside " + layoutBounds);
+                }
+                mLayoutManager.expectLayouts(1);
+                scrollToPosition(position);
+                mLayoutManager.waitForLayout(2);
+                if (DEBUG) {
+                    view = mLayoutManager.findViewByPosition(position);
+                    Rect newBounds = mLayoutManager.getViewBounds(view);
+                    Log.d(TAG, "after scrolling to visible mPosition " +
+                            bounds + " equals " + newBounds);
+                }
+
+                assertRectSetsEqual(
+                        mConfig + "scroll to mPosition on fully visible child should be no-op",
+                        initialBounds, mLayoutManager.collectChildCoordinates());
+            } else {
+                final int position = mRecyclerView.getChildLayoutPosition(view);
+                if (DEBUG) {
+                    Log.d(TAG,
+                            "child(" + position + ") not fully visible " + bounds + " not inside "
+                                    + layoutBounds
+                                    + mRecyclerView.getChildLayoutPosition(view)
+                    );
+                }
+                mLayoutManager.expectLayouts(1);
+                mActivityRule.runOnUiThread(new Runnable() {
+                    @Override
+                    public void run() {
+                        mLayoutManager.scrollToPosition(position);
+                    }
+                });
+                mLayoutManager.waitForLayout(2);
+                view = mLayoutManager.findViewByPosition(position);
+                bounds = mLayoutManager.getViewBounds(view);
+                if (DEBUG) {
+                    Log.d(TAG, "after scroll to partially visible child " + bounds + " in "
+                            + layoutBounds);
+                }
+                assertTrue(mConfig
+                                + " after scrolling to a partially visible child, it should become fully "
+                                + " visible. " + bounds + " not inside " + layoutBounds,
+                        layoutBounds.contains(bounds)
+                );
+                assertTrue(
+                        mConfig + " when scrolling to a partially visible item, one of its edges "
+                                + "should be on the boundaries",
+                        orientationHelper.getStartAfterPadding() ==
+                                orientationHelper.getDecoratedStart(view)
+                                || orientationHelper.getEndAfterPadding() ==
+                                orientationHelper.getDecoratedEnd(view));
+            }
+        }
+
+        // try scrolling to invisible children
+        int testCount = 10;
+        while (testCount-- > 0) {
+            final TargetTuple target = findInvisibleTarget(mConfig);
+            mLayoutManager.expectLayouts(1);
+            scrollToPosition(target.mPosition);
+            mLayoutManager.waitForLayout(2);
+            final View child = mLayoutManager.findViewByPosition(target.mPosition);
+            assertNotNull(mConfig + " scrolling to a mPosition should lay it out", child);
+            final Rect bounds = mLayoutManager.getViewBounds(child);
+            if (DEBUG) {
+                Log.d(TAG, mConfig + " post scroll to invisible mPosition " + bounds + " in "
+                        + layoutBounds);
+            }
+            assertTrue(mConfig + " scrolling to a mPosition should make it fully visible",
+                    layoutBounds.contains(bounds));
+            if (target.mLayoutDirection == LAYOUT_START) {
+                assertEquals(
+                        mConfig + " when scrolling to an invisible child above, its start should"
+                                + " align with recycler view's start",
+                        orientationHelper.getStartAfterPadding(),
+                        orientationHelper.getDecoratedStart(child)
+                );
+            } else {
+                assertEquals(mConfig + " when scrolling to an invisible child below, its end "
+                                + "should align with recycler view's end",
+                        orientationHelper.getEndAfterPadding(),
+                        orientationHelper.getDecoratedEnd(child)
+                );
+            }
+        }
+    }
+
+    @Test
+    public void scollByTest() throws Throwable {
+        setupByConfig(mConfig);
+        waitFirstLayout();
+        // try invalid scroll. should not happen
+        final View first = mLayoutManager.getChildAt(0);
+        OrientationHelper primaryOrientation = OrientationHelper
+                .createOrientationHelper(mLayoutManager, mConfig.mOrientation);
+        int scrollDist;
+        if (mConfig.mReverseLayout) {
+            scrollDist = primaryOrientation.getDecoratedMeasurement(first) / 2;
+        } else {
+            scrollDist = -primaryOrientation.getDecoratedMeasurement(first) / 2;
+        }
+        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
+        scrollBy(scrollDist);
+        Map<Item, Rect> after = mLayoutManager.collectChildCoordinates();
+        assertRectSetsEqual(
+                mConfig + " if there are no more items, scroll should not happen (dt:" + scrollDist
+                        + ")",
+                before, after
+        );
+
+        scrollDist = -scrollDist * 3;
+        before = mLayoutManager.collectChildCoordinates();
+        scrollBy(scrollDist);
+        after = mLayoutManager.collectChildCoordinates();
+        int layoutStart = primaryOrientation.getStartAfterPadding();
+        int layoutEnd = primaryOrientation.getEndAfterPadding();
+        for (Map.Entry<Item, Rect> entry : before.entrySet()) {
+            Rect afterRect = after.get(entry.getKey());
+            // offset rect
+            if (mConfig.mOrientation == VERTICAL) {
+                entry.getValue().offset(0, -scrollDist);
+            } else {
+                entry.getValue().offset(-scrollDist, 0);
+            }
+            if (afterRect == null || afterRect.isEmpty()) {
+                // assert item is out of bounds
+                int start, end;
+                if (mConfig.mOrientation == VERTICAL) {
+                    start = entry.getValue().top;
+                    end = entry.getValue().bottom;
+                } else {
+                    start = entry.getValue().left;
+                    end = entry.getValue().right;
+                }
+                assertTrue(
+                        mConfig + " if item is missing after relayout, it should be out of bounds."
+                                + "item start: " + start + ", end:" + end + " layout start:"
+                                + layoutStart +
+                                ", layout end:" + layoutEnd,
+                        start <= layoutStart && end <= layoutEnd ||
+                                start >= layoutEnd && end >= layoutEnd
+                );
+            } else {
+                assertEquals(mConfig + " Item should be laid out at the scroll offset coordinates",
+                        entry.getValue(),
+                        afterRect);
+            }
+        }
+        assertViewPositions(mConfig);
+    }
+
+    @Test
+    public void layoutOrderTest() throws Throwable {
+        setupByConfig(mConfig);
+        assertViewPositions(mConfig);
+    }
+
+    @Test
+    public void consistentRelayout() throws Throwable {
+        consistentRelayoutTest(mConfig, false);
+    }
+
+    @Test
+    public void consistentRelayoutWithFullSpanFirstChild() throws Throwable {
+        consistentRelayoutTest(mConfig, true);
+    }
+
+    @Suppress
+    @FlakyTest(bugId = 34158822)
+    @Test
+    @LargeTest
+    public void dontRecycleViewsTranslatedOutOfBoundsFromStart() throws Throwable {
+        final Config config = ((Config) mConfig.clone()).itemCount(1000);
+        setupByConfig(config);
+        waitFirstLayout();
+        // pick position from child count so that it is not too far away
+        int pos = mRecyclerView.getChildCount() * 2;
+        smoothScrollToPosition(pos, true);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(pos);
+        OrientationHelper helper = mLayoutManager.mPrimaryOrientation;
+        int gap = helper.getDecoratedStart(vh.itemView);
+        scrollBy(gap);
+        gap = helper.getDecoratedStart(vh.itemView);
+        assertThat("test sanity", gap, is(0));
+
+        final int size = helper.getDecoratedMeasurement(vh.itemView);
+        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mConfig.mOrientation == HORIZONTAL) {
+                    vh.itemView.setTranslationX(size * 2);
+                } else {
+                    vh.itemView.setTranslationY(size * 2);
+                }
+            }
+        });
+        scrollBy(size * 2);
+        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
+        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
+        assertThat(vh.getAdapterPosition(), is(pos));
+        scrollBy(size * 2);
+        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
+    }
+
+    @Test
+    public void dontRecycleViewsTranslatedOutOfBoundsFromEnd() throws Throwable {
+        final Config config = ((Config) mConfig.clone()).itemCount(1000);
+        setupByConfig(config);
+        waitFirstLayout();
+        // pick position from child count so that it is not too far away
+        int pos = mRecyclerView.getChildCount() * 2;
+        mLayoutManager.expectLayouts(1);
+        scrollToPosition(pos);
+        mLayoutManager.waitForLayout(2);
+        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(pos);
+        OrientationHelper helper = mLayoutManager.mPrimaryOrientation;
+        int gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
+        scrollBy(-gap);
+        gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
+        assertThat("test sanity", gap, is(0));
+
+        final int size = helper.getDecoratedMeasurement(vh.itemView);
+        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (mConfig.mOrientation == HORIZONTAL) {
+                    vh.itemView.setTranslationX(-size * 2);
+                } else {
+                    vh.itemView.setTranslationY(-size * 2);
+                }
+            }
+        });
+        scrollBy(-size * 2);
+        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
+        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
+        assertThat(vh.getAdapterPosition(), is(pos));
+        scrollBy(-size * 2);
+        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
+    }
+
+    public void consistentRelayoutTest(Config config, boolean firstChildMultiSpan)
+            throws Throwable {
+        setupByConfig(config);
+        if (firstChildMultiSpan) {
+            mAdapter.mFullSpanItems.add(0);
+        }
+        waitFirstLayout();
+        // record all child positions
+        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
+        requestLayoutOnUIThread(mRecyclerView);
+        Map<Item, Rect> after = mLayoutManager.collectChildCoordinates();
+        assertRectSetsEqual(
+                config + " simple re-layout, firstChildMultiSpan:" + firstChildMultiSpan, before,
+                after);
+        // scroll some to create inconsistency
+        View firstChild = mLayoutManager.getChildAt(0);
+        final int firstChildStartBeforeScroll = mLayoutManager.mPrimaryOrientation
+                .getDecoratedStart(firstChild);
+        int distance = mLayoutManager.mPrimaryOrientation.getDecoratedMeasurement(firstChild) / 2;
+        if (config.mReverseLayout) {
+            distance *= -1;
+        }
+        scrollBy(distance);
+        waitForMainThread(2);
+        assertTrue("scroll by should move children", firstChildStartBeforeScroll !=
+                mLayoutManager.mPrimaryOrientation.getDecoratedStart(firstChild));
+        before = mLayoutManager.collectChildCoordinates();
+        mLayoutManager.expectLayouts(1);
+        requestLayoutOnUIThread(mRecyclerView);
+        mLayoutManager.waitForLayout(2);
+        after = mLayoutManager.collectChildCoordinates();
+        assertRectSetsEqual(config + " simple re-layout after scroll", before, after);
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerCacheTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerGapTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerSavedStateTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerSnappingTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
new file mode 100644
index 0000000..8ed96e4
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
+import static android.support.v7.widget.StaggeredGridLayoutManager
+        .GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
+import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
+import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
+import static android.support.v7.widget.StaggeredGridLayoutManager.LayoutParams;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.test.filters.LargeTest;
+import android.support.v4.view.AccessibilityDelegateCompat;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.StateSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.MatcherAssert;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+@LargeTest
+public class StaggeredGridLayoutManagerTest extends BaseStaggeredGridLayoutManagerTest {
+
+    @Test
+    public void layout_rvHasPaddingChildIsMatchParentVertical_childrenAreInsideParent()
+            throws Throwable {
+        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(VERTICAL, false);
+    }
+
+    @Test
+    public void layout_rvHasPaddingChildIsMatchParentHorizontal_childrenAreInsideParent()
+            throws Throwable {
+        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(HORIZONTAL, false);
+    }
+
+    @Test
+    public void layout_rvHasPaddingChildIsMatchParentVerticalFullSpan_childrenAreInsideParent()
+            throws Throwable {
+        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(VERTICAL, true);
+    }
+
+    @Test
+    public void layout_rvHasPaddingChildIsMatchParentHorizontalFullSpan_childrenAreInsideParent()
+            throws Throwable {
+        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(HORIZONTAL, true);
+    }
+
+    private void layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(
+            final int orientation, final boolean fullSpan)
+            throws Throwable {
+
+        setupByConfig(new Config(orientation, false, 1, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
+                new GridTestAdapter(10, orientation) {
+
+                    @NonNull
+                    @Override
+                    public TestViewHolder onCreateViewHolder(
+                            @NonNull ViewGroup parent, int viewType) {
+                        View view = new View(parent.getContext());
+                        StaggeredGridLayoutManager.LayoutParams layoutParams =
+                                new StaggeredGridLayoutManager.LayoutParams(
+                                        ViewGroup.LayoutParams.MATCH_PARENT,
+                                        ViewGroup.LayoutParams.MATCH_PARENT);
+                        layoutParams.setFullSpan(fullSpan);
+                        view.setLayoutParams(layoutParams);
+                        return new TestViewHolder(view);
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+                        // No actual binding needed, but we need to override this to prevent default
+                        // behavior of GridTestAdapter.
+                    }
+                });
+        mRecyclerView.setPadding(1, 2, 3, 4);
+
+        waitFirstLayout();
+
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                int childDimension;
+                int recyclerViewDimensionMinusPadding;
+                if (orientation == VERTICAL) {
+                    childDimension = mRecyclerView.getChildAt(0).getHeight();
+                    recyclerViewDimensionMinusPadding = mRecyclerView.getHeight()
+                            - mRecyclerView.getPaddingTop()
+                            - mRecyclerView.getPaddingBottom();
+                } else {
+                    childDimension = mRecyclerView.getChildAt(0).getWidth();
+                    recyclerViewDimensionMinusPadding = mRecyclerView.getWidth()
+                            - mRecyclerView.getPaddingLeft()
+                            - mRecyclerView.getPaddingRight();
+                }
+                assertThat(childDimension, equalTo(recyclerViewDimensionMinusPadding));
+            }
+        });
+    }
+
+    @Test
+    public void forceLayoutOnDetach() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
+        waitFirstLayout();
+        assertFalse("test sanity", mRecyclerView.isLayoutRequested());
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mLayoutManager.onDetachedFromWindow(mRecyclerView, mRecyclerView.mRecycler);
+            }
+        });
+        assertTrue(mRecyclerView.isLayoutRequested());
+    }
+
+    @Test
+    public void areAllStartsTheSame() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_NONE).itemCount(300));
+        waitFirstLayout();
+        smoothScrollToPosition(100);
+        mLayoutManager.expectLayouts(1);
+        mAdapter.deleteAndNotify(0, 2);
+        mLayoutManager.waitForLayout(2000);
+        smoothScrollToPosition(0);
+        assertFalse("all starts should not be the same", mLayoutManager.areAllStartsEqual());
+    }
+
+    @Test
+    public void areAllEndsTheSame() throws Throwable {
+        setupByConfig(new Config(VERTICAL, true, 3, GAP_HANDLING_NONE).itemCount(300));
+        waitFirstLayout();
+        smoothScrollToPosition(100);
+        mLayoutManager.expectLayouts(1);
+        mAdapter.deleteAndNotify(0, 2);
+        mLayoutManager.waitForLayout(2);
+        smoothScrollToPosition(0);
+        assertFalse("all ends should not be the same", mLayoutManager.areAllEndsEqual());
+    }
+
+    @Test
+    public void getPositionsBeforeInitialization() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
+        int[] positions = mLayoutManager.findFirstCompletelyVisibleItemPositions(null);
+        MatcherAssert.assertThat(positions,
+                CoreMatchers.is(new int[]{RecyclerView.NO_POSITION, RecyclerView.NO_POSITION,
+                        RecyclerView.NO_POSITION}));
+    }
+
+    @Test
+    public void findLastInUnevenDistribution() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, 2, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS)
+                .itemCount(5));
+        mAdapter.mOnBindCallback = new OnBindCallback() {
+            @Override
+            void onBoundItem(TestViewHolder vh, int position) {
+                LayoutParams lp = (LayoutParams) vh.itemView.getLayoutParams();
+                if (position == 1) {
+                    lp.height = mRecyclerView.getHeight() - 10;
+                } else {
+                    lp.height = 5;
+                }
+                vh.itemView.setMinimumHeight(0);
+            }
+        };
+        waitFirstLayout();
+        int[] into = new int[2];
+        mLayoutManager.findFirstCompletelyVisibleItemPositions(into);
+        assertEquals("first completely visible item from span 0 should be 0", 0, into[0]);
+        assertEquals("first completely visible item from span 1 should be 1", 1, into[1]);
+        mLayoutManager.findLastCompletelyVisibleItemPositions(into);
+        assertEquals("last completely visible item from span 0 should be 4", 4, into[0]);
+        assertEquals("last completely visible item from span 1 should be 1", 1, into[1]);
+        assertEquals("first fully visible child should be at position",
+                0, mRecyclerView.getChildViewHolder(mLayoutManager.
+                        findFirstVisibleItemClosestToStart(true)).getPosition());
+        assertEquals("last fully visible child should be at position",
+                4, mRecyclerView.getChildViewHolder(mLayoutManager.
+                        findFirstVisibleItemClosestToEnd(true)).getPosition());
+
+        assertEquals("first visible child should be at position",
+                0, mRecyclerView.getChildViewHolder(mLayoutManager.
+                        findFirstVisibleItemClosestToStart(false)).getPosition());
+        assertEquals("last visible child should be at position",
+                4, mRecyclerView.getChildViewHolder(mLayoutManager.
+                        findFirstVisibleItemClosestToEnd(false)).getPosition());
+
+    }
+
+    @Test
+    public void customWidthInHorizontal() throws Throwable {
+        customSizeInScrollDirectionTest(
+                new Config(HORIZONTAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
+    }
+
+    @Test
+    public void customHeightInVertical() throws Throwable {
+        customSizeInScrollDirectionTest(
+                new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
+    }
+
+    public void customSizeInScrollDirectionTest(final Config config) throws Throwable {
+        setupByConfig(config);
+        final Map<View, Integer> sizeMap = new HashMap<View, Integer>();
+        mAdapter.mOnBindCallback = new OnBindCallback() {
+            @Override
+            void onBoundItem(TestViewHolder vh, int position) {
+                final ViewGroup.LayoutParams layoutParams = vh.itemView.getLayoutParams();
+                final int size = 1 + position * 5;
+                if (config.mOrientation == HORIZONTAL) {
+                    layoutParams.width = size;
+                } else {
+                    layoutParams.height = size;
+                }
+                sizeMap.put(vh.itemView, size);
+                if (position == 3) {
+                    getLp(vh.itemView).setFullSpan(true);
+                }
+            }
+
+            @Override
+            boolean assignRandomSize() {
+                return false;
+            }
+        };
+        waitFirstLayout();
+        assertTrue("[test sanity] some views should be laid out", sizeMap.size() > 0);
+        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
+            View child = mRecyclerView.getChildAt(i);
+            final int size = config.mOrientation == HORIZONTAL ? child.getWidth()
+                    : child.getHeight();
+            assertEquals("child " + i + " should have the size specified in its layout params",
+                    sizeMap.get(child).intValue(), size);
+        }
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void gapHandlingWhenItemMovesToTop() throws Throwable {
+        gapHandlingWhenItemMovesToTopTest();
+    }
+
+    @Test
+    public void gapHandlingWhenItemMovesToTopWithFullSpan() throws Throwable {
+        gapHandlingWhenItemMovesToTopTest(0);
+    }
+
+    @Test
+    public void gapHandlingWhenItemMovesToTopWithFullSpan2() throws Throwable {
+        gapHandlingWhenItemMovesToTopTest(1);
+    }
+
+    public void gapHandlingWhenItemMovesToTopTest(int... fullSpanIndices) throws Throwable {
+        Config config = new Config(VERTICAL, false, 2, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
+        config.itemCount(3);
+        setupByConfig(config);
+        mAdapter.mOnBindCallback = new OnBindCallback() {
+            @Override
+            void onBoundItem(TestViewHolder vh, int position) {
+            }
+
+            @Override
+            boolean assignRandomSize() {
+                return false;
+            }
+        };
+        for (int i : fullSpanIndices) {
+            mAdapter.mFullSpanItems.add(i);
+        }
+        waitFirstLayout();
+        mLayoutManager.expectLayouts(1);
+        mAdapter.moveItem(1, 0, true);
+        mLayoutManager.waitForLayout(2);
+        final Map<Item, Rect> desiredPositions = mLayoutManager.collectChildCoordinates();
+        // move back.
+        mLayoutManager.expectLayouts(1);
+        mAdapter.moveItem(0, 1, true);
+        mLayoutManager.waitForLayout(2);
+        mLayoutManager.expectLayouts(2);
+        mAdapter.moveAndNotify(1, 0);
+        mLayoutManager.waitForLayout(2);
+        Thread.sleep(1000);
+        getInstrumentation().waitForIdleSync();
+        checkForMainThreadException();
+        // item should be positioned properly
+        assertRectSetsEqual("final position after a move", desiredPositions,
+                mLayoutManager.collectChildCoordinates());
+
+    }
+
+    @Test
+    public void focusSearchFailureUp() throws Throwable {
+        focusSearchFailure(false);
+    }
+
+    @Test
+    public void focusSearchFailureDown() throws Throwable {
+        focusSearchFailure(true);
+    }
+
+    @Test
+    public void focusSearchFailureFromSubChild() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
+                new GridTestAdapter(1000, VERTICAL) {
+
+                    @NonNull
+                    @Override
+                    public TestViewHolder onCreateViewHolder(
+                            @NonNull ViewGroup parent, int viewType) {
+                        FrameLayout fl = new FrameLayout(parent.getContext());
+                        EditText editText = new EditText(parent.getContext());
+                        fl.addView(editText);
+                        editText.setEllipsize(TextUtils.TruncateAt.END);
+                        return new TestViewHolder(fl);
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+                        Item item = mItems.get(position);
+                        holder.mBoundItem = item;
+                        ((EditText) ((FrameLayout) holder.itemView).getChildAt(0)).setText(
+                                item.mText + " (" + item.mId + ")");
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation using this for kitkat tests
+                        holder.itemView.setBackgroundDrawable(stl);
+                        if (mOnBindCallback != null) {
+                            mOnBindCallback.onBoundItem(holder, position);
+                        }
+                    }
+                });
+        mLayoutManager.expectLayouts(1);
+        setRecyclerView(mRecyclerView);
+        mLayoutManager.waitForLayout(10);
+        getInstrumentation().waitForIdleSync();
+        ViewGroup lastChild = (ViewGroup) mRecyclerView.getChildAt(
+                mRecyclerView.getChildCount() - 1);
+        RecyclerView.ViewHolder lastViewHolder = mRecyclerView.getChildViewHolder(lastChild);
+        View subChildToFocus = lastChild.getChildAt(0);
+        requestFocus(subChildToFocus, true);
+        assertThat("test sanity", subChildToFocus.isFocused(), CoreMatchers.is(true));
+        focusSearch(subChildToFocus, View.FOCUS_FORWARD);
+        waitForIdleScroll(mRecyclerView);
+        checkForMainThreadException();
+        View focusedChild = mRecyclerView.getFocusedChild();
+        if (focusedChild == subChildToFocus.getParent()) {
+            focusSearch(focusedChild, View.FOCUS_FORWARD);
+            waitForIdleScroll(mRecyclerView);
+            focusedChild = mRecyclerView.getFocusedChild();
+        }
+        RecyclerView.ViewHolder containingViewHolder = mRecyclerView.findContainingViewHolder(
+                focusedChild);
+        assertTrue("new focused view should have a larger position "
+                        + lastViewHolder.getAdapterPosition() + " vs "
+                        + containingViewHolder.getAdapterPosition(),
+                lastViewHolder.getAdapterPosition() < containingViewHolder.getAdapterPosition());
+    }
+
+    public void focusSearchFailure(boolean scrollDown) throws Throwable {
+        int focusDir = scrollDown ? View.FOCUS_DOWN : View.FOCUS_UP;
+        setupByConfig(new Config(VERTICAL, !scrollDown, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS)
+                , new GridTestAdapter(31, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        testViewHolder.itemView.setFocusable(true);
+                        testViewHolder.itemView.setFocusableInTouchMode(true);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation used to support kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / 3);
+                    }
+                });
+        /**
+         * 0  1  2
+         * 3  4  5
+         * 6  7  8
+         * 9  10 11
+         * 12 13 14
+         * 15 16 17
+         * 18 18 18
+         * 19
+         * 20 20 20
+         * 21 22
+         * 23 23 23
+         * 24 25 26
+         * 27 28 29
+         * 30
+         */
+        mAdapter.mFullSpanItems.add(18);
+        mAdapter.mFullSpanItems.add(20);
+        mAdapter.mFullSpanItems.add(23);
+        waitFirstLayout();
+        View viewToFocus = mRecyclerView.findViewHolderForAdapterPosition(1).itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
+        int pos = 1;
+        View focusedView = viewToFocus;
+        while (pos < 16) {
+            focusSearchAndWaitForScroll(focusedView, focusDir);
+            focusedView = mRecyclerView.getFocusedChild();
+            assertEquals(pos + 3,
+                    mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
+            pos += 3;
+        }
+        for (int i : new int[]{18, 19, 20, 21, 23, 24}) {
+            focusSearchAndWaitForScroll(focusedView, focusDir);
+            focusedView = mRecyclerView.getFocusedChild();
+            assertEquals(i, mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
+        }
+        // now move right
+        focusSearch(focusedView, View.FOCUS_RIGHT);
+        waitForIdleScroll(mRecyclerView);
+        focusedView = mRecyclerView.getFocusedChild();
+        assertEquals(25, mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
+        for (int i : new int[]{28, 30}) {
+            focusSearchAndWaitForScroll(focusedView, focusDir);
+            focusedView = mRecyclerView.getFocusedChild();
+            assertEquals(i, mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
+        }
+    }
+
+    private void focusSearchAndWaitForScroll(View focused, int dir) throws Throwable {
+        focusSearch(focused, dir);
+        waitForIdleScroll(mRecyclerView);
+    }
+
+    @Test
+    public void topUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of rows that can be fully in-bounds of RV.
+        final int visibleRowCount = 5;
+        final int spanCount = 3;
+        final int lastFocusableIndex = 6;
+
+        setupByConfig(new Config(VERTICAL, true, spanCount, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
+                new GridTestAdapter(18, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        testViewHolder.itemView.setFocusable(true);
+                        testViewHolder.itemView.setFocusableInTouchMode(true);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation used to support kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
+                                .getLayoutParams();
+                        if (position <= lastFocusableIndex) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
+                        lp.topMargin = 0;
+                        lp.leftMargin = 0;
+                        lp.rightMargin = 0;
+                        lp.bottomMargin = 0;
+                        if (position == 11) {
+                            lp.bottomMargin = 9;
+                        }
+                    }
+                });
+
+        /**
+         *
+         * 15 16 17
+         * 12 13 14
+         * 11 11 11
+         * 9 10
+         * 8 8 8
+         * 7
+         * 6 6 6
+         * 3 4 5
+         * 0 1 2
+         */
+        mAdapter.mFullSpanItems.add(6);
+        mAdapter.mFullSpanItems.add(8);
+        mAdapter.mFullSpanItems.add(11);
+        waitFirstLayout();
+
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
+
+        // The VH of the unfocusable item that just became fully visible after focusSearch.
+        RecyclerView.ViewHolder toVisible = null;
+
+        View focusedView = viewToFocus;
+        int actualFocusIndex = -1;
+        // First, scroll until the last focusable row.
+        for (int i : new int[]{4, 6}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_UP);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
+                    + actualFocusIndex, i, actualFocusIndex);
+        }
+
+        // Further scroll up in order to make the unfocusable rows visible. This process should
+        // continue until the currently focused item is still visible. The focused item should not
+        // change in this loop.
+        for (int i : new int[]{9, 11, 11, 11}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_UP);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
+
+            assertEquals("Focused view should not be changed, whereas it's now at "
+                    + actualFocusIndex, 6, actualFocusIndex);
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, focusedView));
+            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    @Test
+    public void bottomUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of rows that can be fully in-bounds of RV.
+        final int visibleRowCount = 5;
+        final int spanCount = 3;
+        final int lastFocusableIndex = 6;
+
+        setupByConfig(new Config(VERTICAL, false, spanCount, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
+                new GridTestAdapter(18, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        testViewHolder.itemView.setFocusable(true);
+                        testViewHolder.itemView.setFocusableInTouchMode(true);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation used to support kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
+                                .getLayoutParams();
+                        if (position <= lastFocusableIndex) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
+                        lp.topMargin = 0;
+                        lp.leftMargin = 0;
+                        lp.rightMargin = 0;
+                        lp.bottomMargin = 0;
+                        if (position == 11) {
+                            lp.topMargin = 9;
+                        }
+                    }
+                });
+
+        /**
+         * 0 1 2
+         * 3 4 5
+         * 6 6 6
+         * 7
+         * 8 8 8
+         * 9 10
+         * 11 11 11
+         * 12 13 14
+         * 15 16 17
+         */
+        mAdapter.mFullSpanItems.add(6);
+        mAdapter.mFullSpanItems.add(8);
+        mAdapter.mFullSpanItems.add(11);
+        waitFirstLayout();
+
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
+
+        // The VH of the unfocusable item that just became fully visible after focusSearch.
+        RecyclerView.ViewHolder toVisible = null;
+
+        View focusedView = viewToFocus;
+        int actualFocusIndex = -1;
+        // First, scroll until the last focusable row.
+        for (int i : new int[]{4, 6}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_DOWN);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
+                    + actualFocusIndex, i, actualFocusIndex);
+        }
+
+        // Further scroll down in order to make the unfocusable rows visible. This process should
+        // continue until the currently focused item is still visible. The focused item should not
+        // change in this loop.
+        for (int i : new int[]{9, 11, 11, 11}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_DOWN);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
+
+            assertEquals("Focused view should not be changed, whereas it's now at "
+                    + actualFocusIndex, 6, actualFocusIndex);
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, focusedView));
+            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    @Test
+    public void leftUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of columns that can be fully in-bounds of RV.
+        final int visibleColCount = 5;
+        final int spanCount = 3;
+        final int lastFocusableIndex = 6;
+
+        // Reverse layout so that views are placed from right to left.
+        setupByConfig(new Config(HORIZONTAL, true, spanCount,
+                        GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
+                new GridTestAdapter(18, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        testViewHolder.itemView.setFocusable(true);
+                        testViewHolder.itemView.setFocusableInTouchMode(true);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation used to support kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
+                                .getLayoutParams();
+                        if (position <= lastFocusableIndex) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
+                        lp.topMargin = 0;
+                        lp.leftMargin = 0;
+                        lp.rightMargin = 0;
+                        lp.bottomMargin = 0;
+                        if (position == 11) {
+                            lp.rightMargin = 9;
+                        }
+                    }
+                });
+
+        /**
+         * 15 12 11 9  8 7 6 3 0
+         * 16 13 11 10 8   6 4 1
+         * 17 14 11    8   6 5 2
+         */
+        mAdapter.mFullSpanItems.add(6);
+        mAdapter.mFullSpanItems.add(8);
+        mAdapter.mFullSpanItems.add(11);
+        waitFirstLayout();
+
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
+
+        // The VH of the unfocusable item that just became fully visible after focusSearch.
+        RecyclerView.ViewHolder toVisible = null;
+
+        View focusedView = viewToFocus;
+        int actualFocusIndex = -1;
+        // First, scroll until the last focusable column.
+        for (int i : new int[]{4, 6}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_LEFT);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
+                    + actualFocusIndex, i, actualFocusIndex);
+        }
+
+        // Further scroll left in order to make the unfocusable columns visible. This process should
+        // continue until the currently focused item is still visible. The focused item should not
+        // change in this loop.
+        for (int i : new int[]{9, 11, 11, 11}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_LEFT);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
+
+            assertEquals("Focused view should not be changed, whereas it's now at "
+                    + actualFocusIndex, 6, actualFocusIndex);
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, focusedView));
+            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    @Test
+    public void rightUnfocusableViewsVisibility() throws Throwable {
+        // The maximum number of columns that can be fully in-bounds of RV.
+        final int visibleColCount = 5;
+        final int spanCount = 3;
+        final int lastFocusableIndex = 6;
+
+        setupByConfig(new Config(HORIZONTAL, false, spanCount,
+                        GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
+                new GridTestAdapter(18, 1) {
+                    RecyclerView mAttachedRv;
+
+                    @Override
+                    public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
+                        testViewHolder.itemView.setFocusable(true);
+                        testViewHolder.itemView.setFocusableInTouchMode(true);
+                        // Good to have colors for debugging
+                        StateListDrawable stl = new StateListDrawable();
+                        stl.addState(new int[]{android.R.attr.state_focused},
+                                new ColorDrawable(Color.RED));
+                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
+                        //noinspection deprecation used to support kitkat tests
+                        testViewHolder.itemView.setBackgroundDrawable(stl);
+                        return testViewHolder;
+                    }
+
+                    @Override
+                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+                        mAttachedRv = recyclerView;
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull TestViewHolder holder,
+                            int position) {
+                        super.onBindViewHolder(holder, position);
+                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
+                                .getLayoutParams();
+                        if (position <= lastFocusableIndex) {
+                            holder.itemView.setFocusable(true);
+                            holder.itemView.setFocusableInTouchMode(true);
+                        } else {
+                            holder.itemView.setFocusable(false);
+                            holder.itemView.setFocusableInTouchMode(false);
+                        }
+                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
+                        lp.topMargin = 0;
+                        lp.leftMargin = 0;
+                        lp.rightMargin = 0;
+                        lp.bottomMargin = 0;
+                        if (position == 11) {
+                            lp.leftMargin = 9;
+                        }
+                    }
+                });
+
+        /**
+         * 0 3 6 7 8 9  11 12 15
+         * 1 4 6   8 10 11 13 16
+         * 2 5 6   8    11 14 17
+         */
+        mAdapter.mFullSpanItems.add(6);
+        mAdapter.mFullSpanItems.add(8);
+        mAdapter.mFullSpanItems.add(11);
+        waitFirstLayout();
+
+
+        // adapter position of the currently focused item.
+        int focusIndex = 1;
+        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
+                focusIndex);
+        View viewToFocus = toFocus.itemView;
+        assertTrue(requestFocus(viewToFocus, true));
+        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
+
+        // The VH of the unfocusable item that just became fully visible after focusSearch.
+        RecyclerView.ViewHolder toVisible = null;
+
+        View focusedView = viewToFocus;
+        int actualFocusIndex = -1;
+        // First, scroll until the last focusable column.
+        for (int i : new int[]{4, 6}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_RIGHT);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
+                    + actualFocusIndex, i, actualFocusIndex);
+        }
+
+        // Further scroll right in order to make the unfocusable rows visible. This process should
+        // continue until the currently focused item is still visible. The focused item should not
+        // change in this loop.
+        for (int i : new int[]{9, 11, 11, 11}) {
+            focusSearchAndWaitForScroll(focusedView, View.FOCUS_RIGHT);
+            focusedView = mRecyclerView.getFocusedChild();
+            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
+            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
+
+            assertEquals("Focused view should not be changed, whereas it's now at "
+                    + actualFocusIndex, 6, actualFocusIndex);
+            assertTrue("Focused child should be at least partially visible.",
+                    isViewPartiallyInBound(mRecyclerView, focusedView));
+            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
+                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
+        }
+    }
+
+    @Test
+    public void scrollToPositionWithPredictive() throws Throwable {
+        scrollToPositionWithPredictive(0, LinearLayoutManager.INVALID_OFFSET);
+        removeRecyclerView();
+        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2,
+                LinearLayoutManager.INVALID_OFFSET);
+        removeRecyclerView();
+        scrollToPositionWithPredictive(9, 20);
+        removeRecyclerView();
+        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2, 10);
+
+    }
+
+    public void scrollToPositionWithPredictive(final int scrollPosition, final int scrollOffset)
+            throws Throwable {
+        setupByConfig(new Config(StaggeredGridLayoutManager.VERTICAL,
+                false, 3, StaggeredGridLayoutManager.GAP_HANDLING_NONE));
+        waitFirstLayout();
+        mLayoutManager.mOnLayoutListener = new OnLayoutListener() {
+            @Override
+            void after(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                RecyclerView rv = mLayoutManager.mRecyclerView;
+                if (state.isPreLayout()) {
+                    assertEquals("pending scroll position should still be pending",
+                            scrollPosition, mLayoutManager.mPendingScrollPosition);
+                    if (scrollOffset != LinearLayoutManager.INVALID_OFFSET) {
+                        assertEquals("pending scroll position offset should still be pending",
+                                scrollOffset, mLayoutManager.mPendingScrollPositionOffset);
+                    }
+                } else {
+                    RecyclerView.ViewHolder vh = rv.findViewHolderForLayoutPosition(scrollPosition);
+                    assertNotNull("scroll to position should work", vh);
+                    if (scrollOffset != LinearLayoutManager.INVALID_OFFSET) {
+                        assertEquals("scroll offset should be applied properly",
+                                mLayoutManager.getPaddingTop() + scrollOffset
+                                        + ((RecyclerView.LayoutParams) vh.itemView
+                                        .getLayoutParams()).topMargin,
+                                mLayoutManager.getDecoratedTop(vh.itemView));
+                    }
+                }
+            }
+        };
+        mLayoutManager.expectLayouts(2);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    mAdapter.addAndNotify(0, 1);
+                    if (scrollOffset == LinearLayoutManager.INVALID_OFFSET) {
+                        mLayoutManager.scrollToPosition(scrollPosition);
+                    } else {
+                        mLayoutManager.scrollToPositionWithOffset(scrollPosition,
+                                scrollOffset);
+                    }
+
+                } catch (Throwable throwable) {
+                    throwable.printStackTrace();
+                }
+
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+    }
+
+    @Test
+    public void moveGapHandling() throws Throwable {
+        Config config = new Config().spanCount(2).itemCount(40);
+        setupByConfig(config);
+        waitFirstLayout();
+        mLayoutManager.expectLayouts(2);
+        mAdapter.moveAndNotify(4, 1);
+        mLayoutManager.waitForLayout(2);
+        assertNull("moving item to upper should not cause gaps", mLayoutManager.hasGapsToFix());
+    }
+
+    @Test
+    public void updateAfterFullSpan() throws Throwable {
+        updateAfterFullSpanGapHandlingTest(0);
+    }
+
+    @Test
+    public void updateAfterFullSpan2() throws Throwable {
+        updateAfterFullSpanGapHandlingTest(20);
+    }
+
+    @Test
+    public void temporaryGapHandling() throws Throwable {
+        int fullSpanIndex = 200;
+        setupByConfig(new Config().spanCount(2).itemCount(500));
+        mAdapter.mFullSpanItems.add(fullSpanIndex);
+        waitFirstLayout();
+        smoothScrollToPosition(fullSpanIndex + 200);// go far away
+        assertNull("test sanity. full span item should not be visible",
+                mRecyclerView.findViewHolderForAdapterPosition(fullSpanIndex));
+        mLayoutManager.expectLayouts(1);
+        mAdapter.deleteAndNotify(fullSpanIndex + 1, 3);
+        mLayoutManager.waitForLayout(1);
+        smoothScrollToPosition(0);
+        mLayoutManager.expectLayouts(1);
+        smoothScrollToPosition(fullSpanIndex + 2 * (AVG_ITEM_PER_VIEW - 1));
+        String log = mLayoutManager.layoutToString("post gap");
+        mLayoutManager.assertNoLayout("if an interim gap is fixed, it should not cause a "
+                + "relayout " + log, 2);
+        View fullSpan = mLayoutManager.findViewByPosition(fullSpanIndex);
+        assertNotNull("full span item should be there:\n" + log, fullSpan);
+        View view1 = mLayoutManager.findViewByPosition(fullSpanIndex + 1);
+        assertNotNull("next view should be there\n" + log, view1);
+        View view2 = mLayoutManager.findViewByPosition(fullSpanIndex + 2);
+        assertNotNull("+2 view should be there\n" + log, view2);
+
+        LayoutParams lp1 = (LayoutParams) view1.getLayoutParams();
+        LayoutParams lp2 = (LayoutParams) view2.getLayoutParams();
+        assertEquals("view 1 span index", 0, lp1.getSpanIndex());
+        assertEquals("view 2 span index", 1, lp2.getSpanIndex());
+        assertEquals("no gap between span and view 1",
+                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
+                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view1));
+        assertEquals("no gap between span and view 2",
+                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
+                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view2));
+    }
+
+    public void updateAfterFullSpanGapHandlingTest(int fullSpanIndex) throws Throwable {
+        setupByConfig(new Config().spanCount(2).itemCount(100));
+        mAdapter.mFullSpanItems.add(fullSpanIndex);
+        waitFirstLayout();
+        smoothScrollToPosition(fullSpanIndex + 30);
+        mLayoutManager.expectLayouts(1);
+        mAdapter.deleteAndNotify(fullSpanIndex + 1, 3);
+        mLayoutManager.waitForLayout(1);
+        smoothScrollToPosition(fullSpanIndex);
+        // give it some time to fix the gap
+        Thread.sleep(500);
+        View fullSpan = mLayoutManager.findViewByPosition(fullSpanIndex);
+
+        View view1 = mLayoutManager.findViewByPosition(fullSpanIndex + 1);
+        View view2 = mLayoutManager.findViewByPosition(fullSpanIndex + 2);
+
+        LayoutParams lp1 = (LayoutParams) view1.getLayoutParams();
+        LayoutParams lp2 = (LayoutParams) view2.getLayoutParams();
+        assertEquals("view 1 span index", 0, lp1.getSpanIndex());
+        assertEquals("view 2 span index", 1, lp2.getSpanIndex());
+        assertEquals("no gap between span and view 1",
+                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
+                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view1));
+        assertEquals("no gap between span and view 2",
+                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
+                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view2));
+    }
+
+    @Test
+    public void innerGapHandling() throws Throwable {
+        innerGapHandlingTest(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
+        innerGapHandlingTest(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
+    }
+
+    public void innerGapHandlingTest(int strategy) throws Throwable {
+        Config config = new Config().spanCount(3).itemCount(500);
+        setupByConfig(config);
+        mLayoutManager.setGapStrategy(strategy);
+        mAdapter.mFullSpanItems.add(100);
+        mAdapter.mFullSpanItems.add(104);
+        mAdapter.mViewsHaveEqualSize = true;
+        mAdapter.mOnBindCallback = new OnBindCallback() {
+            @Override
+            void onBoundItem(TestViewHolder vh, int position) {
+
+            }
+
+            @Override
+            void onCreatedViewHolder(TestViewHolder vh) {
+                super.onCreatedViewHolder(vh);
+                //make sure we have enough views
+                mAdapter.mSizeReference = mRecyclerView.getHeight() / 5;
+            }
+        };
+        waitFirstLayout();
+        mLayoutManager.expectLayouts(1);
+        scrollToPosition(400);
+        mLayoutManager.waitForLayout(2);
+        View view400 = mLayoutManager.findViewByPosition(400);
+        assertNotNull("test sanity, scrollToPos should succeed", view400);
+        assertTrue("test sanity, view should be visible top",
+                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view400) >=
+                        mLayoutManager.mPrimaryOrientation.getStartAfterPadding());
+        assertTrue("test sanity, view should be visible bottom",
+                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(view400) <=
+                        mLayoutManager.mPrimaryOrientation.getEndAfterPadding());
+        mLayoutManager.expectLayouts(2);
+        mAdapter.addAndNotify(101, 1);
+        mLayoutManager.waitForLayout(2);
+        checkForMainThreadException();
+        if (strategy == GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
+            mLayoutManager.expectLayouts(1);
+        }
+        // state
+        // now smooth scroll to 99 to trigger a layout around 100
+        mLayoutManager.validateChildren();
+        smoothScrollToPosition(99);
+        switch (strategy) {
+            case GAP_HANDLING_NONE:
+                assertSpans("gap handling:" + Config.gapStrategyName(strategy), new int[]{100, 0},
+                        new int[]{101, 2}, new int[]{102, 0}, new int[]{103, 1}, new int[]{104, 2},
+                        new int[]{105, 0});
+                break;
+            case GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS:
+                mLayoutManager.waitForLayout(2);
+                assertSpans("swap items between spans", new int[]{100, 0}, new int[]{101, 0},
+                        new int[]{102, 1}, new int[]{103, 2}, new int[]{104, 0}, new int[]{105, 0});
+                break;
+        }
+
+    }
+
+    @Test
+    public void fullSizeSpans() throws Throwable {
+        Config config = new Config().spanCount(5).itemCount(30);
+        setupByConfig(config);
+        mAdapter.mFullSpanItems.add(3);
+        waitFirstLayout();
+        assertSpans("Testing full size span", new int[]{0, 0}, new int[]{1, 1}, new int[]{2, 2},
+                new int[]{3, 0}, new int[]{4, 0}, new int[]{5, 1}, new int[]{6, 2},
+                new int[]{7, 3}, new int[]{8, 4});
+    }
+
+    void assertSpans(String msg, int[]... childSpanTuples) {
+        msg = msg + mLayoutManager.layoutToString("\n\n");
+        for (int i = 0; i < childSpanTuples.length; i++) {
+            assertSpan(msg, childSpanTuples[i][0], childSpanTuples[i][1]);
+        }
+    }
+
+    void assertSpan(String msg, int childPosition, int expectedSpan) {
+        View view = mLayoutManager.findViewByPosition(childPosition);
+        assertNotNull(msg + " view at position " + childPosition + " should exists", view);
+        assertEquals(msg + "[child:" + childPosition + "]", expectedSpan,
+                getLp(view).mSpan.mIndex);
+    }
+
+    @Test
+    public void partialSpanInvalidation() throws Throwable {
+        Config config = new Config().spanCount(5).itemCount(100);
+        setupByConfig(config);
+        for (int i = 20; i < mAdapter.getItemCount(); i += 20) {
+            mAdapter.mFullSpanItems.add(i);
+        }
+        waitFirstLayout();
+        smoothScrollToPosition(50);
+        int prevSpanId = mLayoutManager.mLazySpanLookup.mData[30];
+        mAdapter.changeAndNotify(15, 2);
+        Thread.sleep(200);
+        assertEquals("Invalidation should happen within full span item boundaries", prevSpanId,
+                mLayoutManager.mLazySpanLookup.mData[30]);
+        assertEquals("item in invalidated range should have clear span id",
+                LayoutParams.INVALID_SPAN_ID, mLayoutManager.mLazySpanLookup.mData[16]);
+        smoothScrollToPosition(85);
+        int[] prevSpans = copyOfRange(mLayoutManager.mLazySpanLookup.mData, 62, 85);
+        mAdapter.deleteAndNotify(55, 2);
+        Thread.sleep(200);
+        assertEquals("item in invalidated range should have clear span id",
+                LayoutParams.INVALID_SPAN_ID, mLayoutManager.mLazySpanLookup.mData[16]);
+        int[] newSpans = copyOfRange(mLayoutManager.mLazySpanLookup.mData, 60, 83);
+        assertSpanAssignmentEquality("valid spans should be shifted for deleted item", prevSpans,
+                newSpans, 0, 0, newSpans.length);
+    }
+
+    // Same as Arrays.copyOfRange but for API 7
+    private int[] copyOfRange(int[] original, int from, int to) {
+        int newLength = to - from;
+        if (newLength < 0) {
+            throw new IllegalArgumentException(from + " > " + to);
+        }
+        int[] copy = new int[newLength];
+        System.arraycopy(original, from, copy, 0,
+                Math.min(original.length - from, newLength));
+        return copy;
+    }
+
+    @Test
+    public void spanReassignmentsOnItemChange() throws Throwable {
+        Config config = new Config().spanCount(5);
+        setupByConfig(config);
+        waitFirstLayout();
+        smoothScrollToPosition(mAdapter.getItemCount() / 2);
+        final int changePosition = mAdapter.getItemCount() / 4;
+        mLayoutManager.expectLayouts(1);
+        if (RecyclerView.POST_UPDATES_ON_ANIMATION) {
+            mAdapter.changeAndNotify(changePosition, 1);
+            mLayoutManager.assertNoLayout("no layout should happen when an invisible child is "
+                    + "updated", 1);
+        } else {
+            mAdapter.changeAndNotify(changePosition, 1);
+            mLayoutManager.waitForLayout(1);
+        }
+
+        // delete an item before visible area
+        int deletedPosition = mLayoutManager.getPosition(mLayoutManager.getChildAt(0)) - 2;
+        assertTrue("test sanity", deletedPosition >= 0);
+        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
+        if (DEBUG) {
+            Log.d(TAG, "before:");
+            for (Map.Entry<Item, Rect> entry : before.entrySet()) {
+                Log.d(TAG, entry.getKey().mAdapterIndex + ":" + entry.getValue());
+            }
+        }
+        mLayoutManager.expectLayouts(1);
+        mAdapter.deleteAndNotify(deletedPosition, 1);
+        mLayoutManager.waitForLayout(2);
+        assertRectSetsEqual(config + " when an item towards the head of the list is deleted, it "
+                        + "should not affect the layout if it is not visible", before,
+                mLayoutManager.collectChildCoordinates()
+        );
+        deletedPosition = mLayoutManager.getPosition(mLayoutManager.getChildAt(2));
+        mLayoutManager.expectLayouts(1);
+        mAdapter.deleteAndNotify(deletedPosition, 1);
+        mLayoutManager.waitForLayout(2);
+        assertRectSetsNotEqual(config + " when a visible item is deleted, it should affect the "
+                + "layout", before, mLayoutManager.collectChildCoordinates());
+    }
+
+    void assertSpanAssignmentEquality(String msg, int[] set1, int[] set2, int start1, int start2,
+            int length) {
+        for (int i = 0; i < length; i++) {
+            assertEquals(msg + " ind1:" + (start1 + i) + ", ind2:" + (start2 + i), set1[start1 + i],
+                    set2[start2 + i]);
+        }
+    }
+
+    @Test
+    public void spanCountChangeOnRestoreSavedState() throws Throwable {
+        Config config = new Config(HORIZONTAL, true, 5, GAP_HANDLING_NONE).itemCount(50);
+        setupByConfig(config);
+        waitFirstLayout();
+
+        int beforeChildCount = mLayoutManager.getChildCount();
+        Parcelable savedState = mRecyclerView.onSaveInstanceState();
+        // we append a suffix to the parcelable to test out of bounds
+        String parcelSuffix = UUID.randomUUID().toString();
+        Parcel parcel = Parcel.obtain();
+        savedState.writeToParcel(parcel, 0);
+        parcel.writeString(parcelSuffix);
+        removeRecyclerView();
+        // reset for reading
+        parcel.setDataPosition(0);
+        // re-create
+        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
+        removeRecyclerView();
+
+        RecyclerView restored = new RecyclerView(getActivity());
+        mLayoutManager = new WrappedLayoutManager(config.mSpanCount, config.mOrientation);
+        mLayoutManager.setReverseLayout(config.mReverseLayout);
+        mLayoutManager.setGapStrategy(config.mGapStrategy);
+        restored.setLayoutManager(mLayoutManager);
+        // use the same adapter for Rect matching
+        restored.setAdapter(mAdapter);
+        restored.onRestoreInstanceState(savedState);
+        mLayoutManager.setSpanCount(1);
+        mLayoutManager.expectLayouts(1);
+        setRecyclerView(restored);
+        mLayoutManager.waitForLayout(2);
+        assertEquals("on saved state, reverse layout should be preserved",
+                config.mReverseLayout, mLayoutManager.getReverseLayout());
+        assertEquals("on saved state, orientation should be preserved",
+                config.mOrientation, mLayoutManager.getOrientation());
+        assertEquals("after setting new span count, layout manager should keep new value",
+                1, mLayoutManager.getSpanCount());
+        assertEquals("on saved state, gap strategy should be preserved",
+                config.mGapStrategy, mLayoutManager.getGapStrategy());
+        assertTrue("when span count is dramatically changed after restore, # of child views "
+                + "should change", beforeChildCount > mLayoutManager.getChildCount());
+        // make sure SGLM can layout all children. is some span info is leaked, this would crash
+        smoothScrollToPosition(mAdapter.getItemCount() - 1);
+    }
+
+    @Test
+    public void scrollAndClear() throws Throwable {
+        setupByConfig(new Config());
+        waitFirstLayout();
+
+        assertTrue("Children not laid out", mLayoutManager.collectChildCoordinates().size() > 0);
+
+        mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mLayoutManager.scrollToPositionWithOffset(1, 0);
+                mAdapter.clearOnUIThread();
+            }
+        });
+        mLayoutManager.waitForLayout(2);
+
+        assertEquals("Remaining children", 0, mLayoutManager.collectChildCoordinates().size());
+    }
+
+    @Test
+    public void accessibilityPositions() throws Throwable {
+        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_NONE));
+        waitFirstLayout();
+        final AccessibilityDelegateCompat delegateCompat = mRecyclerView
+                .getCompatAccessibilityDelegate();
+        final AccessibilityEvent event = AccessibilityEvent.obtain();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                delegateCompat.onInitializeAccessibilityEvent(mRecyclerView, event);
+            }
+        });
+        final int start = mRecyclerView
+                .getChildLayoutPosition(
+                        mLayoutManager.findFirstVisibleItemClosestToStart(false));
+        final int end = mRecyclerView
+                .getChildLayoutPosition(
+                        mLayoutManager.findFirstVisibleItemClosestToEnd(false));
+        assertEquals("first item position should match",
+                Math.min(start, end), event.getFromIndex());
+        assertEquals("last item position should match",
+                Math.max(start, end), event.getToIndex());
+
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/StaggeredGridLayoutManagerWrapContentTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/TestActivity.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestActivity.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/TestActivity.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestActivity.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
new file mode 100644
index 0000000..6f99f35
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static android.view.View.MeasureSpec.AT_MOST;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.test.filters.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests whether the layout manager can keep its children positions properly after it is re-laid
+ * out with larger/smaller intermediate size but the same final size.
+ */
+@MediumTest
+@RunWith(Parameterized.class)
+public class TestResizingRelayoutWithAutoMeasure extends BaseRecyclerViewInstrumentationTest {
+    private final int mRvWidth;
+    private final int mRvHeight;
+    private final RecyclerView.LayoutManager mLayoutManager;
+    private final float mWidthMultiplier;
+    private final float mHeightMultiplier;
+
+    public TestResizingRelayoutWithAutoMeasure(@SuppressWarnings("UnusedParameters") String name,
+            int rvWidth, int rvHeight,
+            RecyclerView.LayoutManager layoutManager, float widthMultiplier,
+            float heightMultiplier) {
+        mRvWidth = rvWidth;
+        mRvHeight = rvHeight;
+        mLayoutManager = layoutManager;
+        mWidthMultiplier = widthMultiplier;
+        mHeightMultiplier = heightMultiplier;
+    }
+
+    @Parameterized.Parameters(name = "{0} rv w/h:{1}/{2} changed w/h:{4}/{5}")
+    public static List<Object[]> getParams() {
+        List<Object[]> params = new ArrayList<>();
+        for(int[] rvSize : new int[][]{new int[]{200, 200}, new int[]{200, 100},
+                new int[]{100, 200}}) {
+            for (float w : new float[]{.5f, 1f, 2f}) {
+                for (float h : new float[]{.5f, 1f, 2f}) {
+                    params.add(
+                            new Object[]{"linear layout", rvSize[0], rvSize[1],
+                                    new LinearLayoutManager(null), w, h}
+                    );
+                    params.add(
+                            new Object[]{"grid layout", rvSize[0], rvSize[1],
+                                    new GridLayoutManager(null, 3), w, h}
+                    );
+                    params.add(
+                            new Object[]{"staggered", rvSize[0], rvSize[1],
+                                    new StaggeredGridLayoutManager(3,
+                                    StaggeredGridLayoutManager.VERTICAL), w, h}
+                    );
+                }
+            }
+        }
+        return params;
+    }
+
+    @Test
+    public void testResizeDuringMeasurements() throws Throwable {
+        final WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity());
+        recyclerView.setLayoutManager(mLayoutManager);
+        StaticAdapter adapter = new StaticAdapter(50, ViewGroup.LayoutParams.MATCH_PARENT,
+                mRvHeight / 5);
+        recyclerView.setLayoutParams(new FrameLayout.LayoutParams(mRvWidth, mRvHeight));
+        recyclerView.setAdapter(adapter);
+        setRecyclerView(recyclerView);
+        getInstrumentation().waitForIdleSync();
+        assertThat("Test sanity", recyclerView.getChildCount() > 0, is(true));
+        final int lastPosition = recyclerView.getAdapter().getItemCount() - 1;
+        smoothScrollToPosition(lastPosition);
+        assertThat("test sanity", recyclerView.findViewHolderForAdapterPosition(lastPosition),
+                notNullValue());
+        assertThat("test sanity", mRvWidth, is(recyclerView.getWidth()));
+        assertThat("test sanity", mRvHeight, is(recyclerView.getHeight()));
+        recyclerView.waitUntilLayout();
+        recyclerView.waitUntilAnimations();
+        final Map<Integer, Rect> startPositions = capturePositions(recyclerView);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                recyclerView.measure(
+                        makeMeasureSpec((int) (mRvWidth * mWidthMultiplier),
+                                mWidthMultiplier == 1f ? EXACTLY : AT_MOST),
+                        makeMeasureSpec((int) (mRvHeight * mHeightMultiplier),
+                                mHeightMultiplier == 1f ? EXACTLY : AT_MOST));
+
+                recyclerView.measure(
+                        makeMeasureSpec(mRvWidth, EXACTLY),
+                        makeMeasureSpec(mRvHeight, EXACTLY));
+                recyclerView.dispatchLayout();
+                Map<Integer, Rect> endPositions = capturePositions(recyclerView);
+                assertStartItemPositions(startPositions, endPositions);
+            }
+        });
+        recyclerView.waitUntilLayout();
+        recyclerView.waitUntilAnimations();
+        checkForMainThreadException();
+    }
+
+    private void assertStartItemPositions(Map<Integer, Rect> startPositions,
+            Map<Integer, Rect> endPositions) {
+        String log = log(startPositions, endPositions);
+        for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
+            Rect rect = endPositions.get(entry.getKey());
+            assertThat(log + "view for position " + entry.getKey() + " at" + entry.getValue(), rect,
+                    notNullValue());
+            assertThat(log + "rect for position " + entry.getKey(), entry.getValue(), is(rect));
+        }
+    }
+
+    @NonNull
+    private String log(Map<Integer, Rect> startPositions, Map<Integer, Rect> endPositions) {
+        StringBuilder logBuilder = new StringBuilder();
+        for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
+            logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
+        }
+        logBuilder.append("------\n");
+        for (Map.Entry<Integer, Rect> entry : endPositions.entrySet()) {
+            logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
+        }
+        return logBuilder.toString();
+    }
+
+    private Map<Integer, Rect> capturePositions(RecyclerView recyclerView) {
+        Map<Integer, Rect> positions = new HashMap<>();
+        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
+            View view = mLayoutManager.getChildAt(i);
+            int childAdapterPosition = recyclerView.getChildAdapterPosition(view);
+            Rect outRect = new Rect();
+            mLayoutManager.getDecoratedBoundsWithMargins(view, outRect);
+            // only record if outRect is visible
+            if (outRect.left >= mRecyclerView.getWidth() ||
+                    outRect.top >= mRecyclerView.getHeight() ||
+                    outRect.right < 0 ||
+                    outRect.bottom < 0) {
+                continue;
+            }
+            positions.put(childAdapterPosition, outRect);
+        }
+        return positions;
+    }
+
+    private class StaticAdapter extends RecyclerView.Adapter<TestViewHolder> {
+        final int mSize;
+        // is passed to the layout params of the item
+        final int mMinItemWidth;
+        final int mMinItemHeight;
+
+        public StaticAdapter(int size, int minItemWidth, int minItemHeight) {
+            mSize = size;
+            mMinItemWidth = minItemWidth;
+            mMinItemHeight = minItemHeight;
+        }
+
+        @Override
+        public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                int viewType) {
+            return new TestViewHolder(new View(parent.getContext()));
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull TestViewHolder holder, int position) {
+            holder.mBoundItem = new Item(position, "none");
+            if (mMinItemHeight < 1 && mMinItemWidth < 1) {
+                return;
+            }
+            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
+            if (lp == null) {
+                lp = new ViewGroup.LayoutParams(0, 0);
+            }
+            if (mMinItemWidth > 0) {
+                lp.width = (int) (mMinItemWidth + (position % 10) * mMinItemWidth / 7f);
+            } else {
+                lp.width = mMinItemWidth;
+            }
+
+            if (mMinItemHeight > 0) {
+                lp.height = (int) (mMinItemHeight + (position % 10) * mMinItemHeight / 7f);
+            } else {
+                lp.height = mMinItemHeight;
+            }
+            holder.itemView.setLayoutParams(lp);
+        }
+
+        @Override
+        public int getItemCount() {
+            return mSize;
+        }
+    }
+}
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestedFrameLayout.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestedFrameLayout.java
new file mode 100644
index 0000000..bc48167
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/TestedFrameLayout.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static junit.framework.Assert.assertTrue;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.support.annotation.NonNull;
+import android.support.v4.view.NestedScrollingParent2;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TestedFrameLayout extends FrameLayout implements NestedScrollingParent2 {
+
+    private NestedScrollingParent2 mNestedScrollingDelegate;
+    private CountDownLatch mDrawLatch;
+    private CountDownLatch mLayoutLatch;
+
+    public TestedFrameLayout(Context context) {
+        super(context);
+        setWillNotDraw(false);
+    }
+
+    public void expectDraws(int count) {
+        mDrawLatch = new CountDownLatch(count);
+    }
+
+    public void waitForDraw(int seconds) throws InterruptedException {
+        assertTrue(mDrawLatch.await(seconds, TimeUnit.SECONDS));
+    }
+
+    public void expectLayouts(int count) {
+        mLayoutLatch = new CountDownLatch(count);
+    }
+
+    public void waitForLayout(int seconds) throws InterruptedException {
+        assertTrue(mLayoutLatch.await(seconds, TimeUnit.SECONDS));
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        RecyclerView recyclerView = getRvChild();
+        if (recyclerView == null) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+        FullControlLayoutParams lp = (FullControlLayoutParams) recyclerView.getLayoutParams();
+        if (lp.wSpec == null && lp.hSpec == null) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
+        }
+        final int childWidthMeasureSpec;
+        if (lp.wSpec != null) {
+            childWidthMeasureSpec = lp.wSpec;
+        } else if (lp.width == LayoutParams.MATCH_PARENT) {
+            final int width = Math.max(0, getMeasuredWidth()
+                    - lp.leftMargin - lp.rightMargin);
+            childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
+        } else {
+            childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                    lp.leftMargin + lp.rightMargin, lp.width);
+        }
+
+        final int childHeightMeasureSpec;
+        if (lp.hSpec != null) {
+            childHeightMeasureSpec = lp.hSpec;
+        } else if (lp.height == LayoutParams.MATCH_PARENT) {
+            final int height = Math.max(0, getMeasuredHeight()
+                    - lp.topMargin - lp.bottomMargin);
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+        } else {
+            childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+                    lp.topMargin + lp.bottomMargin, lp.height);
+        }
+        recyclerView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY &&
+                MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
+            setMeasuredDimension(
+                    MeasureSpec.getSize(widthMeasureSpec),
+                    MeasureSpec.getSize(heightMeasureSpec)
+            );
+        } else {
+            setMeasuredDimension(
+                    chooseSize(widthMeasureSpec,
+                            recyclerView.getWidth() + getPaddingLeft() + getPaddingRight(),
+                            getMinimumWidth()),
+                    chooseSize(heightMeasureSpec,
+                            recyclerView.getHeight() + getPaddingTop() + getPaddingBottom(),
+                            getMinimumHeight()));
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        if (mLayoutLatch != null) {
+            mLayoutLatch.countDown();
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas c) {
+        super.onDraw(c);
+        if (mDrawLatch != null) {
+            mDrawLatch.countDown();
+        }
+    }
+
+    public static int chooseSize(int spec, int desired, int min) {
+        final int mode = View.MeasureSpec.getMode(spec);
+        final int size = View.MeasureSpec.getSize(spec);
+        switch (mode) {
+            case View.MeasureSpec.EXACTLY:
+                return size;
+            case View.MeasureSpec.AT_MOST:
+                return Math.min(size, desired);
+            case View.MeasureSpec.UNSPECIFIED:
+            default:
+                return Math.max(desired, min);
+        }
+    }
+
+    private RecyclerView getRvChild() {
+        for (int i = 0; i < getChildCount(); i++) {
+            if (getChildAt(i) instanceof RecyclerView) {
+                return (RecyclerView) getChildAt(i);
+            }
+        }
+        return null;
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p instanceof FullControlLayoutParams;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        return new FullControlLayoutParams(p);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new FullControlLayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        return new FullControlLayoutParams(getWidth(), getHeight());
+    }
+
+    @Override
+    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
+        return onStartNestedScroll(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onNestedScrollAccepted(View child, View target, int axes) {
+        onNestedScrollAccepted(child, target, axes, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
+        onNestedPreScroll(target, dx, dy, consumed, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
+            int dyUnconsumed) {
+        onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
+                ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public void onStopNestedScroll(View target) {
+        onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
+    }
+
+    @Override
+    public int getNestedScrollAxes() {
+        return mNestedScrollingDelegate != null
+                ? mNestedScrollingDelegate.getNestedScrollAxes()
+                : 0;
+    }
+
+    @Override
+    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target,
+            @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
+        return mNestedScrollingDelegate != null
+                && mNestedScrollingDelegate.onStartNestedScroll(child, target, axes, type);
+    }
+
+    @Override
+    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target,
+            @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
+        if (mNestedScrollingDelegate != null) {
+            mNestedScrollingDelegate.onNestedScrollAccepted(child, target, axes, type);
+        }
+    }
+
+    @Override
+    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
+        return mNestedScrollingDelegate != null
+                && mNestedScrollingDelegate.onNestedPreFling(target, velocityX, velocityY);
+    }
+
+    @Override
+    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
+        return mNestedScrollingDelegate != null
+                && mNestedScrollingDelegate.onNestedFling(target, velocityX, velocityY, consumed);
+    }
+
+    @Override
+    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
+            int dxUnconsumed, int dyUnconsumed, @ViewCompat.NestedScrollType int type) {
+        if (mNestedScrollingDelegate != null) {
+            mNestedScrollingDelegate.onNestedScroll(target, dxConsumed, dyConsumed,
+                    dxUnconsumed, dyUnconsumed, type);
+        }
+    }
+
+    @Override
+    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed,
+            @ViewCompat.NestedScrollType int type) {
+        if (mNestedScrollingDelegate != null) {
+            mNestedScrollingDelegate.onNestedPreScroll(target, dx, dy, consumed, type);
+        }
+    }
+
+    @Override
+    public void onStopNestedScroll(@NonNull View target, @ViewCompat.NestedScrollType int type) {
+        if (mNestedScrollingDelegate != null) {
+            mNestedScrollingDelegate.onStopNestedScroll(target, type);
+        }
+    }
+
+    public void setNestedScrollingDelegate(NestedScrollingParent2 delegate) {
+        mNestedScrollingDelegate = delegate;
+    }
+
+    public static class FullControlLayoutParams extends FrameLayout.LayoutParams {
+
+        Integer wSpec;
+        Integer hSpec;
+
+        public FullControlLayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+
+        public FullControlLayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public FullControlLayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public FullControlLayoutParams(FrameLayout.LayoutParams source) {
+            super(source);
+        }
+
+        public FullControlLayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ViewBoundsCheckTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/ViewBoundsCheckTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/ViewBoundsCheckTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/ViewBoundsCheckTest.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/WrapContentBasicTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/WrapContentBasicTest.java
new file mode 100644
index 0000000..00d332a
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/WrapContentBasicTest.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WrapContentBasicTest {
+    private Context mContext;
+    private WrapContentLayoutManager mLayoutManager;
+    private RecyclerView mRecyclerView;
+    private WrapAdapter mAdapter;
+    private static int WRAP = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.AT_MOST);
+    private static int EXACT = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.EXACTLY);
+    private static int UNSPECIFIED = View.MeasureSpec
+            .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
+
+    @Before
+    public void setup() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        mRecyclerView = new RecyclerView(mContext);
+        mLayoutManager = spy(new WrapContentLayoutManager());
+        // working around a mockito issue
+        mRecyclerView.setLayoutManager(mLayoutManager);
+        mAdapter = spy(new WrapAdapter());
+        mRecyclerView.setAdapter(mAdapter);
+    }
+
+    @Test
+    public void testLayoutInOnMeasureWithoutPredictive() {
+        when(mLayoutManager.supportsPredictiveItemAnimations()).thenReturn(false);
+        mRecyclerView.onMeasure(WRAP, WRAP);
+        mRecyclerView.onMeasure(WRAP, WRAP);
+        mRecyclerView.onLayout(true, 0, 10, 10, 10);
+        verify(mLayoutManager, times(3))
+                .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState);
+    }
+
+    @Test
+    public void dataChangeAfterMeasure() {
+        mRecyclerView.onMeasure(WRAP, WRAP);
+        mRecyclerView.onMeasure(WRAP, WRAP);
+        mAdapter.notifyItemChanged(1);
+        mRecyclerView.onLayout(true, 0, 10, 10, 10);
+        verify(mLayoutManager, times(3))
+                .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState);
+    }
+
+    @Test
+    public void setDimensionsFromChildren() {
+        View[] children = createMockChildren(3);
+        mLayoutManager.setMeasuredDimensionFromChildren(WRAP, WRAP);
+        verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(),
+                children[0].getHeight());
+    }
+
+    @Test
+    public void setDimensionsFromChildrenAnsSpec1() {
+        View[] children = createMockChildren(3);
+        int hSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY);
+        mLayoutManager.setMeasuredDimensionFromChildren(WRAP, hSpec);
+        verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(), 111);
+    }
+
+    @Test
+    public void setDimensionsFromChildrenAnsSpec2() {
+        View[] children = createMockChildren(3);
+        int wSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY);
+        mLayoutManager.setMeasuredDimensionFromChildren(wSpec, WRAP);
+        verify(mLayoutManager).setMeasuredDimension(111, children[0].getHeight());
+    }
+
+    @Test
+    public void setDimensionsFromChildrenAnsSpec3() {
+        View[] children = createMockChildren(3);
+        children[0].layout(0, 0, 100, 100);
+        children[1].layout(-5, 0, 100, 100);
+        children[2].layout(-5, -10, 100, 100);
+        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
+        verify(mLayoutManager).setMeasuredDimension(105, 110);
+    }
+
+    @Test
+    public void setDimensionsFromChildrenAnsSpec4() {
+        View[] children = createMockChildren(3);
+        children[0].layout(0, 0, 100, 100);
+        children[1].layout(-5, 0, 100, 100);
+        children[2].layout(-5, -10, 100, 100);
+        int atMost = View.MeasureSpec.makeMeasureSpec(95, View.MeasureSpec.AT_MOST);
+        mLayoutManager.setMeasuredDimensionFromChildren(atMost, atMost);
+        verify(mLayoutManager).setMeasuredDimension(95, 95);
+    }
+
+    @Test
+    public void setDimensionsFromChildrenAnsSpec5() {
+        View[] children = createMockChildren(3);
+        children[0].layout(0, 0, 100, 100);
+        children[1].layout(-5, 0, 100, 100);
+        children[2].layout(-5, -10, 100, 100);
+        mRecyclerView.setMinimumWidth(250);
+        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
+        verify(mLayoutManager).setMeasuredDimension(250, 110);
+
+        mRecyclerView.setMinimumWidth(5);
+        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
+        verify(mLayoutManager).setMeasuredDimension(105, 110);
+    }
+
+    @Test
+    public void setDimensionsFromChildrenAnsSpec6() {
+        View[] children = createMockChildren(3);
+        children[0].layout(0, 0, 100, 100);
+        children[1].layout(-5, 0, 100, 100);
+        children[2].layout(-5, -10, 100, 100);
+        mRecyclerView.setMinimumHeight(250);
+        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
+        verify(mLayoutManager).setMeasuredDimension(105, 250);
+
+        mRecyclerView.setMinimumHeight(50);
+        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
+        verify(mLayoutManager).setMeasuredDimension(105, 110);
+    }
+
+    private View[] createMockChildren(int count) {
+        View[] views = new View[count];
+        for (int i = 0; i < count; i++) {
+            View v = new View(mContext);
+            v.setLayoutParams(new RecyclerView.LayoutParams(1, 1));
+            views[i] = v;
+            when(mLayoutManager.getChildAt(i)).thenReturn(v);
+        }
+        when(mLayoutManager.getChildCount()).thenReturn(3);
+        return views;
+    }
+
+    public class WrapContentLayoutManager extends RecyclerView.LayoutManager {
+
+        @Override
+        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+
+        }
+
+        @Override
+        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+
+        @Override
+        public boolean isAutoMeasureEnabled() {
+            return true;
+        }
+
+        // START MOCKITO OVERRIDES
+        // We override package protected methods to make them public. This is necessary to run
+        // mockito on Kitkat
+        @Override
+        public void setRecyclerView(RecyclerView recyclerView) {
+            super.setRecyclerView(recyclerView);
+        }
+
+        @Override
+        public void dispatchAttachedToWindow(RecyclerView view) {
+            super.dispatchAttachedToWindow(view);
+        }
+
+        @Override
+        public void dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
+            super.dispatchDetachedFromWindow(view, recycler);
+        }
+
+        @Override
+        public void setExactMeasureSpecsFrom(RecyclerView recyclerView) {
+            super.setExactMeasureSpecsFrom(recyclerView);
+        }
+
+        @Override
+        public void setMeasureSpecs(int wSpec, int hSpec) {
+            super.setMeasureSpecs(wSpec, hSpec);
+        }
+
+        @Override
+        public void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
+            super.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
+        }
+
+        @Override
+        public boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec,
+                RecyclerView.LayoutParams lp) {
+            return super.shouldReMeasureChild(child, widthSpec, heightSpec, lp);
+        }
+
+        @Override
+        public boolean shouldMeasureChild(View child, int widthSpec, int heightSpec,
+                RecyclerView.LayoutParams lp) {
+            return super.shouldMeasureChild(child, widthSpec, heightSpec, lp);
+        }
+
+        @Override
+        public void removeAndRecycleScrapInt(RecyclerView.Recycler recycler) {
+            super.removeAndRecycleScrapInt(recycler);
+        }
+
+        @Override
+        public void stopSmoothScroller() {
+            super.stopSmoothScroller();
+        }
+
+        @Override
+        public boolean shouldMeasureTwice() {
+            return super.shouldMeasureTwice();
+        }
+
+        // END MOCKITO OVERRIDES
+    }
+
+    public class WrapAdapter extends RecyclerView.Adapter {
+
+        @Override
+        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return null;
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+
+        }
+
+        @Override
+        public int getItemCount() {
+            return 10;
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/WrappedRecyclerView.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/WrappedRecyclerView.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/WrappedRecyclerView.java
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
new file mode 100644
index 0000000..99d1066
--- /dev/null
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v7.widget.helper;
+
+import static android.support.v7.widget.helper.ItemTouchHelper.END;
+import static android.support.v7.widget.helper.ItemTouchHelper.LEFT;
+import static android.support.v7.widget.helper.ItemTouchHelper.RIGHT;
+import static android.support.v7.widget.helper.ItemTouchHelper.START;
+import static android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.Suppress;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.testutils.PollingCheck;
+import android.support.v4.util.Pair;
+import android.support.v7.util.TouchUtils;
+import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.WrappedRecyclerView;
+import android.view.Gravity;
+import android.view.View;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class ItemTouchHelperTest extends BaseRecyclerViewInstrumentationTest {
+
+    private static class RecyclerViewState {
+        public TestAdapter mAdapter;
+        public TestLayoutManager mLayoutManager;
+        public WrappedRecyclerView mWrappedRecyclerView;
+    }
+
+    private LoggingCalback mCalback;
+
+    private LoggingItemTouchHelper mItemTouchHelper;
+
+    private Boolean mSetupRTL;
+
+    public ItemTouchHelperTest() {
+        super(false);
+    }
+
+    private RecyclerViewState setupRecyclerView() throws Throwable {
+        RecyclerViewState rvs = new RecyclerViewState();
+        rvs.mWrappedRecyclerView = inflateWrappedRV();
+        rvs.mAdapter = new TestAdapter(10);
+        rvs.mLayoutManager = new TestLayoutManager() {
+            @Override
+            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+                detachAndScrapAttachedViews(recycler);
+                layoutRange(recycler, 0, Math.min(5, state.getItemCount()));
+                layoutLatch.countDown();
+            }
+
+            @Override
+            public boolean canScrollHorizontally() {
+                return false;
+            }
+
+            @Override
+            public boolean supportsPredictiveItemAnimations() {
+                return false;
+            }
+        };
+        rvs.mWrappedRecyclerView.setFakeRTL(mSetupRTL);
+        rvs.mWrappedRecyclerView.setAdapter(rvs.mAdapter);
+        rvs.mWrappedRecyclerView.setLayoutManager(rvs.mLayoutManager);
+        return rvs;
+    }
+
+    private RecyclerViewState setupItemTouchHelper(final RecyclerViewState rvs, int dragDirs,
+            int swipeDirs) throws Throwable {
+        mCalback = new LoggingCalback(dragDirs, swipeDirs);
+        mItemTouchHelper = new LoggingItemTouchHelper(mCalback);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mItemTouchHelper.attachToRecyclerView(rvs.mWrappedRecyclerView);
+            }
+        });
+
+        return rvs;
+    }
+
+    @Test
+    public void swipeLeft() throws Throwable {
+        basicSwipeTest(LEFT, LEFT | RIGHT, -getActivity().getWindow().getDecorView().getWidth());
+    }
+
+    @Test
+    public void swipeRight() throws Throwable {
+        basicSwipeTest(RIGHT, LEFT | RIGHT, getActivity().getWindow().getDecorView().getWidth());
+    }
+
+    @Test
+    public void swipeStart() throws Throwable {
+        basicSwipeTest(START, START | END, -getActivity().getWindow().getDecorView().getWidth());
+    }
+
+    @Test
+    public void swipeEnd() throws Throwable {
+        basicSwipeTest(END, START | END, getActivity().getWindow().getDecorView().getWidth());
+    }
+
+    // Test is disabled as it is flaky.
+    @Suppress
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
+    @Test
+    public void swipeStartInRTL() throws Throwable {
+        mSetupRTL = true;
+        basicSwipeTest(START, START | END, getActivity().getWindow().getDecorView().getWidth());
+    }
+
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
+    @Test
+    public void swipeEndInRTL() throws Throwable {
+        mSetupRTL = true;
+        basicSwipeTest(END, START | END, -getActivity().getWindow().getDecorView().getWidth());
+    }
+
+    @Test
+    public void attachToNullRecycleViewDuringLongPress() throws Throwable {
+        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
+        rvs.mLayoutManager.expectLayouts(1);
+        setRecyclerView(rvs.mWrappedRecyclerView);
+        rvs.mLayoutManager.waitForLayout(1);
+
+        final RecyclerView.ViewHolder target = mRecyclerView
+                .findViewHolderForAdapterPosition(1);
+        target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                mItemTouchHelper.attachToRecyclerView(null);
+                return false;
+            }
+        });
+        TouchUtils.longClickView(getInstrumentation(), target.itemView);
+    }
+
+    @Test
+    public void attachToAnotherRecycleViewDuringLongPress() throws Throwable {
+        final RecyclerViewState rvs2 = setupRecyclerView();
+        rvs2.mLayoutManager.expectLayouts(1);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                getActivity().getContainer().addView(rvs2.mWrappedRecyclerView);
+            }
+        });
+        rvs2.mLayoutManager.waitForLayout(1);
+
+        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
+        rvs.mLayoutManager.expectLayouts(1);
+        setRecyclerView(rvs.mWrappedRecyclerView);
+        rvs.mLayoutManager.waitForLayout(1);
+
+        final RecyclerView.ViewHolder target = mRecyclerView
+                .findViewHolderForAdapterPosition(1);
+        target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                mItemTouchHelper.attachToRecyclerView(rvs2.mWrappedRecyclerView);
+                return false;
+            }
+        });
+        TouchUtils.longClickView(getInstrumentation(), target.itemView);
+        assertEquals(0, mCalback.mHasDragFlag.size());
+    }
+
+    public void basicSwipeTest(int dir, int swipeDirs, int targetX) throws Throwable {
+        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), 0, swipeDirs);
+        rvs.mLayoutManager.expectLayouts(1);
+        setRecyclerView(rvs.mWrappedRecyclerView);
+        rvs.mLayoutManager.waitForLayout(1);
+
+        final RecyclerView.ViewHolder target = mRecyclerView
+                .findViewHolderForAdapterPosition(1);
+        TouchUtils.dragViewToX(getInstrumentation(), target.itemView, Gravity.CENTER, targetX);
+
+        PollingCheck.waitFor(1000, new PollingCheck.PollingCheckCondition() {
+            @Override
+            public boolean canProceed() {
+                return mCalback.getSwipe(target) != null;
+            }
+        });
+        final SwipeRecord swipe = mCalback.getSwipe(target);
+        assertNotNull(swipe);
+        assertEquals(dir, swipe.dir);
+        assertEquals(1, mItemTouchHelper.mRecoverAnimations.size());
+        assertEquals(1, mItemTouchHelper.mPendingCleanup.size());
+        // get rid of the view
+        rvs.mLayoutManager.expectLayouts(1);
+        rvs.mAdapter.deleteAndNotify(1, 1);
+        rvs.mLayoutManager.waitForLayout(1);
+        waitForAnimations();
+        assertEquals(0, mItemTouchHelper.mRecoverAnimations.size());
+        assertEquals(0, mItemTouchHelper.mPendingCleanup.size());
+        assertTrue(mCalback.isCleared(target));
+    }
+
+    private void waitForAnimations() throws InterruptedException {
+        while (mRecyclerView.getItemAnimator().isRunning()) {
+            Thread.sleep(100);
+        }
+    }
+
+    private static class LoggingCalback extends SimpleCallback {
+
+        private List<MoveRecord> mMoveRecordList = new ArrayList<MoveRecord>();
+
+        private List<SwipeRecord> mSwipeRecords = new ArrayList<SwipeRecord>();
+
+        private List<RecyclerView.ViewHolder> mCleared = new ArrayList<RecyclerView.ViewHolder>();
+
+        public List<Pair<RecyclerView, RecyclerView.ViewHolder>> mHasDragFlag = new ArrayList<>();
+
+        LoggingCalback(int dragDirs, int swipeDirs) {
+            super(dragDirs, swipeDirs);
+        }
+
+        @Override
+        public boolean onMove(@NonNull RecyclerView recyclerView,
+                @NonNull RecyclerView.ViewHolder viewHolder,
+                @NonNull RecyclerView.ViewHolder target) {
+            mMoveRecordList.add(new MoveRecord(viewHolder, target));
+            return true;
+        }
+
+        @Override
+        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
+            mSwipeRecords.add(new SwipeRecord(viewHolder, direction));
+        }
+
+        public MoveRecord getMove(RecyclerView.ViewHolder vh) {
+            for (MoveRecord move : mMoveRecordList) {
+                if (move.from == vh) {
+                    return move;
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void clearView(@NonNull RecyclerView recyclerView,
+                @NonNull RecyclerView.ViewHolder viewHolder) {
+            super.clearView(recyclerView, viewHolder);
+            mCleared.add(viewHolder);
+        }
+
+        @Override
+        boolean hasDragFlag(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
+            mHasDragFlag.add(new Pair<>(recyclerView, viewHolder));
+            return super.hasDragFlag(recyclerView, viewHolder);
+        }
+
+        public SwipeRecord getSwipe(RecyclerView.ViewHolder vh) {
+            for (SwipeRecord swipe : mSwipeRecords) {
+                if (swipe.viewHolder == vh) {
+                    return swipe;
+                }
+            }
+            return null;
+        }
+
+        public boolean isCleared(RecyclerView.ViewHolder vh) {
+            return mCleared.contains(vh);
+        }
+    }
+
+    private static class LoggingItemTouchHelper extends ItemTouchHelper {
+
+        public LoggingItemTouchHelper(Callback callback) {
+            super(callback);
+        }
+    }
+
+    private static class SwipeRecord {
+
+        RecyclerView.ViewHolder viewHolder;
+
+        int dir;
+
+        public SwipeRecord(RecyclerView.ViewHolder viewHolder, int dir) {
+            this.viewHolder = viewHolder;
+            this.dir = dir;
+        }
+    }
+
+    private static class MoveRecord {
+
+        final int fromPos, toPos;
+
+        RecyclerView.ViewHolder from, to;
+
+        MoveRecord(RecyclerView.ViewHolder from, RecyclerView.ViewHolder to) {
+            this.from = from;
+            this.to = to;
+            fromPos = from.getAdapterPosition();
+            toPos = to.getAdapterPosition();
+        }
+    }
+}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/test/NestedScrollingParent2Adapter.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/test/NestedScrollingParent2Adapter.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/test/NestedScrollingParent2Adapter.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/test/NestedScrollingParent2Adapter.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/test/RecyclerViewTest.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTest.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/test/RecyclerViewTest.java
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTestActivity.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/test/RecyclerViewTestActivity.java
similarity index 100%
rename from v7/recyclerview/tests/src/android/support/v7/widget/test/RecyclerViewTestActivity.java
rename to v7/recyclerview/src/androidTest/java/android/support/v7/widget/test/RecyclerViewTestActivity.java
diff --git a/v7/recyclerview/tests/res/drawable/fast_scroll_thumb_drawable.xml b/v7/recyclerview/src/androidTest/res/drawable/fast_scroll_thumb_drawable.xml
similarity index 100%
rename from v7/recyclerview/tests/res/drawable/fast_scroll_thumb_drawable.xml
rename to v7/recyclerview/src/androidTest/res/drawable/fast_scroll_thumb_drawable.xml
diff --git a/v7/recyclerview/tests/res/drawable/fast_scroll_track_drawable.xml b/v7/recyclerview/src/androidTest/res/drawable/fast_scroll_track_drawable.xml
similarity index 100%
rename from v7/recyclerview/tests/res/drawable/fast_scroll_track_drawable.xml
rename to v7/recyclerview/src/androidTest/res/drawable/fast_scroll_track_drawable.xml
diff --git a/v7/recyclerview/tests/res/drawable/item_bg.xml b/v7/recyclerview/src/androidTest/res/drawable/item_bg.xml
similarity index 100%
rename from v7/recyclerview/tests/res/drawable/item_bg.xml
rename to v7/recyclerview/src/androidTest/res/drawable/item_bg.xml
diff --git a/v7/recyclerview/tests/res/layout/fast_scrollbar_test_rv.xml b/v7/recyclerview/src/androidTest/res/layout/fast_scrollbar_test_rv.xml
similarity index 100%
rename from v7/recyclerview/tests/res/layout/fast_scrollbar_test_rv.xml
rename to v7/recyclerview/src/androidTest/res/layout/fast_scrollbar_test_rv.xml
diff --git a/v7/recyclerview/tests/res/layout/focus_search_activity.xml b/v7/recyclerview/src/androidTest/res/layout/focus_search_activity.xml
similarity index 100%
rename from v7/recyclerview/tests/res/layout/focus_search_activity.xml
rename to v7/recyclerview/src/androidTest/res/layout/focus_search_activity.xml
diff --git a/v7/recyclerview/tests/res/layout/focus_test_item_view.xml b/v7/recyclerview/src/androidTest/res/layout/focus_test_item_view.xml
similarity index 100%
rename from v7/recyclerview/tests/res/layout/focus_test_item_view.xml
rename to v7/recyclerview/src/androidTest/res/layout/focus_test_item_view.xml
diff --git a/v7/recyclerview/tests/res/layout/inflation_test.xml b/v7/recyclerview/src/androidTest/res/layout/inflation_test.xml
similarity index 100%
rename from v7/recyclerview/tests/res/layout/inflation_test.xml
rename to v7/recyclerview/src/androidTest/res/layout/inflation_test.xml
diff --git a/v7/recyclerview/tests/res/layout/item_view.xml b/v7/recyclerview/src/androidTest/res/layout/item_view.xml
similarity index 100%
rename from v7/recyclerview/tests/res/layout/item_view.xml
rename to v7/recyclerview/src/androidTest/res/layout/item_view.xml
diff --git a/v7/recyclerview/tests/res/layout/wrapped_test_rv.xml b/v7/recyclerview/src/androidTest/res/layout/wrapped_test_rv.xml
similarity index 100%
rename from v7/recyclerview/tests/res/layout/wrapped_test_rv.xml
rename to v7/recyclerview/src/androidTest/res/layout/wrapped_test_rv.xml
diff --git a/v7/recyclerview/tests/res/values/styles.xml b/v7/recyclerview/src/androidTest/res/values/styles.xml
similarity index 100%
rename from v7/recyclerview/tests/res/values/styles.xml
rename to v7/recyclerview/src/androidTest/res/values/styles.xml
diff --git a/v7/recyclerview/src/main/AndroidManifest.xml b/v7/recyclerview/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e3cde8b
--- /dev/null
+++ b/v7/recyclerview/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.v7.recyclerview"/>
\ No newline at end of file
diff --git a/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/AsyncListDiffer.java b/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/AsyncListDiffer.java
index 73959c5..5259b4f 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/AsyncListDiffer.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/AsyncListDiffer.java
@@ -189,7 +189,7 @@
      * @param newList The new List.
      */
     @SuppressWarnings("WeakerAccess")
-    public void submitList(final List<T> newList) {
+    public void submitList(@Nullable final List<T> newList) {
         if (newList == mList) {
             // nothing to do
             return;
diff --git a/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java b/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
index f3729f9..069d0d2 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/recyclerview/extensions/ListAdapter.java
@@ -17,6 +17,7 @@
 package android.support.v7.recyclerview.extensions;
 
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v7.util.AdapterListUpdateCallback;
 import android.support.v7.util.DiffUtil;
 import android.support.v7.widget.RecyclerView;
@@ -117,7 +118,7 @@
      * @param list The new list to be displayed.
      */
     @SuppressWarnings("WeakerAccess")
-    public void submitList(List<T> list) {
+    public void submitList(@Nullable List<T> list) {
         mHelper.submitList(list);
     }
 
diff --git a/v7/recyclerview/src/main/java/android/support/v7/util/AsyncListUtil.java b/v7/recyclerview/src/main/java/android/support/v7/util/AsyncListUtil.java
index bb31eab..94086e5 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/util/AsyncListUtil.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/util/AsyncListUtil.java
@@ -16,6 +16,8 @@
 
 package android.support.v7.util;
 
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
 import android.support.annotation.WorkerThread;
 import android.util.Log;
@@ -84,8 +86,8 @@
      * @param dataCallback Data access callback.
      * @param viewCallback Callback for querying visible item range and update notifications.
      */
-    public AsyncListUtil(Class<T> klass, int tileSize, DataCallback<T> dataCallback,
-                         ViewCallback viewCallback) {
+    public AsyncListUtil(@NonNull Class<T> klass, int tileSize,
+            @NonNull DataCallback<T> dataCallback, @NonNull ViewCallback viewCallback) {
         mTClass = klass;
         mTileSize = tileSize;
         mDataCallback = dataCallback;
@@ -147,6 +149,7 @@
      * @return The data item at the given position or <code>null</code> if it has not been loaded
      *         yet.
      */
+    @Nullable
     public T getItem(int position) {
         if (position < 0 || position >= mItemCount) {
             throw new IndexOutOfBoundsException(position + " is not within 0 and " + mItemCount);
@@ -471,7 +474,7 @@
          *             <code>itemCount</code>.
          */
         @WorkerThread
-        public abstract void fillData(T[] data, int startPosition, int itemCount);
+        public abstract void fillData(@NonNull T[] data, int startPosition, int itemCount);
 
         /**
          * Recycle the objects created in {@link #fillData} if necessary.
@@ -481,7 +484,7 @@
          * @param itemCount The data item count.
          */
         @WorkerThread
-        public void recycleData(T[] data, int itemCount) {
+        public void recycleData(@NonNull T[] data, int itemCount) {
         }
 
         /**
@@ -548,7 +551,7 @@
          * @param outRange The visible item range.
          */
         @UiThread
-        public abstract void getItemRangeInto(int[] outRange);
+        public abstract void getItemRangeInto(@NonNull int[] outRange);
 
         /**
          * Compute a wider range of items that will be loaded for smoother scrolling.
@@ -569,7 +572,7 @@
          * @param scrollHint The scroll direction hint.
          */
         @UiThread
-        public void extendRangeInto(int[] range, int[] outRange, int scrollHint) {
+        public void extendRangeInto(@NonNull int[] range, @NonNull int[] outRange, int scrollHint) {
             final int fullRange = range[1] - range[0] + 1;
             final int halfRange = fullRange / 2;
             outRange[0] = range[0] - (scrollHint == HINT_SCROLL_DESC ? fullRange : halfRange);
diff --git a/v7/recyclerview/src/main/java/android/support/v7/util/BatchingListUpdateCallback.java b/v7/recyclerview/src/main/java/android/support/v7/util/BatchingListUpdateCallback.java
index c8bc1a4..2906945 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/util/BatchingListUpdateCallback.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/util/BatchingListUpdateCallback.java
@@ -15,6 +15,8 @@
  */
 package android.support.v7.util;
 
+import android.support.annotation.NonNull;
+
 /**
  * Wraps a {@link ListUpdateCallback} callback and batches operations that can be merged.
  * <p>
@@ -41,7 +43,7 @@
     int mLastEventCount = -1;
     Object mLastEventPayload = null;
 
-    public BatchingListUpdateCallback(ListUpdateCallback callback) {
+    public BatchingListUpdateCallback(@NonNull ListUpdateCallback callback) {
         mWrapped = callback;
     }
 
diff --git a/v7/recyclerview/src/main/java/android/support/v7/util/DiffUtil.java b/v7/recyclerview/src/main/java/android/support/v7/util/DiffUtil.java
index 44922f1..6908749 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/util/DiffUtil.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/util/DiffUtil.java
@@ -16,6 +16,7 @@
 
 package android.support.v7.util;
 
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.widget.RecyclerView;
@@ -93,7 +94,8 @@
      * @return A DiffResult that contains the information about the edit sequence to convert the
      * old list into the new list.
      */
-    public static DiffResult calculateDiff(Callback cb) {
+    @NonNull
+    public static DiffResult calculateDiff(@NonNull Callback cb) {
         return calculateDiff(cb, true);
     }
 
@@ -110,7 +112,8 @@
      * @return A DiffResult that contains the information about the edit sequence to convert the
      * old list into the new list.
      */
-    public static DiffResult calculateDiff(Callback cb, boolean detectMoves) {
+    @NonNull
+    public static DiffResult calculateDiff(@NonNull Callback cb, boolean detectMoves) {
         final int oldSize = cb.getOldListSize();
         final int newSize = cb.getNewListSize();
 
@@ -727,7 +730,7 @@
          *                displaying the new list.
          * @see AdapterListUpdateCallback
          */
-        public void dispatchUpdatesTo(final RecyclerView.Adapter adapter) {
+        public void dispatchUpdatesTo(@NonNull final RecyclerView.Adapter adapter) {
             dispatchUpdatesTo(new AdapterListUpdateCallback(adapter));
         }
 
@@ -740,7 +743,7 @@
          * @param updateCallback The callback to receive the update operations.
          * @see #dispatchUpdatesTo(RecyclerView.Adapter)
          */
-        public void dispatchUpdatesTo(ListUpdateCallback updateCallback) {
+        public void dispatchUpdatesTo(@NonNull ListUpdateCallback updateCallback) {
             final BatchingListUpdateCallback batchingCallback;
             if (updateCallback instanceof BatchingListUpdateCallback) {
                 batchingCallback = (BatchingListUpdateCallback) updateCallback;
diff --git a/v7/recyclerview/src/main/java/android/support/v7/util/ListUpdateCallback.java b/v7/recyclerview/src/main/java/android/support/v7/util/ListUpdateCallback.java
index 2136202..91bfd2a 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/util/ListUpdateCallback.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/util/ListUpdateCallback.java
@@ -15,6 +15,8 @@
  */
 package android.support.v7.util;
 
+import android.support.annotation.Nullable;
+
 /**
  * An interface that can receive Update operations that are applied to a list.
  * <p>
@@ -51,5 +53,5 @@
      * @param position The position of the item which has been updated.
      * @param count    The number of items which has changed.
      */
-    void onChanged(int position, int count, Object payload);
+    void onChanged(int position, int count, @Nullable Object payload);
 }
diff --git a/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java b/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
index bd07b01..d29d988 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/util/SortedList.java
@@ -87,7 +87,7 @@
      * @param klass    The class of the contents of the SortedList.
      * @param callback The callback that controls the behavior of SortedList.
      */
-    public SortedList(Class<T> klass, Callback<T> callback) {
+    public SortedList(@NonNull Class<T> klass, @NonNull Callback<T> callback) {
         this(klass, callback, MIN_CAPACITY);
     }
 
@@ -98,7 +98,7 @@
      * @param callback        The callback that controls the behavior of SortedList.
      * @param initialCapacity The initial capacity to hold items.
      */
-    public SortedList(Class<T> klass, Callback<T> callback, int initialCapacity) {
+    public SortedList(@NonNull Class<T> klass, @NonNull Callback<T> callback, int initialCapacity) {
         mTClass = klass;
         mData = (T[]) Array.newInstance(klass, initialCapacity);
         mCallback = callback;
@@ -158,7 +158,7 @@
      *                       input array.
      * @see SortedList#addAll(T[] items)
      */
-    public void addAll(T[] items, boolean mayModifyInput) {
+    public void addAll(@NonNull T[] items, boolean mayModifyInput) {
         throwIfInMutationOperation();
         if (items.length == 0) {
             return;
@@ -178,7 +178,7 @@
      *
      * @param items Array of items to be added into the list.
      */
-    public void addAll(T... items) {
+    public void addAll(@NonNull T... items) {
         addAll(items, false);
     }
 
@@ -189,7 +189,7 @@
      *
      * @param items Collection of items to be added into the list.
      */
-    public void addAll(Collection<T> items) {
+    public void addAll(@NonNull Collection<T> items) {
         T[] copy = (T[]) Array.newInstance(mTClass, items.size());
         addAll(items.toArray(copy), true);
     }
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/FastScroller.java b/v7/recyclerview/src/main/java/android/support/v7/widget/FastScroller.java
index fbe234b..b383c2a 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/FastScroller.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/FastScroller.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
 import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.view.ViewCompat;
@@ -379,7 +380,8 @@
     }
 
     @Override
-    public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent ev) {
+    public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
+            @NonNull MotionEvent ev) {
         final boolean handled;
         if (mState == STATE_VISIBLE) {
             boolean insideVerticalThumb = isPointInsideVerticalThumb(ev.getX(), ev.getY());
@@ -408,7 +410,7 @@
     }
 
     @Override
-    public void onTouchEvent(RecyclerView recyclerView, MotionEvent me) {
+    public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent me) {
         if (mState == STATE_HIDDEN) {
             return;
         }
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/main/java/android/support/v7/widget/LinearLayoutManager.java
index 359229a..70510f6 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/LinearLayoutManager.java
@@ -24,6 +24,7 @@
 import android.graphics.PointF;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
 import android.support.annotation.RestrictTo;
 import android.support.v4.os.TraceCompat;
 import android.support.v4.view.ViewCompat;
@@ -2092,7 +2093,7 @@
      */
     @RestrictTo(LIBRARY_GROUP)
     @Override
-    public void prepareForDrop(View view, View target, int x, int y) {
+    public void prepareForDrop(@NonNull View view, @NonNull View target, int x, int y) {
         assertNotInLayoutOrScroll("Cannot drop a view during a scroll or layout calculation");
         ensureLayoutState();
         resolveShouldLayoutReverse();
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/LinearSmoothScroller.java b/v7/recyclerview/src/main/java/android/support/v7/widget/LinearSmoothScroller.java
index 74d6a3b..0b5c48b 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/LinearSmoothScroller.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/LinearSmoothScroller.java
@@ -18,9 +18,7 @@
 
 import android.content.Context;
 import android.graphics.PointF;
-import android.support.annotation.Nullable;
 import android.util.DisplayMetrics;
-import android.util.Log;
 import android.view.View;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.LinearInterpolator;
@@ -123,6 +121,9 @@
      */
     @Override
     protected void onSeekTargetStep(int dx, int dy, RecyclerView.State state, Action action) {
+        // TODO(b/72745539): Is there ever a time when onSeekTargetStep should be called when
+        // getChildCount returns 0?  Should this logic be extracted out of this method such that
+        // this method is not called if getChildCount() returns 0?
         if (getChildCount() == 0) {
             stop();
             return;
@@ -336,26 +337,4 @@
         final int end = layoutManager.getWidth() - layoutManager.getPaddingRight();
         return calculateDtToFit(left, right, start, end, snapPreference);
     }
-
-    /**
-     * Compute the scroll vector for a given target position.
-     * <p>
-     * This method can return null if the layout manager cannot calculate a scroll vector
-     * for the given position (e.g. it has no current scroll position).
-     *
-     * @param targetPosition the position to which the scroller is scrolling
-     *
-     * @return the scroll vector for a given target position
-     */
-    @Nullable
-    public PointF computeScrollVectorForPosition(int targetPosition) {
-        RecyclerView.LayoutManager layoutManager = getLayoutManager();
-        if (layoutManager instanceof ScrollVectorProvider) {
-            return ((ScrollVectorProvider) layoutManager)
-                    .computeScrollVectorForPosition(targetPosition);
-        }
-        Log.w(TAG, "You should override computeScrollVectorForPosition when the LayoutManager"
-                + " does not implement " + ScrollVectorProvider.class.getCanonicalName());
-        return null;
-    }
 }
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
index 991abb9..d7cc9b9 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/RecyclerView.java
@@ -41,6 +41,7 @@
 import android.support.annotation.IntDef;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
+import android.support.annotation.Px;
 import android.support.annotation.RestrictTo;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.os.TraceCompat;
@@ -518,6 +519,12 @@
     private final int[] mNestedOffsets = new int[2];
 
     /**
+     * Reusable int array for use in calls to {@link #scrollStep(int, int, int[])} so that the
+     * method may mutate it to "return" 2 ints.
+     */
+    private final int[] mScrollStepConsumed = new int[2];
+
+    /**
      * These are views that had their a11y importance changed during a layout. We defer these events
      * until the end of the layout because a11y service may make sync calls back to the RV while
      * the View's state is undefined.
@@ -582,15 +589,15 @@
                 }
             };
 
-    public RecyclerView(Context context) {
+    public RecyclerView(@NonNull Context context) {
         this(context, null);
     }
 
-    public RecyclerView(Context context, @Nullable AttributeSet attrs) {
+    public RecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public RecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
+    public RecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         if (attrs != null) {
             TypedArray a = context.obtainStyledAttributes(attrs, CLIP_TO_PADDING_ATTR, defStyle, 0);
@@ -683,6 +690,7 @@
      * Returns the accessibility delegate compatibility implementation used by the RecyclerView.
      * @return An instance of AccessibilityDelegateCompat used by RecyclerView
      */
+    @Nullable
     public RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate() {
         return mAccessibilityDelegate;
     }
@@ -692,7 +700,7 @@
      * @param accessibilityDelegate The accessibility delegate to be used by RecyclerView.
      */
     public void setAccessibilityDelegateCompat(
-            RecyclerViewAccessibilityDelegate accessibilityDelegate) {
+            @Nullable RecyclerViewAccessibilityDelegate accessibilityDelegate) {
         mAccessibilityDelegate = accessibilityDelegate;
         ViewCompat.setAccessibilityDelegate(this, mAccessibilityDelegate);
     }
@@ -1061,7 +1069,7 @@
      *                                      this to false.
      * @see #setAdapter(Adapter)
      */
-    public void swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews) {
+    public void swapAdapter(@Nullable Adapter adapter, boolean removeAndRecycleExistingViews) {
         // bail out if layout is frozen
         setLayoutFrozen(false);
         setAdapterInternal(adapter, true, removeAndRecycleExistingViews);
@@ -1077,7 +1085,7 @@
      * @param adapter The new adapter to set, or null to set no adapter.
      * @see #swapAdapter(Adapter, boolean)
      */
-    public void setAdapter(Adapter adapter) {
+    public void setAdapter(@Nullable Adapter adapter) {
         // bail out if layout is frozen
         setLayoutFrozen(false);
         setAdapterInternal(adapter, false, true);
@@ -1114,7 +1122,7 @@
      * @param removeAndRecycleViews  If true, we'll remove and recycle all existing views. If
      *                               compatibleWithPrevious is false, this parameter is ignored.
      */
-    private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious,
+    private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,
             boolean removeAndRecycleViews) {
         if (mAdapter != null) {
             mAdapter.unregisterAdapterDataObserver(mObserver);
@@ -1143,6 +1151,7 @@
      * @return The previously set adapter
      * @see #setAdapter(Adapter)
      */
+    @Nullable
     public Adapter getAdapter() {
         return mAdapter;
     }
@@ -1157,7 +1166,7 @@
      *
      * @param listener Listener to register, or null to clear
      */
-    public void setRecyclerListener(RecyclerListener listener) {
+    public void setRecyclerListener(@Nullable RecyclerListener listener) {
         mRecyclerListener = listener;
     }
 
@@ -1189,7 +1198,8 @@
      *
      * @param listener Listener to register
      */
-    public void addOnChildAttachStateChangeListener(OnChildAttachStateChangeListener listener) {
+    public void addOnChildAttachStateChangeListener(
+            @NonNull OnChildAttachStateChangeListener listener) {
         if (mOnChildAttachStateListeners == null) {
             mOnChildAttachStateListeners = new ArrayList<>();
         }
@@ -1201,7 +1211,8 @@
      *
      * @param listener Listener to unregister
      */
-    public void removeOnChildAttachStateChangeListener(OnChildAttachStateChangeListener listener) {
+    public void removeOnChildAttachStateChangeListener(
+            @NonNull OnChildAttachStateChangeListener listener) {
         if (mOnChildAttachStateListeners == null) {
             return;
         }
@@ -1230,7 +1241,7 @@
      *
      * @param layout LayoutManager to use
      */
-    public void setLayoutManager(LayoutManager layout) {
+    public void setLayoutManager(@Nullable LayoutManager layout) {
         if (layout == mLayout) {
             return;
         }
@@ -1388,6 +1399,7 @@
      *
      * @return The currently bound LayoutManager
      */
+    @Nullable
     public LayoutManager getLayoutManager() {
         return mLayout;
     }
@@ -1400,6 +1412,7 @@
      * @return The pool used to store recycled item views for reuse.
      * @see #setRecycledViewPool(RecycledViewPool)
      */
+    @NonNull
     public RecycledViewPool getRecycledViewPool() {
         return mRecycler.getRecycledViewPool();
     }
@@ -1412,7 +1425,7 @@
      *
      * @param pool Pool to set. If this parameter is null a new pool will be created and used.
      */
-    public void setRecycledViewPool(RecycledViewPool pool) {
+    public void setRecycledViewPool(@Nullable RecycledViewPool pool) {
         mRecycler.setRecycledViewPool(pool);
     }
 
@@ -1423,7 +1436,7 @@
      *
      * @see ViewCacheExtension#getViewForPositionAndType(Recycler, int, int)
      */
-    public void setViewCacheExtension(ViewCacheExtension extension) {
+    public void setViewCacheExtension(@Nullable ViewCacheExtension extension) {
         mRecycler.setViewCacheExtension(extension);
     }
 
@@ -1481,7 +1494,7 @@
      * @param index Position in the decoration chain to insert this decoration at. If this value
      *              is negative the decoration will be added at the end.
      */
-    public void addItemDecoration(ItemDecoration decor, int index) {
+    public void addItemDecoration(@NonNull ItemDecoration decor, int index) {
         if (mLayout != null) {
             mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll  or"
                     + " layout");
@@ -1510,7 +1523,7 @@
      *
      * @param decor Decoration to add
      */
-    public void addItemDecoration(ItemDecoration decor) {
+    public void addItemDecoration(@NonNull ItemDecoration decor) {
         addItemDecoration(decor, -1);
     }
 
@@ -1518,8 +1531,10 @@
      * Returns an {@link ItemDecoration} previously added to this RecyclerView.
      *
      * @param index The index position of the desired ItemDecoration.
-     * @return the ItemDecoration at index position, or null if invalid index.
+     * @return the ItemDecoration at index position
+     * @throws IndexOutOfBoundsException on invalid index
      */
+    @NonNull
     public ItemDecoration getItemDecorationAt(int index) {
         final int size = getItemDecorationCount();
         if (index < 0 || index >= size) {
@@ -1561,7 +1576,7 @@
      * @param decor Decoration to remove
      * @see #addItemDecoration(ItemDecoration)
      */
-    public void removeItemDecoration(ItemDecoration decor) {
+    public void removeItemDecoration(@NonNull ItemDecoration decor) {
         if (mLayout != null) {
             mLayout.assertNotInLayoutOrScroll("Cannot remove item decoration during a scroll  or"
                     + " layout");
@@ -1586,7 +1601,8 @@
      * @param childDrawingOrderCallback The ChildDrawingOrderCallback to be used by the drawing
      *                                  system.
      */
-    public void setChildDrawingOrderCallback(ChildDrawingOrderCallback childDrawingOrderCallback) {
+    public void setChildDrawingOrderCallback(
+            @Nullable ChildDrawingOrderCallback childDrawingOrderCallback) {
         if (childDrawingOrderCallback == mChildDrawingOrderCallback) {
             return;
         }
@@ -1603,7 +1619,7 @@
      *             {@link #removeOnScrollListener(OnScrollListener)}
      */
     @Deprecated
-    public void setOnScrollListener(OnScrollListener listener) {
+    public void setOnScrollListener(@Nullable OnScrollListener listener) {
         mScrollListener = listener;
     }
 
@@ -1614,9 +1630,9 @@
      * Other components that take ownership of a view may call {@link #clearOnScrollListeners()}
      * to remove all attached listeners.</p>
      *
-     * @param listener listener to set or null to clear
+     * @param listener listener to set
      */
-    public void addOnScrollListener(OnScrollListener listener) {
+    public void addOnScrollListener(@NonNull OnScrollListener listener) {
         if (mScrollListeners == null) {
             mScrollListeners = new ArrayList<>();
         }
@@ -1628,7 +1644,7 @@
      *
      * @param listener listener to set or null to clear
      */
-    public void removeOnScrollListener(OnScrollListener listener) {
+    public void removeOnScrollListener(@NonNull OnScrollListener listener) {
         if (mScrollListeners != null) {
             mScrollListeners.remove(listener);
         }
@@ -1724,6 +1740,46 @@
     }
 
     /**
+     * Scrolls the RV by 'dx' and 'dy' via calls to
+     * {@link LayoutManager#scrollHorizontallyBy(int, Recycler, State)} and
+     * {@link LayoutManager#scrollVerticallyBy(int, Recycler, State)}.
+     *
+     * Also sets how much of the scroll was actually consumed in 'consumed' parameter (indexes 0 and
+     * 1 for the x axis and y axis, respectively).
+     *
+     * This method should only be called in the context of an existing scroll operation such that
+     * any other necessary operations (such as a call to {@link #consumePendingUpdateOperations()})
+     * is already handled.
+     */
+    private void scrollStep(int dx, int dy, @Nullable int[] consumed) {
+        startInterceptRequestLayout();
+        onEnterLayoutOrScroll();
+
+        TraceCompat.beginSection(TRACE_SCROLL_TAG);
+        fillRemainingScrollValues(mState);
+
+        int consumedX = 0;
+        int consumedY = 0;
+        if (dx != 0) {
+            consumedX = mLayout.scrollHorizontallyBy(dx, mRecycler, mState);
+        }
+        if (dy != 0) {
+            consumedY = mLayout.scrollVerticallyBy(dy, mRecycler, mState);
+        }
+
+        TraceCompat.endSection();
+        repositionShadowingViews();
+
+        onExitLayoutOrScroll();
+        stopInterceptRequestLayout(false);
+
+        if (consumed != null) {
+            consumed[0] = consumedX;
+            consumed[1] = consumedY;
+        }
+    }
+
+    /**
      * Helper method reflect data changes to the state.
      * <p>
      * Adapter changes during a scroll may trigger a crash because scroll assumes no data change
@@ -1803,22 +1859,11 @@
 
         consumePendingUpdateOperations();
         if (mAdapter != null) {
-            startInterceptRequestLayout();
-            onEnterLayoutOrScroll();
-            TraceCompat.beginSection(TRACE_SCROLL_TAG);
-            fillRemainingScrollValues(mState);
-            if (x != 0) {
-                consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState);
-                unconsumedX = x - consumedX;
-            }
-            if (y != 0) {
-                consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState);
-                unconsumedY = y - consumedY;
-            }
-            TraceCompat.endSection();
-            repositionShadowingViews();
-            onExitLayoutOrScroll();
-            stopInterceptRequestLayout(false);
+            scrollStep(x, y, mScrollStepConsumed);
+            consumedX = mScrollStepConsumed[0];
+            consumedY = mScrollStepConsumed[1];
+            unconsumedX = x - consumedX;
+            unconsumedY = y - consumedY;
         }
         if (!mItemDecorations.isEmpty()) {
             invalidate();
@@ -2116,7 +2161,7 @@
      * @param dx Pixels to scroll horizontally
      * @param dy Pixels to scroll vertically
      */
-    public void smoothScrollBy(int dx, int dy) {
+    public void smoothScrollBy(@Px int dx, @Px int dy) {
         smoothScrollBy(dx, dy, null);
     }
 
@@ -2128,7 +2173,7 @@
      * @param interpolator {@link Interpolator} to be used for scrolling. If it is
      *                     {@code null}, RecyclerView is going to use the default interpolator.
      */
-    public void smoothScrollBy(int dx, int dy, Interpolator interpolator) {
+    public void smoothScrollBy(@Px int dx, @Px int dy, @Nullable Interpolator interpolator) {
         if (mLayout == null) {
             Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. "
                     + "Call setLayoutManager with a non-null argument.");
@@ -2427,6 +2472,7 @@
      * @return The previously set {@link EdgeEffectFactory}
      * @see #setEdgeEffectFactory(EdgeEffectFactory)
      */
+    @NonNull
     public EdgeEffectFactory getEdgeEffectFactory() {
         return mEdgeEffectFactory;
     }
@@ -2793,7 +2839,7 @@
      * @param listener Listener to add
      * @see SimpleOnItemTouchListener
      */
-    public void addOnItemTouchListener(OnItemTouchListener listener) {
+    public void addOnItemTouchListener(@NonNull OnItemTouchListener listener) {
         mOnItemTouchListeners.add(listener);
     }
 
@@ -2802,7 +2848,7 @@
      *
      * @param listener Listener to remove
      */
-    public void removeOnItemTouchListener(OnItemTouchListener listener) {
+    public void removeOnItemTouchListener(@NonNull OnItemTouchListener listener) {
         mOnItemTouchListeners.remove(listener);
         if (mActiveOnItemTouchListener == listener) {
             mActiveOnItemTouchListener = null;
@@ -3318,7 +3364,7 @@
      * @param animator The ItemAnimator being set. If null, no animations will occur
      * when changes occur to the items in this RecyclerView.
      */
-    public void setItemAnimator(ItemAnimator animator) {
+    public void setItemAnimator(@Nullable ItemAnimator animator) {
         if (mItemAnimator != null) {
             mItemAnimator.endAnimations();
             mItemAnimator.setListener(null);
@@ -3430,6 +3476,7 @@
      * @return ItemAnimator The current ItemAnimator. If null, no animations will occur
      * when changes occur to the items in this RecyclerView.
      */
+    @Nullable
     public ItemAnimator getItemAnimator() {
         return mItemAnimator;
     }
@@ -4512,7 +4559,7 @@
      * @param child Child View to query
      * @return Adapter position corresponding to the given view or {@link #NO_POSITION}
      */
-    public int getChildAdapterPosition(View child) {
+    public int getChildAdapterPosition(@NonNull View child) {
         final ViewHolder holder = getChildViewHolderInt(child);
         return holder != null ? holder.getAdapterPosition() : NO_POSITION;
     }
@@ -4527,7 +4574,7 @@
      * @return Adapter position of the given View as of last layout pass or {@link #NO_POSITION} if
      * the View is representing a removed item.
      */
-    public int getChildLayoutPosition(View child) {
+    public int getChildLayoutPosition(@NonNull View child) {
         final ViewHolder holder = getChildViewHolderInt(child);
         return holder != null ? holder.getLayoutPosition() : NO_POSITION;
     }
@@ -4538,7 +4585,7 @@
      * @param child Child View to query
      * @return Item id corresponding to the given view or {@link #NO_ID}
      */
-    public long getChildItemId(View child) {
+    public long getChildItemId(@NonNull View child) {
         if (mAdapter == null || !mAdapter.hasStableIds()) {
             return NO_ID;
         }
@@ -4682,6 +4729,7 @@
      * @param y Vertical position in pixels to search
      * @return The child view under (x, y) or null if no matching child is found
      */
+    @Nullable
     public View findChildViewUnder(float x, float y) {
         final int count = mChildHelper.getChildCount();
         for (int i = count - 1; i >= 0; i--) {
@@ -4709,7 +4757,7 @@
      *
      * @param dy Vertical pixel offset to apply to the bounds of all child views
      */
-    public void offsetChildrenVertical(int dy) {
+    public void offsetChildrenVertical(@Px int dy) {
         final int childCount = mChildHelper.getChildCount();
         for (int i = 0; i < childCount; i++) {
             mChildHelper.getChildAt(i).offsetTopAndBottom(dy);
@@ -4726,7 +4774,7 @@
      *
      * @param child Child view that is now attached to this RecyclerView and its associated window
      */
-    public void onChildAttachedToWindow(View child) {
+    public void onChildAttachedToWindow(@NonNull View child) {
     }
 
     /**
@@ -4738,7 +4786,7 @@
      *
      * @param child Child view that is now detached from this RecyclerView and its associated window
      */
-    public void onChildDetachedFromWindow(View child) {
+    public void onChildDetachedFromWindow(@NonNull View child) {
     }
 
     /**
@@ -4747,7 +4795,7 @@
      *
      * @param dx Horizontal pixel offset to apply to the bounds of all child views
      */
-    public void offsetChildrenHorizontal(int dx) {
+    public void offsetChildrenHorizontal(@Px int dx) {
         final int childCount = mChildHelper.getChildCount();
         for (int i = 0; i < childCount; i++) {
             mChildHelper.getChildAt(i).offsetLeftAndRight(dx);
@@ -4761,7 +4809,7 @@
      * @param outBounds A rect that will receive the bounds of the element including its
      *                  decoration and margins.
      */
-    public void getDecoratedBoundsWithMargins(View view, Rect outBounds) {
+    public void getDecoratedBoundsWithMargins(@NonNull View view, @NonNull Rect outBounds) {
         getDecoratedBoundsWithMarginsInt(view, outBounds);
     }
 
@@ -4819,7 +4867,7 @@
      * @param dx horizontal distance scrolled in pixels
      * @param dy vertical distance scrolled in pixels
      */
-    public void onScrolled(int dx, int dy) {
+    public void onScrolled(@Px int dx, @Px int dy) {
         // Do nothing
     }
 
@@ -4907,7 +4955,6 @@
         private OverScroller mScroller;
         Interpolator mInterpolator = sQuinticInterpolator;
 
-
         // When set to true, postOnAnimation callbacks are delayed until the run method completes
         private boolean mEatRunOnAnimationRequest = false;
 
@@ -4948,23 +4995,11 @@
                 }
 
                 if (mAdapter != null) {
-                    startInterceptRequestLayout();
-                    onEnterLayoutOrScroll();
-                    TraceCompat.beginSection(TRACE_SCROLL_TAG);
-                    fillRemainingScrollValues(mState);
-                    if (dx != 0) {
-                        hresult = mLayout.scrollHorizontallyBy(dx, mRecycler, mState);
-                        overscrollX = dx - hresult;
-                    }
-                    if (dy != 0) {
-                        vresult = mLayout.scrollVerticallyBy(dy, mRecycler, mState);
-                        overscrollY = dy - vresult;
-                    }
-                    TraceCompat.endSection();
-                    repositionShadowingViews();
-
-                    onExitLayoutOrScroll();
-                    stopInterceptRequestLayout(false);
+                    scrollStep(dx, dy, mScrollStepConsumed);
+                    hresult = mScrollStepConsumed[0];
+                    vresult = mScrollStepConsumed[1];
+                    overscrollX = dx - hresult;
+                    overscrollY = dy - vresult;
 
                     if (smoothScroller != null && !smoothScroller.isPendingInitialRun()
                             && smoothScroller.isRunning()) {
@@ -5259,7 +5294,7 @@
         /**
          * Create a new EdgeEffect for the provided direction.
          */
-        protected @NonNull EdgeEffect createEdgeEffect(RecyclerView view,
+        protected @NonNull EdgeEffect createEdgeEffect(@NonNull RecyclerView view,
                 @EdgeDirection int direction) {
             return new EdgeEffect(view.getContext());
         }
@@ -5583,6 +5618,7 @@
          *
          * @return List of ViewHolders in the scrap list.
          */
+        @NonNull
         public List<ViewHolder> getScrapList() {
             return mUnmodifiableAttachedScrap;
         }
@@ -5634,7 +5670,7 @@
          *                   bind the holder.
          * @return
          */
-        private boolean tryBindViewHolderByDeadline(ViewHolder holder, int offsetPosition,
+        private boolean tryBindViewHolderByDeadline(@NonNull ViewHolder holder, int offsetPosition,
                 int position, long deadlineNs) {
             holder.mOwnerRecyclerView = RecyclerView.this;
             final int viewType = holder.getItemViewType();
@@ -5669,7 +5705,7 @@
          * @param view The view to update.
          * @param position The position of the item to bind to this View.
          */
-        public void bindViewToPosition(View view, int position) {
+        public void bindViewToPosition(@NonNull View view, int position) {
             ViewHolder holder = getChildViewHolderInt(view);
             if (holder == null) {
                 throw new IllegalArgumentException("The view does not have a ViewHolder. You cannot"
@@ -5744,6 +5780,7 @@
          * @param position Position to obtain a view for
          * @return A view representing the data at <code>position</code> from <code>adapter</code>
          */
+        @NonNull
         public View getViewForPosition(int position) {
             return getViewForPosition(position, false);
         }
@@ -5982,7 +6019,7 @@
          * @param view Removed view for recycling
          * @see LayoutManager#removeAndRecycleView(View, Recycler)
          */
-        public void recycleView(View view) {
+        public void recycleView(@NonNull View view) {
             // This public recycle method tries to make view recycle-able since layout manager
             // intended to recycle this view (e.g. even if it is in scrap or change cache)
             ViewHolder holder = getChildViewHolderInt(view);
@@ -6140,7 +6177,7 @@
          * @param holder Holder to be added to the pool.
          * @param dispatchRecycled True to dispatch View recycled callbacks.
          */
-        void addViewHolderToRecycledViewPool(ViewHolder holder, boolean dispatchRecycled) {
+        void addViewHolderToRecycledViewPool(@NonNull ViewHolder holder, boolean dispatchRecycled) {
             clearNestedRecyclerViewIfNotNested(holder);
             if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE)) {
                 holder.setFlags(0, ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE);
@@ -6371,7 +6408,7 @@
             return null;
         }
 
-        void dispatchViewRecycled(ViewHolder holder) {
+        void dispatchViewRecycled(@NonNull ViewHolder holder) {
             if (mRecyclerListener != null) {
                 mRecyclerListener.onViewRecycled(holder);
             }
@@ -6578,7 +6615,9 @@
          * @return A View that is bound to the given position or NULL if there is no View to re-use
          * @see LayoutManager#ignoreView(View)
          */
-        public abstract View getViewForPositionAndType(Recycler recycler, int position, int type);
+        @Nullable
+        public abstract View getViewForPositionAndType(@NonNull Recycler recycler, int position,
+                int type);
     }
 
     /**
@@ -6679,6 +6718,7 @@
          *
          * @see #onCreateViewHolder(ViewGroup, int)
          */
+        @NonNull
         public final VH createViewHolder(@NonNull ViewGroup parent, int viewType) {
             try {
                 TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG);
@@ -8091,7 +8131,7 @@
         }
 
         /**
-         * @return true if RecycylerView is currently in the state of smooth scrolling.
+         * @return true if RecyclerView is currently in the state of smooth scrolling.
          */
         public boolean isSmoothScrolling() {
             return mSmoothScroller != null && mSmoothScroller.isRunning();
@@ -10188,7 +10228,7 @@
             if (vScroll == 0 && hScroll == 0) {
                 return false;
             }
-            mRecyclerView.scrollBy(hScroll, vScroll);
+            mRecyclerView.smoothScrollBy(hScroll, vScroll);
             return true;
         }
 
@@ -10406,7 +10446,7 @@
          *         to continue with the current behavior and continue observing future events in
          *         the gesture.
          */
-        boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e);
+        boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
 
         /**
          * Process a touch event as part of a gesture that was claimed by returning true from
@@ -10415,7 +10455,7 @@
          * @param e MotionEvent describing the touch event. All coordinates are in
          *          the RecyclerView's coordinate system.
          */
-        void onTouchEvent(RecyclerView rv, MotionEvent e);
+        void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
 
         /**
          * Called when a child of RecyclerView does not want RecyclerView and its ancestors to
@@ -10440,12 +10480,12 @@
      */
     public static class SimpleOnItemTouchListener implements RecyclerView.OnItemTouchListener {
         @Override
-        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
+        public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
             return false;
         }
 
         @Override
-        public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+        public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
         }
 
         @Override
@@ -10470,7 +10510,7 @@
          * @param newState     The updated scroll state. One of {@link #SCROLL_STATE_IDLE},
          *                     {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}.
          */
-        public void onScrollStateChanged(RecyclerView recyclerView, int newState){}
+        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState){}
 
         /**
          * Callback method to be invoked when the RecyclerView has been scrolled. This will be
@@ -10483,7 +10523,7 @@
          * @param dx The amount of horizontal scroll.
          * @param dy The amount of vertical scroll.
          */
-        public void onScrolled(RecyclerView recyclerView, int dx, int dy){}
+        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){}
     }
 
     /**
@@ -10504,7 +10544,7 @@
          *
          * @param holder The ViewHolder containing the view that was recycled
          */
-        void onViewRecycled(ViewHolder holder);
+        void onViewRecycled(@NonNull ViewHolder holder);
     }
 
     /**
@@ -10518,14 +10558,14 @@
          *
          * @param view The View which is attached to the RecyclerView
          */
-        void onChildViewAttachedToWindow(View view);
+        void onChildViewAttachedToWindow(@NonNull View view);
 
         /**
          * Called when a view is detached from RecyclerView.
          *
          * @param view The View which is being detached from the RecyclerView
          */
-        void onChildViewDetachedFromWindow(View view);
+        void onChildViewDetachedFromWindow(@NonNull View view);
     }
 
     /**
@@ -10542,6 +10582,7 @@
      * strong references to extra off-screen item views for caching purposes</p>
      */
     public abstract static class ViewHolder {
+        @NonNull
         public final View itemView;
         WeakReference<RecyclerView> mNestedRecyclerView;
         int mPosition = NO_POSITION;
@@ -10683,7 +10724,7 @@
          */
         RecyclerView mOwnerRecyclerView;
 
-        public ViewHolder(View itemView) {
+        public ViewHolder(@NonNull View itemView) {
             if (itemView == null) {
                 throw new IllegalArgumentException("itemView may not be null");
             }
@@ -11389,6 +11430,28 @@
         }
 
         /**
+         * Compute the scroll vector for a given target position.
+         * <p>
+         * This method can return null if the layout manager cannot calculate a scroll vector
+         * for the given position (e.g. it has no current scroll position).
+         *
+         * @param targetPosition the position to which the scroller is scrolling
+         *
+         * @return the scroll vector for a given target position
+         */
+        @Nullable
+        public PointF computeScrollVectorForPosition(int targetPosition) {
+            LayoutManager layoutManager = getLayoutManager();
+            if (layoutManager instanceof ScrollVectorProvider) {
+                return ((ScrollVectorProvider) layoutManager)
+                        .computeScrollVectorForPosition(targetPosition);
+            }
+            Log.w(TAG, "You should override computeScrollVectorForPosition when the LayoutManager"
+                    + " does not implement " + ScrollVectorProvider.class.getCanonicalName());
+            return null;
+        }
+
+        /**
          * @return The LayoutManager to which this SmoothScroller is attached. Will return
          * <code>null</code> after the SmoothScroller is stopped.
          */
@@ -11450,11 +11513,32 @@
         }
 
         private void onAnimation(int dx, int dy) {
+            // TODO(b/72745539): If mRunning is false, we call stop, which is a no op if mRunning
+            // is false. Also, if recyclerView is null, we call stop, and stop assumes recyclerView
+            // is not null (as does the code following this block).  This should be cleaned up.
             final RecyclerView recyclerView = mRecyclerView;
             if (!mRunning || mTargetPosition == RecyclerView.NO_POSITION || recyclerView == null) {
                 stop();
             }
+
+            // The following if block exists to have the LayoutManager scroll 1 pixel in the correct
+            // direction in order to cause the LayoutManager to draw two pages worth of views so
+            // that the target view may be found before scrolling any further.  This is done to
+            // prevent an initial scroll distance from scrolling past the view, which causes a
+            // jittery looking animation. (This block also necessarily sets mPendingInitialRun to
+            // false if it was true).
+            if (mPendingInitialRun && mTargetView == null && mLayoutManager != null) {
+                PointF pointF = computeScrollVectorForPosition(mTargetPosition);
+                if (pointF != null && (pointF.x != 0 || pointF.y != 0)) {
+                    recyclerView.scrollStep(
+                            (int) Math.signum(pointF.x),
+                            (int) Math.signum(pointF.y),
+                            null);
+                }
+            }
+
             mPendingInitialRun = false;
+
             if (mTargetView != null) {
                 // verify target position
                 if (getChildPosition(mTargetView) == mTargetPosition) {
@@ -11476,6 +11560,8 @@
                         mPendingInitialRun = true;
                         recyclerView.mViewFlinger.postOnAnimation();
                     } else {
+                        // TODO(b/72745539): stop() is a no-op if mRunning is false, so this can be
+                        // removed.
                         stop(); // done
                     }
                 }
@@ -11555,7 +11641,8 @@
          * @param action    If you want to trigger a new smooth scroll and cancel the previous one,
          *                  update this object.
          */
-        protected abstract void onSeekTargetStep(int dx, int dy, State state, Action action);
+        protected abstract void onSeekTargetStep(@Px int dx, @Px int dy, State state,
+                Action action);
 
         /**
          * Called when the target position is laid out. This is the last callback SmoothScroller
@@ -11595,7 +11682,7 @@
              * @param dx Pixels to scroll horizontally
              * @param dy Pixels to scroll vertically
              */
-            public Action(int dx, int dy) {
+            public Action(@Px int dx, @Px int dy) {
                 this(dx, dy, UNDEFINED_DURATION, null);
             }
 
@@ -11604,7 +11691,7 @@
              * @param dy       Pixels to scroll vertically
              * @param duration Duration of the animation in milliseconds
              */
-            public Action(int dx, int dy, int duration) {
+            public Action(@Px int dx, @Px int dy, int duration) {
                 this(dx, dy, duration, null);
             }
 
@@ -11615,7 +11702,8 @@
              * @param interpolator Interpolator to be used when calculating scroll position in each
              *                     animation step
              */
-            public Action(int dx, int dy, int duration, Interpolator interpolator) {
+            public Action(@Px int dx, @Px int dy, int duration,
+                    @Nullable Interpolator interpolator) {
                 mDx = dx;
                 mDy = dy;
                 mDuration = duration;
@@ -11687,20 +11775,22 @@
                 }
             }
 
+            @Px
             public int getDx() {
                 return mDx;
             }
 
-            public void setDx(int dx) {
+            public void setDx(@Px int dx) {
                 mChanged = true;
                 mDx = dx;
             }
 
+            @Px
             public int getDy() {
                 return mDy;
             }
 
-            public void setDy(int dy) {
+            public void setDy(@Px int dy) {
                 mChanged = true;
                 mDy = dy;
             }
@@ -11714,6 +11804,7 @@
                 mDuration = duration;
             }
 
+            @Nullable
             public Interpolator getInterpolator() {
                 return mInterpolator;
             }
@@ -11724,7 +11815,7 @@
              *                     also set the duration.
              * @see #setDuration(int)
              */
-            public void setInterpolator(Interpolator interpolator) {
+            public void setInterpolator(@Nullable Interpolator interpolator) {
                 mChanged = true;
                 mInterpolator = interpolator;
             }
@@ -11737,7 +11828,8 @@
              * @param interpolator Interpolator to be used when calculating scroll position in each
              *                     animation step
              */
-            public void update(int dx, int dy, int duration, Interpolator interpolator) {
+            public void update(@Px int dx, @Px int dy, int duration,
+                    @Nullable Interpolator interpolator) {
                 mDx = dx;
                 mDy = dy;
                 mDuration = duration;
diff --git a/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java b/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
index d2b6a20..578805d 100644
--- a/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
+++ b/v7/recyclerview/src/main/java/android/support/v7/widget/helper/ItemTouchHelper.java
@@ -22,6 +22,7 @@
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.os.Build;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.view.GestureDetectorCompat;
 import android.support.v4.view.ViewCompat;
@@ -112,34 +113,39 @@
     /**
      * A View is currently being swiped.
      */
+    @SuppressWarnings("WeakerAccess")
     public static final int ACTION_STATE_SWIPE = 1;
 
     /**
      * A View is currently being dragged.
      */
+    @SuppressWarnings("WeakerAccess")
     public static final int ACTION_STATE_DRAG = 2;
 
     /**
      * Animation type for views which are swiped successfully.
      */
+    @SuppressWarnings("WeakerAccess")
     public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 1 << 1;
 
     /**
      * Animation type for views which are not completely swiped thus will animate back to their
      * original position.
      */
+    @SuppressWarnings("WeakerAccess")
     public static final int ANIMATION_TYPE_SWIPE_CANCEL = 1 << 2;
 
     /**
      * Animation type for views that were dragged and now will animate to their final position.
      */
+    @SuppressWarnings("WeakerAccess")
     public static final int ANIMATION_TYPE_DRAG = 1 << 3;
 
-    static final String TAG = "ItemTouchHelper";
+    private static final String TAG = "ItemTouchHelper";
 
-    static final boolean DEBUG = false;
+    private static final boolean DEBUG = false;
 
-    static final int ACTIVE_POINTER_ID_NONE = -1;
+    private static final int ACTIVE_POINTER_ID_NONE = -1;
 
     static final int DIRECTION_FLAG_COUNT = 8;
 
@@ -159,7 +165,7 @@
      * This is necessary after swipe dismissing an item. We wait until animator finishes its job
      * to clean these views.
      */
-    final List<View> mPendingCleanup = new ArrayList<View>();
+    final List<View> mPendingCleanup = new ArrayList<>();
 
     /**
      * Re-use array to calculate dx dy for a ViewHolder
@@ -169,63 +175,64 @@
     /**
      * Currently selected view holder
      */
-    ViewHolder mSelected = null;
+    private ViewHolder mSelected = null;
 
     /**
      * The reference coordinates for the action start. For drag & drop, this is the time long
      * press is completed vs for swipe, this is the initial touch point.
      */
-    float mInitialTouchX;
+    private float mInitialTouchX;
 
-    float mInitialTouchY;
+    private float mInitialTouchY;
 
     /**
      * Set when ItemTouchHelper is assigned to a RecyclerView.
      */
-    float mSwipeEscapeVelocity;
+    private float mSwipeEscapeVelocity;
 
     /**
      * Set when ItemTouchHelper is assigned to a RecyclerView.
      */
-    float mMaxSwipeVelocity;
+    private float mMaxSwipeVelocity;
 
     /**
      * The diff between the last event and initial touch.
      */
-    float mDx;
+    private float mDx;
 
-    float mDy;
+    private float mDy;
 
     /**
      * The coordinates of the selected view at the time it is selected. We record these values
      * when action starts so that we can consistently position it even if LayoutManager moves the
      * View.
      */
-    float mSelectedStartX;
+    private float mSelectedStartX;
 
-    float mSelectedStartY;
+    private float mSelectedStartY;
 
     /**
      * The pointer we are tracking.
      */
-    int mActivePointerId = ACTIVE_POINTER_ID_NONE;
+    private int mActivePointerId = ACTIVE_POINTER_ID_NONE;
 
     /**
      * Developer callback which controls the behavior of ItemTouchHelper.
      */
-    Callback mCallback;
+    @NonNull
+    private Callback mCallback;
 
     /**
      * Current mode.
      */
-    int mActionState = ACTION_STATE_IDLE;
+    private int mActionState = ACTION_STATE_IDLE;
 
     /**
      * The direction flags obtained from unmasking
      * {@link Callback#getAbsoluteMovementFlags(RecyclerView, ViewHolder)} for the current
      * action state.
      */
-    int mSelectedFlags;
+    private int mSelectedFlags;
 
     /**
      * When a View is dragged or swiped and needs to go back to where it was, we create a Recover
@@ -234,17 +241,17 @@
      * Using framework animators has the side effect of clashing with ItemAnimator, creating
      * jumpy UIs.
      */
-    List<RecoverAnimation> mRecoverAnimations = new ArrayList<RecoverAnimation>();
+    List<RecoverAnimation> mRecoverAnimations = new ArrayList<>();
 
     private int mSlop;
 
-    RecyclerView mRecyclerView;
+    private RecyclerView mRecyclerView;
 
     /**
      * When user drags a view to the edge, we start scrolling the LayoutManager as long as View
      * is partially out of bounds.
      */
-    final Runnable mScrollRunnable = new Runnable() {
+    private final Runnable mScrollRunnable = new Runnable() {
         @Override
         public void run() {
             if (mSelected != null && scrollIfNecessary()) {
@@ -260,7 +267,7 @@
     /**
      * Used for detecting fling swipe
      */
-    VelocityTracker mVelocityTracker;
+    private VelocityTracker mVelocityTracker;
 
     //re-used list for selecting a swap target
     private List<ViewHolder> mSwapTargets;
@@ -278,19 +285,19 @@
      * until view reaches its final position (end of recover animation), we keep a reference so
      * that it can be drawn above other children.
      */
-    View mOverdrawChild = null;
+    private View mOverdrawChild = null;
 
     /**
      * We cache the position of the overdraw child to avoid recalculating it each time child
      * position callback is called. This value is invalidated whenever a child is attached or
      * detached.
      */
-    int mOverdrawChildPosition = -1;
+    private int mOverdrawChildPosition = -1;
 
     /**
      * Used to detect long press.
      */
-    GestureDetectorCompat mGestureDetector;
+    private GestureDetectorCompat mGestureDetector;
 
     /**
      * Callback for when long press occurs.
@@ -299,7 +306,8 @@
 
     private final OnItemTouchListener mOnItemTouchListener = new OnItemTouchListener() {
         @Override
-        public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event) {
+        public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
+                @NonNull MotionEvent event) {
             mGestureDetector.onTouchEvent(event);
             if (DEBUG) {
                 Log.d(TAG, "intercept: x:" + event.getX() + ",y:" + event.getY() + ", " + event);
@@ -344,7 +352,7 @@
         }
 
         @Override
-        public void onTouchEvent(RecyclerView recyclerView, MotionEvent event) {
+        public void onTouchEvent(@NonNull RecyclerView recyclerView, @NonNull MotionEvent event) {
             mGestureDetector.onTouchEvent(event);
             if (DEBUG) {
                 Log.d(TAG,
@@ -429,7 +437,7 @@
      *
      * @param callback The Callback which controls the behavior of this touch helper.
      */
-    public ItemTouchHelper(Callback callback) {
+    public ItemTouchHelper(@NonNull Callback callback) {
         mCallback = callback;
     }
 
@@ -552,10 +560,10 @@
      * Starts dragging or swiping the given View. Call with null if you want to clear it.
      *
      * @param selected    The ViewHolder to drag or swipe. Can be null if you want to cancel the
-     *                    current action
+     *                    current action, but may not be null if actionState is ACTION_STATE_DRAG.
      * @param actionState The type of action
      */
-    void select(ViewHolder selected, int actionState) {
+    private void select(@Nullable ViewHolder selected, int actionState) {
         if (selected == mSelected && actionState == mActionState) {
             return;
         }
@@ -565,6 +573,10 @@
         endRecoverAnimation(selected, true);
         mActionState = actionState;
         if (actionState == ACTION_STATE_DRAG) {
+            if (selected == null) {
+                throw new IllegalArgumentException("Must pass a ViewHolder when dragging");
+            }
+
             // we remove after animation is complete. this means we only elevate the last drag
             // child but that should perform good enough as it is very hard to start dragging a
             // new child before the previous one settles.
@@ -675,7 +687,7 @@
         mRecyclerView.invalidate();
     }
 
-    void postDispatchSwipe(final RecoverAnimation anim, final int swipeDir) {
+    private void postDispatchSwipe(final RecoverAnimation anim, final int swipeDir) {
         // wait until animations are complete.
         mRecyclerView.post(new Runnable() {
             @Override
@@ -698,7 +710,7 @@
         });
     }
 
-    boolean hasRunningRecoverAnim() {
+    private boolean hasRunningRecoverAnim() {
         final int size = mRecoverAnimations.size();
         for (int i = 0; i < size; i++) {
             if (!mRecoverAnimations.get(i).mEnded) {
@@ -711,7 +723,7 @@
     /**
      * If user drags the view to the edge, trigger a scroll if necessary.
      */
-    boolean scrollIfNecessary() {
+    private boolean scrollIfNecessary() {
         if (mSelected == null) {
             mDragScrollStartTimeInMs = Long.MIN_VALUE;
             return false;
@@ -776,8 +788,8 @@
 
     private List<ViewHolder> findSwapTargets(ViewHolder viewHolder) {
         if (mSwapTargets == null) {
-            mSwapTargets = new ArrayList<ViewHolder>();
-            mDistances = new ArrayList<Integer>();
+            mSwapTargets = new ArrayList<>();
+            mDistances = new ArrayList<>();
         } else {
             mSwapTargets.clear();
             mDistances.clear();
@@ -826,7 +838,7 @@
     /**
      * Checks if we should swap w/ another view holder.
      */
-    void moveIfNecessary(ViewHolder viewHolder) {
+    private void moveIfNecessary(ViewHolder viewHolder) {
         if (mRecyclerView.isLayoutRequested()) {
             return;
         }
@@ -863,11 +875,11 @@
     }
 
     @Override
-    public void onChildViewAttachedToWindow(View view) {
+    public void onChildViewAttachedToWindow(@NonNull View view) {
     }
 
     @Override
-    public void onChildViewDetachedFromWindow(View view) {
+    public void onChildViewDetachedFromWindow(@NonNull View view) {
         removeChildDrawingOrderCallbackIfNecessary(view);
         final ViewHolder holder = mRecyclerView.getChildViewHolder(view);
         if (holder == null) {
@@ -886,7 +898,7 @@
     /**
      * Returns the animation type or 0 if cannot be found.
      */
-    int endRecoverAnimation(ViewHolder viewHolder, boolean override) {
+    private void endRecoverAnimation(ViewHolder viewHolder, boolean override) {
         final int recoverAnimSize = mRecoverAnimations.size();
         for (int i = recoverAnimSize - 1; i >= 0; i--) {
             final RecoverAnimation anim = mRecoverAnimations.get(i);
@@ -896,10 +908,9 @@
                     anim.cancel();
                 }
                 mRecoverAnimations.remove(i);
-                return anim.mAnimationType;
+                return;
             }
         }
-        return 0;
     }
 
     @Override
@@ -908,7 +919,7 @@
         outRect.setEmpty();
     }
 
-    void obtainVelocityTracker() {
+    private void obtainVelocityTracker() {
         if (mVelocityTracker != null) {
             mVelocityTracker.recycle();
         }
@@ -951,17 +962,17 @@
     /**
      * Checks whether we should select a View for swiping.
      */
-    boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
+    private void checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
         if (mSelected != null || action != MotionEvent.ACTION_MOVE
                 || mActionState == ACTION_STATE_DRAG || !mCallback.isItemViewSwipeEnabled()) {
-            return false;
+            return;
         }
         if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
-            return false;
+            return;
         }
         final ViewHolder vh = findSwipedView(motionEvent);
         if (vh == null) {
-            return false;
+            return;
         }
         final int movementFlags = mCallback.getAbsoluteMovementFlags(mRecyclerView, vh);
 
@@ -969,7 +980,7 @@
                 >> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE);
 
         if (swipeFlags == 0) {
-            return false;
+            return;
         }
 
         // mDx and mDy are only set in allowed directions. We use custom x/y here instead of
@@ -986,30 +997,29 @@
         final float absDy = Math.abs(dy);
 
         if (absDx < mSlop && absDy < mSlop) {
-            return false;
+            return;
         }
         if (absDx > absDy) {
             if (dx < 0 && (swipeFlags & LEFT) == 0) {
-                return false;
+                return;
             }
             if (dx > 0 && (swipeFlags & RIGHT) == 0) {
-                return false;
+                return;
             }
         } else {
             if (dy < 0 && (swipeFlags & UP) == 0) {
-                return false;
+                return;
             }
             if (dy > 0 && (swipeFlags & DOWN) == 0) {
-                return false;
+                return;
             }
         }
         mDx = mDy = 0f;
         mActivePointerId = motionEvent.getPointerId(0);
         select(vh, ACTION_STATE_SWIPE);
-        return true;
     }
 
-    View findChildView(MotionEvent event) {
+    private View findChildView(MotionEvent event) {
         // first check elevated views, if none, then call RV
         final float x = event.getX();
         final float y = event.getY();
@@ -1063,7 +1073,7 @@
      *                   RecyclerView.
      * @see ItemTouchHelper.Callback#isItemViewSwipeEnabled()
      */
-    public void startDrag(ViewHolder viewHolder) {
+    public void startDrag(@NonNull ViewHolder viewHolder) {
         if (!mCallback.hasDragFlag(mRecyclerView, viewHolder)) {
             Log.e(TAG, "Start drag has been called but dragging is not enabled");
             return;
@@ -1110,7 +1120,7 @@
      * @param viewHolder The ViewHolder to start swiping. It must be a direct child of
      *                   RecyclerView.
      */
-    public void startSwipe(ViewHolder viewHolder) {
+    public void startSwipe(@NonNull ViewHolder viewHolder) {
         if (!mCallback.hasSwipeFlag(mRecyclerView, viewHolder)) {
             Log.e(TAG, "Start swipe has been called but swiping is not enabled");
             return;
@@ -1125,7 +1135,7 @@
         select(viewHolder, ACTION_STATE_SWIPE);
     }
 
-    RecoverAnimation findAnimation(MotionEvent event) {
+    private RecoverAnimation findAnimation(MotionEvent event) {
         if (mRecoverAnimations.isEmpty()) {
             return null;
         }
@@ -1139,7 +1149,7 @@
         return null;
     }
 
-    void updateDxDy(MotionEvent ev, int directionFlags, int pointerIndex) {
+    private void updateDxDy(MotionEvent ev, int directionFlags, int pointerIndex) {
         final float x = ev.getX(pointerIndex);
         final float y = ev.getY(pointerIndex);
 
@@ -1285,7 +1295,7 @@
         mRecyclerView.setChildDrawingOrderCallback(mChildDrawingOrderCallback);
     }
 
-    void removeChildDrawingOrderCallbackIfNecessary(View view) {
+    private void removeChildDrawingOrderCallbackIfNecessary(View view) {
         if (view == mOverdrawChild) {
             mOverdrawChild = null;
             // only remove if we've added
@@ -1312,15 +1322,15 @@
          * making layout stay consistent.
          *
          * @param view   The View which is being dragged. It is very likely that user is still
-         *               dragging this View so there might be other
-         *               {@link #prepareForDrop(View, View, int, int)} after this one.
+         *               dragging this View so there might be other calls to
+         *               {@code prepareForDrop()} after this one.
          * @param target The target view which is being dropped on.
          * @param x      The <code>left</code> offset of the View that is being dragged. This value
          *               includes the movement caused by the user.
          * @param y      The <code>top</code> offset of the View that is being dragged. This value
          *               includes the movement caused by the user.
          */
-        void prepareForDrop(View view, View target, int x, int y);
+        void prepareForDrop(@NonNull View view, @NonNull View target, int x, int y);
     }
 
     /**
@@ -1356,8 +1366,10 @@
     @SuppressWarnings("UnusedParameters")
     public abstract static class Callback {
 
+        @SuppressWarnings("WeakerAccess")
         public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200;
 
+        @SuppressWarnings("WeakerAccess")
         public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250;
 
         static final int RELATIVE_DIR_FLAGS = START | END
@@ -1440,6 +1452,8 @@
          *
          * @return The {@link ItemTouchUIUtil} instance that is used by the {@link Callback}
          */
+        @SuppressWarnings("WeakerAccess")
+        @NonNull
         public static ItemTouchUIUtil getDefaultUIUtil() {
             return sUICallback;
         }
@@ -1455,6 +1469,7 @@
          * of {@link #LEFT}, {@link #RIGHT}.
          * @see #convertToAbsoluteDirection(int, int)
          */
+        @SuppressWarnings("WeakerAccess")
         public static int convertToRelativeDirection(int flags, int layoutDirection) {
             int masked = flags & ABS_HORIZONTAL_DIR_FLAGS;
             if (masked == 0) {
@@ -1501,6 +1516,7 @@
          *                    {@link #RIGHT}, {@link #LEFT} {@link #START} and {@link #END}.
          * @return And integer that represents the given directions in the provided actionState.
          */
+        @SuppressWarnings("WeakerAccess")
         public static int makeFlag(int actionState, int directions) {
             return directions << (actionState * DIRECTION_FLAG_COUNT);
         }
@@ -1532,8 +1548,8 @@
          * @see #makeMovementFlags(int, int)
          * @see #makeFlag(int, int)
          */
-        public abstract int getMovementFlags(RecyclerView recyclerView,
-                ViewHolder viewHolder);
+        public abstract int getMovementFlags(@NonNull RecyclerView recyclerView,
+                @NonNull ViewHolder viewHolder);
 
         /**
          * Converts a given set of flags to absolution direction which means {@link #START} and
@@ -1544,6 +1560,7 @@
          * @param layoutDirection The layout direction of the RecyclerView.
          * @return Updated flags which includes only absolute direction values.
          */
+        @SuppressWarnings("WeakerAccess")
         public int convertToAbsoluteDirection(int flags, int layoutDirection) {
             int masked = flags & RELATIVE_DIR_FLAGS;
             if (masked == 0) {
@@ -1595,8 +1612,9 @@
          * @return True if the dragged ViewHolder can be replaced with the target ViewHolder, false
          * otherwise.
          */
-        public boolean canDropOver(RecyclerView recyclerView, ViewHolder current,
-                ViewHolder target) {
+        @SuppressWarnings("WeakerAccess")
+        public boolean canDropOver(@NonNull RecyclerView recyclerView, @NonNull ViewHolder current,
+                @NonNull ViewHolder target) {
             return true;
         }
 
@@ -1619,8 +1637,8 @@
          * {@code target}.
          * @see #onMoved(RecyclerView, ViewHolder, int, ViewHolder, int, int, int)
          */
-        public abstract boolean onMove(RecyclerView recyclerView,
-                ViewHolder viewHolder, ViewHolder target);
+        public abstract boolean onMove(@NonNull RecyclerView recyclerView,
+                @NonNull ViewHolder viewHolder, @NonNull ViewHolder target);
 
         /**
          * Returns whether ItemTouchHelper should start a drag and drop operation if an item is
@@ -1659,6 +1677,7 @@
          *
          * @return The extra margin to be added to the hit box of the dragged View.
          */
+        @SuppressWarnings("WeakerAccess")
         public int getBoundingBoxMargin() {
             return 0;
         }
@@ -1674,7 +1693,8 @@
          * @return A float value that denotes the fraction of the View size. Default value
          * is .5f .
          */
-        public float getSwipeThreshold(ViewHolder viewHolder) {
+        @SuppressWarnings("WeakerAccess")
+        public float getSwipeThreshold(@NonNull ViewHolder viewHolder) {
             return .5f;
         }
 
@@ -1687,7 +1707,8 @@
          * @return A float value that denotes the fraction of the View size. Default value is
          * .5f .
          */
-        public float getMoveThreshold(ViewHolder viewHolder) {
+        @SuppressWarnings("WeakerAccess")
+        public float getMoveThreshold(@NonNull ViewHolder viewHolder) {
             return .5f;
         }
 
@@ -1712,6 +1733,7 @@
          * @see #getSwipeVelocityThreshold(float)
          * @see #getSwipeThreshold(ViewHolder)
          */
+        @SuppressWarnings("WeakerAccess")
         public float getSwipeEscapeVelocity(float defaultValue) {
             return defaultValue;
         }
@@ -1735,6 +1757,7 @@
          * <code>defaultValue</code> parameter.
          * @see #getSwipeEscapeVelocity(float)
          */
+        @SuppressWarnings("WeakerAccess")
         public float getSwipeVelocityThreshold(float defaultValue) {
             return defaultValue;
         }
@@ -1765,8 +1788,9 @@
          * @return A ViewHolder to whose position the dragged ViewHolder should be
          * moved to.
          */
-        public ViewHolder chooseDropTarget(ViewHolder selected,
-                List<ViewHolder> dropTargets, int curX, int curY) {
+        @SuppressWarnings("WeakerAccess")
+        public ViewHolder chooseDropTarget(@NonNull ViewHolder selected,
+                @NonNull List<ViewHolder> dropTargets, int curX, int curY) {
             int right = curX + selected.itemView.getWidth();
             int bottom = curY + selected.itemView.getHeight();
             ViewHolder winner = null;
@@ -1845,7 +1869,7 @@
          *                   `direction` will be relative as well. ({@link #START} or {@link
          *                   #END}).
          */
-        public abstract void onSwiped(ViewHolder viewHolder, int direction);
+        public abstract void onSwiped(@NonNull ViewHolder viewHolder, int direction);
 
         /**
          * Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed.
@@ -1859,7 +1883,7 @@
          *                    {@link ItemTouchHelper#ACTION_STATE_DRAG}.
          * @see #clearView(RecyclerView, RecyclerView.ViewHolder)
          */
-        public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
+        public void onSelectedChanged(@Nullable ViewHolder viewHolder, int actionState) {
             if (viewHolder != null) {
                 sUICallback.onSelected(viewHolder.itemView);
             }
@@ -1906,9 +1930,9 @@
          *                     are applied. This value does not include margins added by
          *                     {@link RecyclerView.ItemDecoration}s.
          */
-        public void onMoved(final RecyclerView recyclerView,
-                final ViewHolder viewHolder, int fromPos, final ViewHolder target, int toPos, int x,
-                int y) {
+        public void onMoved(@NonNull final RecyclerView recyclerView,
+                @NonNull final ViewHolder viewHolder, int fromPos, @NonNull final ViewHolder target,
+                int toPos, int x, int y) {
             final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
             if (layoutManager instanceof ViewDropHandler) {
                 ((ViewDropHandler) layoutManager).prepareForDrop(viewHolder.itemView,
@@ -2002,7 +2026,7 @@
          * @param recyclerView The RecyclerView which is controlled by the ItemTouchHelper.
          * @param viewHolder   The View that was interacted by the user.
          */
-        public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
+        public void clearView(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder) {
             sUICallback.clearView(viewHolder.itemView);
         }
 
@@ -2033,8 +2057,8 @@
          * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
          * boolean)
          */
-        public void onChildDraw(Canvas c, RecyclerView recyclerView,
-                ViewHolder viewHolder,
+        public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
+                @NonNull ViewHolder viewHolder,
                 float dX, float dY, int actionState, boolean isCurrentlyActive) {
             sUICallback.onDraw(c, recyclerView, viewHolder.itemView, dX, dY, actionState,
                     isCurrentlyActive);
@@ -2067,7 +2091,7 @@
          * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int,
          * boolean)
          */
-        public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
+        public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView,
                 ViewHolder viewHolder,
                 float dX, float dY, int actionState, boolean isCurrentlyActive) {
             sUICallback.onDrawOver(c, recyclerView, viewHolder.itemView, dX, dY, actionState,
@@ -2094,7 +2118,8 @@
          * @param animateDy     The vertical distance that the animation will offset
          * @return The duration for the animation
          */
-        public long getAnimationDuration(RecyclerView recyclerView, int animationType,
+        @SuppressWarnings("WeakerAccess")
+        public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType,
                 float animateDx, float animateDy) {
             final RecyclerView.ItemAnimator itemAnimator = recyclerView.getItemAnimator();
             if (itemAnimator == null) {
@@ -2126,7 +2151,8 @@
          * @return The amount that RecyclerView should scroll. Keep in mind that this value will
          * be passed to {@link RecyclerView#scrollBy(int, int)} method.
          */
-        public int interpolateOutOfBoundsScroll(RecyclerView recyclerView,
+        @SuppressWarnings("WeakerAccess")
+        public int interpolateOutOfBoundsScroll(@NonNull RecyclerView recyclerView,
                 int viewSize, int viewSizeOutOfBounds,
                 int totalSize, long msSinceStartScroll) {
             final int maxScroll = getMaxDragScroll(recyclerView);
@@ -2207,7 +2233,8 @@
          *
          * @param defaultSwipeDirs Binary OR of directions in which the ViewHolders can be swiped.
          */
-        public void setDefaultSwipeDirs(int defaultSwipeDirs) {
+        @SuppressWarnings({"WeakerAccess", "unused"})
+        public void setDefaultSwipeDirs(@SuppressWarnings("unused") int defaultSwipeDirs) {
             mDefaultSwipeDirs = defaultSwipeDirs;
         }
 
@@ -2217,7 +2244,8 @@
          *
          * @param defaultDragDirs Binary OR of directions in which the ViewHolders can be dragged.
          */
-        public void setDefaultDragDirs(int defaultDragDirs) {
+        @SuppressWarnings({"WeakerAccess", "unused"})
+        public void setDefaultDragDirs(@SuppressWarnings("unused") int defaultDragDirs) {
             mDefaultDragDirs = defaultDragDirs;
         }
 
@@ -2227,10 +2255,12 @@
          * {@link #setDefaultSwipeDirs(int)}.
          *
          * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to.
-         * @param viewHolder   The RecyclerView for which the swipe direction is queried.
+         * @param viewHolder   The ViewHolder for which the swipe direction is queried.
          * @return A binary OR of direction flags.
          */
-        public int getSwipeDirs(RecyclerView recyclerView, ViewHolder viewHolder) {
+        @SuppressWarnings("WeakerAccess")
+        public int getSwipeDirs(@SuppressWarnings("unused") @NonNull RecyclerView recyclerView,
+                @NonNull @SuppressWarnings("unused") ViewHolder viewHolder) {
             return mDefaultSwipeDirs;
         }
 
@@ -2240,15 +2270,18 @@
          * {@link #setDefaultDragDirs(int)}.
          *
          * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to.
-         * @param viewHolder   The RecyclerView for which the swipe direction is queried.
+         * @param viewHolder   The ViewHolder for which the swipe direction is queried.
          * @return A binary OR of direction flags.
          */
-        public int getDragDirs(RecyclerView recyclerView, ViewHolder viewHolder) {
+        @SuppressWarnings("WeakerAccess")
+        public int getDragDirs(@SuppressWarnings("unused") @NonNull RecyclerView recyclerView,
+                @SuppressWarnings("unused") @NonNull ViewHolder viewHolder) {
             return mDefaultDragDirs;
         }
 
         @Override
-        public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
+        public int getMovementFlags(@NonNull RecyclerView recyclerView,
+                @NonNull ViewHolder viewHolder) {
             return makeMovementFlags(getDragDirs(recyclerView, viewHolder),
                     getSwipeDirs(recyclerView, viewHolder));
         }
@@ -2342,7 +2375,7 @@
 
         final int mAnimationType;
 
-        public boolean mIsPendingCleanup;
+        boolean mIsPendingCleanup;
 
         float mX;
 
diff --git a/v7/recyclerview/src/test/NO_DOCS b/v7/recyclerview/src/test/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/v7/recyclerview/src/test/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/v7/recyclerview/tests/NO_DOCS b/v7/recyclerview/tests/NO_DOCS
deleted file mode 100644
index 0c81e4a..0000000
--- a/v7/recyclerview/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/v7/recyclerview/tests/src/android/support/v7/recyclerview/extensions/AsyncListDifferTest.kt b/v7/recyclerview/tests/src/android/support/v7/recyclerview/extensions/AsyncListDifferTest.kt
deleted file mode 100644
index d5a60db..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/recyclerview/extensions/AsyncListDifferTest.kt
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.recyclerview.extensions
-
-import android.support.test.filters.SmallTest
-import android.support.v7.util.DiffUtil
-import android.support.v7.util.ListUpdateCallback
-import org.junit.Assert.assertEquals
-import org.junit.Assert.assertNotSame
-import org.junit.Assert.assertSame
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.Mockito.verifyZeroInteractions
-import java.lang.UnsupportedOperationException
-import java.util.Collections.emptyList
-import java.util.LinkedList
-import java.util.concurrent.Executor
-
-class TestExecutor : Executor {
-    private val mTasks = LinkedList<Runnable>()
-
-    override fun execute(command: Runnable) {
-        mTasks.add(command)
-    }
-
-    fun executeAll(): Boolean {
-        val consumed = !mTasks.isEmpty()
-
-        var task = mTasks.poll()
-        while (task != null) {
-            task.run()
-            task = mTasks.poll()
-        }
-        return consumed
-    }
-}
-
-@SmallTest
-@RunWith(JUnit4::class)
-class AsyncListDifferTest {
-    private val mMainThread = TestExecutor()
-    private val mBackgroundThread = TestExecutor()
-
-    private fun <T> createHelper(listUpdateCallback: ListUpdateCallback,
-            diffCallback: DiffUtil.ItemCallback<T>): AsyncListDiffer<T> {
-        return AsyncListDiffer(listUpdateCallback,
-                AsyncDifferConfig.Builder<T>(diffCallback)
-                        .setMainThreadExecutor(mMainThread)
-                        .setBackgroundThreadExecutor(mBackgroundThread)
-                        .build())
-    }
-
-    @Test
-    fun initialState() {
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-        assertEquals(0, helper.currentList.size)
-        verifyZeroInteractions(callback)
-    }
-
-    @Test(expected = IndexOutOfBoundsException::class)
-    fun getEmpty() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.currentList[0]
-    }
-
-    @Test(expected = IndexOutOfBoundsException::class)
-    fun getNegative() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.submitList(listOf("a", "b"))
-        helper.currentList[-1]
-    }
-
-    @Test(expected = IndexOutOfBoundsException::class)
-    fun getPastEnd() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.submitList(listOf("a", "b"))
-        helper.currentList[2]
-    }
-
-    fun getCurrentList() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-
-        // null is emptyList
-        assertSame(emptyList<String>(), helper.currentList)
-
-        // other list is wrapped
-        val list = listOf("a", "b")
-        helper.submitList(list)
-        assertEquals(list, helper.currentList)
-        assertNotSame(list, helper.currentList)
-
-        // null again, empty again
-        helper.submitList(null)
-        assertSame(emptyList<String>(), helper.currentList)
-    }
-
-    @Test(expected = UnsupportedOperationException::class)
-    fun mutateCurrentListEmpty() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.currentList[0] = ""
-    }
-
-    @Test(expected = UnsupportedOperationException::class)
-    fun mutateCurrentListNonEmpty() {
-        val helper = createHelper(IGNORE_CALLBACK, STRING_DIFF_CALLBACK)
-        helper.submitList(listOf("a"))
-        helper.currentList[0] = ""
-    }
-
-    @Test
-    fun submitListSimple() {
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-
-        helper.submitList(listOf("a", "b"))
-
-        assertEquals(2, helper.currentList.size)
-        assertEquals("a", helper.currentList[0])
-        assertEquals("b", helper.currentList[1])
-
-        verify(callback).onInserted(0, 2)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-    }
-
-    @Test
-    fun submitListUpdate() {
-        val callback = mock(ListUpdateCallback::class.java)
-        val helper = createHelper(callback, STRING_DIFF_CALLBACK)
-
-        // initial list (immediate)
-        helper.submitList(listOf("a", "b"))
-        verify(callback).onInserted(0, 2)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-
-        // update (deferred)
-        helper.submitList(listOf("a", "b", "c"))
-        verifyNoMoreInteractions(callback)
-        drain()
-        verify(callback).onInserted(2, 1)
-        verifyNoMoreInteractions(callback)
-
-        // clear (immediate)
-        helper.submitList(null)
-        verify(callback).onRemoved(0, 3)
-        verifyNoMoreInteractions(callback)
-        drain()
-        verifyNoMoreInteractions(callback)
-    }
-
-    private fun drain() {
-        var executed: Boolean
-        do {
-            executed = mBackgroundThread.executeAll()
-            executed = mMainThread.executeAll() or executed
-        } while (executed)
-    }
-
-    companion object {
-        private val STRING_DIFF_CALLBACK = object : DiffUtil.ItemCallback<String>() {
-            override fun areItemsTheSame(oldItem: String, newItem: String): Boolean {
-                return oldItem == newItem
-            }
-
-            override fun areContentsTheSame(oldItem: String, newItem: String): Boolean {
-                return oldItem == newItem
-            }
-        }
-
-        private val IGNORE_CALLBACK = object : ListUpdateCallback {
-            override fun onInserted(position: Int, count: Int) {}
-
-            override fun onRemoved(position: Int, count: Int) {}
-
-            override fun onMoved(fromPosition: Int, toPosition: Int) {}
-
-            override fun onChanged(position: Int, count: Int, payload: Any) {}
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
deleted file mode 100644
index 3ac53f4..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/AsyncListUtilLayoutTest.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import android.content.Context;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.util.AsyncListUtil;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.BitSet;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class AsyncListUtilLayoutTest extends BaseRecyclerViewInstrumentationTest {
-
-    private static final boolean DEBUG = false;
-
-    private static final String TAG = "AsyncListUtilLayoutTest";
-
-    private static final int ITEM_COUNT = 1000;
-    private static final int TILE_SIZE = 5;
-
-    AsyncTestAdapter mAdapter;
-
-    WrappedLinearLayoutManager mLayoutManager;
-
-    private TestDataCallback mDataCallback;
-    private TestViewCallback mViewCallback;
-    private AsyncListUtil<String> mAsyncListUtil;
-
-    public int mStartPrefetch = 0;
-    public int mEndPrefetch = 0;
-
-    // Test is disabled as it is flaky.
-    @Suppress
-    @Test
-    public void asyncListUtil() throws Throwable {
-        mRecyclerView = inflateWrappedRV();
-        mRecyclerView.setHasFixedSize(true);
-
-        mAdapter = new AsyncTestAdapter();
-        mRecyclerView.setAdapter(mAdapter);
-
-        mLayoutManager = new WrappedLinearLayoutManager(
-                getActivity(), LinearLayoutManager.VERTICAL, false);
-        mRecyclerView.setLayoutManager(mLayoutManager);
-
-        mLayoutManager.expectLayouts(1);
-        setRecyclerView(mRecyclerView);
-        mLayoutManager.waitForLayout(2);
-
-        int rangeStart = 0;
-        assertEquals(rangeStart, mLayoutManager.findFirstVisibleItemPosition());
-
-        final int rangeSize = mLayoutManager.findLastVisibleItemPosition() + 1;
-        assertTrue("No visible items", rangeSize > 0);
-
-        assertEquals("All visible items must be empty at first",
-                rangeSize, getEmptyVisibleChildCount());
-
-        mDataCallback = new TestDataCallback();
-        mViewCallback = new TestViewCallback();
-
-        mDataCallback.expectTilesInRange(rangeStart, rangeSize);
-        mAdapter.expectItemsInRange(rangeStart, rangeSize);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mAsyncListUtil = new AsyncListUtil<>(
-                        String.class, TILE_SIZE, mDataCallback, mViewCallback);
-            }
-        });
-
-        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                mAsyncListUtil.onRangeChanged();
-            }
-        });
-        assertAllLoaded("First load");
-
-        rangeStart = roundUp(rangeSize);
-        scrollAndAssert("Scroll with no prefetch", rangeStart, rangeSize);
-
-        rangeStart = roundUp(rangeStart + rangeSize);
-        mEndPrefetch = TILE_SIZE * 2;
-        scrollAndAssert("Scroll with prefetch", rangeStart, rangeSize);
-
-        rangeStart += mEndPrefetch;
-        mEndPrefetch = 0;
-        scrollAndAssert("Scroll a little down, no prefetch", rangeStart, 0);
-
-        rangeStart = ITEM_COUNT / 2;
-        mStartPrefetch = TILE_SIZE * 2;
-        mEndPrefetch = TILE_SIZE * 3;
-        scrollAndAssert("Scroll to middle, prefetch", rangeStart, rangeSize);
-
-        rangeStart -= mStartPrefetch;
-        mStartPrefetch = 0;
-        mEndPrefetch = 0;
-        scrollAndAssert("Scroll a little up, no prefetch", rangeStart, 0);
-
-        Thread.sleep(500);  // Wait for possible spurious messages.
-    }
-
-    private void assertAllLoaded(String context) throws InterruptedException {
-        assertTrue(context + ", timed out while waiting for items", mAdapter.waitForItems(10));
-        assertTrue(context + ", timed out while waiting for tiles", mDataCallback.waitForTiles(10));
-        assertEquals(context + ", empty child found", 0, getEmptyVisibleChildCount());
-    }
-
-    private void scrollAndAssert(String context, int rangeStart, int rangeSize) throws Throwable {
-        if (rangeSize > 0) {
-            mDataCallback.expectTilesInRange(rangeStart, rangeSize);
-        } else {
-            mDataCallback.expectNoNewTilesLoaded();
-        }
-        mAdapter.expectItemsInRange(rangeStart, rangeSize);
-        mLayoutManager.expectLayouts(1);
-        scrollToPositionWithOffset(rangeStart, 0);
-        mLayoutManager.waitForLayout(1);
-        assertAllLoaded(context);
-    }
-
-    void scrollToPositionWithOffset(final int position, final int offset) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mLayoutManager.scrollToPositionWithOffset(position, offset);
-            }
-        });
-    }
-
-    private int roundUp(int value) {
-        return value - value % TILE_SIZE + TILE_SIZE;
-    }
-
-    private int getTileCount(int start, int size) {
-        return ((start + size - 1) / TILE_SIZE) - (start / TILE_SIZE) + 1;
-    }
-
-    private int getEmptyVisibleChildCount() {
-        int emptyChildCount = 0;
-        int firstVisible = mLayoutManager.findFirstVisibleItemPosition();
-        int lastVisible = mLayoutManager.findLastVisibleItemPosition();
-        for (int i = firstVisible; i <= lastVisible; i++) {
-            View child = mLayoutManager.findViewByPosition(i);
-            assertTrue(child instanceof TextView);
-            if (((TextView) child).getText() == "") {
-                emptyChildCount++;
-            }
-        }
-        return emptyChildCount;
-    }
-
-    private class TestDataCallback extends AsyncListUtil.DataCallback<String> {
-
-        private CountDownLatch mTilesLatch;
-
-        @Override
-        public void fillData(String[] data, int startPosition, int itemCount) {
-            assertTrue("Unexpected tile load @" + startPosition, mTilesLatch.getCount() > 0);
-            try {
-                Thread.sleep(100);
-            } catch (InterruptedException e) {
-            }
-            for (int i = 0; i < itemCount; i++) {
-                data[i] = "Item #" + (startPosition + i);
-            }
-            mTilesLatch.countDown();
-        }
-
-        @Override
-        public int refreshData() {
-            return ITEM_COUNT;
-        }
-
-        private void expectTiles(int count) {
-            mTilesLatch = new CountDownLatch(count);
-        }
-
-        public void expectTilesInRange(int rangeStart, int rangeSize) {
-            expectTiles(getTileCount(rangeStart - mStartPrefetch,
-                    rangeSize + mStartPrefetch + mEndPrefetch));
-        }
-
-        public void expectNoNewTilesLoaded() {
-            expectTiles(0);
-        }
-
-        public boolean waitForTiles(long timeoutInSeconds) throws InterruptedException {
-            return mTilesLatch.await(timeoutInSeconds, TimeUnit.SECONDS);
-        }
-    }
-
-    private class TestViewCallback extends AsyncListUtil.ViewCallback {
-        @Override
-        public void getItemRangeInto(int[] outRange) {
-            outRange[0] = mLayoutManager.findFirstVisibleItemPosition();
-            outRange[1] = mLayoutManager.findLastVisibleItemPosition();
-        }
-
-        @Override
-        public void extendRangeInto(int[] range, int[] outRange, int scrollHint) {
-            outRange[0] = range[0] - mStartPrefetch;
-            outRange[1] = range[1] + mEndPrefetch;
-        }
-
-        @Override
-        public void onDataRefresh() {
-            mRecyclerView.getAdapter().notifyDataSetChanged();
-        }
-
-        @Override
-        public void onItemLoaded(int position) {
-            mRecyclerView.getAdapter().notifyItemChanged(position);
-        }
-    }
-
-    private static class SimpleViewHolder extends RecyclerView.ViewHolder {
-
-        public SimpleViewHolder(Context context) {
-            super(new TextView(context));
-        }
-    }
-
-    private class AsyncTestAdapter extends RecyclerView.Adapter<SimpleViewHolder> {
-
-        private BitSet mLoadedPositions;
-        private BitSet mExpectedPositions;
-
-        private CountDownLatch mItemsLatch;
-        public AsyncTestAdapter() {
-            mLoadedPositions = new BitSet(ITEM_COUNT);
-        }
-
-        @Override
-        public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new SimpleViewHolder(parent.getContext());
-        }
-
-        @Override
-        public void onBindViewHolder(SimpleViewHolder holder, int position) {
-            final String item = mAsyncListUtil == null ? null : mAsyncListUtil.getItem(position);
-            ((TextView) (holder.itemView)).setText(item == null ? "" : item);
-
-            if (item != null) {
-                mLoadedPositions.set(position);
-                if (mExpectedPositions.get(position)) {
-                    mExpectedPositions.clear(position);
-                    if (mExpectedPositions.cardinality() == 0) {
-                        mItemsLatch.countDown();
-                    }
-                }
-            }
-        }
-
-        @Override
-        public int getItemCount() {
-            return ITEM_COUNT;
-        }
-
-        private void expectItemsInRange(int rangeStart, int rangeSize) {
-            mExpectedPositions = new BitSet(rangeStart + rangeSize);
-            for (int i = 0; i < rangeSize; i++) {
-                if (!mLoadedPositions.get(rangeStart + i)) {
-                    mExpectedPositions.set(rangeStart + i);
-                }
-            }
-            mItemsLatch = new CountDownLatch(1);
-            if (mExpectedPositions.cardinality() == 0) {
-                mItemsLatch.countDown();
-            }
-        }
-
-        public boolean waitForItems(long timeoutInSeconds) throws InterruptedException {
-            return mItemsLatch.await(timeoutInSeconds, TimeUnit.SECONDS);
-        }
-    }
-
-    class WrappedLinearLayoutManager extends LinearLayoutManager {
-
-        CountDownLatch mLayoutLatch;
-
-        public WrappedLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
-            super(context, orientation, reverseLayout);
-        }
-
-        public void expectLayouts(int count) {
-            mLayoutLatch = new CountDownLatch(count);
-        }
-
-        public void waitForLayout(int seconds) throws Throwable {
-            mLayoutLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
-            checkForMainThreadException();
-            MatcherAssert.assertThat("all layouts should complete on time",
-                    mLayoutLatch.getCount(), CoreMatchers.is(0L));
-            // use a runnable to ensure RV layout is finished
-            getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                }
-            });
-        }
-
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            try {
-                super.onLayoutChildren(recycler, state);
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-            mLayoutLatch.countDown();
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/AttachDetachCollector.java b/v7/recyclerview/tests/src/android/support/v7/widget/AttachDetachCollector.java
deleted file mode 100644
index 12281ae..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/AttachDetachCollector.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v7.widget;
-
-
-import android.view.View;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Simple class that can collect list of view attach and detach events so that we can assert on them
- */
-public class AttachDetachCollector implements RecyclerView.OnChildAttachStateChangeListener {
-    private final List<View> mAttached = new ArrayList<>();
-    private final List<View> mDetached = new ArrayList<>();
-
-    public AttachDetachCollector(RecyclerView recyclerView) {
-        recyclerView.addOnChildAttachStateChangeListener(this);
-    }
-
-    @Override
-    public void onChildViewAttachedToWindow(View view) {
-        mAttached.add(view);
-    }
-
-    @Override
-    public void onChildViewDetachedFromWindow(View view) {
-        mDetached.add(view);
-    }
-
-    public void reset() {
-        mAttached.clear();
-        mDetached.clear();
-    }
-
-    public List<View> getAttached() {
-        return mAttached;
-    }
-
-    public List<View> getDetached() {
-        return mDetached;
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
deleted file mode 100644
index eed7d20..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ /dev/null
@@ -1,1311 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import android.app.Instrumentation;
-import android.graphics.Rect;
-import android.os.Looper;
-import android.support.annotation.Nullable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
-import android.support.testutils.PollingCheck;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.recyclerview.test.R;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-abstract public class BaseRecyclerViewInstrumentationTest {
-
-    private static final String TAG = "RecyclerViewTest";
-
-    private boolean mDebug;
-
-    protected RecyclerView mRecyclerView;
-
-    protected AdapterHelper mAdapterHelper;
-
-    private Throwable mMainThreadException;
-
-    private boolean mIgnoreMainThreadException = false;
-
-    Thread mInstrumentationThread;
-
-    @Rule
-    public ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule(TestActivity.class);
-
-    public BaseRecyclerViewInstrumentationTest() {
-        this(false);
-    }
-
-    public BaseRecyclerViewInstrumentationTest(boolean debug) {
-        mDebug = debug;
-    }
-
-    void checkForMainThreadException() throws Throwable {
-        if (!mIgnoreMainThreadException && mMainThreadException != null) {
-            throw mMainThreadException;
-        }
-    }
-
-    public void setIgnoreMainThreadException(boolean ignoreMainThreadException) {
-        mIgnoreMainThreadException = ignoreMainThreadException;
-    }
-
-    public Throwable getMainThreadException() {
-        return mMainThreadException;
-    }
-
-    protected TestActivity getActivity() {
-        return mActivityRule.getActivity();
-    }
-
-    @Before
-    public final void setUpInsThread() throws Exception {
-        mInstrumentationThread = Thread.currentThread();
-        Item.idCounter.set(0);
-    }
-
-    void setHasTransientState(final View view, final boolean value) {
-        try {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    ViewCompat.setHasTransientState(view, value);
-                }
-            });
-        } catch (Throwable throwable) {
-            Log.e(TAG, "", throwable);
-        }
-    }
-
-    public boolean canReUseActivity() {
-        return true;
-    }
-
-    protected void enableAccessibility()
-            throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
-        Method getUIAutomation = Instrumentation.class.getMethod("getUiAutomation");
-        getUIAutomation.invoke(InstrumentationRegistry.getInstrumentation());
-    }
-
-    void setAdapter(final RecyclerView.Adapter adapter) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setAdapter(adapter);
-            }
-        });
-    }
-
-    public View focusSearch(final View focused, final int direction) throws Throwable {
-        return focusSearch(focused, direction, false);
-    }
-
-    public View focusSearch(final View focused, final int direction, boolean waitForScroll)
-            throws Throwable {
-        final View[] result = new View[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                View view = focused.focusSearch(direction);
-                if (view != null && view != focused) {
-                    view.requestFocus();
-                }
-                result[0] = view;
-            }
-        });
-        if (waitForScroll && (result[0] != null)) {
-            waitForIdleScroll(mRecyclerView);
-        }
-        return result[0];
-    }
-
-    protected WrappedRecyclerView inflateWrappedRV() {
-        return (WrappedRecyclerView)
-                LayoutInflater.from(getActivity()).inflate(R.layout.wrapped_test_rv,
-                        getRecyclerViewContainer(), false);
-    }
-
-    void swapAdapter(final RecyclerView.Adapter adapter,
-            final boolean removeAndRecycleExistingViews) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mRecyclerView.swapAdapter(adapter, removeAndRecycleExistingViews);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        });
-        checkForMainThreadException();
-    }
-
-    void postExceptionToInstrumentation(Throwable t) {
-        if (mInstrumentationThread == Thread.currentThread()) {
-            throw new RuntimeException(t);
-        }
-        if (mMainThreadException != null) {
-            Log.e(TAG, "receiving another main thread exception. dropping.", t);
-        } else {
-            Log.e(TAG, "captured exception on main thread", t);
-            mMainThreadException = t;
-        }
-
-        if (mRecyclerView != null && mRecyclerView
-                .getLayoutManager() instanceof TestLayoutManager) {
-            TestLayoutManager lm = (TestLayoutManager) mRecyclerView.getLayoutManager();
-            // finish all layouts so that we get the correct exception
-            if (lm.layoutLatch != null) {
-                while (lm.layoutLatch.getCount() > 0) {
-                    lm.layoutLatch.countDown();
-                }
-            }
-        }
-    }
-
-    public Instrumentation getInstrumentation() {
-        return InstrumentationRegistry.getInstrumentation();
-    }
-
-    @After
-    public final void tearDown() throws Exception {
-        if (mRecyclerView != null) {
-            try {
-                removeRecyclerView();
-            } catch (Throwable throwable) {
-                throwable.printStackTrace();
-            }
-        }
-        getInstrumentation().waitForIdleSync();
-
-        try {
-            checkForMainThreadException();
-        } catch (Exception e) {
-            throw e;
-        } catch (Throwable throwable) {
-            throw new Exception(Log.getStackTraceString(throwable));
-        }
-    }
-
-    public Rect getDecoratedRecyclerViewBounds() {
-        return new Rect(
-                mRecyclerView.getPaddingLeft(),
-                mRecyclerView.getPaddingTop(),
-                mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(),
-                mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom()
-        );
-    }
-
-    public void removeRecyclerView() throws Throwable {
-        if (mRecyclerView == null) {
-            return;
-        }
-        if (!isMainThread()) {
-            getInstrumentation().waitForIdleSync();
-        }
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    // do not run validation if we already have an error
-                    if (mMainThreadException == null) {
-                        final RecyclerView.Adapter adapter = mRecyclerView.getAdapter();
-                        if (adapter instanceof AttachDetachCountingAdapter) {
-                            ((AttachDetachCountingAdapter) adapter).getCounter()
-                                    .validateRemaining(mRecyclerView);
-                        }
-                    }
-                    getActivity().getContainer().removeAllViews();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        });
-        mRecyclerView = null;
-    }
-
-    void waitForAnimations(int seconds) throws Throwable {
-        final CountDownLatch latch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.mItemAnimator
-                        .isRunning(new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
-                            @Override
-                            public void onAnimationsFinished() {
-                                latch.countDown();
-                            }
-                        });
-            }
-        });
-
-        assertTrue("animations didn't finish on expected time of " + seconds + " seconds",
-                latch.await(seconds, TimeUnit.SECONDS));
-    }
-
-    public void waitForIdleScroll(final RecyclerView recyclerView) throws Throwable {
-        final CountDownLatch latch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                RecyclerView.OnScrollListener listener = new RecyclerView.OnScrollListener() {
-                    @Override
-                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                        if (newState == SCROLL_STATE_IDLE) {
-                            latch.countDown();
-                            recyclerView.removeOnScrollListener(this);
-                        }
-                    }
-                };
-                if (recyclerView.getScrollState() == SCROLL_STATE_IDLE) {
-                    latch.countDown();
-                } else {
-                    recyclerView.addOnScrollListener(listener);
-                }
-            }
-        });
-        assertTrue("should go idle in 10 seconds", latch.await(10, TimeUnit.SECONDS));
-    }
-
-    public boolean requestFocus(final View view, boolean waitForScroll) throws Throwable {
-        final boolean[] result = new boolean[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = view.requestFocus();
-            }
-        });
-        PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return view.hasFocus();
-            }
-        });
-        if (waitForScroll && result[0]) {
-            waitForIdleScroll(mRecyclerView);
-        }
-        return result[0];
-    }
-
-    public void setRecyclerView(final RecyclerView recyclerView) throws Throwable {
-        setRecyclerView(recyclerView, true);
-    }
-    public void setRecyclerView(final RecyclerView recyclerView, boolean assignDummyPool)
-            throws Throwable {
-        setRecyclerView(recyclerView, assignDummyPool, true);
-    }
-    public void setRecyclerView(final RecyclerView recyclerView, boolean assignDummyPool,
-            boolean addPositionCheckItemAnimator)
-            throws Throwable {
-        mRecyclerView = recyclerView;
-        if (assignDummyPool) {
-            RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool() {
-                @Override
-                public RecyclerView.ViewHolder getRecycledView(int viewType) {
-                    RecyclerView.ViewHolder viewHolder = super.getRecycledView(viewType);
-                    if (viewHolder == null) {
-                        return null;
-                    }
-                    viewHolder.addFlags(RecyclerView.ViewHolder.FLAG_BOUND);
-                    viewHolder.mPosition = 200;
-                    viewHolder.mOldPosition = 300;
-                    viewHolder.mPreLayoutPosition = 500;
-                    return viewHolder;
-                }
-
-                @Override
-                public void putRecycledView(RecyclerView.ViewHolder scrap) {
-                    assertNull(scrap.mOwnerRecyclerView);
-                    super.putRecycledView(scrap);
-                }
-            };
-            mRecyclerView.setRecycledViewPool(pool);
-        }
-        if (addPositionCheckItemAnimator) {
-            mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
-                @Override
-                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                        RecyclerView.State state) {
-                    RecyclerView.ViewHolder vh = parent.getChildViewHolder(view);
-                    if (!vh.isRemoved()) {
-                        assertNotSame("If getItemOffsets is called, child should have a valid"
-                                        + " adapter position unless it is removed : " + vh,
-                                vh.getAdapterPosition(), RecyclerView.NO_POSITION);
-                    }
-                }
-            });
-        }
-        mAdapterHelper = recyclerView.mAdapterHelper;
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().addView(recyclerView);
-            }
-        });
-    }
-
-    protected FrameLayout getRecyclerViewContainer() {
-        return getActivity().getContainer();
-    }
-
-    protected void requestLayoutOnUIThread(final View view) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestLayout();
-            }
-        });
-    }
-
-    protected void scrollBy(final int dt) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (mRecyclerView.getLayoutManager().canScrollHorizontally()) {
-                    mRecyclerView.scrollBy(dt, 0);
-                } else {
-                    mRecyclerView.scrollBy(0, dt);
-                }
-
-            }
-        });
-    }
-
-    protected void smoothScrollBy(final int dt) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (mRecyclerView.getLayoutManager().canScrollHorizontally()) {
-                    mRecyclerView.smoothScrollBy(dt, 0);
-                } else {
-                    mRecyclerView.smoothScrollBy(0, dt);
-                }
-
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-    }
-
-    void scrollToPosition(final int position) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.getLayoutManager().scrollToPosition(position);
-            }
-        });
-    }
-
-    void smoothScrollToPosition(final int position) throws Throwable {
-        smoothScrollToPosition(position, true);
-    }
-
-    void smoothScrollToPosition(final int position, boolean assertArrival) throws Throwable {
-        if (mDebug) {
-            Log.d(TAG, "SMOOTH scrolling to " + position);
-        }
-        final CountDownLatch viewAdded = new CountDownLatch(1);
-        final RecyclerView.OnChildAttachStateChangeListener listener =
-                new RecyclerView.OnChildAttachStateChangeListener() {
-                    @Override
-                    public void onChildViewAttachedToWindow(View view) {
-                        if (position == mRecyclerView.getChildAdapterPosition(view)) {
-                            viewAdded.countDown();
-                        }
-                    }
-                    @Override
-                    public void onChildViewDetachedFromWindow(View view) {
-                    }
-                };
-        final AtomicBoolean addedListener = new AtomicBoolean(false);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                RecyclerView.ViewHolder viewHolderForAdapterPosition =
-                        mRecyclerView.findViewHolderForAdapterPosition(position);
-                if (viewHolderForAdapterPosition != null) {
-                    viewAdded.countDown();
-                } else {
-                    mRecyclerView.addOnChildAttachStateChangeListener(listener);
-                    addedListener.set(true);
-                }
-
-            }
-        });
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.smoothScrollToPosition(position);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        assertThat("should be able to scroll in 10 seconds", !assertArrival ||
-                        viewAdded.await(10, TimeUnit.SECONDS),
-                CoreMatchers.is(true));
-        waitForIdleScroll(mRecyclerView);
-        if (mDebug) {
-            Log.d(TAG, "SMOOTH scrolling done");
-        }
-        if (addedListener.get()) {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    mRecyclerView.removeOnChildAttachStateChangeListener(listener);
-                }
-            });
-        }
-        getInstrumentation().waitForIdleSync();
-    }
-
-    void freezeLayout(final boolean freeze) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setLayoutFrozen(freeze);
-            }
-        });
-    }
-
-    public void setVisibility(final View view, final int visibility) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.setVisibility(visibility);
-            }
-        });
-    }
-
-    public class TestViewHolder extends RecyclerView.ViewHolder {
-
-        Item mBoundItem;
-        Object mData;
-
-        public TestViewHolder(View itemView) {
-            super(itemView);
-            itemView.setFocusable(true);
-        }
-
-        @Override
-        public String toString() {
-            return super.toString() + " item:" + mBoundItem + ", data:" + mData;
-        }
-
-        public Object getData() {
-            return mData;
-        }
-
-        public void setData(Object data) {
-            mData = data;
-        }
-    }
-    class DumbLayoutManager extends TestLayoutManager {
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            detachAndScrapAttachedViews(recycler);
-            layoutRange(recycler, 0, state.getItemCount());
-            if (layoutLatch != null) {
-                layoutLatch.countDown();
-            }
-        }
-    }
-
-    public class TestLayoutManager extends RecyclerView.LayoutManager {
-        int mScrollVerticallyAmount;
-        int mScrollHorizontallyAmount;
-        protected CountDownLatch layoutLatch;
-        private boolean mSupportsPredictive = false;
-
-        public void expectLayouts(int count) {
-            layoutLatch = new CountDownLatch(count);
-        }
-
-        public void waitForLayout(int seconds) throws Throwable {
-            layoutLatch.await(seconds * (mDebug ? 1000 : 1), SECONDS);
-            checkForMainThreadException();
-            MatcherAssert.assertThat("all layouts should complete on time",
-                    layoutLatch.getCount(), CoreMatchers.is(0L));
-            // use a runnable to ensure RV layout is finished
-            getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                }
-            });
-        }
-
-        public boolean isSupportsPredictive() {
-            return mSupportsPredictive;
-        }
-
-        public void setSupportsPredictive(boolean supportsPredictive) {
-            mSupportsPredictive = supportsPredictive;
-        }
-
-        @Override
-        public boolean supportsPredictiveItemAnimations() {
-            return mSupportsPredictive;
-        }
-
-        public void assertLayoutCount(int count, String msg, long timeout) throws Throwable {
-            layoutLatch.await(timeout, TimeUnit.SECONDS);
-            assertEquals(msg, count, layoutLatch.getCount());
-        }
-
-        public void assertNoLayout(String msg, long timeout) throws Throwable {
-            layoutLatch.await(timeout, TimeUnit.SECONDS);
-            assertFalse(msg, layoutLatch.getCount() == 0);
-        }
-
-        @Override
-        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
-            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-        }
-
-        void assertVisibleItemPositions() {
-            int i = getChildCount();
-            TestAdapter testAdapter = (TestAdapter) mRecyclerView.getAdapter();
-            while (i-- > 0) {
-                View view = getChildAt(i);
-                RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
-                Item item = ((TestViewHolder) lp.mViewHolder).mBoundItem;
-                if (mDebug) {
-                    Log.d(TAG, "testing item " + i);
-                }
-                if (!lp.isItemRemoved()) {
-                    RecyclerView.ViewHolder vh = mRecyclerView.getChildViewHolder(view);
-                    assertSame("item position in LP should match adapter value :" + vh,
-                            testAdapter.mItems.get(vh.mPosition), item);
-                }
-            }
-        }
-
-        RecyclerView.LayoutParams getLp(View v) {
-            return (RecyclerView.LayoutParams) v.getLayoutParams();
-        }
-
-        protected void layoutRange(RecyclerView.Recycler recycler, int start, int end) {
-            assertScrap(recycler);
-            if (mDebug) {
-                Log.d(TAG, "will layout items from " + start + " to " + end);
-            }
-            int diff = end > start ? 1 : -1;
-            int top = 0;
-            for (int i = start; i != end; i+=diff) {
-                if (mDebug) {
-                    Log.d(TAG, "laying out item " + i);
-                }
-                View view = recycler.getViewForPosition(i);
-                assertNotNull("view should not be null for valid position. "
-                        + "got null view at position " + i, view);
-                if (!mRecyclerView.mState.isPreLayout()) {
-                    RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view
-                            .getLayoutParams();
-                    assertFalse("In post layout, getViewForPosition should never return a view "
-                            + "that is removed", layoutParams != null
-                            && layoutParams.isItemRemoved());
-
-                }
-                assertEquals("getViewForPosition should return correct position",
-                        i, getPosition(view));
-                addView(view);
-                measureChildWithMargins(view, 0, 0);
-                if (getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL) {
-                    layoutDecorated(view, getWidth() - getDecoratedMeasuredWidth(view), top,
-                            getWidth(), top + getDecoratedMeasuredHeight(view));
-                } else {
-                    layoutDecorated(view, 0, top, getDecoratedMeasuredWidth(view)
-                            , top + getDecoratedMeasuredHeight(view));
-                }
-
-                top += view.getMeasuredHeight();
-            }
-        }
-
-        private void assertScrap(RecyclerView.Recycler recycler) {
-            if (mRecyclerView.getAdapter() != null &&
-                    !mRecyclerView.getAdapter().hasStableIds()) {
-                for (RecyclerView.ViewHolder viewHolder : recycler.getScrapList()) {
-                    assertFalse("Invalid scrap should be no kept", viewHolder.isInvalid());
-                }
-            }
-        }
-
-        @Override
-        public boolean canScrollHorizontally() {
-            return true;
-        }
-
-        @Override
-        public boolean canScrollVertically() {
-            return true;
-        }
-
-        @Override
-        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            mScrollHorizontallyAmount += dx;
-            return dx;
-        }
-
-        @Override
-        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            mScrollVerticallyAmount += dy;
-            return dy;
-        }
-
-        // START MOCKITO OVERRIDES
-        // We override package protected methods to make them public. This is necessary to run
-        // mockito on Kitkat
-        @Override
-        public void setRecyclerView(RecyclerView recyclerView) {
-            super.setRecyclerView(recyclerView);
-        }
-
-        @Override
-        public void dispatchAttachedToWindow(RecyclerView view) {
-            super.dispatchAttachedToWindow(view);
-        }
-
-        @Override
-        public void dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
-            super.dispatchDetachedFromWindow(view, recycler);
-        }
-
-        @Override
-        public void setExactMeasureSpecsFrom(RecyclerView recyclerView) {
-            super.setExactMeasureSpecsFrom(recyclerView);
-        }
-
-        @Override
-        public void setMeasureSpecs(int wSpec, int hSpec) {
-            super.setMeasureSpecs(wSpec, hSpec);
-        }
-
-        @Override
-        public void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
-            super.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
-        }
-
-        @Override
-        public boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec,
-                RecyclerView.LayoutParams lp) {
-            return super.shouldReMeasureChild(child, widthSpec, heightSpec, lp);
-        }
-
-        @Override
-        public boolean shouldMeasureChild(View child, int widthSpec, int heightSpec,
-                RecyclerView.LayoutParams lp) {
-            return super.shouldMeasureChild(child, widthSpec, heightSpec, lp);
-        }
-
-        @Override
-        public void removeAndRecycleScrapInt(RecyclerView.Recycler recycler) {
-            super.removeAndRecycleScrapInt(recycler);
-        }
-
-        @Override
-        public void stopSmoothScroller() {
-            super.stopSmoothScroller();
-        }
-
-        // END MOCKITO OVERRIDES
-    }
-
-    static class Item {
-        final static AtomicInteger idCounter = new AtomicInteger(0);
-        final public int mId = idCounter.incrementAndGet();
-
-        int mAdapterIndex;
-
-        String mText;
-        int mType = 0;
-        boolean mFocusable;
-
-        Item(int adapterIndex, String text) {
-            mAdapterIndex = adapterIndex;
-            mText = text;
-            mFocusable = true;
-        }
-
-        public boolean isFocusable() {
-            return mFocusable;
-        }
-
-        public void setFocusable(boolean mFocusable) {
-            this.mFocusable = mFocusable;
-        }
-
-        @Override
-        public String toString() {
-            return "Item{" +
-                    "mId=" + mId +
-                    ", originalIndex=" + mAdapterIndex +
-                    ", text='" + mText + '\'' +
-                    '}';
-        }
-    }
-
-    public class FocusableAdapter extends RecyclerView.Adapter<TestViewHolder> {
-
-        private int mCount;
-
-        FocusableAdapter(int count) {
-            mCount = count;
-        }
-
-        @Override
-        public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            final TextView textView = new TextView(parent.getContext());
-            textView.setLayoutParams(new ViewGroup.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
-            textView.setFocusable(true);
-            textView.setBackgroundResource(R.drawable.item_bg);
-            return new TestViewHolder(textView);
-        }
-
-        @Override
-        public void onBindViewHolder(TestViewHolder holder, int position) {
-            ((TextView) holder.itemView).setText("Item " + position);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mCount;
-        }
-    }
-
-    public class TestAdapter extends RecyclerView.Adapter<TestViewHolder>
-            implements AttachDetachCountingAdapter {
-
-        public static final String DEFAULT_ITEM_PREFIX = "Item ";
-
-        ViewAttachDetachCounter mAttachmentCounter = new ViewAttachDetachCounter();
-        List<Item> mItems;
-        final @Nullable RecyclerView.LayoutParams mLayoutParams;
-
-        public TestAdapter(int count) {
-            this(count, null);
-        }
-
-        public TestAdapter(int count, @Nullable RecyclerView.LayoutParams layoutParams) {
-            mItems = new ArrayList<Item>(count);
-            addItems(0, count, DEFAULT_ITEM_PREFIX);
-            mLayoutParams = layoutParams;
-        }
-
-        void addItems(int pos, int count, String prefix) {
-            for (int i = 0; i < count; i++, pos++) {
-                mItems.add(pos, new Item(pos, prefix));
-            }
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return getItemAt(position).mType;
-        }
-
-        @Override
-        public void onViewAttachedToWindow(TestViewHolder holder) {
-            super.onViewAttachedToWindow(holder);
-            mAttachmentCounter.onViewAttached(holder);
-        }
-
-        @Override
-        public void onViewDetachedFromWindow(TestViewHolder holder) {
-            super.onViewDetachedFromWindow(holder);
-            mAttachmentCounter.onViewDetached(holder);
-        }
-
-        @Override
-        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-            super.onAttachedToRecyclerView(recyclerView);
-            mAttachmentCounter.onAttached(recyclerView);
-        }
-
-        @Override
-        public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
-            super.onDetachedFromRecyclerView(recyclerView);
-            mAttachmentCounter.onDetached(recyclerView);
-        }
-
-        @Override
-        public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                int viewType) {
-            TextView itemView = new TextView(parent.getContext());
-            itemView.setFocusableInTouchMode(true);
-            itemView.setFocusable(true);
-            return new TestViewHolder(itemView);
-        }
-
-        @Override
-        public void onBindViewHolder(TestViewHolder holder, int position) {
-            assertNotNull(holder.mOwnerRecyclerView);
-            assertEquals(position, holder.getAdapterPosition());
-            final Item item = mItems.get(position);
-            ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mId + ")");
-            holder.mBoundItem = item;
-            if (mLayoutParams != null) {
-                holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(mLayoutParams));
-            }
-        }
-
-        public Item getItemAt(int position) {
-            return mItems.get(position);
-        }
-
-        @Override
-        public void onViewRecycled(TestViewHolder holder) {
-            super.onViewRecycled(holder);
-            final int adapterPosition = holder.getAdapterPosition();
-            final boolean shouldHavePosition = !holder.isRemoved() && holder.isBound() &&
-                    !holder.isAdapterPositionUnknown() && !holder.isInvalid();
-            String log = "Position check for " + holder.toString();
-            assertEquals(log, shouldHavePosition, adapterPosition != RecyclerView.NO_POSITION);
-            if (shouldHavePosition) {
-                assertTrue(log, mItems.size() > adapterPosition);
-                // TODO: fix b/36042615 getAdapterPosition() is wrong in
-                // consumePendingUpdatesInOnePass where it applies pending change to already
-                // modified position.
-                if (holder.mPreLayoutPosition == RecyclerView.NO_POSITION) {
-                    assertSame(log, holder.mBoundItem, mItems.get(adapterPosition));
-                }
-            }
-        }
-
-        public void deleteAndNotify(final int start, final int count) throws Throwable {
-            deleteAndNotify(new int[]{start, count});
-        }
-
-        /**
-         * Deletes items in the given ranges.
-         * <p>
-         * Note that each operation affects the one after so you should offset them properly.
-         * <p>
-         * For example, if adapter has 5 items (A,B,C,D,E), and then you call this method with
-         * <code>[1, 2],[2, 1]</code>, it will first delete items B,C and the new adapter will be
-         * A D E. Then it will delete 2,1 which means it will delete E.
-         */
-        public void deleteAndNotify(final int[]... startCountTuples) throws Throwable {
-            for (int[] tuple : startCountTuples) {
-                tuple[1] = -tuple[1];
-            }
-            mActivityRule.runOnUiThread(new AddRemoveRunnable(startCountTuples));
-        }
-
-        @Override
-        public long getItemId(int position) {
-            return hasStableIds() ? mItems.get(position).mId : super.getItemId(position);
-        }
-
-        public void offsetOriginalIndices(int start, int offset) {
-            for (int i = start; i < mItems.size(); i++) {
-                mItems.get(i).mAdapterIndex += offset;
-            }
-        }
-
-        /**
-         * @param start inclusive
-         * @param end exclusive
-         * @param offset
-         */
-        public void offsetOriginalIndicesBetween(int start, int end, int offset) {
-            for (int i = start; i < end && i < mItems.size(); i++) {
-                mItems.get(i).mAdapterIndex += offset;
-            }
-        }
-
-        public void addAndNotify(final int count) throws Throwable {
-            assertEquals(0, mItems.size());
-            mActivityRule.runOnUiThread(
-                    new AddRemoveRunnable(DEFAULT_ITEM_PREFIX, new int[]{0, count}));
-        }
-
-        public void resetItemsTo(final List<Item> testItems) throws Throwable {
-            if (!mItems.isEmpty()) {
-                deleteAndNotify(0, mItems.size());
-            }
-            mItems = testItems;
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    notifyItemRangeInserted(0, testItems.size());
-                }
-            });
-        }
-
-        public void addAndNotify(final int start, final int count) throws Throwable {
-            addAndNotify(new int[]{start, count});
-        }
-
-        public void addAndNotify(final int[]... startCountTuples) throws Throwable {
-            mActivityRule.runOnUiThread(new AddRemoveRunnable(startCountTuples));
-        }
-
-        public void dispatchDataSetChanged() throws Throwable {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    notifyDataSetChanged();
-                }
-            });
-        }
-
-        public void changeAndNotify(final int start, final int count) throws Throwable {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    notifyItemRangeChanged(start, count);
-                }
-            });
-        }
-
-        public void changeAndNotifyWithPayload(final int start, final int count,
-                final Object payload) throws Throwable {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    notifyItemRangeChanged(start, count, payload);
-                }
-            });
-        }
-
-        public void changePositionsAndNotify(final int... positions) throws Throwable {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    for (int i = 0; i < positions.length; i += 1) {
-                        TestAdapter.super.notifyItemRangeChanged(positions[i], 1);
-                    }
-                }
-            });
-        }
-
-        /**
-         * Similar to other methods but negative count means delete and position count means add.
-         * <p>
-         * For instance, calling this method with <code>[1,1], [2,-1]</code> it will first add an
-         * item to index 1, then remove an item from index 2 (updated index 2)
-         */
-        public void addDeleteAndNotify(final int[]... startCountTuples) throws Throwable {
-            mActivityRule.runOnUiThread(new AddRemoveRunnable(startCountTuples));
-        }
-
-        @Override
-        public int getItemCount() {
-            return mItems.size();
-        }
-
-        /**
-         * Uses notifyDataSetChanged
-         */
-        public void moveItems(boolean notifyChange, int[]... fromToTuples) throws Throwable {
-            for (int i = 0; i < fromToTuples.length; i += 1) {
-                int[] tuple = fromToTuples[i];
-                moveItem(tuple[0], tuple[1], false);
-            }
-            if (notifyChange) {
-                dispatchDataSetChanged();
-            }
-        }
-
-        /**
-         * Uses notifyDataSetChanged
-         */
-        public void moveItem(final int from, final int to, final boolean notifyChange)
-                throws Throwable {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    moveInUIThread(from, to);
-                    if (notifyChange) {
-                        notifyDataSetChanged();
-                    }
-                }
-            });
-        }
-
-        /**
-         * Uses notifyItemMoved
-         */
-        public void moveAndNotify(final int from, final int to) throws Throwable {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    moveInUIThread(from, to);
-                    notifyItemMoved(from, to);
-                }
-            });
-        }
-
-        void changeAllItemsAndNotifyDataSetChanged(int count) {
-            assertEquals("clearOnUIThread called from a wrong thread",
-                    Looper.getMainLooper(), Looper.myLooper());
-            mItems = new ArrayList<>();
-            addItems(0, count, DEFAULT_ITEM_PREFIX);
-            notifyDataSetChanged();
-        }
-
-        public void clearOnUIThread() {
-            changeAllItemsAndNotifyDataSetChanged(0);
-        }
-
-        protected void moveInUIThread(int from, int to) {
-            Item item = mItems.remove(from);
-            offsetOriginalIndices(from, -1);
-            mItems.add(to, item);
-            offsetOriginalIndices(to + 1, 1);
-            item.mAdapterIndex = to;
-        }
-
-
-        @Override
-        public ViewAttachDetachCounter getCounter() {
-            return mAttachmentCounter;
-        }
-
-        private class AddRemoveRunnable implements Runnable {
-            final String mNewItemPrefix;
-            final int[][] mStartCountTuples;
-
-            public AddRemoveRunnable(String newItemPrefix, int[]... startCountTuples) {
-                mNewItemPrefix = newItemPrefix;
-                mStartCountTuples = startCountTuples;
-            }
-
-            public AddRemoveRunnable(int[][] startCountTuples) {
-                this("new item ", startCountTuples);
-            }
-
-            @Override
-            public void run() {
-                for (int[] tuple : mStartCountTuples) {
-                    if (tuple[1] < 0) {
-                        delete(tuple);
-                    } else {
-                        add(tuple);
-                    }
-                }
-            }
-
-            private void add(int[] tuple) {
-                // offset others
-                offsetOriginalIndices(tuple[0], tuple[1]);
-                addItems(tuple[0], tuple[1], mNewItemPrefix);
-                notifyItemRangeInserted(tuple[0], tuple[1]);
-            }
-
-            private void delete(int[] tuple) {
-                final int count = -tuple[1];
-                offsetOriginalIndices(tuple[0] + count, tuple[1]);
-                for (int i = 0; i < count; i++) {
-                    mItems.remove(tuple[0]);
-                }
-                notifyItemRangeRemoved(tuple[0], count);
-            }
-        }
-    }
-
-    public boolean isMainThread() {
-        return Looper.myLooper() == Looper.getMainLooper();
-    }
-
-    static class TargetTuple {
-
-        final int mPosition;
-
-        final int mLayoutDirection;
-
-        TargetTuple(int position, int layoutDirection) {
-            this.mPosition = position;
-            this.mLayoutDirection = layoutDirection;
-        }
-
-        @Override
-        public String toString() {
-            return "TargetTuple{" +
-                    "mPosition=" + mPosition +
-                    ", mLayoutDirection=" + mLayoutDirection +
-                    '}';
-        }
-    }
-
-    public interface AttachDetachCountingAdapter {
-
-        ViewAttachDetachCounter getCounter();
-    }
-
-    public class ViewAttachDetachCounter {
-
-        Set<RecyclerView.ViewHolder> mAttachedSet = new HashSet<RecyclerView.ViewHolder>();
-
-        public void validateRemaining(RecyclerView recyclerView) {
-            final int childCount = recyclerView.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View view = recyclerView.getChildAt(i);
-                RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
-                assertTrue("remaining view should be in attached set " + vh,
-                        mAttachedSet.contains(vh));
-            }
-            assertEquals("there should not be any views left in attached set",
-                    childCount, mAttachedSet.size());
-        }
-
-        public void onViewDetached(RecyclerView.ViewHolder viewHolder) {
-            try {
-                assertTrue("view holder should be in attached set",
-                        mAttachedSet.remove(viewHolder));
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-        }
-
-        public void onViewAttached(RecyclerView.ViewHolder viewHolder) {
-            try {
-                assertTrue("view holder should not be in attached set",
-                        mAttachedSet.add(viewHolder));
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-        }
-
-        public void onAttached(RecyclerView recyclerView) {
-            // when a new RV is attached, clear the set and add all view holders
-            mAttachedSet.clear();
-            final int childCount = recyclerView.getChildCount();
-            for (int i = 0; i < childCount; i ++) {
-                View view = recyclerView.getChildAt(i);
-                mAttachedSet.add(recyclerView.getChildViewHolder(view));
-            }
-        }
-
-        public void onDetached(RecyclerView recyclerView) {
-            validateRemaining(recyclerView);
-        }
-    }
-
-
-    public static View findFirstFullyVisibleChild(RecyclerView parent) {
-        for (int i = 0; i < parent.getChildCount(); i++) {
-            View child = parent.getChildAt(i);
-            if (isViewFullyInBound(parent, child)) {
-                return child;
-            }
-        }
-        return null;
-    }
-
-    public static View findLastFullyVisibleChild(RecyclerView parent) {
-        for (int i = parent.getChildCount() - 1; i >= 0; i--) {
-            View child = parent.getChildAt(i);
-            if (isViewFullyInBound(parent, child)) {
-                return child;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns whether a child of RecyclerView is partially in bound. A child is
-     * partially in-bounds if it's either fully or partially visible on the screen.
-     * @param parent The RecyclerView holding the child.
-     * @param child The child view to be checked whether is partially (or fully) within RV's bounds.
-     * @return True if the child view is partially (or fully) visible; false otherwise.
-     */
-    public static boolean isViewPartiallyInBound(RecyclerView parent, View child) {
-        if (child == null) {
-            return false;
-        }
-        final int parentLeft = parent.getPaddingLeft();
-        final int parentTop = parent.getPaddingTop();
-        final int parentRight = parent.getWidth() - parent.getPaddingRight();
-        final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
-
-        final int childLeft = child.getLeft() - child.getScrollX();
-        final int childTop = child.getTop() - child.getScrollY();
-        final int childRight = child.getRight() - child.getScrollX();
-        final int childBottom = child.getBottom() - child.getScrollY();
-
-        if (childLeft >= parentRight || childRight <= parentLeft
-                || childTop >= parentBottom || childBottom <= parentTop) {
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Returns whether a child of RecyclerView is fully in-bounds, that is it's fully visible
-     * on the screen.
-     * @param parent The RecyclerView holding the child.
-     * @param child The child view to be checked whether is fully within RV's bounds.
-     * @return True if the child view is fully visible; false otherwise.
-     */
-    public static boolean isViewFullyInBound(RecyclerView parent, View child) {
-        if (child == null) {
-            return false;
-        }
-        final int parentLeft = parent.getPaddingLeft();
-        final int parentTop = parent.getPaddingTop();
-        final int parentRight = parent.getWidth() - parent.getPaddingRight();
-        final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
-
-        final int childLeft = child.getLeft() - child.getScrollX();
-        final int childTop = child.getTop() - child.getScrollY();
-        final int childRight = child.getRight() - child.getScrollX();
-        final int childBottom = child.getBottom() - child.getScrollY();
-
-        if (childLeft >= parentLeft && childRight <= parentRight
-                && childTop >= parentTop && childBottom <= parentBottom) {
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
deleted file mode 100644
index 776b10d..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
+++ /dev/null
@@ -1,926 +0,0 @@
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LayoutState.LAYOUT_END;
-import static android.support.v7.widget.LayoutState.LAYOUT_START;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
-import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
-import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.support.annotation.Nullable;
-import android.util.Log;
-import android.util.StateSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-abstract class BaseStaggeredGridLayoutManagerTest extends BaseRecyclerViewInstrumentationTest {
-
-    protected static final boolean DEBUG = false;
-    protected static final int AVG_ITEM_PER_VIEW = 3;
-    protected static final String TAG = "SGLM_TEST";
-    volatile WrappedLayoutManager mLayoutManager;
-    GridTestAdapter mAdapter;
-
-    protected static List<Config> createBaseVariations() {
-        List<Config> variations = new ArrayList<>();
-        for (int orientation : new int[]{VERTICAL, HORIZONTAL}) {
-            for (boolean reverseLayout : new boolean[]{false, true}) {
-                for (int spanCount : new int[]{1, 3}) {
-                    for (int gapStrategy : new int[]{GAP_HANDLING_NONE,
-                            GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}) {
-                        for (boolean wrap : new boolean[]{true, false}) {
-                            variations.add(new Config(orientation, reverseLayout, spanCount,
-                                    gapStrategy).wrap(wrap));
-                        }
-
-                    }
-                }
-            }
-        }
-        return variations;
-    }
-
-    protected static List<Config> addConfigVariation(List<Config> base, String fieldName,
-            Object... variations)
-            throws CloneNotSupportedException, NoSuchFieldException, IllegalAccessException {
-        List<Config> newConfigs = new ArrayList<Config>();
-        Field field = Config.class.getDeclaredField(fieldName);
-        for (Config config : base) {
-            for (Object variation : variations) {
-                Config newConfig = (Config) config.clone();
-                field.set(newConfig, variation);
-                newConfigs.add(newConfig);
-            }
-        }
-        return newConfigs;
-    }
-
-    void setupByConfig(Config config) throws Throwable {
-        setupByConfig(config, new GridTestAdapter(config.mItemCount, config.mOrientation));
-    }
-
-    void setupByConfig(Config config, GridTestAdapter adapter) throws Throwable {
-        mAdapter = adapter;
-        mRecyclerView = new WrappedRecyclerView(getActivity());
-        mRecyclerView.setAdapter(mAdapter);
-        mRecyclerView.setHasFixedSize(true);
-        mLayoutManager = new WrappedLayoutManager(config.mSpanCount, config.mOrientation);
-        mLayoutManager.setGapStrategy(config.mGapStrategy);
-        mLayoutManager.setReverseLayout(config.mReverseLayout);
-        mRecyclerView.setLayoutManager(mLayoutManager);
-        mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
-            @Override
-            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                    RecyclerView.State state) {
-                try {
-                    StaggeredGridLayoutManager.LayoutParams
-                            lp = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
-                    assertNotNull("view should have layout params assigned", lp);
-                    assertNotNull("when item offsets are requested, view should have a valid span",
-                            lp.mSpan);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        });
-    }
-
-    StaggeredGridLayoutManager.LayoutParams getLp(View view) {
-        return (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
-    }
-
-    void waitFirstLayout() throws Throwable {
-        mLayoutManager.expectLayouts(1);
-        setRecyclerView(mRecyclerView);
-        mLayoutManager.waitForLayout(3);
-        getInstrumentation().waitForIdleSync();
-    }
-
-    /**
-     * enqueues an empty runnable to main thread so that we can be assured it did run
-     *
-     * @param count Number of times to run
-     */
-    protected void waitForMainThread(int count) throws Throwable {
-        final AtomicInteger i = new AtomicInteger(count);
-        while (i.get() > 0) {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    i.decrementAndGet();
-                }
-            });
-        }
-    }
-
-    public void assertRectSetsNotEqual(String message, Map<Item, Rect> before,
-            Map<Item, Rect> after) {
-        Throwable throwable = null;
-        try {
-            assertRectSetsEqual("NOT " + message, before, after);
-        } catch (Throwable t) {
-            throwable = t;
-        }
-        assertNotNull(message + " two layout should be different", throwable);
-    }
-
-    public void assertRectSetsEqual(String message, Map<Item, Rect> before, Map<Item, Rect> after) {
-        assertRectSetsEqual(message, before, after, true);
-    }
-
-    public void assertRectSetsEqual(String message, Map<Item, Rect> before, Map<Item, Rect> after,
-            boolean strictItemEquality) {
-        StringBuilder log = new StringBuilder();
-        if (DEBUG) {
-            log.append("checking rectangle equality.\n");
-            log.append("total space:" + mLayoutManager.mPrimaryOrientation.getTotalSpace());
-            log.append("before:");
-            for (Map.Entry<Item, Rect> entry : before.entrySet()) {
-                log.append("\n").append(entry.getKey().mAdapterIndex).append(":")
-                        .append(entry.getValue());
-            }
-            log.append("\nafter:");
-            for (Map.Entry<Item, Rect> entry : after.entrySet()) {
-                log.append("\n").append(entry.getKey().mAdapterIndex).append(":")
-                        .append(entry.getValue());
-            }
-            message += "\n\n" + log.toString();
-        }
-        assertEquals(message + ": item counts should be equal", before.size()
-                , after.size());
-        for (Map.Entry<Item, Rect> entry : before.entrySet()) {
-            final Item beforeItem = entry.getKey();
-            Rect afterRect = null;
-            if (strictItemEquality) {
-                afterRect = after.get(beforeItem);
-                assertNotNull(message + ": Same item should be visible after simple re-layout",
-                        afterRect);
-            } else {
-                for (Map.Entry<Item, Rect> afterEntry : after.entrySet()) {
-                    final Item afterItem = afterEntry.getKey();
-                    if (afterItem.mAdapterIndex == beforeItem.mAdapterIndex) {
-                        afterRect = afterEntry.getValue();
-                        break;
-                    }
-                }
-                assertNotNull(message + ": Item with same adapter index should be visible " +
-                                "after simple re-layout",
-                        afterRect);
-            }
-            assertEquals(message + ": Item should be laid out at the same coordinates",
-                    entry.getValue(),
-                    afterRect);
-        }
-    }
-
-    protected void assertViewPositions(Config config) {
-        ArrayList<ArrayList<View>> viewsBySpan = mLayoutManager.collectChildrenBySpan();
-        OrientationHelper orientationHelper = OrientationHelper
-                .createOrientationHelper(mLayoutManager, config.mOrientation);
-        for (ArrayList<View> span : viewsBySpan) {
-            // validate all children's order. first child should have min start mPosition
-            final int count = span.size();
-            for (int i = 0, j = 1; j < count; i++, j++) {
-                View prev = span.get(i);
-                View next = span.get(j);
-                assertTrue(config + " prev item should be above next item",
-                        orientationHelper.getDecoratedEnd(prev) <= orientationHelper
-                                .getDecoratedStart(next)
-                );
-
-            }
-        }
-    }
-
-    protected TargetTuple findInvisibleTarget(Config config) {
-        int minPosition = Integer.MAX_VALUE, maxPosition = Integer.MIN_VALUE;
-        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
-            View child = mLayoutManager.getChildAt(i);
-            int position = mRecyclerView.getChildLayoutPosition(child);
-            if (position < minPosition) {
-                minPosition = position;
-            }
-            if (position > maxPosition) {
-                maxPosition = position;
-            }
-        }
-        final int tailTarget = maxPosition + (mAdapter.getItemCount() - maxPosition) / 2;
-        final int headTarget = minPosition / 2;
-        final int target;
-        // where will the child come from ?
-        final int itemLayoutDirection;
-        if (Math.abs(tailTarget - maxPosition) > Math.abs(headTarget - minPosition)) {
-            target = tailTarget;
-            itemLayoutDirection = config.mReverseLayout ? LAYOUT_START : LAYOUT_END;
-        } else {
-            target = headTarget;
-            itemLayoutDirection = config.mReverseLayout ? LAYOUT_END : LAYOUT_START;
-        }
-        if (DEBUG) {
-            Log.d(TAG,
-                    config + " target:" + target + " min:" + minPosition + ", max:" + maxPosition);
-        }
-        return new TargetTuple(target, itemLayoutDirection);
-    }
-
-    protected void scrollToPositionWithOffset(final int position, final int offset)
-            throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mLayoutManager.scrollToPositionWithOffset(position, offset);
-            }
-        });
-    }
-
-    static class OnLayoutListener {
-
-        void before(RecyclerView.Recycler recycler, RecyclerView.State state) {
-        }
-
-        void after(RecyclerView.Recycler recycler, RecyclerView.State state) {
-        }
-    }
-
-    static class VisibleChildren {
-
-        int[] firstVisiblePositions;
-
-        int[] firstFullyVisiblePositions;
-
-        int[] lastVisiblePositions;
-
-        int[] lastFullyVisiblePositions;
-
-        View findFirstPartialVisibleClosestToStart;
-        View findFirstPartialVisibleClosestToEnd;
-
-        VisibleChildren(int spanCount) {
-            firstFullyVisiblePositions = new int[spanCount];
-            firstVisiblePositions = new int[spanCount];
-            lastVisiblePositions = new int[spanCount];
-            lastFullyVisiblePositions = new int[spanCount];
-            for (int i = 0; i < spanCount; i++) {
-                firstFullyVisiblePositions[i] = RecyclerView.NO_POSITION;
-                firstVisiblePositions[i] = RecyclerView.NO_POSITION;
-                lastVisiblePositions[i] = RecyclerView.NO_POSITION;
-                lastFullyVisiblePositions[i] = RecyclerView.NO_POSITION;
-            }
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (this == o) {
-                return true;
-            }
-            if (o == null || getClass() != o.getClass()) {
-                return false;
-            }
-
-            VisibleChildren that = (VisibleChildren) o;
-
-            if (!Arrays.equals(firstFullyVisiblePositions, that.firstFullyVisiblePositions)) {
-                return false;
-            }
-            if (findFirstPartialVisibleClosestToStart
-                    != null ? !findFirstPartialVisibleClosestToStart
-                    .equals(that.findFirstPartialVisibleClosestToStart)
-                    : that.findFirstPartialVisibleClosestToStart != null) {
-                return false;
-            }
-            if (!Arrays.equals(firstVisiblePositions, that.firstVisiblePositions)) {
-                return false;
-            }
-            if (!Arrays.equals(lastFullyVisiblePositions, that.lastFullyVisiblePositions)) {
-                return false;
-            }
-            if (findFirstPartialVisibleClosestToEnd != null ? !findFirstPartialVisibleClosestToEnd
-                    .equals(that.findFirstPartialVisibleClosestToEnd)
-                    : that.findFirstPartialVisibleClosestToEnd
-                            != null) {
-                return false;
-            }
-            if (!Arrays.equals(lastVisiblePositions, that.lastVisiblePositions)) {
-                return false;
-            }
-
-            return true;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = Arrays.hashCode(firstVisiblePositions);
-            result = 31 * result + Arrays.hashCode(firstFullyVisiblePositions);
-            result = 31 * result + Arrays.hashCode(lastVisiblePositions);
-            result = 31 * result + Arrays.hashCode(lastFullyVisiblePositions);
-            result = 31 * result + (findFirstPartialVisibleClosestToStart != null
-                    ? findFirstPartialVisibleClosestToStart
-                    .hashCode() : 0);
-            result = 31 * result + (findFirstPartialVisibleClosestToEnd != null
-                    ? findFirstPartialVisibleClosestToEnd
-                    .hashCode()
-                    : 0);
-            return result;
-        }
-
-        @Override
-        public String toString() {
-            return "VisibleChildren{" +
-                    "firstVisiblePositions=" + Arrays.toString(firstVisiblePositions) +
-                    ", firstFullyVisiblePositions=" + Arrays.toString(firstFullyVisiblePositions) +
-                    ", lastVisiblePositions=" + Arrays.toString(lastVisiblePositions) +
-                    ", lastFullyVisiblePositions=" + Arrays.toString(lastFullyVisiblePositions) +
-                    ", findFirstPartialVisibleClosestToStart=" +
-                    viewToString(findFirstPartialVisibleClosestToStart) +
-                    ", findFirstPartialVisibleClosestToEnd=" +
-                    viewToString(findFirstPartialVisibleClosestToEnd) +
-                    '}';
-        }
-
-        private String viewToString(View view) {
-            if (view == null) {
-                return null;
-            }
-            ViewGroup.LayoutParams lp = view.getLayoutParams();
-            if (lp instanceof RecyclerView.LayoutParams == false) {
-                return System.identityHashCode(view) + "(?)";
-            }
-            RecyclerView.LayoutParams rvlp = (RecyclerView.LayoutParams) lp;
-            return System.identityHashCode(view) + "(" + rvlp.getViewAdapterPosition() + ")";
-        }
-    }
-
-    abstract static class OnBindCallback {
-
-        abstract void onBoundItem(TestViewHolder vh, int position);
-
-        boolean assignRandomSize() {
-            return true;
-        }
-
-        void onCreatedViewHolder(TestViewHolder vh) {
-        }
-    }
-
-    static class Config implements Cloneable {
-
-        static final int DEFAULT_ITEM_COUNT = 300;
-
-        int mOrientation = OrientationHelper.VERTICAL;
-
-        boolean mReverseLayout = false;
-
-        int mSpanCount = 3;
-
-        int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
-
-        int mItemCount = DEFAULT_ITEM_COUNT;
-
-        boolean mWrap = false;
-
-        Config(int orientation, boolean reverseLayout, int spanCount, int gapStrategy) {
-            mOrientation = orientation;
-            mReverseLayout = reverseLayout;
-            mSpanCount = spanCount;
-            mGapStrategy = gapStrategy;
-        }
-
-        public Config() {
-
-        }
-
-        Config orientation(int orientation) {
-            mOrientation = orientation;
-            return this;
-        }
-
-        Config reverseLayout(boolean reverseLayout) {
-            mReverseLayout = reverseLayout;
-            return this;
-        }
-
-        Config spanCount(int spanCount) {
-            mSpanCount = spanCount;
-            return this;
-        }
-
-        Config gapStrategy(int gapStrategy) {
-            mGapStrategy = gapStrategy;
-            return this;
-        }
-
-        public Config itemCount(int itemCount) {
-            mItemCount = itemCount;
-            return this;
-        }
-
-        public Config wrap(boolean wrap) {
-            mWrap = wrap;
-            return this;
-        }
-
-        @Override
-        public String toString() {
-            return "[CONFIG:"
-                    + "span:" + mSpanCount
-                    + ",orientation:" + (mOrientation == HORIZONTAL ? "horz," : "vert,")
-                    + ",reverse:" + (mReverseLayout ? "T" : "F")
-                    + ",itemCount:" + mItemCount
-                    + ",wrapContent:" + mWrap
-                    + ",gap_strategy:" + gapStrategyName(mGapStrategy);
-        }
-
-        protected static String gapStrategyName(int gapStrategy) {
-            switch (gapStrategy) {
-                case GAP_HANDLING_NONE:
-                    return "none";
-                case GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS:
-                    return "move_spans";
-            }
-            return "gap_strategy:unknown";
-        }
-
-        @Override
-        public Object clone() throws CloneNotSupportedException {
-            return super.clone();
-        }
-    }
-
-    class WrappedLayoutManager extends StaggeredGridLayoutManager {
-
-        CountDownLatch layoutLatch;
-        CountDownLatch prefetchLatch;
-        OnLayoutListener mOnLayoutListener;
-        // gradle does not yet let us customize manifest for tests which is necessary to test RTL.
-        // until bug is fixed, we'll fake it.
-        // public issue id: 57819
-        Boolean mFakeRTL;
-        CountDownLatch mSnapLatch;
-
-        @Override
-        boolean isLayoutRTL() {
-            return mFakeRTL == null ? super.isLayoutRTL() : mFakeRTL;
-        }
-
-        public void expectLayouts(int count) {
-            layoutLatch = new CountDownLatch(count);
-        }
-
-        public void waitForLayout(int seconds) throws Throwable {
-            layoutLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
-            checkForMainThreadException();
-            MatcherAssert.assertThat("all layouts should complete on time",
-                    layoutLatch.getCount(), CoreMatchers.is(0L));
-            // use a runnable to ensure RV layout is finished
-            getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                }
-            });
-        }
-
-        public void expectPrefetch(int count) {
-            prefetchLatch = new CountDownLatch(count);
-        }
-
-        public void waitForPrefetch(int seconds) throws Throwable {
-            prefetchLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
-            checkForMainThreadException();
-            MatcherAssert.assertThat("all prefetches should complete on time",
-                    prefetchLatch.getCount(), CoreMatchers.is(0L));
-            // use a runnable to ensure RV layout is finished
-            getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                }
-            });
-        }
-
-        public void expectIdleState(int count) {
-            mSnapLatch = new CountDownLatch(count);
-            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-                @Override
-                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                    super.onScrollStateChanged(recyclerView, newState);
-                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
-                        mSnapLatch.countDown();
-                        if (mSnapLatch.getCount() == 0L) {
-                            mRecyclerView.removeOnScrollListener(this);
-                        }
-                    }
-                }
-            });
-        }
-
-        public void waitForSnap(int seconds) throws Throwable {
-            mSnapLatch.await(seconds * (DEBUG ? 100 : 1), SECONDS);
-            checkForMainThreadException();
-            MatcherAssert.assertThat("all scrolling should complete on time",
-                    mSnapLatch.getCount(), CoreMatchers.is(0L));
-            // use a runnable to ensure RV layout is finished
-            getInstrumentation().runOnMainSync(new Runnable() {
-                @Override
-                public void run() {
-                }
-            });
-        }
-
-        public void assertNoLayout(String msg, long timeout) throws Throwable {
-            layoutLatch.await(timeout, TimeUnit.SECONDS);
-            assertFalse(msg, layoutLatch.getCount() == 0);
-        }
-
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            String before;
-            if (DEBUG) {
-                before = layoutToString("before");
-            } else {
-                before = "enable DEBUG";
-            }
-            try {
-                if (mOnLayoutListener != null) {
-                    mOnLayoutListener.before(recycler, state);
-                }
-                super.onLayoutChildren(recycler, state);
-                if (mOnLayoutListener != null) {
-                    mOnLayoutListener.after(recycler, state);
-                }
-                validateChildren(before);
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-
-            layoutLatch.countDown();
-        }
-
-        @Override
-        int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) {
-            try {
-                int result = super.scrollBy(dt, recycler, state);
-                validateChildren();
-                return result;
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-
-            return 0;
-        }
-
-        View findFirstVisibleItemClosestToCenter() {
-            final int boundsStart = mPrimaryOrientation.getStartAfterPadding();
-            final int boundsEnd = mPrimaryOrientation.getEndAfterPadding();
-            final int boundsCenter = (boundsStart + boundsEnd) / 2;
-            final Rect childBounds = new Rect();
-            int minDist = Integer.MAX_VALUE;
-            View closestChild = null;
-            for (int i = getChildCount() - 1; i >= 0; i--) {
-                final View child = getChildAt(i);
-                childBounds.setEmpty();
-                getDecoratedBoundsWithMargins(child, childBounds);
-                int childCenter = canScrollHorizontally()
-                        ? childBounds.centerX() : childBounds.centerY();
-                int dist = Math.abs(boundsCenter - childCenter);
-                if (dist < minDist) {
-                    minDist = dist;
-                    closestChild = child;
-                }
-            }
-            return closestChild;
-        }
-
-        public WrappedLayoutManager(int spanCount, int orientation) {
-            super(spanCount, orientation);
-        }
-
-        ArrayList<ArrayList<View>> collectChildrenBySpan() {
-            ArrayList<ArrayList<View>> viewsBySpan = new ArrayList<ArrayList<View>>();
-            for (int i = 0; i < getSpanCount(); i++) {
-                viewsBySpan.add(new ArrayList<View>());
-            }
-            for (int i = 0; i < getChildCount(); i++) {
-                View view = getChildAt(i);
-                LayoutParams lp
-                        = (LayoutParams) view
-                        .getLayoutParams();
-                viewsBySpan.get(lp.mSpan.mIndex).add(view);
-            }
-            return viewsBySpan;
-        }
-
-        @Nullable
-        @Override
-        public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            View result = null;
-            try {
-                result = super.onFocusSearchFailed(focused, direction, recycler, state);
-                validateChildren();
-            } catch (Throwable t) {
-                postExceptionToInstrumentation(t);
-            }
-            return result;
-        }
-
-        Rect getViewBounds(View view) {
-            if (getOrientation() == HORIZONTAL) {
-                return new Rect(
-                        mPrimaryOrientation.getDecoratedStart(view),
-                        mSecondaryOrientation.getDecoratedStart(view),
-                        mPrimaryOrientation.getDecoratedEnd(view),
-                        mSecondaryOrientation.getDecoratedEnd(view));
-            } else {
-                return new Rect(
-                        mSecondaryOrientation.getDecoratedStart(view),
-                        mPrimaryOrientation.getDecoratedStart(view),
-                        mSecondaryOrientation.getDecoratedEnd(view),
-                        mPrimaryOrientation.getDecoratedEnd(view));
-            }
-        }
-
-        public String getBoundsLog() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("view bounds:[start:").append(mPrimaryOrientation.getStartAfterPadding())
-                    .append(",").append(" end").append(mPrimaryOrientation.getEndAfterPadding());
-            sb.append("\nchildren bounds\n");
-            final int childCount = getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View child = getChildAt(i);
-                sb.append("child (ind:").append(i).append(", pos:").append(getPosition(child))
-                        .append("[").append("start:").append(
-                        mPrimaryOrientation.getDecoratedStart(child)).append(", end:")
-                        .append(mPrimaryOrientation.getDecoratedEnd(child)).append("]\n");
-            }
-            return sb.toString();
-        }
-
-        public VisibleChildren traverseAndFindVisibleChildren() {
-            int childCount = getChildCount();
-            final VisibleChildren visibleChildren = new VisibleChildren(getSpanCount());
-            final int start = mPrimaryOrientation.getStartAfterPadding();
-            final int end = mPrimaryOrientation.getEndAfterPadding();
-            for (int i = 0; i < childCount; i++) {
-                View child = getChildAt(i);
-                final int childStart = mPrimaryOrientation.getDecoratedStart(child);
-                final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
-                final boolean fullyVisible = childStart >= start && childEnd <= end;
-                final boolean hidden = childEnd <= start || childStart >= end;
-                if (hidden) {
-                    continue;
-                }
-                final int position = getPosition(child);
-                final int span = getLp(child).getSpanIndex();
-                if (fullyVisible) {
-                    if (position < visibleChildren.firstFullyVisiblePositions[span] ||
-                            visibleChildren.firstFullyVisiblePositions[span]
-                                    == RecyclerView.NO_POSITION) {
-                        visibleChildren.firstFullyVisiblePositions[span] = position;
-                    }
-
-                    if (position > visibleChildren.lastFullyVisiblePositions[span]) {
-                        visibleChildren.lastFullyVisiblePositions[span] = position;
-                    }
-                }
-
-                if (position < visibleChildren.firstVisiblePositions[span] ||
-                        visibleChildren.firstVisiblePositions[span] == RecyclerView.NO_POSITION) {
-                    visibleChildren.firstVisiblePositions[span] = position;
-                }
-
-                if (position > visibleChildren.lastVisiblePositions[span]) {
-                    visibleChildren.lastVisiblePositions[span] = position;
-                }
-                if (visibleChildren.findFirstPartialVisibleClosestToStart == null) {
-                    visibleChildren.findFirstPartialVisibleClosestToStart = child;
-                }
-                visibleChildren.findFirstPartialVisibleClosestToEnd = child;
-            }
-            return visibleChildren;
-        }
-
-        Map<Item, Rect> collectChildCoordinates() throws Throwable {
-            final Map<Item, Rect> items = new LinkedHashMap<Item, Rect>();
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    final int start = mPrimaryOrientation.getStartAfterPadding();
-                    final int end = mPrimaryOrientation.getEndAfterPadding();
-                    final int childCount = getChildCount();
-                    for (int i = 0; i < childCount; i++) {
-                        View child = getChildAt(i);
-                        // ignore child if it fits the recycling constraints
-                        if (mPrimaryOrientation.getDecoratedStart(child) >= end
-                                || mPrimaryOrientation.getDecoratedEnd(child) < start) {
-                            continue;
-                        }
-                        LayoutParams lp = (LayoutParams) child.getLayoutParams();
-                        TestViewHolder vh = (TestViewHolder) lp.mViewHolder;
-                        items.put(vh.mBoundItem, getViewBounds(child));
-                    }
-                }
-            });
-            return items;
-        }
-
-
-        public void setFakeRtl(Boolean fakeRtl) {
-            mFakeRTL = fakeRtl;
-            try {
-                requestLayoutOnUIThread(mRecyclerView);
-            } catch (Throwable throwable) {
-                postExceptionToInstrumentation(throwable);
-            }
-        }
-
-        String layoutToString(String hint) {
-            StringBuilder sb = new StringBuilder();
-            sb.append("LAYOUT POSITIONS AND INDICES ").append(hint).append("\n");
-            for (int i = 0; i < getChildCount(); i++) {
-                final View view = getChildAt(i);
-                final LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
-                sb.append(String.format("index: %d pos: %d top: %d bottom: %d span: %d isFull:%s",
-                        i, getPosition(view),
-                        mPrimaryOrientation.getDecoratedStart(view),
-                        mPrimaryOrientation.getDecoratedEnd(view),
-                        layoutParams.getSpanIndex(), layoutParams.isFullSpan())).append("\n");
-            }
-            return sb.toString();
-        }
-
-        protected void validateChildren() {
-            validateChildren(null);
-        }
-
-        private void validateChildren(String msg) {
-            if (getChildCount() == 0 || mRecyclerView.mState.isPreLayout()) {
-                return;
-            }
-            final int dir = mShouldReverseLayout ? -1 : 1;
-            int i = 0;
-            int pos = -1;
-            while (i < getChildCount()) {
-                LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
-                if (lp.isItemRemoved()) {
-                    i++;
-                    continue;
-                }
-                pos = getPosition(getChildAt(i));
-                break;
-            }
-            if (pos == -1) {
-                return;
-            }
-            while (++i < getChildCount()) {
-                LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
-                if (lp.isItemRemoved()) {
-                    continue;
-                }
-                pos += dir;
-                if (getPosition(getChildAt(i)) != pos) {
-                    throw new RuntimeException("INVALID POSITION FOR CHILD " + i + "\n" +
-                            layoutToString("ERROR") + "\n msg:" + msg);
-                }
-            }
-        }
-
-        @Override
-        public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
-                LayoutPrefetchRegistry layoutPrefetchRegistry) {
-            if (prefetchLatch != null) prefetchLatch.countDown();
-            super.collectAdjacentPrefetchPositions(dx, dy, state, layoutPrefetchRegistry);
-        }
-    }
-
-    class GridTestAdapter extends TestAdapter {
-
-        int mOrientation;
-        int mRecyclerViewWidth;
-        int mRecyclerViewHeight;
-        Integer mSizeReference = null;
-
-        // original ids of items that should be full span
-        HashSet<Integer> mFullSpanItems = new HashSet<Integer>();
-
-        protected boolean mViewsHaveEqualSize = false; // size in the scrollable direction
-
-        protected OnBindCallback mOnBindCallback;
-
-        GridTestAdapter(int count, int orientation) {
-            super(count);
-            mOrientation = orientation;
-        }
-
-        @Override
-        public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                int viewType) {
-            mRecyclerViewWidth = parent.getWidth();
-            mRecyclerViewHeight = parent.getHeight();
-            TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
-            if (mOnBindCallback != null) {
-                mOnBindCallback.onCreatedViewHolder(vh);
-            }
-            return vh;
-        }
-
-        @Override
-        public void offsetOriginalIndices(int start, int offset) {
-            if (mFullSpanItems.size() > 0) {
-                HashSet<Integer> old = mFullSpanItems;
-                mFullSpanItems = new HashSet<Integer>();
-                for (Integer i : old) {
-                    if (i < start) {
-                        mFullSpanItems.add(i);
-                    } else if (offset > 0 || (start + Math.abs(offset)) <= i) {
-                        mFullSpanItems.add(i + offset);
-                    } else if (DEBUG) {
-                        Log.d(TAG, "removed full span item " + i);
-                    }
-                }
-            }
-            super.offsetOriginalIndices(start, offset);
-        }
-
-        @Override
-        protected void moveInUIThread(int from, int to) {
-            boolean setAsFullSpanAgain = mFullSpanItems.contains(from);
-            super.moveInUIThread(from, to);
-            if (setAsFullSpanAgain) {
-                mFullSpanItems.add(to);
-            }
-        }
-
-        @Override
-        public void onBindViewHolder(TestViewHolder holder,
-                int position) {
-            if (mSizeReference == null) {
-                mSizeReference = mOrientation == OrientationHelper.HORIZONTAL ? mRecyclerViewWidth
-                        / AVG_ITEM_PER_VIEW : mRecyclerViewHeight / AVG_ITEM_PER_VIEW;
-            }
-            super.onBindViewHolder(holder, position);
-
-            Item item = mItems.get(position);
-            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
-                    .getLayoutParams();
-            if (lp instanceof StaggeredGridLayoutManager.LayoutParams) {
-                ((StaggeredGridLayoutManager.LayoutParams) lp)
-                        .setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
-            } else {
-                StaggeredGridLayoutManager.LayoutParams slp
-                    = (StaggeredGridLayoutManager.LayoutParams) mLayoutManager
-                    .generateDefaultLayoutParams();
-                holder.itemView.setLayoutParams(slp);
-                slp.setFullSpan(mFullSpanItems.contains(item.mAdapterIndex));
-                lp = slp;
-            }
-
-            if (mOnBindCallback == null || mOnBindCallback.assignRandomSize()) {
-                final int minSize = mViewsHaveEqualSize ? mSizeReference :
-                        mSizeReference + 20 * (item.mId % 10);
-                if (mOrientation == OrientationHelper.HORIZONTAL) {
-                    holder.itemView.setMinimumWidth(minSize);
-                } else {
-                    holder.itemView.setMinimumHeight(minSize);
-                }
-                lp.topMargin = 3;
-                lp.leftMargin = 5;
-                lp.rightMargin = 7;
-                lp.bottomMargin = 9;
-            }
-            // Good to have colors for debugging
-            StateListDrawable stl = new StateListDrawable();
-            stl.addState(new int[]{android.R.attr.state_focused},
-                    new ColorDrawable(Color.RED));
-            stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-            //noinspection deprecation using this for kitkat tests
-            holder.itemView.setBackgroundDrawable(stl);
-            if (mOnBindCallback != null) {
-                mOnBindCallback.onBoundItem(holder, position);
-            }
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
deleted file mode 100644
index e963235..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentTest.java
+++ /dev/null
@@ -1,556 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v7.widget;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.support.annotation.Nullable;
-import android.support.v4.util.LongSparseArray;
-import android.support.v7.widget.TestedFrameLayout.FullControlLayoutParams;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.hamcrest.CoreMatchers;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Class to test any generic wrap content behavior.
- * It does so by running the same view scenario twice. Once with match parent setup to record all
- * dimensions and once with wrap_content setup. Then compares all child locations & ids +
- * RecyclerView size.
- */
-abstract public class BaseWrapContentTest extends BaseRecyclerViewInstrumentationTest {
-
-    static final boolean DEBUG = false;
-    static final String TAG = "WrapContentTest";
-    RecyclerView.LayoutManager mLayoutManager;
-
-    TestAdapter mTestAdapter;
-
-    LoggingItemAnimator mLoggingItemAnimator;
-
-    boolean mIsWrapContent;
-
-    protected final WrapContentConfig mWrapContentConfig;
-
-    public BaseWrapContentTest(WrapContentConfig config) {
-        mWrapContentConfig = config;
-    }
-
-    abstract RecyclerView.LayoutManager createLayoutManager();
-
-    void unspecifiedWithHintTest(boolean horizontal) throws Throwable {
-        final int itemHeight = 20;
-        final int itemWidth = 15;
-        RecyclerView.LayoutManager layoutManager = createLayoutManager();
-        WrappedRecyclerView rv = createRecyclerView(getActivity());
-        TestAdapter testAdapter = new TestAdapter(20) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                holder.itemView.setLayoutParams(new ViewGroup.LayoutParams(itemWidth, itemHeight));
-            }
-        };
-        rv.setLayoutManager(layoutManager);
-        rv.setAdapter(testAdapter);
-        TestedFrameLayout.FullControlLayoutParams lp =
-                new TestedFrameLayout.FullControlLayoutParams(0, 0);
-        if (horizontal) {
-            lp.wSpec = View.MeasureSpec.makeMeasureSpec(25, View.MeasureSpec.UNSPECIFIED);
-            lp.hSpec = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST);
-        } else {
-            lp.hSpec = View.MeasureSpec.makeMeasureSpec(25, View.MeasureSpec.UNSPECIFIED);
-            lp.wSpec = View.MeasureSpec.makeMeasureSpec(50, View.MeasureSpec.AT_MOST);
-        }
-        rv.setLayoutParams(lp);
-        setRecyclerView(rv);
-        rv.waitUntilLayout();
-
-        // we don't assert against the given size hint because LM will still ask for more if it
-        // lays out more children. This is the correct behavior because the spec is not AT_MOST,
-        // it is UNSPECIFIED.
-        if (horizontal) {
-            int expectedWidth = rv.getPaddingLeft() + rv.getPaddingRight() + itemWidth;
-            while (expectedWidth < 25) {
-                expectedWidth += itemWidth;
-            }
-            assertThat(rv.getWidth(), CoreMatchers.is(expectedWidth));
-        } else {
-            int expectedHeight = rv.getPaddingTop() + rv.getPaddingBottom() + itemHeight;
-            while (expectedHeight < 25) {
-                expectedHeight += itemHeight;
-            }
-            assertThat(rv.getHeight(), CoreMatchers.is(expectedHeight));
-        }
-    }
-
-    protected void testScenerio(Scenario scenario) throws Throwable {
-        FullControlLayoutParams matchParent = new FullControlLayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.MATCH_PARENT);
-        FullControlLayoutParams wrapContent = new FullControlLayoutParams(
-                ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
-        if (mWrapContentConfig.isUnlimitedHeight()) {
-            wrapContent.hSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
-        }
-        if (mWrapContentConfig.isUnlimitedWidth()) {
-            wrapContent.wSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
-        }
-
-        mIsWrapContent = false;
-        List<Snapshot> s1 = runScenario(scenario, matchParent, null);
-        mIsWrapContent = true;
-
-        List<Snapshot> s2 = runScenario(scenario, wrapContent, s1);
-        assertEquals("test sanity", s1.size(), s2.size());
-
-        for (int i = 0; i < s1.size(); i++) {
-            Snapshot step1 = s1.get(i);
-            Snapshot step2 = s2.get(i);
-            step1.assertSame(step2, i);
-        }
-    }
-
-    public List<Snapshot> runScenario(Scenario scenario, ViewGroup.LayoutParams lp,
-            @Nullable List<Snapshot> compareWith)
-            throws Throwable {
-        removeRecyclerView();
-        Item.idCounter.set(0);
-        List<Snapshot> result = new ArrayList<>();
-        RecyclerView.LayoutManager layoutManager = scenario.createLayoutManager();
-        WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity());
-        recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
-        recyclerView.setLayoutManager(layoutManager);
-        recyclerView.setLayoutParams(lp);
-        mLayoutManager = layoutManager;
-        mTestAdapter = new TestAdapter(scenario.getSeedAdapterSize());
-        recyclerView.setAdapter(mTestAdapter);
-        mLoggingItemAnimator = new LoggingItemAnimator();
-        recyclerView.setItemAnimator(mLoggingItemAnimator);
-        setRecyclerView(recyclerView);
-        recyclerView.waitUntilLayout();
-        int stepIndex = 0;
-        for (Step step : scenario.mStepList) {
-            mLoggingItemAnimator.reset();
-            step.onRun();
-            recyclerView.waitUntilLayout();
-            recyclerView.waitUntilAnimations();
-            Snapshot snapshot = takeSnapshot();
-            if (mIsWrapContent) {
-                snapshot.assertRvSize();
-            }
-            result.add(snapshot);
-            if (compareWith != null) {
-                compareWith.get(stepIndex).assertSame(snapshot, stepIndex);
-            }
-            stepIndex++;
-        }
-        recyclerView.waitUntilLayout();
-        recyclerView.waitUntilAnimations();
-        Snapshot snapshot = takeSnapshot();
-        if (mIsWrapContent) {
-            snapshot.assertRvSize();
-        }
-        result.add(snapshot);
-        if (compareWith != null) {
-            compareWith.get(stepIndex).assertSame(snapshot, stepIndex);
-        }
-        return result;
-    }
-
-    protected WrappedRecyclerView createRecyclerView(Activity activity) {
-        return new WrappedRecyclerView(getActivity());
-    }
-
-    void layoutAndCheck(TestedFrameLayout.FullControlLayoutParams lp,
-            BaseWrapContentWithAspectRatioTest.WrapContentAdapter adapter, Rect[] expected,
-            int width, int height) throws Throwable {
-        WrappedRecyclerView recyclerView = createRecyclerView(getActivity());
-        recyclerView.setBackgroundColor(Color.rgb(0, 0, 255));
-        recyclerView.setLayoutManager(createLayoutManager());
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutParams(lp);
-        Rect padding = mWrapContentConfig.padding;
-        recyclerView.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-        setRecyclerView(recyclerView);
-        recyclerView.waitUntilLayout();
-        Snapshot snapshot = takeSnapshot();
-        int index = 0;
-        Rect tmp = new Rect();
-        for (BaseWrapContentWithAspectRatioTest.MeasureBehavior behavior : adapter.behaviors) {
-            tmp.set(expected[index]);
-            tmp.offset(padding.left, padding.top);
-            assertThat("behavior " + index, snapshot.mChildCoordinates.get(behavior.getId()),
-                    is(tmp));
-            index ++;
-        }
-        Rect boundingBox = new Rect(0, 0, 0, 0);
-        for (Rect rect : expected) {
-            boundingBox.union(rect);
-        }
-        assertThat(recyclerView.getWidth(), is(width + padding.left + padding.right));
-        assertThat(recyclerView.getHeight(), is(height + padding.top + padding.bottom));
-    }
-
-
-    abstract protected int getVerticalGravity(RecyclerView.LayoutManager layoutManager);
-
-    abstract protected int getHorizontalGravity(RecyclerView.LayoutManager layoutManager);
-
-    protected Snapshot takeSnapshot() throws Throwable {
-        Snapshot snapshot = new Snapshot(mRecyclerView, mLoggingItemAnimator,
-                getHorizontalGravity(mLayoutManager), getVerticalGravity(mLayoutManager));
-        return snapshot;
-    }
-
-    abstract class Scenario {
-
-        ArrayList<Step> mStepList = new ArrayList<>();
-
-        public Scenario(Step... steps) {
-            Collections.addAll(mStepList, steps);
-        }
-
-        public int getSeedAdapterSize() {
-            return 10;
-        }
-
-        public RecyclerView.LayoutManager createLayoutManager() {
-            return BaseWrapContentTest.this.createLayoutManager();
-        }
-    }
-
-    abstract static class Step {
-
-        abstract void onRun() throws Throwable;
-    }
-
-    class Snapshot {
-
-        Rect mRawChildrenBox = new Rect();
-
-        Rect mRvSize = new Rect();
-
-        Rect mRvPadding = new Rect();
-
-        Rect mRvParentSize = new Rect();
-
-        LongSparseArray<Rect> mChildCoordinates = new LongSparseArray<>();
-
-        LongSparseArray<String> mAppear = new LongSparseArray<>();
-
-        LongSparseArray<String> mDisappear = new LongSparseArray<>();
-
-        LongSparseArray<String> mPersistent = new LongSparseArray<>();
-
-        LongSparseArray<String> mChanged = new LongSparseArray<>();
-
-        int mVerticalGravity;
-
-        int mHorizontalGravity;
-
-        int mOffsetX, mOffsetY;// how much we should offset children
-
-        public Snapshot(RecyclerView recyclerView, LoggingItemAnimator loggingItemAnimator,
-                int horizontalGravity, int verticalGravity)
-                throws Throwable {
-            mRvSize = getViewBounds(recyclerView);
-            mRvParentSize = getViewBounds((View) recyclerView.getParent());
-            mRvPadding = new Rect(recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(),
-                    recyclerView.getPaddingRight(), recyclerView.getPaddingBottom());
-            mVerticalGravity = verticalGravity;
-            mHorizontalGravity = horizontalGravity;
-            if (mVerticalGravity == Gravity.TOP) {
-                mOffsetY = 0;
-            } else {
-                mOffsetY = mRvParentSize.bottom - mRvSize.bottom;
-            }
-
-            if (mHorizontalGravity == Gravity.LEFT) {
-                mOffsetX = 0;
-            } else {
-                mOffsetX = mRvParentSize.right - mRvSize.right;
-            }
-            collectChildCoordinates(recyclerView);
-            if (loggingItemAnimator != null) {
-                collectInto(mAppear, loggingItemAnimator.mAnimateAppearanceList);
-                collectInto(mDisappear, loggingItemAnimator.mAnimateDisappearanceList);
-                collectInto(mPersistent, loggingItemAnimator.mAnimatePersistenceList);
-                collectInto(mChanged, loggingItemAnimator.mAnimateChangeList);
-            }
-        }
-
-        public boolean doesChildrenFitVertically() {
-            return mRawChildrenBox.top >= mRvPadding.top
-                    && mRawChildrenBox.bottom <= mRvSize.bottom - mRvPadding.bottom;
-        }
-
-        public boolean doesChildrenFitHorizontally() {
-            return mRawChildrenBox.left >= mRvPadding.left
-                    && mRawChildrenBox.right <= mRvSize.right - mRvPadding.right;
-        }
-
-        public void assertSame(Snapshot other, int step) {
-            if (mWrapContentConfig.isUnlimitedHeight() &&
-                    (!doesChildrenFitVertically() || !other.doesChildrenFitVertically())) {
-                if (DEBUG) {
-                    Log.d(TAG, "cannot assert coordinates because it does not fit vertically");
-                }
-                return;
-            }
-            if (mWrapContentConfig.isUnlimitedWidth() &&
-                    (!doesChildrenFitHorizontally() || !other.doesChildrenFitHorizontally())) {
-                if (DEBUG) {
-                    Log.d(TAG, "cannot assert coordinates because it does not fit horizontally");
-                }
-                return;
-            }
-            assertMap("child coordinates. step:" + step, mChildCoordinates,
-                    other.mChildCoordinates);
-            if (mWrapContentConfig.isUnlimitedHeight() || mWrapContentConfig.isUnlimitedWidth()) {
-                return;//cannot assert animatinos in unlimited size
-            }
-            assertMap("appearing step:" + step, mAppear, other.mAppear);
-            assertMap("disappearing step:" + step, mDisappear, other.mDisappear);
-            assertMap("persistent step:" + step, mPersistent, other.mPersistent);
-            assertMap("changed step:" + step, mChanged, other.mChanged);
-        }
-
-        private void assertMap(String prefix, LongSparseArray<?> map1, LongSparseArray<?> map2) {
-            StringBuilder logBuilder = new StringBuilder();
-            logBuilder.append(prefix).append("\n");
-            logBuilder.append("map1").append("\n");
-            logInto(map1, logBuilder);
-            logBuilder.append("map2").append("\n");
-            logInto(map2, logBuilder);
-            final String log = logBuilder.toString();
-            assertEquals(log + " same size", map1.size(), map2.size());
-            for (int i = 0; i < map1.size(); i++) {
-                assertAtIndex(log, map1, map2, i);
-            }
-        }
-
-        private void assertAtIndex(String prefix, LongSparseArray<?> map1, LongSparseArray<?> map2,
-                int index) {
-            long key1 = map1.keyAt(index);
-            long key2 = map2.keyAt(index);
-            assertEquals(prefix + "key mismatch at index " + index, key1, key2);
-            Object value1 = map1.valueAt(index);
-            Object value2 = map2.valueAt(index);
-            assertEquals(prefix + " value mismatch at index " + index, value1, value2);
-        }
-
-        private void logInto(LongSparseArray<?> map, StringBuilder sb) {
-            for (int i = 0; i < map.size(); i++) {
-                long key = map.keyAt(i);
-                Object value = map.valueAt(i);
-                sb.append(key).append(" : ").append(value).append("\n");
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder("Snapshot{\n");
-            sb.append("child coordinates:\n");
-            logInto(mChildCoordinates, sb);
-            sb.append("appear animations:\n");
-            logInto(mAppear, sb);
-            sb.append("disappear animations:\n");
-            logInto(mDisappear, sb);
-            sb.append("change animations:\n");
-            logInto(mChanged, sb);
-            sb.append("persistent animations:\n");
-            logInto(mPersistent, sb);
-            sb.append("}");
-            return sb.toString();
-        }
-
-        @Override
-        public int hashCode() {
-            int result = mChildCoordinates.hashCode();
-            result = 31 * result + mAppear.hashCode();
-            result = 31 * result + mDisappear.hashCode();
-            result = 31 * result + mPersistent.hashCode();
-            result = 31 * result + mChanged.hashCode();
-            return result;
-        }
-
-        private void collectInto(
-                LongSparseArray<String> target,
-                List<? extends BaseRecyclerViewAnimationsTest.AnimateLogBase> list) {
-            for (BaseRecyclerViewAnimationsTest.AnimateLogBase base : list) {
-                long id = getItemId(base.viewHolder);
-                assertNull(target.get(id));
-                target.put(id, log(base));
-            }
-        }
-
-        private String log(BaseRecyclerViewAnimationsTest.AnimateLogBase base) {
-            return base.getClass().getSimpleName() +
-                    ((TextView) base.viewHolder.itemView).getText() + ": " +
-                    "[pre:" + log(base.postInfo) +
-                    ", post:" + log(base.postInfo) + "]";
-        }
-
-        private String log(BaseRecyclerViewAnimationsTest.LoggingInfo postInfo) {
-            if (postInfo == null) {
-                return "?";
-            }
-            return "PI[flags: " + postInfo.changeFlags
-                    + ",l:" + (postInfo.left + mOffsetX)
-                    + ",t:" + (postInfo.top + mOffsetY)
-                    + ",r:" + (postInfo.right + mOffsetX)
-                    + ",b:" + (postInfo.bottom + mOffsetY) + "]";
-        }
-
-        void collectChildCoordinates(RecyclerView recyclerView) throws Throwable {
-            mRawChildrenBox = new Rect(0, 0, 0, 0);
-            final int childCount = recyclerView.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View child = recyclerView.getChildAt(i);
-                Rect childBounds = getChildBounds(recyclerView, child, true);
-                mRawChildrenBox.union(getChildBounds(recyclerView, child, false));
-                RecyclerView.ViewHolder childViewHolder = recyclerView.getChildViewHolder(child);
-                mChildCoordinates.put(getItemId(childViewHolder), childBounds);
-            }
-        }
-
-        private Rect getViewBounds(View view) {
-            return new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
-        }
-
-        private Rect getChildBounds(RecyclerView recyclerView, View child, boolean offset) {
-            RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
-            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
-            Rect rect = new Rect(layoutManager.getDecoratedLeft(child) - lp.leftMargin,
-                    layoutManager.getDecoratedTop(child) - lp.topMargin,
-                    layoutManager.getDecoratedRight(child) + lp.rightMargin,
-                    layoutManager.getDecoratedBottom(child) + lp.bottomMargin);
-            if (offset) {
-                rect.offset(mOffsetX, mOffsetY);
-            }
-            return rect;
-        }
-
-        private long getItemId(RecyclerView.ViewHolder vh) {
-            if (vh instanceof TestViewHolder) {
-                return ((TestViewHolder) vh).mBoundItem.mId;
-            } else if (vh instanceof BaseWrapContentWithAspectRatioTest.WrapContentViewHolder) {
-                BaseWrapContentWithAspectRatioTest.WrapContentViewHolder casted =
-                        (BaseWrapContentWithAspectRatioTest.WrapContentViewHolder) vh;
-                return casted.mView.mBehavior.getId();
-            } else {
-                throw new IllegalArgumentException("i don't support any VH");
-            }
-        }
-
-        public void assertRvSize() {
-            if (shouldWrapContentHorizontally()) {
-                int expectedW = mRawChildrenBox.width() + mRvPadding.left + mRvPadding.right;
-                assertTrue(mRvSize.width() + " <= " + expectedW, mRvSize.width() <= expectedW);
-            }
-            if (shouldWrapContentVertically()) {
-                int expectedH = mRawChildrenBox.height() + mRvPadding.top + mRvPadding.bottom;
-                assertTrue(mRvSize.height() + "<=" + expectedH, mRvSize.height() <= expectedH);
-            }
-        }
-    }
-
-    protected boolean shouldWrapContentHorizontally() {
-        return true;
-    }
-
-    protected boolean shouldWrapContentVertically() {
-        return true;
-    }
-
-    static class WrapContentConfig {
-
-        public boolean unlimitedWidth;
-        public boolean unlimitedHeight;
-        public Rect padding = new Rect(0, 0, 0, 0);
-
-        public WrapContentConfig(boolean unlimitedWidth, boolean unlimitedHeight) {
-            this.unlimitedWidth = unlimitedWidth;
-            this.unlimitedHeight = unlimitedHeight;
-        }
-
-        public WrapContentConfig(boolean unlimitedWidth, boolean unlimitedHeight, Rect padding) {
-            this.unlimitedWidth = unlimitedWidth;
-            this.unlimitedHeight = unlimitedHeight;
-            this.padding.set(padding);
-        }
-
-        public boolean isUnlimitedWidth() {
-            return unlimitedWidth;
-        }
-
-        public WrapContentConfig setUnlimitedWidth(boolean unlimitedWidth) {
-            this.unlimitedWidth = unlimitedWidth;
-            return this;
-        }
-
-        public boolean isUnlimitedHeight() {
-            return unlimitedHeight;
-        }
-
-        public WrapContentConfig setUnlimitedHeight(boolean unlimitedHeight) {
-            this.unlimitedHeight = unlimitedHeight;
-            return this;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(32);
-            sb.append("Rect("); sb.append(padding.left); sb.append(",");
-            sb.append(padding.top); sb.append("-"); sb.append(padding.right);
-            sb.append(","); sb.append(padding.bottom); sb.append(")");
-            return "WrapContentConfig{"
-                    + "unlimitedWidth=" + unlimitedWidth
-                    + ",unlimitedHeight=" + unlimitedHeight
-                    + ",padding=" + sb.toString()
-                    + '}';
-        }
-
-        public TestedFrameLayout.FullControlLayoutParams toLayoutParams(int wDim, int hDim) {
-            TestedFrameLayout.FullControlLayoutParams
-                    lp = new TestedFrameLayout.FullControlLayoutParams(
-                    wDim, hDim);
-            if (unlimitedWidth) {
-                lp.wSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
-            }
-            if (unlimitedHeight) {
-                lp.hSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
-            }
-            return lp;
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java
deleted file mode 100644
index b91c37a..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseWrapContentWithAspectRatioTest.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v7.widget;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.support.v4.util.Pair;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-
-abstract public class BaseWrapContentWithAspectRatioTest extends BaseRecyclerViewInstrumentationTest {
-    final BaseWrapContentTest.WrapContentConfig mWrapContentConfig;
-
-    protected BaseWrapContentWithAspectRatioTest(
-            BaseWrapContentTest.WrapContentConfig wrapContentConfig) {
-        mWrapContentConfig = wrapContentConfig;
-    }
-
-    int getSize(View view, int orientation) {
-        if (orientation == VERTICAL) {
-            return view.getHeight();
-        }
-        return view.getWidth();
-    }
-
-    static class LoggingView extends View {
-
-        MeasureBehavior mBehavior;
-
-        public void setBehavior(MeasureBehavior behavior) {
-            mBehavior = behavior;
-        }
-
-        public LoggingView(Context context) {
-            super(context);
-        }
-
-        public LoggingView(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public LoggingView(Context context, AttributeSet attrs, int defStyleAttr) {
-            super(context, attrs, defStyleAttr);
-        }
-
-        public LoggingView(Context context, AttributeSet attrs, int defStyleAttr,
-                int defStyleRes) {
-            super(context, attrs, defStyleAttr, defStyleRes);
-        }
-
-        @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            mBehavior.onMeasure(this, widthMeasureSpec, heightMeasureSpec);
-        }
-
-        @Override
-        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-            super.onLayout(changed, left, top, right, bottom);
-            mBehavior.onLayout(changed, left, top, right, bottom);
-        }
-
-        public void setMeasured(int w, int h) {
-            setMeasuredDimension(w, h);
-        }
-
-        public void prepareLayoutParams() {
-            mBehavior.setLayoutParams(this);
-        }
-    }
-
-    static class AspectRatioMeasureBehavior extends MeasureBehavior {
-
-        Float ratio;
-        int control;
-
-        public AspectRatioMeasureBehavior(int desiredW, int desiredH, int wMode, int hMode) {
-            super(desiredW, desiredH, wMode, hMode);
-        }
-
-        public AspectRatioMeasureBehavior aspectRatio(int control, float ratio) {
-            this.control = control;
-            this.ratio = ratio;
-            return this;
-        }
-
-        @Override
-        public void onMeasure(LoggingView view, int wSpec,
-                int hSpec) {
-            super.onMeasure(view, wSpec, hSpec);
-            if (control == VERTICAL) {
-                view.setMeasured(getSecondary(view.getMeasuredHeight()),
-                        view.getMeasuredHeight());
-            } else if (control == HORIZONTAL) {
-                view.setMeasured(view.getMeasuredWidth(),
-                        getSecondary(view.getMeasuredWidth()));
-            }
-        }
-
-        public int getSecondary(int controlSize) {
-            return (int) (controlSize * ratio);
-        }
-    }
-
-    static class MeasureBehavior {
-        private static final AtomicLong idCounter = new AtomicLong(0);
-        public List<Pair<Integer, Integer>> measureSpecs = new ArrayList<>();
-        public List<Pair<Integer, Integer>> layouts = new ArrayList<>();
-        int desiredW, desiredH;
-        final long mId = idCounter.incrementAndGet();
-
-        ViewGroup.MarginLayoutParams layoutParams;
-
-        public MeasureBehavior(int desiredW, int desiredH, int wMode, int hMode) {
-            this.desiredW = desiredW;
-            this.desiredH = desiredH;
-            layoutParams = new ViewGroup.MarginLayoutParams(
-                    wMode, hMode
-            );
-        }
-
-        public MeasureBehavior withMargins(int left, int top, int right, int bottom) {
-            layoutParams.leftMargin = left;
-            layoutParams.topMargin = top;
-            layoutParams.rightMargin = right;
-            layoutParams.bottomMargin = bottom;
-            return this;
-        }
-
-        public long getId() {
-            return mId;
-        }
-
-        public void onMeasure(LoggingView view, int wSpec, int hSpec) {
-            measureSpecs.add(new Pair<>(wSpec, hSpec));
-            view.setMeasured(
-                    RecyclerView.LayoutManager.chooseSize(wSpec, desiredW, 0),
-                    RecyclerView.LayoutManager.chooseSize(hSpec, desiredH, 0));
-        }
-
-        public int getSpec(int position, int orientation) {
-            if (orientation == VERTICAL) {
-                return measureSpecs.get(position).second;
-            } else {
-                return measureSpecs.get(position).first;
-            }
-        }
-
-        public void setLayoutParams(LoggingView view) {
-            view.setLayoutParams(layoutParams);
-        }
-
-        public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-            if (changed) {
-                layouts.add(new Pair<>(right - left, bottom - top));
-            }
-        }
-    }
-
-
-    static class WrapContentViewHolder extends RecyclerView.ViewHolder {
-
-        LoggingView mView;
-
-        public WrapContentViewHolder(ViewGroup parent) {
-            super(new LoggingView(parent.getContext()));
-            mView = (LoggingView) itemView;
-            mView.setBackgroundColor(Color.GREEN);
-        }
-    }
-
-    static class WrapContentAdapter extends RecyclerView.Adapter<WrapContentViewHolder> {
-
-        List<MeasureBehavior> behaviors = new ArrayList<>();
-
-        public WrapContentAdapter(MeasureBehavior... behaviors) {
-            Collections.addAll(this.behaviors, behaviors);
-        }
-
-        @Override
-        public WrapContentViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new WrapContentViewHolder(parent);
-        }
-
-        @Override
-        public void onBindViewHolder(WrapContentViewHolder holder, int position) {
-            holder.mView.setBehavior(behaviors.get(position));
-            holder.mView.prepareLayoutParams();
-        }
-
-        @Override
-        public int getItemCount() {
-            return behaviors.size();
-        }
-    }
-
-    static class MeasureSpecMatcher extends BaseMatcher<Integer> {
-
-        private boolean checkSize = false;
-        private boolean checkMode = false;
-        private int mSize;
-        private int mMode;
-
-        public static MeasureSpecMatcher is(int size, int mode) {
-            MeasureSpecMatcher matcher = new MeasureSpecMatcher(size, mode);
-            matcher.checkSize = true;
-            matcher.checkMode = true;
-            return matcher;
-        }
-
-        public static MeasureSpecMatcher size(int size) {
-            MeasureSpecMatcher matcher = new MeasureSpecMatcher(size, 0);
-            matcher.checkSize = true;
-            matcher.checkMode = false;
-            return matcher;
-        }
-
-        public static MeasureSpecMatcher mode(int mode) {
-            MeasureSpecMatcher matcher = new MeasureSpecMatcher(0, mode);
-            matcher.checkSize = false;
-            matcher.checkMode = true;
-            return matcher;
-        }
-
-        private MeasureSpecMatcher(int size, int mode) {
-            mSize = size;
-            mMode = mode;
-
-        }
-
-        @Override
-        public boolean matches(Object item) {
-            if (item == null) {
-                return false;
-            }
-            Integer intValue = (Integer) item;
-            final int size = View.MeasureSpec.getSize(intValue);
-            final int mode = View.MeasureSpec.getMode(intValue);
-            if (checkSize && size != mSize) {
-                return false;
-            }
-            if (checkMode && mode != mMode) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public void describeMismatch(Object item, Description description) {
-            Integer intValue = (Integer) item;
-            final int size = View.MeasureSpec.getSize(intValue);
-            final int mode = View.MeasureSpec.getMode(intValue);
-            if (checkSize && size != mSize) {
-                description.appendText(" Expected size was ").appendValue(mSize)
-                        .appendText(" but received size is ").appendValue(size);
-            }
-            if (checkMode && mode != mMode) {
-                description.appendText(" Expected mode was ").appendValue(modeName(mMode))
-                        .appendText(" but received mode is ").appendValue(modeName(mode));
-            }
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            if (checkSize) {
-                description.appendText(" Measure spec size:").appendValue(mSize);
-            }
-            if (checkMode) {
-                description.appendText(" Measure spec mode:").appendValue(modeName(mMode));
-            }
-        }
-
-        private static String modeName(int mode) {
-            switch (mode) {
-                case View.MeasureSpec.AT_MOST:
-                    return "at most";
-                case View.MeasureSpec.EXACTLY:
-                    return "exactly";
-                default:
-                    return "unspecified";
-            }
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/CustomEdgeEffectTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/CustomEdgeEffectTest.java
deleted file mode 100644
index 0644416..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/CustomEdgeEffectTest.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-
-import static android.support.v7.widget.RecyclerView.EdgeEffectFactory;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.support.annotation.NonNull;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.InputDeviceCompat;
-import android.support.v7.util.TouchUtils;
-import android.view.MotionEvent;
-import android.view.ViewGroup;
-import android.widget.EdgeEffect;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests custom edge effect are properly applied when scrolling.
- */
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class CustomEdgeEffectTest extends BaseRecyclerViewInstrumentationTest {
-
-    private static final int NUM_ITEMS = 10;
-
-    private LinearLayoutManager mLayoutManager;
-    private RecyclerView mRecyclerView;
-
-    @Before
-    public void setup() throws Throwable {
-        mLayoutManager = new LinearLayoutManager(getActivity());
-        mLayoutManager.ensureLayoutState();
-
-        mRecyclerView = new RecyclerView(getActivity());
-        mRecyclerView.setLayoutManager(mLayoutManager);
-        mRecyclerView.setAdapter(new TestAdapter(NUM_ITEMS) {
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                TestViewHolder holder = super.onCreateViewHolder(parent, viewType);
-                holder.itemView.setMinimumHeight(mRecyclerView.getMeasuredHeight() * 2 / NUM_ITEMS);
-                return holder;
-            }
-        });
-        setRecyclerView(mRecyclerView);
-        getInstrumentation().waitForIdleSync();
-        assertThat("Test sanity", mRecyclerView.getChildCount() > 0, is(true));
-    }
-
-    @Test
-    public void testEdgeEffectDirections() throws Throwable {
-        TestEdgeEffectFactory factory = new TestEdgeEffectFactory();
-        mRecyclerView.setEdgeEffectFactory(factory);
-        scrollToPosition(0);
-        waitForIdleScroll(mRecyclerView);
-        scrollViewBy(3);
-        assertNull(factory.mBottom);
-        assertNotNull(factory.mTop);
-        assertTrue(factory.mTop.mPullDistance > 0);
-
-        scrollToPosition(NUM_ITEMS - 1);
-        waitForIdleScroll(mRecyclerView);
-        scrollViewBy(-3);
-
-        assertNotNull(factory.mBottom);
-        assertTrue(factory.mBottom.mPullDistance > 0);
-    }
-
-    @Test
-    public void testEdgeEffectReplaced() throws Throwable {
-        TestEdgeEffectFactory factory1 = new TestEdgeEffectFactory();
-        mRecyclerView.setEdgeEffectFactory(factory1);
-        scrollToPosition(0);
-        waitForIdleScroll(mRecyclerView);
-
-        scrollViewBy(3);
-        assertNotNull(factory1.mTop);
-        float oldPullDistance = factory1.mTop.mPullDistance;
-
-        waitForIdleScroll(mRecyclerView);
-        TestEdgeEffectFactory factory2 = new TestEdgeEffectFactory();
-        mRecyclerView.setEdgeEffectFactory(factory2);
-        scrollViewBy(30);
-        assertNotNull(factory2.mTop);
-
-        assertTrue(factory2.mTop.mPullDistance > oldPullDistance);
-        assertEquals(oldPullDistance, factory1.mTop.mPullDistance, 0.1f);
-    }
-
-    private void scrollViewBy(final int value) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                TouchUtils.scrollView(MotionEvent.AXIS_VSCROLL, value,
-                        InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView);
-            }
-        });
-    }
-
-    private class TestEdgeEffectFactory extends EdgeEffectFactory {
-
-        TestEdgeEffect mTop, mBottom;
-
-        @NonNull
-        @Override
-        protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
-            TestEdgeEffect effect = new TestEdgeEffect(view.getContext());
-            if (direction == EdgeEffectFactory.DIRECTION_TOP) {
-                mTop = effect;
-            } else if (direction == EdgeEffectFactory.DIRECTION_BOTTOM) {
-                mBottom = effect;
-            }
-            return effect;
-        }
-    }
-
-    private class TestEdgeEffect extends EdgeEffect {
-
-        private float mPullDistance;
-
-        TestEdgeEffect(Context context) {
-            super(context);
-        }
-
-        @Override
-        public void onPull(float deltaDistance, float displacement) {
-            onPull(deltaDistance);
-        }
-
-        @Override
-        public void onPull(float deltaDistance) {
-            mPullDistance = deltaDistance;
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
deleted file mode 100644
index c28623f..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DefaultItemAnimatorTest.java
+++ /dev/null
@@ -1,443 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class DefaultItemAnimatorTest extends BaseRecyclerViewInstrumentationTest {
-
-    private static final String TAG = "DefaultItemAnimatorTest";
-    Throwable mainThreadException;
-
-    DefaultItemAnimator mAnimator;
-    Adapter mAdapter;
-    ViewGroup mDummyParent;
-    List<RecyclerView.ViewHolder> mExpectedItems = new ArrayList<RecyclerView.ViewHolder>();
-
-    Set<RecyclerView.ViewHolder> mRemoveFinished = new HashSet<RecyclerView.ViewHolder>();
-    Set<RecyclerView.ViewHolder> mAddFinished = new HashSet<RecyclerView.ViewHolder>();
-    Set<RecyclerView.ViewHolder> mMoveFinished = new HashSet<RecyclerView.ViewHolder>();
-    Set<RecyclerView.ViewHolder> mChangeFinished = new HashSet<RecyclerView.ViewHolder>();
-
-    Semaphore mExpectedItemCount = new Semaphore(0);
-
-    @Before
-    public void setUp() throws Exception {
-        mAnimator = new DefaultItemAnimator() {
-            @Override
-            public void onRemoveFinished(RecyclerView.ViewHolder item) {
-                try {
-                    assertTrue(mRemoveFinished.add(item));
-                    onFinished(item);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-
-            @Override
-            public void onAddFinished(RecyclerView.ViewHolder item) {
-                try {
-                    assertTrue(mAddFinished.add(item));
-                    onFinished(item);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-
-            @Override
-            public void onMoveFinished(RecyclerView.ViewHolder item) {
-                try {
-                    assertTrue(mMoveFinished.add(item));
-                    onFinished(item);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-
-            @Override
-            public void onChangeFinished(RecyclerView.ViewHolder item, boolean oldItem) {
-                try {
-                    assertTrue(mChangeFinished.add(item));
-                    onFinished(item);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-
-            private void onFinished(RecyclerView.ViewHolder item) {
-                assertNotNull(mExpectedItems.remove(item));
-                mExpectedItemCount.release(1);
-            }
-        };
-        mAdapter = new Adapter(20);
-        mDummyParent = getActivity().getContainer();
-    }
-
-    @Override
-    void checkForMainThreadException() throws Throwable {
-        if (mainThreadException != null) {
-            throw mainThreadException;
-        }
-    }
-
-    @Test
-    public void reUseWithPayload() {
-        RecyclerView.ViewHolder vh = new ViewHolder(new TextView(getActivity()));
-        assertFalse(mAnimator.canReuseUpdatedViewHolder(vh, new ArrayList<>()));
-        assertTrue(mAnimator.canReuseUpdatedViewHolder(vh, Arrays.asList((Object) "a")));
-    }
-
-    void expectItems(RecyclerView.ViewHolder... viewHolders) {
-        mExpectedItems.addAll(Arrays.asList(viewHolders));
-    }
-
-    void runAndWait(int itemCount, int seconds) throws Throwable {
-        runAndWait(itemCount, seconds, null);
-    }
-
-    void runAndWait(int itemCount, int seconds, final ThrowingRunnable postRun) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mAnimator.runPendingAnimations();
-                if (postRun != null) {
-                    try {
-                        postRun.run();
-                    } catch (Throwable e) {
-                        throw new RuntimeException(e);
-                    }
-                }
-            }
-        });
-        waitForItems(itemCount, seconds);
-        checkForMainThreadException();
-    }
-
-    void waitForItems(int itemCount, int seconds) throws InterruptedException {
-        assertTrue("all vh animations should end",
-                mExpectedItemCount.tryAcquire(itemCount, seconds, TimeUnit.SECONDS));
-        assertEquals("all expected finish events should happen", 0, mExpectedItems.size());
-        // wait one more second for unwanted
-        assertFalse("should not receive any more permits",
-                mExpectedItemCount.tryAcquire(1, 2, TimeUnit.SECONDS));
-    }
-
-    @Test
-    public void animateAdd() throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateAdd(vh));
-        assertTrue(mAnimator.isRunning());
-        runAndWait(1, 1);
-    }
-
-    @Test
-    public void animateRemove() throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateRemove(vh));
-        assertTrue(mAnimator.isRunning());
-        runAndWait(1, 1);
-    }
-
-    @Test
-    public void animateMove() throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateMove(vh, 0, 0, 100, 100));
-        assertTrue(mAnimator.isRunning());
-        runAndWait(1, 1);
-    }
-
-    @Test
-    public void animateChange() throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        ViewHolder vh2 = createViewHolder(2);
-        expectItems(vh, vh2);
-        assertTrue(animateChange(vh, vh2, 0, 0, 100, 100));
-        assertTrue(mAnimator.isRunning());
-        runAndWait(2, 1);
-    }
-
-    public void cancelBefore(int count, final RecyclerView.ViewHolder... toCancel)
-            throws Throwable {
-        cancelTest(true, count, toCancel);
-    }
-
-    public void cancelAfter(int count, final RecyclerView.ViewHolder... toCancel)
-            throws Throwable {
-        cancelTest(false, count, toCancel);
-    }
-
-    public void cancelTest(boolean before, int count, final RecyclerView.ViewHolder... toCancel) throws Throwable {
-        if (before) {
-            endAnimations(toCancel);
-            runAndWait(count, 1);
-        } else {
-            runAndWait(count, 1, new ThrowingRunnable() {
-                @Override
-                public void run() throws Throwable {
-                    endAnimations(toCancel);
-                }
-            });
-        }
-    }
-
-    @Test
-    public void cancelAddBefore() throws Throwable {
-        final ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateAdd(vh));
-        cancelBefore(1, vh);
-    }
-
-    @Test
-    public void cancelAddAfter() throws Throwable {
-        final ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateAdd(vh));
-        cancelAfter(1, vh);
-    }
-
-    @Test
-    public void cancelMoveBefore() throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateMove(vh, 10, 10, 100, 100));
-        cancelBefore(1, vh);
-    }
-
-    @Test
-    public void cancelMoveAfter() throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateMove(vh, 10, 10, 100, 100));
-        cancelAfter(1, vh);
-    }
-
-    @Test
-    public void cancelRemove() throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        expectItems(vh);
-        assertTrue(animateRemove(vh));
-        endAnimations(vh);
-        runAndWait(1, 1);
-    }
-
-    @Test
-    public void cancelChangeOldBefore() throws Throwable {
-        cancelChangeOldTest(true);
-    }
-    @Test
-    public void cancelChangeOldAfter() throws Throwable {
-        cancelChangeOldTest(false);
-    }
-
-    public void cancelChangeOldTest(boolean before) throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        ViewHolder vh2 = createViewHolder(1);
-        expectItems(vh, vh2);
-        assertTrue(animateChange(vh, vh2, 20, 20, 100, 100));
-        cancelTest(before, 2, vh);
-    }
-
-    @Test
-    public void cancelChangeNewBefore() throws Throwable {
-        cancelChangeNewTest(true);
-    }
-
-    @Test
-    public void cancelChangeNewAfter() throws Throwable {
-        cancelChangeNewTest(false);
-    }
-
-    public void cancelChangeNewTest(boolean before) throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        ViewHolder vh2 = createViewHolder(1);
-        expectItems(vh, vh2);
-        assertTrue(animateChange(vh, vh2, 20, 20, 100, 100));
-        cancelTest(before, 2, vh2);
-    }
-
-    @Test
-    public void cancelChangeBothBefore() throws Throwable {
-        cancelChangeBothTest(true);
-    }
-
-    @Test
-    public void cancelChangeBothAfter() throws Throwable {
-        cancelChangeBothTest(false);
-    }
-
-    public void cancelChangeBothTest(boolean before) throws Throwable {
-        ViewHolder vh = createViewHolder(1);
-        ViewHolder vh2 = createViewHolder(1);
-        expectItems(vh, vh2);
-        assertTrue(animateChange(vh, vh2, 20, 20, 100, 100));
-        cancelTest(before, 2, vh, vh2);
-    }
-
-    void endAnimations(final RecyclerView.ViewHolder... vhs) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (RecyclerView.ViewHolder vh : vhs) {
-                    mAnimator.endAnimation(vh);
-                }
-            }
-        });
-    }
-
-    boolean animateAdd(final RecyclerView.ViewHolder vh) throws Throwable {
-        final boolean[] result = new boolean[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = mAnimator.animateAdd(vh);
-            }
-        });
-        return result[0];
-    }
-
-    boolean animateRemove(final RecyclerView.ViewHolder vh) throws Throwable {
-        final boolean[] result = new boolean[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = mAnimator.animateRemove(vh);
-            }
-        });
-        return result[0];
-    }
-
-    boolean animateMove(final RecyclerView.ViewHolder vh, final int fromX, final int fromY,
-            final int toX, final int toY) throws Throwable {
-        final boolean[] result = new boolean[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = mAnimator.animateMove(vh, fromX, fromY, toX, toY);
-            }
-        });
-        return result[0];
-    }
-
-    boolean animateChange(final RecyclerView.ViewHolder oldHolder,
-            final RecyclerView.ViewHolder newHolder,
-            final int fromX, final int fromY, final int toX, final int toY) throws Throwable {
-        final boolean[] result = new boolean[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = mAnimator.animateChange(oldHolder, newHolder, fromX, fromY, toX, toY);
-            }
-        });
-        return result[0];
-    }
-
-    private ViewHolder createViewHolder(final int pos) throws Throwable {
-        final ViewHolder vh = mAdapter.createViewHolder(mDummyParent, 1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mAdapter.bindViewHolder(vh, pos);
-                mDummyParent.addView(vh.itemView);
-            }
-        });
-
-        return vh;
-    }
-
-    @Override
-    void postExceptionToInstrumentation(Throwable t) {
-        if (mainThreadException == null) {
-            mainThreadException = t;
-        } else {
-            Log.e(TAG, "skipping secondary main thread exception", t);
-        }
-    }
-
-
-    private class Adapter extends RecyclerView.Adapter<ViewHolder> {
-
-        List<String> mItems;
-
-        private Adapter(int count) {
-            mItems = new ArrayList<>();
-            for (int i = 0; i < count; i++) {
-                mItems.add("item-" + i);
-            }
-        }
-
-        @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new ViewHolder(new TextView(parent.getContext()));
-        }
-
-        @Override
-        public void onBindViewHolder(ViewHolder holder, int position) {
-            holder.bind(mItems.get(position));
-        }
-
-        @Override
-        public int getItemCount() {
-            return mItems.size();
-        }
-    }
-
-    private class ViewHolder extends RecyclerView.ViewHolder {
-
-        String mBindedText;
-
-        public ViewHolder(View itemView) {
-            super(itemView);
-        }
-
-        public void bind(String text) {
-            mBindedText = text;
-            ((TextView) itemView).setText(text);
-        }
-    }
-
-    private interface ThrowingRunnable {
-        void run() throws Throwable;
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/DividerItemDecorationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/DividerItemDecorationTest.java
deleted file mode 100644
index 6459522..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/DividerItemDecorationTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.recyclerview.test.R;
-import android.view.ContextThemeWrapper;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link DividerItemDecoration}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class DividerItemDecorationTest {
-    private static final String[] STRINGS = {"Foo", "Bar", "Great"};
-
-    @Test
-    public void testNullListDivider() {
-        final Context context = InstrumentationRegistry.getContext();
-        RecyclerView rv = new RecyclerView(context);
-        rv.setLayoutManager(new LinearLayoutManager(context));
-        rv.setAdapter(new MyAdapter(STRINGS));
-        DividerItemDecoration decoration = new DividerItemDecoration(
-                new ContextThemeWrapper(context, R.style.nullListDivider),
-                DividerItemDecoration.HORIZONTAL);
-        rv.addItemDecoration(decoration);
-        rv.layout(0, 0, 1000, 1000);
-        decoration.onDraw(new Canvas(), rv, null);
-    }
-
-    private static class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
-        private String[] mDataset;
-
-        public static class ViewHolder extends RecyclerView.ViewHolder {
-            TextView mTextView;
-            ViewHolder(TextView v) {
-                super(v);
-                mTextView = v;
-            }
-        }
-
-        MyAdapter(String[] myDataset) {
-            mDataset = myDataset;
-        }
-
-        @Override
-        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new ViewHolder(new TextView(parent.getContext()));
-        }
-
-        @Override
-        public void onBindViewHolder(ViewHolder holder, int position) {
-            holder.mTextView.setText(mDataset[position]);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mDataset.length;
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
deleted file mode 100644
index 3755018..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/FocusSearchNavigationTest.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-
-import static android.support.v7.widget.RecyclerView.HORIZONTAL;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static android.support.v7.widget.RecyclerView.VERTICAL;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.content.Context;
-import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.recyclerview.test.R;
-import android.support.v7.widget.test.RecyclerViewTestActivity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.widget.LinearLayout;
-
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.Description;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * This class tests RecyclerView focus search failure handling by using a real LayoutManager.
- */
-@LargeTest
-@RunWith(Parameterized.class)
-public class FocusSearchNavigationTest {
-    @Rule
-    public ActivityTestRule<RecyclerViewTestActivity> mActivityRule =
-            new ActivityTestRule<>(RecyclerViewTestActivity.class);
-
-    private final int mOrientation;
-    private final int mLayoutDir;
-
-    public FocusSearchNavigationTest(int orientation, int layoutDir) {
-        mOrientation = orientation;
-        mLayoutDir = layoutDir;
-    }
-
-    @Parameterized.Parameters(name = "orientation:{0},layoutDir:{1}")
-    public static List<Object[]> params() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            return Arrays.asList(
-                    new Object[]{VERTICAL, ViewCompat.LAYOUT_DIRECTION_LTR},
-                    new Object[]{HORIZONTAL, ViewCompat.LAYOUT_DIRECTION_LTR},
-                    new Object[]{HORIZONTAL, ViewCompat.LAYOUT_DIRECTION_RTL}
-            );
-        } else {
-            // Do not test RTL before API 17
-            return Arrays.asList(
-                    new Object[]{VERTICAL, ViewCompat.LAYOUT_DIRECTION_LTR},
-                    new Object[]{HORIZONTAL, ViewCompat.LAYOUT_DIRECTION_LTR}
-            );
-        }
-    }
-
-    private Activity mActivity;
-    private RecyclerView mRecyclerView;
-    private View mBefore;
-    private View mAfter;
-
-    private void setup(final int itemCount) throws Throwable {
-        mActivity = mActivityRule.getActivity();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.setContentView(R.layout.focus_search_activity);
-                ViewCompat.setLayoutDirection(mActivity.getWindow().getDecorView(), mLayoutDir);
-                LinearLayout linearLayout = (LinearLayout) mActivity.findViewById(R.id.root);
-                linearLayout.setOrientation(mOrientation);
-                mRecyclerView = (RecyclerView) mActivity.findViewById(R.id.recycler_view);
-                ViewCompat.setLayoutDirection(mRecyclerView, mLayoutDir);
-                LinearLayoutManager layout = new LinearLayoutManager(mActivity.getBaseContext());
-                layout.setOrientation(mOrientation);
-                mRecyclerView.setLayoutManager(layout);
-                mRecyclerView.setAdapter(new FocusSearchAdapter(itemCount, mOrientation));
-                if (mOrientation == VERTICAL) {
-                    mRecyclerView.setLayoutParams(new LinearLayout.LayoutParams(
-                            ViewGroup.LayoutParams.MATCH_PARENT, 250));
-                } else {
-                    mRecyclerView.setLayoutParams(new LinearLayout.LayoutParams(
-                            250, ViewGroup.LayoutParams.MATCH_PARENT));
-                }
-
-                mBefore = mActivity.findViewById(R.id.before);
-                mAfter = mActivity.findViewById(R.id.after);
-            }
-        });
-        waitForIdleSync();
-        assertThat("test sanity", mRecyclerView.getLayoutManager().getLayoutDirection(),
-                is(mLayoutDir));
-        assertThat("test sanity", ViewCompat.getLayoutDirection(mRecyclerView), is(mLayoutDir));
-    }
-
-    @Test
-    public void focusSearchForward() throws Throwable {
-        setup(20);
-        requestFocus(mBefore);
-        assertThat(mBefore, hasFocus());
-        View focused = mBefore;
-        for (int i = 0; i < 20; i++) {
-            focusSearchAndGive(focused, View.FOCUS_FORWARD);
-            RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertThat("vh at " + i, viewHolder, hasFocus());
-            focused = viewHolder.itemView;
-        }
-        focusSearchAndGive(focused, View.FOCUS_FORWARD);
-        assertThat(mAfter, hasFocus());
-        focusSearchAndGive(mAfter, View.FOCUS_FORWARD);
-        assertThat(mBefore, hasFocus());
-        focusSearchAndGive(mBefore, View.FOCUS_FORWARD);
-        focused = mActivity.getCurrentFocus();
-        //noinspection ConstantConditions
-        assertThat(focused.getParent(), CoreMatchers.<ViewParent>sameInstance(mRecyclerView));
-    }
-
-    @Test
-    public void focusSearchBackwards() throws Throwable {
-        setup(20);
-        requestFocus(mAfter);
-        assertThat(mAfter, hasFocus());
-        View focused = mAfter;
-        RecyclerView.ViewHolder lastViewHolder = null;
-        int i = 20;
-        while(lastViewHolder == null) {
-            lastViewHolder = mRecyclerView.findViewHolderForAdapterPosition(--i);
-        }
-        assertThat(lastViewHolder, notNullValue());
-
-        while(i >= 0) {
-            focusSearchAndGive(focused, View.FOCUS_BACKWARD);
-            RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertThat("vh at " + i, viewHolder, hasFocus());
-            focused = viewHolder.itemView;
-            i--;
-        }
-        focusSearchAndGive(focused, View.FOCUS_BACKWARD);
-        assertThat(mBefore, hasFocus());
-        focusSearchAndGive(mBefore, View.FOCUS_BACKWARD);
-        assertThat(mAfter, hasFocus());
-    }
-
-    private View focusSearchAndGive(final View view, final int focusDir) throws Throwable {
-        View next = focusSearch(view, focusDir);
-        if (next != null && next != view) {
-            requestFocus(next);
-            return next;
-        }
-        return null;
-    }
-
-    private View focusSearch(final View view, final int focusDir) throws Throwable {
-        final View[] result = new View[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = view.focusSearch(focusDir);
-            }
-        });
-        waitForIdleSync();
-        return result[0];
-    }
-
-    private void waitForIdleSync() throws Throwable {
-        waitForIdleScroll(mRecyclerView);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-    }
-
-    private void requestFocus(final View view) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.requestFocus();
-            }
-        });
-        waitForIdleSync();
-    }
-
-    public void waitForIdleScroll(final RecyclerView recyclerView) throws Throwable {
-        final CountDownLatch latch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                RecyclerView.OnScrollListener listener = new RecyclerView.OnScrollListener() {
-                    @Override
-                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                        if (newState == SCROLL_STATE_IDLE) {
-                            latch.countDown();
-                            recyclerView.removeOnScrollListener(this);
-                        }
-                    }
-                };
-                if (recyclerView.getScrollState() == SCROLL_STATE_IDLE) {
-                    latch.countDown();
-                } else {
-                    recyclerView.addOnScrollListener(listener);
-                }
-            }
-        });
-        assertTrue("should go idle in 10 seconds", latch.await(10, TimeUnit.SECONDS));
-    }
-
-    static class FocusSearchAdapter extends RecyclerView.Adapter {
-        private int mItemCount;
-        private int mOrientation;
-        public FocusSearchAdapter(int itemCount, int orientation) {
-            mItemCount = itemCount;
-            mOrientation = orientation;
-        }
-
-        @Override
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
-        int viewType) {
-            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view,
-                    parent, false);
-            if (mOrientation == VERTICAL) {
-                view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                        50));
-            } else {
-                view.setLayoutParams(new ViewGroup.LayoutParams(50,
-                        ViewGroup.LayoutParams.MATCH_PARENT));
-            }
-            return new RecyclerView.ViewHolder(view) {};
-        }
-
-        @Override
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-            holder.itemView.setTag("pos " + position);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mItemCount;
-        }
-    }
-
-    static HasFocusMatcher hasFocus() {
-        return new HasFocusMatcher();
-    }
-
-    static class HasFocusMatcher extends BaseMatcher<Object> {
-        @Override
-        public boolean matches(Object item) {
-            if (item instanceof RecyclerView.ViewHolder) {
-                item = ((RecyclerView.ViewHolder) item).itemView;
-            }
-            return item instanceof View && ((View) item).hasFocus();
-        }
-
-        @Override
-        public void describeTo(Description description) {
-            description.appendText("view has focus");
-        }
-
-        private String objectToLog(Object item) {
-            if (item instanceof RecyclerView.ViewHolder) {
-                RecyclerView.ViewHolder vh = (RecyclerView.ViewHolder) item;
-                return vh.toString();
-            }
-            if (item instanceof View) {
-                final Object tag = ((View) item).getTag();
-                return tag == null ? item.toString() : tag.toString();
-            }
-            final String classLog = item == null ? "null" : item.getClass().getSimpleName();
-            return classLog;
-        }
-
-        @Override
-        public void describeMismatch(Object item, Description description) {
-            String noun = objectToLog(item);
-            description.appendText(noun + " does not have focus");
-            Context context = null;
-            if (item instanceof RecyclerView.ViewHolder) {
-                context = ((RecyclerView.ViewHolder)item).itemView.getContext();
-            } else  if (item instanceof View) {
-                context = ((View) item).getContext();
-            }
-            if (context instanceof Activity) {
-                View currentFocus = ((Activity) context).getWindow().getCurrentFocus();
-                description.appendText(". Current focus is in " + objectToLog(currentFocus));
-            }
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
deleted file mode 100644
index dec0d72..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerCustomSizeInScrollDirectionTest.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Rect;
-import android.support.test.filters.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@MediumTest
-@RunWith(Parameterized.class)
-public class GridLayoutManagerCustomSizeInScrollDirectionTest extends BaseGridLayoutManagerTest {
-    @Parameterized.Parameters(name = "addDecorOffsets:{1},addMargins:{2},config:{0}")
-    public static List<Object[]> getParams() {
-        List<Object[]> params = new ArrayList<>();
-        Boolean[] options = new Boolean[]{true, false};
-        for (boolean addMargins : options) {
-            for (boolean addDecorOffsets : options) {
-                params.add(new Object[] {
-                        new Config(3, HORIZONTAL, false), addDecorOffsets, addMargins});
-                params.add(new Object[] {
-                        new Config(3, VERTICAL, false), addDecorOffsets, addMargins});
-            }
-        }
-        return params;
-    }
-
-    private final boolean mAddDecorOffsets;
-    private final boolean mAddMargins;
-    private final Config mConfig;
-
-    public GridLayoutManagerCustomSizeInScrollDirectionTest(Config config, boolean addDecorOffsets,
-            boolean addMargins) {
-        mConfig = config;
-        mAddDecorOffsets = addDecorOffsets;
-        mAddMargins = addMargins;
-    }
-
-    @Test
-    public void customSizeInScrollDirectionTest() throws Throwable {
-        final int decorOffset = mAddDecorOffsets ? 7 : 0;
-        final int margin = mAddMargins ? 11 : 0;
-        final int[] sizePerPosition = new int[]{3, 5, 9, 21, 3, 5, 9, 6, 9, 1};
-        final int[] expectedSizePerPosition = new int[]{9, 9, 9, 21, 3, 5, 9, 9, 9, 1};
-
-        final GridTestAdapter testAdapter = new GridTestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)
-                        holder.itemView.getLayoutParams();
-                if (layoutParams == null) {
-                    layoutParams = new ViewGroup.MarginLayoutParams(
-                            ViewGroup.LayoutParams.WRAP_CONTENT,
-                            ViewGroup.LayoutParams.WRAP_CONTENT);
-                    holder.itemView.setLayoutParams(layoutParams);
-                }
-                final int size = sizePerPosition[position];
-                if (mConfig.mOrientation == HORIZONTAL) {
-                    layoutParams.width = size;
-                    layoutParams.leftMargin = margin;
-                    layoutParams.rightMargin = margin;
-                } else {
-                    layoutParams.height = size;
-                    layoutParams.topMargin = margin;
-                    layoutParams.bottomMargin = margin;
-                }
-            }
-        };
-        testAdapter.setFullSpan(3, 5);
-        final RecyclerView rv = setupBasic(mConfig, testAdapter);
-        if (mAddDecorOffsets) {
-            rv.addItemDecoration(new RecyclerView.ItemDecoration() {
-                @Override
-                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                        RecyclerView.State state) {
-                    if (mConfig.mOrientation == HORIZONTAL) {
-                        outRect.set(decorOffset, 0, decorOffset, 0);
-                    } else {
-                        outRect.set(0, decorOffset, 0, decorOffset);
-                    }
-                }
-            });
-        }
-        waitForFirstLayout(rv);
-
-        assertTrue("[test sanity] some views should be laid out",
-                mRecyclerView.getChildCount() > 0);
-        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
-            View child = mRecyclerView.getChildAt(i);
-            final int size = mConfig.mOrientation == HORIZONTAL ? child.getWidth()
-                    : child.getHeight();
-            assertEquals("child " + i + " should have the size specified in its layout params",
-                    expectedSizePerPosition[i], size);
-        }
-        checkForMainThreadException();
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java
deleted file mode 100644
index 3343ff5..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerRtlTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.support.test.filters.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@MediumTest
-@RunWith(Parameterized.class)
-public class GridLayoutManagerRtlTest extends BaseGridLayoutManagerTest {
-
-    public GridLayoutManagerRtlTest(Config config, boolean changeRtlAfter, boolean oneLine,
-            boolean itemsWrapContent) {
-        mConfig = config;
-        mChangeRtlAfter = changeRtlAfter;
-        mOneLine = oneLine;
-        mItemsWrapContent = itemsWrapContent;
-    }
-
-    @Parameterized.Parameters(name = "conf:{0},changeRl:{1},oneLine:{2},itemsWrap:{3}")
-    public static List<Object[]> params() {
-        List<Object[]> result = new ArrayList<>();
-        for (boolean changeRtlAfter : new boolean[]{false, true}) {
-            for (boolean oneLine : new boolean[]{false, true}) {
-                for (boolean itemsWrapContent : new boolean[]{false, true}) {
-                    for (Config config : createBaseVariations()) {
-                        result.add(new Object[] {
-                                config,
-                                changeRtlAfter,
-                                oneLine,
-                                itemsWrapContent
-                        });
-                    }
-                }
-            }
-        }
-        return result;
-    }
-    final Config mConfig;
-    final boolean mChangeRtlAfter;
-    final boolean mOneLine;
-    final boolean mItemsWrapContent;
-
-
-    @Test
-    public void rtlTest() throws Throwable {
-        if (mOneLine && mConfig.mOrientation != VERTICAL) {
-            return;// nothing to test
-        }
-        if (mConfig.mSpanCount == 1) {
-            mConfig.mSpanCount = 2;
-        }
-        String logPrefix = mConfig + ", changeRtlAfterLayout:" + mChangeRtlAfter + ","
-                + "oneLine:" + mOneLine + " itemsWrap:" + mItemsWrapContent;
-        mConfig.mItemCount = 5;
-        if (mOneLine) {
-            mConfig.mSpanCount = mConfig.mItemCount + 1;
-        } else {
-            mConfig.mSpanCount = Math.min(mConfig.mItemCount - 1, mConfig.mSpanCount);
-        }
-
-        RecyclerView rv = setupBasic(mConfig, new GridTestAdapter(mConfig.mItemCount) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (mItemsWrapContent) {
-                    ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-                    if (lp == null) {
-                        lp = mGlm.generateDefaultLayoutParams();
-                    }
-                    if (mConfig.mOrientation == HORIZONTAL) {
-                        lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
-                    } else {
-                        lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
-                    }
-                }
-            }
-        });
-        if (mChangeRtlAfter) {
-            waitForFirstLayout(rv);
-            mGlm.expectLayout(1);
-            mGlm.setFakeRtl(true);
-            mGlm.waitForLayout(2);
-        } else {
-            mGlm.mFakeRTL = true;
-            waitForFirstLayout(rv);
-        }
-
-        assertEquals("view should become rtl", true, mGlm.isLayoutRTL());
-        OrientationHelper helper = OrientationHelper.createHorizontalHelper(mGlm);
-        View child0 = mGlm.findViewByPosition(0);
-        final int secondChildPos = mConfig.mOrientation == VERTICAL ? 1
-                : mConfig.mSpanCount;
-        View child1 = mGlm.findViewByPosition(secondChildPos);
-        assertNotNull(logPrefix + " child position 0 should be laid out", child0);
-        assertNotNull(
-                logPrefix + " second child position " + (secondChildPos) + " should be laid out",
-                child1);
-        if (mConfig.mOrientation == VERTICAL || !mConfig.mReverseLayout) {
-            assertTrue(logPrefix + " second child should be to the left of first child",
-                    helper.getDecoratedStart(child0) >= helper.getDecoratedEnd(child1));
-            assertEquals(logPrefix + " first child should be right aligned",
-                    helper.getDecoratedEnd(child0), helper.getEndAfterPadding());
-        } else {
-            assertTrue(logPrefix + " first child should be to the left of second child",
-                    helper.getDecoratedStart(child1) >= helper.getDecoratedEnd(child0));
-            assertEquals(logPrefix + " first child should be left aligned",
-                    helper.getDecoratedStart(child0), helper.getStartAfterPadding());
-        }
-        checkForMainThreadException();
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
deleted file mode 100644
index 985fd93..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ /dev/null
@@ -1,1305 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.os.Build;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.util.SparseIntArray;
-import android.util.StateSet;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.hamcrest.CoreMatchers;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class GridLayoutManagerTest extends BaseGridLayoutManagerTest {
-
-    @Test
-    public void focusSearchFailureUp() throws Throwable {
-        focusSearchFailure(false);
-    }
-
-    @Test
-    public void focusSearchFailureDown() throws Throwable {
-        focusSearchFailure(true);
-    }
-
-    @Test
-    public void scrollToBadOffset() throws Throwable {
-        scrollToBadOffset(false);
-    }
-
-    @Test
-    public void scrollToBadOffsetReverse() throws Throwable {
-        scrollToBadOffset(true);
-    }
-
-    private void scrollToBadOffset(boolean reverseLayout) throws Throwable {
-        final int w = 500;
-        final int h = 1000;
-        RecyclerView recyclerView = setupBasic(new Config(2, 100).reverseLayout(reverseLayout),
-                new GridTestAdapter(100) {
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-                        if (lp == null) {
-                            lp = new ViewGroup.LayoutParams(w / 2, h / 2);
-                            holder.itemView.setLayoutParams(lp);
-                        } else {
-                            lp.width = w / 2;
-                            lp.height = h / 2;
-                            holder.itemView.setLayoutParams(lp);
-                        }
-                    }
-                });
-        TestedFrameLayout.FullControlLayoutParams lp
-                = new TestedFrameLayout.FullControlLayoutParams(w, h);
-        recyclerView.setLayoutParams(lp);
-        waitForFirstLayout(recyclerView);
-        mGlm.expectLayout(1);
-        scrollToPosition(11);
-        mGlm.waitForLayout(2);
-        // assert spans and position etc
-        for (int i = 0; i < mGlm.getChildCount(); i++) {
-            View child = mGlm.getChildAt(i);
-            GridLayoutManager.LayoutParams params = (GridLayoutManager.LayoutParams) child
-                    .getLayoutParams();
-            assertThat("span index for child at " + i + " with position " + params
-                            .getViewAdapterPosition(),
-                    params.getSpanIndex(), CoreMatchers.is(params.getViewAdapterPosition() % 2));
-        }
-        // assert spans and positions etc.
-        int lastVisible = mGlm.findLastVisibleItemPosition();
-        // this should be the scrolled child
-        assertThat(lastVisible, CoreMatchers.is(11));
-    }
-
-    private void focusSearchFailure(boolean scrollDown) throws Throwable {
-        final RecyclerView recyclerView = setupBasic(new Config(3, 31).reverseLayout(!scrollDown)
-                , new GridTestAdapter(31, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        testViewHolder.itemView.setFocusable(true);
-                        testViewHolder.itemView.setFocusableInTouchMode(true);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation using this for kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / 3);
-                    }
-                });
-        waitForFirstLayout(recyclerView);
-
-        View viewToFocus = recyclerView.findViewHolderForAdapterPosition(1).itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, recyclerView.getFocusedChild());
-        int pos = 1;
-        View focusedView = viewToFocus;
-        while (pos < 31) {
-            focusSearch(focusedView, scrollDown ? View.FOCUS_DOWN : View.FOCUS_UP);
-            waitForIdleScroll(recyclerView);
-            focusedView = recyclerView.getFocusedChild();
-            assertEquals(Math.min(pos + 3, mAdapter.getItemCount() - 1),
-                    recyclerView.getChildViewHolder(focusedView).getAdapterPosition());
-            pos += 3;
-        }
-    }
-
-    /**
-     * Tests that the GridLayoutManager retains the focused element after multiple measure
-     * calls to the RecyclerView.  There was a bug where the focused view was lost when the soft
-     * keyboard opened.  This test simulates the measure/layout events triggered by the opening
-     * of the soft keyboard by making two calls to measure.  A simulation was done because using
-     * the soft keyboard in the test caused many issues on API levels 15, 17 and 19.
-     */
-    @Test
-    public void focusedChildStaysInViewWhenRecyclerViewShrinks() throws Throwable {
-
-        // Arrange.
-
-        final int spanCount = 3;
-        final int itemCount = 100;
-
-        final RecyclerView recyclerView = inflateWrappedRV();
-        ViewGroup.LayoutParams lp = recyclerView.getLayoutParams();
-        lp.height = WRAP_CONTENT;
-        lp.width = MATCH_PARENT;
-
-        Config config = new Config(spanCount, itemCount);
-        mGlm = new WrappedGridLayoutManager(getActivity(), config.mSpanCount, config.mOrientation,
-                config.mReverseLayout);
-        recyclerView.setLayoutManager(mGlm);
-
-        GridFocusableAdapter gridFocusableAdapter = new GridFocusableAdapter(itemCount);
-        gridFocusableAdapter.assignSpanSizeLookup(mGlm);
-        recyclerView.setAdapter(gridFocusableAdapter);
-
-        mGlm.expectLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().addView(recyclerView);
-            }
-        });
-        mGlm.waitForLayout(3);
-
-        int width = recyclerView.getWidth();
-        int height = recyclerView.getHeight();
-        final int widthMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
-        final int fullHeightMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
-        // "MinusOne" so that a measure call will appropriately trigger onMeasure after RecyclerView
-        // was previously laid out with the full height version.
-        final int fullHeightMinusOneMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(height - 1, View.MeasureSpec.AT_MOST);
-        final int halfHeightMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(height / 2, View.MeasureSpec.AT_MOST);
-
-        // Act 1.
-
-        // First focus on the last fully visible child located at span index #1.
-        View toFocus = findLastFullyVisibleChild(recyclerView);
-        int focusIndex = recyclerView.getChildAdapterPosition(toFocus);
-        focusIndex = (focusIndex / spanCount) * spanCount + 1;
-        toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
-        assertTrue(focusIndex >= 1 && focusIndex < itemCount);
-
-        requestFocus(toFocus, false);
-
-        mGlm.expectLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
-                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
-                recyclerView.layout(
-                        0,
-                        0,
-                        recyclerView.getMeasuredWidth(),
-                        recyclerView.getMeasuredHeight());
-            }
-        });
-        mGlm.waitForLayout(3);
-
-        // Assert 1.
-
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.hasFocus(), is(true));
-        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
-                isViewPartiallyInBound(recyclerView, toFocus));
-
-        // Act 2.
-
-        mGlm.expectLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.measure(widthMeasureSpec, fullHeightMeasureSpec);
-                recyclerView.layout(
-                        0,
-                        0,
-                        recyclerView.getMeasuredWidth(),
-                        recyclerView.getMeasuredHeight());
-            }
-        });
-        mGlm.waitForLayout(3);
-
-        // Assert 2.
-
-        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
-                isViewPartiallyInBound(recyclerView, toFocus));
-
-        // Act 3.
-
-        // Now focus on the first fully visible EditText located at the last span index.
-        toFocus = findFirstFullyVisibleChild(recyclerView);
-        focusIndex = recyclerView.getChildAdapterPosition(toFocus);
-        focusIndex = (focusIndex / spanCount) * spanCount + (spanCount - 1);
-        toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex).itemView;
-
-        requestFocus(toFocus, false);
-
-        mGlm.expectLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
-                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
-                recyclerView.layout(
-                        0,
-                        0,
-                        recyclerView.getMeasuredWidth(),
-                        recyclerView.getMeasuredHeight());
-            }
-        });
-        mGlm.waitForLayout(3);
-
-        // Assert 3.
-
-        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
-                isViewPartiallyInBound(recyclerView, toFocus));
-    }
-
-    @Test
-    public void topUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of rows that can be fully in-bounds of RV.
-        final int visibleRowCount = 5;
-        final int spanCount = 3;
-        final int consecutiveFocusableRowsCount = 4;
-        final int consecutiveUnFocusableRowsCount = 8;
-        final int itemCount = (consecutiveFocusableRowsCount + consecutiveUnFocusableRowsCount)
-                * spanCount;
-
-        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
-                        .reverseLayout(true),
-                new GridTestAdapter(itemCount, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation using this for kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        if (position < spanCount * consecutiveFocusableRowsCount) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
-                    }
-                });
-        waitForFirstLayout(recyclerView);
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, recyclerView.getFocusedChild());
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = focusIndex;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        int maxFocusIndex = (consecutiveFocusableRowsCount - 1) * spanCount + focusIndex;
-        int maxVisibleIndex = (consecutiveFocusableRowsCount + visibleRowCount - 2)
-                * spanCount + visibleIndex;
-
-        // Navigate up through the focusable and unfocusable rows. The focusable rows should
-        // become focused one by one until hitting the last focusable row, at which point,
-        // unfocusable rows should become visible on the screen until the currently focused row
-        // stays on the screen.
-        int pos = focusIndex + spanCount;
-        while (pos < itemCount) {
-            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_UP, true);
-            waitForIdleScroll(recyclerView);
-            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
-            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
-            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(recyclerView, toVisible.itemView));
-            pos += spanCount;
-        }
-    }
-
-    @Test
-    public void bottomUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of rows that can be fully in-bounds of RV.
-        final int visibleRowCount = 5;
-        final int spanCount = 3;
-        final int consecutiveFocusableRowsCount = 4;
-        final int consecutiveUnFocusableRowsCount = 8;
-        final int itemCount = (consecutiveFocusableRowsCount + consecutiveUnFocusableRowsCount)
-                * spanCount;
-
-        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
-                        .reverseLayout(false),
-                new GridTestAdapter(itemCount, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation using this for kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        if (position < spanCount * consecutiveFocusableRowsCount) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
-                    }
-                });
-        waitForFirstLayout(recyclerView);
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, recyclerView.getFocusedChild());
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = focusIndex;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        int maxFocusIndex = (consecutiveFocusableRowsCount - 1) * spanCount + focusIndex;
-        int maxVisibleIndex = (consecutiveFocusableRowsCount + visibleRowCount - 2)
-                * spanCount + visibleIndex;
-
-        // Navigate down through the focusable and unfocusable rows. The focusable rows should
-        // become focused one by one until hitting the last focusable row, at which point,
-        // unfocusable rows should become visible on the screen until the currently focused row
-        // stays on the screen.
-        int pos = focusIndex + spanCount;
-        while (pos < itemCount) {
-            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
-            waitForIdleScroll(recyclerView);
-            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
-            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
-            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(recyclerView, toVisible.itemView));
-            pos += spanCount;
-        }
-    }
-
-    @Test
-    public void leftUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of columns that can be fully in-bounds of RV.
-        final int visibleColCount = 5;
-        final int spanCount = 3;
-        final int consecutiveFocusableColsCount = 4;
-        final int consecutiveUnFocusableColsCount = 8;
-        final int itemCount = (consecutiveFocusableColsCount + consecutiveUnFocusableColsCount)
-                * spanCount;
-
-        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
-                        .orientation(HORIZONTAL).reverseLayout(true),
-                new GridTestAdapter(itemCount, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation using this for kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        if (position < spanCount * consecutiveFocusableColsCount) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
-                    }
-                });
-        waitForFirstLayout(recyclerView);
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, recyclerView.getFocusedChild());
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = focusIndex;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        int maxFocusIndex = (consecutiveFocusableColsCount - 1) * spanCount + focusIndex;
-        int maxVisibleIndex = (consecutiveFocusableColsCount + visibleColCount - 2)
-                * spanCount + visibleIndex;
-
-        // Navigate left through the focusable and unfocusable columns. The focusable columns should
-        // become focused one by one until hitting the last focusable column, at which point,
-        // unfocusable columns should become visible on the screen until the currently focused
-        // column stays on the screen.
-        int pos = focusIndex + spanCount;
-        while (pos < itemCount) {
-            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_LEFT, true);
-            waitForIdleScroll(recyclerView);
-            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
-            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
-            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(recyclerView, toVisible.itemView));
-            pos += spanCount;
-        }
-    }
-
-    @Test
-    public void rightUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of columns that can be fully in-bounds of RV.
-        final int visibleColCount = 5;
-        final int spanCount = 3;
-        final int consecutiveFocusableColsCount = 4;
-        final int consecutiveUnFocusableColsCount = 8;
-        final int itemCount = (consecutiveFocusableColsCount + consecutiveUnFocusableColsCount)
-                * spanCount;
-
-        final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
-                        .orientation(HORIZONTAL).reverseLayout(false),
-                new GridTestAdapter(itemCount, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation using this for kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        if (position < spanCount * consecutiveFocusableColsCount) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
-                    }
-                });
-        waitForFirstLayout(recyclerView);
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, recyclerView.getFocusedChild());
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = focusIndex;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        int maxFocusIndex = (consecutiveFocusableColsCount - 1) * spanCount + focusIndex;
-        int maxVisibleIndex = (consecutiveFocusableColsCount + visibleColCount - 2)
-                * spanCount + visibleIndex;
-
-        // Navigate right through the focusable and unfocusable columns. The focusable columns
-        // should become focused one by one until hitting the last focusable column, at which point,
-        // unfocusable columns should become visible on the screen until the currently focused
-        // column stays on the screen.
-        int pos = focusIndex + spanCount;
-        while (pos < itemCount) {
-            focusSearch(recyclerView.getFocusedChild(), View.FOCUS_RIGHT, true);
-            waitForIdleScroll(recyclerView);
-            focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
-            toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
-            toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(recyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(recyclerView, toVisible.itemView));
-            pos += spanCount;
-        }
-    }
-
-    @UiThreadTest
-    @Test
-    public void scrollWithoutLayout() throws Throwable {
-        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
-        mGlm.expectLayout(1);
-        setRecyclerView(recyclerView);
-        mGlm.setSpanCount(5);
-        recyclerView.scrollBy(0, 10);
-    }
-
-    @Test
-    public void scrollWithoutLayoutAfterInvalidate() throws Throwable {
-        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
-        waitForFirstLayout(recyclerView);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGlm.setSpanCount(5);
-                recyclerView.scrollBy(0, 10);
-            }
-        });
-    }
-
-    @Test
-    public void predictiveSpanLookup1() throws Throwable {
-        predictiveSpanLookupTest(0, false);
-    }
-
-    @Test
-    public void predictiveSpanLookup2() throws Throwable {
-        predictiveSpanLookupTest(0, true);
-    }
-
-    @Test
-    public void predictiveSpanLookup3() throws Throwable {
-        predictiveSpanLookupTest(1, false);
-    }
-
-    @Test
-    public void predictiveSpanLookup4() throws Throwable {
-        predictiveSpanLookupTest(1, true);
-    }
-
-    public void predictiveSpanLookupTest(int remaining, boolean removeFromStart) throws Throwable {
-        RecyclerView recyclerView = setupBasic(new Config(3, 10));
-        mGlm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
-            @Override
-            public int getSpanSize(int position) {
-                if (position < 0 || position >= mAdapter.getItemCount()) {
-                    postExceptionToInstrumentation(new AssertionError("position is not within " +
-                            "adapter range. pos:" + position + ", adapter size:" +
-                            mAdapter.getItemCount()));
-                }
-                return 1;
-            }
-
-            @Override
-            public int getSpanIndex(int position, int spanCount) {
-                if (position < 0 || position >= mAdapter.getItemCount()) {
-                    postExceptionToInstrumentation(new AssertionError("position is not within " +
-                            "adapter range. pos:" + position + ", adapter size:" +
-                            mAdapter.getItemCount()));
-                }
-                return super.getSpanIndex(position, spanCount);
-            }
-        });
-        waitForFirstLayout(recyclerView);
-        checkForMainThreadException();
-        assertTrue("test sanity", mGlm.supportsPredictiveItemAnimations());
-        mGlm.expectLayout(2);
-        int deleteCnt = 10 - remaining;
-        int deleteStart = removeFromStart ? 0 : remaining;
-        mAdapter.deleteAndNotify(deleteStart, deleteCnt);
-        mGlm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void movingAGroupOffScreenForAddedItems() throws Throwable {
-        final RecyclerView rv = setupBasic(new Config(3, 100));
-        final int[] maxId = new int[1];
-        maxId[0] = -1;
-        final SparseIntArray spanLookups = new SparseIntArray();
-        final AtomicBoolean enableSpanLookupLogging = new AtomicBoolean(false);
-        mGlm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
-            @Override
-            public int getSpanSize(int position) {
-                if (maxId[0] > 0 && mAdapter.getItemAt(position).mId > maxId[0]) {
-                    return 1;
-                } else if (enableSpanLookupLogging.get() && !rv.mState.isPreLayout()) {
-                    spanLookups.put(position, spanLookups.get(position, 0) + 1);
-                }
-                return 3;
-            }
-        });
-        ((SimpleItemAnimator) rv.getItemAnimator()).setSupportsChangeAnimations(true);
-        waitForFirstLayout(rv);
-        View lastView = rv.getChildAt(rv.getChildCount() - 1);
-        final int lastPos = rv.getChildAdapterPosition(lastView);
-        maxId[0] = mAdapter.getItemAt(mAdapter.getItemCount() - 1).mId;
-        // now add a lot of items below this and those new views should have span size 3
-        enableSpanLookupLogging.set(true);
-        mGlm.expectLayout(2);
-        mAdapter.addAndNotify(lastPos - 2, 30);
-        mGlm.waitForLayout(2);
-        checkForMainThreadException();
-
-        assertEquals("last items span count should be queried twice", 2,
-                spanLookups.get(lastPos + 30));
-
-    }
-
-    @Test
-    public void layoutParams() throws Throwable {
-        layoutParamsTest(GridLayoutManager.HORIZONTAL);
-        removeRecyclerView();
-        layoutParamsTest(GridLayoutManager.VERTICAL);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
-    public void horizontalAccessibilitySpanIndices() throws Throwable {
-        accessibilitySpanIndicesTest(HORIZONTAL);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
-    public void verticalAccessibilitySpanIndices() throws Throwable {
-        accessibilitySpanIndicesTest(VERTICAL);
-    }
-
-    public void accessibilitySpanIndicesTest(int orientation) throws Throwable {
-        final RecyclerView recyclerView = setupBasic(new Config(3, orientation, false));
-        waitForFirstLayout(recyclerView);
-        final AccessibilityDelegateCompat delegateCompat = mRecyclerView
-                .getCompatAccessibilityDelegate().getItemDelegate();
-        final AccessibilityNodeInfoCompat info = AccessibilityNodeInfoCompat.obtain();
-        final View chosen = recyclerView.getChildAt(recyclerView.getChildCount() - 2);
-        final int position = recyclerView.getChildLayoutPosition(chosen);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityNodeInfo(chosen, info);
-            }
-        });
-        GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup;
-        AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo = info
-                .getCollectionItemInfo();
-        assertNotNull(itemInfo);
-        assertEquals("result should have span group position",
-                ssl.getSpanGroupIndex(position, mGlm.getSpanCount()),
-                orientation == HORIZONTAL ? itemInfo.getColumnIndex() : itemInfo.getRowIndex());
-        assertEquals("result should have span index",
-                ssl.getSpanIndex(position, mGlm.getSpanCount()),
-                orientation == HORIZONTAL ? itemInfo.getRowIndex() : itemInfo.getColumnIndex());
-        assertEquals("result should have span size",
-                ssl.getSpanSize(position),
-                orientation == HORIZONTAL ? itemInfo.getRowSpan() : itemInfo.getColumnSpan());
-    }
-
-    public GridLayoutManager.LayoutParams ensureGridLp(View view) {
-        ViewGroup.LayoutParams lp = view.getLayoutParams();
-        GridLayoutManager.LayoutParams glp;
-        if (lp instanceof GridLayoutManager.LayoutParams) {
-            glp = (GridLayoutManager.LayoutParams) lp;
-        } else if (lp == null) {
-            glp = (GridLayoutManager.LayoutParams) mGlm
-                    .generateDefaultLayoutParams();
-            view.setLayoutParams(glp);
-        } else {
-            glp = (GridLayoutManager.LayoutParams) mGlm.generateLayoutParams(lp);
-            view.setLayoutParams(glp);
-        }
-        return glp;
-    }
-
-    public void layoutParamsTest(final int orientation) throws Throwable {
-        final RecyclerView rv = setupBasic(new Config(3, 100).orientation(orientation),
-                new GridTestAdapter(100) {
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView);
-                        int val = 0;
-                        switch (position % 5) {
-                            case 0:
-                                val = 10;
-                                break;
-                            case 1:
-                                val = 30;
-                                break;
-                            case 2:
-                                val = GridLayoutManager.LayoutParams.WRAP_CONTENT;
-                                break;
-                            case 3:
-                                val = GridLayoutManager.LayoutParams.MATCH_PARENT;
-                                break;
-                            case 4:
-                                val = 200;
-                                break;
-                        }
-                        if (orientation == GridLayoutManager.VERTICAL) {
-                            glp.height = val;
-                        } else {
-                            glp.width = val;
-                        }
-                        holder.itemView.setLayoutParams(glp);
-                    }
-                });
-        waitForFirstLayout(rv);
-        final OrientationHelper helper = mGlm.mOrientationHelper;
-        final int firstRowSize = Math.max(30, getSize(mGlm.findViewByPosition(2)));
-        assertEquals(firstRowSize,
-                helper.getDecoratedMeasurement(mGlm.findViewByPosition(0)));
-        assertEquals(firstRowSize,
-                helper.getDecoratedMeasurement(mGlm.findViewByPosition(1)));
-        assertEquals(firstRowSize,
-                helper.getDecoratedMeasurement(mGlm.findViewByPosition(2)));
-        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(0)));
-        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(1)));
-        assertEquals(firstRowSize, getSize(mGlm.findViewByPosition(2)));
-
-        final int secondRowSize = Math.max(200, getSize(mGlm.findViewByPosition(3)));
-        assertEquals(secondRowSize,
-                helper.getDecoratedMeasurement(mGlm.findViewByPosition(3)));
-        assertEquals(secondRowSize,
-                helper.getDecoratedMeasurement(mGlm.findViewByPosition(4)));
-        assertEquals(secondRowSize,
-                helper.getDecoratedMeasurement(mGlm.findViewByPosition(5)));
-        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(3)));
-        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(4)));
-        assertEquals(secondRowSize, getSize(mGlm.findViewByPosition(5)));
-    }
-
-    @Test
-    public void anchorUpdate() throws InterruptedException {
-        GridLayoutManager glm = new GridLayoutManager(getActivity(), 11);
-        final GridLayoutManager.SpanSizeLookup spanSizeLookup
-                = new GridLayoutManager.SpanSizeLookup() {
-            @Override
-            public int getSpanSize(int position) {
-                if (position > 200) {
-                    return 100;
-                }
-                if (position > 20) {
-                    return 2;
-                }
-                return 1;
-            }
-        };
-        glm.setSpanSizeLookup(spanSizeLookup);
-        glm.mAnchorInfo.mPosition = 11;
-        RecyclerView.State state = new RecyclerView.State();
-        mRecyclerView = new RecyclerView(getActivity());
-        state.mItemCount = 1000;
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
-        assertEquals("gm should keep anchor in first span", 11, glm.mAnchorInfo.mPosition);
-
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
-        assertEquals("gm should keep anchor in last span in the row", 20,
-                glm.mAnchorInfo.mPosition);
-
-        glm.mAnchorInfo.mPosition = 5;
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
-        assertEquals("gm should keep anchor in last span in the row", 10,
-                glm.mAnchorInfo.mPosition);
-
-        glm.mAnchorInfo.mPosition = 13;
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
-        assertEquals("gm should move anchor to first span", 11, glm.mAnchorInfo.mPosition);
-
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
-        assertEquals("gm should keep anchor in last span in the row", 20,
-                glm.mAnchorInfo.mPosition);
-
-        glm.mAnchorInfo.mPosition = 23;
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
-        assertEquals("gm should move anchor to first span", 21, glm.mAnchorInfo.mPosition);
-
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
-        assertEquals("gm should keep anchor in last span in the row", 25,
-                glm.mAnchorInfo.mPosition);
-
-        glm.mAnchorInfo.mPosition = 35;
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_TAIL);
-        assertEquals("gm should move anchor to first span", 31, glm.mAnchorInfo.mPosition);
-        glm.onAnchorReady(mRecyclerView.mRecycler, state, glm.mAnchorInfo,
-                LinearLayoutManager.LayoutState.ITEM_DIRECTION_HEAD);
-        assertEquals("gm should keep anchor in last span in the row", 35,
-                glm.mAnchorInfo.mPosition);
-    }
-
-    @Test
-    public void spanLookup() {
-        spanLookupTest(false);
-    }
-
-    @Test
-    public void spanLookupWithCache() {
-        spanLookupTest(true);
-    }
-
-    @Test
-    public void spanLookupCache() {
-        final GridLayoutManager.SpanSizeLookup ssl
-                = new GridLayoutManager.SpanSizeLookup() {
-            @Override
-            public int getSpanSize(int position) {
-                if (position > 6) {
-                    return 2;
-                }
-                return 1;
-            }
-        };
-        ssl.setSpanIndexCacheEnabled(true);
-        assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(2));
-        ssl.getCachedSpanIndex(4, 5);
-        assertEquals("reference child non existent", -1, ssl.findReferenceIndexFromCache(3));
-        // this should not happen and if happens, it is better to return -1
-        assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4));
-        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(5));
-        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(100));
-        ssl.getCachedSpanIndex(6, 5);
-        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7));
-        assertEquals("reference child before", 4, ssl.findReferenceIndexFromCache(6));
-        assertEquals("reference child itself", -1, ssl.findReferenceIndexFromCache(4));
-        ssl.getCachedSpanIndex(12, 5);
-        assertEquals("reference child before", 12, ssl.findReferenceIndexFromCache(13));
-        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(12));
-        assertEquals("reference child before", 6, ssl.findReferenceIndexFromCache(7));
-        for (int i = 0; i < 6; i++) {
-            ssl.getCachedSpanIndex(i, 5);
-        }
-
-        for (int i = 1; i < 7; i++) {
-            assertEquals("reference child right before " + i, i - 1,
-                    ssl.findReferenceIndexFromCache(i));
-        }
-        assertEquals("reference child before 0 ", -1, ssl.findReferenceIndexFromCache(0));
-    }
-
-    public void spanLookupTest(boolean enableCache) {
-        final GridLayoutManager.SpanSizeLookup ssl
-                = new GridLayoutManager.SpanSizeLookup() {
-            @Override
-            public int getSpanSize(int position) {
-                if (position > 200) {
-                    return 100;
-                }
-                if (position > 6) {
-                    return 2;
-                }
-                return 1;
-            }
-        };
-        ssl.setSpanIndexCacheEnabled(enableCache);
-        assertEquals(0, ssl.getCachedSpanIndex(0, 5));
-        assertEquals(4, ssl.getCachedSpanIndex(4, 5));
-        assertEquals(0, ssl.getCachedSpanIndex(5, 5));
-        assertEquals(1, ssl.getCachedSpanIndex(6, 5));
-        assertEquals(2, ssl.getCachedSpanIndex(7, 5));
-        assertEquals(2, ssl.getCachedSpanIndex(9, 5));
-        assertEquals(0, ssl.getCachedSpanIndex(8, 5));
-    }
-
-    @Test
-    public void removeAnchorItem() throws Throwable {
-        removeAnchorItemTest(
-                new Config(3, 0).orientation(VERTICAL).reverseLayout(false), 100, 0);
-    }
-
-    @Test
-    public void removeAnchorItemReverse() throws Throwable {
-        removeAnchorItemTest(
-                new Config(3, 0).orientation(VERTICAL).reverseLayout(true), 100,
-                0);
-    }
-
-    @Test
-    public void removeAnchorItemHorizontal() throws Throwable {
-        removeAnchorItemTest(
-                new Config(3, 0).orientation(HORIZONTAL).reverseLayout(
-                        false), 100, 0);
-    }
-
-    @Test
-    public void removeAnchorItemReverseHorizontal() throws Throwable {
-        removeAnchorItemTest(
-                new Config(3, 0).orientation(HORIZONTAL).reverseLayout(true),
-                100, 0);
-    }
-
-    /**
-     * This tests a regression where predictive animations were not working as expected when the
-     * first item is removed and there aren't any more items to add from that direction.
-     * First item refers to the default anchor item.
-     */
-    public void removeAnchorItemTest(final Config config, int adapterSize,
-            final int removePos) throws Throwable {
-        GridTestAdapter adapter = new GridTestAdapter(adapterSize) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-                if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
-                    lp = new ViewGroup.MarginLayoutParams(0, 0);
-                    holder.itemView.setLayoutParams(lp);
-                }
-                ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
-                final int maxSize;
-                if (config.mOrientation == HORIZONTAL) {
-                    maxSize = mRecyclerView.getWidth();
-                    mlp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
-                } else {
-                    maxSize = mRecyclerView.getHeight();
-                    mlp.width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
-                }
-
-                final int desiredSize;
-                if (position == removePos) {
-                    // make it large
-                    desiredSize = maxSize / 4;
-                } else {
-                    // make it small
-                    desiredSize = maxSize / 8;
-                }
-                if (config.mOrientation == HORIZONTAL) {
-                    mlp.width = desiredSize;
-                } else {
-                    mlp.height = desiredSize;
-                }
-            }
-        };
-        RecyclerView recyclerView = setupBasic(config, adapter);
-        waitForFirstLayout(recyclerView);
-        final int childCount = mGlm.getChildCount();
-        RecyclerView.ViewHolder toBeRemoved = null;
-        List<RecyclerView.ViewHolder> toBeMoved = new ArrayList<RecyclerView.ViewHolder>();
-        for (int i = 0; i < childCount; i++) {
-            View child = mGlm.getChildAt(i);
-            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
-            if (holder.getAdapterPosition() == removePos) {
-                toBeRemoved = holder;
-            } else {
-                toBeMoved.add(holder);
-            }
-        }
-        assertNotNull("test sanity", toBeRemoved);
-        assertEquals("test sanity", childCount - 1, toBeMoved.size());
-        LoggingItemAnimator loggingItemAnimator = new LoggingItemAnimator();
-        mRecyclerView.setItemAnimator(loggingItemAnimator);
-        loggingItemAnimator.reset();
-        loggingItemAnimator.expectRunPendingAnimationsCall(1);
-        mGlm.expectLayout(2);
-        adapter.deleteAndNotify(removePos, 1);
-        mGlm.waitForLayout(1);
-        loggingItemAnimator.waitForPendingAnimationsCall(2);
-        assertTrue("removed child should receive remove animation",
-                loggingItemAnimator.mRemoveVHs.contains(toBeRemoved));
-        for (RecyclerView.ViewHolder vh : toBeMoved) {
-            assertTrue("view holder should be in moved list",
-                    loggingItemAnimator.mMoveVHs.contains(vh));
-        }
-        List<RecyclerView.ViewHolder> newHolders = new ArrayList<RecyclerView.ViewHolder>();
-        for (int i = 0; i < mGlm.getChildCount(); i++) {
-            View child = mGlm.getChildAt(i);
-            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
-            if (toBeRemoved != holder && !toBeMoved.contains(holder)) {
-                newHolders.add(holder);
-            }
-        }
-        assertTrue("some new children should show up for the new space", newHolders.size() > 0);
-        assertEquals("no items should receive animate add since they are not new", 0,
-                loggingItemAnimator.mAddVHs.size());
-        for (RecyclerView.ViewHolder holder : newHolders) {
-            assertTrue("new holder should receive a move animation",
-                    loggingItemAnimator.mMoveVHs.contains(holder));
-        }
-        // for removed view, 3 for new row
-        assertTrue("control against adding too many children due to bad layout state preparation."
-                        + " initial:" + childCount + ", current:" + mRecyclerView.getChildCount(),
-                mRecyclerView.getChildCount() <= childCount + 1 + 3);
-    }
-
-    @Test
-    public void spanGroupIndex() {
-        final GridLayoutManager.SpanSizeLookup ssl
-                = new GridLayoutManager.SpanSizeLookup() {
-            @Override
-            public int getSpanSize(int position) {
-                if (position > 200) {
-                    return 100;
-                }
-                if (position > 6) {
-                    return 2;
-                }
-                return 1;
-            }
-        };
-        assertEquals(0, ssl.getSpanGroupIndex(0, 5));
-        assertEquals(0, ssl.getSpanGroupIndex(4, 5));
-        assertEquals(1, ssl.getSpanGroupIndex(5, 5));
-        assertEquals(1, ssl.getSpanGroupIndex(6, 5));
-        assertEquals(1, ssl.getSpanGroupIndex(7, 5));
-        assertEquals(2, ssl.getSpanGroupIndex(9, 5));
-        assertEquals(2, ssl.getSpanGroupIndex(8, 5));
-    }
-
-    @Test
-    public void notifyDataSetChange() throws Throwable {
-        final RecyclerView recyclerView = setupBasic(new Config(3, 100));
-        final GridLayoutManager.SpanSizeLookup ssl = mGlm.getSpanSizeLookup();
-        ssl.setSpanIndexCacheEnabled(true);
-        waitForFirstLayout(recyclerView);
-        assertTrue("some positions should be cached", ssl.mSpanIndexCache.size() > 0);
-        final Callback callback = new Callback() {
-            @Override
-            public void onBeforeLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                if (!state.isPreLayout()) {
-                    assertEquals("cache should be empty", 0, ssl.mSpanIndexCache.size());
-                }
-            }
-
-            @Override
-            public void onAfterLayout(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                if (!state.isPreLayout()) {
-                    assertTrue("some items should be cached", ssl.mSpanIndexCache.size() > 0);
-                }
-            }
-        };
-        mGlm.mCallbacks.add(callback);
-        mGlm.expectLayout(2);
-        mAdapter.deleteAndNotify(2, 3);
-        mGlm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void unevenHeights() throws Throwable {
-        final Map<Integer, RecyclerView.ViewHolder> viewHolderMap =
-                new HashMap<Integer, RecyclerView.ViewHolder>();
-        RecyclerView recyclerView = setupBasic(new Config(3, 3), new GridTestAdapter(3) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView);
-                glp.height = 50 + position * 50;
-                viewHolderMap.put(position, holder);
-            }
-        });
-        waitForFirstLayout(recyclerView);
-        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
-            assertEquals("all items should get max height", 150,
-                    vh.itemView.getHeight());
-        }
-
-        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
-            assertEquals("all items should have measured the max height", 150,
-                    vh.itemView.getMeasuredHeight());
-        }
-    }
-
-    @Test
-    public void unevenWidths() throws Throwable {
-        final Map<Integer, RecyclerView.ViewHolder> viewHolderMap =
-                new HashMap<Integer, RecyclerView.ViewHolder>();
-        RecyclerView recyclerView = setupBasic(new Config(3, HORIZONTAL, false),
-                new GridTestAdapter(3) {
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        final GridLayoutManager.LayoutParams glp = ensureGridLp(holder.itemView);
-                        glp.width = 50 + position * 50;
-                        viewHolderMap.put(position, holder);
-                    }
-                });
-        waitForFirstLayout(recyclerView);
-        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
-            assertEquals("all items should get max width", 150,
-                    vh.itemView.getWidth());
-        }
-
-        for (RecyclerView.ViewHolder vh : viewHolderMap.values()) {
-            assertEquals("all items should have measured the max width", 150,
-                    vh.itemView.getMeasuredWidth());
-        }
-    }
-
-    @Test
-    public void spanSizeChange() throws Throwable {
-        final RecyclerView rv = setupBasic(new Config(3, 100));
-        waitForFirstLayout(rv);
-        assertTrue(mGlm.supportsPredictiveItemAnimations());
-        mGlm.expectLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mGlm.setSpanCount(5);
-                assertFalse(mGlm.supportsPredictiveItemAnimations());
-            }
-        });
-        mGlm.waitForLayout(2);
-        mGlm.expectLayout(2);
-        mAdapter.deleteAndNotify(3, 2);
-        mGlm.waitForLayout(2);
-        assertTrue(mGlm.supportsPredictiveItemAnimations());
-    }
-
-    @Test
-    public void cacheSpanIndices() throws Throwable {
-        final RecyclerView rv = setupBasic(new Config(3, 100));
-        mGlm.mSpanSizeLookup.setSpanIndexCacheEnabled(true);
-        waitForFirstLayout(rv);
-        GridLayoutManager.SpanSizeLookup ssl = mGlm.mSpanSizeLookup;
-        assertTrue("cache should be filled", mGlm.mSpanSizeLookup.mSpanIndexCache.size() > 0);
-        assertEquals("item index 5 should be in span 2", 2,
-                getLp(mGlm.findViewByPosition(5)).getSpanIndex());
-        mGlm.expectLayout(2);
-        mAdapter.mFullSpanItems.add(4);
-        mAdapter.changeAndNotify(4, 1);
-        mGlm.waitForLayout(2);
-        assertEquals("item index 5 should be in span 2", 0,
-                getLp(mGlm.findViewByPosition(5)).getSpanIndex());
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java
deleted file mode 100644
index 4c7161b..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/ItemAnimatorV2ApiTest.java
+++ /dev/null
@@ -1,712 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v7.widget;
-
-import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_CHANGED;
-import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_MOVED;
-import static android.support.v7.widget.RecyclerView.ItemAnimator.FLAG_REMOVED;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-
-import org.hamcrest.CoreMatchers;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Includes tests for the new RecyclerView animations API (v2).
- */
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class ItemAnimatorV2ApiTest extends BaseRecyclerViewAnimationsTest {
-    @Override
-    protected RecyclerView.ItemAnimator createItemAnimator() {
-        return mAnimator;
-    }
-
-    @Test
-    public void changeMovedOutside() throws Throwable {
-        setupBasic(10);
-        final RecyclerView.ViewHolder target = mRecyclerView.findViewHolderForAdapterPosition(9);
-        mLayoutManager.expectLayouts(2);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
-        mTestAdapter.changeAndNotify(9, 1);
-        mLayoutManager.waitForLayout(2);
-        // changed item should not be laid out and should just receive disappear
-        LoggingInfo pre = mAnimator.preLayoutInfoMap.get(target);
-        assertNotNull("test sanity", pre);
-        assertNull("test sanity", mAnimator.postLayoutInfoMap.get(target));
-        assertTrue(mAnimator.animateChangeList.isEmpty());
-        assertEquals(1, mAnimator.animateDisappearanceList.size());
-        assertEquals(new AnimateDisappearance(target, pre, null),
-                mAnimator.animateDisappearanceList.get(0));
-        // This is kind of problematic because layout manager will never layout the updated
-        // version of this view since it went out of bounds and it won't show up in scrap.
-        // I don't think we can do much better since other option is to bind a fresh view
-    }
-
-    @Test
-    public void changeMovedOutsideWithPredictiveAndTwoViewHolders() throws Throwable {
-        final RecyclerView.ViewHolder[] targets = new RecyclerView.ViewHolder[2];
-
-        setupBasic(10, 0, 10, new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (position == 0) {
-                    if (targets[0] == null) {
-                        targets[0] = holder;
-                    } else {
-                        assertThat(targets[1], CoreMatchers.nullValue());
-                        targets[1] = holder;
-                    }
-                }
-            }
-        });
-        final RecyclerView.ViewHolder singleItemTarget =
-                mRecyclerView.findViewHolderForAdapterPosition(1);
-        mAnimator.canReUseCallback = new CanReUseCallback() {
-            @Override
-            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
-                return viewHolder == singleItemTarget;
-            }
-        };
-        mLayoutManager.expectLayouts(2);
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void onLayoutChildren(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager lm, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, lm, state);
-                if (!state.isPreLayout()) {
-                    mLayoutManager.addDisappearingView(recycler.getViewForPosition(0));
-                    mLayoutManager.addDisappearingView(recycler.getScrapList().get(0).itemView);
-                }
-            }
-        };
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 2;
-        mTestAdapter.changeAndNotify(0, 2);
-        mLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        final RecyclerView.ViewHolder oldTarget = targets[0];
-        final RecyclerView.ViewHolder newTarget = targets[1];
-        assertNotNull("test sanity", targets[0]);
-        assertNotNull("test sanity", targets[1]);
-        // changed item should not be laid out and should just receive disappear
-        LoggingInfo pre = mAnimator.preLayoutInfoMap.get(oldTarget);
-        assertNotNull("test sanity", pre);
-        assertNull("test sanity", mAnimator.postLayoutInfoMap.get(oldTarget));
-
-        assertNull("test sanity", mAnimator.preLayoutInfoMap.get(newTarget));
-        LoggingInfo post = mAnimator.postLayoutInfoMap.get(newTarget);
-        assertNotNull("test sanity", post);
-        assertEquals(1, mAnimator.animateChangeList.size());
-        assertEquals(1, mAnimator.animateDisappearanceList.size());
-
-        assertEquals(new AnimateChange(oldTarget, newTarget, pre, post),
-                mAnimator.animateChangeList.get(0));
-
-        LoggingInfo singleItemPre = mAnimator.preLayoutInfoMap.get(singleItemTarget);
-        assertNotNull("test sanity", singleItemPre);
-        LoggingInfo singleItemPost = mAnimator.postLayoutInfoMap.get(singleItemTarget);
-        assertNotNull("test sanity", singleItemPost);
-
-        assertEquals(new AnimateDisappearance(singleItemTarget, singleItemPre, singleItemPost),
-                mAnimator.animateDisappearanceList.get(0));
-    }
-    @Test
-    public void changeMovedOutsideWithPredictive() throws Throwable {
-        setupBasic(10);
-        final RecyclerView.ViewHolder target = mRecyclerView.findViewHolderForAdapterPosition(0);
-        mLayoutManager.expectLayouts(2);
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void onLayoutChildren(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager lm, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, lm, state);
-                List<RecyclerView.ViewHolder> scrapList = recycler.getScrapList();
-                assertThat(scrapList.size(), CoreMatchers.is(2));
-                mLayoutManager.addDisappearingView(scrapList.get(0).itemView);
-                mLayoutManager.addDisappearingView(scrapList.get(0).itemView);
-            }
-        };
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 2;
-        mTestAdapter.changeAndNotify(0, 2);
-        mLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        // changed item should not be laid out and should just receive disappear
-        LoggingInfo pre = mAnimator.preLayoutInfoMap.get(target);
-        assertNotNull("test sanity", pre);
-        LoggingInfo postInfo = mAnimator.postLayoutInfoMap.get(target);
-        assertNotNull("test sanity", postInfo);
-        assertTrue(mAnimator.animateChangeList.isEmpty());
-        assertEquals(2, mAnimator.animateDisappearanceList.size());
-        try {
-            assertEquals(new AnimateDisappearance(target, pre, postInfo),
-                    mAnimator.animateDisappearanceList.get(0));
-        } catch (Throwable t) {
-            assertEquals(new AnimateDisappearance(target, pre, postInfo),
-                    mAnimator.animateDisappearanceList.get(1));
-        }
-
-    }
-
-    @Test
-    public void simpleAdd() throws Throwable {
-        setupBasic(10);
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.addAndNotify(2, 1);
-        mLayoutManager.waitForLayout(2);
-        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
-        assertEquals(1, mAnimator.animateAppearanceList.size());
-        AnimateAppearance log = mAnimator.animateAppearanceList.get(0);
-        assertSame(vh, log.viewHolder);
-        assertNull(log.preInfo);
-        assertEquals(0, log.postInfo.changeFlags);
-        // the first two should not receive anything
-        for (int i = 0; i < 2; i++) {
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void simpleRemove() throws Throwable {
-        setupBasic(10);
-        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(2, 1);
-        mLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        assertEquals(1, mAnimator.animateDisappearanceList.size());
-        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
-        assertSame(vh, log.viewHolder);
-        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
-        assertEquals(FLAG_REMOVED, log.preInfo.changeFlags);
-        // the first two should not receive anything
-        for (int i = 0; i < 2; i++) {
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        for (int i = 3; i < mTestAdapter.getItemCount(); i++) {
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(FLAG_MOVED, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void simpleUpdate() throws Throwable {
-        setupBasic(10);
-        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.changeAndNotify(2, 1);
-        mLayoutManager.waitForLayout(2);
-        assertEquals(1, mAnimator.animateChangeList.size());
-        AnimateChange log = mAnimator.animateChangeList.get(0);
-        assertSame(vh, log.viewHolder);
-        assertSame(vh, log.newHolder);
-        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
-        assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
-        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
-        assertEquals(0, log.postInfo.changeFlags);
-        //others should not receive anything
-        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
-            if (i == 2) {
-                continue;
-            }
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void updateWithDuplicateViewHolder() throws Throwable {
-        setupBasic(10);
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
-        mAnimator.canReUseCallback = new CanReUseCallback() {
-            @Override
-            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
-                assertSame(viewHolder, vh);
-                return false;
-            }
-        };
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.changeAndNotify(2, 1);
-        mLayoutManager.waitForLayout(2);
-        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
-        assertNotSame(vh, newVh);
-        assertEquals(1, mAnimator.animateChangeList.size());
-        AnimateChange log = mAnimator.animateChangeList.get(0);
-        assertSame(vh, log.viewHolder);
-        assertSame(newVh, log.newHolder);
-        assertNull(vh.itemView.getParent());
-        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
-        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
-        assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
-        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
-        assertEquals(0, log.postInfo.changeFlags);
-        //others should not receive anything
-        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
-            if (i == 2) {
-                continue;
-            }
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void updateWithOneDuplicateAndOneInPlace() throws Throwable {
-        setupBasic(10);
-        final RecyclerView.ViewHolder replaced = mRecyclerView.findViewHolderForAdapterPosition(2);
-        final RecyclerView.ViewHolder reused = mRecyclerView.findViewHolderForAdapterPosition(3);
-        mAnimator.canReUseCallback = new CanReUseCallback() {
-            @Override
-            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
-                if (viewHolder == replaced) {
-                    return false;
-                } else if (viewHolder == reused) {
-                    return true;
-                }
-                fail("unpexpected view");
-                return false;
-            }
-        };
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.changeAndNotify(2, 2);
-        mLayoutManager.waitForLayout(2);
-        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
-
-        assertNotSame(replaced, newVh);
-        assertSame(reused, mRecyclerView.findViewHolderForAdapterPosition(3));
-
-        assertEquals(2, mAnimator.animateChangeList.size());
-        AnimateChange logReplaced = null, logReused = null;
-        for (AnimateChange change : mAnimator.animateChangeList) {
-            if (change.newHolder == change.viewHolder) {
-                logReused = change;
-            } else {
-                logReplaced = change;
-            }
-        }
-        assertNotNull(logReplaced);
-        assertNotNull(logReused);
-        assertSame(replaced, logReplaced.viewHolder);
-        assertSame(newVh, logReplaced.newHolder);
-        assertSame(reused, logReused.viewHolder);
-        assertSame(reused, logReused.newHolder);
-
-        assertTrue(mAnimator.preLayoutInfoMap.containsKey(replaced));
-        assertTrue(mAnimator.preLayoutInfoMap.containsKey(reused));
-
-        assertTrue(mAnimator.postLayoutInfoMap.containsKey(newVh));
-        assertTrue(mAnimator.postLayoutInfoMap.containsKey(reused));
-        assertFalse(mAnimator.postLayoutInfoMap.containsKey(replaced));
-
-        assertEquals(FLAG_CHANGED, logReplaced.preInfo.changeFlags);
-        assertEquals(FLAG_CHANGED, logReused.preInfo.changeFlags);
-
-        assertEquals(0, logReplaced.postInfo.changeFlags);
-        assertEquals(0, logReused.postInfo.changeFlags);
-        //others should not receive anything
-        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
-            if (i == 2 || i == 3) {
-                continue;
-            }
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void changeToDisappear() throws Throwable {
-        setupBasic(10);
-        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(9);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.changeAndNotify(9, 1);
-        mLayoutManager.waitForLayout(2);
-        assertEquals(1, mAnimator.animateDisappearanceList.size());
-        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
-        assertSame(vh, log.viewHolder);
-        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
-        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
-        assertEquals(0, mAnimator.animateChangeList.size());
-        assertEquals(0, mAnimator.animateAppearanceList.size());
-        assertEquals(9, mAnimator.animatePersistenceList.size());
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void changeToDisappearFromHead() throws Throwable {
-        setupBasic(10);
-        RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(0);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.changeAndNotify(0, 1);
-        mLayoutManager.waitForLayout(2);
-        assertEquals(1, mAnimator.animateDisappearanceList.size());
-        AnimateDisappearance log = mAnimator.animateDisappearanceList.get(0);
-        assertSame(vh, log.viewHolder);
-        assertFalse(mAnimator.postLayoutInfoMap.containsKey(vh));
-        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
-        assertEquals(0, mAnimator.animateChangeList.size());
-        assertEquals(0, mAnimator.animateAppearanceList.size());
-        assertEquals(9, mAnimator.animatePersistenceList.size());
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void updatePayload() throws Throwable {
-        setupBasic(10);
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
-        final Object payload = new Object();
-        mAnimator.canReUseCallback = new CanReUseCallback() {
-            @Override
-            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
-                assertSame(vh, viewHolder);
-                assertEquals(1, payloads.size());
-                assertSame(payload, payloads.get(0));
-                return true;
-            }
-        };
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.changeAndNotifyWithPayload(2, 1, payload);
-        mLayoutManager.waitForLayout(2);
-        assertEquals(1, mAnimator.animateChangeList.size());
-        AnimateChange log = mAnimator.animateChangeList.get(0);
-        assertSame(vh, log.viewHolder);
-        assertSame(vh, log.newHolder);
-        assertTrue(mAnimator.preLayoutInfoMap.containsKey(vh));
-        assertTrue(mAnimator.postLayoutInfoMap.containsKey(vh));
-        assertEquals(FLAG_CHANGED, log.preInfo.changeFlags);
-        assertEquals(0, log.postInfo.changeFlags);
-        assertNotNull(log.preInfo.payloads);
-        assertTrue(log.preInfo.payloads.contains(payload));
-        //others should not receive anything
-        for (int i = 0; i < mTestAdapter.getItemCount(); i++) {
-            if (i == 2) {
-                continue;
-            }
-            RecyclerView.ViewHolder other = mRecyclerView.findViewHolderForAdapterPosition(i);
-            assertEquals(0, mAnimator.preLayoutInfoMap.get(other).changeFlags);
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void notifyDataSetChanged() throws Throwable {
-        TestAdapter adapter = new TestAdapter(10);
-        adapter.setHasStableIds(true);
-        setupBasic(10, 0, 10, adapter);
-        mLayoutManager.expectLayouts(1);
-        mTestAdapter.dispatchDataSetChanged();
-        mLayoutManager.waitForLayout(2);
-        assertEquals(10, mAnimator.animateChangeList.size());
-        for (AnimateChange change : mAnimator.animateChangeList) {
-            assertNotNull(change.preInfo);
-            assertNotNull(change.postInfo);
-            assertSame(change.preInfo.viewHolder, change.postInfo.viewHolder);
-        }
-        assertEquals(0, mAnimator.animatePersistenceList.size());
-        assertEquals(0, mAnimator.animateAppearanceList.size());
-        assertEquals(0, mAnimator.animateDisappearanceList.size());
-    }
-
-    @Test
-    public void notifyDataSetChangedWithoutStableIds() throws Throwable {
-        TestAdapter adapter = new TestAdapter(10);
-        adapter.setHasStableIds(false);
-        setupBasic(10, 0, 10, adapter);
-        mLayoutManager.expectLayouts(1);
-        mTestAdapter.dispatchDataSetChanged();
-        mLayoutManager.waitForLayout(2);
-        assertEquals(0, mAnimator.animateChangeList.size());
-        assertEquals(0, mAnimator.animatePersistenceList.size());
-        assertEquals(0, mAnimator.animateAppearanceList.size());
-        assertEquals(0, mAnimator.animateDisappearanceList.size());
-    }
-
-    @Test
-    public void notifyDataSetChangedWithAppearing() throws Throwable {
-        notifyDataSetChangedWithAppearing(false);
-    }
-
-    @Test
-    public void notifyDataSetChangedWithAppearingNotifyBoth() throws Throwable {
-        notifyDataSetChangedWithAppearing(true);
-    }
-
-    private void notifyDataSetChangedWithAppearing(final boolean notifyBoth) throws Throwable {
-        final TestAdapter adapter = new TestAdapter(10);
-        adapter.setHasStableIds(true);
-        setupBasic(10, 0, 10, adapter);
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    if (notifyBoth) {
-                        adapter.addAndNotify(2, 2);
-                    } else {
-                        adapter.mItems.add(2, new Item(2, "custom 1"));
-                        adapter.mItems.add(3, new Item(3, "custom 2"));
-                    }
-
-                    adapter.notifyDataSetChanged();
-                } catch (Throwable throwable) {
-                    throwable.printStackTrace();
-                }
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        assertEquals(10, mAnimator.animateChangeList.size());
-        assertEquals(0, mAnimator.animatePersistenceList.size());
-        assertEquals(2, mAnimator.animateAppearanceList.size());
-        assertEquals(0, mAnimator.animateDisappearanceList.size());
-    }
-
-    @Test
-    public void notifyDataSetChangedWithDispappearing() throws Throwable {
-        notifyDataSetChangedWithDispappearing(false);
-    }
-
-    @Test
-    public void notifyDataSetChangedWithDispappearingNotifyBoth() throws Throwable {
-        notifyDataSetChangedWithDispappearing(true);
-    }
-
-    private void notifyDataSetChangedWithDispappearing(final boolean notifyBoth) throws Throwable {
-        final TestAdapter adapter = new TestAdapter(10);
-        adapter.setHasStableIds(true);
-        setupBasic(10, 0, 10, adapter);
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    if (notifyBoth) {
-                        adapter.deleteAndNotify(2, 2);
-                    } else {
-                        adapter.mItems.remove(2);
-                        adapter.mItems.remove(2);
-                    }
-                    adapter.notifyDataSetChanged();
-                } catch (Throwable throwable) {
-                    throwable.printStackTrace();
-                }
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        assertEquals(8, mAnimator.animateChangeList.size());
-        assertEquals(0, mAnimator.animatePersistenceList.size());
-        assertEquals(0, mAnimator.animateAppearanceList.size());
-        assertEquals(2, mAnimator.animateDisappearanceList.size());
-    }
-
-    @Test
-    public void notifyUpdateWithChangedAdapterType() throws Throwable {
-        final AtomicInteger itemType = new AtomicInteger(1);
-        final TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public int getItemViewType(int position) {
-                return position == 2 ? itemType.get() : 20;
-            }
-        };
-        adapter.setHasStableIds(true);
-        setupBasic(10, 0, 10, adapter);
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(2);
-
-        mAnimator.canReUseCallback = new CanReUseCallback() {
-            @Override
-            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
-                return viewHolder != vh;
-            }
-        };
-
-        mLayoutManager.expectLayouts(1);
-        itemType.set(3);
-        adapter.dispatchDataSetChanged();
-        mLayoutManager.waitForLayout(2);
-        final RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(2);
-        // TODO we should be able to map old type to the new one but doing that change has some
-        // recycling side effects.
-        assertEquals(9, mAnimator.animateChangeList.size());
-        assertEquals(0, mAnimator.animatePersistenceList.size());
-        assertEquals(1, mAnimator.animateAppearanceList.size());
-        assertEquals(0, mAnimator.animateDisappearanceList.size());
-        assertNotSame(vh, newVh);
-        for (AnimateChange change : mAnimator.animateChangeList) {
-            if (change.viewHolder == vh) {
-                assertSame(change.newHolder, newVh);
-                assertSame(change.viewHolder, vh);
-            } else {
-                assertSame(change.newHolder, change.viewHolder);
-            }
-        }
-    }
-
-    LoggingV2Animator mAnimator = new LoggingV2Animator();
-
-    class LoggingV2Animator extends RecyclerView.ItemAnimator {
-
-        CanReUseCallback canReUseCallback = new CanReUseCallback() {
-            @Override
-            public boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads) {
-                return true;
-            }
-        };
-        Map<RecyclerView.ViewHolder, LoggingInfo> preLayoutInfoMap = new HashMap<>();
-        Map<RecyclerView.ViewHolder, LoggingInfo> postLayoutInfoMap = new HashMap<>();
-
-        List<AnimateAppearance> animateAppearanceList = new ArrayList<>();
-        List<AnimateDisappearance> animateDisappearanceList = new ArrayList<>();
-        List<AnimatePersistence> animatePersistenceList = new ArrayList<>();
-        List<AnimateChange> animateChangeList = new ArrayList<>();
-
-        @Override
-        public boolean canReuseUpdatedViewHolder(RecyclerView.ViewHolder viewHolder,
-                List<Object> payloads) {
-            return canReUseCallback.canReUse(viewHolder, payloads);
-        }
-
-        @NonNull
-        @Override
-        public ItemHolderInfo recordPreLayoutInformation(@NonNull RecyclerView.State state,
-                @NonNull RecyclerView.ViewHolder viewHolder,
-                @AdapterChanges int changeFlags, @NonNull List<Object> payloads) {
-            LoggingInfo loggingInfo = new LoggingInfo(viewHolder, changeFlags, payloads);
-            preLayoutInfoMap.put(viewHolder, loggingInfo);
-            return loggingInfo;
-        }
-
-        @NonNull
-        @Override
-        public ItemHolderInfo recordPostLayoutInformation(@NonNull RecyclerView.State state,
-                @NonNull RecyclerView.ViewHolder viewHolder) {
-            LoggingInfo loggingInfo = new LoggingInfo(viewHolder, 0, null);
-            postLayoutInfoMap.put(viewHolder, loggingInfo);
-            return loggingInfo;
-        }
-
-        @Override
-        public boolean animateDisappearance(@NonNull RecyclerView.ViewHolder viewHolder,
-                @NonNull ItemHolderInfo preLayoutInfo,
-                @Nullable ItemHolderInfo postLayoutInfo) {
-            animateDisappearanceList.add(new AnimateDisappearance(viewHolder,
-                    (LoggingInfo) preLayoutInfo, (LoggingInfo) postLayoutInfo));
-            assertSame(preLayoutInfoMap.get(viewHolder), preLayoutInfo);
-            assertSame(postLayoutInfoMap.get(viewHolder), postLayoutInfo);
-            dispatchAnimationFinished(viewHolder);
-
-            return false;
-        }
-
-        @Override
-        public boolean animateAppearance(@NonNull RecyclerView.ViewHolder viewHolder,
-                ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
-            animateAppearanceList.add(
-                    new AnimateAppearance(viewHolder, (LoggingInfo) preInfo, (LoggingInfo) postInfo));
-            assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
-            assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
-            dispatchAnimationFinished(viewHolder);
-            return false;
-        }
-
-        @Override
-        public boolean animatePersistence(@NonNull RecyclerView.ViewHolder viewHolder,
-                @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
-            animatePersistenceList.add(new AnimatePersistence(viewHolder, (LoggingInfo) preInfo,
-                    (LoggingInfo) postInfo));
-            dispatchAnimationFinished(viewHolder);
-            assertSame(preLayoutInfoMap.get(viewHolder), preInfo);
-            assertSame(postLayoutInfoMap.get(viewHolder), postInfo);
-            return false;
-        }
-
-        @Override
-        public boolean animateChange(@NonNull RecyclerView.ViewHolder oldHolder,
-                @NonNull RecyclerView.ViewHolder newHolder, @NonNull ItemHolderInfo preInfo,
-                @NonNull ItemHolderInfo postInfo) {
-            animateChangeList.add(new AnimateChange(oldHolder, newHolder, (LoggingInfo) preInfo,
-                    (LoggingInfo) postInfo));
-            if (oldHolder != null) {
-                dispatchAnimationFinished(oldHolder);
-                assertSame(preLayoutInfoMap.get(oldHolder), preInfo);
-            }
-            if (newHolder != null && oldHolder != newHolder) {
-                dispatchAnimationFinished(newHolder);
-                assertSame(postLayoutInfoMap.get(newHolder), postInfo);
-            }
-
-            return false;
-        }
-
-        @Override
-        public void runPendingAnimations() {
-
-        }
-
-        @Override
-        public void endAnimation(RecyclerView.ViewHolder item) {
-        }
-
-        @Override
-        public void endAnimations() {
-
-        }
-
-        @Override
-        public boolean isRunning() {
-            return false;
-        }
-    }
-
-    interface CanReUseCallback {
-
-        boolean canReUse(RecyclerView.ViewHolder viewHolder, List<Object> payloads);
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
deleted file mode 100644
index 731cc67..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerBaseConfigSetTest.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LayoutState.LAYOUT_END;
-import static android.support.v7.widget.LayoutState.LAYOUT_START;
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-
-import static org.hamcrest.CoreMatchers.hasItem;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-
-import android.graphics.Rect;
-import android.support.test.filters.LargeTest;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewParent;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Tests that rely on the basic configuration and does not do any additions / removals
- */
-@RunWith(Parameterized.class)
-@LargeTest
-public class LinearLayoutManagerBaseConfigSetTest extends BaseLinearLayoutManagerTest {
-
-    private final Config mConfig;
-
-    public LinearLayoutManagerBaseConfigSetTest(Config config) {
-        mConfig = config;
-    }
-
-
-    @Parameterized.Parameters(name = "{0}")
-    public static List<Config> configs() throws CloneNotSupportedException {
-        List<Config> result = new ArrayList<>();
-        for (Config config : createBaseVariations()) {
-            result.add(config);
-        }
-        return result;
-    }
-
-    @Test
-    public void scrollToPositionWithOffsetTest() throws Throwable {
-        Config config = ((Config) mConfig.clone()).itemCount(300);
-        setupByConfig(config, true);
-        OrientationHelper orientationHelper = OrientationHelper
-                .createOrientationHelper(mLayoutManager, config.mOrientation);
-        Rect layoutBounds = getDecoratedRecyclerViewBounds();
-        // try scrolling towards head, should not affect anything
-        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
-        if (config.mStackFromEnd) {
-            scrollToPositionWithOffset(mTestAdapter.getItemCount() - 1,
-                    mLayoutManager.mOrientationHelper.getEnd() - 500);
-        } else {
-            scrollToPositionWithOffset(0, 20);
-        }
-        assertRectSetsEqual(config + " trying to over scroll with offset should be no-op",
-                before, mLayoutManager.collectChildCoordinates());
-        // try offsetting some visible children
-        int testCount = 10;
-        while (testCount-- > 0) {
-            // get middle child
-            final View child = mLayoutManager.getChildAt(mLayoutManager.getChildCount() / 2);
-            final int position = mRecyclerView.getChildLayoutPosition(child);
-            final int startOffset = config.mReverseLayout ?
-                    orientationHelper.getEndAfterPadding() - orientationHelper
-                            .getDecoratedEnd(child)
-                    : orientationHelper.getDecoratedStart(child) - orientationHelper
-                            .getStartAfterPadding();
-            final int scrollOffset = config.mStackFromEnd ? startOffset + startOffset / 2
-                    : startOffset / 2;
-            mLayoutManager.expectLayouts(1);
-            scrollToPositionWithOffset(position, scrollOffset);
-            mLayoutManager.waitForLayout(2);
-            final int finalOffset = config.mReverseLayout ?
-                    orientationHelper.getEndAfterPadding() - orientationHelper
-                            .getDecoratedEnd(child)
-                    : orientationHelper.getDecoratedStart(child) - orientationHelper
-                            .getStartAfterPadding();
-            assertEquals(config + " scroll with offset on a visible child should work fine " +
-                            " offset:" + finalOffset + " , existing offset:" + startOffset + ", "
-                            + "child " + position,
-                    scrollOffset, finalOffset);
-        }
-
-        // try scrolling to invisible children
-        testCount = 10;
-        // we test above and below, one by one
-        int offsetMultiplier = -1;
-        while (testCount-- > 0) {
-            final TargetTuple target = findInvisibleTarget(config);
-            final String logPrefix = config + " " + target;
-            mLayoutManager.expectLayouts(1);
-            final int offset = offsetMultiplier
-                    * orientationHelper.getDecoratedMeasurement(mLayoutManager.getChildAt(0)) / 3;
-            scrollToPositionWithOffset(target.mPosition, offset);
-            mLayoutManager.waitForLayout(2);
-            final View child = mLayoutManager.findViewByPosition(target.mPosition);
-            assertNotNull(logPrefix + " scrolling to a mPosition with offset " + offset
-                    + " should layout it", child);
-            final Rect bounds = mLayoutManager.getViewBounds(child);
-            if (DEBUG) {
-                Log.d(TAG, logPrefix + " post scroll to invisible mPosition " + bounds + " in "
-                        + layoutBounds + " with offset " + offset);
-            }
-
-            if (config.mReverseLayout) {
-                assertEquals(logPrefix + " when scrolling with offset to an invisible in reverse "
-                                + "layout, its end should align with recycler view's end - offset",
-                        orientationHelper.getEndAfterPadding() - offset,
-                        orientationHelper.getDecoratedEnd(child)
-                );
-            } else {
-                assertEquals(
-                        logPrefix + " when scrolling with offset to an invisible child in normal"
-                                + " layout its start should align with recycler view's start + "
-                                + "offset",
-                        orientationHelper.getStartAfterPadding() + offset,
-                        orientationHelper.getDecoratedStart(child)
-                );
-            }
-            offsetMultiplier *= -1;
-        }
-    }
-
-    @Test
-    public void getFirstLastChildrenTest() throws Throwable {
-        final Config config = ((Config) mConfig.clone()).itemCount(300);
-        setupByConfig(config, true);
-        Runnable viewInBoundsTest = new Runnable() {
-            @Override
-            public void run() {
-                VisibleChildren visibleChildren = mLayoutManager.traverseAndFindVisibleChildren();
-                final String boundsLog = mLayoutManager.getBoundsLog();
-                assertEquals(config + ":\nfirst visible child should match traversal result\n"
-                                + boundsLog, visibleChildren.firstVisiblePosition,
-                        mLayoutManager.findFirstVisibleItemPosition()
-                );
-                assertEquals(
-                        config + ":\nfirst fully visible child should match traversal result\n"
-                                + boundsLog, visibleChildren.firstFullyVisiblePosition,
-                        mLayoutManager.findFirstCompletelyVisibleItemPosition()
-                );
-
-                assertEquals(config + ":\nlast visible child should match traversal result\n"
-                                + boundsLog, visibleChildren.lastVisiblePosition,
-                        mLayoutManager.findLastVisibleItemPosition()
-                );
-                assertEquals(
-                        config + ":\nlast fully visible child should match traversal result\n"
-                                + boundsLog, visibleChildren.lastFullyVisiblePosition,
-                        mLayoutManager.findLastCompletelyVisibleItemPosition()
-                );
-            }
-        };
-        mActivityRule.runOnUiThread(viewInBoundsTest);
-        // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching
-        // case
-        final int scrollPosition = config.mStackFromEnd ? 0 : mTestAdapter.getItemCount();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.smoothScrollToPosition(scrollPosition);
-            }
-        });
-        while (mLayoutManager.isSmoothScrolling() ||
-                mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
-            mActivityRule.runOnUiThread(viewInBoundsTest);
-            Thread.sleep(400);
-        }
-        // delete all items
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(0, mTestAdapter.getItemCount());
-        mLayoutManager.waitForLayout(2);
-        // test empty case
-        mActivityRule.runOnUiThread(viewInBoundsTest);
-        // set a new adapter with huge items to test full bounds check
-        mLayoutManager.expectLayouts(1);
-        final int totalSpace = mLayoutManager.mOrientationHelper.getTotalSpace();
-        final TestAdapter newAdapter = new TestAdapter(100) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (config.mOrientation == HORIZONTAL) {
-                    holder.itemView.setMinimumWidth(totalSpace + 5);
-                } else {
-                    holder.itemView.setMinimumHeight(totalSpace + 5);
-                }
-            }
-        };
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setAdapter(newAdapter);
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        mActivityRule.runOnUiThread(viewInBoundsTest);
-    }
-
-    @Test
-    public void dontRecycleViewsTranslatedOutOfBoundsFromStart() throws Throwable {
-        final Config config = ((Config) mConfig.clone()).itemCount(1000);
-        setupByConfig(config, true);
-        mLayoutManager.expectLayouts(1);
-        scrollToPosition(500);
-        mLayoutManager.waitForLayout(2);
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(500);
-        OrientationHelper helper = mLayoutManager.mOrientationHelper;
-        int gap = helper.getDecoratedStart(vh.itemView);
-        scrollBy(gap);
-        gap = helper.getDecoratedStart(vh.itemView);
-        assertThat("test sanity", gap, is(0));
-
-        final int size = helper.getDecoratedMeasurement(vh.itemView);
-        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (mConfig.mOrientation == HORIZONTAL) {
-                    vh.itemView.setTranslationX(size * 2);
-                } else {
-                    vh.itemView.setTranslationY(size * 2);
-                }
-            }
-        });
-        scrollBy(size * 2);
-        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
-        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
-        assertThat(vh.getAdapterPosition(), is(500));
-        scrollBy(size * 2);
-        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
-    }
-
-    @Test
-    public void dontRecycleViewsTranslatedOutOfBoundsFromEnd() throws Throwable {
-        final Config config = ((Config) mConfig.clone()).itemCount(1000);
-        setupByConfig(config, true);
-        mLayoutManager.expectLayouts(1);
-        scrollToPosition(500);
-        mLayoutManager.waitForLayout(2);
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(500);
-        OrientationHelper helper = mLayoutManager.mOrientationHelper;
-        int gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
-        scrollBy(-gap);
-        gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
-        assertThat("test sanity", gap, is(0));
-
-        final int size = helper.getDecoratedMeasurement(vh.itemView);
-        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (mConfig.mOrientation == HORIZONTAL) {
-                    vh.itemView.setTranslationX(-size * 2);
-                } else {
-                    vh.itemView.setTranslationY(-size * 2);
-                }
-            }
-        });
-        scrollBy(-size * 2);
-        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
-        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
-        assertThat(vh.getAdapterPosition(), is(500));
-        scrollBy(-size * 2);
-        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
-    }
-
-    private TargetTuple findInvisibleTarget(Config config) {
-        int minPosition = Integer.MAX_VALUE, maxPosition = Integer.MIN_VALUE;
-        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
-            View child = mLayoutManager.getChildAt(i);
-            int position = mRecyclerView.getChildLayoutPosition(child);
-            if (position < minPosition) {
-                minPosition = position;
-            }
-            if (position > maxPosition) {
-                maxPosition = position;
-            }
-        }
-        final int tailTarget = maxPosition +
-                (mRecyclerView.getAdapter().getItemCount() - maxPosition) / 2;
-        final int headTarget = minPosition / 2;
-        final int target;
-        // where will the child come from ?
-        final int itemLayoutDirection;
-        if (Math.abs(tailTarget - maxPosition) > Math.abs(headTarget - minPosition)) {
-            target = tailTarget;
-            itemLayoutDirection = config.mReverseLayout ? LAYOUT_START : LAYOUT_END;
-        } else {
-            target = headTarget;
-            itemLayoutDirection = config.mReverseLayout ? LAYOUT_END : LAYOUT_START;
-        }
-        if (DEBUG) {
-            Log.d(TAG,
-                    config + " target:" + target + " min:" + minPosition + ", max:" + maxPosition);
-        }
-        return new TargetTuple(target, itemLayoutDirection);
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
deleted file mode 100644
index 2cdb2e7..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerPrepareForDropTest.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-
-import android.support.test.filters.MediumTest;
-import android.view.View;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(Parameterized.class)
-public class LinearLayoutManagerPrepareForDropTest extends BaseLinearLayoutManagerTest {
-
-    final BaseLinearLayoutManagerTest.Config mConfig;
-    final SelectTargetChildren mSelectTargetChildren;
-
-    public LinearLayoutManagerPrepareForDropTest(
-            Config config, SelectTargetChildren selectTargetChildren) {
-        mConfig = config;
-        mSelectTargetChildren = selectTargetChildren;
-    }
-
-    @Parameterized.Parameters(name = "{0},selectTargetChildren:{1}")
-    public static Iterable<Object[]> params() {
-        SelectTargetChildren[] selectors
-                = new SelectTargetChildren[]{
-                new SelectTargetChildren() {
-                    @Override
-                    public int[] selectTargetChildren(int childCount) {
-                        return new int[]{1, 0};
-                    }
-                    @Override
-                    public String toString() {
-                        return "{1,0}";
-                    }
-                },
-                new SelectTargetChildren() {
-                    @Override
-                    public int[] selectTargetChildren(int childCount) {
-                        return new int[]{0, 1};
-                    }
-                    @Override
-                    public String toString() {
-                        return "{0,1}";
-                    }
-                },
-                new SelectTargetChildren() {
-                    @Override
-                    public int[] selectTargetChildren(int childCount) {
-                        return new int[]{childCount - 1, childCount - 2};
-                    }
-                    @Override
-                    public String toString() {
-                        return "{childCount-1,childCount-2}";
-                    }
-                },
-                new SelectTargetChildren() {
-                    @Override
-                    public int[] selectTargetChildren(int childCount) {
-                        return new int[]{childCount - 2, childCount - 1};
-                    }
-                    @Override
-                    public String toString() {
-                        return "{childCount-2,childCount-1}";
-                    }
-                },
-                new SelectTargetChildren() {
-                    @Override
-                    public int[] selectTargetChildren(int childCount) {
-                        return new int[]{childCount / 2, childCount / 2 + 1};
-                    }
-                    @Override
-                    public String toString() {
-                        return "{childCount/2,childCount/2+1}";
-                    }
-                },
-                new SelectTargetChildren() {
-                    @Override
-                    public int[] selectTargetChildren(int childCount) {
-                        return new int[]{childCount / 2 + 1, childCount / 2};
-                    }
-                    @Override
-                    public String toString() {
-                        return "{childCount/2+1,childCount/2}";
-                    }
-                }
-        };
-        List<Object[]> variations = new ArrayList<>();
-        for (SelectTargetChildren selector : selectors) {
-            for (BaseLinearLayoutManagerTest.Config config : createBaseVariations()) {
-                variations.add(new Object[]{config, selector});
-            }
-        }
-        return variations;
-    }
-
-    @Test
-    @MediumTest
-    public void prepareForDropTest()
-            throws Throwable {
-        final Config config = (Config) mConfig.clone();
-        config.mTestAdapter = new BaseRecyclerViewInstrumentationTest.TestAdapter(100) {
-            @Override
-            public void onBindViewHolder(BaseRecyclerViewInstrumentationTest.TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (config.mOrientation == HORIZONTAL) {
-                    final int base = mLayoutManager.getWidth() / 5;
-                    final int itemRand = holder.mBoundItem.mText.hashCode() % base;
-                    holder.itemView.setMinimumWidth(base + itemRand);
-                } else {
-                    final int base = mLayoutManager.getHeight() / 5;
-                    final int itemRand = holder.mBoundItem.mText.hashCode() % base;
-                    holder.itemView.setMinimumHeight(base + itemRand);
-                }
-            }
-        };
-        setupByConfig(config, true);
-        mLayoutManager.expectLayouts(1);
-        scrollToPosition(mTestAdapter.getItemCount() / 2);
-        mLayoutManager.waitForLayout(1);
-        int[] positions = mSelectTargetChildren.selectTargetChildren(mRecyclerView.getChildCount());
-        final View fromChild = mLayoutManager.getChildAt(positions[0]);
-        final int fromPos = mLayoutManager.getPosition(fromChild);
-        final View onChild = mLayoutManager.getChildAt(positions[1]);
-        final int toPos = mLayoutManager.getPosition(onChild);
-        final OrientationHelper helper = mLayoutManager.mOrientationHelper;
-        final int dragCoordinate;
-        final boolean towardsHead = toPos < fromPos;
-        final int referenceLine;
-        if (config.mReverseLayout == towardsHead) {
-            referenceLine = helper.getDecoratedEnd(onChild);
-            dragCoordinate = referenceLine + 3 -
-                    helper.getDecoratedMeasurement(fromChild);
-        } else {
-            referenceLine = helper.getDecoratedStart(onChild);
-            dragCoordinate = referenceLine - 3;
-        }
-        mLayoutManager.expectLayouts(2);
-
-        final int x, y;
-        if (config.mOrientation == HORIZONTAL) {
-            x = dragCoordinate;
-            y = fromChild.getTop();
-        } else {
-            y = dragCoordinate;
-            x = fromChild.getLeft();
-        }
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTestAdapter.moveInUIThread(fromPos, toPos);
-                mTestAdapter.notifyItemMoved(fromPos, toPos);
-                mLayoutManager.prepareForDrop(fromChild, onChild, x, y);
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-
-        assertSame(fromChild, mRecyclerView.findViewHolderForAdapterPosition(toPos).itemView);
-        // make sure it has the position we wanted
-        if (config.mReverseLayout == towardsHead) {
-            assertEquals(referenceLine, helper.getDecoratedEnd(fromChild));
-        } else {
-            assertEquals(referenceLine, helper.getDecoratedStart(fromChild));
-        }
-    }
-
-    protected interface SelectTargetChildren {
-        int[] selectTargetChildren(int childCount);
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
deleted file mode 100644
index dd2c650..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
+++ /dev/null
@@ -1,1258 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.os.Build;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.util.Log;
-import android.util.StateSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-
-/**
- * Includes tests for {@link LinearLayoutManager}.
- * <p>
- * Since most UI tests are not practical, these tests are focused on internal data representation
- * and stability of LinearLayoutManager in response to different events (state change, scrolling
- * etc) where it is very hard to do manual testing.
- */
-@LargeTest
-public class LinearLayoutManagerTest extends BaseLinearLayoutManagerTest {
-
-    /**
-     * Tests that the LinearLayoutManager retains the focused element after multiple measure
-     * calls to the RecyclerView.  There was a bug where the focused view was lost when the soft
-     * keyboard opened.  This test simulates the measure/layout events triggered by the opening
-     * of the soft keyboard by making two calls to measure.  A simulation was done because using
-     * the soft keyboard in the test caused many issues on API levels 15, 17 and 19.
-     */
-    @Test
-    public void focusedChildStaysInViewWhenRecyclerViewShrinks() throws Throwable {
-
-        // Arrange.
-
-        final RecyclerView recyclerView = inflateWrappedRV();
-        ViewGroup.LayoutParams lp = recyclerView.getLayoutParams();
-        lp.height = WRAP_CONTENT;
-        lp.width = MATCH_PARENT;
-        recyclerView.setHasFixedSize(true);
-
-        final FocusableAdapter focusableAdapter =
-                new FocusableAdapter(50);
-        recyclerView.setAdapter(focusableAdapter);
-
-        mLayoutManager = new WrappedLinearLayoutManager(getActivity(), VERTICAL, false);
-        recyclerView.setLayoutManager(mLayoutManager);
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().addView(recyclerView);
-            }
-        });
-        mLayoutManager.waitForLayout(3);
-
-        int width = recyclerView.getWidth();
-        int height = recyclerView.getHeight();
-        final int widthMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
-        final int fullHeightMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST);
-        // "MinusOne" so that a measure call will appropriately trigger onMeasure after RecyclerView
-        // was previously laid out with the full height version.
-        final int fullHeightMinusOneMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(height - 1, View.MeasureSpec.AT_MOST);
-        final int halfHeightMeasureSpec =
-                View.MeasureSpec.makeMeasureSpec(height / 2, View.MeasureSpec.AT_MOST);
-
-        // Act 1.
-
-        View toFocus = findLastFullyVisibleChild(recyclerView);
-        int focusIndex = recyclerView.getChildAdapterPosition(toFocus);
-
-        requestFocus(toFocus, false);
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
-                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
-                recyclerView.layout(
-                        0,
-                        0,
-                        recyclerView.getMeasuredWidth(),
-                        recyclerView.getMeasuredHeight());
-            }
-        });
-        mLayoutManager.waitForLayout(3);
-
-        // Verify 1.
-
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.hasFocus(), is(true));
-        // Testing for partial visibility instead of full visibility since TextView calls
-        // requestRectangleOnScreen (inside bringPointIntoView) for the focused view with a rect
-        // containing the content area. This rect is guaranteed to be fully visible whereas a
-        // portion of TextView could be out of bounds.
-        assertThat("Child view at adapter pos " + focusIndex + " should be fully visible.",
-                isViewPartiallyInBound(recyclerView, toFocus), is(true));
-
-        // Act 2.
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.measure(widthMeasureSpec, fullHeightMeasureSpec);
-                recyclerView.layout(
-                        0,
-                        0,
-                        recyclerView.getMeasuredWidth(),
-                        recyclerView.getMeasuredHeight());
-            }
-        });
-        mLayoutManager.waitForLayout(3);
-
-        // Verify 2.
-
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.hasFocus(), is(true));
-        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
-                isViewPartiallyInBound(recyclerView, toFocus));
-
-        // Act 3.
-
-        // Now focus on the first fully visible EditText.
-        toFocus = findFirstFullyVisibleChild(recyclerView);
-        focusIndex = recyclerView.getChildAdapterPosition(toFocus);
-
-        requestFocus(toFocus, false);
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.measure(widthMeasureSpec, fullHeightMinusOneMeasureSpec);
-                recyclerView.measure(widthMeasureSpec, halfHeightMeasureSpec);
-                recyclerView.layout(
-                        0,
-                        0,
-                        recyclerView.getMeasuredWidth(),
-                        recyclerView.getMeasuredHeight());
-            }
-        });
-        mLayoutManager.waitForLayout(3);
-
-        // Assert 3.
-
-        assertTrue("Child view at adapter pos " + focusIndex + " should be fully visible.",
-                isViewPartiallyInBound(recyclerView, toFocus));
-    }
-
-    @Test
-    public void topUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of child views that can be visible at any time.
-        final int visibleChildCount = 5;
-        final int consecutiveFocusablesCount = 2;
-        final int consecutiveUnFocusablesCount = 18;
-        final TestAdapter adapter = new TestAdapter(
-                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
-            RecyclerView mAttachedRv;
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                // Good to have colors for debugging
-                StateListDrawable stl = new StateListDrawable();
-                stl.addState(new int[]{android.R.attr.state_focused},
-                        new ColorDrawable(Color.RED));
-                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                //noinspection deprecation used to support kitkat tests
-                testViewHolder.itemView.setBackgroundDrawable(stl);
-                return testViewHolder;
-            }
-
-            @Override
-            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                mAttachedRv = recyclerView;
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (position < consecutiveFocusablesCount) {
-                    holder.itemView.setFocusable(true);
-                    holder.itemView.setFocusableInTouchMode(true);
-                } else {
-                    holder.itemView.setFocusable(false);
-                    holder.itemView.setFocusableInTouchMode(false);
-                }
-                // This height ensures that some portion of #visibleChildCount'th child is
-                // off-bounds, creating more interesting test scenario.
-                holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
-                        + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
-            }
-        };
-        setupByConfig(new Config(VERTICAL, false, false).adapter(adapter).reverseLayout(true),
-                false);
-        waitForFirstLayout();
-
-        // adapter position of the currently focused item.
-        int focusIndex = 0;
-        View newFocused = mRecyclerView.getChildAt(focusIndex);
-        requestFocus(newFocused, true);
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.itemView.hasFocus(), is(true));
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = 0;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        // Navigate up through the focusable and unfocusable chunks. The focusable items should
-        // become focused one by one until hitting the last focusable item, at which point,
-        // unfocusable items should become visible on the screen until the currently focused item
-        // stays on the screen.
-        for (int i = 0; i < adapter.getItemCount(); i++) {
-            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_UP, true);
-            // adapter position of the currently focused item.
-            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
-            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
-                    (visibleIndex + 1));
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    @Test
-    public void bottomUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of child views that can be visible at any time.
-        final int visibleChildCount = 5;
-        final int consecutiveFocusablesCount = 2;
-        final int consecutiveUnFocusablesCount = 18;
-        final TestAdapter adapter = new TestAdapter(
-                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
-            RecyclerView mAttachedRv;
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                // Good to have colors for debugging
-                StateListDrawable stl = new StateListDrawable();
-                stl.addState(new int[]{android.R.attr.state_focused},
-                        new ColorDrawable(Color.RED));
-                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                //noinspection deprecation used to support kitkat tests
-                testViewHolder.itemView.setBackgroundDrawable(stl);
-                return testViewHolder;
-            }
-
-            @Override
-            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                mAttachedRv = recyclerView;
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (position < consecutiveFocusablesCount) {
-                    holder.itemView.setFocusable(true);
-                    holder.itemView.setFocusableInTouchMode(true);
-                } else {
-                    holder.itemView.setFocusable(false);
-                    holder.itemView.setFocusableInTouchMode(false);
-                }
-                // This height ensures that some portion of #visibleChildCount'th child is
-                // off-bounds, creating more interesting test scenario.
-                holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
-                        + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
-            }
-        };
-        setupByConfig(new Config(VERTICAL, false, false).adapter(adapter), false);
-        waitForFirstLayout();
-
-        // adapter position of the currently focused item.
-        int focusIndex = 0;
-        View newFocused = mRecyclerView.getChildAt(focusIndex);
-        requestFocus(newFocused, true);
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.itemView.hasFocus(), is(true));
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = 0;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        // Navigate down through the focusable and unfocusable chunks. The focusable items should
-        // become focused one by one until hitting the last focusable item, at which point,
-        // unfocusable items should become visible on the screen until the currently focused item
-        // stays on the screen.
-        for (int i = 0; i < adapter.getItemCount(); i++) {
-            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
-            // adapter position of the currently focused item.
-            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
-            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
-                    (visibleIndex + 1));
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    @Test
-    public void leftUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of child views that can be visible at any time.
-        final int visibleChildCount = 5;
-        final int consecutiveFocusablesCount = 2;
-        final int consecutiveUnFocusablesCount = 18;
-        final TestAdapter adapter = new TestAdapter(
-                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
-            RecyclerView mAttachedRv;
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                // Good to have colors for debugging
-                StateListDrawable stl = new StateListDrawable();
-                stl.addState(new int[]{android.R.attr.state_focused},
-                        new ColorDrawable(Color.RED));
-                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                //noinspection deprecation used to support kitkat tests
-                testViewHolder.itemView.setBackgroundDrawable(stl);
-                return testViewHolder;
-            }
-
-            @Override
-            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                mAttachedRv = recyclerView;
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (position < consecutiveFocusablesCount) {
-                    holder.itemView.setFocusable(true);
-                    holder.itemView.setFocusableInTouchMode(true);
-                } else {
-                    holder.itemView.setFocusable(false);
-                    holder.itemView.setFocusableInTouchMode(false);
-                }
-                // This width ensures that some portion of #visibleChildCount'th child is
-                // off-bounds, creating more interesting test scenario.
-                holder.itemView.setMinimumWidth((mAttachedRv.getWidth()
-                        + mAttachedRv.getWidth() / (2 * visibleChildCount)) / visibleChildCount);
-            }
-        };
-        setupByConfig(new Config(HORIZONTAL, false, false).adapter(adapter).reverseLayout(true),
-                false);
-        waitForFirstLayout();
-
-        // adapter position of the currently focused item.
-        int focusIndex = 0;
-        View newFocused = mRecyclerView.getChildAt(focusIndex);
-        requestFocus(newFocused, true);
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.itemView.hasFocus(), is(true));
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = 0;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        // Navigate left through the focusable and unfocusable chunks. The focusable items should
-        // become focused one by one until hitting the last focusable item, at which point,
-        // unfocusable items should become visible on the screen until the currently focused item
-        // stays on the screen.
-        for (int i = 0; i < adapter.getItemCount(); i++) {
-            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_LEFT, true);
-            // adapter position of the currently focused item.
-            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
-            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
-                    (visibleIndex + 1));
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    @Test
-    public void rightUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of child views that can be visible at any time.
-        final int visibleChildCount = 5;
-        final int consecutiveFocusablesCount = 2;
-        final int consecutiveUnFocusablesCount = 18;
-        final TestAdapter adapter = new TestAdapter(
-                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
-            RecyclerView mAttachedRv;
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                // Good to have colors for debugging
-                StateListDrawable stl = new StateListDrawable();
-                stl.addState(new int[]{android.R.attr.state_focused},
-                        new ColorDrawable(Color.RED));
-                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                //noinspection deprecation used to support kitkat tests
-                testViewHolder.itemView.setBackgroundDrawable(stl);
-                return testViewHolder;
-            }
-
-            @Override
-            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                mAttachedRv = recyclerView;
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (position < consecutiveFocusablesCount) {
-                    holder.itemView.setFocusable(true);
-                    holder.itemView.setFocusableInTouchMode(true);
-                } else {
-                    holder.itemView.setFocusable(false);
-                    holder.itemView.setFocusableInTouchMode(false);
-                }
-                // This width ensures that some portion of #visibleChildCount'th child is
-                // off-bounds, creating more interesting test scenario.
-                holder.itemView.setMinimumWidth((mAttachedRv.getWidth()
-                        + mAttachedRv.getWidth() / (2 * visibleChildCount)) / visibleChildCount);
-            }
-        };
-        setupByConfig(new Config(HORIZONTAL, false, false).adapter(adapter), false);
-        waitForFirstLayout();
-
-        // adapter position of the currently focused item.
-        int focusIndex = 0;
-        View newFocused = mRecyclerView.getChildAt(focusIndex);
-        requestFocus(newFocused, true);
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.itemView.hasFocus(), is(true));
-
-        // adapter position of the item (whether focusable or not) that just becomes fully
-        // visible after focusSearch.
-        int visibleIndex = 0;
-        // The VH of the above adapter position
-        RecyclerView.ViewHolder toVisible = null;
-
-        // Navigate right through the focusable and unfocusable chunks. The focusable items should
-        // become focused one by one until hitting the last focusable item, at which point,
-        // unfocusable items should become visible on the screen until the currently focused item
-        // stays on the screen.
-        for (int i = 0; i < adapter.getItemCount(); i++) {
-            focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_RIGHT, true);
-            // adapter position of the currently focused item.
-            focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
-            toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
-            visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
-                    (visibleIndex + 1));
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
-            assertThat("Child at position " + focusIndex + " should be focused",
-                    toFocus.itemView.hasFocus(), is(true));
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
-            assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    // Run this test on Jelly Bean and newer because clearFocus on API 15 will call
-    // requestFocus in ViewRootImpl when clearChildFocus is called. Whereas, in API 16 and above,
-    // this call is delayed until after onFocusChange callback is called. Thus on API 16+, there's a
-    // transient state of no child having focus during which onFocusChange is executed. This
-    // transient state does not exist on API 15-.
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
-    @Test
-    public void unfocusableScrollingWhenFocusCleared() throws Throwable {
-        // The maximum number of child views that can be visible at any time.
-        final int visibleChildCount = 5;
-        final int consecutiveFocusablesCount = 2;
-        final int consecutiveUnFocusablesCount = 18;
-        final TestAdapter adapter = new TestAdapter(
-                consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
-            RecyclerView mAttachedRv;
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                // Good to have colors for debugging
-                StateListDrawable stl = new StateListDrawable();
-                stl.addState(new int[]{android.R.attr.state_focused},
-                        new ColorDrawable(Color.RED));
-                stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                //noinspection deprecation used to support kitkat tests
-                testViewHolder.itemView.setBackgroundDrawable(stl);
-                return testViewHolder;
-            }
-
-            @Override
-            public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                mAttachedRv = recyclerView;
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (position < consecutiveFocusablesCount) {
-                    holder.itemView.setFocusable(true);
-                    holder.itemView.setFocusableInTouchMode(true);
-                } else {
-                    holder.itemView.setFocusable(false);
-                    holder.itemView.setFocusableInTouchMode(false);
-                }
-                // This height ensures that some portion of #visibleChildCount'th child is
-                // off-bounds, creating more interesting test scenario.
-                holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
-                        + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
-            }
-        };
-        setupByConfig(new Config(VERTICAL, false, false).adapter(adapter), false);
-        waitForFirstLayout();
-
-        // adapter position of the currently focused item.
-        int focusIndex = 0;
-        View newFocused = mRecyclerView.getChildAt(focusIndex);
-        requestFocus(newFocused, true);
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        assertThat("Child at position " + focusIndex + " should be focused",
-                toFocus.itemView.hasFocus(), is(true));
-
-        final View nextView = focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
-        focusIndex++;
-        assertThat("Child at position " + focusIndex + " should be focused",
-                mRecyclerView.findViewHolderForAdapterPosition(focusIndex).itemView.hasFocus(),
-                is(true));
-        final CountDownLatch focusLatch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                nextView.setOnFocusChangeListener(new View.OnFocusChangeListener(){
-                    @Override
-                    public void onFocusChange(View v, boolean hasFocus) {
-                        assertNull("Focus just got cleared and no children should be holding"
-                                + " focus now.", mRecyclerView.getFocusedChild());
-                        try {
-                            // Calling focusSearch should be a no-op here since even though there
-                            // are unfocusable views down to scroll to, none of RV's children hold
-                            // focus at this stage.
-                            View focusedChild  = focusSearch(v, View.FOCUS_DOWN, true);
-                            assertNull("Calling focusSearch should be no-op when no children hold"
-                                    + "focus", focusedChild);
-                            // No scrolling should have happened, so any unfocusables that were
-                            // invisible should still be invisible.
-                            RecyclerView.ViewHolder unforcusablePartiallyVisibleChild =
-                                    mRecyclerView.findViewHolderForAdapterPosition(
-                                            visibleChildCount - 1);
-                            assertFalse("Child view at adapter pos " + (visibleChildCount - 1)
-                                            + " should not be fully visible.",
-                                    isViewFullyInBound(mRecyclerView,
-                                            unforcusablePartiallyVisibleChild.itemView));
-                        } catch (Throwable t) {
-                            postExceptionToInstrumentation(t);
-                        }
-                    }
-                });
-                nextView.clearFocus();
-                focusLatch.countDown();
-            }
-        });
-        assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
-        assertThat("Child at position " + focusIndex + " should no longer be focused",
-                mRecyclerView.findViewHolderForAdapterPosition(focusIndex).itemView.hasFocus(),
-                is(false));
-    }
-
-    @Test
-    public void removeAnchorItem() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(VERTICAL).stackFromBottom(false).reverseLayout(
-                        false), 100, 0);
-    }
-
-    @Test
-    public void removeAnchorItemReverse() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(VERTICAL).stackFromBottom(false).reverseLayout(true), 100,
-                0);
-    }
-
-    @Test
-    public void removeAnchorItemStackFromEnd() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(VERTICAL).stackFromBottom(true).reverseLayout(false), 100,
-                99);
-    }
-
-    @Test
-    public void removeAnchorItemStackFromEndAndReverse() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(VERTICAL).stackFromBottom(true).reverseLayout(true), 100,
-                99);
-    }
-
-    @Test
-    public void removeAnchorItemHorizontal() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(HORIZONTAL).stackFromBottom(false).reverseLayout(
-                        false), 100, 0);
-    }
-
-    @Test
-    public void removeAnchorItemReverseHorizontal() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(HORIZONTAL).stackFromBottom(false).reverseLayout(true),
-                100, 0);
-    }
-
-    @Test
-    public void removeAnchorItemStackFromEndHorizontal() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(HORIZONTAL).stackFromBottom(true).reverseLayout(false),
-                100, 99);
-    }
-
-    @Test
-    public void removeAnchorItemStackFromEndAndReverseHorizontal() throws Throwable {
-        removeAnchorItemTest(
-                new Config().orientation(HORIZONTAL).stackFromBottom(true).reverseLayout(true), 100,
-                99);
-    }
-
-    /**
-     * This tests a regression where predictive animations were not working as expected when the
-     * first item is removed and there aren't any more items to add from that direction.
-     * First item refers to the default anchor item.
-     */
-    public void removeAnchorItemTest(final Config config, int adapterSize,
-            final int removePos) throws Throwable {
-        config.adapter(new TestAdapter(adapterSize) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-                if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
-                    lp = new ViewGroup.MarginLayoutParams(0, 0);
-                    holder.itemView.setLayoutParams(lp);
-                }
-                ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
-                final int maxSize;
-                if (config.mOrientation == HORIZONTAL) {
-                    maxSize = mRecyclerView.getWidth();
-                    mlp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
-                } else {
-                    maxSize = mRecyclerView.getHeight();
-                    mlp.width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
-                }
-
-                final int desiredSize;
-                if (position == removePos) {
-                    // make it large
-                    desiredSize = maxSize / 4;
-                } else {
-                    // make it small
-                    desiredSize = maxSize / 8;
-                }
-                if (config.mOrientation == HORIZONTAL) {
-                    mlp.width = desiredSize;
-                } else {
-                    mlp.height = desiredSize;
-                }
-            }
-        });
-        setupByConfig(config, true);
-        final int childCount = mLayoutManager.getChildCount();
-        RecyclerView.ViewHolder toBeRemoved = null;
-        List<RecyclerView.ViewHolder> toBeMoved = new ArrayList<RecyclerView.ViewHolder>();
-        for (int i = 0; i < childCount; i++) {
-            View child = mLayoutManager.getChildAt(i);
-            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
-            if (holder.getAdapterPosition() == removePos) {
-                toBeRemoved = holder;
-            } else {
-                toBeMoved.add(holder);
-            }
-        }
-        assertNotNull("test sanity", toBeRemoved);
-        assertEquals("test sanity", childCount - 1, toBeMoved.size());
-        LoggingItemAnimator loggingItemAnimator = new LoggingItemAnimator();
-        mRecyclerView.setItemAnimator(loggingItemAnimator);
-        loggingItemAnimator.reset();
-        loggingItemAnimator.expectRunPendingAnimationsCall(1);
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(removePos, 1);
-        mLayoutManager.waitForLayout(1);
-        loggingItemAnimator.waitForPendingAnimationsCall(2);
-        assertTrue("removed child should receive remove animation",
-                loggingItemAnimator.mRemoveVHs.contains(toBeRemoved));
-        for (RecyclerView.ViewHolder vh : toBeMoved) {
-            assertTrue("view holder should be in moved list",
-                    loggingItemAnimator.mMoveVHs.contains(vh));
-        }
-        List<RecyclerView.ViewHolder> newHolders = new ArrayList<RecyclerView.ViewHolder>();
-        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
-            View child = mLayoutManager.getChildAt(i);
-            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(child);
-            if (toBeRemoved != holder && !toBeMoved.contains(holder)) {
-                newHolders.add(holder);
-            }
-        }
-        assertTrue("some new children should show up for the new space", newHolders.size() > 0);
-        assertEquals("no items should receive animate add since they are not new", 0,
-                loggingItemAnimator.mAddVHs.size());
-        for (RecyclerView.ViewHolder holder : newHolders) {
-            assertTrue("new holder should receive a move animation",
-                    loggingItemAnimator.mMoveVHs.contains(holder));
-        }
-        assertTrue("control against adding too many children due to bad layout state preparation."
-                        + " initial:" + childCount + ", current:" + mRecyclerView.getChildCount(),
-                mRecyclerView.getChildCount() <= childCount + 3 /*1 for removed view, 2 for its size*/);
-    }
-
-    void waitOneCycle() throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-            }
-        });
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
-    @Test
-    public void hiddenNoneRemoveViewAccessibility() throws Throwable {
-        final Config config = new Config();
-        int adapterSize = 1000;
-        final boolean[] firstItemSpecialSize = new boolean[] {false};
-        TestAdapter adapter = new TestAdapter(adapterSize) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-                if (!(lp instanceof ViewGroup.MarginLayoutParams)) {
-                    lp = new ViewGroup.MarginLayoutParams(0, 0);
-                    holder.itemView.setLayoutParams(lp);
-                }
-                ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;
-                final int maxSize;
-                if (config.mOrientation == HORIZONTAL) {
-                    maxSize = mRecyclerView.getWidth();
-                    mlp.height = ViewGroup.MarginLayoutParams.MATCH_PARENT;
-                } else {
-                    maxSize = mRecyclerView.getHeight();
-                    mlp.width = ViewGroup.MarginLayoutParams.MATCH_PARENT;
-                }
-
-                final int desiredSize;
-                if (position == 0 && firstItemSpecialSize[0]) {
-                    desiredSize = maxSize / 3;
-                } else {
-                    desiredSize = maxSize / 8;
-                }
-                if (config.mOrientation == HORIZONTAL) {
-                    mlp.width = desiredSize;
-                } else {
-                    mlp.height = desiredSize;
-                }
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position, List<Object> payloads) {
-                onBindViewHolder(holder, position);
-            }
-        };
-        adapter.setHasStableIds(false);
-        config.adapter(adapter);
-        setupByConfig(config, true);
-        final DummyItemAnimator itemAnimator = new DummyItemAnimator();
-        mRecyclerView.setItemAnimator(itemAnimator);
-
-        // push last item out by increasing first item's size
-        final int childBeingPushOut = mLayoutManager.getChildCount() - 1;
-        RecyclerView.ViewHolder itemViewHolder = mRecyclerView
-                .findViewHolderForAdapterPosition(childBeingPushOut);
-        final int originalAccessibility = ViewCompat.getImportantForAccessibility(
-                itemViewHolder.itemView);
-        assertTrue(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO == originalAccessibility
-                || ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES == originalAccessibility);
-
-        itemAnimator.expect(DummyItemAnimator.MOVE_START, 1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                firstItemSpecialSize[0] = true;
-                mTestAdapter.notifyItemChanged(0, "XXX");
-            }
-        });
-        // wait till itemAnimator starts which will block itemView's accessibility
-        itemAnimator.waitFor(DummyItemAnimator.MOVE_START);
-        // RV Changes accessiblity after onMoveStart, so wait one more cycle.
-        waitOneCycle();
-        assertTrue(itemAnimator.getMovesAnimations().contains(itemViewHolder));
-        assertEquals(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
-                ViewCompat.getImportantForAccessibility(itemViewHolder.itemView));
-
-        // notify Change again to run predictive animation.
-        mLayoutManager.expectLayouts(2);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTestAdapter.notifyItemChanged(0, "XXX");
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                itemAnimator.endAnimations();
-            }
-        });
-        // scroll to the view being pushed out, it should get same view from cache as the item
-        // in adapter does not change.
-        smoothScrollToPosition(childBeingPushOut);
-        RecyclerView.ViewHolder itemViewHolder2 = mRecyclerView
-                .findViewHolderForAdapterPosition(childBeingPushOut);
-        assertSame(itemViewHolder, itemViewHolder2);
-        // the important for accessibility should be reset to YES/AUTO:
-        final int newAccessibility = ViewCompat.getImportantForAccessibility(
-                itemViewHolder.itemView);
-        assertTrue(ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO == newAccessibility
-                || ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES == newAccessibility);
-    }
-
-    @Test
-    public void layoutFrozenBug70402422() throws Throwable {
-        final Config config = new Config();
-        TestAdapter adapter = new TestAdapter(2);
-        adapter.setHasStableIds(false);
-        config.adapter(adapter);
-        setupByConfig(config, true);
-        final DummyItemAnimator itemAnimator = new DummyItemAnimator();
-        mRecyclerView.setItemAnimator(itemAnimator);
-
-        final View firstItemView = mRecyclerView
-                .findViewHolderForAdapterPosition(0).itemView;
-
-        itemAnimator.expect(DummyItemAnimator.REMOVE_START, 1);
-        mTestAdapter.deleteAndNotify(1, 1);
-        itemAnimator.waitFor(DummyItemAnimator.REMOVE_START);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setLayoutFrozen(true);
-            }
-        });
-        // requestLayout during item animation, which should be eaten by setLayoutFrozen(true)
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                firstItemView.requestLayout();
-            }
-        });
-        assertTrue(firstItemView.isLayoutRequested());
-        assertFalse(mRecyclerView.isLayoutRequested());
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                itemAnimator.endAnimations();
-            }
-        });
-        // When setLayoutFrozen(false), the firstItemView should run a layout pass and clear
-        // isLayoutRequested() flag.
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setLayoutFrozen(false);
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        assertFalse(firstItemView.isLayoutRequested());
-        assertFalse(mRecyclerView.isLayoutRequested());
-    }
-
-    @Test
-    public void keepFocusOnRelayout() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, false).itemCount(500), true);
-        int center = (mLayoutManager.findLastVisibleItemPosition()
-                - mLayoutManager.findFirstVisibleItemPosition()) / 2;
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(center);
-        final int top = mLayoutManager.mOrientationHelper.getDecoratedStart(vh.itemView);
-        requestFocus(vh.itemView, true);
-        assertTrue("view should have the focus", vh.itemView.hasFocus());
-        // add a bunch of items right before that view, make sure it keeps its position
-        mLayoutManager.expectLayouts(2);
-        final int childCountToAdd = mRecyclerView.getChildCount() * 2;
-        mTestAdapter.addAndNotify(center, childCountToAdd);
-        center += childCountToAdd; // offset item
-        mLayoutManager.waitForLayout(2);
-        mLayoutManager.waitForAnimationsToEnd(20);
-        final RecyclerView.ViewHolder postVH = mRecyclerView.findViewHolderForLayoutPosition(center);
-        assertNotNull("focused child should stay in layout", postVH);
-        assertSame("same view holder should be kept for unchanged child", vh, postVH);
-        assertEquals("focused child's screen position should stay unchanged", top,
-                mLayoutManager.mOrientationHelper.getDecoratedStart(postVH.itemView));
-    }
-
-    @Test
-    public void keepFullFocusOnResize() throws Throwable {
-        keepFocusOnResizeTest(new Config(VERTICAL, false, false).itemCount(500), true);
-    }
-
-    @Test
-    public void keepPartialFocusOnResize() throws Throwable {
-        keepFocusOnResizeTest(new Config(VERTICAL, false, false).itemCount(500), false);
-    }
-
-    @Test
-    public void keepReverseFullFocusOnResize() throws Throwable {
-        keepFocusOnResizeTest(new Config(VERTICAL, true, false).itemCount(500), true);
-    }
-
-    @Test
-    public void keepReversePartialFocusOnResize() throws Throwable {
-        keepFocusOnResizeTest(new Config(VERTICAL, true, false).itemCount(500), false);
-    }
-
-    @Test
-    public void keepStackFromEndFullFocusOnResize() throws Throwable {
-        keepFocusOnResizeTest(new Config(VERTICAL, false, true).itemCount(500), true);
-    }
-
-    @Test
-    public void keepStackFromEndPartialFocusOnResize() throws Throwable {
-        keepFocusOnResizeTest(new Config(VERTICAL, false, true).itemCount(500), false);
-    }
-
-    public void keepFocusOnResizeTest(final Config config, boolean fullyVisible) throws Throwable {
-        setupByConfig(config, true);
-        final int targetPosition;
-        if (config.mStackFromEnd) {
-            targetPosition = mLayoutManager.findFirstVisibleItemPosition();
-        } else {
-            targetPosition = mLayoutManager.findLastVisibleItemPosition();
-        }
-        final OrientationHelper helper = mLayoutManager.mOrientationHelper;
-        final RecyclerView.ViewHolder vh = mRecyclerView
-                .findViewHolderForLayoutPosition(targetPosition);
-
-        // scroll enough to offset the child
-        int startMargin = helper.getDecoratedStart(vh.itemView) -
-                helper.getStartAfterPadding();
-        int endMargin = helper.getEndAfterPadding() -
-                helper.getDecoratedEnd(vh.itemView);
-        Log.d(TAG, "initial start margin " + startMargin + " , end margin:" + endMargin);
-        requestFocus(vh.itemView, true);
-        assertTrue("view should gain the focus", vh.itemView.hasFocus());
-        // scroll enough to offset the child
-        startMargin = helper.getDecoratedStart(vh.itemView) -
-                helper.getStartAfterPadding();
-        endMargin = helper.getEndAfterPadding() -
-                helper.getDecoratedEnd(vh.itemView);
-
-        Log.d(TAG, "start margin " + startMargin + " , end margin:" + endMargin);
-        assertTrue("View should become fully visible", startMargin >= 0 && endMargin >= 0);
-
-        int expectedOffset = 0;
-        boolean offsetAtStart = false;
-        if (!fullyVisible) {
-            // move it a bit such that it is no more fully visible
-            final int childSize = helper
-                    .getDecoratedMeasurement(vh.itemView);
-            expectedOffset = childSize / 3;
-            if (startMargin < endMargin) {
-                scrollBy(expectedOffset);
-                offsetAtStart = true;
-            } else {
-                scrollBy(-expectedOffset);
-                offsetAtStart = false;
-            }
-            startMargin = helper.getDecoratedStart(vh.itemView) -
-                    helper.getStartAfterPadding();
-            endMargin = helper.getEndAfterPadding() -
-                    helper.getDecoratedEnd(vh.itemView);
-            assertTrue("test sanity, view should not be fully visible", startMargin < 0
-                    || endMargin < 0);
-        }
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final ViewGroup.LayoutParams layoutParams = mRecyclerView.getLayoutParams();
-                if (config.mOrientation == HORIZONTAL) {
-                    layoutParams.width = mRecyclerView.getWidth() / 2;
-                } else {
-                    layoutParams.height = mRecyclerView.getHeight() / 2;
-                }
-                mRecyclerView.setLayoutParams(layoutParams);
-            }
-        });
-        Thread.sleep(100);
-        // add a bunch of items right before that view, make sure it keeps its position
-        mLayoutManager.waitForLayout(2);
-        mLayoutManager.waitForAnimationsToEnd(20);
-        assertTrue("view should preserve the focus", vh.itemView.hasFocus());
-        final RecyclerView.ViewHolder postVH = mRecyclerView
-                .findViewHolderForLayoutPosition(targetPosition);
-        assertNotNull("focused child should stay in layout", postVH);
-        assertSame("same view holder should be kept for unchanged child", vh, postVH);
-        View focused = postVH.itemView;
-
-        startMargin = helper.getDecoratedStart(focused) - helper.getStartAfterPadding();
-        endMargin = helper.getEndAfterPadding() - helper.getDecoratedEnd(focused);
-
-        assertTrue("focused child should be somewhat visible",
-                helper.getDecoratedStart(focused) < helper.getEndAfterPadding()
-                        && helper.getDecoratedEnd(focused) > helper.getStartAfterPadding());
-        if (fullyVisible) {
-            assertTrue("focused child end should stay fully visible",
-                    endMargin >= 0);
-            assertTrue("focused child start should stay fully visible",
-                    startMargin >= 0);
-        } else {
-            if (offsetAtStart) {
-                assertTrue("start should preserve its offset", startMargin < 0);
-                assertTrue("end should be visible", endMargin >= 0);
-            } else {
-                assertTrue("end should preserve its offset", endMargin < 0);
-                assertTrue("start should be visible", startMargin >= 0);
-            }
-        }
-    }
-
-    @Test
-    public void scrollToPositionWithPredictive() throws Throwable {
-        scrollToPositionWithPredictive(0, LinearLayoutManager.INVALID_OFFSET);
-        removeRecyclerView();
-        scrollToPositionWithPredictive(3, 20);
-        removeRecyclerView();
-        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2,
-                LinearLayoutManager.INVALID_OFFSET);
-        removeRecyclerView();
-        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2, 10);
-    }
-
-    @Test
-    public void recycleDuringAnimations() throws Throwable {
-        final AtomicInteger childCount = new AtomicInteger(0);
-        final TestAdapter adapter = new TestAdapter(300) {
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                final int cnt = childCount.incrementAndGet();
-                final TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                if (DEBUG) {
-                    Log.d(TAG, "CHILD_CNT(create):" + cnt + ", " + testViewHolder);
-                }
-                return testViewHolder;
-            }
-        };
-        setupByConfig(new Config(VERTICAL, false, false).itemCount(300)
-                .adapter(adapter), true);
-
-        final RecyclerView.RecycledViewPool pool = new RecyclerView.RecycledViewPool() {
-            @Override
-            public void putRecycledView(RecyclerView.ViewHolder scrap) {
-                super.putRecycledView(scrap);
-                int cnt = childCount.decrementAndGet();
-                if (DEBUG) {
-                    Log.d(TAG, "CHILD_CNT(put):" + cnt + ", " + scrap);
-                }
-            }
-
-            @Override
-            public RecyclerView.ViewHolder getRecycledView(int viewType) {
-                final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType);
-                if (recycledView != null) {
-                    final int cnt = childCount.incrementAndGet();
-                    if (DEBUG) {
-                        Log.d(TAG, "CHILD_CNT(get):" + cnt + ", " + recycledView);
-                    }
-                }
-                return recycledView;
-            }
-        };
-        pool.setMaxRecycledViews(mTestAdapter.getItemViewType(0), 500);
-        mRecyclerView.setRecycledViewPool(pool);
-
-
-        // now keep adding children to trigger more children being created etc.
-        for (int i = 0; i < 100; i ++) {
-            adapter.addAndNotify(15, 1);
-            Thread.sleep(15);
-        }
-        getInstrumentation().waitForIdleSync();
-        waitForAnimations(2);
-        assertEquals("Children count should add up", childCount.get(),
-                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
-
-        // now trigger lots of add again, followed by a scroll to position
-        for (int i = 0; i < 100; i ++) {
-            adapter.addAndNotify(5 + (i % 3) * 3, 1);
-            Thread.sleep(25);
-        }
-        smoothScrollToPosition(mLayoutManager.findLastVisibleItemPosition() + 20);
-        waitForAnimations(2);
-        getInstrumentation().waitForIdleSync();
-        assertEquals("Children count should add up", childCount.get(),
-                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
-    }
-
-
-    @Test
-    public void dontRecycleChildrenOnDetach() throws Throwable {
-        setupByConfig(new Config().recycleChildrenOnDetach(false), true);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int recyclerSize = mRecyclerView.mRecycler.getRecycledViewPool().size();
-                ((ViewGroup)mRecyclerView.getParent()).removeView(mRecyclerView);
-                assertEquals("No views are recycled", recyclerSize,
-                        mRecyclerView.mRecycler.getRecycledViewPool().size());
-            }
-        });
-    }
-
-    @Test
-    public void recycleChildrenOnDetach() throws Throwable {
-        setupByConfig(new Config().recycleChildrenOnDetach(true), true);
-        final int childCount = mLayoutManager.getChildCount();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int recyclerSize = mRecyclerView.mRecycler.getRecycledViewPool().size();
-                mRecyclerView.mRecycler.getRecycledViewPool().setMaxRecycledViews(
-                        mTestAdapter.getItemViewType(0), recyclerSize + childCount);
-                ((ViewGroup)mRecyclerView.getParent()).removeView(mRecyclerView);
-                assertEquals("All children should be recycled", childCount + recyclerSize,
-                        mRecyclerView.mRecycler.getRecycledViewPool().size());
-            }
-        });
-    }
-
-    @Test
-    public void scrollAndClear() throws Throwable {
-        setupByConfig(new Config(), true);
-
-        assertTrue("Children not laid out", mLayoutManager.collectChildCoordinates().size() > 0);
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mLayoutManager.scrollToPositionWithOffset(1, 0);
-                mTestAdapter.clearOnUIThread();
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-
-        assertEquals("Remaining children", 0, mLayoutManager.collectChildCoordinates().size());
-    }
-
-
-    @Test
-    public void accessibilityPositions() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, false), true);
-        final AccessibilityDelegateCompat delegateCompat = mRecyclerView
-                .getCompatAccessibilityDelegate();
-        final AccessibilityEvent event = AccessibilityEvent.obtain();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityEvent(mRecyclerView, event);
-            }
-        });
-        assertEquals("result should have first position",
-                event.getFromIndex(),
-                mLayoutManager.findFirstVisibleItemPosition());
-        assertEquals("result should have last position",
-                event.getToIndex(),
-                mLayoutManager.findLastVisibleItemPosition());
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
deleted file mode 100644
index 3eba432..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/MultiRecyclerViewPrefetchTest.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.Context;
-import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
-@RunWith(AndroidJUnit4.class)
-public class MultiRecyclerViewPrefetchTest {
-    private RecyclerView.RecycledViewPool mRecycledViewPool;
-    private ArrayList<RecyclerView> mViews = new ArrayList<>();
-
-    private long mMockNanoTime = 0;
-
-    @Before
-    public void setup() throws Exception {
-        GapWorker gapWorker = GapWorker.sGapWorker.get();
-        if (gapWorker != null) {
-            assertTrue(gapWorker.mRecyclerViews.isEmpty());
-        }
-        mMockNanoTime = 0;
-        mRecycledViewPool = new RecyclerView.RecycledViewPool();
-    }
-
-    @After
-    public void teardown() {
-        for (RecyclerView rv : mViews) {
-            if (rv.isAttachedToWindow()) {
-                // ensure we detach views, so ThreadLocal GapWorker's list is cleared
-                rv.onDetachedFromWindow();
-            }
-        }
-        GapWorker gapWorker = GapWorker.sGapWorker.get();
-        if (gapWorker != null) {
-            assertTrue(gapWorker.mRecyclerViews.isEmpty());
-        }
-        mViews.clear();
-    }
-
-    private RecyclerView createRecyclerView() {
-        RecyclerView rv = new RecyclerView(getContext()) {
-            @Override
-            long getNanoTime() {
-                return mMockNanoTime;
-            }
-
-            @Override
-            public int getWindowVisibility() {
-                // Pretend to be visible to avoid being filtered out
-                return View.VISIBLE;
-            }
-        };
-
-        // shared stats + enable clearing of pool
-        rv.setRecycledViewPool(mRecycledViewPool);
-
-        // enable GapWorker
-        rv.onAttachedToWindow();
-        mViews.add(rv);
-
-        return rv;
-    }
-
-    public void registerTimePassingMs(long ms) {
-        mMockNanoTime += TimeUnit.MILLISECONDS.toNanos(ms);
-    }
-
-    private Context getContext() {
-        return InstrumentationRegistry.getContext();
-    }
-
-    private void clearCachesAndPool() {
-        for (RecyclerView rv : mViews) {
-            rv.mRecycler.recycleAndClearCachedViews();
-        }
-        mRecycledViewPool.clear();
-    }
-
-    @Test
-    public void prefetchOrdering() throws Throwable {
-        for (int i = 0; i < 3; i++) {
-            RecyclerView rv = createRecyclerView();
-
-            // first view 50x100 pixels, rest are 100x100 so second column is offset
-            rv.setAdapter(new RecyclerView.Adapter() {
-                @Override
-                public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
-                        int viewType) {
-                    registerTimePassingMs(5);
-                    return new RecyclerView.ViewHolder(new View(parent.getContext())) {};
-                }
-
-                @Override
-                public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-                    registerTimePassingMs(5);
-                    holder.itemView.setMinimumWidth(100);
-                    holder.itemView.setMinimumHeight(position == 0 ? 50 : 100);
-                }
-
-                @Override
-                public int getItemCount() {
-                    return 100;
-                }
-            });
-            rv.setLayoutManager(
-                    new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL));
-
-            // Attach, position 200x200 view at 100 scroll offset, with an empty cache.
-            rv.measure(View.MeasureSpec.AT_MOST | 200, View.MeasureSpec.AT_MOST | 200);
-            rv.layout(0, 0, 200, 200);
-            rv.scrollBy(0, 100);
-
-            rv.setTranslationX(100 * i);
-        }
-
-        GapWorker worker = GapWorker.sGapWorker.get();
-        assertNotNull(worker);
-
-        /* Each row is 50 pixels:
-         * ------------- *
-         *   0   |   1   *
-         *___2___|___1___*
-         *   2   |   3   *
-         *   4   |   3   *
-         *   4   |   5   *
-         *___6___|___5___*
-         *   6   |   7   *
-         *   8   |   7   *
-         *      ...      *
-         */
-
-        mViews.get(0).mPrefetchRegistry.setPrefetchVector(0, 10);
-        mViews.get(1).mPrefetchRegistry.setPrefetchVector(0, -11);
-        mViews.get(2).mPrefetchRegistry.setPrefetchVector(0, 60);
-
-        // prefetch with deadline that has passed - only demand-loaded views
-        clearCachesAndPool();
-        worker.prefetch(0);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(0), 7);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(1), 1);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(2), 7, 8);
-
-
-        // prefetch with 54ms - should load demand-loaded views (taking 40ms) + one more
-        clearCachesAndPool();
-        worker.prefetch(mMockNanoTime + TimeUnit.MILLISECONDS.toNanos(54));
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(0), 7);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(1), 0, 1);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mViews.get(2), 7, 8);
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
deleted file mode 100644
index 973b138..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAccessibilityLifecycleTest.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.os.Build;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.MediumTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityNodeInfo;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class RecyclerViewAccessibilityLifecycleTest extends BaseRecyclerViewInstrumentationTest {
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
-    @Test
-    public void dontDispatchChangeDuringLayout() throws Throwable {
-        LayoutAllLayoutManager lm = new LayoutAllLayoutManager();
-        final AtomicBoolean calledA11DuringLayout = new AtomicBoolean(false);
-        final List<Integer> invocations = new ArrayList<>();
-
-        final WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity()) {
-            @Override
-            boolean isAccessibilityEnabled() {
-                return true;
-            }
-
-            @Override
-            public boolean setChildImportantForAccessibilityInternal(ViewHolder viewHolder,
-                    int importantForAccessibilityBeforeHidden) {
-                invocations.add(importantForAccessibilityBeforeHidden);
-                boolean notified = super.setChildImportantForAccessibilityInternal(viewHolder,
-                        importantForAccessibilityBeforeHidden);
-                if (notified && mRecyclerView.isComputingLayout()) {
-                    calledA11DuringLayout.set(true);
-                }
-                return notified;
-            }
-        };
-        TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
-                ViewCompat.setImportantForAccessibility(vh.itemView,
-                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-                return vh;
-            }
-        };
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(1);
-        assertThat(calledA11DuringLayout.get(), is(false));
-        lm.expectLayouts(1);
-        adapter.deleteAndNotify(2, 2);
-        lm.waitForLayout(2);
-        recyclerView.waitUntilAnimations();
-        assertThat(invocations, is(Arrays.asList(
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES)));
-
-        assertThat(calledA11DuringLayout.get(), is(false));
-    }
-
-    @LargeTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
-    @Test
-    public void processAllViewHolders() {
-        RecyclerView rv = new RecyclerView(getActivity());
-        rv.setLayoutManager(new LinearLayoutManager(getActivity()));
-        View itemView1 = spy(new View(getActivity()));
-        View itemView2 = spy(new View(getActivity()));
-        View itemView3 = spy(new View(getActivity()));
-
-        rv.addView(itemView1);
-        // do not add 2
-        rv.addView(itemView3);
-
-        RecyclerView.ViewHolder vh1 = new RecyclerView.ViewHolder(itemView1) {};
-        vh1.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
-        RecyclerView.ViewHolder vh2 = new RecyclerView.ViewHolder(itemView2) {};
-        vh2.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
-        RecyclerView.ViewHolder vh3 = new RecyclerView.ViewHolder(itemView3) {};
-        vh3.mPendingAccessibilityState = View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
-
-        rv.mPendingAccessibilityImportanceChange.add(vh1);
-        rv.mPendingAccessibilityImportanceChange.add(vh2);
-        rv.mPendingAccessibilityImportanceChange.add(vh3);
-        rv.dispatchPendingImportantForAccessibilityChanges();
-
-        verify(itemView1).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
-        //noinspection WrongConstant
-        verify(itemView2, never()).setImportantForAccessibility(anyInt());
-        verify(itemView3).setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
-        assertThat(rv.mPendingAccessibilityImportanceChange.size(), is(0));
-    }
-
-    public class LayoutAllLayoutManager extends TestLayoutManager {
-        private final boolean mAllowNullLayoutLatch;
-
-        public LayoutAllLayoutManager() {
-            // by default, we don't allow unexpected layouts.
-            this(false);
-        }
-        LayoutAllLayoutManager(boolean allowNullLayoutLatch) {
-            mAllowNullLayoutLatch = allowNullLayoutLatch;
-        }
-
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            detachAndScrapAttachedViews(recycler);
-            layoutRange(recycler, 0, state.getItemCount());
-            if (!mAllowNullLayoutLatch || layoutLatch != null) {
-                layoutLatch.countDown();
-            }
-        }
-    }
-
-    @Test
-    public void notClearCustomViewDelegate() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity()) {
-            @Override
-            boolean isAccessibilityEnabled() {
-                return true;
-            }
-        };
-        final int[] layoutStart = new int[] {0};
-        final int layoutCount = 5;
-        final TestLayoutManager layoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                removeAndRecycleScrapInt(recycler);
-                layoutRange(recycler, layoutStart[0], layoutStart[0] + layoutCount);
-                if (layoutLatch != null) {
-                    layoutLatch.countDown();
-                }
-            }
-        };
-        final AccessibilityDelegateCompat delegateCompat = new AccessibilityDelegateCompat() {
-            @Override
-            public void onInitializeAccessibilityNodeInfo(View host,
-                    AccessibilityNodeInfoCompat info) {
-                super.onInitializeAccessibilityNodeInfo(host, info);
-                info.setChecked(true);
-            }
-        };
-        final TestAdapter adapter = new TestAdapter(100) {
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
-                ViewCompat.setAccessibilityDelegate(vh.itemView, delegateCompat);
-                return vh;
-            }
-        };
-        layoutManager.expectLayouts(1);
-        recyclerView.getRecycledViewPool().setMaxRecycledViews(0, 100);
-        recyclerView.setItemViewCacheSize(0); // no cache, directly goes to pool
-        recyclerView.setLayoutManager(layoutManager);
-        setRecyclerView(recyclerView);
-         mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.setAdapter(adapter);
-            }
-        });
-        layoutManager.waitForLayout(1);
-
-        assertEquals(layoutCount, recyclerView.getChildCount());
-        final ArrayList<View> children = new ArrayList();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < recyclerView.getChildCount(); i++) {
-                    View view = recyclerView.getChildAt(i);
-                    assertEquals(layoutStart[0] + i,
-                            recyclerView.getChildAdapterPosition(view));
-                    AccessibilityNodeInfo info = recyclerView.getChildAt(i)
-                            .createAccessibilityNodeInfo();
-                    assertTrue("custom delegate sets isChecked", info.isChecked());
-                    assertFalse(recyclerView.findContainingViewHolder(view).hasAnyOfTheFlags(
-                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
-                    assertTrue(ViewCompat.hasAccessibilityDelegate(view));
-                    children.add(view);
-                }
-            }
-        });
-
-        // invalidate and start layout at 50, all existing views will goes to recycler and
-        // being reused.
-        layoutStart[0] = 50;
-        layoutManager.expectLayouts(1);
-        adapter.dispatchDataSetChanged();
-        layoutManager.waitForLayout(1);
-        assertEquals(layoutCount, recyclerView.getChildCount());
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < recyclerView.getChildCount(); i++) {
-                    View view = recyclerView.getChildAt(i);
-                    assertEquals(layoutStart[0] + i,
-                            recyclerView.getChildAdapterPosition(view));
-                    assertTrue(children.contains(view));
-                    AccessibilityNodeInfo info = view.createAccessibilityNodeInfo();
-                    assertTrue("custom delegate sets isChecked", info.isChecked());
-                    assertFalse(recyclerView.findContainingViewHolder(view).hasAnyOfTheFlags(
-                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
-                    assertTrue(ViewCompat.hasAccessibilityDelegate(view));
-                }
-            }
-        });
-    }
-
-    @Test
-    public void clearItemDelegateWhenGoesToPool() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity()) {
-            @Override
-            boolean isAccessibilityEnabled() {
-                return true;
-            }
-        };
-        final int firstPassLayoutCount = 5;
-        final int[] layoutCount = new int[] {firstPassLayoutCount};
-        final TestLayoutManager layoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                removeAndRecycleScrapInt(recycler);
-                layoutRange(recycler, 0, layoutCount[0]);
-                if (layoutLatch != null) {
-                    layoutLatch.countDown();
-                }
-            }
-        };
-        final TestAdapter adapter = new TestAdapter(100);
-        layoutManager.expectLayouts(1);
-        recyclerView.getRecycledViewPool().setMaxRecycledViews(0, 100);
-        recyclerView.setItemViewCacheSize(0); // no cache, directly goes to pool
-        recyclerView.setLayoutManager(layoutManager);
-        setRecyclerView(recyclerView);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.setAdapter(adapter);
-            }
-        });
-        layoutManager.waitForLayout(1);
-
-        assertEquals(firstPassLayoutCount, recyclerView.getChildCount());
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < recyclerView.getChildCount(); i++) {
-                    View view = recyclerView.getChildAt(i);
-                    assertEquals(i, recyclerView.getChildAdapterPosition(view));
-                    assertTrue(recyclerView.findContainingViewHolder(view).hasAnyOfTheFlags(
-                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
-                    assertTrue(ViewCompat.hasAccessibilityDelegate(view));
-                    AccessibilityNodeInfo info = view.createAccessibilityNodeInfo();
-                    if (Build.VERSION.SDK_INT >= 19) {
-                        assertNotNull(info.getCollectionItemInfo());
-                    }
-                }
-            }
-        });
-
-        // let all items go to recycler pool
-        layoutManager.expectLayouts(1);
-        layoutCount[0] = 0;
-        adapter.resetItemsTo(new ArrayList());
-        layoutManager.waitForLayout(1);
-        assertEquals(0, recyclerView.getChildCount());
-        assertEquals(firstPassLayoutCount, recyclerView.getRecycledViewPool()
-                .getRecycledViewCount(0));
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < firstPassLayoutCount; i++) {
-                    RecyclerView.ViewHolder vh = recyclerView.getRecycledViewPool()
-                            .getRecycledView(0);
-                    View view = vh.itemView;
-                    assertEquals(RecyclerView.NO_POSITION,
-                            recyclerView.getChildAdapterPosition(view));
-                    assertFalse(vh.hasAnyOfTheFlags(
-                            RecyclerView.ViewHolder.FLAG_SET_A11Y_ITEM_DELEGATE));
-                    assertFalse(ViewCompat.hasAccessibilityDelegate(view));
-                }
-            }
-        });
-
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
deleted file mode 100644
index da5be39..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewAnimationsTest.java
+++ /dev/null
@@ -1,1772 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.graphics.Rect;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.ViewCompat;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Tests for {@link SimpleItemAnimator} API.
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class RecyclerViewAnimationsTest extends BaseRecyclerViewAnimationsTest {
-
-    final List<TestViewHolder> recycledVHs = new ArrayList<>();
-
-    @Test
-    public void keepFocusAfterChangeAnimation() throws Throwable {
-        setupBasic(10, 0, 5, new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                holder.itemView.setFocusableInTouchMode(true);
-            }
-        });
-        ((SimpleItemAnimator)(mRecyclerView.getItemAnimator())).setSupportsChangeAnimations(true);
-
-        final RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForAdapterPosition(3);
-        assertNotNull("test sanity", oldVh);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                oldVh.itemView.requestFocus();
-            }
-        });
-        assertTrue("test sanity", oldVh.itemView.hasFocus());
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.changeAndNotify(3, 1);
-        mLayoutManager.waitForLayout(2);
-
-        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3);
-        assertNotNull("test sanity", newVh);
-        assertNotSame(oldVh, newVh);
-        assertFalse(oldVh.itemView.hasFocus());
-        assertTrue(newVh.itemView.hasFocus());
-    }
-
-    @Test
-    public void changeAndDisappearDontReUseViewHolder() throws Throwable {
-        changeAndDisappearTest(false, false);
-    }
-
-    @Test
-    public void changeAndDisappearReUseViewHolder() throws Throwable {
-        changeAndDisappearTest(true, false);
-    }
-
-    @Test
-    public void changeAndDisappearReUseWithScrapViewHolder() throws Throwable {
-        changeAndDisappearTest(true, true);
-    }
-
-    public void changeAndDisappearTest(final boolean reUse, final boolean useScrap)
-            throws Throwable {
-        final List<RecyclerView.ViewHolder> mRecycled = new ArrayList<>();
-        final TestAdapter adapter = new TestAdapter(1) {
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                super.onViewRecycled(holder);
-                mRecycled.add(holder);
-            }
-        };
-        setupBasic(1, 0, 1, adapter);
-        RecyclerView.ViewHolder vh = mRecyclerView.getChildViewHolder(mRecyclerView.getChildAt(0));
-        LoggingItemAnimator animator = new LoggingItemAnimator() {
-            @Override
-            public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
-                                                     @NonNull List<Object> payloads) {
-                return reUse;
-            }
-        };
-        mRecyclerView.setItemAnimator(animator);
-        mLayoutManager.expectLayouts(2);
-        final RecyclerView.ViewHolder[] updatedVH = new RecyclerView.ViewHolder[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                adapter.notifyItemChanged(0);
-                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-                    @Override
-                    void doLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
-                                  RecyclerView.State state) {
-                        if (state.isPreLayout()) {
-                            super.doLayout(recycler, lm, state);
-                        } else {
-                            lm.detachAndScrapAttachedViews(recycler);
-                            final View view;
-                            if (reUse && useScrap) {
-                                view = recycler.getScrapViewAt(0);
-                            } else {
-                                view = recycler.getViewForPosition(0);
-                            }
-                            updatedVH[0] = RecyclerView.getChildViewHolderInt(view);
-                            lm.addDisappearingView(view);
-                        }
-                    }
-                };
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-
-        MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateDisappearanceList),
-                CoreMatchers.is(reUse));
-        MatcherAssert.assertThat(animator.contains(vh, animator.mAnimateChangeList),
-                CoreMatchers.is(!reUse));
-        MatcherAssert.assertThat(animator.contains(updatedVH[0], animator.mAnimateChangeList),
-                CoreMatchers.is(!reUse));
-        MatcherAssert.assertThat(animator.contains(updatedVH[0],
-                animator.mAnimateDisappearanceList), CoreMatchers.is(reUse));
-        waitForAnimations(10);
-        MatcherAssert.assertThat(mRecyclerView.getChildCount(), CoreMatchers.is(0));
-        if (useScrap || !reUse) {
-            MatcherAssert.assertThat(mRecycled.contains(vh), CoreMatchers.is(true));
-        } else {
-            MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(vh),
-                    CoreMatchers.is(true));
-        }
-
-        if (!reUse) {
-            MatcherAssert.assertThat(mRecycled.contains(updatedVH[0]), CoreMatchers.is(false));
-            MatcherAssert.assertThat(mRecyclerView.mRecycler.mCachedViews.contains(updatedVH[0]),
-                    CoreMatchers.is(true));
-        }
-    }
-
-    @Test
-    public void detectStableIdError() throws Throwable {
-        setIgnoreMainThreadException(true);
-        final AtomicBoolean useBadIds = new AtomicBoolean(false);
-        TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public long getItemId(int position) {
-                if (useBadIds.get() && position == 5) {
-                    return super.getItemId(position) - 1;
-                }
-                return super.getItemId(position);
-            }
-
-            @Override
-            public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
-                // ignore validation
-            }
-        };
-        adapter.setHasStableIds(true);
-        setupBasic(10, 0, 10, adapter);
-        mLayoutManager.expectLayouts(2);
-        useBadIds.set(true);
-        adapter.changeAndNotify(4, 2);
-        mLayoutManager.waitForLayout(2);
-        assertTrue(getMainThreadException() instanceof IllegalStateException);
-        assertTrue(getMainThreadException().getMessage()
-                .contains("Two different ViewHolders have the same stable ID."));
-        // TODO don't use this after moving this class to Junit 4
-        try {
-            removeRecyclerView();
-        } catch (Throwable t){}
-    }
-
-
-    @Test
-    public void dontLayoutReusedViewWithoutPredictive() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    final TestViewHolder target) throws Throwable {
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-                    @Override
-                    void beforePreLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager lm, RecyclerView.State state) {
-                        fail("pre layout is not expected");
-                    }
-
-                    @Override
-                    void beforePostLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager layoutManager,
-                            RecyclerView.State state) {
-                        mLayoutItemCount = 7;
-                        View targetView = recycler
-                                .getViewForPosition(target.getAdapterPosition());
-                        assertSame(targetView, target.itemView);
-                        super.beforePostLayout(recycler, layoutManager, state);
-                    }
-
-                    @Override
-                    void afterPostLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager layoutManager,
-                            RecyclerView.State state) {
-                        super.afterPostLayout(recycler, layoutManager, state);
-                        assertNull("test sanity. this view should not be re-laid out in post "
-                                + "layout", target.itemView.getParent());
-                    }
-                };
-                mLayoutManager.expectLayouts(1);
-                mLayoutManager.requestSimpleAnimationsInNextLayout();
-                requestLayoutOnUIThread(mRecyclerView);
-                mLayoutManager.waitForLayout(2);
-                checkForMainThreadException();
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                // This is a LayoutManager problem if it asked for the view but didn't properly
-                // lay it out. It will move to disappearance
-                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                waitForAnimations(5);
-                assertTrue(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    @Test
-    public void dontLayoutReusedViewWithPredictive() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    final TestViewHolder target) throws Throwable {
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-                    @Override
-                    void beforePreLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager lm, RecyclerView.State state) {
-                        mLayoutItemCount = 9;
-                        super.beforePreLayout(recycler, lm, state);
-                    }
-
-                    @Override
-                    void beforePostLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager layoutManager,
-                            RecyclerView.State state) {
-                        mLayoutItemCount = 7;
-                        super.beforePostLayout(recycler, layoutManager, state);
-                    }
-
-                    @Override
-                    void afterPostLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager layoutManager,
-                            RecyclerView.State state) {
-                        super.afterPostLayout(recycler, layoutManager, state);
-                        assertNull("test sanity. this view should not be re-laid out in post "
-                                + "layout", target.itemView.getParent());
-                    }
-                };
-                mLayoutManager.expectLayouts(2);
-                mTestAdapter.deleteAndNotify(1, 1);
-                mLayoutManager.waitForLayout(2);
-                checkForMainThreadException();
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                // This is a LayoutManager problem if it asked for the view but didn't properly
-                // lay it out. It will move to disappearance.
-                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                waitForAnimations(5);
-                assertTrue(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    @Test
-    public void reuseHiddenViewWithoutPredictive() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    TestViewHolder target) throws Throwable {
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.expectLayouts(1);
-                mLayoutManager.requestSimpleAnimationsInNextLayout();
-                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
-                requestLayoutOnUIThread(mRecyclerView);
-                mLayoutManager.waitForLayout(2);
-                waitForAnimations(5);
-                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                assertFalse(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    @Test
-    public void reuseHiddenViewWithoutAnimations() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    TestViewHolder target) throws Throwable {
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.expectLayouts(1);
-                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
-                requestLayoutOnUIThread(mRecyclerView);
-                mLayoutManager.waitForLayout(2);
-                waitForAnimations(5);
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                assertFalse(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    @Test
-    public void reuseHiddenViewWithPredictive() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    TestViewHolder target) throws Throwable {
-                // it should move to change scrap and then show up from there
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.expectLayouts(2);
-                mTestAdapter.deleteAndNotify(2, 1);
-                mLayoutManager.waitForLayout(2);
-                waitForAnimations(5);
-                // This LM does not layout the additional item so it does predictive wrong.
-                // We should still handle it and animate persistence for this item
-                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                assertTrue(itemAnimator.mMoveVHs.contains(target));
-                assertFalse(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    @Test
-    public void reuseHiddenViewWithProperPredictive() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    TestViewHolder target) throws Throwable {
-                // it should move to change scrap and then show up from there
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-                    @Override
-                    void beforePreLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager lm, RecyclerView.State state) {
-                        mLayoutItemCount = 9;
-                        super.beforePreLayout(recycler, lm, state);
-                    }
-
-                    @Override
-                    void afterPreLayout(RecyclerView.Recycler recycler,
-                            AnimationLayoutManager layoutManager,
-                            RecyclerView.State state) {
-                        mLayoutItemCount = 8;
-                        super.afterPreLayout(recycler, layoutManager, state);
-                    }
-                };
-
-                mLayoutManager.expectLayouts(2);
-                mTestAdapter.deleteAndNotify(2, 1);
-                mLayoutManager.waitForLayout(2);
-                waitForAnimations(5);
-                // This LM implements predictive animations properly by requesting target view
-                // in pre-layout.
-                assertTrue(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                assertTrue(itemAnimator.mMoveVHs.contains(target));
-                assertFalse(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    // Disable this test on ICS because it causes testing devices to freeze.
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
-    @Test
-    public void dontReuseHiddenViewOnInvalidate() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    TestViewHolder target) throws Throwable {
-                // it should move to change scrap and then show up from there
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.expectLayouts(1);
-                mTestAdapter.dispatchDataSetChanged();
-                mLayoutManager.waitForLayout(2);
-                waitForAnimations(5);
-                assertFalse(mRecyclerView.getItemAnimator().isRunning());
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateChangeList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                assertTrue(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    @Test
-    public void dontReuseOnTypeChange() throws Throwable {
-        reuseHiddenViewTest(new ReuseTestCallback() {
-            @Override
-            public void postSetup(List<TestViewHolder> recycledList,
-                    TestViewHolder target) throws Throwable {
-                // it should move to change scrap and then show up from there
-                LoggingItemAnimator itemAnimator = (LoggingItemAnimator) mRecyclerView
-                        .getItemAnimator();
-                itemAnimator.reset();
-                mLayoutManager.expectLayouts(1);
-                target.mBoundItem.mType += 2;
-                mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 9;
-                mTestAdapter.changeAndNotify(target.getAdapterPosition(), 1);
-                requestLayoutOnUIThread(mRecyclerView);
-                mLayoutManager.waitForLayout(2);
-
-                assertTrue(itemAnimator.mChangeOldVHs.contains(target));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimatePersistenceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateAppearanceList));
-                assertFalse(itemAnimator.contains(target, itemAnimator.mAnimateDisappearanceList));
-                assertTrue(mRecyclerView.mChildHelper.isHidden(target.itemView));
-                assertFalse(recycledVHs.contains(target));
-                waitForAnimations(5);
-                assertTrue(recycledVHs.contains(target));
-            }
-        });
-    }
-
-    interface ReuseTestCallback {
-
-        void postSetup(List<TestViewHolder> recycledList, TestViewHolder target) throws Throwable;
-    }
-
-    @Override
-    protected RecyclerView.ItemAnimator createItemAnimator() {
-        return new LoggingItemAnimator();
-    }
-
-    public void reuseHiddenViewTest(ReuseTestCallback callback) throws Throwable {
-        TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                super.onViewRecycled(holder);
-                recycledVHs.add(holder);
-            }
-        };
-        setupBasic(10, 0, 10, adapter);
-        mRecyclerView.setItemViewCacheSize(0);
-        TestViewHolder target = (TestViewHolder) mRecyclerView.findViewHolderForAdapterPosition(9);
-        mRecyclerView.getItemAnimator().setAddDuration(1000);
-        mRecyclerView.getItemAnimator().setRemoveDuration(1000);
-        mRecyclerView.getItemAnimator().setChangeDuration(1000);
-        mRecyclerView.getItemAnimator().setMoveDuration(1000);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
-        mLayoutManager.expectLayouts(2);
-        adapter.deleteAndNotify(2, 1);
-        mLayoutManager.waitForLayout(2);
-        // test sanity, make sure target is hidden now
-        assertTrue("test sanity", mRecyclerView.mChildHelper.isHidden(target.itemView));
-        callback.postSetup(recycledVHs, target);
-        // TODO TEST ITEM INVALIDATION OR TYPE CHANGE IN BETWEEN
-        // TODO TEST ITEM IS RECEIVED FROM RECYCLER BUT NOT RE-ADDED
-        // TODO TEST ITEM ANIMATOR IS CALLED TO GET NEW INFORMATION ABOUT LOCATION
-
-    }
-
-    @Test
-    public void detachBeforeAnimations() throws Throwable {
-        setupBasic(10, 0, 5);
-        final RecyclerView rv = mRecyclerView;
-        waitForAnimations(2);
-        final DefaultItemAnimator animator = new DefaultItemAnimator() {
-            @Override
-            public void runPendingAnimations() {
-                super.runPendingAnimations();
-            }
-        };
-        rv.setItemAnimator(animator);
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(3, 4);
-        mLayoutManager.waitForLayout(2);
-        removeRecyclerView();
-        assertNull("test sanity check RV should be removed", rv.getParent());
-        assertEquals("no views should be hidden", 0, rv.mChildHelper.mHiddenViews.size());
-        assertFalse("there should not be any animations running", animator.isRunning());
-    }
-
-    @Test
-    public void moveDeleted() throws Throwable {
-        setupBasic(4, 0, 3);
-        waitForAnimations(2);
-        final View[] targetChild = new View[1];
-        final LoggingItemAnimator animator = new LoggingItemAnimator();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setItemAnimator(animator);
-                targetChild[0] = mRecyclerView.getChildAt(1);
-            }
-        });
-
-        assertNotNull("test sanity", targetChild);
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
-                    @Override
-                    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                            RecyclerView.State state) {
-                        if (view == targetChild[0]) {
-                            outRect.set(10, 20, 30, 40);
-                        } else {
-                            outRect.set(0, 0, 0, 0);
-                        }
-                    }
-                });
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-
-        // now delete that item.
-        mLayoutManager.expectLayouts(2);
-        RecyclerView.ViewHolder targetVH = mRecyclerView.getChildViewHolder(targetChild[0]);
-        targetChild[0] = null;
-        mTestAdapter.deleteAndNotify(1, 1);
-        mLayoutManager.waitForLayout(2);
-        assertFalse("if deleted view moves, it should not be in move animations",
-                animator.mMoveVHs.contains(targetVH));
-        assertEquals("only 1 item is deleted", 1, animator.mRemoveVHs.size());
-        assertTrue("the target view is removed", animator.mRemoveVHs.contains(targetVH
-        ));
-    }
-
-    private void runTestImportantForAccessibilityWhileDeteling(
-            final int boundImportantForAccessibility,
-            final int expectedImportantForAccessibility) throws Throwable {
-        // Adapter binding the item to the initial accessibility option.
-        // RecyclerView is expected to change it to 'expectedImportantForAccessibility'.
-        TestAdapter adapter = new TestAdapter(1) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder, int position) {
-                super.onBindViewHolder(holder, position);
-                ViewCompat.setImportantForAccessibility(
-                        holder.itemView, boundImportantForAccessibility);
-            }
-        };
-
-        // Set up with 1 item.
-        setupBasic(1, 0, 1, adapter);
-        waitForAnimations(2);
-        final View[] targetChild = new View[1];
-        final LoggingItemAnimator animator = new LoggingItemAnimator();
-        animator.setRemoveDuration(500);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setItemAnimator(animator);
-                targetChild[0] = mRecyclerView.getChildAt(0);
-                assertEquals(
-                        expectedImportantForAccessibility,
-                        ViewCompat.getImportantForAccessibility(targetChild[0]));
-            }
-        });
-
-        assertNotNull("test sanity", targetChild[0]);
-
-        // now delete that item.
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(0, 1);
-
-        mLayoutManager.waitForLayout(2);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // The view is still a child of mRecyclerView, and is invisible for accessibility.
-                assertTrue(targetChild[0].getParent() == mRecyclerView);
-                assertEquals(
-                        ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
-                        ViewCompat.getImportantForAccessibility(targetChild[0]));
-            }
-        });
-
-        waitForAnimations(2);
-
-        // Delete animation is now complete.
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // The view is in recycled state, and back to the expected accessibility.
-                assertTrue(targetChild[0].getParent() == null);
-                assertEquals(
-                        expectedImportantForAccessibility,
-                        ViewCompat.getImportantForAccessibility(targetChild[0]));
-            }
-        });
-
-        // Add 1 element, which should use same view.
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.addAndNotify(1);
-        mLayoutManager.waitForLayout(2);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // The view should be reused, and have the expected accessibility.
-                assertTrue(
-                        "the item must be reused", targetChild[0] == mRecyclerView.getChildAt(0));
-                assertEquals(
-                        expectedImportantForAccessibility,
-                        ViewCompat.getImportantForAccessibility(targetChild[0]));
-            }
-        });
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
-    public void importantForAccessibilityWhileDetelingAuto() throws Throwable {
-        runTestImportantForAccessibilityWhileDeteling(
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
-    public void importantForAccessibilityWhileDetelingNo() throws Throwable {
-        runTestImportantForAccessibilityWhileDeteling(
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
-    public void importantForAccessibilityWhileDetelingNoHideDescandants() throws Throwable {
-        runTestImportantForAccessibilityWhileDeteling(
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
-    }
-
-    @Test
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
-    public void importantForAccessibilityWhileDetelingYes() throws Throwable {
-        runTestImportantForAccessibilityWhileDeteling(
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES,
-                ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
-    }
-
-    @Test
-    public void preLayoutPositionCleanup() throws Throwable {
-        setupBasic(4, 0, 4);
-        mLayoutManager.expectLayouts(2);
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void beforePreLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager lm, RecyclerView.State state) {
-                mLayoutMin = 0;
-                mLayoutItemCount = 3;
-            }
-
-            @Override
-            void beforePostLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager layoutManager,
-                    RecyclerView.State state) {
-                mLayoutMin = 0;
-                mLayoutItemCount = 4;
-            }
-        };
-        mTestAdapter.addAndNotify(0, 1);
-        mLayoutManager.waitForLayout(2);
-
-
-    }
-
-    @Test
-    public void addRemoveSamePass() throws Throwable {
-        final List<RecyclerView.ViewHolder> mRecycledViews
-                = new ArrayList<RecyclerView.ViewHolder>();
-        TestAdapter adapter = new TestAdapter(50) {
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                super.onViewRecycled(holder);
-                mRecycledViews.add(holder);
-            }
-        };
-        adapter.setHasStableIds(true);
-        setupBasic(50, 3, 5, adapter);
-        mRecyclerView.setItemViewCacheSize(0);
-        final ArrayList<RecyclerView.ViewHolder> addVH
-                = new ArrayList<RecyclerView.ViewHolder>();
-        final ArrayList<RecyclerView.ViewHolder> removeVH
-                = new ArrayList<RecyclerView.ViewHolder>();
-
-        final ArrayList<RecyclerView.ViewHolder> moveVH
-                = new ArrayList<RecyclerView.ViewHolder>();
-
-        final View[] testView = new View[1];
-        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
-            @Override
-            public boolean animateAdd(RecyclerView.ViewHolder holder) {
-                addVH.add(holder);
-                return true;
-            }
-
-            @Override
-            public boolean animateRemove(RecyclerView.ViewHolder holder) {
-                removeVH.add(holder);
-                return true;
-            }
-
-            @Override
-            public boolean animateMove(RecyclerView.ViewHolder holder, int fromX, int fromY,
-                    int toX, int toY) {
-                moveVH.add(holder);
-                return true;
-            }
-        });
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void afterPreLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager layoutManager,
-                    RecyclerView.State state) {
-                super.afterPreLayout(recycler, layoutManager, state);
-                testView[0] = recycler.getViewForPosition(45);
-                testView[0].measure(View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST),
-                        View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.AT_MOST));
-                testView[0].layout(10, 10, 10 + testView[0].getMeasuredWidth(),
-                        10 + testView[0].getMeasuredHeight());
-                layoutManager.addView(testView[0], 4);
-            }
-
-            @Override
-            void afterPostLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager layoutManager,
-                    RecyclerView.State state) {
-                super.afterPostLayout(recycler, layoutManager, state);
-                testView[0].layout(50, 50, 50 + testView[0].getMeasuredWidth(),
-                        50 + testView[0].getMeasuredHeight());
-                layoutManager.addDisappearingView(testView[0], 4);
-            }
-        };
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 3;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 5;
-        mRecycledViews.clear();
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(3, 1);
-        mLayoutManager.waitForLayout(2);
-
-        for (RecyclerView.ViewHolder vh : addVH) {
-            assertNotSame("add-remove item should not animate add", testView[0], vh.itemView);
-        }
-        for (RecyclerView.ViewHolder vh : moveVH) {
-            assertNotSame("add-remove item should not animate move", testView[0], vh.itemView);
-        }
-        for (RecyclerView.ViewHolder vh : removeVH) {
-            assertNotSame("add-remove item should not animate remove", testView[0], vh.itemView);
-        }
-        boolean found = false;
-        for (RecyclerView.ViewHolder vh : mRecycledViews) {
-            found |= vh.itemView == testView[0];
-        }
-        assertTrue("added-removed view should be recycled", found);
-    }
-
-    @Test
-    public void tmpRemoveMe() throws Throwable {
-        changeAnimTest(false, false, true, false);
-    }
-
-    @Test
-    public void changeAnimations() throws Throwable {
-        final boolean[] booleans = {true, false};
-        for (boolean supportsChange : booleans) {
-            for (boolean changeType : booleans) {
-                for (boolean hasStableIds : booleans) {
-                    for (boolean deleteSomeItems : booleans) {
-                        changeAnimTest(supportsChange, changeType, hasStableIds, deleteSomeItems);
-                    }
-                    removeRecyclerView();
-                }
-            }
-        }
-    }
-
-    public void changeAnimTest(final boolean supportsChangeAnim, final boolean changeType,
-            final boolean hasStableIds, final boolean deleteSomeItems) throws Throwable {
-        final int changedIndex = 3;
-        final int defaultType = 1;
-        final AtomicInteger changedIndexNewType = new AtomicInteger(defaultType);
-        final String logPrefix = "supportsChangeAnim:" + supportsChangeAnim +
-                ", change view type:" + changeType +
-                ", has stable ids:" + hasStableIds +
-                ", delete some items:" + deleteSomeItems;
-        TestAdapter testAdapter = new TestAdapter(10) {
-            @Override
-            public int getItemViewType(int position) {
-                return position == changedIndex ? changedIndexNewType.get() : defaultType;
-            }
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
-                if (DEBUG) {
-                    Log.d(TAG, logPrefix + " onCreateVH" + vh.toString());
-                }
-                return vh;
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (DEBUG) {
-                    Log.d(TAG, logPrefix + " onBind to " + position + "" + holder.toString());
-                }
-            }
-        };
-        testAdapter.setHasStableIds(hasStableIds);
-        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
-        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
-                supportsChangeAnim);
-
-        final RecyclerView.ViewHolder toBeChangedVH =
-                mRecyclerView.findViewHolderForLayoutPosition(changedIndex);
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void afterPreLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager layoutManager,
-                    RecyclerView.State state) {
-                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
-                        changedIndex);
-                assertTrue(logPrefix + " changed view holder should have correct flag"
-                        , vh.isUpdated());
-            }
-
-            @Override
-            void afterPostLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager layoutManager, RecyclerView.State state) {
-                RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForLayoutPosition(
-                        changedIndex);
-                if (supportsChangeAnim) {
-                    assertNotSame(logPrefix + "a new VH should be given if change is supported",
-                            toBeChangedVH, vh);
-                } else if (!changeType && hasStableIds) {
-                    assertSame(logPrefix + "if change animations are not supported but we have "
-                            + "stable ids, same view holder should be returned", toBeChangedVH, vh);
-                }
-                super.beforePostLayout(recycler, layoutManager, state);
-            }
-        };
-        mLayoutManager.expectLayouts(1);
-        if (changeType) {
-            changedIndexNewType.set(defaultType + 1);
-        }
-        if (deleteSomeItems) {
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    try {
-                        mTestAdapter.deleteAndNotify(changedIndex + 2, 1);
-                        mTestAdapter.notifyItemChanged(3);
-                    } catch (Throwable throwable) {
-                        throwable.printStackTrace();
-                    }
-
-                }
-            });
-        } else {
-            mTestAdapter.changeAndNotify(3, 1);
-        }
-
-        mLayoutManager.waitForLayout(2);
-    }
-
-    private void testChangeWithPayload(final boolean supportsChangeAnim,
-            final boolean canReUse, Object[][] notifyPayloads, Object[][] expectedPayloadsInOnBind)
-            throws Throwable {
-        final List<Object> expectedPayloads = new ArrayList<Object>();
-        final int changedIndex = 3;
-        TestAdapter testAdapter = new TestAdapter(10) {
-            @Override
-            public int getItemViewType(int position) {
-                return 1;
-            }
-
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                TestViewHolder vh = super.onCreateViewHolder(parent, viewType);
-                if (DEBUG) {
-                    Log.d(TAG, " onCreateVH" + vh.toString());
-                }
-                return vh;
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position, List<Object> payloads) {
-                super.onBindViewHolder(holder, position);
-                if (DEBUG) {
-                    Log.d(TAG, " onBind to " + position + "" + holder.toString());
-                }
-                assertEquals(expectedPayloads, payloads);
-            }
-        };
-        testAdapter.setHasStableIds(false);
-        setupBasic(testAdapter.getItemCount(), 0, 10, testAdapter);
-        mRecyclerView.setItemAnimator(new DefaultItemAnimator() {
-            @Override
-            public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder,
-                    @NonNull List<Object> payloads) {
-                return canReUse && super.canReuseUpdatedViewHolder(viewHolder, payloads);
-            }
-        });
-        ((SimpleItemAnimator) mRecyclerView.getItemAnimator()).setSupportsChangeAnimations(
-                supportsChangeAnim);
-
-        int numTests = notifyPayloads.length;
-        for (int i = 0; i < numTests; i++) {
-            mLayoutManager.expectLayouts(1);
-            expectedPayloads.clear();
-            for (int j = 0; j < expectedPayloadsInOnBind[i].length; j++) {
-                expectedPayloads.add(expectedPayloadsInOnBind[i][j]);
-            }
-            final Object[] payloadsToSend = notifyPayloads[i];
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    for (int j = 0; j < payloadsToSend.length; j++) {
-                        mTestAdapter.notifyItemChanged(changedIndex, payloadsToSend[j]);
-                    }
-                }
-            });
-            mLayoutManager.waitForLayout(2);
-            checkForMainThreadException();
-        }
-    }
-
-    @Test
-    public void crossFadingChangeAnimationWithPayload() throws Throwable {
-        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
-        testChangeWithPayload(true, true,
-                new Object[][]{
-                        new Object[]{"abc"},
-                        new Object[]{"abc", null, "cdf"},
-                        new Object[]{"abc", null},
-                        new Object[]{null, "abc"},
-                        new Object[]{"abc", "cdf"}
-                },
-                new Object[][]{
-                        new Object[]{"abc"},
-                        new Object[0],
-                        new Object[0],
-                        new Object[0],
-                        new Object[]{"abc", "cdf"}
-                });
-    }
-
-    @Test
-    public void crossFadingChangeAnimationWithPayloadWithoutReuse() throws Throwable {
-        // for crossfading change animation,  will receive EMPTY payload in onBindViewHolder
-        testChangeWithPayload(true, false,
-                new Object[][]{
-                        new Object[]{"abc"},
-                        new Object[]{"abc", null, "cdf"},
-                        new Object[]{"abc", null},
-                        new Object[]{null, "abc"},
-                        new Object[]{"abc", "cdf"}
-                },
-                new Object[][]{
-                        new Object[0],
-                        new Object[0],
-                        new Object[0],
-                        new Object[0],
-                        new Object[0]
-                });
-    }
-
-    @Test
-    public void noChangeAnimationWithPayload() throws Throwable {
-        // for Change Animation disabled, payload should match the payloads unless
-        // null payload is fired.
-        testChangeWithPayload(false, true,
-                new Object[][]{
-                        new Object[]{"abc"},
-                        new Object[]{"abc", null, "cdf"},
-                        new Object[]{"abc", null},
-                        new Object[]{null, "abc"},
-                        new Object[]{"abc", "cdf"}
-                },
-                new Object[][]{
-                        new Object[]{"abc"},
-                        new Object[0],
-                        new Object[0],
-                        new Object[0],
-                        new Object[]{"abc", "cdf"}
-                });
-    }
-
-    @Test
-    public void recycleDuringAnimations() throws Throwable {
-        final AtomicInteger childCount = new AtomicInteger(0);
-        final TestAdapter adapter = new TestAdapter(1000) {
-            @Override
-            public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                childCount.incrementAndGet();
-                return super.onCreateViewHolder(parent, viewType);
-            }
-        };
-        setupBasic(1000, 10, 20, adapter);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 10;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 20;
-
-        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
-            @Override
-            public void putRecycledView(RecyclerView.ViewHolder scrap) {
-                super.putRecycledView(scrap);
-                childCount.decrementAndGet();
-            }
-
-            @Override
-            public RecyclerView.ViewHolder getRecycledView(int viewType) {
-                final RecyclerView.ViewHolder recycledView = super.getRecycledView(viewType);
-                if (recycledView != null) {
-                    childCount.incrementAndGet();
-                }
-                return recycledView;
-            }
-        });
-
-        // now keep adding children to trigger more children being created etc.
-        for (int i = 0; i < 100; i++) {
-            adapter.addAndNotify(15, 1);
-            Thread.sleep(50);
-        }
-        getInstrumentation().waitForIdleSync();
-        waitForAnimations(2);
-        assertEquals("Children count should add up", childCount.get(),
-                mRecyclerView.getChildCount() + mRecyclerView.mRecycler.mCachedViews.size());
-    }
-
-    @Test
-    public void notifyDataSetChanged() throws Throwable {
-        setupBasic(10, 3, 4);
-        int layoutCount = mLayoutManager.mTotalLayoutCount;
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mTestAdapter.deleteAndNotify(4, 1);
-                    mTestAdapter.dispatchDataSetChanged();
-                } catch (Throwable throwable) {
-                    throwable.printStackTrace();
-                }
-
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        getInstrumentation().waitForIdleSync();
-        assertEquals("on notify data set changed, predictive animations should not run",
-                layoutCount + 1, mLayoutManager.mTotalLayoutCount);
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.addAndNotify(4, 2);
-        // make sure animations recover
-        mLayoutManager.waitForLayout(2);
-    }
-
-    @Test
-    public void stableIdNotifyDataSetChanged() throws Throwable {
-        final int itemCount = 20;
-        List<Item> initialSet = new ArrayList<Item>();
-        final TestAdapter adapter = new TestAdapter(itemCount) {
-            @Override
-            public long getItemId(int position) {
-                return mItems.get(position).mId;
-            }
-        };
-        adapter.setHasStableIds(true);
-        initialSet.addAll(adapter.mItems);
-        positionStatesTest(itemCount, 5, 5, adapter, new AdapterOps() {
-                    @Override
-                    void onRun(TestAdapter testAdapter) throws Throwable {
-                        Item item5 = adapter.mItems.get(5);
-                        Item item6 = adapter.mItems.get(6);
-                        item5.mAdapterIndex = 6;
-                        item6.mAdapterIndex = 5;
-                        adapter.mItems.remove(5);
-                        adapter.mItems.add(6, item5);
-                        adapter.dispatchDataSetChanged();
-                        //hacky, we support only 1 layout pass
-                        mLayoutManager.layoutLatch.countDown();
-                    }
-                }, PositionConstraint.scrap(6, -1, 5), PositionConstraint.scrap(5, -1, 6),
-                PositionConstraint.scrap(7, -1, 7), PositionConstraint.scrap(8, -1, 8),
-                PositionConstraint.scrap(9, -1, 9));
-        // now mix items.
-    }
-
-
-    @Test
-    public void getItemForDeletedView() throws Throwable {
-        getItemForDeletedViewTest(false);
-        getItemForDeletedViewTest(true);
-    }
-
-    public void getItemForDeletedViewTest(boolean stableIds) throws Throwable {
-        final Set<Integer> itemViewTypeQueries = new HashSet<Integer>();
-        final Set<Integer> itemIdQueries = new HashSet<Integer>();
-        TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public int getItemViewType(int position) {
-                itemViewTypeQueries.add(position);
-                return super.getItemViewType(position);
-            }
-
-            @Override
-            public long getItemId(int position) {
-                itemIdQueries.add(position);
-                return mItems.get(position).mId;
-            }
-        };
-        adapter.setHasStableIds(stableIds);
-        setupBasic(10, 0, 10, adapter);
-        assertEquals("getItemViewType for all items should be called", 10,
-                itemViewTypeQueries.size());
-        if (adapter.hasStableIds()) {
-            assertEquals("getItemId should be called when adapter has stable ids", 10,
-                    itemIdQueries.size());
-        } else {
-            assertEquals("getItemId should not be called when adapter does not have stable ids", 0,
-                    itemIdQueries.size());
-        }
-        itemViewTypeQueries.clear();
-        itemIdQueries.clear();
-        mLayoutManager.expectLayouts(2);
-        // delete last two
-        final int deleteStart = 8;
-        final int deleteCount = adapter.getItemCount() - deleteStart;
-        adapter.deleteAndNotify(deleteStart, deleteCount);
-        mLayoutManager.waitForLayout(2);
-        for (int i = 0; i < deleteStart; i++) {
-            assertTrue("getItemViewType for existing item " + i + " should be called",
-                    itemViewTypeQueries.contains(i));
-            if (adapter.hasStableIds()) {
-                assertTrue("getItemId for existing item " + i
-                                + " should be called when adapter has stable ids",
-                        itemIdQueries.contains(i));
-            }
-        }
-        for (int i = deleteStart; i < deleteStart + deleteCount; i++) {
-            assertFalse("getItemViewType for deleted item " + i + " SHOULD NOT be called",
-                    itemViewTypeQueries.contains(i));
-            if (adapter.hasStableIds()) {
-                assertFalse("getItemId for deleted item " + i + " SHOULD NOT be called",
-                        itemIdQueries.contains(i));
-            }
-        }
-    }
-
-    @Test
-    public void deleteInvisibleMultiStep() throws Throwable {
-        setupBasic(1000, 1, 7);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
-        mLayoutManager.expectLayouts(1);
-        // try to trigger race conditions
-        int targetItemCount = mTestAdapter.getItemCount();
-        for (int i = 0; i < 100; i++) {
-            mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});
-            checkForMainThreadException();
-            targetItemCount -= 2;
-        }
-        // wait until main thread runnables are consumed
-        while (targetItemCount != mTestAdapter.getItemCount()) {
-            Thread.sleep(100);
-        }
-        mLayoutManager.waitForLayout(2);
-    }
-
-    @Test
-    public void addManyMultiStep() throws Throwable {
-        setupBasic(10, 1, 7);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
-        mLayoutManager.expectLayouts(1);
-        // try to trigger race conditions
-        int targetItemCount = mTestAdapter.getItemCount();
-        for (int i = 0; i < 100; i++) {
-            checkForMainThreadException();
-            mTestAdapter.addAndNotify(0, 1);
-            checkForMainThreadException();
-            mTestAdapter.addAndNotify(7, 1);
-            targetItemCount += 2;
-        }
-        checkForMainThreadException();
-        // wait until main thread runnables are consumed
-        while (targetItemCount != mTestAdapter.getItemCount()) {
-            Thread.sleep(100);
-            checkForMainThreadException();
-        }
-        mLayoutManager.waitForLayout(2);
-    }
-
-    @Test
-    public void basicDelete() throws Throwable {
-        setupBasic(10);
-        final OnLayoutCallbacks callbacks = new OnLayoutCallbacks() {
-            @Override
-            public void postDispatchLayout() {
-                // verify this only in first layout
-                assertEquals("deleted views should still be children of RV",
-                        mLayoutManager.getChildCount() + mDeletedViewCount
-                        , mRecyclerView.getChildCount());
-            }
-
-            @Override
-            void afterPreLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager layoutManager,
-                    RecyclerView.State state) {
-                super.afterPreLayout(recycler, layoutManager, state);
-                mLayoutItemCount = 3;
-                mLayoutMin = 0;
-            }
-        };
-        callbacks.mLayoutItemCount = 10;
-        callbacks.setExpectedItemCounts(10, 3);
-        mLayoutManager.setOnLayoutCallbacks(callbacks);
-
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(0, 7);
-        mLayoutManager.waitForLayout(2);
-        callbacks.reset();// when animations end another layout will happen
-    }
-
-
-    @Test
-    public void adapterChangeDuringScrolling() throws Throwable {
-        setupBasic(10);
-        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
-        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
-
-        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
-            @Override
-            void onLayoutChildren(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager lm, RecyclerView.State state) {
-                onLayoutItemCount.set(state.getItemCount());
-                super.onLayoutChildren(recycler, lm, state);
-            }
-
-            @Override
-            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
-                onScrollItemCount.set(state.getItemCount());
-                super.onScroll(dx, recycler, state);
-            }
-        });
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTestAdapter.mItems.remove(5);
-                mTestAdapter.notifyItemRangeRemoved(5, 1);
-                mRecyclerView.scrollBy(0, 100);
-                assertTrue("scrolling while there are pending adapter updates should "
-                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
-                assertEquals("scroll by should be called w/ updated adapter count",
-                        mTestAdapter.mItems.size(), onScrollItemCount.get());
-
-            }
-        });
-    }
-
-    @Test
-    public void notifyDataSetChangedDuringScroll() throws Throwable {
-        setupBasic(10);
-        final AtomicInteger onLayoutItemCount = new AtomicInteger(0);
-        final AtomicInteger onScrollItemCount = new AtomicInteger(0);
-
-        mLayoutManager.setOnLayoutCallbacks(new OnLayoutCallbacks() {
-            @Override
-            void onLayoutChildren(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager lm, RecyclerView.State state) {
-                onLayoutItemCount.set(state.getItemCount());
-                super.onLayoutChildren(recycler, lm, state);
-            }
-
-            @Override
-            public void onScroll(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
-                onScrollItemCount.set(state.getItemCount());
-                super.onScroll(dx, recycler, state);
-            }
-        });
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTestAdapter.mItems.remove(5);
-                mTestAdapter.notifyDataSetChanged();
-                mRecyclerView.scrollBy(0, 100);
-                assertTrue("scrolling while there are pending adapter updates should "
-                        + "trigger a layout", mLayoutManager.mOnLayoutCallbacks.mLayoutCount > 0);
-                assertEquals("scroll by should be called w/ updated adapter count",
-                        mTestAdapter.mItems.size(), onScrollItemCount.get());
-
-            }
-        });
-    }
-
-    @Test
-    public void addInvisibleAndVisible() throws Throwable {
-        setupBasic(10, 1, 7);
-        mLayoutManager.expectLayouts(2);
-        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
-        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{7, 1});// add a new item 0 // invisible
-        mLayoutManager.waitForLayout(2);
-    }
-
-    @Test
-    public void addInvisible() throws Throwable {
-        setupBasic(10, 1, 7);
-        mLayoutManager.expectLayouts(1);
-        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(10, 12);
-        mTestAdapter.addAndNotify(new int[]{0, 1}, new int[]{8, 1});// add a new item 0
-        mLayoutManager.waitForLayout(2);
-    }
-
-    @Test
-    public void basicAdd() throws Throwable {
-        setupBasic(10);
-        mLayoutManager.expectLayouts(2);
-        setExpectedItemCounts(10, 13);
-        mTestAdapter.addAndNotify(2, 3);
-        mLayoutManager.waitForLayout(2);
-    }
-
-    // Run this test on Jelly Bean and newer because hasTransientState was introduced in API 16.
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
-    @Test
-    public void appCancelAnimationInDetach() throws Throwable {
-        final View[] addedView = new View[2];
-        TestAdapter adapter = new TestAdapter(1) {
-            @Override
-            public void onViewDetachedFromWindow(TestViewHolder holder) {
-                if ((addedView[0] == holder.itemView || addedView[1] == holder.itemView)
-                        && ViewCompat.hasTransientState(holder.itemView)) {
-                    holder.itemView.animate().cancel();
-                }
-                super.onViewDetachedFromWindow(holder);
-            }
-        };
-        // original 1 item
-        setupBasic(1, 0, 1, adapter);
-        mRecyclerView.getItemAnimator().setAddDuration(10000);
-        mLayoutManager.expectLayouts(2);
-        // add 2 items
-        setExpectedItemCounts(1, 3);
-        mTestAdapter.addAndNotify(0, 2);
-        mLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        // wait till "add animation" starts
-        int limit = 200;
-        while (addedView[0] == null || addedView[1] == null) {
-            Thread.sleep(100);
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    if (mRecyclerView.getChildCount() == 3) {
-                        View view = mRecyclerView.getChildAt(0);
-                        if (ViewCompat.hasTransientState(view)) {
-                            addedView[0] = view;
-                        }
-                        view = mRecyclerView.getChildAt(1);
-                        if (ViewCompat.hasTransientState(view)) {
-                            addedView[1] = view;
-                        }
-                    }
-                }
-            });
-            assertTrue("add should start on time", --limit > 0);
-        }
-
-        // Layout from item2, exclude the current adding items
-        mLayoutManager.expectLayouts(1);
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void beforePostLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager layoutManager,
-                    RecyclerView.State state) {
-                mLayoutMin = 2;
-                mLayoutItemCount = 1;
-            }
-        };
-        requestLayoutOnUIThread(mRecyclerView);
-        mLayoutManager.waitForLayout(2);
-    }
-
-    @Test
-    public void adapterChangeFrozen() throws Throwable {
-        setupBasic(10, 1, 7);
-        assertTrue(mRecyclerView.getChildCount() == 7);
-
-        mLayoutManager.expectLayouts(2);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 8;
-        freezeLayout(true);
-        mTestAdapter.addAndNotify(0, 1);
-
-        mLayoutManager.assertNoLayout("RV should keep old child during frozen", 2);
-        assertEquals(7, mRecyclerView.getChildCount());
-
-        freezeLayout(false);
-        mLayoutManager.waitForLayout(2);
-        assertEquals("RV should get updated after waken from frozen",
-                8, mRecyclerView.getChildCount());
-    }
-
-    @Test
-    public void removeScrapInvalidate() throws Throwable {
-        setupBasic(10);
-        TestRecyclerView testRecyclerView = getTestRecyclerView();
-        mLayoutManager.expectLayouts(1);
-        testRecyclerView.expectDraw(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mTestAdapter.mItems.clear();
-                mTestAdapter.notifyDataSetChanged();
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        testRecyclerView.waitForDraw(2);
-    }
-
-    @Test
-    public void deleteVisibleAndInvisible() throws Throwable {
-        setupBasic(11, 3, 5); //layout items  3 4 5 6 7
-        mLayoutManager.expectLayouts(2);
-        setLayoutRange(3, 5); //layout previously invisible child 10 from end of the list
-        setExpectedItemCounts(9, 8);
-        mTestAdapter.deleteAndNotify(new int[]{4, 1}, new int[]{7, 2});// delete items 4, 8, 9
-        mLayoutManager.waitForLayout(2);
-    }
-
-    @Test
-    public void findPositionOffset() throws Throwable {
-        setupBasic(10);
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void beforePreLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager lm, RecyclerView.State state) {
-                super.beforePreLayout(recycler, lm, state);
-                // [0,2,4]
-                assertEquals("offset check", 0, mAdapterHelper.findPositionOffset(0));
-                assertEquals("offset check", 1, mAdapterHelper.findPositionOffset(2));
-                assertEquals("offset check", 2, mAdapterHelper.findPositionOffset(4));
-            }
-        };
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    // delete 1
-                    mTestAdapter.deleteAndNotify(1, 1);
-                    // delete 3
-                    mTestAdapter.deleteAndNotify(2, 1);
-                } catch (Throwable throwable) {
-                    throwable.printStackTrace();
-                }
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-    }
-
-    private void setLayoutRange(int start, int count) {
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = start;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = count;
-    }
-
-    private void setExpectedItemCounts(int preLayout, int postLayout) {
-        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(preLayout, postLayout);
-    }
-
-    @Test
-    public void deleteInvisible() throws Throwable {
-        setupBasic(10, 1, 7);
-        mLayoutManager.mOnLayoutCallbacks.mLayoutMin = 1;
-        mLayoutManager.mOnLayoutCallbacks.mLayoutItemCount = 7;
-        mLayoutManager.expectLayouts(1);
-        mLayoutManager.mOnLayoutCallbacks.setExpectedItemCounts(8, 8);
-        mTestAdapter.deleteAndNotify(new int[]{0, 1}, new int[]{7, 1});// delete item id 0,8
-        mLayoutManager.waitForLayout(2);
-    }
-
-    private CollectPositionResult findByPos(RecyclerView recyclerView,
-            RecyclerView.Recycler recycler, RecyclerView.State state, int position) {
-        View view = recycler.getViewForPosition(position, true);
-        RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
-        if (vh.wasReturnedFromScrap()) {
-            vh.clearReturnedFromScrapFlag(); //keep data consistent.
-            return CollectPositionResult.fromScrap(vh);
-        } else {
-            return CollectPositionResult.fromAdapter(vh);
-        }
-    }
-
-    public Map<Integer, CollectPositionResult> collectPositions(RecyclerView recyclerView,
-            RecyclerView.Recycler recycler, RecyclerView.State state, int... positions) {
-        Map<Integer, CollectPositionResult> positionToAdapterMapping
-                = new HashMap<Integer, CollectPositionResult>();
-        for (int position : positions) {
-            if (position < 0) {
-                continue;
-            }
-            positionToAdapterMapping.put(position,
-                    findByPos(recyclerView, recycler, state, position));
-        }
-        return positionToAdapterMapping;
-    }
-
-    @Test
-    public void addDelete2() throws Throwable {
-        positionStatesTest(5, 0, 5, new AdapterOps() {
-                    // 0 1 2 3 4
-                    // 0 1 2 a b 3 4
-                    // 0 1 b 3 4
-                    // pre: 0 1 2 3 4
-                    // pre w/ adap: 0 1 2 b 3 4
-                    @Override
-                    void onRun(TestAdapter adapter) throws Throwable {
-                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{2, -2});
-                    }
-                }, PositionConstraint.scrap(2, 2, -1), PositionConstraint.scrap(1, 1, 1),
-                PositionConstraint.scrap(3, 3, 3)
-        );
-    }
-
-    @Test
-    public void addDelete1() throws Throwable {
-        positionStatesTest(5, 0, 5, new AdapterOps() {
-                    // 0 1 2 3 4
-                    // 0 1 2 a b 3 4
-                    // 0 2 a b 3 4
-                    // 0 c d 2 a b 3 4
-                    // 0 c d 2 a 4
-                    // c d 2 a 4
-                    // pre: 0 1 2 3 4
-                    @Override
-                    void onRun(TestAdapter adapter) throws Throwable {
-                        adapter.addDeleteAndNotify(new int[]{3, 2}, new int[]{1, -1},
-                                new int[]{1, 2}, new int[]{5, -2}, new int[]{0, -1});
-                    }
-                }, PositionConstraint.scrap(0, 0, -1), PositionConstraint.scrap(1, 1, -1),
-                PositionConstraint.scrap(2, 2, 2), PositionConstraint.scrap(3, 3, -1),
-                PositionConstraint.scrap(4, 4, 4), PositionConstraint.adapter(0),
-                PositionConstraint.adapter(1), PositionConstraint.adapter(3)
-        );
-    }
-
-    @Test
-    public void addSameIndexTwice() throws Throwable {
-        positionStatesTest(12, 2, 7, new AdapterOps() {
-                    @Override
-                    void onRun(TestAdapter adapter) throws Throwable {
-                        adapter.addAndNotify(new int[]{1, 2}, new int[]{5, 1}, new int[]{5, 1},
-                                new int[]{11, 1});
-                    }
-                }, PositionConstraint.adapterScrap(0, 0), PositionConstraint.adapterScrap(1, 3),
-                PositionConstraint.scrap(2, 2, 4), PositionConstraint.scrap(3, 3, 7),
-                PositionConstraint.scrap(4, 4, 8), PositionConstraint.scrap(7, 7, 12),
-                PositionConstraint.scrap(8, 8, 13)
-        );
-    }
-
-    @Test
-    public void deleteTwice() throws Throwable {
-        positionStatesTest(12, 2, 7, new AdapterOps() {
-                    @Override
-                    void onRun(TestAdapter adapter) throws Throwable {
-                        adapter.deleteAndNotify(new int[]{0, 1}, new int[]{1, 1}, new int[]{7, 1},
-                                new int[]{0, 1});// delete item ids 0,2,9,1
-                    }
-                }, PositionConstraint.scrap(2, 0, -1), PositionConstraint.scrap(3, 1, 0),
-                PositionConstraint.scrap(4, 2, 1), PositionConstraint.scrap(5, 3, 2),
-                PositionConstraint.scrap(6, 4, 3), PositionConstraint.scrap(8, 6, 5),
-                PositionConstraint.adapterScrap(7, 6), PositionConstraint.adapterScrap(8, 7)
-        );
-    }
-
-
-    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
-            int firstLayoutItemCount, AdapterOps adapterChanges,
-            final PositionConstraint... constraints) throws Throwable {
-        positionStatesTest(itemCount, firstLayoutStartIndex, firstLayoutItemCount, null,
-                adapterChanges, constraints);
-    }
-
-    public void positionStatesTest(int itemCount, int firstLayoutStartIndex,
-            int firstLayoutItemCount, TestAdapter adapter, AdapterOps adapterChanges,
-            final PositionConstraint... constraints) throws Throwable {
-        setupBasic(itemCount, firstLayoutStartIndex, firstLayoutItemCount, adapter);
-        mLayoutManager.expectLayouts(2);
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void beforePreLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
-                    RecyclerView.State state) {
-                super.beforePreLayout(recycler, lm, state);
-                //harmless
-                lm.detachAndScrapAttachedViews(recycler);
-                final int[] ids = new int[constraints.length];
-                for (int i = 0; i < constraints.length; i++) {
-                    ids[i] = constraints[i].mPreLayoutPos;
-                }
-                Map<Integer, CollectPositionResult> positions
-                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
-                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
-                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
-                    positionLog.append(entry.getKey()).append(":").append(entry.getValue())
-                            .append("\n");
-                }
-                for (PositionConstraint constraint : constraints) {
-                    if (constraint.mPreLayoutPos != -1) {
-                        constraint.validate(state, positions.get(constraint.mPreLayoutPos),
-                                lm.getLog() + positionLog);
-                    }
-                }
-            }
-
-            @Override
-            void beforePostLayout(RecyclerView.Recycler recycler, AnimationLayoutManager lm,
-                    RecyclerView.State state) {
-                super.beforePostLayout(recycler, lm, state);
-                lm.detachAndScrapAttachedViews(recycler);
-                final int[] ids = new int[constraints.length];
-                for (int i = 0; i < constraints.length; i++) {
-                    ids[i] = constraints[i].mPostLayoutPos;
-                }
-                Map<Integer, CollectPositionResult> positions
-                        = collectPositions(lm.mRecyclerView, recycler, state, ids);
-                StringBuilder positionLog = new StringBuilder("\nPosition logs:\n");
-                for (Map.Entry<Integer, CollectPositionResult> entry : positions.entrySet()) {
-                    positionLog.append(entry.getKey()).append(":")
-                            .append(entry.getValue()).append("\n");
-                }
-                for (PositionConstraint constraint : constraints) {
-                    if (constraint.mPostLayoutPos >= 0) {
-                        constraint.validate(state, positions.get(constraint.mPostLayoutPos),
-                                lm.getLog() + positionLog);
-                    }
-                }
-            }
-        };
-        adapterChanges.run(mTestAdapter);
-        mLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        for (PositionConstraint constraint : constraints) {
-            constraint.assertValidate();
-        }
-    }
-
-    @Test
-    public void addThenRecycleRemovedView() throws Throwable {
-        setupBasic(10);
-        final AtomicInteger step = new AtomicInteger(0);
-        final List<RecyclerView.ViewHolder> animateRemoveList
-                = new ArrayList<RecyclerView.ViewHolder>();
-        DefaultItemAnimator animator = new DefaultItemAnimator() {
-            @Override
-            public boolean animateRemove(RecyclerView.ViewHolder holder) {
-                animateRemoveList.add(holder);
-                return super.animateRemove(holder);
-            }
-        };
-        mRecyclerView.setItemAnimator(animator);
-        final List<RecyclerView.ViewHolder> pooledViews = new ArrayList<RecyclerView.ViewHolder>();
-        mRecyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool() {
-            @Override
-            public void putRecycledView(RecyclerView.ViewHolder scrap) {
-                pooledViews.add(scrap);
-                super.putRecycledView(scrap);
-            }
-        });
-        final RecyclerView.ViewHolder[] targetVh = new RecyclerView.ViewHolder[1];
-        mLayoutManager.mOnLayoutCallbacks = new OnLayoutCallbacks() {
-            @Override
-            void doLayout(RecyclerView.Recycler recycler,
-                    AnimationLayoutManager lm, RecyclerView.State state) {
-                switch (step.get()) {
-                    case 1:
-                        super.doLayout(recycler, lm, state);
-                        if (state.isPreLayout()) {
-                            View view = mLayoutManager.getChildAt(1);
-                            RecyclerView.ViewHolder holder =
-                                    mRecyclerView.getChildViewHolderInt(view);
-                            targetVh[0] = holder;
-                            assertTrue("test sanity", holder.isRemoved());
-                            mLayoutManager.removeAndRecycleView(view, recycler);
-                        }
-                        break;
-                }
-            }
-        };
-        step.set(1);
-        animateRemoveList.clear();
-        mLayoutManager.expectLayouts(2);
-        mTestAdapter.deleteAndNotify(1, 1);
-        mLayoutManager.waitForLayout(2);
-        assertTrue("test sanity, view should be recycled", pooledViews.contains(targetVh[0]));
-        assertTrue("since LM force recycled a view, animate disappearance should not be called",
-                animateRemoveList.isEmpty());
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
deleted file mode 100644
index 50e2d8b..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewBasicTest.java
+++ /dev/null
@@ -1,830 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.annotation.NonNull;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.recyclerview.test.R;
-import android.util.AttributeSet;
-import android.util.SparseArray;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RecyclerViewBasicTest {
-
-    RecyclerView mRecyclerView;
-
-    @Before
-    public void setUp() throws Exception {
-        mRecyclerView = new RecyclerView(getContext());
-    }
-
-    private Context getContext() {
-        return InstrumentationRegistry.getTargetContext();
-    }
-
-    @Test
-    public void measureWithoutLayoutManager() {
-        measure();
-    }
-
-    private void measure() {
-        mRecyclerView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240);
-    }
-
-    private void layout() {
-        mRecyclerView.layout(0, 0, 320, 320);
-    }
-
-    private void focusSearch() {
-        mRecyclerView.focusSearch(1);
-    }
-
-    @Test
-    public void layoutWithoutAdapter() throws InterruptedException {
-        MockLayoutManager layoutManager = new MockLayoutManager();
-        mRecyclerView.setLayoutManager(layoutManager);
-        layout();
-        assertEquals("layout manager should not be called if there is no adapter attached",
-                0, layoutManager.mLayoutCount);
-    }
-
-    public void setScrollContainer() {
-        assertEquals("RecyclerView should announce itself as scroll container for the IME to "
-                + "handle it properly", true, mRecyclerView.isScrollContainer());
-    }
-
-    @Test
-    public void layoutWithoutLayoutManager() throws InterruptedException {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-    }
-
-    @Test
-    public void focusWithoutLayoutManager() throws InterruptedException {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-        focusSearch();
-    }
-
-    @Test
-    public void scrollWithoutLayoutManager() throws InterruptedException {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-        mRecyclerView.scrollBy(10, 10);
-    }
-
-    @Test
-    public void smoothScrollWithoutLayoutManager() throws InterruptedException {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-        mRecyclerView.smoothScrollBy(10, 10);
-    }
-
-    @Test
-    public void scrollToPositionWithoutLayoutManager() throws InterruptedException {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-        mRecyclerView.scrollToPosition(5);
-    }
-
-    @Test
-    public void smoothScrollToPositionWithoutLayoutManager() throws InterruptedException {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-        mRecyclerView.smoothScrollToPosition(5);
-    }
-
-    @Test
-    public void interceptTouchWithoutLayoutManager() {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-        assertFalse(mRecyclerView.onInterceptTouchEvent(
-                MotionEvent.obtain(SystemClock.uptimeMillis(),
-                        SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10, 10, 0)));
-    }
-
-    @Test
-    public void onTouchWithoutLayoutManager() {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        measure();
-        layout();
-        assertFalse(mRecyclerView.onTouchEvent(MotionEvent.obtain(SystemClock.uptimeMillis(),
-                SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 10, 10, 0)));
-    }
-
-    @Test
-    public void layoutSimple() throws InterruptedException {
-        MockLayoutManager layoutManager = new MockLayoutManager();
-        mRecyclerView.setLayoutManager(layoutManager);
-        mRecyclerView.setAdapter(new MockAdapter(3));
-        layout();
-        assertEquals("when both layout manager and activity is set, recycler view should call"
-                + " layout manager's layout method", 1, layoutManager.mLayoutCount);
-    }
-
-    @Test
-    public void observingAdapters() {
-        MockAdapter adapterOld = new MockAdapter(1);
-        mRecyclerView.setAdapter(adapterOld);
-        assertTrue("attached adapter should have observables", adapterOld.hasObservers());
-
-        MockAdapter adapterNew = new MockAdapter(2);
-        mRecyclerView.setAdapter(adapterNew);
-        assertFalse("detached adapter should lose observable", adapterOld.hasObservers());
-        assertTrue("new adapter should have observers", adapterNew.hasObservers());
-
-        mRecyclerView.setAdapter(null);
-        assertNull("adapter should be removed successfully", mRecyclerView.getAdapter());
-        assertFalse("when adapter is removed, observables should be removed too",
-                adapterNew.hasObservers());
-    }
-
-    @Test
-    public void adapterChangeCallbacks() {
-        MockLayoutManager layoutManager = new MockLayoutManager();
-        mRecyclerView.setLayoutManager(layoutManager);
-        MockAdapter adapterOld = new MockAdapter(1);
-        mRecyclerView.setAdapter(adapterOld);
-        layoutManager.assertPrevNextAdapters(null, adapterOld);
-
-        MockAdapter adapterNew = new MockAdapter(2);
-        mRecyclerView.setAdapter(adapterNew);
-        layoutManager.assertPrevNextAdapters("switching adapters should trigger correct callbacks"
-                , adapterOld, adapterNew);
-
-        mRecyclerView.setAdapter(null);
-        layoutManager.assertPrevNextAdapters(
-                "Setting adapter null should trigger correct callbacks",
-                adapterNew, null);
-    }
-
-    @Test
-    public void recyclerOffsetsOnMove() {
-        MockLayoutManager  layoutManager = new MockLayoutManager();
-        final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>();
-        mRecyclerView.setLayoutManager(layoutManager);
-        MockAdapter adapter = new MockAdapter(100) {
-            @Override
-            public void onViewRecycled(RecyclerView.ViewHolder holder) {
-                super.onViewRecycled(holder);
-                recycledVhs.add(holder);
-            }
-        };
-        MockViewHolder mvh = new MockViewHolder(new TextView(getContext()));
-        mRecyclerView.setAdapter(adapter);
-        adapter.bindViewHolder(mvh, 20);
-        mRecyclerView.mRecycler.mCachedViews.add(mvh);
-        mRecyclerView.offsetPositionRecordsForRemove(10, 9, false);
-
-        mRecyclerView.offsetPositionRecordsForRemove(11, 1, false);
-        assertEquals(1, recycledVhs.size());
-        assertSame(mvh, recycledVhs.get(0));
-    }
-
-    @Test
-    public void recyclerOffsetsOnAdd() {
-        MockLayoutManager  layoutManager = new MockLayoutManager();
-        final List<RecyclerView.ViewHolder> recycledVhs = new ArrayList<>();
-        mRecyclerView.setLayoutManager(layoutManager);
-        MockAdapter adapter = new MockAdapter(100) {
-            @Override
-            public void onViewRecycled(RecyclerView.ViewHolder holder) {
-                super.onViewRecycled(holder);
-                recycledVhs.add(holder);
-            }
-        };
-        MockViewHolder mvh = new MockViewHolder(new TextView(getContext()));
-        mRecyclerView.setAdapter(adapter);
-        adapter.bindViewHolder(mvh, 20);
-        mRecyclerView.mRecycler.mCachedViews.add(mvh);
-        mRecyclerView.offsetPositionRecordsForRemove(10, 9, false);
-
-        mRecyclerView.offsetPositionRecordsForInsert(15, 10);
-        assertEquals(11, mvh.mPosition);
-    }
-
-    @Test
-    public void savedStateWithStatelessLayoutManager() throws InterruptedException {
-        mRecyclerView.setLayoutManager(new MockLayoutManager() {
-            @Override
-            public Parcelable onSaveInstanceState() {
-                return null;
-            }
-        });
-        mRecyclerView.setAdapter(new MockAdapter(3));
-        Parcel parcel = Parcel.obtain();
-        String parcelSuffix = UUID.randomUUID().toString();
-        Parcelable savedState = mRecyclerView.onSaveInstanceState();
-        savedState.writeToParcel(parcel, 0);
-        parcel.writeString(parcelSuffix);
-
-        // reset position for reading
-        parcel.setDataPosition(0);
-        RecyclerView restored = new RecyclerView(getContext());
-        restored.setLayoutManager(new MockLayoutManager());
-        mRecyclerView.setAdapter(new MockAdapter(3));
-        // restore
-        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
-        restored.onRestoreInstanceState(savedState);
-
-        assertEquals("Parcel reading should not go out of bounds", parcelSuffix,
-                parcel.readString());
-        assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail());
-
-    }
-
-    @Test
-    public void savedState() throws InterruptedException {
-        MockLayoutManager mlm = new MockLayoutManager();
-        mRecyclerView.setLayoutManager(mlm);
-        mRecyclerView.setAdapter(new MockAdapter(3));
-        layout();
-        Parcelable savedState = mRecyclerView.onSaveInstanceState();
-        // we append a suffix to the parcelable to test out of bounds
-        String parcelSuffix = UUID.randomUUID().toString();
-        Parcel parcel = Parcel.obtain();
-        savedState.writeToParcel(parcel, 0);
-        parcel.writeString(parcelSuffix);
-
-        // reset for reading
-        parcel.setDataPosition(0);
-        // re-create
-        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
-
-        RecyclerView restored = new RecyclerView(getContext());
-        MockLayoutManager mlmRestored = new MockLayoutManager();
-        restored.setLayoutManager(mlmRestored);
-        restored.setAdapter(new MockAdapter(3));
-        restored.onRestoreInstanceState(savedState);
-
-        assertEquals("Parcel reading should not go out of bounds", parcelSuffix,
-                parcel.readString());
-        assertEquals("When unmarshalling, all of the parcel should be read", 0, parcel.dataAvail());
-        assertEquals("uuid in layout manager should be preserved properly", mlm.mUuid,
-                mlmRestored.mUuid);
-        assertNotSame("stateless parameter should not be preserved", mlm.mLayoutCount,
-                mlmRestored.mLayoutCount);
-        layout();
-    }
-
-    @Test
-    public void dontSaveChildrenState() throws InterruptedException {
-        MockLayoutManager mlm = new MockLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                View view = recycler.getViewForPosition(0);
-                addView(view);
-                measureChildWithMargins(view, 0, 0);
-                view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
-            }
-        };
-        mRecyclerView.setLayoutManager(mlm);
-        mRecyclerView.setAdapter(new MockAdapter(3) {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                final LoggingView itemView = new LoggingView(parent.getContext());
-                //noinspection ResourceType
-                itemView.setId(3);
-                return new MockViewHolder(itemView);
-            }
-        });
-        measure();
-        layout();
-        View view = mRecyclerView.getChildAt(0);
-        assertNotNull("test sanity", view);
-        LoggingView loggingView = (LoggingView) view;
-        SparseArray<Parcelable> container = new SparseArray<Parcelable>();
-        mRecyclerView.saveHierarchyState(container);
-        assertEquals("children's save state method should not be called", 0,
-                loggingView.getOnSavedInstanceCnt());
-    }
-
-    @Test
-    public void smoothScrollWithCustomInterpolator() {
-        mRecyclerView.setLayoutManager(new MockLayoutManager());
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        Interpolator interpolator = new LinearInterpolator();
-        mRecyclerView.smoothScrollBy(0, 100, interpolator);
-        assertSame(interpolator, mRecyclerView.mViewFlinger.mInterpolator);
-
-        mRecyclerView.smoothScrollBy(0, -100);
-        assertSame(RecyclerView.sQuinticInterpolator, mRecyclerView.mViewFlinger.mInterpolator);
-    }
-
-    @Test
-    public void createAttachedException() {
-        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
-            @NonNull
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
-                    int viewType) {
-                View view = LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.item_view, parent, true)
-                        .findViewById(R.id.item_view); // find child, since parent is returned
-                return new RecyclerView.ViewHolder(view) {};
-            }
-
-            @Override
-            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
-                fail("shouldn't get here, should throw during create");
-            }
-
-            @Override
-            public int getItemCount() {
-                return 1;
-            }
-        });
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-
-        try {
-            measure();
-            //layout();
-            fail("IllegalStateException expected");
-        } catch (IllegalStateException e) {
-            // expected
-        }
-    }
-
-    @Test
-    public void prefetchChangesCacheSize() {
-        mRecyclerView.setAdapter(new MockAdapter(20));
-        MockLayoutManager mlm = new MockLayoutManager() {
-            @Override
-            public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
-                    RecyclerView.LayoutManager.LayoutPrefetchRegistry prefetchManager) {
-                prefetchManager.addPosition(0, 0);
-                prefetchManager.addPosition(1, 0);
-                prefetchManager.addPosition(2, 0);
-            }
-        };
-
-        RecyclerView.Recycler recycler = mRecyclerView.mRecycler;
-        assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
-        mRecyclerView.setLayoutManager(mlm);
-        assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
-
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            // layout, so prefetches can occur
-            mRecyclerView.measure(View.MeasureSpec.EXACTLY | 100, View.MeasureSpec.EXACTLY | 100);
-            mRecyclerView.layout(0, 0, 100, 100);
-
-            // prefetch gets 3 items, so expands cache by 3
-            mRecyclerView.mPrefetchRegistry.collectPrefetchPositionsFromView(mRecyclerView, false);
-            assertEquals(3, mRecyclerView.mPrefetchRegistry.mCount);
-            assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax);
-
-            // Reset to default by removing layout
-            mRecyclerView.setLayoutManager(null);
-            assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE, recycler.mViewCacheMax);
-
-            // And restore by restoring layout
-            mRecyclerView.setLayoutManager(mlm);
-            assertEquals(RecyclerView.Recycler.DEFAULT_CACHE_SIZE + 3, recycler.mViewCacheMax);
-        }
-    }
-
-    @Test
-    public void getNanoTime() {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            // check that it looks vaguely time-ish
-            long time = mRecyclerView.getNanoTime();
-            assertNotEquals(0, time);
-            assertNotEquals(time, mRecyclerView.getNanoTime());
-        } else {
-            // expect to avoid cost of system.nanoTime on older platforms that don't do prefetch
-            assertEquals(0, mRecyclerView.getNanoTime());
-        }
-    }
-
-    @Test
-    public void findNestedRecyclerView() {
-        RecyclerView recyclerView = new RecyclerView(getContext());
-        assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(recyclerView));
-
-        ViewGroup parent = new FrameLayout(getContext());
-        assertEquals(null, RecyclerView.findNestedRecyclerView(parent));
-        parent.addView(recyclerView);
-        assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(parent));
-
-        ViewGroup grandParent = new FrameLayout(getContext());
-        assertEquals(null, RecyclerView.findNestedRecyclerView(grandParent));
-        grandParent.addView(parent);
-        assertEquals(recyclerView, RecyclerView.findNestedRecyclerView(grandParent));
-    }
-
-    @Test
-    public void clearNestedRecyclerViewIfNotNested() {
-        RecyclerView recyclerView = new RecyclerView(getContext());
-        ViewGroup parent = new FrameLayout(getContext());
-        parent.addView(recyclerView);
-        ViewGroup grandParent = new FrameLayout(getContext());
-        grandParent.addView(parent);
-
-        // verify trivial noop case
-        RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(recyclerView) {};
-        holder.mNestedRecyclerView = new WeakReference<>(recyclerView);
-        RecyclerView.clearNestedRecyclerViewIfNotNested(holder);
-        assertEquals(recyclerView, holder.mNestedRecyclerView.get());
-
-        // verify clear case
-        holder = new RecyclerView.ViewHolder(new View(getContext())) {};
-        holder.mNestedRecyclerView = new WeakReference<>(recyclerView);
-        RecyclerView.clearNestedRecyclerViewIfNotNested(holder);
-        assertNull(holder.mNestedRecyclerView);
-
-        // verify more deeply nested case
-        holder = new RecyclerView.ViewHolder(grandParent) {};
-        holder.mNestedRecyclerView = new WeakReference<>(recyclerView);
-        RecyclerView.clearNestedRecyclerViewIfNotNested(holder);
-        assertEquals(recyclerView, holder.mNestedRecyclerView.get());
-    }
-
-    @Test
-    public void exceptionContainsClasses() {
-        RecyclerView first = new RecyclerView(getContext());
-        first.setLayoutManager(new LinearLayoutManager(getContext()));
-        first.setAdapter(new MockAdapter(10));
-
-        RecyclerView second = new RecyclerView(getContext());
-        try {
-            second.setLayoutManager(first.getLayoutManager());
-            fail("exception expected");
-        } catch (IllegalArgumentException e) {
-            // Note: exception contains first RV
-            String m = e.getMessage();
-            assertTrue("must contain RV class", m.contains(RecyclerView.class.getName()));
-            assertTrue("must contain Adapter class", m.contains(MockAdapter.class.getName()));
-            assertTrue("must contain LM class", m.contains(LinearLayoutManager.class.getName()));
-            assertTrue("must contain ctx class", m.contains(getContext().getClass().getName()));
-        }
-    }
-
-    @Test
-    public void focusOrderTest() {
-        FocusOrderAdapter focusAdapter = new FocusOrderAdapter(getContext());
-        mRecyclerView.setAdapter(focusAdapter);
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        measure();
-        layout();
-
-        boolean isIcsOrLower = Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1;
-
-        // On API 15 and lower, focus forward get's translated to focus down.
-        View expected = isIcsOrLower ? focusAdapter.mBottomRight : focusAdapter.mBottomLeft;
-        assertEquals(expected, focusAdapter.mTopRight.focusSearch(View.FOCUS_FORWARD));
-
-        // On API 15 and lower, focus forward get's translated to focus down, which in this case
-        // runs out of the RecyclerView, thus returning null.
-        expected = isIcsOrLower ? null : focusAdapter.mBottomRight;
-        assertSame(expected, focusAdapter.mBottomLeft.focusSearch(View.FOCUS_FORWARD));
-
-        // we don't want looping within RecyclerView
-        assertNull(focusAdapter.mBottomRight.focusSearch(View.FOCUS_FORWARD));
-        assertNull(focusAdapter.mTopLeft.focusSearch(View.FOCUS_BACKWARD));
-    }
-
-    @Test
-    public void setAdapter_callsCorrectLmMethods() throws Throwable {
-        MockLayoutManager mockLayoutManager = new MockLayoutManager();
-        MockAdapter mockAdapter = new MockAdapter(1);
-        mRecyclerView.setLayoutManager(mockLayoutManager);
-
-        mRecyclerView.setAdapter(mockAdapter);
-        layout();
-
-        assertEquals(1, mockLayoutManager.mAdapterChangedCount);
-        assertEquals(0, mockLayoutManager.mItemsChangedCount);
-    }
-
-    @Test
-    public void swapAdapter_callsCorrectLmMethods() throws Throwable {
-        MockLayoutManager mockLayoutManager = new MockLayoutManager();
-        MockAdapter mockAdapter = new MockAdapter(1);
-        mRecyclerView.setLayoutManager(mockLayoutManager);
-
-        mRecyclerView.swapAdapter(mockAdapter, true);
-        layout();
-
-        assertEquals(1, mockLayoutManager.mAdapterChangedCount);
-        assertEquals(1, mockLayoutManager.mItemsChangedCount);
-    }
-
-    @Test
-    public void notifyDataSetChanged_callsCorrectLmMethods() throws Throwable {
-        MockLayoutManager mockLayoutManager = new MockLayoutManager();
-        MockAdapter mockAdapter = new MockAdapter(1);
-        mRecyclerView.setLayoutManager(mockLayoutManager);
-        mRecyclerView.setAdapter(mockAdapter);
-        mockLayoutManager.mAdapterChangedCount = 0;
-        mockLayoutManager.mItemsChangedCount = 0;
-
-        mockAdapter.notifyDataSetChanged();
-        layout();
-
-        assertEquals(0, mockLayoutManager.mAdapterChangedCount);
-        assertEquals(1, mockLayoutManager.mItemsChangedCount);
-    }
-
-    static class MockLayoutManager extends RecyclerView.LayoutManager {
-
-        int mLayoutCount = 0;
-
-        int mAdapterChangedCount = 0;
-        int mItemsChangedCount = 0;
-
-        RecyclerView.Adapter mPrevAdapter;
-
-        RecyclerView.Adapter mNextAdapter;
-
-        String mUuid = UUID.randomUUID().toString();
-
-        @Override
-        public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
-                RecyclerView.Adapter newAdapter) {
-            super.onAdapterChanged(oldAdapter, newAdapter);
-            mPrevAdapter = oldAdapter;
-            mNextAdapter = newAdapter;
-            mAdapterChangedCount++;
-        }
-
-        @Override
-        public void onItemsChanged(RecyclerView recyclerView) {
-            mItemsChangedCount++;
-        }
-
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            mLayoutCount += 1;
-        }
-
-        @Override
-        public Parcelable onSaveInstanceState() {
-            LayoutManagerSavedState lss = new LayoutManagerSavedState();
-            lss.mUuid = mUuid;
-            return lss;
-        }
-
-        @Override
-        public void onRestoreInstanceState(Parcelable state) {
-            super.onRestoreInstanceState(state);
-            if (state instanceof LayoutManagerSavedState) {
-                mUuid = ((LayoutManagerSavedState) state).mUuid;
-            }
-        }
-
-        @Override
-        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
-            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-        }
-
-        public void assertPrevNextAdapters(String message, RecyclerView.Adapter prevAdapter,
-                RecyclerView.Adapter nextAdapter) {
-            assertSame(message, prevAdapter, mPrevAdapter);
-            assertSame(message, nextAdapter, mNextAdapter);
-        }
-
-        public void assertPrevNextAdapters(RecyclerView.Adapter prevAdapter,
-                RecyclerView.Adapter nextAdapter) {
-            assertPrevNextAdapters("Adapters from onAdapterChanged callback should match",
-                    prevAdapter, nextAdapter);
-        }
-
-        @Override
-        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            return dx;
-        }
-
-        @Override
-        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            return dy;
-        }
-
-        @Override
-        public boolean canScrollHorizontally() {
-            return true;
-        }
-
-        @Override
-        public boolean canScrollVertically() {
-            return true;
-        }
-    }
-
-    static class LayoutManagerSavedState implements Parcelable {
-
-        String mUuid;
-
-        public LayoutManagerSavedState(Parcel in) {
-            mUuid = in.readString();
-        }
-
-        public LayoutManagerSavedState() {
-
-        }
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeString(mUuid);
-        }
-
-        public static final Parcelable.Creator<LayoutManagerSavedState> CREATOR
-                = new Parcelable.Creator<LayoutManagerSavedState>() {
-            @Override
-            public LayoutManagerSavedState createFromParcel(Parcel in) {
-                return new LayoutManagerSavedState(in);
-            }
-
-            @Override
-            public LayoutManagerSavedState[] newArray(int size) {
-                return new LayoutManagerSavedState[size];
-            }
-        };
-    }
-
-    static class MockAdapter extends RecyclerView.Adapter {
-
-        private int mCount = 0;
-
-
-        MockAdapter(int count) {
-            this.mCount = count;
-        }
-
-        @Override
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new MockViewHolder(new TextView(parent.getContext()));
-        }
-
-        @Override
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-
-        }
-
-        @Override
-        public int getItemCount() {
-            return mCount;
-        }
-
-        void removeItems(int start, int count) {
-            mCount -= count;
-            notifyItemRangeRemoved(start, count);
-        }
-
-        void addItems(int start, int count) {
-            mCount += count;
-            notifyItemRangeInserted(start, count);
-        }
-    }
-
-    static class MockViewHolder extends RecyclerView.ViewHolder {
-        public Object mItem;
-        public MockViewHolder(View itemView) {
-            super(itemView);
-        }
-    }
-
-    static class LoggingView extends TextView {
-        private int mOnSavedInstanceCnt = 0;
-
-        public LoggingView(Context context) {
-            super(context);
-        }
-
-        public LoggingView(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public LoggingView(Context context, AttributeSet attrs, int defStyleAttr) {
-            super(context, attrs, defStyleAttr);
-        }
-
-        @Override
-        public Parcelable onSaveInstanceState() {
-            mOnSavedInstanceCnt ++;
-            return super.onSaveInstanceState();
-        }
-
-        public int getOnSavedInstanceCnt() {
-            return mOnSavedInstanceCnt;
-        }
-    }
-
-    static class FocusOrderAdapter extends RecyclerView.Adapter {
-        TextView mTopLeft;
-        TextView mTopRight;
-        TextView mBottomLeft;
-        TextView mBottomRight;
-
-        FocusOrderAdapter(Context context) {
-            mTopLeft = new TextView(context);
-            mTopRight = new TextView(context);
-            mBottomLeft = new TextView(context);
-            mBottomRight = new TextView(context);
-            for (TextView tv : new TextView[]{mTopLeft, mTopRight, mBottomLeft, mBottomRight}) {
-                tv.setFocusableInTouchMode(true);
-                tv.setLayoutParams(new LinearLayout.LayoutParams(100, 100));
-            }
-            // create a scenario where the "first" focusable is to the right of the last one
-            mTopLeft.setFocusable(false);
-            mTopRight.getLayoutParams().width = 101;
-            mTopLeft.getLayoutParams().width = 101;
-        }
-
-        @Override
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            LinearLayout holder = new LinearLayout(parent.getContext());
-            holder.setOrientation(LinearLayout.HORIZONTAL);
-            return new MockViewHolder(holder);
-        }
-
-        @Override
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-            LinearLayout l = (LinearLayout) holder.itemView;
-            l.removeAllViews();
-            if (position == 0) {
-                l.addView(mTopLeft);
-                l.addView(mTopRight);
-            } else {
-                l.addView(mBottomLeft);
-                l.addView(mBottomRight);
-            }
-        }
-
-        @Override
-        public int getItemCount() {
-            return 2;
-        }
-
-        void removeItems(int start, int count) {
-        }
-
-        void addItems(int start, int count) {
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
deleted file mode 100644
index 1267fdb..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewCacheTest.java
+++ /dev/null
@@ -1,1293 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-@SmallTest
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.LOLLIPOP)
-@RunWith(AndroidJUnit4.class)
-public class RecyclerViewCacheTest {
-    TimeMockingRecyclerView mRecyclerView;
-    RecyclerView.Recycler mRecycler;
-
-    private class TimeMockingRecyclerView extends RecyclerView {
-        private long mMockNanoTime = 0;
-
-        TimeMockingRecyclerView(Context context) {
-            super(context);
-        }
-
-        public void registerTimePassingMs(long ms) {
-            mMockNanoTime += TimeUnit.MILLISECONDS.toNanos(ms);
-        }
-
-        @Override
-        long getNanoTime() {
-            return mMockNanoTime;
-        }
-
-        @Override
-        public int getWindowVisibility() {
-            // Pretend to be visible to avoid being filtered out
-            return View.VISIBLE;
-        }
-    }
-
-    @Before
-    public void setup() throws Exception {
-        mRecyclerView = new TimeMockingRecyclerView(getContext());
-        mRecyclerView.onAttachedToWindow();
-        mRecycler = mRecyclerView.mRecycler;
-    }
-
-    @After
-    public void teardown() throws Exception {
-        if (mRecyclerView.isAttachedToWindow()) {
-            mRecyclerView.onDetachedFromWindow();
-        }
-        GapWorker gapWorker = GapWorker.sGapWorker.get();
-        if (gapWorker != null) {
-            assertTrue(gapWorker.mRecyclerViews.isEmpty());
-        }
-    }
-
-    private Context getContext() {
-        return InstrumentationRegistry.getContext();
-    }
-
-    private void layout(int width, int height) {
-        mRecyclerView.measure(
-                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
-        mRecyclerView.layout(0, 0, width, height);
-    }
-
-    @Test
-    public void prefetchReusesCacheItems() {
-        RecyclerView.LayoutManager prefetchingLayoutManager = new RecyclerView.LayoutManager() {
-            @Override
-            public RecyclerView.LayoutParams generateDefaultLayoutParams() {
-                return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
-            }
-
-            @Override
-            public void collectAdjacentPrefetchPositions(int dx, int dy, RecyclerView.State state,
-                    LayoutPrefetchRegistry prefetchManager) {
-                prefetchManager.addPosition(0, 0);
-                prefetchManager.addPosition(1, 0);
-                prefetchManager.addPosition(2, 0);
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            }
-        };
-        mRecyclerView.setLayoutManager(prefetchingLayoutManager);
-
-        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
-        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
-                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
-                    @Override
-                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
-                            throws Throwable {
-                        return new RecyclerView.ViewHolder(new View(getContext())) {};
-                    }
-                });
-        when(mockAdapter.getItemCount()).thenReturn(10);
-        mRecyclerView.setAdapter(mockAdapter);
-
-        layout(320, 320);
-
-        verify(mockAdapter, never()).onCreateViewHolder(any(ViewGroup.class), anyInt());
-        verify(mockAdapter, never()).onBindViewHolder(
-                any(RecyclerView.ViewHolder.class), anyInt(), any(List.class));
-        assertTrue(mRecycler.mCachedViews.isEmpty());
-
-        // Prefetch multiple times...
-        for (int i = 0; i < 4; i++) {
-            mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-            // ...but should only see the same three items fetched/bound once each
-            verify(mockAdapter, times(3)).onCreateViewHolder(any(ViewGroup.class), anyInt());
-            verify(mockAdapter, times(3)).onBindViewHolder(
-                    any(RecyclerView.ViewHolder.class), anyInt(), any(List.class));
-
-            assertTrue(mRecycler.mCachedViews.size() == 3);
-            CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 0, 1, 2);
-        }
-    }
-
-    @Test
-    public void prefetchItemsNotEvictedWithInserts() {
-        mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
-
-        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
-        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
-                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
-                    @Override
-                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
-                            throws Throwable {
-                        View view = new View(getContext());
-                        view.setMinimumWidth(100);
-                        view.setMinimumHeight(100);
-                        return new RecyclerView.ViewHolder(view) {};
-                    }
-                });
-        when(mockAdapter.getItemCount()).thenReturn(100);
-        mRecyclerView.setAdapter(mockAdapter);
-
-        layout(300, 100);
-
-        assertEquals(2, mRecyclerView.mRecycler.mViewCacheMax);
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        assertEquals(5, mRecyclerView.mRecycler.mViewCacheMax);
-
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 3, 4, 5);
-
-        // further views recycled, as though from scrolling, shouldn't evict prefetched views:
-        mRecycler.recycleView(mRecycler.getViewForPosition(10));
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 10);
-
-        mRecycler.recycleView(mRecycler.getViewForPosition(20));
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 10, 20);
-
-        mRecycler.recycleView(mRecycler.getViewForPosition(30));
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 20, 30);
-
-        mRecycler.recycleView(mRecycler.getViewForPosition(40));
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 3, 4, 5, 30, 40);
-
-        // After clearing the cache, the prefetch priorities should be cleared as well:
-        mRecyclerView.mRecycler.recycleAndClearCachedViews();
-        for (int i : new int[] {3, 4, 5, 50, 60, 70, 80, 90}) {
-            mRecycler.recycleView(mRecycler.getViewForPosition(i));
-        }
-
-        // cache only contains most recent positions, no priority for previous prefetches:
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 50, 60, 70, 80, 90);
-    }
-
-    @Test
-    public void prefetchItemsNotEvictedOnScroll() {
-        mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
-
-        // 100x100 pixel views
-        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
-        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
-                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
-                    @Override
-                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
-                            throws Throwable {
-                        View view = new View(getContext());
-                        view.setMinimumWidth(100);
-                        view.setMinimumHeight(100);
-                        return new RecyclerView.ViewHolder(view) {};
-                    }
-                });
-        when(mockAdapter.getItemCount()).thenReturn(100);
-        mRecyclerView.setAdapter(mockAdapter);
-
-        // NOTE: requested cache size must be smaller than span count so two rows cannot fit
-        mRecyclerView.setItemViewCacheSize(2);
-
-        layout(300, 150);
-        mRecyclerView.scrollBy(0, 75);
-        assertTrue(mRecycler.mCachedViews.isEmpty());
-
-        // rows 0, 1, and 2 are all attached and visible. Prefetch row 3:
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        // row 3 is cached:
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 9, 10, 11);
-        assertTrue(mRecycler.mCachedViews.size() == 3);
-
-        // Scroll so 1 falls off (though 3 is still not on screen)
-        mRecyclerView.scrollBy(0, 50);
-
-        // row 3 is still cached, with a couple other recycled views:
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 9, 10, 11);
-        assertTrue(mRecycler.mCachedViews.size() == 5);
-    }
-
-    @Test
-    public void prefetchIsComputingLayout() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-
-        // 100x100 pixel views
-        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
-        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
-                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
-                    @Override
-                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
-                            throws Throwable {
-                        View view = new View(getContext());
-                        view.setMinimumWidth(100);
-                        view.setMinimumHeight(100);
-                        assertTrue(mRecyclerView.isComputingLayout());
-                        return new RecyclerView.ViewHolder(view) {};
-                    }
-                });
-        when(mockAdapter.getItemCount()).thenReturn(100);
-        mRecyclerView.setAdapter(mockAdapter);
-
-        layout(100, 100);
-
-        verify(mockAdapter, times(1)).onCreateViewHolder(mRecyclerView, 0);
-
-        // prefetch an item, should still observe isComputingLayout in that create
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        verify(mockAdapter, times(2)).onCreateViewHolder(mRecyclerView, 0);
-    }
-
-    @Test
-    public void prefetchAfterOrientationChange() {
-        LinearLayoutManager layout = new LinearLayoutManager(getContext(),
-                LinearLayoutManager.VERTICAL, false);
-        mRecyclerView.setLayoutManager(layout);
-
-        // 100x100 pixel views
-        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                View view = new View(getContext());
-                view.setMinimumWidth(100);
-                view.setMinimumHeight(100);
-                assertTrue(mRecyclerView.isComputingLayout());
-                return new RecyclerView.ViewHolder(view) {};
-            }
-
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
-
-            @Override
-            public int getItemCount() {
-                return 100;
-            }
-        });
-
-        layout(100, 100);
-
-        layout.setOrientation(LinearLayoutManager.HORIZONTAL);
-
-        // Prefetch an item after changing orientation, before layout - shouldn't crash
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(1, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-    }
-
-    @Test
-    public void prefetchDrag() {
-        // event dispatch requires a parent
-        ViewGroup parent = new FrameLayout(getContext());
-        parent.addView(mRecyclerView);
-
-
-        mRecyclerView.setLayoutManager(
-                new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
-
-        // 1000x1000 pixel views
-        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                mRecyclerView.registerTimePassingMs(5);
-                View view = new View(getContext());
-                view.setMinimumWidth(1000);
-                view.setMinimumHeight(1000);
-                return new RecyclerView.ViewHolder(view) {};
-            }
-
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-                mRecyclerView.registerTimePassingMs(5);
-            }
-
-            @Override
-            public int getItemCount() {
-                return 100;
-            }
-        };
-        mRecyclerView.setAdapter(adapter);
-
-        layout(1000, 1000);
-
-        long time = SystemClock.uptimeMillis();
-        mRecyclerView.onTouchEvent(
-                MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 500, 1000, 0));
-
-        assertEquals(0, mRecyclerView.mPrefetchRegistry.mPrefetchDx);
-        assertEquals(0, mRecyclerView.mPrefetchRegistry.mPrefetchDy);
-
-        // Consume slop
-        mRecyclerView.onTouchEvent(
-                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 50, 500, 0));
-
-        // move by 0,30
-        mRecyclerView.onTouchEvent(
-                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 50, 470, 0));
-        assertEquals(0, mRecyclerView.mPrefetchRegistry.mPrefetchDx);
-        assertEquals(30, mRecyclerView.mPrefetchRegistry.mPrefetchDy);
-
-        // move by 10,15
-        mRecyclerView.onTouchEvent(
-                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 40, 455, 0));
-        assertEquals(10, mRecyclerView.mPrefetchRegistry.mPrefetchDx);
-        assertEquals(15, mRecyclerView.mPrefetchRegistry.mPrefetchDy);
-
-        // move by 0,0 - IGNORED
-        mRecyclerView.onTouchEvent(
-                MotionEvent.obtain(time, time, MotionEvent.ACTION_MOVE, 40, 455, 0));
-        assertEquals(10, mRecyclerView.mPrefetchRegistry.mPrefetchDx); // same as prev
-        assertEquals(15, mRecyclerView.mPrefetchRegistry.mPrefetchDy); // same as prev
-    }
-
-    @Test
-    public void prefetchItemsRespectDeadline() {
-        mRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
-
-        // 100x100 pixel views
-        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                mRecyclerView.registerTimePassingMs(5);
-                View view = new View(getContext());
-                view.setMinimumWidth(100);
-                view.setMinimumHeight(100);
-                return new RecyclerView.ViewHolder(view) {};
-            }
-
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-                mRecyclerView.registerTimePassingMs(5);
-            }
-
-            @Override
-            public int getItemCount() {
-                return 100;
-            }
-        };
-        mRecyclerView.setAdapter(adapter);
-
-        layout(300, 300);
-
-        // offset scroll so that no prefetch-able views are directly adjacent to viewport
-        mRecyclerView.scrollBy(0, 50);
-
-        assertTrue(mRecycler.mCachedViews.size() == 0);
-        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 0);
-
-        // Should take 15 ms to inflate, bind, inflate, so give 19 to be safe
-        final long deadlineNs = mRecyclerView.getNanoTime() + TimeUnit.MILLISECONDS.toNanos(19);
-
-        // Timed prefetch
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(deadlineNs);
-
-        // will have enough time to inflate/bind one view, and inflate another
-        assertTrue(mRecycler.mCachedViews.size() == 1);
-        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 1);
-        // Note: order/view below is an implementation detail
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 12);
-
-
-        // Unbounded prefetch this time
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        // Should finish all work
-        assertTrue(mRecycler.mCachedViews.size() == 3);
-        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 0);
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 12, 13, 14);
-    }
-
-    @Test
-    public void partialPrefetchAvoidsViewRecycledCallback() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-
-        // 100x100 pixel views
-        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                mRecyclerView.registerTimePassingMs(5);
-                View view = new View(getContext());
-                view.setMinimumWidth(100);
-                view.setMinimumHeight(100);
-                return new RecyclerView.ViewHolder(view) {};
-            }
-
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-                mRecyclerView.registerTimePassingMs(5);
-            }
-
-            @Override
-            public int getItemCount() {
-                return 100;
-            }
-
-            @Override
-            public void onViewRecycled(RecyclerView.ViewHolder holder) {
-                // verify unbound view doesn't get
-                assertNotEquals(RecyclerView.NO_POSITION, holder.getAdapterPosition());
-            }
-        };
-        mRecyclerView.setAdapter(adapter);
-
-        layout(100, 300);
-
-        // offset scroll so that no prefetch-able views are directly adjacent to viewport
-        mRecyclerView.scrollBy(0, 50);
-
-        assertTrue(mRecycler.mCachedViews.size() == 0);
-        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 0);
-
-        // Should take 10 ms to inflate + bind, so just give it 9 so it doesn't have time to bind
-        final long deadlineNs = mRecyclerView.getNanoTime() + TimeUnit.MILLISECONDS.toNanos(9);
-
-        // Timed prefetch
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(deadlineNs);
-
-        // will have enough time to inflate but not bind one view
-        assertTrue(mRecycler.mCachedViews.size() == 0);
-        assertTrue(mRecyclerView.getRecycledViewPool().getRecycledViewCount(0) == 1);
-        RecyclerView.ViewHolder pooledHolder = mRecyclerView.getRecycledViewPool()
-                .mScrap.get(0).mScrapHeap.get(0);
-        assertEquals(RecyclerView.NO_POSITION, pooledHolder.getAdapterPosition());
-    }
-
-    @Test
-    public void prefetchStaggeredItemsPriority() {
-        StaggeredGridLayoutManager sglm =
-                new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
-        mRecyclerView.setLayoutManager(sglm);
-
-        // first view 50x100 pixels, rest are 100x100 so second column is offset
-        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                return new RecyclerView.ViewHolder(new View(getContext())) {};
-            }
-
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-                holder.itemView.setMinimumWidth(100);
-                holder.itemView.setMinimumHeight(position == 0 ? 50 : 100);
-            }
-
-            @Override
-            public int getItemCount() {
-                return 100;
-            }
-        });
-
-        layout(200, 200);
-
-        /* Each row is 50 pixels:
-         * ------------- *
-         *   0   |   1   *
-         *   2   |   1   *
-         *   2   |   3   *
-         *___4___|___3___*
-         *   4   |   5   *
-         *   6   |   5   *
-         *      ...      *
-         */
-        assertEquals(5, mRecyclerView.getChildCount());
-        assertEquals(0, sglm.getFirstChildPosition());
-        assertEquals(4, sglm.getLastChildPosition());
-
-        // prefetching down shows 5 at 0 pixels away, 6 at 50 pixels away
-        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, 10,
-                new Integer[] {5, 0}, new Integer[] {6, 50});
-
-        // Prefetch upward shows nothing
-        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, -10);
-
-        mRecyclerView.scrollBy(0, 100);
-
-        /* Each row is 50 pixels:
-         * ------------- *
-         *   0   |   1   *
-         *___2___|___1___*
-         *   2   |   3   *
-         *   4   |   3   *
-         *   4   |   5   *
-         *___6___|___5___*
-         *   6   |   7   *
-         *   8   |   7   *
-         *      ...      *
-         */
-
-        assertEquals(5, mRecyclerView.getChildCount());
-        assertEquals(2, sglm.getFirstChildPosition());
-        assertEquals(6, sglm.getLastChildPosition());
-
-        // prefetching down shows 7 at 0 pixels away, 8 at 50 pixels away
-        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, 10,
-                new Integer[] {7, 0}, new Integer[] {8, 50});
-
-        // prefetching up shows 1 is 0 pixels away, 0 at 50 pixels away
-        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, -10,
-                new Integer[] {1, 0}, new Integer[] {0, 50});
-    }
-
-    @Test
-    public void prefetchStaggeredPastBoundary() {
-        StaggeredGridLayoutManager sglm =
-                new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
-        mRecyclerView.setLayoutManager(sglm);
-        mRecyclerView.setAdapter(new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                return new RecyclerView.ViewHolder(new View(getContext())) {};
-            }
-
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-                holder.itemView.setMinimumWidth(100);
-                holder.itemView.setMinimumHeight(position == 0 ? 100 : 200);
-            }
-
-            @Override
-            public int getItemCount() {
-                return 2;
-            }
-        });
-
-        layout(200, 100);
-        mRecyclerView.scrollBy(0, 50);
-
-        /* Each row is 50 pixels:
-         * ------------- *
-         *___0___|___1___*
-         *   0   |   1   *
-         *_______|___1___*
-         *       |   1   *
-         */
-        assertEquals(2, mRecyclerView.getChildCount());
-        assertEquals(0, sglm.getFirstChildPosition());
-        assertEquals(1, sglm.getLastChildPosition());
-
-        // prefetch upward gets nothing
-        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, -10);
-
-        // prefetch downward gets nothing (and doesn't crash...)
-        CacheUtils.verifyPositionsPrefetched(mRecyclerView, 0, 10);
-    }
-
-    @Test
-    public void prefetchItemsSkipAnimations() {
-        LinearLayoutManager llm = new LinearLayoutManager(getContext());
-        mRecyclerView.setLayoutManager(llm);
-        final int[] expandedPosition = new int[] {-1};
-
-        final RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                return new RecyclerView.ViewHolder(new View(parent.getContext())) {};
-            }
-
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-                int height = expandedPosition[0] == position ? 400 : 100;
-                holder.itemView.setLayoutParams(new RecyclerView.LayoutParams(200, height));
-            }
-
-            @Override
-            public int getItemCount() {
-                return 10;
-            }
-        };
-
-        // make move duration long enough to be able to see the effects
-        RecyclerView.ItemAnimator itemAnimator = mRecyclerView.getItemAnimator();
-        itemAnimator.setMoveDuration(10000);
-        mRecyclerView.setAdapter(adapter);
-
-        layout(200, 400);
-
-        expandedPosition[0] = 1;
-        // insert payload to avoid creating a new view
-        adapter.notifyItemChanged(1, new Object());
-
-        layout(200, 400);
-        layout(200, 400);
-
-        assertTrue(itemAnimator.isRunning());
-        assertEquals(2, llm.getChildCount());
-        assertEquals(4, mRecyclerView.getChildCount());
-
-        // animating view should be observable as hidden, uncached...
-        CacheUtils.verifyCacheDoesNotContainPositions(mRecyclerView, 2);
-        assertNotNull("Animating view should be found, hidden",
-                mRecyclerView.mChildHelper.findHiddenNonRemovedView(2));
-        assertTrue(GapWorker.isPrefetchPositionAttached(mRecyclerView, 2));
-
-        // ...but must not be removed for prefetch
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        assertEquals("Prefetch must target one view", 1, mRecyclerView.mPrefetchRegistry.mCount);
-        int prefetchTarget = mRecyclerView.mPrefetchRegistry.mPrefetchArray[0];
-        assertEquals("Prefetch must target view 2", 2, prefetchTarget);
-
-        // animating view still observable as hidden, uncached
-        CacheUtils.verifyCacheDoesNotContainPositions(mRecyclerView, 2);
-        assertNotNull("Animating view should be found, hidden",
-                mRecyclerView.mChildHelper.findHiddenNonRemovedView(2));
-        assertTrue(GapWorker.isPrefetchPositionAttached(mRecyclerView, 2));
-
-        assertTrue(itemAnimator.isRunning());
-        assertEquals(2, llm.getChildCount());
-        assertEquals(4, mRecyclerView.getChildCount());
-    }
-
-    @Test
-    public void viewHolderFindsNestedRecyclerViews() {
-        LinearLayoutManager llm = new LinearLayoutManager(getContext());
-        mRecyclerView.setLayoutManager(llm);
-
-        RecyclerView.Adapter mockAdapter = mock(RecyclerView.Adapter.class);
-        when(mockAdapter.onCreateViewHolder(any(ViewGroup.class), anyInt()))
-                .thenAnswer(new Answer<RecyclerView.ViewHolder>() {
-                    @Override
-                    public RecyclerView.ViewHolder answer(InvocationOnMock invocation)
-                            throws Throwable {
-                        View view = new RecyclerView(getContext());
-                        view.setLayoutParams(new RecyclerView.LayoutParams(100, 100));
-                        return new RecyclerView.ViewHolder(view) {};
-                    }
-                });
-        when(mockAdapter.getItemCount()).thenReturn(100);
-        mRecyclerView.setAdapter(mockAdapter);
-
-        layout(100, 200);
-
-        verify(mockAdapter, times(2)).onCreateViewHolder(any(ViewGroup.class), anyInt());
-        verify(mockAdapter, times(2)).onBindViewHolder(
-                argThat(new ArgumentMatcher<RecyclerView.ViewHolder>() {
-                    @Override
-                    public boolean matches(RecyclerView.ViewHolder holder) {
-                        return holder.itemView == holder.mNestedRecyclerView.get();
-                    }
-                }),
-                anyInt(),
-                any(List.class));
-    }
-
-    class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.ViewHolder> {
-        private static final int INNER_ITEM_COUNT = 20;
-        int mItemsBound = 0;
-
-        class ViewHolder extends RecyclerView.ViewHolder {
-            ViewHolder(View itemView) {
-                super(itemView);
-            }
-        }
-
-        InnerAdapter() {}
-
-        @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            mRecyclerView.registerTimePassingMs(5);
-            View view = new View(parent.getContext());
-            view.setLayoutParams(new RecyclerView.LayoutParams(100, 100));
-            return new ViewHolder(view);
-        }
-
-        @Override
-        public void onBindViewHolder(ViewHolder holder, int position) {
-            mRecyclerView.registerTimePassingMs(5);
-            mItemsBound++;
-        }
-
-        @Override
-        public int getItemCount() {
-            return INNER_ITEM_COUNT;
-        }
-    }
-
-    class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.ViewHolder> {
-
-        private boolean mReverseInner;
-
-        class ViewHolder extends RecyclerView.ViewHolder {
-            private final RecyclerView mRecyclerView;
-            ViewHolder(RecyclerView itemView) {
-                super(itemView);
-                mRecyclerView = itemView;
-            }
-        }
-
-        ArrayList<InnerAdapter> mAdapters = new ArrayList<>();
-        ArrayList<Parcelable> mSavedStates = new ArrayList<>();
-        RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool();
-
-        OuterAdapter() {
-            this(false);
-        }
-
-        OuterAdapter(boolean reverseInner) {
-            this(reverseInner, 10);
-        }
-
-        OuterAdapter(boolean reverseInner, int itemCount) {
-            mReverseInner = reverseInner;
-            for (int i = 0; i < itemCount; i++) {
-                mAdapters.add(new InnerAdapter());
-                mSavedStates.add(null);
-            }
-        }
-
-        void addItem() {
-            int index = getItemCount();
-            mAdapters.add(new InnerAdapter());
-            mSavedStates.add(null);
-            notifyItemInserted(index);
-        }
-
-        @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            mRecyclerView.registerTimePassingMs(5);
-
-            RecyclerView rv = new RecyclerView(parent.getContext()) {
-                @Override
-                public int getWindowVisibility() {
-                    // Pretend to be visible to avoid being filtered out
-                    return View.VISIBLE;
-                }
-            };
-            rv.setLayoutManager(new LinearLayoutManager(parent.getContext(),
-                    LinearLayoutManager.HORIZONTAL, mReverseInner));
-            rv.setRecycledViewPool(mSharedPool);
-            rv.setLayoutParams(new RecyclerView.LayoutParams(200, 100));
-            return new ViewHolder(rv);
-        }
-
-        @Override
-        public void onBindViewHolder(ViewHolder holder, int position) {
-            mRecyclerView.registerTimePassingMs(5);
-
-            // Tests may rely on bound holders not being shared between inner adapters,
-            // since we force recycle here
-            holder.mRecyclerView.swapAdapter(mAdapters.get(position), true);
-
-            Parcelable savedState = mSavedStates.get(position);
-            if (savedState != null) {
-                holder.mRecyclerView.getLayoutManager().onRestoreInstanceState(savedState);
-                mSavedStates.set(position, null);
-            }
-        }
-
-        @Override
-        public void onViewRecycled(ViewHolder holder) {
-            mSavedStates.set(holder.getAdapterPosition(),
-                    holder.mRecyclerView.getLayoutManager().onSaveInstanceState());
-        }
-
-        @Override
-        public int getItemCount() {
-            return mAdapters.size();
-        }
-    }
-
-    @Test
-    public void nestedPrefetchSimple() {
-        LinearLayoutManager llm = new LinearLayoutManager(getContext());
-        assertEquals(2, llm.getInitialPrefetchItemCount());
-
-        mRecyclerView.setLayoutManager(llm);
-        mRecyclerView.setAdapter(new OuterAdapter());
-
-        layout(200, 200);
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-
-        // prefetch 2 (default)
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
-        assertNotNull(holder);
-        assertNotNull(holder.mNestedRecyclerView);
-        RecyclerView innerView = holder.mNestedRecyclerView.get();
-        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1);
-
-        // prefetch 4
-        ((LinearLayoutManager) innerView.getLayoutManager())
-                .setInitialPrefetchItemCount(4);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1, 2, 3);
-    }
-
-    @Test
-    public void nestedPrefetchNotClearInnerStructureChangeFlag() {
-        LinearLayoutManager llm = new LinearLayoutManager(getContext());
-        assertEquals(2, llm.getInitialPrefetchItemCount());
-
-        mRecyclerView.setLayoutManager(llm);
-        mRecyclerView.setAdapter(new OuterAdapter());
-
-        layout(200, 200);
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-
-        // prefetch 2 (default)
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
-        assertNotNull(holder);
-        assertNotNull(holder.mNestedRecyclerView);
-        RecyclerView innerView = holder.mNestedRecyclerView.get();
-        RecyclerView.Adapter innerAdapter = innerView.getAdapter();
-        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1);
-        // mStructureChanged is initially true before first layout pass.
-        assertTrue(innerView.mState.mStructureChanged);
-        assertTrue(innerView.hasPendingAdapterUpdates());
-
-        // layout position 2 and clear mStructureChanged
-        mRecyclerView.scrollToPosition(2);
-        layout(200, 200);
-        mRecyclerView.scrollToPosition(0);
-        layout(200, 200);
-        assertFalse(innerView.mState.mStructureChanged);
-        assertFalse(innerView.hasPendingAdapterUpdates());
-
-        // notify change on the cached innerView.
-        innerAdapter.notifyDataSetChanged();
-        assertTrue(innerView.mState.mStructureChanged);
-        assertTrue(innerView.hasPendingAdapterUpdates());
-
-        // prefetch again
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        ((LinearLayoutManager) innerView.getLayoutManager())
-                .setInitialPrefetchItemCount(2);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(innerView, 0, 1);
-
-        // The re-prefetch is not necessary get the same inner view but we will get same Adapter
-        holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
-        innerView = holder.mNestedRecyclerView.get();
-        assertSame(innerAdapter, innerView.getAdapter());
-        // prefetch shouldn't clear the mStructureChanged flag
-        assertTrue(innerView.mState.mStructureChanged);
-        assertTrue(innerView.hasPendingAdapterUpdates());
-    }
-
-    @Test
-    public void nestedPrefetchReverseInner() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        mRecyclerView.setAdapter(new OuterAdapter(/* reverseInner = */ true));
-
-        layout(200, 200);
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
-
-        // anchor from right side, should see last two positions
-        CacheUtils.verifyCacheContainsPrefetchedPositions(holder.mNestedRecyclerView.get(), 18, 19);
-    }
-
-    @Test
-    public void nestedPrefetchOffset() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        mRecyclerView.setAdapter(new OuterAdapter());
-
-        layout(200, 200);
-
-        // Scroll top row by 5.5 items, verify positions 5, 6, 7 showing
-        RecyclerView inner = (RecyclerView) mRecyclerView.getChildAt(0);
-        inner.scrollBy(550, 0);
-        assertEquals(5, RecyclerView.getChildViewHolderInt(inner.getChildAt(0)).mPosition);
-        assertEquals(6, RecyclerView.getChildViewHolderInt(inner.getChildAt(1)).mPosition);
-        assertEquals(7, RecyclerView.getChildViewHolderInt(inner.getChildAt(2)).mPosition);
-
-        // scroll down 4 rows, up 3 so row 0 is adjacent but uncached
-        mRecyclerView.scrollBy(0, 400);
-        mRecyclerView.scrollBy(0, -300);
-
-        // top row no longer present
-        CacheUtils.verifyCacheDoesNotContainPositions(mRecyclerView, 0);
-
-        // prefetch upward, and validate that we've gotten the top row with correct offsets
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, -1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        inner = (RecyclerView) CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 0).itemView;
-        CacheUtils.verifyCacheContainsPrefetchedPositions(inner, 5, 6);
-
-        // prefetch 4
-        ((LinearLayoutManager) inner.getLayoutManager()).setInitialPrefetchItemCount(4);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(inner, 5, 6, 7, 8);
-    }
-
-    @Test
-    public void nestedPrefetchNotReset() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        OuterAdapter outerAdapter = new OuterAdapter();
-        mRecyclerView.setAdapter(outerAdapter);
-
-        layout(200, 200);
-
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-
-        // prefetch row 2, items 0 & 1
-        assertEquals(0, outerAdapter.mAdapters.get(2).mItemsBound);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
-        RecyclerView innerRecyclerView = holder.mNestedRecyclerView.get();
-
-        assertNotNull(innerRecyclerView);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(innerRecyclerView, 0, 1);
-        assertEquals(2, outerAdapter.mAdapters.get(2).mItemsBound);
-
-        // new row comes on, triggers layout...
-        mRecyclerView.scrollBy(0, 50);
-
-        // ... which shouldn't require new items to be bound,
-        // as prefetch has already done that work
-        assertEquals(2, outerAdapter.mAdapters.get(2).mItemsBound);
-    }
-
-    static void validateRvChildrenValid(RecyclerView recyclerView, int childCount) {
-        ChildHelper childHelper = recyclerView.mChildHelper;
-
-        assertEquals(childCount, childHelper.getUnfilteredChildCount());
-        for (int i = 0; i < childHelper.getUnfilteredChildCount(); i++) {
-            assertFalse(recyclerView.getChildViewHolder(
-                    childHelper.getUnfilteredChildAt(i)).isInvalid());
-        }
-    }
-
-    @Test
-    public void nestedPrefetchCacheNotTouched() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        OuterAdapter outerAdapter = new OuterAdapter();
-        mRecyclerView.setAdapter(outerAdapter);
-
-        layout(200, 200);
-        mRecyclerView.scrollBy(0, 100);
-
-        // item 0 is cached
-        assertEquals(2, outerAdapter.mAdapters.get(0).mItemsBound);
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 0);
-        validateRvChildrenValid(holder.mNestedRecyclerView.get(), 2);
-
-        // try and prefetch it
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, -1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        // make sure cache's inner items aren't rebound unnecessarily
-        assertEquals(2, outerAdapter.mAdapters.get(0).mItemsBound);
-        validateRvChildrenValid(holder.mNestedRecyclerView.get(), 2);
-    }
-
-    @Test
-    public void nestedRemoveAnimatingView() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        OuterAdapter outerAdapter = new OuterAdapter(false, 1);
-        mRecyclerView.setAdapter(outerAdapter);
-        mRecyclerView.getItemAnimator().setAddDuration(TimeUnit.MILLISECONDS.toNanos(30));
-
-        layout(200, 200);
-
-        // Insert 3 items - only first one in viewport, so only it animates
-        for (int i = 0; i < 3; i++) {
-            outerAdapter.addItem();
-        }
-        layout(200, 200); // layout again to kick off animation
-
-
-        // item 1 is animating, so scroll it out of viewport
-        mRecyclerView.scrollBy(0, 200);
-
-        // 2 items attached, 1 cached (pos 0), but item animating pos 1 not accounted for...
-        assertEquals(2, mRecyclerView.mChildHelper.getUnfilteredChildCount());
-        assertEquals(1, mRecycler.mCachedViews.size());
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 0);
-        assertEquals(0, mRecyclerView.getRecycledViewPool().getRecycledViewCount(0));
-
-        // until animation ends
-        mRecyclerView.getItemAnimator().endAnimations();
-        assertEquals(2, mRecyclerView.mChildHelper.getUnfilteredChildCount());
-        assertEquals(2, mRecycler.mCachedViews.size());
-        CacheUtils.verifyCacheContainsPositions(mRecyclerView, 0, 1);
-        assertEquals(0, mRecyclerView.getRecycledViewPool().getRecycledViewCount(0));
-
-        for (RecyclerView.ViewHolder viewHolder : mRecycler.mCachedViews) {
-            assertNotNull(viewHolder.mNestedRecyclerView);
-        }
-    }
-
-    @Test
-    public void nestedExpandCacheCorrectly() {
-        final int DEFAULT_CACHE_SIZE = RecyclerView.Recycler.DEFAULT_CACHE_SIZE;
-
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        OuterAdapter outerAdapter = new OuterAdapter();
-        mRecyclerView.setAdapter(outerAdapter);
-
-        layout(200, 200);
-
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        // after initial prefetch, view cache max expanded by number of inner items prefetched (2)
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
-        RecyclerView innerView = holder.mNestedRecyclerView.get();
-        assertTrue(innerView.getLayoutManager().mPrefetchMaxObservedInInitialPrefetch);
-        assertEquals(2, innerView.getLayoutManager().mPrefetchMaxCountObserved);
-        assertEquals(2 + DEFAULT_CACHE_SIZE, innerView.mRecycler.mViewCacheMax);
-
-        try {
-            // Note: As a hack, we not only must manually dispatch attachToWindow(), but we
-            // also have to be careful to call innerView.mGapWorker below. mRecyclerView.mGapWorker
-            // is registered to the wrong thread, since @setup is called on a different thread
-            // from @Test. Assert this, so this test can be fixed when setup == test thread.
-            assertEquals(1, mRecyclerView.mGapWorker.mRecyclerViews.size());
-            assertFalse(innerView.isAttachedToWindow());
-            innerView.onAttachedToWindow();
-
-            // bring prefetch view into viewport, at which point it shouldn't have cache expanded...
-            mRecyclerView.scrollBy(0, 100);
-            assertFalse(innerView.getLayoutManager().mPrefetchMaxObservedInInitialPrefetch);
-            assertEquals(0, innerView.getLayoutManager().mPrefetchMaxCountObserved);
-            assertEquals(DEFAULT_CACHE_SIZE, innerView.mRecycler.mViewCacheMax);
-
-            // until a valid horizontal prefetch caches an item, and expands view count by one
-            innerView.mPrefetchRegistry.setPrefetchVector(1, 0);
-            innerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS); // NB: must be innerView.mGapWorker
-            assertFalse(innerView.getLayoutManager().mPrefetchMaxObservedInInitialPrefetch);
-            assertEquals(1, innerView.getLayoutManager().mPrefetchMaxCountObserved);
-            assertEquals(1 + DEFAULT_CACHE_SIZE, innerView.mRecycler.mViewCacheMax);
-        } finally {
-            if (innerView.isAttachedToWindow()) {
-                innerView.onDetachedFromWindow();
-            }
-        }
-    }
-
-    /**
-     * Similar to OuterAdapter above, but uses notifyDataSetChanged() instead of set/swapAdapter
-     * to update data for the inner RecyclerViews when containing ViewHolder is bound.
-     */
-    class OuterNotifyAdapter extends RecyclerView.Adapter<OuterNotifyAdapter.ViewHolder> {
-        private static final int OUTER_ITEM_COUNT = 10;
-
-        private boolean mReverseInner;
-
-        class ViewHolder extends RecyclerView.ViewHolder {
-            private final RecyclerView mRecyclerView;
-            private final InnerAdapter mAdapter;
-            ViewHolder(RecyclerView itemView) {
-                super(itemView);
-                mRecyclerView = itemView;
-                mAdapter = new InnerAdapter();
-                mRecyclerView.setAdapter(mAdapter);
-            }
-        }
-
-        ArrayList<Parcelable> mSavedStates = new ArrayList<>();
-        RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool();
-
-        OuterNotifyAdapter() {
-            this(false);
-        }
-
-        OuterNotifyAdapter(boolean reverseInner) {
-            mReverseInner = reverseInner;
-            for (int i = 0; i <= OUTER_ITEM_COUNT; i++) {
-                mSavedStates.add(null);
-            }
-        }
-
-        @Override
-        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            mRecyclerView.registerTimePassingMs(5);
-            RecyclerView rv = new RecyclerView(parent.getContext());
-            rv.setLayoutManager(new LinearLayoutManager(parent.getContext(),
-                    LinearLayoutManager.HORIZONTAL, mReverseInner));
-            rv.setRecycledViewPool(mSharedPool);
-            rv.setLayoutParams(new RecyclerView.LayoutParams(200, 100));
-            return new ViewHolder(rv);
-        }
-
-        @Override
-        public void onBindViewHolder(ViewHolder holder, int position) {
-            mRecyclerView.registerTimePassingMs(5);
-            // if we had actual data to put into our adapter, this is where we'd do it...
-
-            // ... then notify the adapter that it has new content:
-            holder.mAdapter.notifyDataSetChanged();
-
-            Parcelable savedState = mSavedStates.get(position);
-            if (savedState != null) {
-                holder.mRecyclerView.getLayoutManager().onRestoreInstanceState(savedState);
-                mSavedStates.set(position, null);
-            }
-        }
-
-        @Override
-        public void onViewRecycled(ViewHolder holder) {
-            if (holder.getAdapterPosition() >= 0) {
-                mSavedStates.set(holder.getAdapterPosition(),
-                        holder.mRecyclerView.getLayoutManager().onSaveInstanceState());
-            }
-        }
-
-        @Override
-        public int getItemCount() {
-            return OUTER_ITEM_COUNT;
-        }
-    }
-
-    @Test
-    public void nestedPrefetchDiscardStaleChildren() {
-        LinearLayoutManager llm = new LinearLayoutManager(getContext());
-        assertEquals(2, llm.getInitialPrefetchItemCount());
-
-        mRecyclerView.setLayoutManager(llm);
-        OuterNotifyAdapter outerAdapter = new OuterNotifyAdapter();
-        mRecyclerView.setAdapter(outerAdapter);
-
-        // zero cache, so item we prefetch can't already be ready
-        mRecyclerView.setItemViewCacheSize(0);
-
-        // layout 3 items, then resize to 2...
-        layout(200, 300);
-        layout(200, 200);
-
-        // so 1 item is evicted into the RecycledViewPool (bypassing cache)
-        assertEquals(1, mRecycler.mRecyclerPool.getRecycledViewCount(0));
-        assertEquals(0, mRecycler.mCachedViews.size());
-
-        // This is a simple imitation of other behavior (namely, varied types in the outer adapter)
-        // that results in the same initial state to test: items in the pool with attached children
-        for (RecyclerView.ViewHolder holder : mRecycler.mRecyclerPool.mScrap.get(0).mScrapHeap) {
-            // verify that children are attached and valid, since the RVs haven't been rebound
-            assertNotNull(holder.mNestedRecyclerView);
-            assertFalse(holder.mNestedRecyclerView.get().mDataSetHasChangedAfterLayout);
-            validateRvChildrenValid(holder.mNestedRecyclerView.get(), 2);
-        }
-
-        // prefetch the outer item bind, but without enough time to do any inner binds
-        final long deadlineNs = mRecyclerView.getNanoTime() + TimeUnit.MILLISECONDS.toNanos(9);
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(deadlineNs);
-
-        // 2 is prefetched without children
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 2);
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 2);
-        assertNotNull(holder);
-        assertNotNull(holder.mNestedRecyclerView);
-        assertEquals(0, holder.mNestedRecyclerView.get().mChildHelper.getUnfilteredChildCount());
-        assertEquals(0, holder.mNestedRecyclerView.get().mRecycler.mCachedViews.size());
-
-        // but if we give it more time to bind items, it'll now acquire its inner items
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-        CacheUtils.verifyCacheContainsPrefetchedPositions(holder.mNestedRecyclerView.get(), 0, 1);
-    }
-
-
-    @Test
-    public void nestedPrefetchDiscardStalePrefetch() {
-        mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
-        OuterNotifyAdapter outerAdapter = new OuterNotifyAdapter();
-        mRecyclerView.setAdapter(outerAdapter);
-
-        // zero cache, so item we prefetch can't already be ready
-        mRecyclerView.setItemViewCacheSize(0);
-
-        // layout as 2x2, starting on row index 2, with empty cache
-        layout(200, 200);
-        mRecyclerView.scrollBy(0, 200);
-
-        // no views cached, or previously used (so we can trust number in mItemsBound)
-        mRecycler.mRecyclerPool.clear();
-        assertEquals(0, mRecycler.mRecyclerPool.getRecycledViewCount(0));
-        assertEquals(0, mRecycler.mCachedViews.size());
-
-        // prefetch the outer item and its inner children
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        // 4 is prefetched with 2 inner children, first two binds
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 4);
-        RecyclerView.ViewHolder holder = CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 4);
-        assertNotNull(holder);
-        assertNotNull(holder.mNestedRecyclerView);
-        RecyclerView innerRecyclerView = holder.mNestedRecyclerView.get();
-        assertEquals(0, innerRecyclerView.mChildHelper.getUnfilteredChildCount());
-        assertEquals(2, innerRecyclerView.mRecycler.mCachedViews.size());
-        assertEquals(2, ((InnerAdapter) innerRecyclerView.getAdapter()).mItemsBound);
-
-        // notify data set changed, so any previously prefetched items invalid, and re-prefetch
-        innerRecyclerView.getAdapter().notifyDataSetChanged();
-        mRecyclerView.mPrefetchRegistry.setPrefetchVector(0, 1);
-        mRecyclerView.mGapWorker.prefetch(RecyclerView.FOREVER_NS);
-
-        // 4 is prefetched again...
-        CacheUtils.verifyCacheContainsPrefetchedPositions(mRecyclerView, 4);
-
-        // reusing the same instance with 2 inner children...
-        assertSame(holder, CacheUtils.peekAtCachedViewForPosition(mRecyclerView, 4));
-        assertSame(innerRecyclerView, holder.mNestedRecyclerView.get());
-        assertEquals(0, innerRecyclerView.mChildHelper.getUnfilteredChildCount());
-        assertEquals(2, innerRecyclerView.mRecycler.mCachedViews.size());
-
-        // ... but there should be two new binds
-        assertEquals(4, ((InnerAdapter) innerRecyclerView.getAdapter()).mItemsBound);
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java
deleted file mode 100644
index 584a116..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFastScrollerTest.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.RecyclerView.VERTICAL;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.app.Activity;
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.graphics.drawable.StateListDrawable;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.recyclerview.R;
-import android.support.v7.util.TouchUtils;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.TextView;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class RecyclerViewFastScrollerTest extends BaseRecyclerViewInstrumentationTest {
-    private static final int FLAG_HORIZONTAL = 1;
-    private static final int FLAG_VERTICAL = 1 << 1;
-    private int mScrolledByY = -1000;
-    private int mScrolledByX = -1000;
-    private FastScroller mScroller;
-    private boolean mHide;
-
-    private void setContentView(final int layoutId) throws Throwable {
-        final Activity activity = mActivityRule.getActivity();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                activity.setContentView(layoutId);
-            }
-        });
-    }
-
-    @Test
-    public void xml_fastScrollEnabled_startsInvisibleAndAtTop() throws Throwable {
-        arrangeWithXml();
-
-        assertTrue("Expected centerY to start == 0", mScroller.mVerticalThumbCenterY == 0);
-        assertFalse("Expected thumb to start invisible", mScroller.isVisible());
-    }
-
-    @Test
-    public void scrollBy_displaysAndMovesFastScrollerThumb() throws Throwable {
-        arrangeWithXml();
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.scrollBy(0, 400);
-            }
-        });
-
-        assertTrue("Expected centerY to be > 0" + mScroller.mVerticalThumbCenterY,
-                mScroller.mVerticalThumbCenterY > 0);
-        assertTrue("Expected thumb to be visible", mScroller.isVisible());
-    }
-
-    @Test
-    public void ui_dragsThumb_scrollsRecyclerView() throws Throwable {
-        arrangeWithXml();
-
-        // RecyclerView#scrollBy(int, int) used to cause the scroller thumb to show up.
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.scrollBy(0, 1);
-                mRecyclerView.scrollBy(0, -1);
-            }
-        });
-        int[] absoluteCoords = new int[2];
-        mRecyclerView.getLocationOnScreen(absoluteCoords);
-        TouchUtils.drag(InstrumentationRegistry.getInstrumentation(), mRecyclerView.getWidth() - 10,
-                mRecyclerView.getWidth() - 10, mScroller.mVerticalThumbCenterY + absoluteCoords[1],
-                mRecyclerView.getHeight() + absoluteCoords[1], 100);
-
-        assertTrue("Expected dragging thumb to move recyclerView",
-                mRecyclerView.computeVerticalScrollOffset() > 0);
-    }
-
-    @Test
-    public void properCleanUp() throws Throwable {
-        mRecyclerView = new RecyclerView(getActivity());
-        final Activity activity = mActivityRule.getActivity();
-        final CountDownLatch latch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                activity.setContentView(
-                        android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
-                mRecyclerView = (RecyclerView) activity.findViewById(
-                        android.support.v7.recyclerview.test.R.id.recycler_view);
-                LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext());
-                layout.setOrientation(VERTICAL);
-                mRecyclerView.setLayoutManager(layout);
-                mRecyclerView.setAdapter(new TestAdapter(50));
-                Resources res = getActivity().getResources();
-                mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable(
-                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
-                        res.getDrawable(
-                                android.support.v7.recyclerview.test.R.drawable
-                                        .fast_scroll_track_drawable),
-                        (StateListDrawable) res.getDrawable(
-                                android.support.v7.recyclerview.test.R.drawable
-                                        .fast_scroll_thumb_drawable),
-                        res.getDrawable(
-                                android.support.v7.recyclerview.test.R.drawable
-                                        .fast_scroll_track_drawable),
-                        res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
-                        res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
-                        res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) {
-                    @Override
-                    public void show() {
-                        // Overriden to avoid animation calls in instrumentation thread
-                    }
-
-                    @Override
-                    public void hide(int duration) {
-                        latch.countDown();
-                        mHide = true;
-                    }
-                };
-
-            }
-        });
-        waitForIdleScroll(mRecyclerView);
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.scrollBy(0, 400);
-                mScroller.attachToRecyclerView(new RecyclerView(getActivity()));
-            }
-        });
-        assertFalse(latch.await(2, TimeUnit.SECONDS));
-        assertFalse(mHide);
-    }
-
-    @Test
-    public void inflationTest() throws Throwable {
-        setContentView(android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
-        getInstrumentation().waitForIdleSync();
-        RecyclerView view = (RecyclerView) getActivity().findViewById(
-                android.support.v7.recyclerview.test.R.id.recycler_view);
-        assertTrue(view.getItemDecorationCount() == 1);
-        assertTrue(view.getItemDecorationAt(0) instanceof FastScroller);
-        FastScroller scroller = (FastScroller) view.getItemDecorationAt(0);
-        assertNotNull(scroller.getHorizontalThumbDrawable());
-        assertNotNull(scroller.getHorizontalTrackDrawable());
-        assertNotNull(scroller.getVerticalThumbDrawable());
-        assertNotNull(scroller.getVerticalTrackDrawable());
-    }
-
-    @Test
-    public void removeFastScrollerSuccessful() throws Throwable {
-        setContentView(android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv);
-        getInstrumentation().waitForIdleSync();
-        final RecyclerView view = (RecyclerView) getActivity().findViewById(
-                android.support.v7.recyclerview.test.R.id.recycler_view);
-        assertTrue(view.getItemDecorationCount() == 1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                view.removeItemDecorationAt(0);
-                assertTrue(view.getItemDecorationCount() == 0);
-            }
-        });
-    }
-
-    @UiThreadTest
-    @Test
-    public void initWithBadDrawables() throws Throwable {
-        arrangeWithCode();
-
-        Throwable exception = null;
-        try {
-            mRecyclerView.initFastScroller(null, null, null, null);
-        } catch (Throwable t) {
-            exception = t;
-        }
-        assertTrue(exception instanceof IllegalArgumentException);
-    }
-
-    @Test
-    public void verticalScrollUpdatesFastScrollThumb() throws Throwable {
-        scrollUpdatesFastScrollThumb(FLAG_VERTICAL);
-    }
-
-    @Test
-    public void horizontalScrollUpdatesFastScrollThumb() throws Throwable {
-        scrollUpdatesFastScrollThumb(FLAG_HORIZONTAL);
-    }
-
-    private void scrollUpdatesFastScrollThumb(int direction) throws Throwable {
-        arrangeWithCode();
-        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250,
-                direction == FLAG_VERTICAL ? 250 : 0);
-        if (direction == FLAG_VERTICAL) {
-            assertTrue("Expected 250 for centerY, got " + mScroller.mVerticalThumbCenterY,
-                    mScroller.mVerticalThumbCenterY == 250);
-            assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight,
-                    mScroller.mVerticalThumbHeight == 250);
-        } else if (direction == FLAG_HORIZONTAL) {
-            assertTrue("Expected 250 for centerX, got " + mScroller.mHorizontalThumbCenterX,
-                    mScroller.mHorizontalThumbCenterX == 250);
-            assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth,
-                    mScroller.mHorizontalThumbWidth == 250);
-        }
-        assertTrue(mScroller.isVisible());
-
-        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 42,
-                direction == FLAG_VERTICAL ? 42 : 0);
-        if (direction == FLAG_VERTICAL) {
-            assertTrue("Expected 146 for centerY, got " + mScroller.mVerticalThumbCenterY,
-                    mScroller.mVerticalThumbCenterY == 146);
-            assertTrue("Expected 250 for thumb height, got " + mScroller.mVerticalThumbHeight,
-                    mScroller.mVerticalThumbHeight == 250);
-        } else if (direction == FLAG_HORIZONTAL) {
-            assertTrue("Expected 146 for centerX, got " + mScroller.mHorizontalThumbCenterX,
-                    mScroller.mHorizontalThumbCenterX == 146);
-            assertTrue("Expected 250 for thumb width, got " + mScroller.mHorizontalThumbWidth,
-                    mScroller.mHorizontalThumbWidth == 250);
-        }
-        assertTrue(mScroller.isVisible());
-    }
-
-    @Test
-    public void draggingDoesNotTriggerFastScrollIfNotInThumb() throws Throwable {
-        arrangeWithCode();
-        mScroller.updateScrollPosition(0, 250);
-        final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN, 250, 250,
-                0);
-        assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent));
-        final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE, 250, 275,
-                0);
-        assertFalse(mScroller.onInterceptTouchEvent(mRecyclerView, moveEvent));
-    }
-
-    @Test
-    public void verticalDraggingFastScrollThumbDoesActualScrolling() throws Throwable {
-        draggingFastScrollThumbDoesActualScrolling(FLAG_VERTICAL);
-    }
-
-    @Test
-    public void horizontalDraggingFastScrollThumbDoesActualScrolling() throws Throwable {
-        draggingFastScrollThumbDoesActualScrolling(FLAG_HORIZONTAL);
-    }
-
-    private void draggingFastScrollThumbDoesActualScrolling(int direction) throws Throwable {
-        arrangeWithCode();
-        mScroller.updateScrollPosition(direction == FLAG_VERTICAL ? 0 : 250,
-                direction == FLAG_VERTICAL ? 250 : 0);
-        final MotionEvent downEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_DOWN,
-                direction == FLAG_VERTICAL ? 500 : 250, direction == FLAG_VERTICAL ? 250 : 500, 0);
-        assertTrue(mScroller.onInterceptTouchEvent(mRecyclerView, downEvent));
-        assertTrue(mScroller.isDragging());
-        final MotionEvent moveEvent = MotionEvent.obtain(10, 10, MotionEvent.ACTION_MOVE,
-                direction == FLAG_VERTICAL ? 500 : 221, direction == FLAG_VERTICAL ? 221 : 500, 0);
-        mScroller.onTouchEvent(mRecyclerView, moveEvent);
-        if (direction == FLAG_VERTICAL) {
-            assertTrue("Expected to get -29, but got " + mScrolledByY, mScrolledByY == -29);
-        } else {
-            assertTrue("Expected to get -29, but got " + mScrolledByX, mScrolledByX == -29);
-        }
-    }
-
-    private void arrangeWithXml() throws Throwable {
-
-        final TestActivity activity = mActivityRule.getActivity();
-        final TestedFrameLayout testedFrameLayout = activity.getContainer();
-
-        RecyclerView recyclerView = (RecyclerView) LayoutInflater.from(activity).inflate(
-                android.support.v7.recyclerview.test.R.layout.fast_scrollbar_test_rv,
-                testedFrameLayout,
-                false);
-
-        LinearLayoutManager layout = new LinearLayoutManager(activity.getBaseContext());
-        layout.setOrientation(VERTICAL);
-        recyclerView.setLayoutManager(layout);
-
-        recyclerView.setAdapter(new TestAdapter(50));
-
-        mScroller = (FastScroller) recyclerView.getItemDecorationAt(0);
-
-        testedFrameLayout.expectDraws(1);
-        setRecyclerView(recyclerView);
-        testedFrameLayout.waitForDraw(2);
-    }
-
-    private void arrangeWithCode() throws Exception {
-        final int width = 500;
-        final int height = 500;
-
-        mRecyclerView = new RecyclerView(getActivity()) {
-            @Override
-            public int computeVerticalScrollRange() {
-                return 1000;
-            }
-
-            @Override
-            public int computeVerticalScrollExtent() {
-                return 500;
-            }
-
-            @Override
-            public int computeVerticalScrollOffset() {
-                return 250;
-            }
-
-            @Override
-            public int computeHorizontalScrollRange() {
-                return 1000;
-            }
-
-            @Override
-            public int computeHorizontalScrollExtent() {
-                return 500;
-            }
-
-            @Override
-            public int computeHorizontalScrollOffset() {
-                return 250;
-            }
-
-            @Override
-            public void scrollBy(int x, int y) {
-                mScrolledByY = y;
-                mScrolledByX = x;
-            }
-        };
-        mRecyclerView.setAdapter(new TestAdapter(50));
-        mRecyclerView.measure(
-                View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
-                View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));
-        mRecyclerView.layout(0, 0, width, height);
-
-        Resources res = getActivity().getResources();
-        mScroller = new FastScroller(mRecyclerView, (StateListDrawable) res.getDrawable(
-                android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
-                res.getDrawable(
-                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_track_drawable),
-                (StateListDrawable) res.getDrawable(
-                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_thumb_drawable),
-                res.getDrawable(
-                        android.support.v7.recyclerview.test.R.drawable.fast_scroll_track_drawable),
-                res.getDimensionPixelSize(R.dimen.fastscroll_default_thickness),
-                res.getDimensionPixelSize(R.dimen.fastscroll_minimum_range),
-                res.getDimensionPixelOffset(R.dimen.fastscroll_margin)) {
-            @Override
-            public void show() {
-                // Overriden to avoid animation calls in instrumentation thread
-            }
-
-            @Override
-            public void hide(int duration) {
-                mHide = true;
-            }
-        };
-        mRecyclerView.mEnableFastScroller = true;
-
-        // Draw it once so height/width gets updated
-        mScroller.onDrawOver(null, mRecyclerView, null);
-    }
-
-    private static class TestAdapter extends RecyclerView.Adapter {
-        private int mItemCount;
-
-        public static class ViewHolder extends RecyclerView.ViewHolder {
-            public TextView mTextView;
-
-            ViewHolder(TextView v) {
-                super(v);
-                mTextView = v;
-            }
-
-            @Override
-            public String toString() {
-                return super.toString() + " '" + mTextView.getText();
-            }
-        }
-
-        TestAdapter(int itemCount) {
-            mItemCount = itemCount;
-        }
-
-        @Override
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
-                int viewType) {
-            final ViewHolder h = new ViewHolder(new TextView(parent.getContext()));
-            h.mTextView.setMinimumHeight(128);
-            h.mTextView.setPadding(20, 0, 20, 0);
-            h.mTextView.setFocusable(true);
-            h.mTextView.setBackgroundColor(Color.BLUE);
-            RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(
-                    LayoutParams.MATCH_PARENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-            lp.leftMargin = 10;
-            lp.rightMargin = 5;
-            lp.topMargin = 20;
-            lp.bottomMargin = 15;
-            h.mTextView.setLayoutParams(lp);
-            return h;
-        }
-
-        @Override
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-            holder.itemView.setTag("pos " + position);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mItemCount;
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
deleted file mode 100644
index 0354d53..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewFocusRecoveryTest.java
+++ /dev/null
@@ -1,933 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.support.v7.widget;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.filters.MediumTest;
-import android.support.v7.recyclerview.test.R;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * This class only tests the RV's focus recovery logic as focus moves between two views that
- * represent the same item in the adapter. Keeping a focused view visible is up-to-the
- * LayoutManager and all FW LayoutManagers already have tests for it.
- */
-@MediumTest
-@RunWith(Parameterized.class)
-public class RecyclerViewFocusRecoveryTest extends BaseRecyclerViewInstrumentationTest {
-    TestLayoutManager mLayoutManager;
-    TestAdapter mAdapter;
-    int mChildCount = 10;
-
-    // Parameter indicating whether RV's children are simple views (false) or ViewGroups (true).
-    private final boolean mFocusOnChild;
-    // Parameter indicating whether RV recovers focus after layout is finished.
-    private final boolean mDisableRecovery;
-    // Parameter indicating whether animation is enabled for the ViewHolder items.
-    private final boolean mDisableAnimation;
-
-    @Parameterized.Parameters(name = "focusSubChild:{0},disableRecovery:{1},"
-            + "disableAnimation:{2}")
-    public static List<Object[]> getParams() {
-        return Arrays.asList(
-                new Object[]{false, false, true},
-                new Object[]{true, false, true},
-                new Object[]{false, true, true},
-                new Object[]{true, true, true},
-                new Object[]{false, false, false},
-                new Object[]{true, false, false},
-                new Object[]{false, true, false},
-                new Object[]{true, true, false}
-        );
-    }
-
-    public RecyclerViewFocusRecoveryTest(boolean focusOnChild, boolean disableRecovery,
-                                         boolean disableAnimation) {
-        super(false);
-        mFocusOnChild = focusOnChild;
-        mDisableRecovery = disableRecovery;
-        mDisableAnimation = disableAnimation;
-    }
-
-    void setupBasic() throws Throwable {
-        setupBasic(false);
-    }
-
-    void setupBasic(boolean hasStableIds) throws Throwable {
-        TestAdapter adapter = new FocusTestAdapter(mChildCount);
-        adapter.setHasStableIds(hasStableIds);
-        setupBasic(adapter, null);
-    }
-
-    void setupBasic(TestLayoutManager layoutManager) throws Throwable {
-        setupBasic(null, layoutManager);
-    }
-
-    void setupBasic(TestAdapter adapter) throws Throwable {
-        setupBasic(adapter, null);
-    }
-
-    void setupBasic(@Nullable TestAdapter adapter, @Nullable TestLayoutManager layoutManager)
-            throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        if (layoutManager == null) {
-            layoutManager = new FocusLayoutManager();
-        }
-
-        if (adapter == null) {
-            adapter = new FocusTestAdapter(mChildCount);
-        }
-        mLayoutManager = layoutManager;
-        mAdapter = adapter;
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(mLayoutManager);
-        recyclerView.setPreserveFocusAfterLayout(!mDisableRecovery);
-        if (mDisableAnimation) {
-            recyclerView.setItemAnimator(null);
-        }
-        mLayoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        mLayoutManager.waitForLayout(1);
-    }
-
-    @Test
-    public void testFocusRecoveryInChange() throws Throwable {
-        setupBasic();
-        mLayoutManager.setSupportsPredictive(true);
-        final RecyclerView.ViewHolder oldVh = focusVh(3);
-
-        mLayoutManager.expectLayouts(mDisableAnimation ? 1 : 2);
-        mAdapter.changeAndNotify(3, 1);
-        mLayoutManager.waitForLayout(2);
-        if (!mDisableAnimation) {
-            // waiting for RV's ItemAnimator to finish the animation of the removed item
-            waitForAnimations(2);
-        }
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3);
-                assertFocusTransition(oldVh, newVh, false);
-
-            }
-        });
-    }
-
-    @Test
-    public void testFocusRecoveryAfterRemovingFocusedChild() throws Throwable {
-        setupBasic(true);
-        FocusViewHolder fvh = cast(focusVh(4));
-
-        assertThat("test sanity", fvh, notNullValue());
-        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
-
-        assertThat("RV should pass the focus down to its children",
-                mRecyclerView.isFocused(), is(false));
-        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
-                is(true));
-        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
-                is(true));
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // removing focused child
-                mAdapter.mItems.remove(4);
-                mAdapter.notifyItemRemoved(4);
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        if (!mDisableAnimation) {
-            // waiting for RV's ItemAnimator to finish the animation of the removed item
-            waitForAnimations(2);
-        }
-        assertThat("RV should have " + (mChildCount - 1) + " instead of "
-                        + mRecyclerView.getChildCount() + " children",
-                mChildCount - 1, is(mRecyclerView.getChildCount()));
-        assertFocusAfterLayout(4, 0);
-    }
-
-    @Test
-    public void testFocusRecoveryAfterMovingFocusedChild() throws Throwable {
-        setupBasic(true);
-        FocusViewHolder fvh = cast(focusVh(3));
-
-        assertThat("test sanity", fvh, notNullValue());
-        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
-
-        assertThat("RV should pass the focus down to its children",
-                mRecyclerView.isFocused(), is(false));
-        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
-                is(true));
-        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
-                is(true));
-
-        mLayoutManager.expectLayouts(1);
-        mAdapter.moveAndNotify(3, 1);
-        mLayoutManager.waitForLayout(1);
-        if (!mDisableAnimation) {
-            // waiting for RV's ItemAnimator to finish the animation of the removed item
-            waitForAnimations(2);
-        }
-        assertFocusAfterLayout(1, 1);
-    }
-
-    @Test
-    public void testFocusRecoveryAfterRemovingLastChild() throws Throwable {
-        mChildCount = 1;
-        setupBasic(true);
-        FocusViewHolder fvh = cast(focusVh(0));
-
-        assertThat("test sanity", fvh, notNullValue());
-        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
-
-        assertThat("RV should pass the focus down to its children",
-                mRecyclerView.isFocused(), is(false));
-        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
-                is(true));
-        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
-                is(true));
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // removing focused child
-                mAdapter.mItems.remove(0);
-                mAdapter.notifyDataSetChanged();
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        if (!mDisableAnimation) {
-            // waiting for RV's ItemAnimator to finish the animation of the removed item
-            waitForAnimations(2);
-        }
-        assertThat("RV should have " + (mChildCount - 1) + " instead of "
-                        + mRecyclerView.getChildCount() + " children",
-                mChildCount - 1, is(mRecyclerView.getChildCount()));
-        assertFocusAfterLayout(-1, -1);
-    }
-
-    @Test
-    public void testFocusRecoveryAfterAddingFirstChild() throws Throwable {
-        mChildCount = 0;
-        setupBasic(true);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                requestFocusOnRV();
-            }
-        });
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                // adding first child
-                mAdapter.mItems.add(0, new Item(0, TestAdapter.DEFAULT_ITEM_PREFIX));
-                mAdapter.notifyDataSetChanged();
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        if (!mDisableAnimation) {
-            // waiting for RV's ItemAnimator to finish the animation of the removed item
-            waitForAnimations(2);
-        }
-        assertFocusAfterLayout(0, -1);
-    }
-
-    @Test
-    public void testFocusRecoveryAfterChangingFocusableFlag() throws Throwable {
-        setupBasic(true);
-        FocusViewHolder fvh = cast(focusVh(6));
-
-        assertThat("test sanity", fvh, notNullValue());
-        assertThat("RV should have focus", mRecyclerView.hasFocus(), is(true));
-
-        assertThat("RV should pass the focus down to its children",
-                mRecyclerView.isFocused(), is(false));
-        assertThat("Viewholder did not receive focus", fvh.itemView.hasFocus(),
-                is(true));
-        assertThat("Viewholder is not focused", fvh.getViewToFocus().isFocused(),
-                is(true));
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Item item = mAdapter.mItems.get(6);
-                item.setFocusable(false);
-                mAdapter.notifyItemChanged(6);
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        if (!mDisableAnimation) {
-            waitForAnimations(2);
-        }
-        FocusViewHolder newVh = cast(mRecyclerView.findViewHolderForAdapterPosition(6));
-        assertThat("VH should no longer be focusable", newVh.getViewToFocus().isFocusable(),
-                is(false));
-        assertFocusAfterLayout(7, 0);
-    }
-
-    @Test
-    public void testFocusRecoveryBeforeLayoutWithFocusBefore() throws Throwable {
-        testFocusRecoveryBeforeLayout(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-    }
-
-    @Test
-    public void testFocusRecoveryBeforeLayoutWithFocusAfter() throws Throwable {
-        testFocusRecoveryBeforeLayout(ViewGroup.FOCUS_AFTER_DESCENDANTS);
-    }
-
-    @Test
-    public void testFocusRecoveryBeforeLayoutWithFocusBlocked() throws Throwable {
-        testFocusRecoveryBeforeLayout(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-    }
-
-    @Test
-    public void testFocusRecoveryDuringLayoutWithFocusBefore() throws Throwable {
-        testFocusRecoveryDuringLayout(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-    }
-
-    @Test
-    public void testFocusRecoveryDuringLayoutWithFocusAfter() throws Throwable {
-        testFocusRecoveryDuringLayout(ViewGroup.FOCUS_AFTER_DESCENDANTS);
-    }
-
-    @Test
-    public void testFocusRecoveryDuringLayoutWithFocusBlocked() throws Throwable {
-        testFocusRecoveryDuringLayout(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-    }
-
-    /**
-     * Tests whether the focus is correctly recovered when requestFocus on RV is called before
-     * laying out the children.
-     * @throws Throwable
-     */
-    private void testFocusRecoveryBeforeLayout(int descendantFocusability) throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setDescendantFocusability(descendantFocusability);
-        mLayoutManager = new FocusLayoutManager();
-        mAdapter = new FocusTestAdapter(10);
-        recyclerView.setLayoutManager(mLayoutManager);
-        recyclerView.setPreserveFocusAfterLayout(!mDisableRecovery);
-        if (mDisableAnimation) {
-            recyclerView.setItemAnimator(null);
-        }
-        setRecyclerView(recyclerView);
-        assertThat("RV should always be focusable", mRecyclerView.isFocusable(), is(true));
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                requestFocusOnRV();
-                mRecyclerView.setAdapter(mAdapter);
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        assertFocusAfterLayout(0, -1);
-    }
-
-    /**
-     * Tests whether the focus is correctly recovered when requestFocus on RV is called during
-     * laying out the children.
-     * @throws Throwable
-     */
-    private void testFocusRecoveryDuringLayout(int descendantFocusability) throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setDescendantFocusability(descendantFocusability);
-        mLayoutManager = new FocusLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                requestFocusOnRV();
-            }
-        };
-        mAdapter = new FocusTestAdapter(10);
-        recyclerView.setAdapter(mAdapter);
-        recyclerView.setLayoutManager(mLayoutManager);
-        if (mDisableAnimation) {
-            recyclerView.setItemAnimator(null);
-        }
-        recyclerView.setPreserveFocusAfterLayout(!mDisableRecovery);
-        mLayoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        mLayoutManager.waitForLayout(1);
-        assertFocusAfterLayout(0, -1);
-    }
-
-    private void requestFocusOnRV() {
-        assertThat("RV initially has no focus", mRecyclerView.hasFocus(), is(false));
-        assertThat("RV initially is not focused", mRecyclerView.isFocused(), is(false));
-        mRecyclerView.requestFocus();
-        String msg = !mRecyclerView.isComputingLayout() ? " before laying out the children"
-                : " during laying out the children";
-        assertThat("RV should have focus after calling requestFocus()" + msg,
-                mRecyclerView.hasFocus(), is(true));
-        assertThat("RV after calling requestFocus() should become focused" + msg,
-                mRecyclerView.isFocused(), is(true));
-    }
-
-    /**
-     * Asserts whether RV and one of its children have the correct focus flags after the layout is
-     * complete. This is normally called once the RV layout is complete after initiating
-     * notifyItemChanged.
-     * @param focusedChildIndexWhenRecoveryEnabled
-     * This index is relevant when mDisableRecovery is false. In that case, it refers to the index
-     * of the child that should have focus if the ancestors allow passing down the focus. -1
-     * indicates none of the children can receive focus even if the ancestors don't block focus, in
-     * which case RV holds and becomes focused.
-     * @param focusedChildIndexWhenRecoveryDisabled
-     * This index is relevant when mDisableRecovery is true. In that case, it refers to the index
-     * of the child that should have focus if the ancestors allow passing down the focus. -1
-     * indicates none of the children can receive focus even if the ancestors don't block focus, in
-     * which case RV holds and becomes focused.
-     */
-    private void assertFocusAfterLayout(int focusedChildIndexWhenRecoveryEnabled,
-                                        int focusedChildIndexWhenRecoveryDisabled) {
-        if (mDisableAnimation && mDisableRecovery) {
-            // This case is not quite handled properly at the moment. For now, RV may become focused
-            // without re-delivering the focus down to the children. Skip the checks for now.
-            return;
-        }
-        if (mRecyclerView.getChildCount() == 0) {
-            assertThat("RV should have focus when it has no children",
-                    mRecyclerView.hasFocus(), is(true));
-            assertThat("RV should be focused when it has no children",
-                    mRecyclerView.isFocused(), is(true));
-            return;
-        }
-
-        assertThat("RV should still have focus after layout", mRecyclerView.hasFocus(), is(true));
-        if ((mDisableRecovery && focusedChildIndexWhenRecoveryDisabled == -1)
-                || (!mDisableRecovery && focusedChildIndexWhenRecoveryEnabled == -1)
-                || mRecyclerView.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS
-                || mRecyclerView.getDescendantFocusability()
-                == ViewGroup.FOCUS_BEFORE_DESCENDANTS) {
-            FocusViewHolder fvh = cast(mRecyclerView.findViewHolderForAdapterPosition(0));
-            String msg1 = " when focus recovery is disabled";
-            String msg2 = " when descendant focusability is FOCUS_BLOCK_DESCENDANTS";
-            String msg3 = " when descendant focusability is FOCUS_BEFORE_DESCENDANTS";
-
-            assertThat("RV should not pass the focus down to its children"
-                            + (mDisableRecovery ? msg1 : (mRecyclerView.getDescendantFocusability()
-                                    == ViewGroup.FOCUS_BLOCK_DESCENDANTS ? msg2 : msg3)),
-                    mRecyclerView.isFocused(), is(true));
-            assertThat("RV's first child should not have focus"
-                            + (mDisableRecovery ? msg1 : (mRecyclerView.getDescendantFocusability()
-                                    == ViewGroup.FOCUS_BLOCK_DESCENDANTS ? msg2 : msg3)),
-                    fvh.itemView.hasFocus(), is(false));
-            assertThat("RV's first child should not be focused"
-                            + (mDisableRecovery ? msg1 : (mRecyclerView.getDescendantFocusability()
-                                    == ViewGroup.FOCUS_BLOCK_DESCENDANTS ? msg2 : msg3)),
-                    fvh.getViewToFocus().isFocused(), is(false));
-        } else {
-            FocusViewHolder fvh = mDisableRecovery
-                    ? cast(mRecyclerView.findViewHolderForAdapterPosition(
-                            focusedChildIndexWhenRecoveryDisabled)) :
-                    (focusedChildIndexWhenRecoveryEnabled != -1
-                            ? cast(mRecyclerView.findViewHolderForAdapterPosition(
-                                    focusedChildIndexWhenRecoveryEnabled)) :
-                    cast(mRecyclerView.findViewHolderForAdapterPosition(0)));
-
-            assertThat("test sanity", fvh, notNullValue());
-            assertThat("RV's first child should be focusable", fvh.getViewToFocus().isFocusable(),
-                    is(true));
-            String msg = " when descendant focusability is FOCUS_AFTER_DESCENDANTS";
-            assertThat("RV should pass the focus down to its children after layout" + msg,
-                    mRecyclerView.isFocused(), is(false));
-            assertThat("RV's child #" + focusedChildIndexWhenRecoveryEnabled + " should have focus"
-                            + " after layout" + msg,
-                    fvh.itemView.hasFocus(), is(true));
-            if (mFocusOnChild) {
-                assertThat("Either the ViewGroup or the TextView within the first child of RV"
-                                + "should be focused after layout" + msg,
-                        fvh.itemView.isFocused() || fvh.getViewToFocus().isFocused(), is(true));
-            } else {
-                assertThat("RV's first child should be focused after layout" + msg,
-                        fvh.getViewToFocus().isFocused(), is(true));
-            }
-
-        }
-    }
-
-    private void assertFocusTransition(RecyclerView.ViewHolder oldVh,
-            RecyclerView.ViewHolder newVh, boolean typeChanged) {
-        if (mDisableRecovery) {
-            if (mDisableAnimation) {
-                return;
-            }
-            assertFocus(newVh, false);
-            return;
-        }
-        assertThat("test sanity", newVh, notNullValue());
-        if (!typeChanged && mDisableAnimation) {
-            assertThat(oldVh, sameInstance(newVh));
-        } else {
-            assertThat(oldVh, not(sameInstance(newVh)));
-            assertFocus(oldVh, false);
-        }
-        assertFocus(newVh, true);
-    }
-
-    @Test
-    public void testFocusRecoveryInTypeChangeWithPredictive() throws Throwable {
-        testFocusRecoveryInTypeChange(true);
-    }
-
-    @Test
-    public void testFocusRecoveryInTypeChangeWithoutPredictive() throws Throwable {
-        testFocusRecoveryInTypeChange(false);
-    }
-
-    private void testFocusRecoveryInTypeChange(boolean withAnimation) throws Throwable {
-        setupBasic();
-        if (!mDisableAnimation) {
-            ((SimpleItemAnimator) (mRecyclerView.getItemAnimator()))
-                    .setSupportsChangeAnimations(true);
-        }
-        mLayoutManager.setSupportsPredictive(withAnimation);
-        final RecyclerView.ViewHolder oldVh = focusVh(3);
-        mLayoutManager.expectLayouts(!mDisableAnimation && withAnimation ? 2 : 1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Item item = mAdapter.mItems.get(3);
-                item.mType += 2;
-                mAdapter.notifyItemChanged(3);
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-
-        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForAdapterPosition(3);
-        assertFocusTransition(oldVh, newVh, true);
-        assertThat("test sanity", oldVh.getItemViewType(), not(newVh.getItemViewType()));
-    }
-
-    @Test
-    public void testRecoverAdapterChangeViaStableIdOnDataSetChanged() throws Throwable {
-        recoverAdapterChangeViaStableId(false, false);
-    }
-
-    @Test
-    public void testRecoverAdapterChangeViaStableIdOnSwap() throws Throwable {
-        recoverAdapterChangeViaStableId(true, false);
-    }
-
-    @Test
-    public void testRecoverAdapterChangeViaStableIdOnDataSetChangedWithTypeChange()
-            throws Throwable {
-        recoverAdapterChangeViaStableId(false, true);
-    }
-
-    @Test
-    public void testRecoverAdapterChangeViaStableIdOnSwapWithTypeChange() throws Throwable {
-        recoverAdapterChangeViaStableId(true, true);
-    }
-
-    private void recoverAdapterChangeViaStableId(final boolean swap, final boolean changeType)
-            throws Throwable {
-        setupBasic(true);
-        RecyclerView.ViewHolder oldVh = focusVh(4);
-        long itemId = oldVh.getItemId();
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Item item = mAdapter.mItems.get(4);
-                if (changeType) {
-                    item.mType += 2;
-                }
-                if (swap) {
-                    mAdapter = new FocusTestAdapter(8);
-                    mAdapter.setHasStableIds(true);
-                    mAdapter.mItems.add(2, item);
-                    mRecyclerView.swapAdapter(mAdapter, false);
-                } else {
-                    mAdapter.mItems.remove(0);
-                    mAdapter.mItems.remove(0);
-                    mAdapter.notifyDataSetChanged();
-                }
-            }
-        });
-        mLayoutManager.waitForLayout(1);
-        if (!mDisableAnimation) {
-            waitForAnimations(2);
-        }
-
-        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForItemId(itemId);
-        if (changeType) {
-            assertFocusTransition(oldVh, newVh, true);
-        } else {
-            // in this case we should use the same VH because we have stable ids
-            assertThat(oldVh, sameInstance(newVh));
-            assertFocus(newVh, true);
-        }
-    }
-
-    @Test
-    public void testDoNotRecoverViaPositionOnSetAdapter() throws Throwable {
-        testDoNotRecoverViaPositionOnNewDataSet(new RecyclerViewLayoutTest.AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                mRecyclerView.setAdapter(new FocusTestAdapter(10));
-            }
-        });
-    }
-
-    @Test
-    public void testDoNotRecoverViaPositionOnSwapAdapterWithRecycle() throws Throwable {
-        testDoNotRecoverViaPositionOnNewDataSet(new RecyclerViewLayoutTest.AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                mRecyclerView.swapAdapter(new FocusTestAdapter(10), true);
-            }
-        });
-    }
-
-    @Test
-    public void testDoNotRecoverViaPositionOnSwapAdapterWithoutRecycle() throws Throwable {
-        testDoNotRecoverViaPositionOnNewDataSet(new RecyclerViewLayoutTest.AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                mRecyclerView.swapAdapter(new FocusTestAdapter(10), false);
-            }
-        });
-    }
-
-    public void testDoNotRecoverViaPositionOnNewDataSet(
-            final RecyclerViewLayoutTest.AdapterRunnable runnable) throws Throwable {
-        setupBasic(false);
-        assertThat("test sanity", mAdapter.hasStableIds(), is(false));
-        focusVh(4);
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    runnable.run(mAdapter);
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-
-        mLayoutManager.waitForLayout(1);
-        RecyclerView.ViewHolder otherVh = mRecyclerView.findViewHolderForAdapterPosition(4);
-        checkForMainThreadException();
-        // even if the VH is re-used, it will be removed-reAdded so focus will go away from it.
-        assertFocus("should not recover focus if data set is badly invalid", otherVh, false);
-
-    }
-
-    @Test
-    public void testDoNotRecoverIfReplacementIsNotFocusable() throws Throwable {
-        final int TYPE_NO_FOCUS = 1001;
-        TestAdapter adapter = new FocusTestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (holder.getItemViewType() == TYPE_NO_FOCUS) {
-                    cast(holder).setFocusable(false);
-                }
-            }
-        };
-        adapter.setHasStableIds(true);
-        setupBasic(adapter);
-        RecyclerView.ViewHolder oldVh = focusVh(3);
-        final long itemId = oldVh.getItemId();
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mAdapter.mItems.get(3).mType = TYPE_NO_FOCUS;
-                mAdapter.notifyDataSetChanged();
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        if (!mDisableAnimation) {
-            waitForAnimations(2);
-        }
-        RecyclerView.ViewHolder newVh = mRecyclerView.findViewHolderForItemId(itemId);
-        assertFocus(newVh, false);
-    }
-
-    @NonNull
-    private RecyclerView.ViewHolder focusVh(int pos) throws Throwable {
-        final RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForAdapterPosition(pos);
-        assertThat("test sanity", oldVh, notNullValue());
-        requestFocus(oldVh);
-        assertFocus("test sanity", oldVh, true);
-        getInstrumentation().waitForIdleSync();
-        return oldVh;
-    }
-
-    @Test
-    public void testDoNotOverrideAdapterRequestedFocus() throws Throwable {
-        final AtomicLong toFocusId = new AtomicLong(-1);
-
-        FocusTestAdapter adapter = new FocusTestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (holder.getItemId() == toFocusId.get()) {
-                    try {
-                        requestFocus(holder);
-                    } catch (Throwable throwable) {
-                        postExceptionToInstrumentation(throwable);
-                    }
-                }
-            }
-        };
-        adapter.setHasStableIds(true);
-        toFocusId.set(adapter.mItems.get(3).mId);
-        long firstFocusId = toFocusId.get();
-        setupBasic(adapter);
-        RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForItemId(toFocusId.get());
-        assertFocus(oldVh, true);
-        toFocusId.set(mAdapter.mItems.get(5).mId);
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mAdapter.mItems.get(3).mType += 2;
-                mAdapter.mItems.get(5).mType += 2;
-                mAdapter.notifyDataSetChanged();
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        if (!mDisableAnimation) {
-            waitForAnimations(2);
-        }
-        RecyclerView.ViewHolder requested = mRecyclerView.findViewHolderForItemId(toFocusId.get());
-        assertFocus(oldVh, false);
-        assertFocus(requested, true);
-        RecyclerView.ViewHolder oldReplacement = mRecyclerView
-                .findViewHolderForItemId(firstFocusId);
-        assertFocus(oldReplacement, false);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void testDoNotOverrideLayoutManagerRequestedFocus() throws Throwable {
-        final AtomicLong toFocusId = new AtomicLong(-1);
-        FocusTestAdapter adapter = new FocusTestAdapter(10);
-        adapter.setHasStableIds(true);
-
-        FocusLayoutManager lm = new FocusLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, state.getItemCount());
-                RecyclerView.ViewHolder toFocus = mRecyclerView
-                        .findViewHolderForItemId(toFocusId.get());
-                if (toFocus != null) {
-                    try {
-                        requestFocus(toFocus);
-                    } catch (Throwable throwable) {
-                        postExceptionToInstrumentation(throwable);
-                    }
-                }
-                layoutLatch.countDown();
-            }
-        };
-
-        toFocusId.set(adapter.mItems.get(3).mId);
-        long firstFocusId = toFocusId.get();
-        setupBasic(adapter, lm);
-
-        RecyclerView.ViewHolder oldVh = mRecyclerView.findViewHolderForItemId(toFocusId.get());
-        assertFocus(oldVh, true);
-        toFocusId.set(mAdapter.mItems.get(5).mId);
-        mLayoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(mRecyclerView);
-        mLayoutManager.waitForLayout(2);
-        RecyclerView.ViewHolder requested = mRecyclerView.findViewHolderForItemId(toFocusId.get());
-        assertFocus(oldVh, false);
-        assertFocus(requested, true);
-        RecyclerView.ViewHolder oldReplacement = mRecyclerView
-                .findViewHolderForItemId(firstFocusId);
-        assertFocus(oldReplacement, false);
-        checkForMainThreadException();
-    }
-
-    private void requestFocus(RecyclerView.ViewHolder viewHolder) throws Throwable {
-        FocusViewHolder fvh = cast(viewHolder);
-        requestFocus(fvh.getViewToFocus(), false);
-    }
-
-    private void assertFocus(RecyclerView.ViewHolder viewHolder, boolean hasFocus) {
-        assertFocus("", viewHolder, hasFocus);
-    }
-
-    private void assertFocus(String msg, RecyclerView.ViewHolder vh, boolean hasFocus) {
-        FocusViewHolder fvh = cast(vh);
-        assertThat(msg, fvh.getViewToFocus().hasFocus(), is(hasFocus));
-    }
-
-    private <T extends FocusViewHolder> T cast(RecyclerView.ViewHolder vh) {
-        assertThat(vh, instanceOf(FocusViewHolder.class));
-        //noinspection unchecked
-        return (T) vh;
-    }
-
-    private class FocusTestAdapter extends TestAdapter {
-
-        public FocusTestAdapter(int count) {
-            super(count);
-        }
-
-        @Override
-        public FocusViewHolder onCreateViewHolder(ViewGroup parent,
-                int viewType) {
-            final FocusViewHolder fvh;
-            if (mFocusOnChild) {
-                fvh = new FocusViewHolderWithChildren(
-                        LayoutInflater.from(parent.getContext())
-                                .inflate(R.layout.focus_test_item_view, parent, false));
-            } else {
-                fvh = new SimpleFocusViewHolder(new TextView(parent.getContext()));
-            }
-            fvh.setFocusable(true);
-            return fvh;
-        }
-
-        @Override
-        public void onBindViewHolder(TestViewHolder holder, int position) {
-            cast(holder).bindTo(mItems.get(position));
-        }
-    }
-
-    private class FocusLayoutManager extends TestLayoutManager {
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            detachAndScrapAttachedViews(recycler);
-            layoutRange(recycler, 0, state.getItemCount());
-            layoutLatch.countDown();
-        }
-    }
-
-    private class FocusViewHolderWithChildren extends FocusViewHolder {
-        public final ViewGroup root;
-        public final ViewGroup parent1;
-        public final ViewGroup parent2;
-        public final TextView textView;
-
-        public FocusViewHolderWithChildren(View view) {
-            super(view);
-            root = (ViewGroup) view;
-            parent1 = (ViewGroup) root.findViewById(R.id.parent1);
-            parent2 = (ViewGroup) root.findViewById(R.id.parent2);
-            textView = (TextView) root.findViewById(R.id.text_view);
-
-        }
-
-        @Override
-        void setFocusable(boolean focusable) {
-            parent1.setFocusableInTouchMode(focusable);
-            parent2.setFocusableInTouchMode(focusable);
-            textView.setFocusableInTouchMode(focusable);
-            root.setFocusableInTouchMode(focusable);
-
-            parent1.setFocusable(focusable);
-            parent2.setFocusable(focusable);
-            textView.setFocusable(focusable);
-            root.setFocusable(focusable);
-        }
-
-        @Override
-        void onBind(Item item) {
-            textView.setText(getText(item));
-        }
-
-        @Override
-        View getViewToFocus() {
-            return textView;
-        }
-    }
-
-    private class SimpleFocusViewHolder extends FocusViewHolder {
-
-        public SimpleFocusViewHolder(View itemView) {
-            super(itemView);
-        }
-
-        @Override
-        void setFocusable(boolean focusable) {
-            itemView.setFocusableInTouchMode(focusable);
-            itemView.setFocusable(focusable);
-        }
-
-        @Override
-        View getViewToFocus() {
-            return itemView;
-        }
-
-        @Override
-        void onBind(Item item) {
-            ((TextView) (itemView)).setText(getText(item));
-        }
-    }
-
-    private abstract class FocusViewHolder extends TestViewHolder {
-
-        public FocusViewHolder(View itemView) {
-            super(itemView);
-        }
-
-        protected String getText(Item item) {
-            return item.mText + "(" + item.mId + ")";
-        }
-
-        abstract void setFocusable(boolean focusable);
-
-        abstract View getViewToFocus();
-
-        abstract void onBind(Item item);
-
-        final void bindTo(Item item) {
-            mBoundItem = item;
-            setFocusable(item.isFocusable());
-            onBind(item);
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
deleted file mode 100644
index 3b7cac7..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ /dev/null
@@ -1,5179 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.RecyclerView.NO_POSITION;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;
-import static android.support.v7.widget.RecyclerView.getChildViewHolderInt;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.os.Build;
-import android.os.SystemClock;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.test.filters.FlakyTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.NestedScrollingParent2;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.util.TouchUtils;
-import android.support.v7.widget.test.NestedScrollingParent2Adapter;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@RunWith(AndroidJUnit4.class)
-@LargeTest
-public class RecyclerViewLayoutTest extends BaseRecyclerViewInstrumentationTest {
-    private static final int FLAG_HORIZONTAL = 1;
-    private static final int FLAG_VERTICAL = 1 << 1;
-    private static final int FLAG_FLING = 1 << 2;
-
-    private static final boolean DEBUG = false;
-
-    private static final String TAG = "RecyclerViewLayoutTest";
-
-    public RecyclerViewLayoutTest() {
-        super(DEBUG);
-    }
-
-    @Test
-    public void triggerFocusSearchInOnRecycledCallback() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity()) {
-            @Override
-            void consumePendingUpdateOperations() {
-                try {
-                    super.consumePendingUpdateOperations();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        };
-        final AtomicBoolean receivedOnRecycled = new AtomicBoolean(false);
-        final TestAdapter adapter = new TestAdapter(20) {
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                super.onViewRecycled(holder);
-                if (receivedOnRecycled.getAndSet(true)) {
-                    return;
-                }
-                rv.focusSearch(rv.getChildAt(0), View.FOCUS_FORWARD);
-            }
-        };
-        final AtomicInteger layoutCnt = new AtomicInteger(5);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, layoutCnt.get());
-                layoutLatch.countDown();
-            }
-        };
-        rv.setLayoutManager(tlm);
-        rv.setAdapter(adapter);
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(2);
-
-        layoutCnt.set(4);
-        tlm.expectLayouts(1);
-        requestLayoutOnUIThread(rv);
-        tlm.waitForLayout(1);
-
-        assertThat("test sanity", rv.mRecycler.mCachedViews.size(), is(1));
-        tlm.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                adapter.notifyItemChanged(4);
-                rv.smoothScrollBy(0, 1);
-            }
-        });
-        checkForMainThreadException();
-        tlm.waitForLayout(2);
-        assertThat("test sanity", rv.mRecycler.mCachedViews.size(), is(0));
-        assertThat(receivedOnRecycled.get(), is(true));
-    }
-
-    @Test
-    public void detachAttachGetReadyWithoutChanges() throws Throwable {
-        detachAttachGetReady(false, false, false);
-    }
-
-    @Test
-    public void detachAttachGetReadyRequireLayout() throws Throwable {
-        detachAttachGetReady(true, false, false);
-    }
-
-    @Test
-    public void detachAttachGetReadyRemoveAdapter() throws Throwable {
-        detachAttachGetReady(false, true, false);
-    }
-
-    @Test
-    public void detachAttachGetReadyRemoveLayoutManager() throws Throwable {
-        detachAttachGetReady(false, false, true);
-    }
-
-    private void detachAttachGetReady(final boolean requestLayoutOnDetach,
-            final boolean removeAdapter, final boolean removeLayoutManager) throws Throwable {
-        final LinearLayout ll1 = new LinearLayout(getActivity());
-        final LinearLayout ll2 = new LinearLayout(getActivity());
-        final LinearLayout ll3 = new LinearLayout(getActivity());
-
-        final RecyclerView rv = new RecyclerView(getActivity());
-        ll1.addView(ll2);
-        ll2.addView(ll3);
-        ll3.addView(rv);
-        TestLayoutManager layoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutCompleted(RecyclerView.State state) {
-                super.onLayoutCompleted(state);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
-                super.onDetachedFromWindow(view, recycler);
-                if (requestLayoutOnDetach) {
-                    view.requestLayout();
-                }
-            }
-        };
-        rv.setLayoutManager(layoutManager);
-        rv.setAdapter(new TestAdapter(10));
-        layoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().addView(ll1);
-            }
-        });
-        layoutManager.waitForLayout(2);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ll1.removeView(ll2);
-            }
-        });
-        getInstrumentation().waitForIdleSync();
-        if (removeLayoutManager) {
-            rv.setLayoutManager(null);
-            rv.setLayoutManager(layoutManager);
-        }
-        if (removeAdapter) {
-            rv.setAdapter(null);
-            rv.setAdapter(new TestAdapter(10));
-        }
-        final boolean requireLayout = requestLayoutOnDetach || removeAdapter || removeLayoutManager;
-        layoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ll1.addView(ll2);
-                if (requireLayout) {
-                    assertTrue(rv.hasPendingAdapterUpdates());
-                    assertFalse(rv.mFirstLayoutComplete);
-                } else {
-                    assertFalse(rv.hasPendingAdapterUpdates());
-                    assertTrue(rv.mFirstLayoutComplete);
-                }
-            }
-        });
-        if (requireLayout) {
-            layoutManager.waitForLayout(2);
-        } else {
-            layoutManager.assertNoLayout("nothing is invalid, layout should not happen", 2);
-        }
-    }
-
-    @Test
-    public void setAdapter_afterSwapAdapter_callsCorrectLmMethods() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
-        final TestAdapter testAdapter = new TestAdapter(1);
-
-        lm.expectLayouts(1);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        setAdapter(testAdapter);
-        lm.waitForLayout(2);
-
-        lm.onAdapterChagnedCallCount = 0;
-        lm.onItemsChangedCallCount = 0;
-
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        rv.swapAdapter(testAdapter, true);
-                        rv.setAdapter(testAdapter);
-                    }
-                });
-        lm.waitForLayout(2);
-
-        assertEquals(2, lm.onAdapterChagnedCallCount);
-        assertEquals(1, lm.onItemsChangedCallCount);
-    }
-
-    @Test
-    public void setAdapter_afterNotifyDataSetChanged_callsCorrectLmMethods() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
-        final TestAdapter testAdapter = new TestAdapter(1);
-
-        lm.expectLayouts(1);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        setAdapter(testAdapter);
-        lm.waitForLayout(2);
-
-        lm.onAdapterChagnedCallCount = 0;
-        lm.onItemsChangedCallCount = 0;
-
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        testAdapter.notifyDataSetChanged();
-                        rv.setAdapter(testAdapter);
-                    }
-                });
-        lm.waitForLayout(2);
-
-        assertEquals(1, lm.onAdapterChagnedCallCount);
-        assertEquals(1, lm.onItemsChangedCallCount);
-    }
-
-    @Test
-    public void notifyDataSetChanged_afterSetAdapter_callsCorrectLmMethods() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
-        final TestAdapter testAdapter = new TestAdapter(1);
-
-        lm.expectLayouts(1);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        setAdapter(testAdapter);
-        lm.waitForLayout(2);
-
-        lm.onAdapterChagnedCallCount = 0;
-        lm.onItemsChangedCallCount = 0;
-
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        rv.setAdapter(testAdapter);
-                        testAdapter.notifyDataSetChanged();
-                    }
-                });
-        lm.waitForLayout(2);
-
-        assertEquals(1, lm.onAdapterChagnedCallCount);
-        assertEquals(1, lm.onItemsChangedCallCount);
-    }
-
-    @Test
-    public void notifyDataSetChanged_afterSwapAdapter_callsCorrectLmMethods() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
-        final TestAdapter testAdapter = new TestAdapter(1);
-
-        lm.expectLayouts(1);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        setAdapter(testAdapter);
-        lm.waitForLayout(2);
-
-        lm.onAdapterChagnedCallCount = 0;
-        lm.onItemsChangedCallCount = 0;
-
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        rv.swapAdapter(testAdapter, true);
-                        testAdapter.notifyDataSetChanged();
-                    }
-                });
-        lm.waitForLayout(2);
-
-        assertEquals(1, lm.onAdapterChagnedCallCount);
-        assertEquals(1, lm.onItemsChangedCallCount);
-    }
-
-    @Test
-    public void swapAdapter_afterSetAdapter_callsCorrectLmMethods() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
-        final TestAdapter testAdapter = new TestAdapter(1);
-
-        lm.expectLayouts(1);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        setAdapter(testAdapter);
-        lm.waitForLayout(2);
-
-        lm.onAdapterChagnedCallCount = 0;
-        lm.onItemsChangedCallCount = 0;
-
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        rv.setAdapter(testAdapter);
-                        rv.swapAdapter(testAdapter, true);
-                    }
-                });
-        lm.waitForLayout(2);
-
-        assertEquals(2, lm.onAdapterChagnedCallCount);
-        assertEquals(1, lm.onItemsChangedCallCount);
-    }
-
-    @Test
-    public void swapAdapter_afterNotifyDataSetChanged_callsCorrectLmMethods() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
-        final TestAdapter testAdapter = new TestAdapter(1);
-
-        lm.expectLayouts(1);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        setAdapter(testAdapter);
-        lm.waitForLayout(2);
-
-        lm.onAdapterChagnedCallCount = 0;
-        lm.onItemsChangedCallCount = 0;
-
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        testAdapter.notifyDataSetChanged();
-                        rv.swapAdapter(testAdapter, true);
-                    }
-                });
-        lm.waitForLayout(2);
-
-        assertEquals(1, lm.onAdapterChagnedCallCount);
-        assertEquals(1, lm.onItemsChangedCallCount);
-    }
-
-    @Test
-    public void setAdapterNotifyItemRangeInsertedCrashTest() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final TestLayoutManager lm = new LayoutAllLayoutManager(true);
-        lm.setSupportsPredictive(true);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        lm.expectLayouts(1);
-        setAdapter(new TestAdapter(1));
-        lm.waitForLayout(2);
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final TestAdapter adapter2 = new TestAdapter(0);
-                rv.setAdapter(adapter2);
-                adapter2.addItems(0, 1, "1");
-                adapter2.notifyItemRangeInserted(0, 1);
-            }
-        });
-        lm.waitForLayout(2);
-    }
-
-    @Test
-    public void swapAdapterNotifyItemRangeInsertedCrashTest() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final TestLayoutManager lm = new LayoutAllLayoutManager(true);
-        lm.setSupportsPredictive(true);
-        rv.setLayoutManager(lm);
-        setRecyclerView(rv);
-        lm.expectLayouts(1);
-        setAdapter(new TestAdapter(1));
-        lm.waitForLayout(2);
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final TestAdapter adapter2 = new TestAdapter(0);
-                rv.swapAdapter(adapter2, true);
-                adapter2.addItems(0, 1, "1");
-                adapter2.notifyItemRangeInserted(0, 1);
-            }
-        });
-        lm.waitForLayout(2);
-    }
-
-    @Test
-    public void onDataSetChanged_doesntHaveStableIds_cachedViewHasNoPosition() throws Throwable {
-        onDataSetChanged_handleCachedViews(false);
-    }
-
-    @Test
-    public void onDataSetChanged_hasStableIds_noCachedViewsAreRecycled() throws Throwable {
-        onDataSetChanged_handleCachedViews(true);
-    }
-
-    /**
-     * If Adapter#setHasStableIds(boolean) is false, cached ViewHolders should be recycled in
-     * response to RecyclerView.Adapter#notifyDataSetChanged() and should report a position of
-     * RecyclerView#NO_POSITION inside of
-     * RecyclerView.Adapter#onViewRecycled(RecyclerView.ViewHolder).
-     *
-     * If Adapter#setHasStableIds(boolean) is true, cached Views/ViewHolders should not be recycled.
-     */
-    public void onDataSetChanged_handleCachedViews(boolean hasStableIds) throws Throwable {
-        final AtomicInteger cachedRecycleCount = new AtomicInteger(0);
-
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setItemViewCacheSize(1);
-
-        final TestAdapter adapter = new TestAdapter(2) {
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                // If the recycled holder is currently in the cache, then it's position in the
-                // adapter should be RecyclerView.NO_POSITION.
-                if (mRecyclerView.mRecycler.mCachedViews.contains(holder)) {
-                    assertThat("ViewHolder's getAdapterPosition should be "
-                                    + "RecyclerView.NO_POSITION",
-                            holder.getAdapterPosition(),
-                            is(RecyclerView.NO_POSITION));
-                    cachedRecycleCount.incrementAndGet();
-                }
-                super.onViewRecycled(holder);
-            }
-        };
-        adapter.setHasStableIds(hasStableIds);
-        recyclerView.setAdapter(adapter);
-
-        final AtomicInteger numItemsToLayout = new AtomicInteger(2);
-
-        TestLayoutManager layoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    detachAndScrapAttachedViews(recycler);
-                    layoutRange(recycler, 0, numItemsToLayout.get());
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    this.layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return false;
-            }
-        };
-        recyclerView.setLayoutManager(layoutManager);
-
-        // Layout 2 items and sanity check that no items are in the recycler's cache.
-        numItemsToLayout.set(2);
-        layoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView, true, false);
-        layoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        assertThat("Sanity check, no views should be cached at this time",
-                mRecyclerView.mRecycler.mCachedViews.size(),
-                is(0));
-
-        // Now only layout 1 item and assert that 1 item is cached.
-        numItemsToLayout.set(1);
-        layoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(mRecyclerView);
-        layoutManager.waitForLayout(1);
-        checkForMainThreadException();
-        assertThat("One view should be cached.",
-                mRecyclerView.mRecycler.mCachedViews.size(),
-                is(1));
-
-        // Notify data set has changed then final assert.
-        layoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                adapter.notifyDataSetChanged();
-            }
-        });
-        layoutManager.waitForLayout(1);
-        checkForMainThreadException();
-        // If hasStableIds, then no cached views should be recycled, otherwise just 1 should have
-        // been recycled.
-        assertThat(cachedRecycleCount.get(), is(hasStableIds ? 0 : 1));
-    }
-
-    @Test
-    public void notifyDataSetChanged_hasStableIds_cachedViewsAreReusedForSamePositions()
-            throws Throwable {
-        final Map<Integer, TestViewHolder> positionToViewHolderMap = new HashMap<>();
-        final AtomicInteger layoutItemCount = new AtomicInteger();
-        final AtomicBoolean inFirstBindViewHolderPass = new AtomicBoolean();
-
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setItemViewCacheSize(5);
-
-        final TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder, int position) {
-                // Only track the top 5 positions that are going to be cached and then reused.
-                if (position >= 5) {
-                    // If we are in the first phase, put the items in the map, if we are in the
-                    // second phase, remove each one at the position and verify that it matches the
-                    // provided ViewHolder.
-                    if (inFirstBindViewHolderPass.get()) {
-                        positionToViewHolderMap.put(position, holder);
-                    } else {
-                        TestViewHolder testViewHolder = positionToViewHolderMap.get(position);
-                        assertThat(holder, is(testViewHolder));
-                        positionToViewHolderMap.remove(position);
-                    }
-                }
-                super.onBindViewHolder(holder, position);
-            }
-        };
-        adapter.setHasStableIds(true);
-        recyclerView.setAdapter(adapter);
-
-        TestLayoutManager testLayoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    detachAndScrapAttachedViews(recycler);
-                    layoutRange(recycler, 0, layoutItemCount.get());
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return false;
-            }
-        };
-        recyclerView.setLayoutManager(testLayoutManager);
-
-        // First layout 10 items, then verify that the map has all 5 ViewHolders in it that will
-        // be cached, and sanity check that the cache is empty.
-        inFirstBindViewHolderPass.set(true);
-        layoutItemCount.set(10);
-        testLayoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView, true, false);
-        testLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        for (int i = 5; i < 10; i++) {
-            assertThat(positionToViewHolderMap.get(i), notNullValue());
-        }
-        assertThat(mRecyclerView.mRecycler.mCachedViews.size(), is(0));
-
-        // Now only layout the first 5 items and verify that the cache has 5 items in it.
-        layoutItemCount.set(5);
-        testLayoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(mRecyclerView);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-        assertThat(mRecyclerView.mRecycler.mCachedViews.size(), is(5));
-
-        // Trigger notifyDataSetChanged and wait for layout.
-        testLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                adapter.notifyDataSetChanged();
-            }
-        });
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-
-        // Layout 10 items again, via the onBindViewholder method, check that each one of the views
-        // returned from the recycler for positions >= 5 was in our cache of views, and verify that
-        // all 5 cached views were returned.
-        inFirstBindViewHolderPass.set(false);
-        layoutItemCount.set(10);
-        testLayoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(mRecyclerView);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-        assertThat(positionToViewHolderMap.size(), is(0));
-    }
-
-    @Test
-    public void predictiveMeasuredCrashTest() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true) {
-            @Override
-            public void onAttachedToWindow(RecyclerView view) {
-                super.onAttachedToWindow(view);
-                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
-            }
-
-            @Override
-            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
-                super.onDetachedFromWindow(view, recycler);
-                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
-            }
-
-            @Override
-            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
-                    int widthSpec,
-                    int heightSpec) {
-                if (state.getItemCount() > 0) {
-                    // A typical LayoutManager will use a child view to measure the size.
-                    View v = recycler.getViewForPosition(0);
-                }
-                super.onMeasure(recycler, state, widthSpec, heightSpec);
-            }
-
-            @Override
-            public boolean isAutoMeasureEnabled() {
-                return false;
-            }
-        };
-        lm.setSupportsPredictive(true);
-        rv.setHasFixedSize(false);
-        final TestAdapter adapter = new TestAdapter(0);
-        rv.setAdapter(adapter);
-        rv.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(rv);
-        lm.waitForLayout(2);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ViewGroup parent = (ViewGroup) rv.getParent();
-                parent.removeView(rv);
-                // setting RV as child of LinearLayout using MATCH_PARENT will cause
-                // RV.onMeasure() being called twice before layout(). This may cause crash.
-                LinearLayout linearLayout = new LinearLayout(parent.getContext());
-                linearLayout.setOrientation(LinearLayout.VERTICAL);
-                parent.addView(linearLayout,
-                        ViewGroup.LayoutParams.WRAP_CONTENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
-                linearLayout.addView(rv, ViewGroup.LayoutParams.MATCH_PARENT,
-                        ViewGroup.LayoutParams.WRAP_CONTENT);
-
-            }
-        });
-
-        lm.expectLayouts(1);
-        adapter.addAndNotify(1);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void detachRvAndLayoutManagerProperly() throws Throwable {
-        final RecyclerView rv = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true) {
-            @Override
-            public void onAttachedToWindow(RecyclerView view) {
-                super.onAttachedToWindow(view);
-                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
-            }
-
-            @Override
-            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
-                super.onDetachedFromWindow(view, recycler);
-                assertThat(view.mLayout, is((RecyclerView.LayoutManager) this));
-            }
-        };
-        final Runnable check = new Runnable() {
-            @Override
-            public void run() {
-                assertThat("bound between the RV and the LM should be disconnected at the"
-                        + " same time", rv.mLayout == lm, is(lm.mRecyclerView == rv));
-            }
-        };
-        final AtomicInteger detachCounter = new AtomicInteger(0);
-        rv.setAdapter(new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                holder.itemView.setFocusable(true);
-                holder.itemView.setFocusableInTouchMode(true);
-            }
-
-            @Override
-            public void onViewDetachedFromWindow(TestViewHolder holder) {
-                super.onViewDetachedFromWindow(holder);
-                detachCounter.incrementAndGet();
-                check.run();
-            }
-
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                super.onViewRecycled(holder);
-                check.run();
-            }
-        });
-        rv.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(rv);
-        lm.waitForLayout(2);
-        assertThat("test sanity", rv.getChildCount(), is(10));
-
-        final TestLayoutManager replacement = new LayoutAllLayoutManager(true);
-        replacement.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                rv.setLayoutManager(replacement);
-            }
-        });
-        replacement.waitForLayout(2);
-        assertThat("test sanity", rv.getChildCount(), is(10));
-        assertThat("all initial views should be detached", detachCounter.get(), is(10));
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void focusSearchWithOtherFocusables() throws Throwable {
-        final LinearLayout container = new LinearLayout(getActivity());
-        container.setOrientation(LinearLayout.VERTICAL);
-        RecyclerView rv = new RecyclerView(getActivity());
-        mRecyclerView = rv;
-        rv.setAdapter(new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                holder.itemView.setFocusableInTouchMode(true);
-                holder.itemView.setLayoutParams(
-                        new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
-                                ViewGroup.LayoutParams.WRAP_CONTENT));
-            }
-        });
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, 1);
-                layoutLatch.countDown();
-            }
-
-            @Nullable
-            @Override
-            public View onFocusSearchFailed(View focused, int direction,
-                    RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                int expectedDir = Build.VERSION.SDK_INT <= 15 ? View.FOCUS_DOWN :
-                        View.FOCUS_FORWARD;
-                assertEquals(expectedDir, direction);
-                assertEquals(1, getChildCount());
-                View child0 = getChildAt(0);
-                View view = recycler.getViewForPosition(1);
-                addView(view);
-                measureChild(view, 0, 0);
-                layoutDecorated(view, 0, child0.getBottom(), getDecoratedMeasuredWidth(view),
-                        child0.getBottom() + getDecoratedMeasuredHeight(view));
-                return view;
-            }
-
-            @Override
-            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                super.scrollHorizontallyBy(dx, recycler, state);
-                // offset by -dx because the views translate opposite of the scrolling direction
-                mRecyclerView.offsetChildrenHorizontal(-dx);
-                return dx;
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                super.scrollVerticallyBy(dy, recycler, state);
-                // offset by -dy because the views translate opposite of the scrolling direction
-                mRecyclerView.offsetChildrenVertical(-dy);
-                return dy;
-            }
-
-            @Override
-            public boolean isAutoMeasureEnabled() {
-                return true;
-            }
-        };
-        rv.setLayoutManager(tlm);
-        TextView viewAbove = new TextView(getActivity());
-        viewAbove.setText("view above");
-        viewAbove.setFocusableInTouchMode(true);
-        container.addView(viewAbove);
-        container.addView(rv);
-        TextView viewBelow = new TextView(getActivity());
-        viewBelow.setText("view below");
-        viewBelow.setFocusableInTouchMode(true);
-        container.addView(viewBelow);
-        tlm.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().addView(container);
-            }
-        });
-
-        tlm.waitForLayout(2);
-        requestFocus(viewAbove, true);
-        assertTrue(viewAbove.hasFocus());
-        View newFocused = focusSearch(viewAbove, View.FOCUS_FORWARD);
-        assertThat(newFocused, sameInstance(rv.getChildAt(0)));
-        newFocused = focusSearch(rv.getChildAt(0), View.FOCUS_FORWARD);
-        assertThat(newFocused, sameInstance(rv.getChildAt(1)));
-    }
-
-    @Test
-    public void boundingBoxNoTranslation() throws Throwable {
-        transformedBoundingBoxTest(new ViewRunnable() {
-            @Override
-            public void run(View view) throws RuntimeException {
-                view.layout(10, 10, 30, 50);
-                assertThat(getTransformedBoundingBox(view), is(new Rect(10, 10, 30, 50)));
-            }
-        });
-    }
-
-    @Test
-    public void boundingBoxTranslateX() throws Throwable {
-        transformedBoundingBoxTest(new ViewRunnable() {
-            @Override
-            public void run(View view) throws RuntimeException {
-                view.layout(10, 10, 30, 50);
-                view.setTranslationX(10);
-                assertThat(getTransformedBoundingBox(view), is(new Rect(20, 10, 40, 50)));
-            }
-        });
-    }
-
-    @Test
-    public void boundingBoxTranslateY() throws Throwable {
-        transformedBoundingBoxTest(new ViewRunnable() {
-            @Override
-            public void run(View view) throws RuntimeException {
-                view.layout(10, 10, 30, 50);
-                view.setTranslationY(10);
-                assertThat(getTransformedBoundingBox(view), is(new Rect(10, 20, 30, 60)));
-            }
-        });
-    }
-
-    @Test
-    public void boundingBoxScaleX() throws Throwable {
-        transformedBoundingBoxTest(new ViewRunnable() {
-            @Override
-            public void run(View view) throws RuntimeException {
-                view.layout(10, 10, 30, 50);
-                view.setScaleX(2);
-                assertThat(getTransformedBoundingBox(view), is(new Rect(0, 10, 40, 50)));
-            }
-        });
-    }
-
-    @Test
-    public void boundingBoxScaleY() throws Throwable {
-        transformedBoundingBoxTest(new ViewRunnable() {
-            @Override
-            public void run(View view) throws RuntimeException {
-                view.layout(10, 10, 30, 50);
-                view.setScaleY(2);
-                assertThat(getTransformedBoundingBox(view), is(new Rect(10, -10, 30, 70)));
-            }
-        });
-    }
-
-    @Test
-    public void boundingBoxRotated() throws Throwable {
-        transformedBoundingBoxTest(new ViewRunnable() {
-            @Override
-            public void run(View view) throws RuntimeException {
-                view.layout(10, 10, 30, 50);
-                view.setRotation(90);
-                assertThat(getTransformedBoundingBox(view), is(new Rect(0, 20, 40, 40)));
-            }
-        });
-    }
-
-    @Test
-    public void boundingBoxRotatedWithDecorOffsets() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final TestAdapter adapter = new TestAdapter(1);
-        recyclerView.setAdapter(adapter);
-        recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
-            @Override
-            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                    RecyclerView.State state) {
-                outRect.set(1, 2, 3, 4);
-            }
-        });
-        TestLayoutManager layoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                View view = recycler.getViewForPosition(0);
-                addView(view);
-                view.measure(
-                        View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY),
-                        View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY)
-                );
-                // trigger decor offsets calculation
-                calculateItemDecorationsForChild(view, new Rect());
-                view.layout(10, 10, 30, 50);
-                view.setRotation(90);
-                assertThat(RecyclerViewLayoutTest.this.getTransformedBoundingBox(view),
-                        is(new Rect(-4, 19, 42, 43)));
-
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setLayoutManager(layoutManager);
-        layoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        layoutManager.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    private Rect getTransformedBoundingBox(View child) {
-        Rect rect = new Rect();
-        mRecyclerView.getLayoutManager().getTransformedBoundingBox(child, true, rect);
-        return rect;
-    }
-
-    public void transformedBoundingBoxTest(final ViewRunnable layout) throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final TestAdapter adapter = new TestAdapter(1);
-        recyclerView.setAdapter(adapter);
-        TestLayoutManager layoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                View view = recycler.getViewForPosition(0);
-                addView(view);
-                view.measure(
-                        View.MeasureSpec.makeMeasureSpec(20, View.MeasureSpec.EXACTLY),
-                        View.MeasureSpec.makeMeasureSpec(40, View.MeasureSpec.EXACTLY)
-                );
-                layout.run(view);
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setLayoutManager(layoutManager);
-        layoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        layoutManager.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void flingFrozen() throws Throwable {
-        testScrollFrozen(true);
-    }
-
-    @Test
-    public void dragFrozen() throws Throwable {
-        testScrollFrozen(false);
-    }
-
-    @Test
-    public void requestRectOnScreenWithScrollOffset() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final LayoutAllLayoutManager tlm = spy(new LayoutAllLayoutManager());
-        final int scrollY = 50;
-        RecyclerView.Adapter adapter = new RecyclerView.Adapter() {
-            @Override
-            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                View view = new View(parent.getContext());
-                view.setScrollY(scrollY);
-                return new RecyclerView.ViewHolder(view) {
-                };
-            }
-            @Override
-            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
-            @Override
-            public int getItemCount() {
-                return 1;
-            }
-        };
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        final View child = recyclerView.getChildAt(0);
-        assertThat(child.getScrollY(), CoreMatchers.is(scrollY));
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.requestChildRectangleOnScreen(child, new Rect(3, 4, 5, 6), true);
-                verify(tlm, times(1)).scrollVerticallyBy(eq(-46), any(RecyclerView.Recycler.class),
-                        any(RecyclerView.State.class));
-            }
-        });
-    }
-
-    @Test
-    public void reattachAndScrollCrash() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final TestLayoutManager tlm = new TestLayoutManager() {
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, Math.min(state.getItemCount(), 10));
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                // Access views in the state (that might have been deleted).
-                for (int  i = 10; i < state.getItemCount(); i++) {
-                    recycler.getViewForPosition(i);
-                }
-                return dy;
-            }
-        };
-
-        final TestAdapter adapter = new TestAdapter(12);
-
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-
-        setRecyclerView(recyclerView);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().removeView(recyclerView);
-                getActivity().getContainer().addView(recyclerView);
-                try {
-                    adapter.deleteAndNotify(1, adapter.getItemCount() - 1);
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-                recyclerView.scrollBy(0, 10);
-            }
-        });
-    }
-
-    private void testScrollFrozen(boolean fling) throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-
-        final int horizontalScrollCount = 3;
-        final int verticalScrollCount = 3;
-        final int horizontalVelocity = 1000;
-        final int verticalVelocity = 1000;
-        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
-        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public boolean canScrollHorizontally() {
-                return true;
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, 10);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                if (verticalCounter.get() > 0) {
-                    verticalCounter.decrementAndGet();
-                    return dy;
-                }
-                return 0;
-            }
-
-            @Override
-            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                if (horizontalCounter.get() > 0) {
-                    horizontalCounter.decrementAndGet();
-                    return dx;
-                }
-                return 0;
-            }
-        };
-        TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(2);
-
-        freezeLayout(true);
-
-        if (fling) {
-            assertFalse("fling should be blocked", fling(horizontalVelocity, verticalVelocity));
-        } else { // drag
-            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
-                    Gravity.LEFT | Gravity.TOP,
-                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
-        }
-        assertEquals("rv's horizontal scroll cb must not run", horizontalScrollCount,
-                horizontalCounter.get());
-        assertEquals("rv's vertical scroll cb must not run", verticalScrollCount,
-                verticalCounter.get());
-
-        freezeLayout(false);
-
-        if (fling) {
-            assertTrue("fling should be started", fling(horizontalVelocity, verticalVelocity));
-        } else { // drag
-            TouchUtils.dragViewTo(getInstrumentation(), recyclerView,
-                    Gravity.LEFT | Gravity.TOP,
-                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
-        }
-        assertEquals("rv's horizontal scroll cb must finishes", 0, horizontalCounter.get());
-        assertEquals("rv's vertical scroll cb must finishes", 0, verticalCounter.get());
-    }
-
-    @Test
-    public void testFocusSearchAfterChangedData() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, 2);
-                layoutLatch.countDown();
-            }
-
-            @Nullable
-            @Override
-            public View onFocusSearchFailed(View focused, int direction,
-                    RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                try {
-                    recycler.getViewForPosition(state.getItemCount() - 1);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-                return null;
-            }
-        };
-        recyclerView.setLayoutManager(tlm);
-        final TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder, int position) {
-                super.onBindViewHolder(holder, position);
-                holder.itemView.setFocusable(false);
-                holder.itemView.setFocusableInTouchMode(false);
-            }
-        };
-        recyclerView.setAdapter(adapter);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                adapter.mItems.remove(9);
-                adapter.notifyItemRemoved(9);
-                recyclerView.focusSearch(recyclerView.getChildAt(1), View.FOCUS_DOWN);
-            }
-        });
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void testFocusSearchWithRemovedFocusedItem() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setItemAnimator(null);
-        TestLayoutManager tlm = new LayoutAllLayoutManager();
-        recyclerView.setLayoutManager(tlm);
-        final TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder, int position) {
-                super.onBindViewHolder(holder, position);
-                holder.itemView.setFocusable(true);
-                holder.itemView.setFocusableInTouchMode(true);
-            }
-        };
-        recyclerView.setAdapter(adapter);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        final RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(9);
-        requestFocus(toFocus.itemView, true);
-        assertThat("test sanity", toFocus.itemView.hasFocus(), is(true));
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                adapter.mItems.remove(9);
-                adapter.notifyItemRemoved(9);
-                recyclerView.focusSearch(toFocus.itemView, View.FOCUS_DOWN);
-            }
-        });
-        checkForMainThreadException();
-    }
-
-
-    @Test
-    public void  testFocusSearchFailFrozen() throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        final CountDownLatch focusLatch = new CountDownLatch(1);
-        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public boolean canScrollHorizontally() {
-                return true;
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, 10);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public View onFocusSearchFailed(View focused, int direction,
-                    RecyclerView.Recycler recycler, RecyclerView.State state) {
-                focusSearchCalled.addAndGet(1);
-                focusLatch.countDown();
-                return null;
-            }
-        };
-        TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(2);
-        final View c = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
-        assertTrue("test sanity", requestFocus(c, true));
-        assertTrue("test sanity", c.hasFocus());
-        freezeLayout(true);
-        focusSearch(recyclerView, c, View.FOCUS_DOWN);
-        assertEquals("onFocusSearchFailed should not be called when layout is frozen",
-                0, focusSearchCalled.get());
-        freezeLayout(false);
-        focusSearch(c, View.FOCUS_DOWN);
-        assertTrue(focusLatch.await(2, TimeUnit.SECONDS));
-        assertEquals(1, focusSearchCalled.get());
-    }
-
-    public View focusSearch(final ViewGroup parent, final View focused, final int direction)
-            throws Throwable {
-        final View[] result = new View[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                result[0] = parent.focusSearch(focused, direction);
-            }
-        });
-        return result[0];
-    }
-
-    @Test
-    public void frozenAndChangeAdapter() throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-
-        final AtomicInteger focusSearchCalled = new AtomicInteger(0);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public boolean canScrollHorizontally() {
-                return true;
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, 10);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                focusSearchCalled.addAndGet(1);
-                return null;
-            }
-        };
-        TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(2);
-
-        freezeLayout(true);
-        TestAdapter adapter2 = new TestAdapter(1000);
-        setAdapter(adapter2);
-        assertFalse(recyclerView.isLayoutFrozen());
-        assertSame(adapter2, recyclerView.getAdapter());
-
-        freezeLayout(true);
-        TestAdapter adapter3 = new TestAdapter(1000);
-        swapAdapter(adapter3, true);
-        assertFalse(recyclerView.isLayoutFrozen());
-        assertSame(adapter3, recyclerView.getAdapter());
-    }
-
-    @Test
-    public void moveAndUpdateCachedViews() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setItemViewCacheSize(3);
-        recyclerView.setItemAnimator(null);
-        final TestAdapter adapter = new TestAdapter(1000);
-        final CountDownLatch layoutLatch = new CountDownLatch(1);
-        LinearLayoutManager tlm = new LinearLayoutManager(recyclerView.getContext()) {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                layoutLatch.countDown();
-            }
-        };
-        tlm.setItemPrefetchEnabled(false);
-        recyclerView.setLayoutManager(tlm);
-        recyclerView.setAdapter(adapter);
-        setRecyclerView(recyclerView);
-        // wait first layout pass
-        layoutLatch.await();
-        // scroll and hide 0 and 1
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.smoothScrollBy(0, recyclerView.getChildAt(2).getTop() + 5);
-            }
-        });
-        waitForIdleScroll(recyclerView);
-        assertNull(recyclerView.findViewHolderForAdapterPosition(0));
-        assertNull(recyclerView.findViewHolderForAdapterPosition(1));
-        // swap 1 and 0 and update 0
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    // swap 1 and 0
-                    adapter.moveInUIThread(1, 0);
-                    adapter.notifyItemMoved(1, 0);
-                    // update 0
-                    adapter.mItems.get(0).mText = "updated";
-                    adapter.notifyItemChanged(0);
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-        // scroll back to 0
-        smoothScrollToPosition(0);
-        waitForIdleScroll(recyclerView);
-        TestViewHolder vh = (TestViewHolder) recyclerView.findViewHolderForAdapterPosition(0);
-        // assert updated right item
-        assertTrue((((TextView) (vh.itemView)).getText()).toString().contains("updated"));
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void noLayoutIf0ItemsAreChanged() throws Throwable {
-        unnecessaryNotifyEvents(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.notifyItemRangeChanged(3, 0);
-            }
-        });
-    }
-
-    @Test
-    public void noLayoutIf0ItemsAreChangedWithPayload() throws Throwable {
-        unnecessaryNotifyEvents(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.notifyItemRangeChanged(0, 0, new Object());
-            }
-        });
-    }
-
-    @Test
-    public void noLayoutIf0ItemsAreAdded() throws Throwable {
-        unnecessaryNotifyEvents(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.notifyItemRangeInserted(3, 0);
-            }
-        });
-    }
-
-    @Test
-    public void noLayoutIf0ItemsAreRemoved() throws Throwable {
-        unnecessaryNotifyEvents(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.notifyItemRangeRemoved(3, 0);
-            }
-        });
-    }
-
-    @Test
-    public void noLayoutIfItemMovedIntoItsOwnPlace() throws Throwable {
-        unnecessaryNotifyEvents(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.notifyItemMoved(3, 3);
-            }
-        });
-    }
-
-    public void unnecessaryNotifyEvents(final AdapterRunnable action) throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final TestAdapter adapter = new TestAdapter(5);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setLayoutManager(tlm);
-        recyclerView.setAdapter(adapter);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        // ready
-        tlm.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    action.run(adapter);
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-        tlm.assertNoLayout("dummy event should not trigger a layout", 1);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void scrollToPositionCallback() throws Throwable {
-
-        class TestRecyclerView extends RecyclerView {
-
-            private CountDownLatch mDrawLatch;
-
-            TestRecyclerView(Context context) {
-                super(context);
-            }
-
-            public void expectDraws(int count) {
-                mDrawLatch = new CountDownLatch(count);
-            }
-
-            public void waitForDraw(int seconds) throws InterruptedException {
-                mDrawLatch.await(seconds, TimeUnit.SECONDS);
-            }
-
-            @Override
-            public void onDraw(Canvas c) {
-                super.onDraw(c);
-                if (mDrawLatch != null) {
-                    mDrawLatch.countDown();
-                }
-            }
-        }
-
-        TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
-        TestLayoutManager tlm = new TestLayoutManager() {
-            int scrollPos = RecyclerView.NO_POSITION;
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutLatch.countDown();
-                if (scrollPos == RecyclerView.NO_POSITION) {
-                    layoutRange(recycler, 0, 10);
-                } else {
-                    layoutRange(recycler, scrollPos, scrollPos + 10);
-                }
-            }
-
-            @Override
-            public void scrollToPosition(int position) {
-                scrollPos = position;
-                requestLayout();
-            }
-        };
-        recyclerView.setLayoutManager(tlm);
-        TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        final AtomicInteger rvCounter = new AtomicInteger(0);
-        final AtomicInteger viewGroupCounter = new AtomicInteger(0);
-
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                rvCounter.incrementAndGet();
-            }
-        });
-
-        getRecyclerViewContainer().getViewTreeObserver().addOnScrollChangedListener(
-                new ViewTreeObserver.OnScrollChangedListener() {
-                    @Override
-                    public void onScrollChanged() {
-                        viewGroupCounter.incrementAndGet();
-                    }
-                });
-
-        recyclerView.expectDraws(1);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(2);
-        recyclerView.waitForDraw(2);
-        assertEquals("RV on scroll should be called for initialization", 1, rvCounter.get());
-        assertEquals("VTO on scroll should be called for initialization", 1,
-                viewGroupCounter.get());
-
-        recyclerView.expectDraws(1);
-        tlm.expectLayouts(1);
-        freezeLayout(true);
-        scrollToPosition(3);
-        tlm.assertNoLayout("scrollToPosition should be ignored", 2);
-        freezeLayout(false);
-        scrollToPosition(3);
-        tlm.waitForLayout(2);
-        recyclerView.waitForDraw(2);
-        assertEquals("RV on scroll should be called", 2, rvCounter.get());
-        assertEquals("VTO on scroll should be called", 2, viewGroupCounter.get());
-
-        recyclerView.expectDraws(1);
-        tlm.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        tlm.waitForLayout(2);
-        recyclerView.waitForDraw(2);
-        assertEquals("on scroll should NOT be called", 2, rvCounter.get());
-        assertEquals("on scroll should NOT be called", 2, viewGroupCounter.get());
-    }
-
-    @Test
-    public void scrollCallbackFromEmptyToSome() throws Throwable {
-        scrollCallbackOnVisibleRangeChange(1, new int[]{0, 0}, new int[]{0, 1});
-    }
-
-    @Test
-    public void scrollCallbackOnVisibleRangeExpand() throws Throwable {
-        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{3, 6});
-    }
-
-    @Test
-    public void scrollCallbackOnVisibleRangeShrink() throws Throwable {
-        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{3, 5});
-    }
-
-    @Test
-    public void scrollCallbackOnVisibleRangeExpand2() throws Throwable {
-        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 5}, new int[]{2, 5});
-    }
-
-    @Test
-    public void scrollCallbackOnVisibleRangeShrink2() throws Throwable {
-        scrollCallbackOnVisibleRangeChange(10, new int[]{3, 6}, new int[]{2, 6});
-    }
-
-    private void scrollCallbackOnVisibleRangeChange(int itemCount, final int[] beforeRange,
-            final int[] afterRange) throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity()) {
-            @Override
-            void dispatchLayout() {
-                super.dispatchLayout();
-                ((TestLayoutManager) getLayoutManager()).layoutLatch.countDown();
-            }
-        };
-        final AtomicBoolean beforeState = new AtomicBoolean(true);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                int[] range = beforeState.get() ? beforeRange : afterRange;
-                layoutRange(recycler, range[0], range[1]);
-            }
-        };
-        recyclerView.setLayoutManager(tlm);
-        final TestAdapter adapter = new TestAdapter(itemCount);
-        recyclerView.setAdapter(adapter);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-
-        RecyclerView.OnScrollListener mockListener = mock(RecyclerView.OnScrollListener.class);
-        recyclerView.addOnScrollListener(mockListener);
-        verify(mockListener, never()).onScrolled(any(RecyclerView.class), anyInt(), anyInt());
-
-        tlm.expectLayouts(1);
-        beforeState.set(false);
-        requestLayoutOnUIThread(recyclerView);
-        tlm.waitForLayout(2);
-        checkForMainThreadException();
-        verify(mockListener).onScrolled(recyclerView, 0, 0);
-    }
-
-    @Test
-    public void addItemOnScroll() throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        final AtomicInteger start = new AtomicInteger(0);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, start.get(), start.get() + 10);
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setLayoutManager(tlm);
-        final TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        final Throwable[] error = new Throwable[1];
-        final AtomicBoolean calledOnScroll = new AtomicBoolean(false);
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-                super.onScrolled(recyclerView, dx, dy);
-                calledOnScroll.set(true);
-                try {
-                    adapter.addAndNotify(5, 20);
-                } catch (Throwable throwable) {
-                    error[0] = throwable;
-                }
-            }
-        });
-        start.set(4);
-        MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(false));
-        tlm.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        tlm.waitForLayout(2);
-        checkForMainThreadException();
-        MatcherAssert.assertThat("test sanity", calledOnScroll.get(), CoreMatchers.is(true));
-        MatcherAssert.assertThat(error[0], CoreMatchers.nullValue());
-    }
-
-    @Test
-    public void scrollInBothDirectionEqual() throws Throwable {
-        scrollInBothDirection(3, 3, 1000, 1000);
-    }
-
-    @Test
-    public void scrollInBothDirectionMoreVertical() throws Throwable {
-        scrollInBothDirection(2, 3, 1000, 1000);
-    }
-
-    @Test
-    public void scrollInBothDirectionMoreHorizontal() throws Throwable {
-        scrollInBothDirection(3, 2, 1000, 1000);
-    }
-
-    @Test
-    public void scrollHorizontalOnly() throws Throwable {
-        scrollInBothDirection(3, 0, 1000, 0);
-    }
-
-    @Test
-    public void scrollVerticalOnly() throws Throwable {
-        scrollInBothDirection(0, 3, 0, 1000);
-    }
-
-    @Test
-    public void scrollInBothDirectionEqualReverse() throws Throwable {
-        scrollInBothDirection(3, 3, -1000, -1000);
-    }
-
-    @Test
-    public void scrollInBothDirectionMoreVerticalReverse() throws Throwable {
-        scrollInBothDirection(2, 3, -1000, -1000);
-    }
-
-    @Test
-    public void scrollInBothDirectionMoreHorizontalReverse() throws Throwable {
-        scrollInBothDirection(3, 2, -1000, -1000);
-    }
-
-    @Test
-    public void scrollHorizontalOnlyReverse() throws Throwable {
-        scrollInBothDirection(3, 0, -1000, 0);
-    }
-
-    @Test
-    public void scrollVerticalOnlyReverse() throws Throwable {
-        scrollInBothDirection(0, 3, 0, -1000);
-    }
-
-    public void scrollInBothDirection(int horizontalScrollCount, int verticalScrollCount,
-            int horizontalVelocity, int verticalVelocity)
-            throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        final AtomicInteger horizontalCounter = new AtomicInteger(horizontalScrollCount);
-        final AtomicInteger verticalCounter = new AtomicInteger(verticalScrollCount);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public boolean canScrollHorizontally() {
-                return true;
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, 10);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                if (verticalCounter.get() > 0) {
-                    verticalCounter.decrementAndGet();
-                    return dy;
-                }
-                return 0;
-            }
-
-            @Override
-            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                if (horizontalCounter.get() > 0) {
-                    horizontalCounter.decrementAndGet();
-                    return dx;
-                }
-                return 0;
-            }
-        };
-        TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(2);
-        assertTrue("test sanity, fling must run", fling(horizontalVelocity, verticalVelocity));
-        assertEquals("rv's horizontal scroll cb must run " + horizontalScrollCount + " times'", 0,
-                horizontalCounter.get());
-        assertEquals("rv's vertical scroll cb must run " + verticalScrollCount + " times'", 0,
-                verticalCounter.get());
-    }
-
-    @Test
-    public void dragHorizontal() throws Throwable {
-        scrollInOtherOrientationTest(FLAG_HORIZONTAL);
-    }
-
-    @Test
-    public void dragVertical() throws Throwable {
-        scrollInOtherOrientationTest(FLAG_VERTICAL);
-    }
-
-    @Test
-    public void flingHorizontal() throws Throwable {
-        scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING);
-    }
-
-    @Test
-    public void flingVertical() throws Throwable {
-        scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING);
-    }
-
-    @SuppressWarnings("WrongConstant")
-    @Test
-    public void nestedDragVertical() throws Throwable {
-        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
-        getActivity().getContainer().setNestedScrollingDelegate(nsp);
-        // Scroll and expect the RV to not scroll
-        scrollInOtherOrientationTest(FLAG_VERTICAL, 0);
-
-        // Verify that the touch nested scroll was started and finished
-        verify(nsp, atLeastOnce()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, atLeastOnce()).onStopNestedScroll(eq(mRecyclerView), eq(ViewCompat.TYPE_TOUCH));
-
-        // Verify that the non-touch events were dispatched by the fling settle
-        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
-    }
-
-    @SuppressWarnings("WrongConstant")
-    @Test
-    public void nestedDragHorizontal() throws Throwable {
-        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
-        getActivity().getContainer().setNestedScrollingDelegate(nsp);
-        // Scroll and expect the RV to not scroll
-        scrollInOtherOrientationTest(FLAG_HORIZONTAL, 0);
-
-        // Verify that the touch nested scroll was started and finished
-        verify(nsp, atLeastOnce()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, atLeastOnce()).onStopNestedScroll(eq(mRecyclerView), eq(ViewCompat.TYPE_TOUCH));
-
-        // Verify that the non-touch events were dispatched by the fling settle
-        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
-    }
-
-    @SuppressWarnings("WrongConstant")
-    @Test
-    public void nestedFlingVertical() throws Throwable {
-        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
-        getActivity().getContainer().setNestedScrollingDelegate(nsp);
-        // Fling and expect the RV to not scroll
-        scrollInOtherOrientationTest(FLAG_VERTICAL | FLAG_FLING, FLAG_FLING);
-
-        // Verify that the touch nested scroll was not started
-        verify(nsp, never()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, never()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, never()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, never()).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_TOUCH);
-
-        // Verify that the non-touch nested scroll was started and finished
-        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_VERTICAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, times(1)).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_NON_TOUCH);
-    }
-
-    @SuppressWarnings("WrongConstant")
-    @Test
-    public void nestedFlingHorizontal() throws Throwable {
-        final NestedScrollingParent2 nsp = spy(new FullyConsumingNestedScroller());
-        getActivity().getContainer().setNestedScrollingDelegate(nsp);
-        // Fling and expect the RV to not scroll
-        scrollInOtherOrientationTest(FLAG_HORIZONTAL | FLAG_FLING, FLAG_FLING);
-
-        // Verify that the touch nested scroll was not started
-        verify(nsp, never()).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, never()).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, never()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_TOUCH));
-        verify(nsp, never()).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_TOUCH);
-
-        // Verify that the non-touch nested scroll was started and finished
-        verify(nsp, times(1)).onStartNestedScroll(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, times(1)).onNestedScrollAccepted(eq(mRecyclerView), eq(mRecyclerView),
-                eq(ViewCompat.SCROLL_AXIS_HORIZONTAL), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, atLeastOnce()).onNestedPreScroll(eq(mRecyclerView), anyInt(), anyInt(),
-                any(int[].class), eq(ViewCompat.TYPE_NON_TOUCH));
-        verify(nsp, times(1)).onStopNestedScroll(mRecyclerView, ViewCompat.TYPE_NON_TOUCH);
-    }
-
-    private void scrollInOtherOrientationTest(int flags)
-            throws Throwable {
-        scrollInOtherOrientationTest(flags, flags);
-    }
-
-    private void scrollInOtherOrientationTest(final int flags, int expectedFlags) throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        final AtomicBoolean scrolledHorizontal = new AtomicBoolean(false);
-        final AtomicBoolean scrolledVertical = new AtomicBoolean(false);
-
-        final TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public boolean canScrollHorizontally() {
-                return (flags & FLAG_HORIZONTAL) != 0;
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return (flags & FLAG_VERTICAL) != 0;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, 10);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                scrolledVertical.set(true);
-                return super.scrollVerticallyBy(dy, recycler, state);
-            }
-
-            @Override
-            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                scrolledHorizontal.set(true);
-                return super.scrollHorizontallyBy(dx, recycler, state);
-            }
-        };
-        TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(2);
-        if ( (flags & FLAG_FLING) != 0 ) {
-            int flingVelocity = (mRecyclerView.getMaxFlingVelocity() +
-                    mRecyclerView.getMinFlingVelocity()) / 2;
-            assertEquals("fling started", (expectedFlags & FLAG_FLING) != 0,
-                    fling(flingVelocity, flingVelocity));
-        } else { // drag
-            TouchUtils.dragViewTo(getInstrumentation(), recyclerView, Gravity.LEFT | Gravity.TOP,
-                    mRecyclerView.getWidth() / 2, mRecyclerView.getHeight() / 2);
-        }
-        assertEquals("horizontally scrolled: " + tlm.mScrollHorizontallyAmount,
-                (expectedFlags & FLAG_HORIZONTAL) != 0, scrolledHorizontal.get());
-        assertEquals("vertically scrolled: " + tlm.mScrollVerticallyAmount,
-                (expectedFlags & FLAG_VERTICAL) != 0, scrolledVertical.get());
-    }
-
-    private boolean fling(final int velocityX, final int velocityY) throws Throwable {
-        final AtomicBoolean didStart = new AtomicBoolean(false);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                boolean result = mRecyclerView.fling(velocityX, velocityY);
-                didStart.set(result);
-            }
-        });
-        if (!didStart.get()) {
-            return false;
-        }
-        waitForIdleScroll(mRecyclerView);
-        return true;
-    }
-
-    private void assertPendingUpdatesAndLayoutTest(final AdapterRunnable runnable) throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        TestLayoutManager layoutManager = new DumbLayoutManager();
-        final TestAdapter testAdapter = new TestAdapter(10);
-        setupBasic(recyclerView, layoutManager, testAdapter, false);
-        layoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    runnable.run(testAdapter);
-                } catch (Throwable throwable) {
-                    fail("runnable has thrown an exception");
-                }
-                assertTrue(mRecyclerView.hasPendingAdapterUpdates());
-            }
-        });
-        layoutManager.waitForLayout(1);
-        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
-        checkForMainThreadException();
-    }
-
-    private void setupBasic(RecyclerView recyclerView, TestLayoutManager tlm,
-            TestAdapter adapter, boolean waitForFirstLayout) throws Throwable {
-        recyclerView.setLayoutManager(tlm);
-        recyclerView.setAdapter(adapter);
-        if (waitForFirstLayout) {
-            tlm.expectLayouts(1);
-            setRecyclerView(recyclerView);
-            tlm.waitForLayout(1);
-        } else {
-            setRecyclerView(recyclerView);
-        }
-    }
-
-    @Suppress
-    @FlakyTest(bugId = 33949798)
-    @Test
-    @LargeTest
-    public void hasPendingUpdatesBeforeFirstLayout() throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        TestLayoutManager layoutManager = new DumbLayoutManager();
-        TestAdapter testAdapter = new TestAdapter(10);
-        setupBasic(recyclerView, layoutManager, testAdapter, false);
-        assertTrue(mRecyclerView.hasPendingAdapterUpdates());
-    }
-
-    @Test
-    public void noPendingUpdatesAfterLayout() throws Throwable {
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        TestLayoutManager layoutManager = new DumbLayoutManager();
-        TestAdapter testAdapter = new TestAdapter(10);
-        setupBasic(recyclerView, layoutManager, testAdapter, true);
-        assertFalse(mRecyclerView.hasPendingAdapterUpdates());
-    }
-
-    @Test
-    public void hasPendingUpdatesAfterItemIsRemoved() throws Throwable {
-        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter testAdapter) throws Throwable {
-                testAdapter.deleteAndNotify(1, 1);
-            }
-        });
-    }
-    @Test
-    public void hasPendingUpdatesAfterItemIsInserted() throws Throwable {
-        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter testAdapter) throws Throwable {
-                testAdapter.addAndNotify(2, 1);
-            }
-        });
-    }
-    @Test
-    public void hasPendingUpdatesAfterItemIsMoved() throws Throwable {
-        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter testAdapter) throws Throwable {
-                testAdapter.moveItem(2, 3, true);
-            }
-        });
-    }
-    @Test
-    public void hasPendingUpdatesAfterItemIsChanged() throws Throwable {
-        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter testAdapter) throws Throwable {
-                testAdapter.changeAndNotify(2, 1);
-            }
-        });
-    }
-    @Test
-    public void hasPendingUpdatesAfterDataSetIsChanged() throws Throwable {
-        assertPendingUpdatesAndLayoutTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter testAdapter) {
-                mRecyclerView.getAdapter().notifyDataSetChanged();
-            }
-        });
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
-    @Test
-    public void transientStateRecycleViaAdapter() throws Throwable {
-        transientStateRecycleTest(true, false);
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
-    @Test
-    public void transientStateRecycleViaTransientStateCleanup() throws Throwable {
-        transientStateRecycleTest(false, true);
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
-    @Test
-    public void transientStateDontRecycle() throws Throwable {
-        transientStateRecycleTest(false, false);
-    }
-
-    public void transientStateRecycleTest(final boolean succeed, final boolean unsetTransientState)
-            throws Throwable {
-        final List<View> failedToRecycle = new ArrayList<>();
-        final List<View> recycled = new ArrayList<>();
-        TestAdapter testAdapter = new TestAdapter(10) {
-            @Override
-            public boolean onFailedToRecycleView(TestViewHolder holder) {
-                failedToRecycle.add(holder.itemView);
-                if (unsetTransientState) {
-                    setHasTransientState(holder.itemView, false);
-                }
-                return succeed;
-            }
-
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                recycled.add(holder.itemView);
-                super.onViewRecycled(holder);
-            }
-        };
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                if (getChildCount() == 0) {
-                    detachAndScrapAttachedViews(recycler);
-                    layoutRange(recycler, 0, 5);
-                } else {
-                    removeAndRecycleAllViews(recycler);
-                }
-                if (layoutLatch != null) {
-                    layoutLatch.countDown();
-                }
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(tlm);
-        recyclerView.setItemAnimator(null);
-        setRecyclerView(recyclerView);
-        getInstrumentation().waitForIdleSync();
-        // make sure we have enough views after this position so that we'll receive the on recycled
-        // callback
-        View view = recyclerView.getChildAt(3);//this has to be greater than def cache size.
-        setHasTransientState(view, true);
-        tlm.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        tlm.waitForLayout(2);
-
-        assertTrue(failedToRecycle.contains(view));
-        assertEquals(succeed || unsetTransientState, recycled.contains(view));
-    }
-
-    @Test
-    public void adapterPositionInvalidation() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final TestAdapter adapter = new TestAdapter(10);
-        final TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, state.getItemCount());
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < tlm.getChildCount(); i++) {
-                    assertNotSame("adapter positions should not be undefined",
-                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
-                            RecyclerView.NO_POSITION);
-                }
-                adapter.notifyDataSetChanged();
-                for (int i = 0; i < tlm.getChildCount(); i++) {
-                    assertSame("adapter positions should be undefined",
-                            recyclerView.getChildAdapterPosition(tlm.getChildAt(i)),
-                            RecyclerView.NO_POSITION);
-                }
-            }
-        });
-    }
-
-    @Test
-    public void adapterPositionsBasic() throws Throwable {
-        adapterPositionsTest(null);
-    }
-
-    @Test
-    public void adapterPositionsRemoveItems() throws Throwable {
-        adapterPositionsTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.deleteAndNotify(3, 4);
-            }
-        });
-    }
-
-    @Test
-    public void adapterPositionsRemoveItemsBefore() throws Throwable {
-        adapterPositionsTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.deleteAndNotify(0, 1);
-            }
-        });
-    }
-
-    @Test
-    public void adapterPositionsAddItemsBefore() throws Throwable {
-        adapterPositionsTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.addAndNotify(0, 5);
-            }
-        });
-    }
-
-    @Test
-    public void adapterPositionsAddItemsInside() throws Throwable {
-        adapterPositionsTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.addAndNotify(3, 2);
-            }
-        });
-    }
-
-    @Test
-    public void adapterPositionsMoveItems() throws Throwable {
-        adapterPositionsTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.moveAndNotify(3, 5);
-            }
-        });
-    }
-
-    @Test
-    public void adapterPositionsNotifyDataSetChanged() throws Throwable {
-        adapterPositionsTest(new AdapterRunnable() {
-            @Override
-            public void run(TestAdapter adapter) throws Throwable {
-                adapter.mItems.clear();
-                for (int i = 0; i < 20; i++) {
-                    adapter.mItems.add(new Item(i, "added item"));
-                }
-                adapter.notifyDataSetChanged();
-            }
-        });
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN) // transientState is API 16
-    @Test
-    public void avoidLeakingRecyclerViewIfViewIsNotRecycled() throws Throwable {
-        final AtomicBoolean failedToRecycle = new AtomicBoolean(false);
-        final AtomicInteger recycledViewCount = new AtomicInteger(0);
-        RecyclerView rv = new RecyclerView(getActivity());
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, state.getItemCount());
-                layoutLatch.countDown();
-            }
-        };
-        TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public boolean onFailedToRecycleView(
-                    TestViewHolder holder) {
-                failedToRecycle.set(true);
-                return false;
-            }
-
-            @Override
-            public void onViewRecycled(TestViewHolder holder) {
-                recycledViewCount.incrementAndGet();
-                super.onViewRecycled(holder);
-            }
-        };
-        rv.setAdapter(adapter);
-        rv.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(1);
-        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ViewCompat.setHasTransientState(vh.itemView, true);
-            }
-        });
-        tlm.expectLayouts(1);
-        adapter.deleteAndNotify(0, 10);
-        tlm.waitForLayout(2);
-        final CountDownLatch animationsLatch = new CountDownLatch(1);
-        rv.getItemAnimator().isRunning(
-                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
-                    @Override
-                    public void onAnimationsFinished() {
-                        animationsLatch.countDown();
-                    }
-                });
-        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
-        assertThat(recycledViewCount.get(), is(9));
-        assertTrue(failedToRecycle.get());
-        assertNull(vh.mOwnerRecyclerView);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void avoidLeakingRecyclerViewViaViewHolder() throws Throwable {
-        RecyclerView rv = new RecyclerView(getActivity());
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, state.getItemCount());
-                layoutLatch.countDown();
-            }
-        };
-        TestAdapter adapter = new TestAdapter(10);
-        rv.setAdapter(adapter);
-        rv.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(1);
-        final RecyclerView.ViewHolder vh = rv.getChildViewHolder(rv.getChildAt(0));
-        tlm.expectLayouts(1);
-        adapter.deleteAndNotify(0, 10);
-        tlm.waitForLayout(2);
-        final CountDownLatch animationsLatch = new CountDownLatch(1);
-        rv.getItemAnimator().isRunning(
-                new RecyclerView.ItemAnimator.ItemAnimatorFinishedListener() {
-                    @Override
-                    public void onAnimationsFinished() {
-                        animationsLatch.countDown();
-                    }
-                });
-        assertTrue(animationsLatch.await(2, TimeUnit.SECONDS));
-        assertNull(vh.mOwnerRecyclerView);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void duplicateAdapterPositionTest() throws Throwable {
-        final TestAdapter testAdapter = new TestAdapter(10);
-        final TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, state.getItemCount());
-                if (!state.isPreLayout()) {
-                    while (!recycler.getScrapList().isEmpty()) {
-                        RecyclerView.ViewHolder viewHolder = recycler.getScrapList().get(0);
-                        addDisappearingView(viewHolder.itemView, 0);
-                    }
-                }
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return true;
-            }
-        };
-        final DefaultItemAnimator animator = new DefaultItemAnimator();
-        animator.setSupportsChangeAnimations(true);
-        animator.setChangeDuration(10000);
-        testAdapter.setHasStableIds(true);
-        final TestRecyclerView recyclerView = new TestRecyclerView(getActivity());
-        recyclerView.setLayoutManager(tlm);
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setItemAnimator(animator);
-
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(2);
-
-        tlm.expectLayouts(2);
-        testAdapter.mItems.get(2).mType += 2;
-        final int itemId = testAdapter.mItems.get(2).mId;
-        testAdapter.changeAndNotify(2, 1);
-        tlm.waitForLayout(2);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                assertThat("test sanity", recyclerView.getChildCount(), CoreMatchers.is(11));
-                // now mangle the order and run the test
-                RecyclerView.ViewHolder hidden = null;
-                RecyclerView.ViewHolder updated = null;
-                for (int i = 0; i < recyclerView.getChildCount(); i ++) {
-                    View view = recyclerView.getChildAt(i);
-                    RecyclerView.ViewHolder vh = recyclerView.getChildViewHolder(view);
-                    if (vh.getAdapterPosition() == 2) {
-                        if (mRecyclerView.mChildHelper.isHidden(view)) {
-                            assertThat(hidden, CoreMatchers.nullValue());
-                            hidden = vh;
-                        } else {
-                            assertThat(updated, CoreMatchers.nullValue());
-                            updated = vh;
-                        }
-                    }
-                }
-                assertThat(hidden, CoreMatchers.notNullValue());
-                assertThat(updated, CoreMatchers.notNullValue());
-
-                mRecyclerView.startInterceptRequestLayout();
-
-                // first put the hidden child back
-                int index1 = mRecyclerView.indexOfChild(hidden.itemView);
-                int index2 = mRecyclerView.indexOfChild(updated.itemView);
-                if (index1 < index2) {
-                    // swap views
-                    swapViewsAtIndices(recyclerView, index1, index2);
-                }
-                assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView));
-
-                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
-                        CoreMatchers.sameInstance(updated));
-                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
-                        CoreMatchers.sameInstance(updated));
-                assertThat(recyclerView.findViewHolderForItemId(itemId),
-                        CoreMatchers.sameInstance(updated));
-
-                // now swap back
-                swapViewsAtIndices(recyclerView, index1, index2);
-
-                assertThat(tlm.findViewByPosition(2), CoreMatchers.sameInstance(updated.itemView));
-                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
-                        CoreMatchers.sameInstance(updated));
-                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
-                        CoreMatchers.sameInstance(updated));
-                assertThat(recyclerView.findViewHolderForItemId(itemId),
-                        CoreMatchers.sameInstance(updated));
-
-                // now remove updated. re-assert fallback to the hidden one
-                tlm.removeView(updated.itemView);
-
-                assertThat(tlm.findViewByPosition(2), CoreMatchers.nullValue());
-                assertThat(recyclerView.findViewHolderForAdapterPosition(2),
-                        CoreMatchers.sameInstance(hidden));
-                assertThat(recyclerView.findViewHolderForLayoutPosition(2),
-                        CoreMatchers.sameInstance(hidden));
-                assertThat(recyclerView.findViewHolderForItemId(itemId),
-                        CoreMatchers.sameInstance(hidden));
-            }
-        });
-
-    }
-
-    private void swapViewsAtIndices(TestRecyclerView recyclerView, int index1, int index2) {
-        if (index1 == index2) {
-            return;
-        }
-        if (index2 < index1) {
-            int tmp = index1;
-            index1 = index2;
-            index2 = tmp;
-        }
-        final View v1 = recyclerView.getChildAt(index1);
-        final View v2 = recyclerView.getChildAt(index2);
-        boolean v1Hidden = recyclerView.mChildHelper.isHidden(v1);
-        boolean v2Hidden = recyclerView.mChildHelper.isHidden(v2);
-        // must un-hide before swap otherwise bucket indices will become invalid.
-        if (v1Hidden) {
-            mRecyclerView.mChildHelper.unhide(v1);
-        }
-        if (v2Hidden) {
-            mRecyclerView.mChildHelper.unhide(v2);
-        }
-        recyclerView.detachViewFromParent(index2);
-        recyclerView.attachViewToParent(v2, index1, v2.getLayoutParams());
-        recyclerView.detachViewFromParent(index1 + 1);
-        recyclerView.attachViewToParent(v1, index2, v1.getLayoutParams());
-
-        if (v1Hidden) {
-            mRecyclerView.mChildHelper.hide(v1);
-        }
-        if (v2Hidden) {
-            mRecyclerView.mChildHelper.hide(v2);
-        }
-    }
-
-    public void adapterPositionsTest(final AdapterRunnable adapterChanges) throws Throwable {
-        final TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    layoutRange(recycler, Math.min(state.getItemCount(), 2)
-                            , Math.min(state.getItemCount(), 7));
-                    layoutLatch.countDown();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        };
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setLayoutManager(tlm);
-        recyclerView.setAdapter(testAdapter);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    final int count = recyclerView.getChildCount();
-                    Map<View, Integer> layoutPositions = new HashMap<>();
-                    assertTrue("test sanity", count > 0);
-                    for (int i = 0; i < count; i++) {
-                        View view = recyclerView.getChildAt(i);
-                        TestViewHolder vh = (TestViewHolder) recyclerView.getChildViewHolder(view);
-                        int index = testAdapter.mItems.indexOf(vh.mBoundItem);
-                        assertEquals("should be able to find VH with adapter position " + index, vh,
-                                recyclerView.findViewHolderForAdapterPosition(index));
-                        assertEquals("get adapter position should return correct index", index,
-                                vh.getAdapterPosition());
-                        layoutPositions.put(view, vh.mPosition);
-                    }
-                    if (adapterChanges != null) {
-                        adapterChanges.run(testAdapter);
-                        for (int i = 0; i < count; i++) {
-                            View view = recyclerView.getChildAt(i);
-                            TestViewHolder vh = (TestViewHolder) recyclerView
-                                    .getChildViewHolder(view);
-                            int index = testAdapter.mItems.indexOf(vh.mBoundItem);
-                            if (index >= 0) {
-                                assertEquals("should be able to find VH with adapter position "
-                                                + index, vh,
-                                        recyclerView.findViewHolderForAdapterPosition(index));
-                            }
-                            assertSame("get adapter position should return correct index", index,
-                                    vh.getAdapterPosition());
-                            assertSame("should be able to find view with layout position",
-                                    vh, mRecyclerView.findViewHolderForLayoutPosition(
-                                            layoutPositions.get(view)));
-                        }
-
-                    }
-
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        });
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void scrollStateForSmoothScroll() throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager tlm = new TestLayoutManager();
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(tlm);
-        setRecyclerView(recyclerView);
-        getInstrumentation().waitForIdleSync();
-        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
-        final int[] stateCnts = new int[10];
-        final CountDownLatch latch = new CountDownLatch(2);
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                stateCnts[newState] = stateCnts[newState] + 1;
-                latch.countDown();
-            }
-        });
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.smoothScrollBy(0, 500);
-            }
-        });
-        latch.await(5, TimeUnit.SECONDS);
-        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
-        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
-        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
-    }
-
-    @Test
-    public void scrollStateForSmoothScrollWithStop() throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager tlm = new TestLayoutManager();
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(tlm);
-        setRecyclerView(recyclerView);
-        getInstrumentation().waitForIdleSync();
-        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
-        final int[] stateCnts = new int[10];
-        final CountDownLatch latch = new CountDownLatch(1);
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                stateCnts[newState] = stateCnts[newState] + 1;
-                latch.countDown();
-            }
-        });
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.smoothScrollBy(0, 500);
-            }
-        });
-        latch.await(5, TimeUnit.SECONDS);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.stopScroll();
-            }
-        });
-        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
-        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
-        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
-        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
-    }
-
-    @Test
-    public void scrollStateForFling() throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager tlm = new TestLayoutManager();
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(tlm);
-        setRecyclerView(recyclerView);
-        getInstrumentation().waitForIdleSync();
-        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
-        final int[] stateCnts = new int[10];
-        final CountDownLatch latch = new CountDownLatch(2);
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                stateCnts[newState] = stateCnts[newState] + 1;
-                latch.countDown();
-            }
-        });
-        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
-        final float fling = vc.getScaledMinimumFlingVelocity()
-                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .1f;
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.fling(0, Math.round(fling));
-            }
-        });
-        latch.await(5, TimeUnit.SECONDS);
-        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
-        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
-        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
-    }
-
-    @Test
-    public void scrollStateForFlingWithStop() throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager tlm = new TestLayoutManager();
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(tlm);
-        setRecyclerView(recyclerView);
-        getInstrumentation().waitForIdleSync();
-        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
-        final int[] stateCnts = new int[10];
-        final CountDownLatch latch = new CountDownLatch(1);
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                stateCnts[newState] = stateCnts[newState] + 1;
-                latch.countDown();
-            }
-        });
-        final ViewConfiguration vc = ViewConfiguration.get(getActivity());
-        final float fling = vc.getScaledMinimumFlingVelocity()
-                + (vc.getScaledMaximumFlingVelocity() - vc.getScaledMinimumFlingVelocity()) * .8f;
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.fling(0, Math.round(fling));
-            }
-        });
-        latch.await(5, TimeUnit.SECONDS);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.stopScroll();
-            }
-        });
-        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
-        assertEquals(1, stateCnts[SCROLL_STATE_SETTLING]);
-        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
-        assertEquals(0, stateCnts[SCROLL_STATE_DRAGGING]);
-    }
-
-    @Test
-    public void scrollStateDrag() throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager tlm = new TestLayoutManager();
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(tlm);
-        setRecyclerView(recyclerView);
-        getInstrumentation().waitForIdleSync();
-        assertEquals(SCROLL_STATE_IDLE, recyclerView.getScrollState());
-        final int[] stateCnts = new int[10];
-        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                stateCnts[newState] = stateCnts[newState] + 1;
-            }
-        });
-        drag(mRecyclerView, 0, 0, 0, 500, 5);
-        assertEquals(0, stateCnts[SCROLL_STATE_SETTLING]);
-        assertEquals(1, stateCnts[SCROLL_STATE_IDLE]);
-        assertEquals(1, stateCnts[SCROLL_STATE_DRAGGING]);
-    }
-
-    public void drag(ViewGroup view, float fromX, float toX, float fromY, float toY,
-            int stepCount) throws Throwable {
-        long downTime = SystemClock.uptimeMillis();
-        long eventTime = SystemClock.uptimeMillis();
-
-        float y = fromY;
-        float x = fromX;
-
-        float yStep = (toY - fromY) / stepCount;
-        float xStep = (toX - fromX) / stepCount;
-
-        MotionEvent event = MotionEvent.obtain(downTime, eventTime,
-                MotionEvent.ACTION_DOWN, x, y, 0);
-        sendTouch(view, event);
-        for (int i = 0; i < stepCount; ++i) {
-            y += yStep;
-            x += xStep;
-            eventTime = SystemClock.uptimeMillis();
-            event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x, y, 0);
-            sendTouch(view, event);
-        }
-
-        eventTime = SystemClock.uptimeMillis();
-        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
-        sendTouch(view, event);
-        getInstrumentation().waitForIdleSync();
-    }
-
-    private void sendTouch(final ViewGroup view, final MotionEvent event) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (view.onInterceptTouchEvent(event)) {
-                    view.onTouchEvent(event);
-                }
-            }
-        });
-    }
-
-    @Test
-    public void recycleScrap() throws Throwable {
-        recycleScrapTest(false);
-        removeRecyclerView();
-        recycleScrapTest(true);
-    }
-
-    public void recycleScrapTest(final boolean useRecycler) throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        final AtomicBoolean test = new AtomicBoolean(false);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                ViewInfoStore infoStore = mRecyclerView.mViewInfoStore;
-                if (test.get()) {
-                    try {
-                        detachAndScrapAttachedViews(recycler);
-                        for (int i = recycler.getScrapList().size() - 1; i >= 0; i--) {
-                            if (useRecycler) {
-                                recycler.recycleView(recycler.getScrapList().get(i).itemView);
-                            } else {
-                                removeAndRecycleView(recycler.getScrapList().get(i).itemView,
-                                        recycler);
-                            }
-                        }
-                        if (infoStore.mOldChangedHolders != null) {
-                            for (int i = infoStore.mOldChangedHolders.size() - 1; i >= 0; i--) {
-                                if (useRecycler) {
-                                    recycler.recycleView(
-                                            infoStore.mOldChangedHolders.valueAt(i).itemView);
-                                } else {
-                                    removeAndRecycleView(
-                                            infoStore.mOldChangedHolders.valueAt(i).itemView,
-                                            recycler);
-                                }
-                            }
-                        }
-                        assertEquals("no scrap should be left over", 0, recycler.getScrapCount());
-                        assertEquals("pre layout map should be empty", 0,
-                                InfoStoreTrojan.sizeOfPreLayout(infoStore));
-                        assertEquals("post layout map should be empty", 0,
-                                InfoStoreTrojan.sizeOfPostLayout(infoStore));
-                        if (infoStore.mOldChangedHolders != null) {
-                            assertEquals("post old change map should be empty", 0,
-                                    infoStore.mOldChangedHolders.size());
-                        }
-                    } catch (Throwable t) {
-                        postExceptionToInstrumentation(t);
-                    }
-
-                }
-                layoutRange(recycler, 0, 5);
-                layoutLatch.countDown();
-                super.onLayoutChildren(recycler, state);
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(lm);
-        ((SimpleItemAnimator)recyclerView.getItemAnimator()).setSupportsChangeAnimations(true);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        test.set(true);
-        lm.expectLayouts(1);
-        testAdapter.changeAndNotify(3, 1);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void aAccessRecyclerOnOnMeasureWithPredictive() throws Throwable {
-        accessRecyclerOnOnMeasureTest(true);
-    }
-
-    @Test
-    public void accessRecyclerOnOnMeasureWithoutPredictive() throws Throwable {
-        accessRecyclerOnOnMeasureTest(false);
-    }
-
-    @Test
-    public void smoothScrollWithRemovedItemsAndRemoveItem() throws Throwable {
-        smoothScrollTest(true);
-    }
-
-    @Test
-    public void smoothScrollWithRemovedItems() throws Throwable {
-        smoothScrollTest(false);
-    }
-
-    public void smoothScrollTest(final boolean removeItem) throws Throwable {
-        final LinearSmoothScroller[] lss = new LinearSmoothScroller[1];
-        final CountDownLatch calledOnStart = new CountDownLatch(1);
-        final CountDownLatch calledOnStop = new CountDownLatch(1);
-        final int visibleChildCount = 10;
-        TestLayoutManager lm = new TestLayoutManager() {
-            int start = 0;
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                layoutRange(recycler, start, visibleChildCount);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                start++;
-                if (DEBUG) {
-                    Log.d(TAG, "on scroll, remove and recycling. start:" + start + ", cnt:"
-                            + visibleChildCount);
-                }
-                removeAndRecycleAllViews(recycler);
-                layoutRange(recycler, start,
-                        Math.max(state.getItemCount(), start + visibleChildCount));
-                return dy;
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
-                    int position) {
-                LinearSmoothScroller linearSmoothScroller =
-                        new LinearSmoothScroller(recyclerView.getContext()) {
-                            @Override
-                            public PointF computeScrollVectorForPosition(int targetPosition) {
-                                return new PointF(0, 1);
-                            }
-
-                            @Override
-                            protected void onStart() {
-                                super.onStart();
-                                calledOnStart.countDown();
-                            }
-
-                            @Override
-                            protected void onStop() {
-                                super.onStop();
-                                calledOnStop.countDown();
-                            }
-                        };
-                linearSmoothScroller.setTargetPosition(position);
-                lss[0] = linearSmoothScroller;
-                startSmoothScroll(linearSmoothScroller);
-            }
-        };
-        final RecyclerView rv = new RecyclerView(getActivity());
-        TestAdapter testAdapter = new TestAdapter(500);
-        rv.setLayoutManager(lm);
-        rv.setAdapter(testAdapter);
-        lm.expectLayouts(1);
-        setRecyclerView(rv);
-        lm.waitForLayout(1);
-        // regular scroll
-        final int targetPosition = visibleChildCount * (removeItem ? 30 : 4);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                rv.smoothScrollToPosition(targetPosition);
-            }
-        });
-        if (DEBUG) {
-            Log.d(TAG, "scrolling to target position " + targetPosition);
-        }
-        assertTrue("on start should be called very soon", calledOnStart.await(2, TimeUnit.SECONDS));
-        if (removeItem) {
-            final int newTarget = targetPosition - 10;
-            testAdapter.deleteAndNotify(newTarget + 1, testAdapter.getItemCount() - newTarget - 1);
-            final CountDownLatch targetCheck = new CountDownLatch(1);
-            mActivityRule.runOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    ViewCompat.postOnAnimationDelayed(rv, new Runnable() {
-                        @Override
-                        public void run() {
-                            try {
-                                assertEquals("scroll position should be updated to next available",
-                                        newTarget, lss[0].getTargetPosition());
-                            } catch (Throwable t) {
-                                postExceptionToInstrumentation(t);
-                            }
-                            targetCheck.countDown();
-                        }
-                    }, 50);
-                }
-            });
-            assertTrue("target position should be checked on time ",
-                    targetCheck.await(10, TimeUnit.SECONDS));
-            checkForMainThreadException();
-            assertTrue("on stop should be called", calledOnStop.await(30, TimeUnit.SECONDS));
-            checkForMainThreadException();
-            assertNotNull("should scroll to new target " + newTarget
-                    , rv.findViewHolderForLayoutPosition(newTarget));
-            if (DEBUG) {
-                Log.d(TAG, "on stop has been called on time");
-            }
-        } else {
-            assertTrue("on stop should be called eventually",
-                    calledOnStop.await(30, TimeUnit.SECONDS));
-            assertNotNull("scroll to position should succeed",
-                    rv.findViewHolderForLayoutPosition(targetPosition));
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void consecutiveSmoothScroll() throws Throwable {
-        final AtomicInteger visibleChildCount = new AtomicInteger(10);
-        final AtomicInteger totalScrolled = new AtomicInteger(0);
-        final TestLayoutManager lm = new TestLayoutManager() {
-            int start = 0;
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                layoutRange(recycler, start, visibleChildCount.get());
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                totalScrolled.set(totalScrolled.get() + dy);
-                return dy;
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-        };
-        final RecyclerView rv = new RecyclerView(getActivity());
-        TestAdapter testAdapter = new TestAdapter(500);
-        rv.setLayoutManager(lm);
-        rv.setAdapter(testAdapter);
-        lm.expectLayouts(1);
-        setRecyclerView(rv);
-        lm.waitForLayout(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                rv.smoothScrollBy(0, 2000);
-            }
-        });
-        Thread.sleep(250);
-        final AtomicInteger scrollAmt = new AtomicInteger();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final int soFar = totalScrolled.get();
-                scrollAmt.set(soFar);
-                rv.smoothScrollBy(0, 5000 - soFar);
-            }
-        });
-        while (rv.getScrollState() != SCROLL_STATE_IDLE) {
-            Thread.sleep(100);
-        }
-        final int soFar = totalScrolled.get();
-        assertEquals("second scroll should be competed properly", 5000, soFar);
-    }
-
-    public void accessRecyclerOnOnMeasureTest(final boolean enablePredictiveAnimations)
-            throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        final AtomicInteger expectedOnMeasureStateCount = new AtomicInteger(10);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                try {
-                    layoutRange(recycler, 0, state.getItemCount());
-                    layoutLatch.countDown();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
-                    int widthSpec, int heightSpec) {
-                try {
-                    // make sure we access all views
-                    for (int i = 0; i < state.getItemCount(); i++) {
-                        View view = recycler.getViewForPosition(i);
-                        assertNotNull(view);
-                        assertEquals(i, getPosition(view));
-                    }
-                    if (!state.isPreLayout()) {
-                        assertEquals(state.toString(),
-                                expectedOnMeasureStateCount.get(), state.getItemCount());
-                    }
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-                super.onMeasure(recycler, state, widthSpec, heightSpec);
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return enablePredictiveAnimations;
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-        lm.expectLayouts(1);
-        if (!enablePredictiveAnimations) {
-            expectedOnMeasureStateCount.set(15);
-        }
-        testAdapter.addAndNotify(4, 5);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void setCompatibleAdapter() throws Throwable {
-        compatibleAdapterTest(true, true);
-        removeRecyclerView();
-        compatibleAdapterTest(false, true);
-        removeRecyclerView();
-        compatibleAdapterTest(true, false);
-        removeRecyclerView();
-        compatibleAdapterTest(false, false);
-        removeRecyclerView();
-    }
-
-    private void compatibleAdapterTest(boolean useCustomPool, boolean removeAndRecycleExistingViews)
-            throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        final AtomicInteger recycledViewCount = new AtomicInteger();
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    layoutRange(recycler, 0, state.getItemCount());
-                    layoutLatch.countDown();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setRecyclerListener(new RecyclerView.RecyclerListener() {
-            @Override
-            public void onViewRecycled(RecyclerView.ViewHolder holder) {
-                recycledViewCount.incrementAndGet();
-            }
-        });
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView, !useCustomPool);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-        lm.expectLayouts(1);
-        swapAdapter(new TestAdapter(10), removeAndRecycleExistingViews);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-        if (removeAndRecycleExistingViews) {
-            assertTrue("Previous views should be recycled", recycledViewCount.get() > 0);
-        } else {
-            assertEquals("No views should be recycled if adapters are compatible and developer "
-                    + "did not request a recycle", 0, recycledViewCount.get());
-        }
-    }
-
-    @Test
-    public void setIncompatibleAdapter() throws Throwable {
-        incompatibleAdapterTest(true);
-        incompatibleAdapterTest(false);
-    }
-
-    public void incompatibleAdapterTest(boolean useCustomPool) throws Throwable {
-        TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                try {
-                    layoutRange(recycler, 0, state.getItemCount());
-                    layoutLatch.countDown();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView, !useCustomPool);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-        lm.expectLayouts(1);
-        setAdapter(new TestAdapter2(10));
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void recycleIgnored() throws Throwable {
-        final TestAdapter adapter = new TestAdapter(10);
-        final TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                layoutRange(recycler, 0, 5);
-                layoutLatch.countDown();
-            }
-        };
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                View child1 = lm.findViewByPosition(0);
-                View child2 = lm.findViewByPosition(1);
-                lm.ignoreView(child1);
-                lm.ignoreView(child2);
-
-                lm.removeAndRecycleAllViews(recyclerView.mRecycler);
-                assertEquals("ignored child should not be recycled or removed", 2,
-                        lm.getChildCount());
-
-                Throwable[] throwables = new Throwable[1];
-                try {
-                    lm.removeAndRecycleView(child1, mRecyclerView.mRecycler);
-                } catch (Throwable t) {
-                    throwables[0] = t;
-                }
-                assertTrue("Trying to recycle an ignored view should throw IllegalArgException "
-                        , throwables[0] instanceof IllegalArgumentException);
-                lm.removeAllViews();
-                assertEquals("ignored child should be removed as well ", 0, lm.getChildCount());
-            }
-        });
-    }
-
-    @Test
-    public void findIgnoredByPosition() throws Throwable {
-        final TestAdapter adapter = new TestAdapter(10);
-        final TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, 5);
-                layoutLatch.countDown();
-            }
-        };
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        Thread.sleep(5000);
-        final int pos = 1;
-        final View[] ignored = new View[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                View child = lm.findViewByPosition(pos);
-                lm.ignoreView(child);
-                ignored[0] = child;
-            }
-        });
-        assertNotNull("ignored child should not be null", ignored[0]);
-        assertNull("find view by position should not return ignored child",
-                lm.findViewByPosition(pos));
-        lm.expectLayouts(1);
-        requestLayoutOnUIThread(mRecyclerView);
-        lm.waitForLayout(1);
-        assertEquals("child count should be ", 6, lm.getChildCount());
-        View replacement = lm.findViewByPosition(pos);
-        assertNotNull("re-layout should replace ignored child w/ another one", replacement);
-        assertNotSame("replacement should be a different view", replacement, ignored[0]);
-    }
-
-    @Test
-    public void itemDecorsWithPredictive() throws Throwable {
-        LayoutAllLayoutManager lm = new LayoutAllLayoutManager(true);
-        lm.setSupportsPredictive(true);
-        final Object changePayload = new Object();
-        final TestAdapter adapter = new TestAdapter(10) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position, List<Object> payloads) {
-                super.onBindViewHolder(holder, position);
-                holder.setData(payloads.isEmpty() ? null : payloads.get(0));
-            }
-        };
-        final Map<Integer, Object> preLayoutData = new HashMap<>();
-        final Map<Integer, Object> postLayoutData = new HashMap<>();
-
-        final RecyclerView.ItemDecoration decoration = new RecyclerView.ItemDecoration() {
-            @Override
-            public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                    RecyclerView.State state) {
-                try {
-                    TestViewHolder tvh = (TestViewHolder) parent.getChildViewHolder(view);
-                    Object data = tvh.getData();
-                    int adapterPos = tvh.getAdapterPosition();
-                    assertThat(adapterPos, is(not(NO_POSITION)));
-                    if (state.isPreLayout()) {
-                        preLayoutData.put(adapterPos, data);
-                    } else {
-                        postLayoutData.put(adapterPos, data);
-                    }
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-
-            }
-        };
-        RecyclerView rv = new RecyclerView(getActivity());
-        rv.addItemDecoration(decoration);
-        rv.setAdapter(adapter);
-        rv.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(rv);
-        lm.waitForLayout(2);
-
-        preLayoutData.clear();
-        postLayoutData.clear();
-        lm.expectLayouts(2);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                adapter.notifyItemChanged(3, changePayload);
-            }
-        });
-        lm.waitForLayout(2);
-        assertThat(preLayoutData.containsKey(3), is(false));
-        assertThat(postLayoutData.get(3), is(changePayload));
-        assertThat(preLayoutData.size(), is(0));
-        assertThat(postLayoutData.size(), is(1));
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void invalidateAllDecorOffsets() throws Throwable {
-        final TestAdapter adapter = new TestAdapter(10);
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final AtomicBoolean invalidatedOffsets = new AtomicBoolean(true);
-        recyclerView.setAdapter(adapter);
-        final AtomicInteger layoutCount = new AtomicInteger(4);
-        final RecyclerView.ItemDecoration dummyItemDecoration = new RecyclerView.ItemDecoration() {
-        };
-        TestLayoutManager testLayoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    // test
-                    for (int i = 0; i < getChildCount(); i++) {
-                        View child = getChildAt(i);
-                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
-                                child.getLayoutParams();
-                        assertEquals(
-                                "Decor insets validation for VH should have expected value.",
-                                invalidatedOffsets.get(), lp.mInsetsDirty);
-                    }
-                    for (RecyclerView.ViewHolder vh : mRecyclerView.mRecycler.mCachedViews) {
-                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
-                                vh.itemView.getLayoutParams();
-                        assertEquals(
-                                "Decor insets invalidation in cache for VH should have expected "
-                                        + "value.",
-                                invalidatedOffsets.get(), lp.mInsetsDirty);
-                    }
-                    detachAndScrapAttachedViews(recycler);
-                    layoutRange(recycler, 0, layoutCount.get());
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return false;
-            }
-        };
-        // first layout
-        recyclerView.setItemViewCacheSize(5);
-        recyclerView.setLayoutManager(testLayoutManager);
-        testLayoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView, true, false);
-        testLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-
-        // re-layout w/o any change
-        invalidatedOffsets.set(false);
-        testLayoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-
-        // invalidate w/o an item decorator
-
-        invalidateDecorOffsets(recyclerView);
-        testLayoutManager.expectLayouts(1);
-        invalidateDecorOffsets(recyclerView);
-        testLayoutManager.assertNoLayout("layout should not happen", 2);
-        checkForMainThreadException();
-
-        // set item decorator, should invalidate
-        invalidatedOffsets.set(true);
-        testLayoutManager.expectLayouts(1);
-        addItemDecoration(mRecyclerView, dummyItemDecoration);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-
-        // re-layout w/o any change
-        invalidatedOffsets.set(false);
-        testLayoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-
-        // invalidate w/ item decorator
-        invalidatedOffsets.set(true);
-        invalidateDecorOffsets(recyclerView);
-        testLayoutManager.expectLayouts(1);
-        invalidateDecorOffsets(recyclerView);
-        testLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-
-        // trigger cache.
-        layoutCount.set(3);
-        invalidatedOffsets.set(false);
-        testLayoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(mRecyclerView);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-        assertEquals("a view should be cached", 1, mRecyclerView.mRecycler.mCachedViews.size());
-
-        layoutCount.set(5);
-        invalidatedOffsets.set(true);
-        testLayoutManager.expectLayouts(1);
-        invalidateDecorOffsets(recyclerView);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-
-        // remove item decorator
-        invalidatedOffsets.set(true);
-        testLayoutManager.expectLayouts(1);
-        removeItemDecoration(mRecyclerView, dummyItemDecoration);
-        testLayoutManager.waitForLayout(1);
-        checkForMainThreadException();
-    }
-
-    public void addItemDecoration(final RecyclerView recyclerView, final
-    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.addItemDecoration(itemDecoration);
-            }
-        });
-    }
-
-    public void removeItemDecoration(final RecyclerView recyclerView, final
-    RecyclerView.ItemDecoration itemDecoration) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.removeItemDecoration(itemDecoration);
-            }
-        });
-    }
-
-    public void invalidateDecorOffsets(final RecyclerView recyclerView) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.invalidateItemDecorations();
-            }
-        });
-    }
-
-    @Test
-    public void invalidateDecorOffsets() throws Throwable {
-        final TestAdapter adapter = new TestAdapter(10);
-        adapter.setHasStableIds(true);
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(adapter);
-
-        final Map<Long, Boolean> changes = new HashMap<>();
-
-        TestLayoutManager testLayoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    if (changes.size() > 0) {
-                        // test
-                        for (int i = 0; i < getChildCount(); i++) {
-                            View child = getChildAt(i);
-                            RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams)
-                                    child.getLayoutParams();
-                            RecyclerView.ViewHolder vh = lp.mViewHolder;
-                            if (!changes.containsKey(vh.getItemId())) {
-                                continue; //nothing to test
-                            }
-                            assertEquals(
-                                    "Decor insets validation for VH should have expected value.",
-                                    changes.get(vh.getItemId()), lp.mInsetsDirty);
-                        }
-                    }
-                    detachAndScrapAttachedViews(recycler);
-                    layoutRange(recycler, 0, state.getItemCount());
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return false;
-            }
-        };
-        recyclerView.setLayoutManager(testLayoutManager);
-        testLayoutManager.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        testLayoutManager.waitForLayout(2);
-        int itemAddedTo = 5;
-        for (int i = 0; i < itemAddedTo; i++) {
-            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
-        }
-        for (int i = itemAddedTo; i < mRecyclerView.getChildCount(); i++) {
-            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
-        }
-        testLayoutManager.expectLayouts(1);
-        adapter.addAndNotify(5, 1);
-        testLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-
-        changes.clear();
-        int[] changedItems = new int[]{3, 5, 6};
-        for (int i = 0; i < adapter.getItemCount(); i++) {
-            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), false);
-        }
-        for (int changedItem : changedItems) {
-            changes.put(mRecyclerView.findViewHolderForLayoutPosition(changedItem).getItemId(),
-                    true);
-        }
-        testLayoutManager.expectLayouts(1);
-        adapter.changePositionsAndNotify(changedItems);
-        testLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-
-        for (int i = 0; i < adapter.getItemCount(); i++) {
-            changes.put(mRecyclerView.findViewHolderForLayoutPosition(i).getItemId(), true);
-        }
-        testLayoutManager.expectLayouts(1);
-        adapter.dispatchDataSetChanged();
-        testLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void movingViaStableIds() throws Throwable {
-        stableIdsMoveTest(true);
-        removeRecyclerView();
-        stableIdsMoveTest(false);
-        removeRecyclerView();
-    }
-
-    public void stableIdsMoveTest(final boolean supportsPredictive) throws Throwable {
-        final TestAdapter testAdapter = new TestAdapter(10);
-        testAdapter.setHasStableIds(true);
-        final AtomicBoolean test = new AtomicBoolean(false);
-        final int movedViewFromIndex = 3;
-        final int movedViewToIndex = 6;
-        final View[] movedView = new View[1];
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                try {
-                    if (test.get()) {
-                        if (state.isPreLayout()) {
-                            View view = recycler.getViewForPosition(movedViewFromIndex, true);
-                            assertSame("In pre layout, should be able to get moved view w/ old "
-                                    + "position", movedView[0], view);
-                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
-                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
-                            // clear scrap flag
-                            holder.clearReturnedFromScrapFlag();
-                        } else {
-                            View view = recycler.getViewForPosition(movedViewToIndex, true);
-                            assertSame("In post layout, should be able to get moved view w/ new "
-                                    + "position", movedView[0], view);
-                            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(view);
-                            assertTrue("it should come from scrap", holder.wasReturnedFromScrap());
-                            // clear scrap flag
-                            holder.clearReturnedFromScrapFlag();
-                        }
-                    }
-                    layoutRange(recycler, 0, state.getItemCount());
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-
-
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return supportsPredictive;
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(this.getActivity());
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(1);
-
-        movedView[0] = recyclerView.getChildAt(movedViewFromIndex);
-        test.set(true);
-        lm.expectLayouts(supportsPredictive ? 2 : 1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                Item item = testAdapter.mItems.remove(movedViewFromIndex);
-                testAdapter.mItems.add(movedViewToIndex, item);
-                testAdapter.notifyItemRemoved(movedViewFromIndex);
-                testAdapter.notifyItemInserted(movedViewToIndex);
-            }
-        });
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void adapterChangeDuringLayout() throws Throwable {
-        adapterChangeInMainThreadTest("notifyDataSetChanged", new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.getAdapter().notifyDataSetChanged();
-            }
-        });
-
-        adapterChangeInMainThreadTest("notifyItemChanged", new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.getAdapter().notifyItemChanged(2);
-            }
-        });
-
-        adapterChangeInMainThreadTest("notifyItemInserted", new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.getAdapter().notifyItemInserted(2);
-            }
-        });
-        adapterChangeInMainThreadTest("notifyItemRemoved", new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.getAdapter().notifyItemRemoved(2);
-            }
-        });
-    }
-
-    public void adapterChangeInMainThreadTest(String msg,
-            final Runnable onLayoutRunnable) throws Throwable {
-        setIgnoreMainThreadException(true);
-        final AtomicBoolean doneFirstLayout = new AtomicBoolean(false);
-        TestAdapter testAdapter = new TestAdapter(10);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                try {
-                    layoutRange(recycler, 0, state.getItemCount());
-                    if (doneFirstLayout.get()) {
-                        onLayoutRunnable.run();
-                    }
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setAdapter(testAdapter);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        doneFirstLayout.set(true);
-        lm.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        lm.waitForLayout(2);
-        removeRecyclerView();
-        assertTrue("Invalid data updates should be caught:" + msg,
-                getMainThreadException() instanceof IllegalStateException);
-    }
-
-    @Test
-    public void adapterChangeDuringScroll() throws Throwable {
-        for (int orientation : new int[]{OrientationHelper.HORIZONTAL,
-                OrientationHelper.VERTICAL}) {
-            adapterChangeDuringScrollTest("notifyDataSetChanged", orientation,
-                    new Runnable() {
-                        @Override
-                        public void run() {
-                            mRecyclerView.getAdapter().notifyDataSetChanged();
-                        }
-                    });
-            adapterChangeDuringScrollTest("notifyItemChanged", orientation, new Runnable() {
-                @Override
-                public void run() {
-                    mRecyclerView.getAdapter().notifyItemChanged(2);
-                }
-            });
-
-            adapterChangeDuringScrollTest("notifyItemInserted", orientation, new Runnable() {
-                @Override
-                public void run() {
-                    mRecyclerView.getAdapter().notifyItemInserted(2);
-                }
-            });
-            adapterChangeDuringScrollTest("notifyItemRemoved", orientation, new Runnable() {
-                @Override
-                public void run() {
-                    mRecyclerView.getAdapter().notifyItemRemoved(2);
-                }
-            });
-        }
-    }
-
-    public void adapterChangeDuringScrollTest(String msg, final int orientation,
-            final Runnable onScrollRunnable) throws Throwable {
-        setIgnoreMainThreadException(true);
-        TestAdapter testAdapter = new TestAdapter(100);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                try {
-                    layoutRange(recycler, 0, 10);
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return orientation == OrientationHelper.VERTICAL;
-            }
-
-            @Override
-            public boolean canScrollHorizontally() {
-                return orientation == OrientationHelper.HORIZONTAL;
-            }
-
-            public int mockScroll() {
-                try {
-                    onScrollRunnable.run();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-                return 0;
-            }
-
-            @Override
-            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                return mockScroll();
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                return mockScroll();
-            }
-        };
-        RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setAdapter(testAdapter);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        lm.expectLayouts(1);
-        scrollBy(200);
-        lm.waitForLayout(2);
-        removeRecyclerView();
-        assertTrue("Invalid data updates should be caught:" + msg,
-                getMainThreadException() instanceof IllegalStateException);
-    }
-
-    @Test
-    public void recycleOnDetach() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final TestAdapter testAdapter = new TestAdapter(10);
-        final AtomicBoolean didRunOnDetach = new AtomicBoolean(false);
-        final TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                layoutRange(recycler, 0, state.getItemCount() - 1);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
-                super.onDetachedFromWindow(view, recycler);
-                didRunOnDetach.set(true);
-                removeAndRecycleAllViews(recycler);
-            }
-        };
-        recyclerView.setAdapter(testAdapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        removeRecyclerView();
-        assertTrue("When recycler view is removed, detach should run", didRunOnDetach.get());
-        assertEquals("All children should be recycled", recyclerView.getChildCount(), 0);
-    }
-
-    @Test
-    public void updatesWhileDetached() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final int initialAdapterSize = 20;
-        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
-        final AtomicInteger layoutCount = new AtomicInteger(0);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                layoutRange(recycler, 0, 5);
-                layoutCount.incrementAndGet();
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setHasFixedSize(true);
-        lm.expectLayouts(1);
-        adapter.addAndNotify(4, 5);
-        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
-    }
-
-    @Test
-    public void updatesAfterDetach() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final int initialAdapterSize = 20;
-        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
-        final AtomicInteger layoutCount = new AtomicInteger(0);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                layoutRange(recycler, 0, 5);
-                layoutCount.incrementAndGet();
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        recyclerView.setHasFixedSize(true);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        lm.expectLayouts(1);
-        final int prevLayoutCount = layoutCount.get();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    adapter.addAndNotify(4, 5);
-                    removeRecyclerView();
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-        checkForMainThreadException();
-
-        lm.assertNoLayout("When RV is not attached, layout should not happen", 1);
-        assertEquals("No extra layout should happen when detached", prevLayoutCount,
-                layoutCount.get());
-    }
-
-    @Test
-    public void notifyDataSetChangedWithStableIds() throws Throwable {
-        final Map<Integer, Integer> oldPositionToNewPositionMapping = new HashMap<>();
-        final TestAdapter adapter = new TestAdapter(100) {
-            @Override
-            public long getItemId(int position) {
-                return mItems.get(position).mId;
-            }
-        };
-        adapter.setHasStableIds(true);
-        final ArrayList<Item> previousItems = new ArrayList<>();
-        previousItems.addAll(adapter.mItems);
-
-        final AtomicInteger layoutStart = new AtomicInteger(50);
-        final AtomicBoolean validate = new AtomicBoolean(false);
-        final int childCount = 10;
-        final TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    super.onLayoutChildren(recycler, state);
-                    if (validate.get()) {
-                        assertEquals("Cached views should be kept", 5, recycler
-                                .mCachedViews.size());
-                        for (RecyclerView.ViewHolder vh : recycler.mCachedViews) {
-                            TestViewHolder tvh = (TestViewHolder) vh;
-                            assertTrue("view holder should be marked for update",
-                                    tvh.needsUpdate());
-                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
-                        }
-                    }
-                    detachAndScrapAttachedViews(recycler);
-                    if (validate.get()) {
-                        assertEquals("cache size should stay the same", 5,
-                                recycler.mCachedViews.size());
-                        assertEquals("all views should be scrapped", childCount,
-                                recycler.getScrapList().size());
-                        for (RecyclerView.ViewHolder vh : recycler.getScrapList()) {
-                            // TODO create test case for type change
-                            TestViewHolder tvh = (TestViewHolder) vh;
-                            assertTrue("view holder should be marked for update",
-                                    tvh.needsUpdate());
-                            assertTrue("view holder should be marked as invalid", tvh.isInvalid());
-                        }
-                    }
-                    layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
-                    if (validate.get()) {
-                        for (int i = 0; i < getChildCount(); i++) {
-                            View view = getChildAt(i);
-                            TestViewHolder tvh = (TestViewHolder) mRecyclerView
-                                    .getChildViewHolder(view);
-                            final int oldPos = previousItems.indexOf(tvh.mBoundItem);
-                            assertEquals("view holder's position should be correct",
-                                    oldPositionToNewPositionMapping.get(oldPos).intValue(),
-                                    tvh.getLayoutPosition());
-                        }
-                    }
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-        };
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setItemAnimator(null);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setItemViewCacheSize(10);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-        getInstrumentation().waitForIdleSync();
-        layoutStart.set(layoutStart.get() + 5);//55
-        lm.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        lm.waitForLayout(2);
-        validate.set(true);
-        lm.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    adapter.moveItems(false,
-                            new int[]{50, 56}, new int[]{51, 1}, new int[]{52, 2},
-                            new int[]{53, 54}, new int[]{60, 61}, new int[]{62, 64},
-                            new int[]{75, 58});
-                    for (int i = 0; i < previousItems.size(); i++) {
-                        Item item = previousItems.get(i);
-                        oldPositionToNewPositionMapping.put(i, adapter.mItems.indexOf(item));
-                    }
-                    adapter.dispatchDataSetChanged();
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void callbacksDuringAdapterSwap() throws Throwable {
-        callbacksDuringAdapterChange(true);
-    }
-
-    @Test
-    public void callbacksDuringAdapterSet() throws Throwable {
-        callbacksDuringAdapterChange(false);
-    }
-
-    public void callbacksDuringAdapterChange(boolean swap) throws Throwable {
-        final TestAdapter2 adapter1 = swap ? createBinderCheckingAdapter()
-                : createOwnerCheckingAdapter();
-        final TestAdapter2 adapter2 = swap ? createBinderCheckingAdapter()
-                : createOwnerCheckingAdapter();
-
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    layoutRange(recycler, 0, state.getItemCount());
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-                layoutLatch.countDown();
-            }
-        };
-        RecyclerView rv = new RecyclerView(getActivity());
-        rv.setAdapter(adapter1);
-        rv.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(1);
-        checkForMainThreadException();
-        tlm.expectLayouts(1);
-        if (swap) {
-            swapAdapter(adapter2, true);
-        } else {
-            setAdapter(adapter2);
-        }
-        checkForMainThreadException();
-        tlm.waitForLayout(1);
-        checkForMainThreadException();
-    }
-
-    private TestAdapter2 createOwnerCheckingAdapter() {
-        return new TestAdapter2(10) {
-            @Override
-            public void onViewRecycled(TestViewHolder2 holder) {
-                assertSame("on recycled should be called w/ the creator adapter", this,
-                        holder.mData);
-                super.onViewRecycled(holder);
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder2 holder, int position) {
-                super.onBindViewHolder(holder, position);
-                assertSame("on bind should be called w/ the creator adapter", this, holder.mData);
-            }
-
-            @Override
-            public TestViewHolder2 onCreateViewHolder(ViewGroup parent,
-                    int viewType) {
-                final TestViewHolder2 vh = super.onCreateViewHolder(parent, viewType);
-                vh.mData = this;
-                return vh;
-            }
-        };
-    }
-
-    private TestAdapter2 createBinderCheckingAdapter() {
-        return new TestAdapter2(10) {
-            @Override
-            public void onViewRecycled(TestViewHolder2 holder) {
-                assertSame("on recycled should be called w/ the creator adapter", this,
-                        holder.mData);
-                holder.mData = null;
-                super.onViewRecycled(holder);
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder2 holder, int position) {
-                super.onBindViewHolder(holder, position);
-                holder.mData = this;
-            }
-        };
-    }
-
-    @Test
-    public void findViewById() throws Throwable {
-        findViewByIdTest(false);
-        removeRecyclerView();
-        findViewByIdTest(true);
-    }
-
-    public void findViewByIdTest(final boolean supportPredictive) throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final int initialAdapterSize = 20;
-        final TestAdapter adapter = new TestAdapter(initialAdapterSize);
-        final int deleteStart = 6;
-        final int deleteCount = 5;
-        recyclerView.setAdapter(adapter);
-        final AtomicBoolean assertPositions = new AtomicBoolean(false);
-        TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                if (assertPositions.get()) {
-                    if (state.isPreLayout()) {
-                        for (int i = 0; i < deleteStart; i++) {
-                            View view = findViewByPosition(i);
-                            assertNotNull("find view by position for existing items should work "
-                                    + "fine", view);
-                            assertFalse("view should not be marked as removed",
-                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
-                                            .isItemRemoved());
-                        }
-                        for (int i = 0; i < deleteCount; i++) {
-                            View view = findViewByPosition(i + deleteStart);
-                            assertNotNull("find view by position should work fine for removed "
-                                    + "views in pre-layout", view);
-                            assertTrue("view should be marked as removed",
-                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
-                                            .isItemRemoved());
-                        }
-                        for (int i = deleteStart + deleteCount; i < 20; i++) {
-                            View view = findViewByPosition(i);
-                            assertNotNull(view);
-                            assertFalse("view should not be marked as removed",
-                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
-                                            .isItemRemoved());
-                        }
-                    } else {
-                        for (int i = 0; i < initialAdapterSize - deleteCount; i++) {
-                            View view = findViewByPosition(i);
-                            assertNotNull("find view by position for existing item " + i +
-                                    " should work fine. child count:" + getChildCount(), view);
-                            TestViewHolder viewHolder =
-                                    (TestViewHolder) mRecyclerView.getChildViewHolder(view);
-                            assertSame("should be the correct item " + viewHolder
-                                    , viewHolder.mBoundItem,
-                                    adapter.mItems.get(viewHolder.mPosition));
-                            assertFalse("view should not be marked as removed",
-                                    ((RecyclerView.LayoutParams) view.getLayoutParams())
-                                            .isItemRemoved());
-                        }
-                    }
-                }
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, state.getItemCount() - 1, -1);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return supportPredictive;
-            }
-        };
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        getInstrumentation().waitForIdleSync();
-
-        assertPositions.set(true);
-        lm.expectLayouts(supportPredictive ? 2 : 1);
-        adapter.deleteAndNotify(new int[]{deleteStart, deleteCount - 1}, new int[]{deleteStart, 1});
-        lm.waitForLayout(2);
-    }
-
-    @Test
-    public void typeForCache() throws Throwable {
-        final AtomicInteger viewType = new AtomicInteger(1);
-        final TestAdapter adapter = new TestAdapter(100) {
-            @Override
-            public int getItemViewType(int position) {
-                return viewType.get();
-            }
-
-            @Override
-            public long getItemId(int position) {
-                return mItems.get(position).mId;
-            }
-        };
-        adapter.setHasStableIds(true);
-        final AtomicInteger layoutStart = new AtomicInteger(2);
-        final int childCount = 10;
-        final TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, layoutStart.get(), layoutStart.get() + childCount);
-                layoutLatch.countDown();
-            }
-        };
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setItemAnimator(null);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        recyclerView.setItemViewCacheSize(10);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        getInstrumentation().waitForIdleSync();
-        layoutStart.set(4); // trigger a cache for 3,4
-        lm.expectLayouts(1);
-        requestLayoutOnUIThread(recyclerView);
-        lm.waitForLayout(2);
-        //
-        viewType.incrementAndGet();
-        layoutStart.set(2); // go back to bring views from cache
-        lm.expectLayouts(1);
-        adapter.mItems.remove(1);
-        adapter.dispatchDataSetChanged();
-        lm.waitForLayout(2);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 2; i < 4; i++) {
-                    RecyclerView.ViewHolder vh = recyclerView.findViewHolderForLayoutPosition(i);
-                    assertEquals("View holder's type should match latest type", viewType.get(),
-                            vh.getItemViewType());
-                }
-            }
-        });
-    }
-
-    @Test
-    public void typeForExistingViews() throws Throwable {
-        final AtomicInteger viewType = new AtomicInteger(1);
-        final int invalidatedCount = 2;
-        final int layoutStart = 2;
-        final TestAdapter adapter = new TestAdapter(100) {
-            @Override
-            public int getItemViewType(int position) {
-                return viewType.get();
-            }
-
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (position >= layoutStart && position < invalidatedCount + layoutStart) {
-                    try {
-                        assertEquals("holder type should match current view type at position " +
-                                position, viewType.get(), holder.getItemViewType());
-                    } catch (Throwable t) {
-                        postExceptionToInstrumentation(t);
-                    }
-                }
-            }
-
-            @Override
-            public long getItemId(int position) {
-                return mItems.get(position).mId;
-            }
-        };
-        adapter.setHasStableIds(true);
-
-        final int childCount = 10;
-        final TestLayoutManager lm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, layoutStart, layoutStart + childCount);
-                layoutLatch.countDown();
-            }
-        };
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(lm);
-        lm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        lm.waitForLayout(2);
-        getInstrumentation().waitForIdleSync();
-        viewType.incrementAndGet();
-        lm.expectLayouts(1);
-        adapter.changeAndNotify(layoutStart, invalidatedCount);
-        lm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-
-    @Test
-    public void state() throws Throwable {
-        final TestAdapter adapter = new TestAdapter(10);
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        recyclerView.setAdapter(adapter);
-        recyclerView.setItemAnimator(null);
-        final AtomicInteger itemCount = new AtomicInteger();
-        final AtomicBoolean structureChanged = new AtomicBoolean();
-        TestLayoutManager testLayoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, state.getItemCount());
-                itemCount.set(state.getItemCount());
-                structureChanged.set(state.didStructureChange());
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.setLayoutManager(testLayoutManager);
-        testLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().addView(recyclerView);
-            }
-        });
-        testLayoutManager.waitForLayout(2);
-
-        assertEquals("item count in state should be correct", adapter.getItemCount()
-                , itemCount.get());
-        assertEquals("structure changed should be true for first layout", true,
-                structureChanged.get());
-        Thread.sleep(1000); //wait for other layouts.
-        testLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.requestLayout();
-            }
-        });
-        testLayoutManager.waitForLayout(2);
-        assertEquals("in second layout,structure changed should be false", false,
-                structureChanged.get());
-        testLayoutManager.expectLayouts(1); //
-        adapter.deleteAndNotify(3, 2);
-        testLayoutManager.waitForLayout(2);
-        assertEquals("when items are removed, item count in state should be updated",
-                adapter.getItemCount(),
-                itemCount.get());
-        assertEquals("structure changed should be true when items are removed", true,
-                structureChanged.get());
-        testLayoutManager.expectLayouts(1);
-        adapter.addAndNotify(2, 5);
-        testLayoutManager.waitForLayout(2);
-
-        assertEquals("when items are added, item count in state should be updated",
-                adapter.getItemCount(),
-                itemCount.get());
-        assertEquals("structure changed should be true when items are removed", true,
-                structureChanged.get());
-    }
-
-    @Test
-    public void detachWithoutLayoutManager() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    setRecyclerView(recyclerView);
-                    removeRecyclerView();
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        });
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void updateHiddenView() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final int[] preLayoutRange = new int[]{0, 10};
-        final int[] postLayoutRange = new int[]{0, 10};
-        final AtomicBoolean enableGetViewTest = new AtomicBoolean(false);
-        final List<Integer> disappearingPositions = new ArrayList<>();
-        final TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return true;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    final int[] layoutRange = state.isPreLayout() ? preLayoutRange
-                            : postLayoutRange;
-                    detachAndScrapAttachedViews(recycler);
-                    layoutRange(recycler, layoutRange[0], layoutRange[1]);
-                    if (!state.isPreLayout()) {
-                        for (Integer position : disappearingPositions) {
-                            // test sanity.
-                            assertNull(findViewByPosition(position));
-                            final View view = recycler.getViewForPosition(position);
-                            assertNotNull(view);
-                            addDisappearingView(view);
-                            measureChildWithMargins(view, 0, 0);
-                            // position item out of bounds.
-                            view.layout(0, -500, view.getMeasuredWidth(),
-                                    -500 + view.getMeasuredHeight());
-                        }
-                    }
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-                layoutLatch.countDown();
-            }
-        };
-        recyclerView.getItemAnimator().setMoveDuration(4000);
-        recyclerView.getItemAnimator().setRemoveDuration(4000);
-        final TestAdapter adapter = new TestAdapter(100);
-        recyclerView.setAdapter(adapter);
-        recyclerView.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(recyclerView);
-        tlm.waitForLayout(1);
-        checkForMainThreadException();
-        // now, a child disappears
-        disappearingPositions.add(0);
-        // layout one shifted
-        postLayoutRange[0] = 1;
-        postLayoutRange[1] = 11;
-        tlm.expectLayouts(2);
-        adapter.addAndNotify(8, 1);
-        tlm.waitForLayout(2);
-        checkForMainThreadException();
-
-        tlm.expectLayouts(2);
-        disappearingPositions.clear();
-        // now that item should be moving, invalidate it and delete it.
-        enableGetViewTest.set(true);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    assertThat("test sanity, should still be animating",
-                            mRecyclerView.isAnimating(), CoreMatchers.is(true));
-                    adapter.changeAndNotify(0, 1);
-                    adapter.deleteAndNotify(0, 1);
-                } catch (Throwable throwable) {
-                    fail(throwable.getMessage());
-                }
-            }
-        });
-        tlm.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void focusBigViewOnTop() throws Throwable {
-        focusTooBigViewTest(Gravity.TOP);
-    }
-
-    @Test
-    public void focusBigViewOnLeft() throws Throwable {
-        focusTooBigViewTest(Gravity.LEFT);
-    }
-
-    @Test
-    public void focusBigViewOnRight() throws Throwable {
-        focusTooBigViewTest(Gravity.RIGHT);
-    }
-
-    @Test
-    public void focusBigViewOnBottom() throws Throwable {
-        focusTooBigViewTest(Gravity.BOTTOM);
-    }
-
-    @Test
-    public void focusBigViewOnLeftRTL() throws Throwable {
-        focusTooBigViewTest(Gravity.LEFT, true);
-        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
-                mRecyclerView.getLayoutManager().getLayoutDirection());
-    }
-
-    @Test
-    public void focusBigViewOnRightRTL() throws Throwable {
-        focusTooBigViewTest(Gravity.RIGHT, true);
-        assertEquals("test sanity", ViewCompat.LAYOUT_DIRECTION_RTL,
-                mRecyclerView.getLayoutManager().getLayoutDirection());
-    }
-
-    public void focusTooBigViewTest(final int gravity) throws Throwable {
-        focusTooBigViewTest(gravity, false);
-    }
-
-    public void focusTooBigViewTest(final int gravity, final boolean rtl) throws Throwable {
-        RecyclerView rv = new RecyclerView(getActivity());
-        if (rtl) {
-            ViewCompat.setLayoutDirection(rv, ViewCompat.LAYOUT_DIRECTION_RTL);
-        }
-        final AtomicInteger vScrollDist = new AtomicInteger(0);
-        final AtomicInteger hScrollDist = new AtomicInteger(0);
-        final AtomicInteger vDesiredDist = new AtomicInteger(0);
-        final AtomicInteger hDesiredDist = new AtomicInteger(0);
-        TestLayoutManager tlm = new TestLayoutManager() {
-
-            @Override
-            public int getLayoutDirection() {
-                return rtl ? ViewCompat.LAYOUT_DIRECTION_RTL : ViewCompat.LAYOUT_DIRECTION_LTR;
-            }
-
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                final View view = recycler.getViewForPosition(0);
-                addView(view);
-                int left = 0, top = 0;
-                view.setBackgroundColor(Color.rgb(0, 0, 255));
-                switch (gravity) {
-                    case Gravity.LEFT:
-                    case Gravity.RIGHT:
-                        view.measure(
-                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * 1.5),
-                                        View.MeasureSpec.EXACTLY),
-                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * .9),
-                                        View.MeasureSpec.AT_MOST));
-                        left = gravity == Gravity.LEFT ? getWidth() - view.getMeasuredWidth() - 80
-                                : 90;
-                        top = 0;
-                        if (ViewCompat.LAYOUT_DIRECTION_RTL == getLayoutDirection()) {
-                            hDesiredDist.set((left + view.getMeasuredWidth()) - getWidth());
-                        } else {
-                            hDesiredDist.set(left);
-                        }
-                        break;
-                    case Gravity.TOP:
-                    case Gravity.BOTTOM:
-                        view.measure(
-                                View.MeasureSpec.makeMeasureSpec((int) (getWidth() * .9),
-                                        View.MeasureSpec.AT_MOST),
-                                View.MeasureSpec.makeMeasureSpec((int) (getHeight() * 1.5),
-                                        View.MeasureSpec.EXACTLY));
-                        top = gravity == Gravity.TOP ? getHeight() - view.getMeasuredHeight() -
-                                80 : 90;
-                        left = 0;
-                        vDesiredDist.set(top);
-                        break;
-                }
-
-                view.layout(left, top, left + view.getMeasuredWidth(),
-                        top + view.getMeasuredHeight());
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public boolean canScrollHorizontally() {
-                return super.canScrollHorizontally();
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                vScrollDist.addAndGet(dy);
-                getChildAt(0).offsetTopAndBottom(-dy);
-                return dy;
-            }
-
-            @Override
-            public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                hScrollDist.addAndGet(dx);
-                getChildAt(0).offsetLeftAndRight(-dx);
-                return dx;
-            }
-        };
-        TestAdapter adapter = new TestAdapter(10);
-        rv.setAdapter(adapter);
-        rv.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(2);
-        View view = rv.getChildAt(0);
-        assertTrue("test sanity", requestFocus(view, true));
-        assertTrue("test sanity", view.hasFocus());
-        assertEquals(vDesiredDist.get(), vScrollDist.get());
-        assertEquals(hDesiredDist.get(), hScrollDist.get());
-        assertEquals(mRecyclerView.getPaddingTop(), view.getTop());
-        if (rtl) {
-            assertEquals(mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(),
-                    view.getRight());
-        } else {
-            assertEquals(mRecyclerView.getPaddingLeft(), view.getLeft());
-        }
-    }
-
-    @Test
-    public void firstLayoutWithAdapterChanges() throws Throwable {
-        final TestAdapter adapter = new TestAdapter(0);
-        final RecyclerView rv = new RecyclerView(getActivity());
-        setVisibility(rv, View.GONE);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                try {
-                    super.onLayoutChildren(recycler, state);
-                    layoutRange(recycler, 0, state.getItemCount());
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                } finally {
-                    layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return true;
-            }
-        };
-        rv.setLayoutManager(tlm);
-        rv.setAdapter(adapter);
-        rv.setHasFixedSize(true);
-        setRecyclerView(rv);
-        tlm.expectLayouts(1);
-        tlm.assertNoLayout("test sanity, layout should not run", 1);
-        getInstrumentation().waitForIdleSync();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    adapter.addAndNotify(2);
-                } catch (Throwable throwable) {
-                    throwable.printStackTrace();
-                }
-                rv.setVisibility(View.VISIBLE);
-            }
-        });
-        checkForMainThreadException();
-        tlm.waitForLayout(2);
-        assertEquals(2, rv.getChildCount());
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void computeScrollOffsetWithoutLayoutManager() throws Throwable {
-        RecyclerView rv = new RecyclerView(getActivity());
-        rv.setAdapter(new TestAdapter(10));
-        setRecyclerView(rv);
-        assertEquals(0, rv.computeHorizontalScrollExtent());
-        assertEquals(0, rv.computeHorizontalScrollOffset());
-        assertEquals(0, rv.computeHorizontalScrollRange());
-
-        assertEquals(0, rv.computeVerticalScrollExtent());
-        assertEquals(0, rv.computeVerticalScrollOffset());
-        assertEquals(0, rv.computeVerticalScrollRange());
-    }
-
-    @Test
-    public void computeScrollOffsetWithoutAdapter() throws Throwable {
-        RecyclerView rv = new RecyclerView(getActivity());
-        rv.setLayoutManager(new TestLayoutManager());
-        setRecyclerView(rv);
-        assertEquals(0, rv.computeHorizontalScrollExtent());
-        assertEquals(0, rv.computeHorizontalScrollOffset());
-        assertEquals(0, rv.computeHorizontalScrollRange());
-
-        assertEquals(0, rv.computeVerticalScrollExtent());
-        assertEquals(0, rv.computeVerticalScrollOffset());
-        assertEquals(0, rv.computeVerticalScrollRange());
-    }
-
-    @Test
-    public void focusRectOnScreenWithDecorOffsets() throws Throwable {
-        focusRectOnScreenTest(true);
-    }
-
-    @Test
-    public void focusRectOnScreenWithout() throws Throwable {
-        focusRectOnScreenTest(false);
-    }
-
-    public void focusRectOnScreenTest(boolean addItemDecors) throws Throwable {
-        RecyclerView rv = new RecyclerView(getActivity());
-        final AtomicInteger scrollDist = new AtomicInteger(0);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                final View view = recycler.getViewForPosition(0);
-                addView(view);
-                measureChildWithMargins(view, 0, 0);
-                view.layout(0, -20, view.getWidth(),
-                        -20 + view.getHeight());// ignore decors on purpose
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                scrollDist.addAndGet(dy);
-                return dy;
-            }
-        };
-        TestAdapter adapter = new TestAdapter(10);
-        if (addItemDecors) {
-            rv.addItemDecoration(new RecyclerView.ItemDecoration() {
-                @Override
-                public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
-                        RecyclerView.State state) {
-                    outRect.set(0, 10, 0, 10);
-                }
-            });
-        }
-        rv.setAdapter(adapter);
-        rv.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(2);
-
-        View view = rv.getChildAt(0);
-        requestFocus(view, true);
-        assertEquals(addItemDecors ? -30 : -20, scrollDist.get());
-    }
-
-    @Test
-    public void unimplementedSmoothScroll() throws Throwable {
-        final AtomicInteger receivedScrollToPosition = new AtomicInteger(-1);
-        final AtomicInteger receivedSmoothScrollToPosition = new AtomicInteger(-1);
-        final CountDownLatch cbLatch = new CountDownLatch(2);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, 10);
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
-                    int position) {
-                assertEquals(-1, receivedSmoothScrollToPosition.get());
-                receivedSmoothScrollToPosition.set(position);
-                RecyclerView.SmoothScroller ss =
-                        new LinearSmoothScroller(recyclerView.getContext()) {
-                            @Override
-                            public PointF computeScrollVectorForPosition(int targetPosition) {
-                                return null;
-                            }
-                        };
-                ss.setTargetPosition(position);
-                startSmoothScroll(ss);
-                cbLatch.countDown();
-            }
-
-            @Override
-            public void scrollToPosition(int position) {
-                assertEquals(-1, receivedScrollToPosition.get());
-                receivedScrollToPosition.set(position);
-                cbLatch.countDown();
-            }
-        };
-        RecyclerView rv = new RecyclerView(getActivity());
-        rv.setAdapter(new TestAdapter(100));
-        rv.setLayoutManager(tlm);
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(2);
-        freezeLayout(true);
-        smoothScrollToPosition(35, false);
-        assertEquals("smoothScrollToPosition should be ignored when frozen",
-                -1, receivedSmoothScrollToPosition.get());
-        freezeLayout(false);
-        smoothScrollToPosition(35, false);
-        assertTrue("both scrolls should be called", cbLatch.await(3, TimeUnit.SECONDS));
-        checkForMainThreadException();
-        assertEquals(35, receivedSmoothScrollToPosition.get());
-        assertEquals(35, receivedScrollToPosition.get());
-    }
-
-    @Test
-    public void jumpingJackSmoothScroller() throws Throwable {
-        jumpingJackSmoothScrollerTest(true);
-    }
-
-    @Test
-    public void jumpingJackSmoothScrollerGoesIdle() throws Throwable {
-        jumpingJackSmoothScrollerTest(false);
-    }
-
-    @Test
-    public void testScrollByBeforeFirstLayout() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        TestAdapter adapter = new TestAdapter(10);
-        recyclerView.setLayoutManager(new TestLayoutManager() {
-            AtomicBoolean didLayout = new AtomicBoolean(false);
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                super.onLayoutChildren(recycler, state);
-                didLayout.set(true);
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                assertThat("should run layout before scroll",
-                        didLayout.get(), CoreMatchers.is(true));
-                return super.scrollVerticallyBy(dy, recycler, state);
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-        });
-        recyclerView.setAdapter(adapter);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    setRecyclerView(recyclerView);
-                    recyclerView.scrollBy(10, 19);
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-
-        checkForMainThreadException();
-    }
-
-    private void jumpingJackSmoothScrollerTest(final boolean succeed) throws Throwable {
-        final List<Integer> receivedScrollToPositions = new ArrayList<>();
-        final TestAdapter testAdapter = new TestAdapter(200);
-        final AtomicBoolean mTargetFound = new AtomicBoolean(false);
-        TestLayoutManager tlm = new TestLayoutManager() {
-            int pendingScrollPosition = -1;
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                final int pos = pendingScrollPosition < 0 ? 0: pendingScrollPosition;
-                layoutRange(recycler, pos, pos + 10);
-                if (layoutLatch != null) {
-                    layoutLatch.countDown();
-                }
-            }
-
-            @Override
-            public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
-                    final int position) {
-                RecyclerView.SmoothScroller ss =
-                        new LinearSmoothScroller(recyclerView.getContext()) {
-                            @Override
-                            public PointF computeScrollVectorForPosition(int targetPosition) {
-                                return new PointF(0, 1);
-                            }
-
-                            @Override
-                            protected void onTargetFound(View targetView, RecyclerView.State state,
-                                    Action action) {
-                                super.onTargetFound(targetView, state, action);
-                                mTargetFound.set(true);
-                            }
-
-                            @Override
-                            protected void updateActionForInterimTarget(Action action) {
-                                int limit = succeed ? getTargetPosition() : 100;
-                                if (pendingScrollPosition + 2 < limit) {
-                                    if (pendingScrollPosition != NO_POSITION) {
-                                        assertEquals(pendingScrollPosition,
-                                                getChildViewHolderInt(getChildAt(0))
-                                                        .getAdapterPosition());
-                                    }
-                                    action.jumpTo(pendingScrollPosition + 2);
-                                }
-                            }
-                        };
-                ss.setTargetPosition(position);
-                startSmoothScroll(ss);
-            }
-
-            @Override
-            public void scrollToPosition(int position) {
-                receivedScrollToPositions.add(position);
-                pendingScrollPosition = position;
-                requestLayout();
-            }
-        };
-        final RecyclerView rv = new RecyclerView(getActivity());
-        rv.setAdapter(testAdapter);
-        rv.setLayoutManager(tlm);
-
-        tlm.expectLayouts(1);
-        setRecyclerView(rv);
-        tlm.waitForLayout(2);
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                rv.smoothScrollToPosition(150);
-            }
-        });
-        int limit = 100;
-        while (rv.getLayoutManager().isSmoothScrolling() && --limit > 0) {
-            Thread.sleep(200);
-            checkForMainThreadException();
-        }
-        checkForMainThreadException();
-        assertTrue(limit > 0);
-        for (int i = 1; i < 100; i+=2) {
-            assertTrue("scroll positions must include " + i, receivedScrollToPositions.contains(i));
-        }
-
-        assertEquals(succeed, mTargetFound.get());
-
-    }
-
-    private static class TestViewHolder2 extends RecyclerView.ViewHolder {
-
-        Object mData;
-
-        public TestViewHolder2(View itemView) {
-            super(itemView);
-        }
-    }
-
-    private static class TestAdapter2 extends RecyclerView.Adapter<TestViewHolder2> {
-
-        List<Item> mItems;
-
-        private TestAdapter2(int count) {
-            mItems = new ArrayList<>(count);
-            for (int i = 0; i < count; i++) {
-                mItems.add(new Item(i, "Item " + i));
-            }
-        }
-
-        @Override
-        public TestViewHolder2 onCreateViewHolder(ViewGroup parent,
-                int viewType) {
-            return new TestViewHolder2(new TextView(parent.getContext()));
-        }
-
-        @Override
-        public void onBindViewHolder(TestViewHolder2 holder, int position) {
-            final Item item = mItems.get(position);
-            ((TextView) (holder.itemView)).setText(item.mText + "(" + item.mAdapterIndex + ")");
-        }
-
-        @Override
-        public int getItemCount() {
-            return mItems.size();
-        }
-    }
-
-    public interface AdapterRunnable {
-
-        void run(TestAdapter adapter) throws Throwable;
-    }
-
-    public class LayoutAllLayoutManager extends TestLayoutManager {
-        private final boolean mAllowNullLayoutLatch;
-        public int onItemsChangedCallCount = 0;
-        public int onAdapterChagnedCallCount = 0;
-
-        public LayoutAllLayoutManager() {
-            // by default, we don't allow unexpected layouts.
-            this(false);
-        }
-        public LayoutAllLayoutManager(boolean allowNullLayoutLatch) {
-            mAllowNullLayoutLatch = allowNullLayoutLatch;
-        }
-
-        @Override
-        public void onItemsChanged(RecyclerView recyclerView) {
-            super.onItemsChanged(recyclerView);
-            onItemsChangedCallCount++;
-        }
-
-        @Override
-        public void onAdapterChanged(RecyclerView.Adapter oldAdapter,
-                RecyclerView.Adapter newAdapter) {
-            super.onAdapterChanged(oldAdapter, newAdapter);
-            onAdapterChagnedCallCount++;
-        }
-
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-            detachAndScrapAttachedViews(recycler);
-            layoutRange(recycler, 0, state.getItemCount());
-            if (!mAllowNullLayoutLatch || layoutLatch != null) {
-                layoutLatch.countDown();
-            }
-        }
-    }
-
-    /**
-     * Proxy class to make protected methods public
-     */
-    public static class TestRecyclerView extends RecyclerView {
-
-        public TestRecyclerView(Context context) {
-            super(context);
-        }
-
-        public TestRecyclerView(Context context, @Nullable AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public TestRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
-            super(context, attrs, defStyle);
-        }
-
-        @Override
-        public void detachViewFromParent(int index) {
-            super.detachViewFromParent(index);
-        }
-
-        @Override
-        public void attachViewToParent(View child, int index, ViewGroup.LayoutParams params) {
-            super.attachViewToParent(child, index, params);
-        }
-    }
-
-    private interface ViewRunnable {
-        void run(View view) throws RuntimeException;
-    }
-
-    public static class FullyConsumingNestedScroller extends NestedScrollingParent2Adapter {
-        @Override
-        public boolean onStartNestedScroll(@NonNull View child, @NonNull View target,
-                @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
-            // Always start regardless of type
-            return true;
-        }
-
-        @Override
-        public void onNestedPreScroll(@NonNull View target, int dx, int dy,
-                @NonNull int[] consumed, @ViewCompat.NestedScrollType int type) {
-            // Consume everything!
-            consumed[0] = dx;
-            consumed[1] = dy;
-        }
-
-        @Override
-        public int getNestedScrollAxes() {
-            return ViewCompat.SCROLL_AXIS_VERTICAL | ViewCompat.SCROLL_AXIS_HORIZONTAL;
-        }
-
-        @Override
-        public void onStopNestedScroll(View target) {
-            super.onStopNestedScroll(target);
-        }
-
-        @Override
-        public void onStopNestedScroll(@NonNull View target,
-                @ViewCompat.NestedScrollType int type) {
-            super.onStopNestedScroll(target, type);
-        }
-    }
-
-    @Test
-    public void testRemainingScrollInLayout() throws Throwable {
-        final RecyclerView recyclerView = new RecyclerView(getActivity());
-        final TestAdapter adapter = new TestAdapter(100);
-
-        final CountDownLatch firstScrollDone = new CountDownLatch(1);
-        final CountDownLatch scrollFinished = new CountDownLatch(1);
-        final int[] totalScrollDistance = new int[] {0};
-        recyclerView.setLayoutManager(new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                if (firstScrollDone.getCount() < 1 && scrollFinished.getCount() == 1) {
-                    try {
-                        assertTrue("layout pass has remaining scroll",
-                                state.getRemainingScrollVertical() != 0);
-                        assertEquals("layout pass has remaining scroll",
-                                1000 - totalScrollDistance[0], state.getRemainingScrollVertical());
-                    } catch (Throwable throwable) {
-                        postExceptionToInstrumentation(throwable);
-                    }
-                }
-                super.onLayoutChildren(recycler, state);
-            }
-
-            @Override
-            public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                    RecyclerView.State state) {
-                firstScrollDone.countDown();
-                totalScrollDistance[0] += dy;
-                if (state.getRemainingScrollVertical() == 0) {
-                    // the last scroll pass will have remaining 0
-                    scrollFinished.countDown();
-                }
-                return super.scrollVerticallyBy(dy, recycler, state);
-            }
-
-            @Override
-            public boolean canScrollVertically() {
-                return true;
-            }
-        });
-        recyclerView.setAdapter(adapter);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    setRecyclerView(recyclerView);
-                    recyclerView.smoothScrollBy(0, 1000);
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-
-        firstScrollDone.await(1, TimeUnit.SECONDS);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    recyclerView.requestLayout();
-                } catch (Throwable throwable) {
-                    postExceptionToInstrumentation(throwable);
-                }
-            }
-        });
-        waitForIdleScroll(recyclerView);
-        assertTrue(scrollFinished.getCount() < 1);
-        assertEquals(totalScrollDistance[0], 1000);
-    }
-
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java
deleted file mode 100644
index 2f80156..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewOnGenericMotionEventTest.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.view.InputDeviceCompat;
-import android.support.v4.view.ViewConfigurationCompat;
-import android.support.v7.util.TouchUtils;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class RecyclerViewOnGenericMotionEventTest {
-
-    TestRecyclerView mRecyclerView;
-
-    @Before
-    public void setUp() throws Exception {
-        mRecyclerView = new TestRecyclerView(getContext());
-    }
-
-    private Context getContext() {
-        return InstrumentationRegistry.getContext();
-    }
-
-    private void layout() {
-        mRecyclerView.layout(0, 0, 320, 320);
-    }
-
-    @Test
-    public void rotaryEncoderVerticalScroll() {
-        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
-        mRecyclerView.setLayoutManager(layoutManager);
-        layout();
-        TouchUtils.scrollView(
-                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
-        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()));
-    }
-
-    @Test
-    public void rotaryEncoderHorizontalScroll() {
-        // The encoder is one-dimensional, and can only scroll horizontally if vertical scrolling
-        // is not enabled.
-        MockLayoutManager layoutManager = new MockLayoutManager(true, false);
-        mRecyclerView.setLayoutManager(layoutManager);
-        layout();
-        TouchUtils.scrollView(
-                MotionEvent.AXIS_SCROLL, 2, InputDeviceCompat.SOURCE_ROTARY_ENCODER, mRecyclerView);
-        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0);
-    }
-
-    @Test
-    public void pointerVerticalScroll() {
-        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
-        mRecyclerView.setLayoutManager(layoutManager);
-        layout();
-        TouchUtils.scrollView(
-                MotionEvent.AXIS_VSCROLL, 2, InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView);
-        assertTotalScroll(0, (int) (-2f * getScaledVerticalScrollFactor()));
-    }
-
-    @Test
-    public void pointerHorizontalScroll() {
-        MockLayoutManager layoutManager = new MockLayoutManager(true, true);
-        mRecyclerView.setLayoutManager(layoutManager);
-        layout();
-        TouchUtils.scrollView(
-                MotionEvent.AXIS_HSCROLL, 2, InputDeviceCompat.SOURCE_CLASS_POINTER, mRecyclerView);
-        assertTotalScroll((int) (2f * getScaledHorizontalScrollFactor()), 0);
-    }
-
-    @Test
-    public void nonZeroScaledVerticalScrollFactor() {
-        assertNotEquals(0, getScaledVerticalScrollFactor());
-    }
-
-    @Test
-    public void nonZeroScaledHorizontalScrollFactor() {
-        assertNotEquals(0, getScaledHorizontalScrollFactor());
-    }
-
-    private void assertTotalScroll(int x, int y) {
-        assertEquals("x total scroll", x, mRecyclerView.mTotalX);
-        assertEquals("y total scroll", y, mRecyclerView.mTotalY);
-    }
-
-    private static MotionEvent obtainScrollMotionEvent(int axis, int axisValue, int inputDevice) {
-        MotionEvent.PointerProperties[] pointerProperties = { new MotionEvent.PointerProperties() };
-        MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
-        coords.setAxisValue(axis, axisValue);
-        MotionEvent.PointerCoords[] pointerCoords = { coords };
-        float xPrecision = 1;
-        float yPrecision = 1;
-        int deviceId = 0;
-        int edgeFlags = 0;
-        int flags = 0;
-        return MotionEvent.obtain(0, System.currentTimeMillis(), MotionEvent.ACTION_SCROLL,
-                1, pointerProperties, pointerCoords, 0, 0, xPrecision, yPrecision, deviceId,
-                edgeFlags, inputDevice, flags);
-    }
-
-    private float getScaledVerticalScrollFactor() {
-        return ViewConfigurationCompat.getScaledVerticalScrollFactor(
-                ViewConfiguration.get(getContext()), getContext());
-    }
-
-    private float getScaledHorizontalScrollFactor() {
-        return ViewConfigurationCompat.getScaledHorizontalScrollFactor(
-                ViewConfiguration.get(getContext()), getContext());
-    }
-
-    static class MockLayoutManager extends RecyclerView.LayoutManager {
-
-        private final boolean mCanScrollHorizontally;
-
-        private final boolean mCanScrollVertically;
-
-        MockLayoutManager(boolean canScrollHorizontally, boolean canScrollVertically) {
-            mCanScrollHorizontally = canScrollHorizontally;
-            mCanScrollVertically = canScrollVertically;
-        }
-
-        @Override
-        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
-            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-        }
-
-        @Override
-        public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            return dx;
-        }
-
-        @Override
-        public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
-                RecyclerView.State state) {
-            return dy;
-        }
-
-        @Override
-        public boolean canScrollHorizontally() {
-            return mCanScrollHorizontally;
-        }
-
-        @Override
-        public boolean canScrollVertically() {
-            return mCanScrollVertically;
-        }
-    }
-
-    static class MockAdapter extends RecyclerView.Adapter {
-
-        private int mCount = 0;
-
-        MockAdapter(int count) {
-            this.mCount = count;
-        }
-
-        @Override
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return new MockViewHolder(new TextView(parent.getContext()));
-        }
-
-        @Override
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-
-        }
-
-        @Override
-        public int getItemCount() {
-            return mCount;
-        }
-    }
-
-    static class MockViewHolder extends RecyclerView.ViewHolder {
-        MockViewHolder(View itemView) {
-            super(itemView);
-        }
-    }
-
-    private static class TestRecyclerView extends RecyclerView {
-        int mTotalX = 0;
-        int mTotalY = 0;
-
-        TestRecyclerView(Context context) {
-            super(context);
-        }
-
-        boolean scrollByInternal(int x, int y, MotionEvent ev) {
-            mTotalX += x;
-            mTotalY += y;
-            return super.scrollByInternal(x, y, ev);
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
deleted file mode 100644
index 6a32572..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerBaseConfigSetTest.java
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LayoutState.LAYOUT_START;
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
-
-import static org.hamcrest.CoreMatchers.hasItem;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Rect;
-import android.os.Looper;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.test.filters.FlakyTest;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.Suppress;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewParent;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.Arrays;
-import java.util.BitSet;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-@RunWith(Parameterized.class)
-@LargeTest
-public class StaggeredGridLayoutManagerBaseConfigSetTest
-        extends BaseStaggeredGridLayoutManagerTest {
-
-    @Parameterized.Parameters(name = "{0}")
-    public static List<Config> getParams() {
-        return createBaseVariations();
-    }
-
-    private final Config mConfig;
-
-    public StaggeredGridLayoutManagerBaseConfigSetTest(Config config)
-            throws CloneNotSupportedException {
-        mConfig = (Config) config.clone();
-    }
-
-    @Test
-    public void rTL() throws Throwable {
-        rtlTest(false, false);
-    }
-
-    @Test
-    public void rTLChangeAfter() throws Throwable {
-        rtlTest(true, false);
-    }
-
-    @Test
-    public void rTLItemWrapContent() throws Throwable {
-        rtlTest(false, true);
-    }
-
-    @Test
-    public void rTLChangeAfterItemWrapContent() throws Throwable {
-        rtlTest(true, true);
-    }
-
-    void rtlTest(boolean changeRtlAfter, final boolean wrapContent) throws Throwable {
-        if (mConfig.mSpanCount == 1) {
-            mConfig.mSpanCount = 2;
-        }
-        String logPrefix = mConfig + ", changeRtlAfterLayout:" + changeRtlAfter;
-        setupByConfig(mConfig.itemCount(5),
-                new GridTestAdapter(mConfig.mItemCount, mConfig.mOrientation) {
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        if (wrapContent) {
-                            if (mOrientation == HORIZONTAL) {
-                                holder.itemView.getLayoutParams().height
-                                        = RecyclerView.LayoutParams.WRAP_CONTENT;
-                            } else {
-                                holder.itemView.getLayoutParams().width
-                                        = RecyclerView.LayoutParams.MATCH_PARENT;
-                            }
-                        }
-                    }
-                });
-        if (changeRtlAfter) {
-            waitFirstLayout();
-            mLayoutManager.expectLayouts(1);
-            mLayoutManager.setFakeRtl(true);
-            mLayoutManager.waitForLayout(2);
-        } else {
-            mLayoutManager.mFakeRTL = true;
-            waitFirstLayout();
-        }
-
-        assertEquals("view should become rtl", true, mLayoutManager.isLayoutRTL());
-        OrientationHelper helper = OrientationHelper.createHorizontalHelper(mLayoutManager);
-        View child0 = mLayoutManager.findViewByPosition(0);
-        View child1 = mLayoutManager.findViewByPosition(mConfig.mOrientation == VERTICAL ? 1
-                : mConfig.mSpanCount);
-        assertNotNull(logPrefix + " child position 0 should be laid out", child0);
-        assertNotNull(logPrefix + " child position 0 should be laid out", child1);
-        logPrefix += " child1 pos:" + mLayoutManager.getPosition(child1);
-        if (mConfig.mOrientation == VERTICAL || !mConfig.mReverseLayout) {
-            assertTrue(logPrefix + " second child should be to the left of first child",
-                    helper.getDecoratedEnd(child0) > helper.getDecoratedEnd(child1));
-            assertEquals(logPrefix + " first child should be right aligned",
-                    helper.getDecoratedEnd(child0), helper.getEndAfterPadding());
-        } else {
-            assertTrue(logPrefix + " first child should be to the left of second child",
-                    helper.getDecoratedStart(child1) >= helper.getDecoratedStart(child0));
-            assertEquals(logPrefix + " first child should be left aligned",
-                    helper.getDecoratedStart(child0), helper.getStartAfterPadding());
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void scrollBackAndPreservePositions() throws Throwable {
-        scrollBackAndPreservePositionsTest(false);
-    }
-
-    @Test
-    public void scrollBackAndPreservePositionsWithRestore() throws Throwable {
-        scrollBackAndPreservePositionsTest(true);
-    }
-
-    public void scrollBackAndPreservePositionsTest(final boolean saveRestoreInBetween)
-            throws Throwable {
-        setupByConfig(mConfig);
-        mAdapter.mOnBindCallback = new OnBindCallback() {
-            @Override
-            public void onBoundItem(TestViewHolder vh, int position) {
-                StaggeredGridLayoutManager.LayoutParams
-                        lp = (StaggeredGridLayoutManager.LayoutParams) vh.itemView
-                        .getLayoutParams();
-                lp.setFullSpan((position * 7) % (mConfig.mSpanCount + 1) == 0);
-            }
-        };
-        waitFirstLayout();
-        final int[] globalPositions = new int[mAdapter.getItemCount()];
-        Arrays.fill(globalPositions, Integer.MIN_VALUE);
-        final int scrollStep = (mLayoutManager.mPrimaryOrientation.getTotalSpace() / 10)
-                * (mConfig.mReverseLayout ? -1 : 1);
-
-        final int[] globalPos = new int[1];
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int globalScrollPosition = 0;
-                while (globalPositions[mAdapter.getItemCount() - 1] == Integer.MIN_VALUE) {
-                    for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
-                        View child = mRecyclerView.getChildAt(i);
-                        final int pos = mRecyclerView.getChildLayoutPosition(child);
-                        if (globalPositions[pos] != Integer.MIN_VALUE) {
-                            continue;
-                        }
-                        if (mConfig.mReverseLayout) {
-                            globalPositions[pos] = globalScrollPosition +
-                                    mLayoutManager.mPrimaryOrientation.getDecoratedEnd(child);
-                        } else {
-                            globalPositions[pos] = globalScrollPosition +
-                                    mLayoutManager.mPrimaryOrientation.getDecoratedStart(child);
-                        }
-                    }
-                    globalScrollPosition += mLayoutManager.scrollBy(scrollStep,
-                            mRecyclerView.mRecycler, mRecyclerView.mState);
-                }
-                if (DEBUG) {
-                    Log.d(TAG, "done recording positions " + Arrays.toString(globalPositions));
-                }
-                globalPos[0] = globalScrollPosition;
-            }
-        });
-        checkForMainThreadException();
-
-        if (saveRestoreInBetween) {
-            saveRestore(mConfig);
-        }
-
-        checkForMainThreadException();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int globalScrollPosition = globalPos[0];
-                // now scroll back and make sure global positions match
-                BitSet shouldTest = new BitSet(mAdapter.getItemCount());
-                shouldTest.set(0, mAdapter.getItemCount() - 1, true);
-                String assertPrefix = mConfig + ", restored in between:" + saveRestoreInBetween
-                        + " global pos must match when scrolling in reverse for position ";
-                int scrollAmount = Integer.MAX_VALUE;
-                while (!shouldTest.isEmpty() && scrollAmount != 0) {
-                    for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
-                        View child = mRecyclerView.getChildAt(i);
-                        int pos = mRecyclerView.getChildLayoutPosition(child);
-                        if (!shouldTest.get(pos)) {
-                            continue;
-                        }
-                        shouldTest.clear(pos);
-                        int globalPos;
-                        if (mConfig.mReverseLayout) {
-                            globalPos = globalScrollPosition +
-                                    mLayoutManager.mPrimaryOrientation.getDecoratedEnd(child);
-                        } else {
-                            globalPos = globalScrollPosition +
-                                    mLayoutManager.mPrimaryOrientation.getDecoratedStart(child);
-                        }
-                        assertEquals(assertPrefix + pos,
-                                globalPositions[pos], globalPos);
-                    }
-                    scrollAmount = mLayoutManager.scrollBy(-scrollStep,
-                            mRecyclerView.mRecycler, mRecyclerView.mState);
-                    globalScrollPosition += scrollAmount;
-                }
-                assertTrue("all views should be seen", shouldTest.isEmpty());
-            }
-        });
-        checkForMainThreadException();
-    }
-
-    private void saveRestore(final Config config) throws Throwable {
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    Parcelable savedState = mRecyclerView.onSaveInstanceState();
-                    // we append a suffix to the parcelable to test out of bounds
-                    String parcelSuffix = UUID.randomUUID().toString();
-                    Parcel parcel = Parcel.obtain();
-                    savedState.writeToParcel(parcel, 0);
-                    parcel.writeString(parcelSuffix);
-                    removeRecyclerView();
-                    // reset for reading
-                    parcel.setDataPosition(0);
-                    // re-create
-                    savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
-                    RecyclerView restored = new RecyclerView(getActivity());
-                    mLayoutManager = new WrappedLayoutManager(config.mSpanCount,
-                            config.mOrientation);
-                    mLayoutManager.setGapStrategy(config.mGapStrategy);
-                    restored.setLayoutManager(mLayoutManager);
-                    // use the same adapter for Rect matching
-                    restored.setAdapter(mAdapter);
-                    restored.onRestoreInstanceState(savedState);
-                    if (Looper.myLooper() == Looper.getMainLooper()) {
-                        mLayoutManager.expectLayouts(1);
-                        setRecyclerView(restored);
-                    } else {
-                        mLayoutManager.expectLayouts(1);
-                        setRecyclerView(restored);
-                        mLayoutManager.waitForLayout(2);
-                    }
-                } catch (Throwable t) {
-                    postExceptionToInstrumentation(t);
-                }
-            }
-        });
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void getFirstLastChildrenTest() throws Throwable {
-        getFirstLastChildrenTest(false);
-    }
-
-    @Test
-    public void getFirstLastChildrenTestProvideArray() throws Throwable {
-        getFirstLastChildrenTest(true);
-    }
-
-    public void getFirstLastChildrenTest(final boolean provideArr) throws Throwable {
-        setupByConfig(mConfig);
-        waitFirstLayout();
-        Runnable viewInBoundsTest = new Runnable() {
-            @Override
-            public void run() {
-                VisibleChildren visibleChildren = mLayoutManager.traverseAndFindVisibleChildren();
-                final String boundsLog = mLayoutManager.getBoundsLog();
-                VisibleChildren queryResult = new VisibleChildren(mLayoutManager.getSpanCount());
-                queryResult.findFirstPartialVisibleClosestToStart = mLayoutManager
-                        .findFirstVisibleItemClosestToStart(false);
-                queryResult.findFirstPartialVisibleClosestToEnd = mLayoutManager
-                        .findFirstVisibleItemClosestToEnd(false);
-                queryResult.firstFullyVisiblePositions = mLayoutManager
-                        .findFirstCompletelyVisibleItemPositions(
-                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
-                queryResult.firstVisiblePositions = mLayoutManager
-                        .findFirstVisibleItemPositions(
-                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
-                queryResult.lastFullyVisiblePositions = mLayoutManager
-                        .findLastCompletelyVisibleItemPositions(
-                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
-                queryResult.lastVisiblePositions = mLayoutManager
-                        .findLastVisibleItemPositions(
-                                provideArr ? new int[mLayoutManager.getSpanCount()] : null);
-                assertEquals(mConfig + ":\nfirst visible child should match traversal result\n"
-                        + "traversed:" + visibleChildren + "\n"
-                        + "queried:" + queryResult + "\n"
-                        + boundsLog, visibleChildren, queryResult
-                );
-            }
-        };
-        mActivityRule.runOnUiThread(viewInBoundsTest);
-        // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching
-        // case
-        final int scrollPosition = mAdapter.getItemCount();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.smoothScrollToPosition(scrollPosition);
-            }
-        });
-        while (mLayoutManager.isSmoothScrolling() ||
-                mRecyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
-            mActivityRule.runOnUiThread(viewInBoundsTest);
-            checkForMainThreadException();
-            Thread.sleep(400);
-        }
-        // delete all items
-        mLayoutManager.expectLayouts(2);
-        mAdapter.deleteAndNotify(0, mAdapter.getItemCount());
-        mLayoutManager.waitForLayout(2);
-        // test empty case
-        mActivityRule.runOnUiThread(viewInBoundsTest);
-        // set a new adapter with huge items to test full bounds check
-        mLayoutManager.expectLayouts(1);
-        final int totalSpace = mLayoutManager.mPrimaryOrientation.getTotalSpace();
-        final TestAdapter newAdapter = new TestAdapter(100) {
-            @Override
-            public void onBindViewHolder(TestViewHolder holder,
-                    int position) {
-                super.onBindViewHolder(holder, position);
-                if (mConfig.mOrientation == LinearLayoutManager.HORIZONTAL) {
-                    holder.itemView.setMinimumWidth(totalSpace + 100);
-                } else {
-                    holder.itemView.setMinimumHeight(totalSpace + 100);
-                }
-            }
-        };
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mRecyclerView.setAdapter(newAdapter);
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        mActivityRule.runOnUiThread(viewInBoundsTest);
-        checkForMainThreadException();
-
-        // smooth scroll to end of the list and keep testing meanwhile. This will test pre-caching
-        // case
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final int diff;
-                if (mConfig.mReverseLayout) {
-                    diff = -1;
-                } else {
-                    diff = 1;
-                }
-                final int distance = diff * 10;
-                if (mConfig.mOrientation == HORIZONTAL) {
-                    mRecyclerView.scrollBy(distance, 0);
-                } else {
-                    mRecyclerView.scrollBy(0, distance);
-                }
-            }
-        });
-        mActivityRule.runOnUiThread(viewInBoundsTest);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void viewSnapTest() throws Throwable {
-        final Config config = ((Config) mConfig.clone()).itemCount(mConfig.mSpanCount + 1);
-        setupByConfig(config);
-        mAdapter.mOnBindCallback = new OnBindCallback() {
-            @Override
-            void onBoundItem(TestViewHolder vh, int position) {
-                StaggeredGridLayoutManager.LayoutParams
-                        lp = (StaggeredGridLayoutManager.LayoutParams) vh.itemView
-                        .getLayoutParams();
-                if (config.mOrientation == HORIZONTAL) {
-                    lp.width = mRecyclerView.getWidth() / 3;
-                } else {
-                    lp.height = mRecyclerView.getHeight() / 3;
-                }
-            }
-
-            @Override
-            boolean assignRandomSize() {
-                return false;
-            }
-        };
-        waitFirstLayout();
-        // run these tests twice. once initial layout, once after scroll
-        String logSuffix = "";
-        for (int i = 0; i < 2; i++) {
-            Map<Item, Rect> itemRectMap = mLayoutManager.collectChildCoordinates();
-            Rect recyclerViewBounds = getDecoratedRecyclerViewBounds();
-            // workaround for SGLM's span distribution issue. Right now, it may leave gaps so we
-            // avoid it by setting its layout params directly
-            if (config.mOrientation == HORIZONTAL) {
-                recyclerViewBounds.bottom -= recyclerViewBounds.height() % config.mSpanCount;
-            } else {
-                recyclerViewBounds.right -= recyclerViewBounds.width() % config.mSpanCount;
-            }
-
-            Rect usedLayoutBounds = new Rect();
-            for (Rect rect : itemRectMap.values()) {
-                usedLayoutBounds.union(rect);
-            }
-
-            if (DEBUG) {
-                Log.d(TAG, "testing view snapping (" + logSuffix + ") for config " + config);
-            }
-            if (config.mOrientation == VERTICAL) {
-                assertEquals(config + " there should be no gap on left" + logSuffix,
-                        usedLayoutBounds.left, recyclerViewBounds.left);
-                assertEquals(config + " there should be no gap on right" + logSuffix,
-                        usedLayoutBounds.right, recyclerViewBounds.right);
-                if (config.mReverseLayout) {
-                    assertEquals(config + " there should be no gap on bottom" + logSuffix,
-                            usedLayoutBounds.bottom, recyclerViewBounds.bottom);
-                    assertTrue(config + " there should be some gap on top" + logSuffix,
-                            usedLayoutBounds.top > recyclerViewBounds.top);
-                } else {
-                    assertEquals(config + " there should be no gap on top" + logSuffix,
-                            usedLayoutBounds.top, recyclerViewBounds.top);
-                    assertTrue(config + " there should be some gap at the bottom" + logSuffix,
-                            usedLayoutBounds.bottom < recyclerViewBounds.bottom);
-                }
-            } else {
-                assertEquals(config + " there should be no gap on top" + logSuffix,
-                        usedLayoutBounds.top, recyclerViewBounds.top);
-                assertEquals(config + " there should be no gap at the bottom" + logSuffix,
-                        usedLayoutBounds.bottom, recyclerViewBounds.bottom);
-                if (config.mReverseLayout) {
-                    assertEquals(config + " there should be no on right" + logSuffix,
-                            usedLayoutBounds.right, recyclerViewBounds.right);
-                    assertTrue(config + " there should be some gap on left" + logSuffix,
-                            usedLayoutBounds.left > recyclerViewBounds.left);
-                } else {
-                    assertEquals(config + " there should be no gap on left" + logSuffix,
-                            usedLayoutBounds.left, recyclerViewBounds.left);
-                    assertTrue(config + " there should be some gap on right" + logSuffix,
-                            usedLayoutBounds.right < recyclerViewBounds.right);
-                }
-            }
-            final int scroll = config.mReverseLayout ? -500 : 500;
-            scrollBy(scroll);
-            logSuffix = " scrolled " + scroll;
-        }
-    }
-
-    @Test
-    public void scrollToPositionWithOffsetTest() throws Throwable {
-        setupByConfig(mConfig);
-        waitFirstLayout();
-        OrientationHelper orientationHelper = OrientationHelper
-                .createOrientationHelper(mLayoutManager, mConfig.mOrientation);
-        Rect layoutBounds = getDecoratedRecyclerViewBounds();
-        // try scrolling towards head, should not affect anything
-        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
-        scrollToPositionWithOffset(0, 20);
-        assertRectSetsEqual(mConfig + " trying to over scroll with offset should be no-op",
-                before, mLayoutManager.collectChildCoordinates());
-        // try offsetting some visible children
-        int testCount = 10;
-        while (testCount-- > 0) {
-            // get middle child
-            final View child = mLayoutManager.getChildAt(mLayoutManager.getChildCount() / 2);
-            final int position = mRecyclerView.getChildLayoutPosition(child);
-            final int startOffset = mConfig.mReverseLayout ?
-                    orientationHelper.getEndAfterPadding() - orientationHelper
-                            .getDecoratedEnd(child)
-                    : orientationHelper.getDecoratedStart(child) - orientationHelper
-                            .getStartAfterPadding();
-            final int scrollOffset = startOffset / 2;
-            mLayoutManager.expectLayouts(1);
-            scrollToPositionWithOffset(position, scrollOffset);
-            mLayoutManager.waitForLayout(2);
-            final int finalOffset = mConfig.mReverseLayout ?
-                    orientationHelper.getEndAfterPadding() - orientationHelper
-                            .getDecoratedEnd(child)
-                    : orientationHelper.getDecoratedStart(child) - orientationHelper
-                            .getStartAfterPadding();
-            assertEquals(mConfig + " scroll with offset on a visible child should work fine",
-                    scrollOffset, finalOffset);
-        }
-
-        // try scrolling to invisible children
-        testCount = 10;
-        // we test above and below, one by one
-        int offsetMultiplier = -1;
-        while (testCount-- > 0) {
-            final TargetTuple target = findInvisibleTarget(mConfig);
-            mLayoutManager.expectLayouts(1);
-            final int offset = offsetMultiplier
-                    * orientationHelper.getDecoratedMeasurement(mLayoutManager.getChildAt(0)) / 3;
-            scrollToPositionWithOffset(target.mPosition, offset);
-            mLayoutManager.waitForLayout(2);
-            final View child = mLayoutManager.findViewByPosition(target.mPosition);
-            assertNotNull(mConfig + " scrolling to a mPosition with offset " + offset
-                    + " should layout it", child);
-            final Rect bounds = mLayoutManager.getViewBounds(child);
-            if (DEBUG) {
-                Log.d(TAG, mConfig + " post scroll to invisible mPosition " + bounds + " in "
-                        + layoutBounds + " with offset " + offset);
-            }
-
-            if (mConfig.mReverseLayout) {
-                assertEquals(mConfig + " when scrolling with offset to an invisible in reverse "
-                                + "layout, its end should align with recycler view's end - offset",
-                        orientationHelper.getEndAfterPadding() - offset,
-                        orientationHelper.getDecoratedEnd(child)
-                );
-            } else {
-                assertEquals(mConfig + " when scrolling with offset to an invisible child in normal"
-                                + " layout its start should align with recycler view's start + "
-                                + "offset",
-                        orientationHelper.getStartAfterPadding() + offset,
-                        orientationHelper.getDecoratedStart(child)
-                );
-            }
-            offsetMultiplier *= -1;
-        }
-    }
-
-    @Test
-    public void scrollToPositionTest() throws Throwable {
-        setupByConfig(mConfig);
-        waitFirstLayout();
-        OrientationHelper orientationHelper = OrientationHelper
-                .createOrientationHelper(mLayoutManager, mConfig.mOrientation);
-        Rect layoutBounds = getDecoratedRecyclerViewBounds();
-        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
-            View view = mLayoutManager.getChildAt(i);
-            Rect bounds = mLayoutManager.getViewBounds(view);
-            if (layoutBounds.contains(bounds)) {
-                Map<Item, Rect> initialBounds = mLayoutManager.collectChildCoordinates();
-                final int position = mRecyclerView.getChildLayoutPosition(view);
-                StaggeredGridLayoutManager.LayoutParams layoutParams
-                        = (StaggeredGridLayoutManager.LayoutParams) (view.getLayoutParams());
-                TestViewHolder vh = (TestViewHolder) layoutParams.mViewHolder;
-                assertEquals("recycler view mPosition should match adapter mPosition", position,
-                        vh.mBoundItem.mAdapterIndex);
-                if (DEBUG) {
-                    Log.d(TAG, "testing scroll to visible mPosition at " + position
-                            + " " + bounds + " inside " + layoutBounds);
-                }
-                mLayoutManager.expectLayouts(1);
-                scrollToPosition(position);
-                mLayoutManager.waitForLayout(2);
-                if (DEBUG) {
-                    view = mLayoutManager.findViewByPosition(position);
-                    Rect newBounds = mLayoutManager.getViewBounds(view);
-                    Log.d(TAG, "after scrolling to visible mPosition " +
-                            bounds + " equals " + newBounds);
-                }
-
-                assertRectSetsEqual(
-                        mConfig + "scroll to mPosition on fully visible child should be no-op",
-                        initialBounds, mLayoutManager.collectChildCoordinates());
-            } else {
-                final int position = mRecyclerView.getChildLayoutPosition(view);
-                if (DEBUG) {
-                    Log.d(TAG,
-                            "child(" + position + ") not fully visible " + bounds + " not inside "
-                                    + layoutBounds
-                                    + mRecyclerView.getChildLayoutPosition(view)
-                    );
-                }
-                mLayoutManager.expectLayouts(1);
-                mActivityRule.runOnUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        mLayoutManager.scrollToPosition(position);
-                    }
-                });
-                mLayoutManager.waitForLayout(2);
-                view = mLayoutManager.findViewByPosition(position);
-                bounds = mLayoutManager.getViewBounds(view);
-                if (DEBUG) {
-                    Log.d(TAG, "after scroll to partially visible child " + bounds + " in "
-                            + layoutBounds);
-                }
-                assertTrue(mConfig
-                                + " after scrolling to a partially visible child, it should become fully "
-                                + " visible. " + bounds + " not inside " + layoutBounds,
-                        layoutBounds.contains(bounds)
-                );
-                assertTrue(
-                        mConfig + " when scrolling to a partially visible item, one of its edges "
-                                + "should be on the boundaries",
-                        orientationHelper.getStartAfterPadding() ==
-                                orientationHelper.getDecoratedStart(view)
-                                || orientationHelper.getEndAfterPadding() ==
-                                orientationHelper.getDecoratedEnd(view));
-            }
-        }
-
-        // try scrolling to invisible children
-        int testCount = 10;
-        while (testCount-- > 0) {
-            final TargetTuple target = findInvisibleTarget(mConfig);
-            mLayoutManager.expectLayouts(1);
-            scrollToPosition(target.mPosition);
-            mLayoutManager.waitForLayout(2);
-            final View child = mLayoutManager.findViewByPosition(target.mPosition);
-            assertNotNull(mConfig + " scrolling to a mPosition should lay it out", child);
-            final Rect bounds = mLayoutManager.getViewBounds(child);
-            if (DEBUG) {
-                Log.d(TAG, mConfig + " post scroll to invisible mPosition " + bounds + " in "
-                        + layoutBounds);
-            }
-            assertTrue(mConfig + " scrolling to a mPosition should make it fully visible",
-                    layoutBounds.contains(bounds));
-            if (target.mLayoutDirection == LAYOUT_START) {
-                assertEquals(
-                        mConfig + " when scrolling to an invisible child above, its start should"
-                                + " align with recycler view's start",
-                        orientationHelper.getStartAfterPadding(),
-                        orientationHelper.getDecoratedStart(child)
-                );
-            } else {
-                assertEquals(mConfig + " when scrolling to an invisible child below, its end "
-                                + "should align with recycler view's end",
-                        orientationHelper.getEndAfterPadding(),
-                        orientationHelper.getDecoratedEnd(child)
-                );
-            }
-        }
-    }
-
-    @Test
-    public void scollByTest() throws Throwable {
-        setupByConfig(mConfig);
-        waitFirstLayout();
-        // try invalid scroll. should not happen
-        final View first = mLayoutManager.getChildAt(0);
-        OrientationHelper primaryOrientation = OrientationHelper
-                .createOrientationHelper(mLayoutManager, mConfig.mOrientation);
-        int scrollDist;
-        if (mConfig.mReverseLayout) {
-            scrollDist = primaryOrientation.getDecoratedMeasurement(first) / 2;
-        } else {
-            scrollDist = -primaryOrientation.getDecoratedMeasurement(first) / 2;
-        }
-        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
-        scrollBy(scrollDist);
-        Map<Item, Rect> after = mLayoutManager.collectChildCoordinates();
-        assertRectSetsEqual(
-                mConfig + " if there are no more items, scroll should not happen (dt:" + scrollDist
-                        + ")",
-                before, after
-        );
-
-        scrollDist = -scrollDist * 3;
-        before = mLayoutManager.collectChildCoordinates();
-        scrollBy(scrollDist);
-        after = mLayoutManager.collectChildCoordinates();
-        int layoutStart = primaryOrientation.getStartAfterPadding();
-        int layoutEnd = primaryOrientation.getEndAfterPadding();
-        for (Map.Entry<Item, Rect> entry : before.entrySet()) {
-            Rect afterRect = after.get(entry.getKey());
-            // offset rect
-            if (mConfig.mOrientation == VERTICAL) {
-                entry.getValue().offset(0, -scrollDist);
-            } else {
-                entry.getValue().offset(-scrollDist, 0);
-            }
-            if (afterRect == null || afterRect.isEmpty()) {
-                // assert item is out of bounds
-                int start, end;
-                if (mConfig.mOrientation == VERTICAL) {
-                    start = entry.getValue().top;
-                    end = entry.getValue().bottom;
-                } else {
-                    start = entry.getValue().left;
-                    end = entry.getValue().right;
-                }
-                assertTrue(
-                        mConfig + " if item is missing after relayout, it should be out of bounds."
-                                + "item start: " + start + ", end:" + end + " layout start:"
-                                + layoutStart +
-                                ", layout end:" + layoutEnd,
-                        start <= layoutStart && end <= layoutEnd ||
-                                start >= layoutEnd && end >= layoutEnd
-                );
-            } else {
-                assertEquals(mConfig + " Item should be laid out at the scroll offset coordinates",
-                        entry.getValue(),
-                        afterRect);
-            }
-        }
-        assertViewPositions(mConfig);
-    }
-
-    @Test
-    public void layoutOrderTest() throws Throwable {
-        setupByConfig(mConfig);
-        assertViewPositions(mConfig);
-    }
-
-    @Test
-    public void consistentRelayout() throws Throwable {
-        consistentRelayoutTest(mConfig, false);
-    }
-
-    @Test
-    public void consistentRelayoutWithFullSpanFirstChild() throws Throwable {
-        consistentRelayoutTest(mConfig, true);
-    }
-
-    @Suppress
-    @FlakyTest(bugId = 34158822)
-    @Test
-    @LargeTest
-    public void dontRecycleViewsTranslatedOutOfBoundsFromStart() throws Throwable {
-        final Config config = ((Config) mConfig.clone()).itemCount(1000);
-        setupByConfig(config);
-        waitFirstLayout();
-        // pick position from child count so that it is not too far away
-        int pos = mRecyclerView.getChildCount() * 2;
-        smoothScrollToPosition(pos, true);
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(pos);
-        OrientationHelper helper = mLayoutManager.mPrimaryOrientation;
-        int gap = helper.getDecoratedStart(vh.itemView);
-        scrollBy(gap);
-        gap = helper.getDecoratedStart(vh.itemView);
-        assertThat("test sanity", gap, is(0));
-
-        final int size = helper.getDecoratedMeasurement(vh.itemView);
-        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (mConfig.mOrientation == HORIZONTAL) {
-                    vh.itemView.setTranslationX(size * 2);
-                } else {
-                    vh.itemView.setTranslationY(size * 2);
-                }
-            }
-        });
-        scrollBy(size * 2);
-        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
-        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
-        assertThat(vh.getAdapterPosition(), is(pos));
-        scrollBy(size * 2);
-        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
-    }
-
-    @Test
-    public void dontRecycleViewsTranslatedOutOfBoundsFromEnd() throws Throwable {
-        final Config config = ((Config) mConfig.clone()).itemCount(1000);
-        setupByConfig(config);
-        waitFirstLayout();
-        // pick position from child count so that it is not too far away
-        int pos = mRecyclerView.getChildCount() * 2;
-        mLayoutManager.expectLayouts(1);
-        scrollToPosition(pos);
-        mLayoutManager.waitForLayout(2);
-        final RecyclerView.ViewHolder vh = mRecyclerView.findViewHolderForAdapterPosition(pos);
-        OrientationHelper helper = mLayoutManager.mPrimaryOrientation;
-        int gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
-        scrollBy(-gap);
-        gap = helper.getEnd() - helper.getDecoratedEnd(vh.itemView);
-        assertThat("test sanity", gap, is(0));
-
-        final int size = helper.getDecoratedMeasurement(vh.itemView);
-        AttachDetachCollector collector = new AttachDetachCollector(mRecyclerView);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                if (mConfig.mOrientation == HORIZONTAL) {
-                    vh.itemView.setTranslationX(-size * 2);
-                } else {
-                    vh.itemView.setTranslationY(-size * 2);
-                }
-            }
-        });
-        scrollBy(-size * 2);
-        assertThat(collector.getDetached(), not(hasItem(sameInstance(vh.itemView))));
-        assertThat(vh.itemView.getParent(), is((ViewParent) mRecyclerView));
-        assertThat(vh.getAdapterPosition(), is(pos));
-        scrollBy(-size * 2);
-        assertThat(collector.getDetached(), hasItem(sameInstance(vh.itemView)));
-    }
-
-    public void consistentRelayoutTest(Config config, boolean firstChildMultiSpan)
-            throws Throwable {
-        setupByConfig(config);
-        if (firstChildMultiSpan) {
-            mAdapter.mFullSpanItems.add(0);
-        }
-        waitFirstLayout();
-        // record all child positions
-        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
-        requestLayoutOnUIThread(mRecyclerView);
-        Map<Item, Rect> after = mLayoutManager.collectChildCoordinates();
-        assertRectSetsEqual(
-                config + " simple re-layout, firstChildMultiSpan:" + firstChildMultiSpan, before,
-                after);
-        // scroll some to create inconsistency
-        View firstChild = mLayoutManager.getChildAt(0);
-        final int firstChildStartBeforeScroll = mLayoutManager.mPrimaryOrientation
-                .getDecoratedStart(firstChild);
-        int distance = mLayoutManager.mPrimaryOrientation.getDecoratedMeasurement(firstChild) / 2;
-        if (config.mReverseLayout) {
-            distance *= -1;
-        }
-        scrollBy(distance);
-        waitForMainThread(2);
-        assertTrue("scroll by should move children", firstChildStartBeforeScroll !=
-                mLayoutManager.mPrimaryOrientation.getDecoratedStart(firstChild));
-        before = mLayoutManager.collectChildCoordinates();
-        mLayoutManager.expectLayouts(1);
-        requestLayoutOnUIThread(mRecyclerView);
-        mLayoutManager.waitForLayout(2);
-        after = mLayoutManager.collectChildCoordinates();
-        assertRectSetsEqual(config + " simple re-layout after scroll", before, after);
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
deleted file mode 100644
index cfc9c4e..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
+++ /dev/null
@@ -1,1345 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static android.support.v7.widget.StaggeredGridLayoutManager
-        .GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS;
-import static android.support.v7.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
-import static android.support.v7.widget.StaggeredGridLayoutManager.HORIZONTAL;
-import static android.support.v7.widget.StaggeredGridLayoutManager.LayoutParams;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.support.test.filters.LargeTest;
-import android.support.v4.view.AccessibilityDelegateCompat;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.StateSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.EditText;
-import android.widget.FrameLayout;
-
-import org.hamcrest.CoreMatchers;
-import org.hamcrest.MatcherAssert;
-import org.junit.Test;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-@LargeTest
-public class StaggeredGridLayoutManagerTest extends BaseStaggeredGridLayoutManagerTest {
-
-    @Test
-    public void layout_rvHasPaddingChildIsMatchParentVertical_childrenAreInsideParent()
-            throws Throwable {
-        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(VERTICAL, false);
-    }
-
-    @Test
-    public void layout_rvHasPaddingChildIsMatchParentHorizontal_childrenAreInsideParent()
-            throws Throwable {
-        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(HORIZONTAL, false);
-    }
-
-    @Test
-    public void layout_rvHasPaddingChildIsMatchParentVerticalFullSpan_childrenAreInsideParent()
-            throws Throwable {
-        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(VERTICAL, true);
-    }
-
-    @Test
-    public void layout_rvHasPaddingChildIsMatchParentHorizontalFullSpan_childrenAreInsideParent()
-            throws Throwable {
-        layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(HORIZONTAL, true);
-    }
-
-    private void layout_rvHasPaddingChildIsMatchParent_childrenAreInsideParent(
-            final int orientation, final boolean fullSpan)
-            throws Throwable {
-
-        setupByConfig(new Config(orientation, false, 1, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
-                new GridTestAdapter(10, orientation) {
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                        View view = new View(parent.getContext());
-                        StaggeredGridLayoutManager.LayoutParams layoutParams =
-                                new StaggeredGridLayoutManager.LayoutParams(
-                                        ViewGroup.LayoutParams.MATCH_PARENT,
-                                        ViewGroup.LayoutParams.MATCH_PARENT);
-                        layoutParams.setFullSpan(fullSpan);
-                        view.setLayoutParams(layoutParams);
-                        return new TestViewHolder(view);
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder, int position) {
-                        // No actual binding needed, but we need to override this to prevent default
-                        // behavior of GridTestAdapter.
-                    }
-                });
-        mRecyclerView.setPadding(1, 2, 3, 4);
-
-        waitFirstLayout();
-
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                int childDimension;
-                int recyclerViewDimensionMinusPadding;
-                if (orientation == VERTICAL) {
-                    childDimension = mRecyclerView.getChildAt(0).getHeight();
-                    recyclerViewDimensionMinusPadding = mRecyclerView.getHeight()
-                            - mRecyclerView.getPaddingTop()
-                            - mRecyclerView.getPaddingBottom();
-                } else {
-                    childDimension = mRecyclerView.getChildAt(0).getWidth();
-                    recyclerViewDimensionMinusPadding = mRecyclerView.getWidth()
-                            - mRecyclerView.getPaddingLeft()
-                            - mRecyclerView.getPaddingRight();
-                }
-                assertThat(childDimension, equalTo(recyclerViewDimensionMinusPadding));
-            }
-        });
-    }
-
-    @Test
-    public void forceLayoutOnDetach() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
-        waitFirstLayout();
-        assertFalse("test sanity", mRecyclerView.isLayoutRequested());
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mLayoutManager.onDetachedFromWindow(mRecyclerView, mRecyclerView.mRecycler);
-            }
-        });
-        assertTrue(mRecyclerView.isLayoutRequested());
-    }
-    @Test
-    public void areAllStartsTheSame() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_NONE).itemCount(300));
-        waitFirstLayout();
-        smoothScrollToPosition(100);
-        mLayoutManager.expectLayouts(1);
-        mAdapter.deleteAndNotify(0, 2);
-        mLayoutManager.waitForLayout(2000);
-        smoothScrollToPosition(0);
-        assertFalse("all starts should not be the same", mLayoutManager.areAllStartsEqual());
-    }
-
-    @Test
-    public void areAllEndsTheSame() throws Throwable {
-        setupByConfig(new Config(VERTICAL, true, 3, GAP_HANDLING_NONE).itemCount(300));
-        waitFirstLayout();
-        smoothScrollToPosition(100);
-        mLayoutManager.expectLayouts(1);
-        mAdapter.deleteAndNotify(0, 2);
-        mLayoutManager.waitForLayout(2);
-        smoothScrollToPosition(0);
-        assertFalse("all ends should not be the same", mLayoutManager.areAllEndsEqual());
-    }
-
-    @Test
-    public void getPositionsBeforeInitialization() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
-        int[] positions = mLayoutManager.findFirstCompletelyVisibleItemPositions(null);
-        MatcherAssert.assertThat(positions,
-                CoreMatchers.is(new int[]{RecyclerView.NO_POSITION, RecyclerView.NO_POSITION,
-                        RecyclerView.NO_POSITION}));
-    }
-
-    @Test
-    public void findLastInUnevenDistribution() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, 2, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS)
-                .itemCount(5));
-        mAdapter.mOnBindCallback = new OnBindCallback() {
-            @Override
-            void onBoundItem(TestViewHolder vh, int position) {
-                LayoutParams lp = (LayoutParams) vh.itemView.getLayoutParams();
-                if (position == 1) {
-                    lp.height = mRecyclerView.getHeight() - 10;
-                } else {
-                    lp.height = 5;
-                }
-                vh.itemView.setMinimumHeight(0);
-            }
-        };
-        waitFirstLayout();
-        int[] into = new int[2];
-        mLayoutManager.findFirstCompletelyVisibleItemPositions(into);
-        assertEquals("first completely visible item from span 0 should be 0", 0, into[0]);
-        assertEquals("first completely visible item from span 1 should be 1", 1, into[1]);
-        mLayoutManager.findLastCompletelyVisibleItemPositions(into);
-        assertEquals("last completely visible item from span 0 should be 4", 4, into[0]);
-        assertEquals("last completely visible item from span 1 should be 1", 1, into[1]);
-        assertEquals("first fully visible child should be at position",
-                0, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToStart(true)).getPosition());
-        assertEquals("last fully visible child should be at position",
-                4, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToEnd(true)).getPosition());
-
-        assertEquals("first visible child should be at position",
-                0, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToStart(false)).getPosition());
-        assertEquals("last visible child should be at position",
-                4, mRecyclerView.getChildViewHolder(mLayoutManager.
-                        findFirstVisibleItemClosestToEnd(false)).getPosition());
-
-    }
-
-    @Test
-    public void customWidthInHorizontal() throws Throwable {
-        customSizeInScrollDirectionTest(
-                new Config(HORIZONTAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
-    }
-
-    @Test
-    public void customHeightInVertical() throws Throwable {
-        customSizeInScrollDirectionTest(
-                new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS));
-    }
-
-    public void customSizeInScrollDirectionTest(final Config config) throws Throwable {
-        setupByConfig(config);
-        final Map<View, Integer> sizeMap = new HashMap<View, Integer>();
-        mAdapter.mOnBindCallback = new OnBindCallback() {
-            @Override
-            void onBoundItem(TestViewHolder vh, int position) {
-                final ViewGroup.LayoutParams layoutParams = vh.itemView.getLayoutParams();
-                final int size = 1 + position * 5;
-                if (config.mOrientation == HORIZONTAL) {
-                    layoutParams.width = size;
-                } else {
-                    layoutParams.height = size;
-                }
-                sizeMap.put(vh.itemView, size);
-                if (position == 3) {
-                    getLp(vh.itemView).setFullSpan(true);
-                }
-            }
-
-            @Override
-            boolean assignRandomSize() {
-                return false;
-            }
-        };
-        waitFirstLayout();
-        assertTrue("[test sanity] some views should be laid out", sizeMap.size() > 0);
-        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
-            View child = mRecyclerView.getChildAt(i);
-            final int size = config.mOrientation == HORIZONTAL ? child.getWidth()
-                    : child.getHeight();
-            assertEquals("child " + i + " should have the size specified in its layout params",
-                    sizeMap.get(child).intValue(), size);
-        }
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void gapHandlingWhenItemMovesToTop() throws Throwable {
-        gapHandlingWhenItemMovesToTopTest();
-    }
-
-    @Test
-    public void gapHandlingWhenItemMovesToTopWithFullSpan() throws Throwable {
-        gapHandlingWhenItemMovesToTopTest(0);
-    }
-
-    @Test
-    public void gapHandlingWhenItemMovesToTopWithFullSpan2() throws Throwable {
-        gapHandlingWhenItemMovesToTopTest(1);
-    }
-
-    public void gapHandlingWhenItemMovesToTopTest(int... fullSpanIndices) throws Throwable {
-        Config config = new Config(VERTICAL, false, 2, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
-        config.itemCount(3);
-        setupByConfig(config);
-        mAdapter.mOnBindCallback = new OnBindCallback() {
-            @Override
-            void onBoundItem(TestViewHolder vh, int position) {
-            }
-
-            @Override
-            boolean assignRandomSize() {
-                return false;
-            }
-        };
-        for (int i : fullSpanIndices) {
-            mAdapter.mFullSpanItems.add(i);
-        }
-        waitFirstLayout();
-        mLayoutManager.expectLayouts(1);
-        mAdapter.moveItem(1, 0, true);
-        mLayoutManager.waitForLayout(2);
-        final Map<Item, Rect> desiredPositions = mLayoutManager.collectChildCoordinates();
-        // move back.
-        mLayoutManager.expectLayouts(1);
-        mAdapter.moveItem(0, 1, true);
-        mLayoutManager.waitForLayout(2);
-        mLayoutManager.expectLayouts(2);
-        mAdapter.moveAndNotify(1, 0);
-        mLayoutManager.waitForLayout(2);
-        Thread.sleep(1000);
-        getInstrumentation().waitForIdleSync();
-        checkForMainThreadException();
-        // item should be positioned properly
-        assertRectSetsEqual("final position after a move", desiredPositions,
-                mLayoutManager.collectChildCoordinates());
-
-    }
-
-    @Test
-    public void focusSearchFailureUp() throws Throwable {
-        focusSearchFailure(false);
-    }
-
-    @Test
-    public void focusSearchFailureDown() throws Throwable {
-        focusSearchFailure(true);
-    }
-
-    @Test
-    public void focusSearchFailureFromSubChild() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
-                new GridTestAdapter(1000, VERTICAL) {
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-                        FrameLayout fl = new FrameLayout(parent.getContext());
-                        EditText editText = new EditText(parent.getContext());
-                        fl.addView(editText);
-                        editText.setEllipsize(TextUtils.TruncateAt.END);
-                        return new TestViewHolder(fl);
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder, int position) {
-                        Item item = mItems.get(position);
-                        holder.mBoundItem = item;
-                        ((EditText) ((FrameLayout) holder.itemView).getChildAt(0)).setText(
-                                item.mText + " (" + item.mId + ")");
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation using this for kitkat tests
-                        holder.itemView.setBackgroundDrawable(stl);
-                        if (mOnBindCallback != null) {
-                            mOnBindCallback.onBoundItem(holder, position);
-                        }
-                    }
-                });
-        mLayoutManager.expectLayouts(1);
-        setRecyclerView(mRecyclerView);
-        mLayoutManager.waitForLayout(10);
-        getInstrumentation().waitForIdleSync();
-        ViewGroup lastChild = (ViewGroup) mRecyclerView.getChildAt(
-                mRecyclerView.getChildCount() - 1);
-        RecyclerView.ViewHolder lastViewHolder = mRecyclerView.getChildViewHolder(lastChild);
-        View subChildToFocus = lastChild.getChildAt(0);
-        requestFocus(subChildToFocus, true);
-        assertThat("test sanity", subChildToFocus.isFocused(), CoreMatchers.is(true));
-        focusSearch(subChildToFocus, View.FOCUS_FORWARD);
-        waitForIdleScroll(mRecyclerView);
-        checkForMainThreadException();
-        View focusedChild = mRecyclerView.getFocusedChild();
-        if (focusedChild == subChildToFocus.getParent()) {
-            focusSearch(focusedChild, View.FOCUS_FORWARD);
-            waitForIdleScroll(mRecyclerView);
-            focusedChild = mRecyclerView.getFocusedChild();
-        }
-        RecyclerView.ViewHolder containingViewHolder = mRecyclerView.findContainingViewHolder(
-                focusedChild);
-        assertTrue("new focused view should have a larger position "
-                        + lastViewHolder.getAdapterPosition() + " vs "
-                        + containingViewHolder.getAdapterPosition(),
-                lastViewHolder.getAdapterPosition() < containingViewHolder.getAdapterPosition());
-    }
-
-    public void focusSearchFailure(boolean scrollDown) throws Throwable {
-        int focusDir = scrollDown ? View.FOCUS_DOWN : View.FOCUS_UP;
-        setupByConfig(new Config(VERTICAL, !scrollDown, 3, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS)
-                , new GridTestAdapter(31, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        testViewHolder.itemView.setFocusable(true);
-                        testViewHolder.itemView.setFocusableInTouchMode(true);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation used to support kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / 3);
-                    }
-                });
-        /**
-         * 0  1  2
-         * 3  4  5
-         * 6  7  8
-         * 9  10 11
-         * 12 13 14
-         * 15 16 17
-         * 18 18 18
-         * 19
-         * 20 20 20
-         * 21 22
-         * 23 23 23
-         * 24 25 26
-         * 27 28 29
-         * 30
-         */
-        mAdapter.mFullSpanItems.add(18);
-        mAdapter.mFullSpanItems.add(20);
-        mAdapter.mFullSpanItems.add(23);
-        waitFirstLayout();
-        View viewToFocus = mRecyclerView.findViewHolderForAdapterPosition(1).itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-        int pos = 1;
-        View focusedView = viewToFocus;
-        while (pos < 16) {
-            focusSearchAndWaitForScroll(focusedView, focusDir);
-            focusedView = mRecyclerView.getFocusedChild();
-            assertEquals(pos + 3,
-                    mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
-            pos += 3;
-        }
-        for (int i : new int[]{18, 19, 20, 21, 23, 24}) {
-            focusSearchAndWaitForScroll(focusedView, focusDir);
-            focusedView = mRecyclerView.getFocusedChild();
-            assertEquals(i, mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
-        }
-        // now move right
-        focusSearch(focusedView, View.FOCUS_RIGHT);
-        waitForIdleScroll(mRecyclerView);
-        focusedView = mRecyclerView.getFocusedChild();
-        assertEquals(25, mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
-        for (int i : new int[]{28, 30}) {
-            focusSearchAndWaitForScroll(focusedView, focusDir);
-            focusedView = mRecyclerView.getFocusedChild();
-            assertEquals(i, mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition());
-        }
-    }
-
-    private void focusSearchAndWaitForScroll(View focused, int dir) throws Throwable {
-        focusSearch(focused, dir);
-        waitForIdleScroll(mRecyclerView);
-    }
-
-    @Test
-    public void topUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of rows that can be fully in-bounds of RV.
-        final int visibleRowCount = 5;
-        final int spanCount = 3;
-        final int lastFocusableIndex = 6;
-
-        setupByConfig(new Config(VERTICAL, true, spanCount, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
-                new GridTestAdapter(18, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        testViewHolder.itemView.setFocusable(true);
-                        testViewHolder.itemView.setFocusableInTouchMode(true);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation used to support kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
-                                .getLayoutParams();
-                        if (position <= lastFocusableIndex) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
-                        lp.topMargin = 0;
-                        lp.leftMargin = 0;
-                        lp.rightMargin = 0;
-                        lp.bottomMargin = 0;
-                        if (position == 11) {
-                            lp.bottomMargin = 9;
-                        }
-                    }
-                });
-
-        /**
-         *
-         * 15 16 17
-         * 12 13 14
-         * 11 11 11
-         * 9 10
-         * 8 8 8
-         * 7
-         * 6 6 6
-         * 3 4 5
-         * 0 1 2
-         */
-        mAdapter.mFullSpanItems.add(6);
-        mAdapter.mFullSpanItems.add(8);
-        mAdapter.mFullSpanItems.add(11);
-        waitFirstLayout();
-
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
-        // The VH of the unfocusable item that just became fully visible after focusSearch.
-        RecyclerView.ViewHolder toVisible = null;
-
-        View focusedView = viewToFocus;
-        int actualFocusIndex = -1;
-        // First, scroll until the last focusable row.
-        for (int i : new int[]{4, 6}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_UP);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
-                    + actualFocusIndex, i, actualFocusIndex);
-        }
-
-        // Further scroll up in order to make the unfocusable rows visible. This process should
-        // continue until the currently focused item is still visible. The focused item should not
-        // change in this loop.
-        for (int i : new int[]{9, 11, 11, 11}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_UP);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
-            assertEquals("Focused view should not be changed, whereas it's now at "
-                    + actualFocusIndex, 6, actualFocusIndex);
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, focusedView));
-            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    @Test
-    public void bottomUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of rows that can be fully in-bounds of RV.
-        final int visibleRowCount = 5;
-        final int spanCount = 3;
-        final int lastFocusableIndex = 6;
-
-        setupByConfig(new Config(VERTICAL, false, spanCount, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
-                new GridTestAdapter(18, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        testViewHolder.itemView.setFocusable(true);
-                        testViewHolder.itemView.setFocusableInTouchMode(true);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation used to support kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
-                                .getLayoutParams();
-                        if (position <= lastFocusableIndex) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
-                        lp.topMargin = 0;
-                        lp.leftMargin = 0;
-                        lp.rightMargin = 0;
-                        lp.bottomMargin = 0;
-                        if (position == 11) {
-                            lp.topMargin = 9;
-                        }
-                    }
-                });
-
-        /**
-         * 0 1 2
-         * 3 4 5
-         * 6 6 6
-         * 7
-         * 8 8 8
-         * 9 10
-         * 11 11 11
-         * 12 13 14
-         * 15 16 17
-         */
-        mAdapter.mFullSpanItems.add(6);
-        mAdapter.mFullSpanItems.add(8);
-        mAdapter.mFullSpanItems.add(11);
-        waitFirstLayout();
-
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
-        // The VH of the unfocusable item that just became fully visible after focusSearch.
-        RecyclerView.ViewHolder toVisible = null;
-
-        View focusedView = viewToFocus;
-        int actualFocusIndex = -1;
-        // First, scroll until the last focusable row.
-        for (int i : new int[]{4, 6}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_DOWN);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
-                    + actualFocusIndex, i, actualFocusIndex);
-        }
-
-        // Further scroll down in order to make the unfocusable rows visible. This process should
-        // continue until the currently focused item is still visible. The focused item should not
-        // change in this loop.
-        for (int i : new int[]{9, 11, 11, 11}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_DOWN);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
-            assertEquals("Focused view should not be changed, whereas it's now at "
-                    + actualFocusIndex, 6, actualFocusIndex);
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, focusedView));
-            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    @Test
-    public void leftUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of columns that can be fully in-bounds of RV.
-        final int visibleColCount = 5;
-        final int spanCount = 3;
-        final int lastFocusableIndex = 6;
-
-        // Reverse layout so that views are placed from right to left.
-        setupByConfig(new Config(HORIZONTAL, true, spanCount,
-                        GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
-                new GridTestAdapter(18, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        testViewHolder.itemView.setFocusable(true);
-                        testViewHolder.itemView.setFocusableInTouchMode(true);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation used to support kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
-                                .getLayoutParams();
-                        if (position <= lastFocusableIndex) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
-                        lp.topMargin = 0;
-                        lp.leftMargin = 0;
-                        lp.rightMargin = 0;
-                        lp.bottomMargin = 0;
-                        if (position == 11) {
-                            lp.rightMargin = 9;
-                        }
-                    }
-                });
-
-        /**
-         * 15 12 11 9  8 7 6 3 0
-         * 16 13 11 10 8   6 4 1
-         * 17 14 11    8   6 5 2
-         */
-        mAdapter.mFullSpanItems.add(6);
-        mAdapter.mFullSpanItems.add(8);
-        mAdapter.mFullSpanItems.add(11);
-        waitFirstLayout();
-
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
-        // The VH of the unfocusable item that just became fully visible after focusSearch.
-        RecyclerView.ViewHolder toVisible = null;
-
-        View focusedView = viewToFocus;
-        int actualFocusIndex = -1;
-        // First, scroll until the last focusable column.
-        for (int i : new int[]{4, 6}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_LEFT);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
-                    + actualFocusIndex, i, actualFocusIndex);
-        }
-
-        // Further scroll left in order to make the unfocusable columns visible. This process should
-        // continue until the currently focused item is still visible. The focused item should not
-        // change in this loop.
-        for (int i : new int[]{9, 11, 11, 11}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_LEFT);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
-            assertEquals("Focused view should not be changed, whereas it's now at "
-                    + actualFocusIndex, 6, actualFocusIndex);
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, focusedView));
-            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    @Test
-    public void rightUnfocusableViewsVisibility() throws Throwable {
-        // The maximum number of columns that can be fully in-bounds of RV.
-        final int visibleColCount = 5;
-        final int spanCount = 3;
-        final int lastFocusableIndex = 6;
-
-        setupByConfig(new Config(HORIZONTAL, false, spanCount,
-                        GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
-                new GridTestAdapter(18, 1) {
-                    RecyclerView mAttachedRv;
-
-                    @Override
-                    public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                            int viewType) {
-                        TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
-                        testViewHolder.itemView.setFocusable(true);
-                        testViewHolder.itemView.setFocusableInTouchMode(true);
-                        // Good to have colors for debugging
-                        StateListDrawable stl = new StateListDrawable();
-                        stl.addState(new int[]{android.R.attr.state_focused},
-                                new ColorDrawable(Color.RED));
-                        stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
-                        //noinspection deprecation used to support kitkat tests
-                        testViewHolder.itemView.setBackgroundDrawable(stl);
-                        return testViewHolder;
-                    }
-
-                    @Override
-                    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
-                        mAttachedRv = recyclerView;
-                    }
-
-                    @Override
-                    public void onBindViewHolder(TestViewHolder holder,
-                            int position) {
-                        super.onBindViewHolder(holder, position);
-                        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
-                                .getLayoutParams();
-                        if (position <= lastFocusableIndex) {
-                            holder.itemView.setFocusable(true);
-                            holder.itemView.setFocusableInTouchMode(true);
-                        } else {
-                            holder.itemView.setFocusable(false);
-                            holder.itemView.setFocusableInTouchMode(false);
-                        }
-                        holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
-                        lp.topMargin = 0;
-                        lp.leftMargin = 0;
-                        lp.rightMargin = 0;
-                        lp.bottomMargin = 0;
-                        if (position == 11) {
-                            lp.leftMargin = 9;
-                        }
-                    }
-                });
-
-        /**
-         * 0 3 6 7 8 9  11 12 15
-         * 1 4 6   8 10 11 13 16
-         * 2 5 6   8    11 14 17
-         */
-        mAdapter.mFullSpanItems.add(6);
-        mAdapter.mFullSpanItems.add(8);
-        mAdapter.mFullSpanItems.add(11);
-        waitFirstLayout();
-
-
-        // adapter position of the currently focused item.
-        int focusIndex = 1;
-        RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
-                focusIndex);
-        View viewToFocus = toFocus.itemView;
-        assertTrue(requestFocus(viewToFocus, true));
-        assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
-        // The VH of the unfocusable item that just became fully visible after focusSearch.
-        RecyclerView.ViewHolder toVisible = null;
-
-        View focusedView = viewToFocus;
-        int actualFocusIndex = -1;
-        // First, scroll until the last focusable column.
-        for (int i : new int[]{4, 6}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_RIGHT);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
-                    + actualFocusIndex, i, actualFocusIndex);
-        }
-
-        // Further scroll right in order to make the unfocusable rows visible. This process should
-        // continue until the currently focused item is still visible. The focused item should not
-        // change in this loop.
-        for (int i : new int[]{9, 11, 11, 11}) {
-            focusSearchAndWaitForScroll(focusedView, View.FOCUS_RIGHT);
-            focusedView = mRecyclerView.getFocusedChild();
-            actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
-            toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
-            assertEquals("Focused view should not be changed, whereas it's now at "
-                    + actualFocusIndex, 6, actualFocusIndex);
-            assertTrue("Focused child should be at least partially visible.",
-                    isViewPartiallyInBound(mRecyclerView, focusedView));
-            assertTrue("Child view at adapter pos " + i + " should be fully visible.",
-                    isViewFullyInBound(mRecyclerView, toVisible.itemView));
-        }
-    }
-
-    @Test
-    public void scrollToPositionWithPredictive() throws Throwable {
-        scrollToPositionWithPredictive(0, LinearLayoutManager.INVALID_OFFSET);
-        removeRecyclerView();
-        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2,
-                LinearLayoutManager.INVALID_OFFSET);
-        removeRecyclerView();
-        scrollToPositionWithPredictive(9, 20);
-        removeRecyclerView();
-        scrollToPositionWithPredictive(Config.DEFAULT_ITEM_COUNT / 2, 10);
-
-    }
-
-    public void scrollToPositionWithPredictive(final int scrollPosition, final int scrollOffset)
-            throws Throwable {
-        setupByConfig(new Config(StaggeredGridLayoutManager.VERTICAL,
-                false, 3, StaggeredGridLayoutManager.GAP_HANDLING_NONE));
-        waitFirstLayout();
-        mLayoutManager.mOnLayoutListener = new OnLayoutListener() {
-            @Override
-            void after(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                RecyclerView rv = mLayoutManager.mRecyclerView;
-                if (state.isPreLayout()) {
-                    assertEquals("pending scroll position should still be pending",
-                            scrollPosition, mLayoutManager.mPendingScrollPosition);
-                    if (scrollOffset != LinearLayoutManager.INVALID_OFFSET) {
-                        assertEquals("pending scroll position offset should still be pending",
-                                scrollOffset, mLayoutManager.mPendingScrollPositionOffset);
-                    }
-                } else {
-                    RecyclerView.ViewHolder vh = rv.findViewHolderForLayoutPosition(scrollPosition);
-                    assertNotNull("scroll to position should work", vh);
-                    if (scrollOffset != LinearLayoutManager.INVALID_OFFSET) {
-                        assertEquals("scroll offset should be applied properly",
-                                mLayoutManager.getPaddingTop() + scrollOffset
-                                        + ((RecyclerView.LayoutParams) vh.itemView
-                                        .getLayoutParams()).topMargin,
-                                mLayoutManager.getDecoratedTop(vh.itemView));
-                    }
-                }
-            }
-        };
-        mLayoutManager.expectLayouts(2);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    mAdapter.addAndNotify(0, 1);
-                    if (scrollOffset == LinearLayoutManager.INVALID_OFFSET) {
-                        mLayoutManager.scrollToPosition(scrollPosition);
-                    } else {
-                        mLayoutManager.scrollToPositionWithOffset(scrollPosition,
-                                scrollOffset);
-                    }
-
-                } catch (Throwable throwable) {
-                    throwable.printStackTrace();
-                }
-
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-    }
-
-    @Test
-    public void moveGapHandling() throws Throwable {
-        Config config = new Config().spanCount(2).itemCount(40);
-        setupByConfig(config);
-        waitFirstLayout();
-        mLayoutManager.expectLayouts(2);
-        mAdapter.moveAndNotify(4, 1);
-        mLayoutManager.waitForLayout(2);
-        assertNull("moving item to upper should not cause gaps", mLayoutManager.hasGapsToFix());
-    }
-
-    @Test
-    public void updateAfterFullSpan() throws Throwable {
-        updateAfterFullSpanGapHandlingTest(0);
-    }
-
-    @Test
-    public void updateAfterFullSpan2() throws Throwable {
-        updateAfterFullSpanGapHandlingTest(20);
-    }
-
-    @Test
-    public void temporaryGapHandling() throws Throwable {
-        int fullSpanIndex = 200;
-        setupByConfig(new Config().spanCount(2).itemCount(500));
-        mAdapter.mFullSpanItems.add(fullSpanIndex);
-        waitFirstLayout();
-        smoothScrollToPosition(fullSpanIndex + 200);// go far away
-        assertNull("test sanity. full span item should not be visible",
-                mRecyclerView.findViewHolderForAdapterPosition(fullSpanIndex));
-        mLayoutManager.expectLayouts(1);
-        mAdapter.deleteAndNotify(fullSpanIndex + 1, 3);
-        mLayoutManager.waitForLayout(1);
-        smoothScrollToPosition(0);
-        mLayoutManager.expectLayouts(1);
-        smoothScrollToPosition(fullSpanIndex + 2 * (AVG_ITEM_PER_VIEW - 1));
-        String log = mLayoutManager.layoutToString("post gap");
-        mLayoutManager.assertNoLayout("if an interim gap is fixed, it should not cause a "
-                + "relayout " + log, 2);
-        View fullSpan = mLayoutManager.findViewByPosition(fullSpanIndex);
-        assertNotNull("full span item should be there:\n" + log, fullSpan);
-        View view1 = mLayoutManager.findViewByPosition(fullSpanIndex + 1);
-        assertNotNull("next view should be there\n" + log, view1);
-        View view2 = mLayoutManager.findViewByPosition(fullSpanIndex + 2);
-        assertNotNull("+2 view should be there\n" + log, view2);
-
-        LayoutParams lp1 = (LayoutParams) view1.getLayoutParams();
-        LayoutParams lp2 = (LayoutParams) view2.getLayoutParams();
-        assertEquals("view 1 span index", 0, lp1.getSpanIndex());
-        assertEquals("view 2 span index", 1, lp2.getSpanIndex());
-        assertEquals("no gap between span and view 1",
-                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
-                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view1));
-        assertEquals("no gap between span and view 2",
-                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
-                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view2));
-    }
-
-    public void updateAfterFullSpanGapHandlingTest(int fullSpanIndex) throws Throwable {
-        setupByConfig(new Config().spanCount(2).itemCount(100));
-        mAdapter.mFullSpanItems.add(fullSpanIndex);
-        waitFirstLayout();
-        smoothScrollToPosition(fullSpanIndex + 30);
-        mLayoutManager.expectLayouts(1);
-        mAdapter.deleteAndNotify(fullSpanIndex + 1, 3);
-        mLayoutManager.waitForLayout(1);
-        smoothScrollToPosition(fullSpanIndex);
-        // give it some time to fix the gap
-        Thread.sleep(500);
-        View fullSpan = mLayoutManager.findViewByPosition(fullSpanIndex);
-
-        View view1 = mLayoutManager.findViewByPosition(fullSpanIndex + 1);
-        View view2 = mLayoutManager.findViewByPosition(fullSpanIndex + 2);
-
-        LayoutParams lp1 = (LayoutParams) view1.getLayoutParams();
-        LayoutParams lp2 = (LayoutParams) view2.getLayoutParams();
-        assertEquals("view 1 span index", 0, lp1.getSpanIndex());
-        assertEquals("view 2 span index", 1, lp2.getSpanIndex());
-        assertEquals("no gap between span and view 1",
-                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
-                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view1));
-        assertEquals("no gap between span and view 2",
-                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(fullSpan),
-                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view2));
-    }
-
-    @Test
-    public void innerGapHandling() throws Throwable {
-        innerGapHandlingTest(StaggeredGridLayoutManager.GAP_HANDLING_NONE);
-        innerGapHandlingTest(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS);
-    }
-
-    public void innerGapHandlingTest(int strategy) throws Throwable {
-        Config config = new Config().spanCount(3).itemCount(500);
-        setupByConfig(config);
-        mLayoutManager.setGapStrategy(strategy);
-        mAdapter.mFullSpanItems.add(100);
-        mAdapter.mFullSpanItems.add(104);
-        mAdapter.mViewsHaveEqualSize = true;
-        mAdapter.mOnBindCallback = new OnBindCallback() {
-            @Override
-            void onBoundItem(TestViewHolder vh, int position) {
-
-            }
-
-            @Override
-            void onCreatedViewHolder(TestViewHolder vh) {
-                super.onCreatedViewHolder(vh);
-                //make sure we have enough views
-                mAdapter.mSizeReference = mRecyclerView.getHeight() / 5;
-            }
-        };
-        waitFirstLayout();
-        mLayoutManager.expectLayouts(1);
-        scrollToPosition(400);
-        mLayoutManager.waitForLayout(2);
-        View view400 = mLayoutManager.findViewByPosition(400);
-        assertNotNull("test sanity, scrollToPos should succeed", view400);
-        assertTrue("test sanity, view should be visible top",
-                mLayoutManager.mPrimaryOrientation.getDecoratedStart(view400) >=
-                        mLayoutManager.mPrimaryOrientation.getStartAfterPadding());
-        assertTrue("test sanity, view should be visible bottom",
-                mLayoutManager.mPrimaryOrientation.getDecoratedEnd(view400) <=
-                        mLayoutManager.mPrimaryOrientation.getEndAfterPadding());
-        mLayoutManager.expectLayouts(2);
-        mAdapter.addAndNotify(101, 1);
-        mLayoutManager.waitForLayout(2);
-        checkForMainThreadException();
-        if (strategy == GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) {
-            mLayoutManager.expectLayouts(1);
-        }
-        // state
-        // now smooth scroll to 99 to trigger a layout around 100
-        mLayoutManager.validateChildren();
-        smoothScrollToPosition(99);
-        switch (strategy) {
-            case GAP_HANDLING_NONE:
-                assertSpans("gap handling:" + Config.gapStrategyName(strategy), new int[]{100, 0},
-                        new int[]{101, 2}, new int[]{102, 0}, new int[]{103, 1}, new int[]{104, 2},
-                        new int[]{105, 0});
-                break;
-            case GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS:
-                mLayoutManager.waitForLayout(2);
-                assertSpans("swap items between spans", new int[]{100, 0}, new int[]{101, 0},
-                        new int[]{102, 1}, new int[]{103, 2}, new int[]{104, 0}, new int[]{105, 0});
-                break;
-        }
-
-    }
-
-    @Test
-    public void fullSizeSpans() throws Throwable {
-        Config config = new Config().spanCount(5).itemCount(30);
-        setupByConfig(config);
-        mAdapter.mFullSpanItems.add(3);
-        waitFirstLayout();
-        assertSpans("Testing full size span", new int[]{0, 0}, new int[]{1, 1}, new int[]{2, 2},
-                new int[]{3, 0}, new int[]{4, 0}, new int[]{5, 1}, new int[]{6, 2},
-                new int[]{7, 3}, new int[]{8, 4});
-    }
-
-    void assertSpans(String msg, int[]... childSpanTuples) {
-        msg = msg + mLayoutManager.layoutToString("\n\n");
-        for (int i = 0; i < childSpanTuples.length; i++) {
-            assertSpan(msg, childSpanTuples[i][0], childSpanTuples[i][1]);
-        }
-    }
-
-    void assertSpan(String msg, int childPosition, int expectedSpan) {
-        View view = mLayoutManager.findViewByPosition(childPosition);
-        assertNotNull(msg + " view at position " + childPosition + " should exists", view);
-        assertEquals(msg + "[child:" + childPosition + "]", expectedSpan,
-                getLp(view).mSpan.mIndex);
-    }
-
-    @Test
-    public void partialSpanInvalidation() throws Throwable {
-        Config config = new Config().spanCount(5).itemCount(100);
-        setupByConfig(config);
-        for (int i = 20; i < mAdapter.getItemCount(); i += 20) {
-            mAdapter.mFullSpanItems.add(i);
-        }
-        waitFirstLayout();
-        smoothScrollToPosition(50);
-        int prevSpanId = mLayoutManager.mLazySpanLookup.mData[30];
-        mAdapter.changeAndNotify(15, 2);
-        Thread.sleep(200);
-        assertEquals("Invalidation should happen within full span item boundaries", prevSpanId,
-                mLayoutManager.mLazySpanLookup.mData[30]);
-        assertEquals("item in invalidated range should have clear span id",
-                LayoutParams.INVALID_SPAN_ID, mLayoutManager.mLazySpanLookup.mData[16]);
-        smoothScrollToPosition(85);
-        int[] prevSpans = copyOfRange(mLayoutManager.mLazySpanLookup.mData, 62, 85);
-        mAdapter.deleteAndNotify(55, 2);
-        Thread.sleep(200);
-        assertEquals("item in invalidated range should have clear span id",
-                LayoutParams.INVALID_SPAN_ID, mLayoutManager.mLazySpanLookup.mData[16]);
-        int[] newSpans = copyOfRange(mLayoutManager.mLazySpanLookup.mData, 60, 83);
-        assertSpanAssignmentEquality("valid spans should be shifted for deleted item", prevSpans,
-                newSpans, 0, 0, newSpans.length);
-    }
-
-    // Same as Arrays.copyOfRange but for API 7
-    private int[] copyOfRange(int[] original, int from, int to) {
-        int newLength = to - from;
-        if (newLength < 0) {
-            throw new IllegalArgumentException(from + " > " + to);
-        }
-        int[] copy = new int[newLength];
-        System.arraycopy(original, from, copy, 0,
-                Math.min(original.length - from, newLength));
-        return copy;
-    }
-
-    @Test
-    public void spanReassignmentsOnItemChange() throws Throwable {
-        Config config = new Config().spanCount(5);
-        setupByConfig(config);
-        waitFirstLayout();
-        smoothScrollToPosition(mAdapter.getItemCount() / 2);
-        final int changePosition = mAdapter.getItemCount() / 4;
-        mLayoutManager.expectLayouts(1);
-        if (RecyclerView.POST_UPDATES_ON_ANIMATION) {
-            mAdapter.changeAndNotify(changePosition, 1);
-            mLayoutManager.assertNoLayout("no layout should happen when an invisible child is "
-                    + "updated", 1);
-        } else {
-            mAdapter.changeAndNotify(changePosition, 1);
-            mLayoutManager.waitForLayout(1);
-        }
-
-        // delete an item before visible area
-        int deletedPosition = mLayoutManager.getPosition(mLayoutManager.getChildAt(0)) - 2;
-        assertTrue("test sanity", deletedPosition >= 0);
-        Map<Item, Rect> before = mLayoutManager.collectChildCoordinates();
-        if (DEBUG) {
-            Log.d(TAG, "before:");
-            for (Map.Entry<Item, Rect> entry : before.entrySet()) {
-                Log.d(TAG, entry.getKey().mAdapterIndex + ":" + entry.getValue());
-            }
-        }
-        mLayoutManager.expectLayouts(1);
-        mAdapter.deleteAndNotify(deletedPosition, 1);
-        mLayoutManager.waitForLayout(2);
-        assertRectSetsEqual(config + " when an item towards the head of the list is deleted, it "
-                        + "should not affect the layout if it is not visible", before,
-                mLayoutManager.collectChildCoordinates()
-        );
-        deletedPosition = mLayoutManager.getPosition(mLayoutManager.getChildAt(2));
-        mLayoutManager.expectLayouts(1);
-        mAdapter.deleteAndNotify(deletedPosition, 1);
-        mLayoutManager.waitForLayout(2);
-        assertRectSetsNotEqual(config + " when a visible item is deleted, it should affect the "
-                + "layout", before, mLayoutManager.collectChildCoordinates());
-    }
-
-    void assertSpanAssignmentEquality(String msg, int[] set1, int[] set2, int start1, int start2,
-            int length) {
-        for (int i = 0; i < length; i++) {
-            assertEquals(msg + " ind1:" + (start1 + i) + ", ind2:" + (start2 + i), set1[start1 + i],
-                    set2[start2 + i]);
-        }
-    }
-
-    @Test
-    public void spanCountChangeOnRestoreSavedState() throws Throwable {
-        Config config = new Config(HORIZONTAL, true, 5, GAP_HANDLING_NONE).itemCount(50);
-        setupByConfig(config);
-        waitFirstLayout();
-
-        int beforeChildCount = mLayoutManager.getChildCount();
-        Parcelable savedState = mRecyclerView.onSaveInstanceState();
-        // we append a suffix to the parcelable to test out of bounds
-        String parcelSuffix = UUID.randomUUID().toString();
-        Parcel parcel = Parcel.obtain();
-        savedState.writeToParcel(parcel, 0);
-        parcel.writeString(parcelSuffix);
-        removeRecyclerView();
-        // reset for reading
-        parcel.setDataPosition(0);
-        // re-create
-        savedState = RecyclerView.SavedState.CREATOR.createFromParcel(parcel);
-        removeRecyclerView();
-
-        RecyclerView restored = new RecyclerView(getActivity());
-        mLayoutManager = new WrappedLayoutManager(config.mSpanCount, config.mOrientation);
-        mLayoutManager.setReverseLayout(config.mReverseLayout);
-        mLayoutManager.setGapStrategy(config.mGapStrategy);
-        restored.setLayoutManager(mLayoutManager);
-        // use the same adapter for Rect matching
-        restored.setAdapter(mAdapter);
-        restored.onRestoreInstanceState(savedState);
-        mLayoutManager.setSpanCount(1);
-        mLayoutManager.expectLayouts(1);
-        setRecyclerView(restored);
-        mLayoutManager.waitForLayout(2);
-        assertEquals("on saved state, reverse layout should be preserved",
-                config.mReverseLayout, mLayoutManager.getReverseLayout());
-        assertEquals("on saved state, orientation should be preserved",
-                config.mOrientation, mLayoutManager.getOrientation());
-        assertEquals("after setting new span count, layout manager should keep new value",
-                1, mLayoutManager.getSpanCount());
-        assertEquals("on saved state, gap strategy should be preserved",
-                config.mGapStrategy, mLayoutManager.getGapStrategy());
-        assertTrue("when span count is dramatically changed after restore, # of child views "
-                + "should change", beforeChildCount > mLayoutManager.getChildCount());
-        // make sure SGLM can layout all children. is some span info is leaked, this would crash
-        smoothScrollToPosition(mAdapter.getItemCount() - 1);
-    }
-
-    @Test
-    public void scrollAndClear() throws Throwable {
-        setupByConfig(new Config());
-        waitFirstLayout();
-
-        assertTrue("Children not laid out", mLayoutManager.collectChildCoordinates().size() > 0);
-
-        mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mLayoutManager.scrollToPositionWithOffset(1, 0);
-                mAdapter.clearOnUIThread();
-            }
-        });
-        mLayoutManager.waitForLayout(2);
-
-        assertEquals("Remaining children", 0, mLayoutManager.collectChildCoordinates().size());
-    }
-
-    @Test
-    public void accessibilityPositions() throws Throwable {
-        setupByConfig(new Config(VERTICAL, false, 3, GAP_HANDLING_NONE));
-        waitFirstLayout();
-        final AccessibilityDelegateCompat delegateCompat = mRecyclerView
-                .getCompatAccessibilityDelegate();
-        final AccessibilityEvent event = AccessibilityEvent.obtain();
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                delegateCompat.onInitializeAccessibilityEvent(mRecyclerView, event);
-            }
-        });
-        final int start = mRecyclerView
-                .getChildLayoutPosition(
-                        mLayoutManager.findFirstVisibleItemClosestToStart(false));
-        final int end = mRecyclerView
-                .getChildLayoutPosition(
-                        mLayoutManager.findFirstVisibleItemClosestToEnd(false));
-        assertEquals("first item position should match",
-                Math.min(start, end), event.getFromIndex());
-        assertEquals("last item position should match",
-                Math.max(start, end), event.getToIndex());
-
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java b/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
deleted file mode 100644
index 9881653..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/TestResizingRelayoutWithAutoMeasure.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static android.view.View.MeasureSpec.AT_MOST;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.makeMeasureSpec;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.test.filters.MediumTest;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Tests whether the layout manager can keep its children positions properly after it is re-laid
- * out with larger/smaller intermediate size but the same final size.
- */
-@MediumTest
-@RunWith(Parameterized.class)
-public class TestResizingRelayoutWithAutoMeasure extends BaseRecyclerViewInstrumentationTest {
-    private final int mRvWidth;
-    private final int mRvHeight;
-    private final RecyclerView.LayoutManager mLayoutManager;
-    private final float mWidthMultiplier;
-    private final float mHeightMultiplier;
-
-    public TestResizingRelayoutWithAutoMeasure(@SuppressWarnings("UnusedParameters") String name,
-            int rvWidth, int rvHeight,
-            RecyclerView.LayoutManager layoutManager, float widthMultiplier,
-            float heightMultiplier) {
-        mRvWidth = rvWidth;
-        mRvHeight = rvHeight;
-        mLayoutManager = layoutManager;
-        mWidthMultiplier = widthMultiplier;
-        mHeightMultiplier = heightMultiplier;
-    }
-
-    @Parameterized.Parameters(name = "{0} rv w/h:{1}/{2} changed w/h:{4}/{5}")
-    public static List<Object[]> getParams() {
-        List<Object[]> params = new ArrayList<>();
-        for(int[] rvSize : new int[][]{new int[]{200, 200}, new int[]{200, 100},
-                new int[]{100, 200}}) {
-            for (float w : new float[]{.5f, 1f, 2f}) {
-                for (float h : new float[]{.5f, 1f, 2f}) {
-                    params.add(
-                            new Object[]{"linear layout", rvSize[0], rvSize[1],
-                                    new LinearLayoutManager(null), w, h}
-                    );
-                    params.add(
-                            new Object[]{"grid layout", rvSize[0], rvSize[1],
-                                    new GridLayoutManager(null, 3), w, h}
-                    );
-                    params.add(
-                            new Object[]{"staggered", rvSize[0], rvSize[1],
-                                    new StaggeredGridLayoutManager(3,
-                                    StaggeredGridLayoutManager.VERTICAL), w, h}
-                    );
-                }
-            }
-        }
-        return params;
-    }
-
-    @Test
-    public void testResizeDuringMeasurements() throws Throwable {
-        final WrappedRecyclerView recyclerView = new WrappedRecyclerView(getActivity());
-        recyclerView.setLayoutManager(mLayoutManager);
-        StaticAdapter adapter = new StaticAdapter(50, ViewGroup.LayoutParams.MATCH_PARENT,
-                mRvHeight / 5);
-        recyclerView.setLayoutParams(new FrameLayout.LayoutParams(mRvWidth, mRvHeight));
-        recyclerView.setAdapter(adapter);
-        setRecyclerView(recyclerView);
-        getInstrumentation().waitForIdleSync();
-        assertThat("Test sanity", recyclerView.getChildCount() > 0, is(true));
-        final int lastPosition = recyclerView.getAdapter().getItemCount() - 1;
-        smoothScrollToPosition(lastPosition);
-        assertThat("test sanity", recyclerView.findViewHolderForAdapterPosition(lastPosition),
-                notNullValue());
-        assertThat("test sanity", mRvWidth, is(recyclerView.getWidth()));
-        assertThat("test sanity", mRvHeight, is(recyclerView.getHeight()));
-        recyclerView.waitUntilLayout();
-        recyclerView.waitUntilAnimations();
-        final Map<Integer, Rect> startPositions = capturePositions(recyclerView);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                recyclerView.measure(
-                        makeMeasureSpec((int) (mRvWidth * mWidthMultiplier),
-                                mWidthMultiplier == 1f ? EXACTLY : AT_MOST),
-                        makeMeasureSpec((int) (mRvHeight * mHeightMultiplier),
-                                mHeightMultiplier == 1f ? EXACTLY : AT_MOST));
-
-                recyclerView.measure(
-                        makeMeasureSpec(mRvWidth, EXACTLY),
-                        makeMeasureSpec(mRvHeight, EXACTLY));
-                recyclerView.dispatchLayout();
-                Map<Integer, Rect> endPositions = capturePositions(recyclerView);
-                assertStartItemPositions(startPositions, endPositions);
-            }
-        });
-        recyclerView.waitUntilLayout();
-        recyclerView.waitUntilAnimations();
-        checkForMainThreadException();
-    }
-
-    private void assertStartItemPositions(Map<Integer, Rect> startPositions,
-            Map<Integer, Rect> endPositions) {
-        String log = log(startPositions, endPositions);
-        for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
-            Rect rect = endPositions.get(entry.getKey());
-            assertThat(log + "view for position " + entry.getKey() + " at" + entry.getValue(), rect,
-                    notNullValue());
-            assertThat(log + "rect for position " + entry.getKey(), entry.getValue(), is(rect));
-        }
-    }
-
-    @NonNull
-    private String log(Map<Integer, Rect> startPositions, Map<Integer, Rect> endPositions) {
-        StringBuilder logBuilder = new StringBuilder();
-        for (Map.Entry<Integer, Rect> entry : startPositions.entrySet()) {
-            logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
-        }
-        logBuilder.append("------\n");
-        for (Map.Entry<Integer, Rect> entry : endPositions.entrySet()) {
-            logBuilder.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
-        }
-        return logBuilder.toString();
-    }
-
-    private Map<Integer, Rect> capturePositions(RecyclerView recyclerView) {
-        Map<Integer, Rect> positions = new HashMap<>();
-        for (int i = 0; i < mLayoutManager.getChildCount(); i++) {
-            View view = mLayoutManager.getChildAt(i);
-            int childAdapterPosition = recyclerView.getChildAdapterPosition(view);
-            Rect outRect = new Rect();
-            mLayoutManager.getDecoratedBoundsWithMargins(view, outRect);
-            // only record if outRect is visible
-            if (outRect.left >= mRecyclerView.getWidth() ||
-                    outRect.top >= mRecyclerView.getHeight() ||
-                    outRect.right < 0 ||
-                    outRect.bottom < 0) {
-                continue;
-            }
-            positions.put(childAdapterPosition, outRect);
-        }
-        return positions;
-    }
-
-    private class StaticAdapter extends RecyclerView.Adapter<TestViewHolder> {
-        final int mSize;
-        // is passed to the layout params of the item
-        final int mMinItemWidth;
-        final int mMinItemHeight;
-
-        public StaticAdapter(int size, int minItemWidth, int minItemHeight) {
-            mSize = size;
-            mMinItemWidth = minItemWidth;
-            mMinItemHeight = minItemHeight;
-        }
-
-        @Override
-        public TestViewHolder onCreateViewHolder(ViewGroup parent,
-                int viewType) {
-            return new TestViewHolder(new View(parent.getContext()));
-        }
-
-        @Override
-        public void onBindViewHolder(TestViewHolder holder, int position) {
-            holder.mBoundItem = new Item(position, "none");
-            if (mMinItemHeight < 1 && mMinItemWidth < 1) {
-                return;
-            }
-            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
-            if (lp == null) {
-                lp = new ViewGroup.LayoutParams(0, 0);
-            }
-            if (mMinItemWidth > 0) {
-                lp.width = (int) (mMinItemWidth + (position % 10) * mMinItemWidth / 7f);
-            } else {
-                lp.width = mMinItemWidth;
-            }
-
-            if (mMinItemHeight > 0) {
-                lp.height = (int) (mMinItemHeight + (position % 10) * mMinItemHeight / 7f);
-            } else {
-                lp.height = mMinItemHeight;
-            }
-            holder.itemView.setLayoutParams(lp);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mSize;
-        }
-    }
-}
\ No newline at end of file
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/TestedFrameLayout.java b/v7/recyclerview/tests/src/android/support/v7/widget/TestedFrameLayout.java
deleted file mode 100644
index 514d737..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/TestedFrameLayout.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.support.annotation.NonNull;
-import android.support.v4.view.NestedScrollingParent2;
-import android.support.v4.view.ViewCompat;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-public class TestedFrameLayout extends FrameLayout implements NestedScrollingParent2 {
-
-    private NestedScrollingParent2 mNestedScrollingDelegate;
-    private CountDownLatch mDrawLatch;
-
-    public TestedFrameLayout(Context context) {
-        super(context);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        RecyclerView recyclerView = getRvChild();
-        if (recyclerView == null) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-        FullControlLayoutParams lp = (FullControlLayoutParams) recyclerView.getLayoutParams();
-        if (lp.wSpec == null && lp.hSpec == null) {
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-            return;
-        }
-        final int childWidthMeasureSpec;
-        if (lp.wSpec != null) {
-            childWidthMeasureSpec = lp.wSpec;
-        } else if (lp.width == LayoutParams.MATCH_PARENT) {
-            final int width = Math.max(0, getMeasuredWidth()
-                    - lp.leftMargin - lp.rightMargin);
-            childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
-        } else {
-            childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
-                    lp.leftMargin + lp.rightMargin, lp.width);
-        }
-
-        final int childHeightMeasureSpec;
-        if (lp.hSpec != null) {
-            childHeightMeasureSpec = lp.hSpec;
-        } else if (lp.height == LayoutParams.MATCH_PARENT) {
-            final int height = Math.max(0, getMeasuredHeight()
-                    - lp.topMargin - lp.bottomMargin);
-            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
-        } else {
-            childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
-                    lp.topMargin + lp.bottomMargin, lp.height);
-        }
-        recyclerView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
-        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY &&
-                MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
-            setMeasuredDimension(
-                    MeasureSpec.getSize(widthMeasureSpec),
-                    MeasureSpec.getSize(heightMeasureSpec)
-            );
-        } else {
-            setMeasuredDimension(
-                    chooseSize(widthMeasureSpec,
-                            recyclerView.getWidth() + getPaddingLeft() + getPaddingRight(),
-                            getMinimumWidth()),
-                    chooseSize(heightMeasureSpec,
-                            recyclerView.getHeight() + getPaddingTop() + getPaddingBottom(),
-                            getMinimumHeight()));
-        }
-    }
-
-    @Override
-    public void onDraw(Canvas c) {
-        super.onDraw(c);
-        if (mDrawLatch != null) {
-            mDrawLatch.countDown();
-        }
-    }
-
-    public void expectDraws(int count) {
-        mDrawLatch = new CountDownLatch(count);
-    }
-
-    public void waitForDraw(int seconds) throws InterruptedException {
-        mDrawLatch.await(seconds, TimeUnit.SECONDS);
-    }
-
-    public static int chooseSize(int spec, int desired, int min) {
-        final int mode = View.MeasureSpec.getMode(spec);
-        final int size = View.MeasureSpec.getSize(spec);
-        switch (mode) {
-            case View.MeasureSpec.EXACTLY:
-                return size;
-            case View.MeasureSpec.AT_MOST:
-                return Math.min(size, desired);
-            case View.MeasureSpec.UNSPECIFIED:
-            default:
-                return Math.max(desired, min);
-        }
-    }
-
-    private RecyclerView getRvChild() {
-        for (int i = 0; i < getChildCount(); i++) {
-            if (getChildAt(i) instanceof RecyclerView) {
-                return (RecyclerView) getChildAt(i);
-            }
-        }
-        return null;
-    }
-
-    @Override
-    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
-        return p instanceof FullControlLayoutParams;
-    }
-
-    @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
-        return new FullControlLayoutParams(p);
-    }
-
-    @Override
-    public LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return new FullControlLayoutParams(getContext(), attrs);
-    }
-
-    @Override
-    protected LayoutParams generateDefaultLayoutParams() {
-        return new FullControlLayoutParams(getWidth(), getHeight());
-    }
-
-    @Override
-    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
-        return onStartNestedScroll(child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onNestedScrollAccepted(View child, View target, int axes) {
-        onNestedScrollAccepted(child, target, axes, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
-        onNestedPreScroll(target, dx, dy, consumed, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
-            int dyUnconsumed) {
-        onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
-                ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public void onStopNestedScroll(View target) {
-        onStopNestedScroll(target, ViewCompat.TYPE_TOUCH);
-    }
-
-    @Override
-    public int getNestedScrollAxes() {
-        return mNestedScrollingDelegate != null
-                ? mNestedScrollingDelegate.getNestedScrollAxes()
-                : 0;
-    }
-
-    @Override
-    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target,
-            @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
-        return mNestedScrollingDelegate != null
-                && mNestedScrollingDelegate.onStartNestedScroll(child, target, axes, type);
-    }
-
-    @Override
-    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target,
-            @ViewCompat.ScrollAxis int axes, @ViewCompat.NestedScrollType int type) {
-        if (mNestedScrollingDelegate != null) {
-            mNestedScrollingDelegate.onNestedScrollAccepted(child, target, axes, type);
-        }
-    }
-
-    @Override
-    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
-        return mNestedScrollingDelegate != null
-                && mNestedScrollingDelegate.onNestedPreFling(target, velocityX, velocityY);
-    }
-
-    @Override
-    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
-        return mNestedScrollingDelegate != null
-                && mNestedScrollingDelegate.onNestedFling(target, velocityX, velocityY, consumed);
-    }
-
-    @Override
-    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
-            int dxUnconsumed, int dyUnconsumed, @ViewCompat.NestedScrollType int type) {
-        if (mNestedScrollingDelegate != null) {
-            mNestedScrollingDelegate.onNestedScroll(target, dxConsumed, dyConsumed,
-                    dxUnconsumed, dyUnconsumed, type);
-        }
-    }
-
-    @Override
-    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed,
-            @ViewCompat.NestedScrollType int type) {
-        if (mNestedScrollingDelegate != null) {
-            mNestedScrollingDelegate.onNestedPreScroll(target, dx, dy, consumed, type);
-        }
-    }
-
-    @Override
-    public void onStopNestedScroll(@NonNull View target, @ViewCompat.NestedScrollType int type) {
-        if (mNestedScrollingDelegate != null) {
-            mNestedScrollingDelegate.onStopNestedScroll(target, type);
-        }
-    }
-
-    public void setNestedScrollingDelegate(NestedScrollingParent2 delegate) {
-        mNestedScrollingDelegate = delegate;
-    }
-
-    public static class FullControlLayoutParams extends FrameLayout.LayoutParams {
-
-        Integer wSpec;
-        Integer hSpec;
-
-        public FullControlLayoutParams(Context c, AttributeSet attrs) {
-            super(c, attrs);
-        }
-
-        public FullControlLayoutParams(int width, int height) {
-            super(width, height);
-        }
-
-        public FullControlLayoutParams(ViewGroup.LayoutParams source) {
-            super(source);
-        }
-
-        public FullControlLayoutParams(FrameLayout.LayoutParams source) {
-            super(source);
-        }
-
-        public FullControlLayoutParams(MarginLayoutParams source) {
-            super(source);
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
deleted file mode 100644
index 1947bc9..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/WrapContentBasicTest.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget;
-
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class WrapContentBasicTest {
-    private Context mContext;
-    private WrapContentLayoutManager mLayoutManager;
-    private RecyclerView mRecyclerView;
-    private WrapAdapter mAdapter;
-    private static int WRAP = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.AT_MOST);
-    private static int EXACT = View.MeasureSpec.makeMeasureSpec(10, View.MeasureSpec.EXACTLY);
-    private static int UNSPECIFIED = View.MeasureSpec
-            .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
-
-    @Before
-    public void setup() throws Exception {
-        mContext = InstrumentationRegistry.getContext();
-        mRecyclerView = new RecyclerView(mContext);
-        mLayoutManager = spy(new WrapContentLayoutManager());
-        // working around a mockito issue
-        mRecyclerView.setLayoutManager(mLayoutManager);
-        mAdapter = spy(new WrapAdapter());
-        mRecyclerView.setAdapter(mAdapter);
-    }
-
-    @Test
-    public void testLayoutInOnMeasureWithoutPredictive() {
-        when(mLayoutManager.supportsPredictiveItemAnimations()).thenReturn(false);
-        mRecyclerView.onMeasure(WRAP, WRAP);
-        mRecyclerView.onMeasure(WRAP, WRAP);
-        mRecyclerView.onLayout(true, 0, 10, 10, 10);
-        verify(mLayoutManager, times(3))
-                .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState);
-    }
-
-    @Test
-    public void dataChangeAfterMeasure() {
-        mRecyclerView.onMeasure(WRAP, WRAP);
-        mRecyclerView.onMeasure(WRAP, WRAP);
-        mAdapter.notifyItemChanged(1);
-        mRecyclerView.onLayout(true, 0, 10, 10, 10);
-        verify(mLayoutManager, times(3))
-                .onLayoutChildren(mRecyclerView.mRecycler, mRecyclerView.mState);
-    }
-
-    @Test
-    public void setDimensionsFromChildren() {
-        View[] children = createMockChildren(3);
-        mLayoutManager.setMeasuredDimensionFromChildren(WRAP, WRAP);
-        verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(),
-                children[0].getHeight());
-    }
-
-    @Test
-    public void setDimensionsFromChildrenAnsSpec1() {
-        View[] children = createMockChildren(3);
-        int hSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY);
-        mLayoutManager.setMeasuredDimensionFromChildren(WRAP, hSpec);
-        verify(mLayoutManager).setMeasuredDimension(children[0].getWidth(), 111);
-    }
-
-    @Test
-    public void setDimensionsFromChildrenAnsSpec2() {
-        View[] children = createMockChildren(3);
-        int wSpec = View.MeasureSpec.makeMeasureSpec(111, View.MeasureSpec.EXACTLY);
-        mLayoutManager.setMeasuredDimensionFromChildren(wSpec, WRAP);
-        verify(mLayoutManager).setMeasuredDimension(111, children[0].getHeight());
-    }
-
-    @Test
-    public void setDimensionsFromChildrenAnsSpec3() {
-        View[] children = createMockChildren(3);
-        children[0].layout(0, 0, 100, 100);
-        children[1].layout(-5, 0, 100, 100);
-        children[2].layout(-5, -10, 100, 100);
-        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
-        verify(mLayoutManager).setMeasuredDimension(105, 110);
-    }
-
-    @Test
-    public void setDimensionsFromChildrenAnsSpec4() {
-        View[] children = createMockChildren(3);
-        children[0].layout(0, 0, 100, 100);
-        children[1].layout(-5, 0, 100, 100);
-        children[2].layout(-5, -10, 100, 100);
-        int atMost = View.MeasureSpec.makeMeasureSpec(95, View.MeasureSpec.AT_MOST);
-        mLayoutManager.setMeasuredDimensionFromChildren(atMost, atMost);
-        verify(mLayoutManager).setMeasuredDimension(95, 95);
-    }
-
-    @Test
-    public void setDimensionsFromChildrenAnsSpec5() {
-        View[] children = createMockChildren(3);
-        children[0].layout(0, 0, 100, 100);
-        children[1].layout(-5, 0, 100, 100);
-        children[2].layout(-5, -10, 100, 100);
-        mRecyclerView.setMinimumWidth(250);
-        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
-        verify(mLayoutManager).setMeasuredDimension(250, 110);
-
-        mRecyclerView.setMinimumWidth(5);
-        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
-        verify(mLayoutManager).setMeasuredDimension(105, 110);
-    }
-
-    @Test
-    public void setDimensionsFromChildrenAnsSpec6() {
-        View[] children = createMockChildren(3);
-        children[0].layout(0, 0, 100, 100);
-        children[1].layout(-5, 0, 100, 100);
-        children[2].layout(-5, -10, 100, 100);
-        mRecyclerView.setMinimumHeight(250);
-        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
-        verify(mLayoutManager).setMeasuredDimension(105, 250);
-
-        mRecyclerView.setMinimumHeight(50);
-        mLayoutManager.setMeasuredDimensionFromChildren(UNSPECIFIED, UNSPECIFIED);
-        verify(mLayoutManager).setMeasuredDimension(105, 110);
-    }
-
-    private View[] createMockChildren(int count) {
-        View[] views = new View[count];
-        for (int i = 0; i < count; i++) {
-            View v = new View(mContext);
-            v.setLayoutParams(new RecyclerView.LayoutParams(1, 1));
-            views[i] = v;
-            when(mLayoutManager.getChildAt(i)).thenReturn(v);
-        }
-        when(mLayoutManager.getChildCount()).thenReturn(3);
-        return views;
-    }
-
-    public class WrapContentLayoutManager extends RecyclerView.LayoutManager {
-
-        @Override
-        public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-
-        }
-
-        @Override
-        public RecyclerView.LayoutParams generateDefaultLayoutParams() {
-            return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT);
-        }
-
-        @Override
-        public boolean isAutoMeasureEnabled() {
-            return true;
-        }
-
-        // START MOCKITO OVERRIDES
-        // We override package protected methods to make them public. This is necessary to run
-        // mockito on Kitkat
-        @Override
-        public void setRecyclerView(RecyclerView recyclerView) {
-            super.setRecyclerView(recyclerView);
-        }
-
-        @Override
-        public void dispatchAttachedToWindow(RecyclerView view) {
-            super.dispatchAttachedToWindow(view);
-        }
-
-        @Override
-        public void dispatchDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
-            super.dispatchDetachedFromWindow(view, recycler);
-        }
-
-        @Override
-        public void setExactMeasureSpecsFrom(RecyclerView recyclerView) {
-            super.setExactMeasureSpecsFrom(recyclerView);
-        }
-
-        @Override
-        public void setMeasureSpecs(int wSpec, int hSpec) {
-            super.setMeasureSpecs(wSpec, hSpec);
-        }
-
-        @Override
-        public void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
-            super.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
-        }
-
-        @Override
-        public boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec,
-                RecyclerView.LayoutParams lp) {
-            return super.shouldReMeasureChild(child, widthSpec, heightSpec, lp);
-        }
-
-        @Override
-        public boolean shouldMeasureChild(View child, int widthSpec, int heightSpec,
-                RecyclerView.LayoutParams lp) {
-            return super.shouldMeasureChild(child, widthSpec, heightSpec, lp);
-        }
-
-        @Override
-        public void removeAndRecycleScrapInt(RecyclerView.Recycler recycler) {
-            super.removeAndRecycleScrapInt(recycler);
-        }
-
-        @Override
-        public void stopSmoothScroller() {
-            super.stopSmoothScroller();
-        }
-
-        @Override
-        public boolean shouldMeasureTwice() {
-            return super.shouldMeasureTwice();
-        }
-
-        // END MOCKITO OVERRIDES
-    }
-
-    public class WrapAdapter extends RecyclerView.Adapter {
-
-        @Override
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return null;
-        }
-
-        @Override
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
-
-        }
-
-        @Override
-        public int getItemCount() {
-            return 10;
-        }
-    }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
deleted file mode 100644
index 090ea69..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.support.v7.widget.helper;
-
-import static android.support.v7.widget.helper.ItemTouchHelper.END;
-import static android.support.v7.widget.helper.ItemTouchHelper.LEFT;
-import static android.support.v7.widget.helper.ItemTouchHelper.RIGHT;
-import static android.support.v7.widget.helper.ItemTouchHelper.START;
-import static android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.os.Build;
-import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
-import android.support.test.filters.Suppress;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
-import android.support.v4.util.Pair;
-import android.support.v7.util.TouchUtils;
-import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.WrappedRecyclerView;
-import android.view.Gravity;
-import android.view.View;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class ItemTouchHelperTest extends BaseRecyclerViewInstrumentationTest {
-
-    private static class RecyclerViewState {
-        public TestAdapter mAdapter;
-        public TestLayoutManager mLayoutManager;
-        public WrappedRecyclerView mWrappedRecyclerView;
-    }
-
-    private LoggingCalback mCalback;
-
-    private LoggingItemTouchHelper mItemTouchHelper;
-
-    private Boolean mSetupRTL;
-
-    public ItemTouchHelperTest() {
-        super(false);
-    }
-
-    private RecyclerViewState setupRecyclerView() throws Throwable {
-        RecyclerViewState rvs = new RecyclerViewState();
-        rvs.mWrappedRecyclerView = inflateWrappedRV();
-        rvs.mAdapter = new TestAdapter(10);
-        rvs.mLayoutManager = new TestLayoutManager() {
-            @Override
-            public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
-                detachAndScrapAttachedViews(recycler);
-                layoutRange(recycler, 0, Math.min(5, state.getItemCount()));
-                layoutLatch.countDown();
-            }
-
-            @Override
-            public boolean canScrollHorizontally() {
-                return false;
-            }
-
-            @Override
-            public boolean supportsPredictiveItemAnimations() {
-                return false;
-            }
-        };
-        rvs.mWrappedRecyclerView.setFakeRTL(mSetupRTL);
-        rvs.mWrappedRecyclerView.setAdapter(rvs.mAdapter);
-        rvs.mWrappedRecyclerView.setLayoutManager(rvs.mLayoutManager);
-        return rvs;
-    }
-
-    private RecyclerViewState setupItemTouchHelper(final RecyclerViewState rvs, int dragDirs,
-            int swipeDirs) throws Throwable {
-        mCalback = new LoggingCalback(dragDirs, swipeDirs);
-        mItemTouchHelper = new LoggingItemTouchHelper(mCalback);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mItemTouchHelper.attachToRecyclerView(rvs.mWrappedRecyclerView);
-            }
-        });
-
-        return rvs;
-    }
-
-    @Test
-    public void swipeLeft() throws Throwable {
-        basicSwipeTest(LEFT, LEFT | RIGHT, -getActivity().getWindow().getDecorView().getWidth());
-    }
-
-    @Test
-    public void swipeRight() throws Throwable {
-        basicSwipeTest(RIGHT, LEFT | RIGHT, getActivity().getWindow().getDecorView().getWidth());
-    }
-
-    @Test
-    public void swipeStart() throws Throwable {
-        basicSwipeTest(START, START | END, -getActivity().getWindow().getDecorView().getWidth());
-    }
-
-    @Test
-    public void swipeEnd() throws Throwable {
-        basicSwipeTest(END, START | END, getActivity().getWindow().getDecorView().getWidth());
-    }
-
-    // Test is disabled as it is flaky.
-    @Suppress
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
-    @Test
-    public void swipeStartInRTL() throws Throwable {
-        mSetupRTL = true;
-        basicSwipeTest(START, START | END, getActivity().getWindow().getDecorView().getWidth());
-    }
-
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.JELLY_BEAN_MR1)
-    @Test
-    public void swipeEndInRTL() throws Throwable {
-        mSetupRTL = true;
-        basicSwipeTest(END, START | END, -getActivity().getWindow().getDecorView().getWidth());
-    }
-
-    @Test
-    public void attachToNullRecycleViewDuringLongPress() throws Throwable {
-        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
-        rvs.mLayoutManager.expectLayouts(1);
-        setRecyclerView(rvs.mWrappedRecyclerView);
-        rvs.mLayoutManager.waitForLayout(1);
-
-        final RecyclerView.ViewHolder target = mRecyclerView
-                .findViewHolderForAdapterPosition(1);
-        target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                mItemTouchHelper.attachToRecyclerView(null);
-                return false;
-            }
-        });
-        TouchUtils.longClickView(getInstrumentation(), target.itemView);
-    }
-
-    @Test
-    public void attachToAnotherRecycleViewDuringLongPress() throws Throwable {
-        final RecyclerViewState rvs2 = setupRecyclerView();
-        rvs2.mLayoutManager.expectLayouts(1);
-        mActivityRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                getActivity().getContainer().addView(rvs2.mWrappedRecyclerView);
-            }
-        });
-        rvs2.mLayoutManager.waitForLayout(1);
-
-        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), END, 0);
-        rvs.mLayoutManager.expectLayouts(1);
-        setRecyclerView(rvs.mWrappedRecyclerView);
-        rvs.mLayoutManager.waitForLayout(1);
-
-        final RecyclerView.ViewHolder target = mRecyclerView
-                .findViewHolderForAdapterPosition(1);
-        target.itemView.setOnLongClickListener(new View.OnLongClickListener() {
-            @Override
-            public boolean onLongClick(View v) {
-                mItemTouchHelper.attachToRecyclerView(rvs2.mWrappedRecyclerView);
-                return false;
-            }
-        });
-        TouchUtils.longClickView(getInstrumentation(), target.itemView);
-        assertEquals(0, mCalback.mHasDragFlag.size());
-    }
-
-    public void basicSwipeTest(int dir, int swipeDirs, int targetX) throws Throwable {
-        final RecyclerViewState rvs = setupItemTouchHelper(setupRecyclerView(), 0, swipeDirs);
-        rvs.mLayoutManager.expectLayouts(1);
-        setRecyclerView(rvs.mWrappedRecyclerView);
-        rvs.mLayoutManager.waitForLayout(1);
-
-        final RecyclerView.ViewHolder target = mRecyclerView
-                .findViewHolderForAdapterPosition(1);
-        TouchUtils.dragViewToX(getInstrumentation(), target.itemView, Gravity.CENTER, targetX);
-
-        PollingCheck.waitFor(1000, new PollingCheck.PollingCheckCondition() {
-            @Override
-            public boolean canProceed() {
-                return mCalback.getSwipe(target) != null;
-            }
-        });
-        final SwipeRecord swipe = mCalback.getSwipe(target);
-        assertNotNull(swipe);
-        assertEquals(dir, swipe.dir);
-        assertEquals(1, mItemTouchHelper.mRecoverAnimations.size());
-        assertEquals(1, mItemTouchHelper.mPendingCleanup.size());
-        // get rid of the view
-        rvs.mLayoutManager.expectLayouts(1);
-        rvs.mAdapter.deleteAndNotify(1, 1);
-        rvs.mLayoutManager.waitForLayout(1);
-        waitForAnimations();
-        assertEquals(0, mItemTouchHelper.mRecoverAnimations.size());
-        assertEquals(0, mItemTouchHelper.mPendingCleanup.size());
-        assertTrue(mCalback.isCleared(target));
-    }
-
-    private void waitForAnimations() throws InterruptedException {
-        while (mRecyclerView.getItemAnimator().isRunning()) {
-            Thread.sleep(100);
-        }
-    }
-
-    private static class LoggingCalback extends SimpleCallback {
-
-        private List<MoveRecord> mMoveRecordList = new ArrayList<MoveRecord>();
-
-        private List<SwipeRecord> mSwipeRecords = new ArrayList<SwipeRecord>();
-
-        private List<RecyclerView.ViewHolder> mCleared = new ArrayList<RecyclerView.ViewHolder>();
-
-        public List<Pair<RecyclerView, RecyclerView.ViewHolder>> mHasDragFlag = new ArrayList<>();
-
-        LoggingCalback(int dragDirs, int swipeDirs) {
-            super(dragDirs, swipeDirs);
-        }
-
-        @Override
-        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
-                RecyclerView.ViewHolder target) {
-            mMoveRecordList.add(new MoveRecord(viewHolder, target));
-            return true;
-        }
-
-        @Override
-        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
-            mSwipeRecords.add(new SwipeRecord(viewHolder, direction));
-        }
-
-        public MoveRecord getMove(RecyclerView.ViewHolder vh) {
-            for (MoveRecord move : mMoveRecordList) {
-                if (move.from == vh) {
-                    return move;
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
-            super.clearView(recyclerView, viewHolder);
-            mCleared.add(viewHolder);
-        }
-
-        @Override
-        boolean hasDragFlag(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
-            mHasDragFlag.add(new Pair<>(recyclerView, viewHolder));
-            return super.hasDragFlag(recyclerView, viewHolder);
-        }
-
-        public SwipeRecord getSwipe(RecyclerView.ViewHolder vh) {
-            for (SwipeRecord swipe : mSwipeRecords) {
-                if (swipe.viewHolder == vh) {
-                    return swipe;
-                }
-            }
-            return null;
-        }
-
-        public boolean isCleared(RecyclerView.ViewHolder vh) {
-            return mCleared.contains(vh);
-        }
-    }
-
-    private static class LoggingItemTouchHelper extends ItemTouchHelper {
-
-        public LoggingItemTouchHelper(Callback callback) {
-            super(callback);
-        }
-    }
-
-    private static class SwipeRecord {
-
-        RecyclerView.ViewHolder viewHolder;
-
-        int dir;
-
-        public SwipeRecord(RecyclerView.ViewHolder viewHolder, int dir) {
-            this.viewHolder = viewHolder;
-            this.dir = dir;
-        }
-    }
-
-    private static class MoveRecord {
-
-        final int fromPos, toPos;
-
-        RecyclerView.ViewHolder from, to;
-
-        MoveRecord(RecyclerView.ViewHolder from, RecyclerView.ViewHolder to) {
-            this.from = from;
-            this.to = to;
-            fromPos = from.getAdapterPosition();
-            toPos = to.getAdapterPosition();
-        }
-    }
-}
diff --git a/viewpager/api/current.txt b/viewpager/api/current.txt
new file mode 100644
index 0000000..31baf49
--- /dev/null
+++ b/viewpager/api/current.txt
@@ -0,0 +1,125 @@
+package android.support.v4.view {
+
+  public abstract class PagerAdapter {
+    ctor public PagerAdapter();
+    method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
+    method public void finishUpdate(android.view.ViewGroup);
+    method public deprecated void finishUpdate(android.view.View);
+    method public abstract int getCount();
+    method public int getItemPosition(java.lang.Object);
+    method public java.lang.CharSequence getPageTitle(int);
+    method public float getPageWidth(int);
+    method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
+    method public deprecated java.lang.Object instantiateItem(android.view.View, int);
+    method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
+    method public void notifyDataSetChanged();
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+    method public android.os.Parcelable saveState();
+    method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
+    method public void startUpdate(android.view.ViewGroup);
+    method public deprecated void startUpdate(android.view.View);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
+    field public static final int POSITION_NONE = -2; // 0xfffffffe
+    field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
+  }
+
+  public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
+    ctor public PagerTabStrip(android.content.Context);
+    ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
+    method public boolean getDrawFullUnderline();
+    method public int getTabIndicatorColor();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setDrawFullUnderline(boolean);
+    method public void setTabIndicatorColor(int);
+    method public void setTabIndicatorColorResource(int);
+  }
+
+  public class PagerTitleStrip extends android.view.ViewGroup {
+    ctor public PagerTitleStrip(android.content.Context);
+    ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
+    method public int getTextSpacing();
+    method public void setGravity(int);
+    method public void setNonPrimaryAlpha(float);
+    method public void setTextColor(int);
+    method public void setTextSize(int, float);
+    method public void setTextSpacing(int);
+  }
+
+  public class ViewPager extends android.view.ViewGroup {
+    ctor public ViewPager(android.content.Context);
+    ctor public ViewPager(android.content.Context, android.util.AttributeSet);
+    method public void addOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+    method public void addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public boolean arrowScroll(int);
+    method public boolean beginFakeDrag();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public void clearOnPageChangeListeners();
+    method public void endFakeDrag();
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fakeDragBy(float);
+    method public android.support.v4.view.PagerAdapter getAdapter();
+    method public int getCurrentItem();
+    method public int getOffscreenPageLimit();
+    method public int getPageMargin();
+    method public boolean isFakeDragging();
+    method protected void onPageScrolled(int, float, int);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void removeOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+    method public void removeOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setAdapter(android.support.v4.view.PagerAdapter);
+    method public void setCurrentItem(int);
+    method public void setCurrentItem(int, boolean);
+    method public void setOffscreenPageLimit(int);
+    method public deprecated void setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setPageMargin(int);
+    method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
+    method public void setPageMarginDrawable(int);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer, int);
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class ViewPager.DecorView implements java.lang.annotation.Annotation {
+  }
+
+  public static class ViewPager.LayoutParams extends android.view.ViewGroup.LayoutParams {
+    ctor public ViewPager.LayoutParams();
+    ctor public ViewPager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public int gravity;
+    field public boolean isDecor;
+  }
+
+  public static abstract interface ViewPager.OnAdapterChangeListener {
+    method public abstract void onAdapterChanged(android.support.v4.view.ViewPager, android.support.v4.view.PagerAdapter, android.support.v4.view.PagerAdapter);
+  }
+
+  public static abstract interface ViewPager.OnPageChangeListener {
+    method public abstract void onPageScrollStateChanged(int);
+    method public abstract void onPageScrolled(int, float, int);
+    method public abstract void onPageSelected(int);
+  }
+
+  public static abstract interface ViewPager.PageTransformer {
+    method public abstract void transformPage(android.view.View, float);
+  }
+
+  public static class ViewPager.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public ViewPager.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.view.ViewPager.SavedState> CREATOR;
+  }
+
+  public static class ViewPager.SimpleOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+    ctor public ViewPager.SimpleOnPageChangeListener();
+    method public void onPageScrollStateChanged(int);
+    method public void onPageScrolled(int, float, int);
+    method public void onPageSelected(int);
+  }
+
+}
+
diff --git a/viewpager/build.gradle b/viewpager/build.gradle
new file mode 100644
index 0000000..fdf3b29
--- /dev/null
+++ b/viewpager/build.gradle
@@ -0,0 +1,27 @@
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(":support-compat"))
+    api(project(":customview"))
+
+    androidTestImplementation(TEST_RUNNER)
+    androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+    androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
+}
+
+supportLibrary {
+    name = "Android Support Library View Pager"
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
+    inceptionYear = "2018"
+    description = "The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."
+}
diff --git a/viewpager/src/androidTest/AndroidManifest.xml b/viewpager/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..d7fd2e6
--- /dev/null
+++ b/viewpager/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.support.viewpager.test">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+
+    <uses-permission android:name="android.permission.VIBRATE"/>
+    <uses-permission android:name="android.permission.WAKE_LOCK"/>
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
+
+    <application
+        android:supportsRtl="true"
+        android:theme="@style/TestActivityTheme">
+
+        <activity android:name="android.support.v4.view.ViewPagerWithTitleStripActivity"/>
+
+        <activity android:name="android.support.v4.view.ViewPagerWithTabStripActivity"/>
+
+        <activity android:name="android.support.v4.view.ViewPagerTest$ViewPagerActivity"/>
+
+    </application>
+
+</manifest>
diff --git a/compat/tests/java/android/support/v4/BaseInstrumentationTestCase.java b/viewpager/src/androidTest/java/android/support/v4/BaseInstrumentationTestCase.java
similarity index 100%
copy from compat/tests/java/android/support/v4/BaseInstrumentationTestCase.java
copy to viewpager/src/androidTest/java/android/support/v4/BaseInstrumentationTestCase.java
diff --git a/compat/tests/java/android/support/v4/BaseTestActivity.java b/viewpager/src/androidTest/java/android/support/v4/BaseTestActivity.java
similarity index 100%
copy from compat/tests/java/android/support/v4/BaseTestActivity.java
copy to viewpager/src/androidTest/java/android/support/v4/BaseTestActivity.java
diff --git a/compat/tests/java/android/support/v4/testutils/TestUtils.java b/viewpager/src/androidTest/java/android/support/v4/testutils/TestUtils.java
similarity index 100%
copy from compat/tests/java/android/support/v4/testutils/TestUtils.java
copy to viewpager/src/androidTest/java/android/support/v4/testutils/TestUtils.java
diff --git a/core-ui/tests/java/android/support/v4/testutils/TestUtilsAssertions.java b/viewpager/src/androidTest/java/android/support/v4/testutils/TestUtilsAssertions.java
similarity index 100%
rename from core-ui/tests/java/android/support/v4/testutils/TestUtilsAssertions.java
rename to viewpager/src/androidTest/java/android/support/v4/testutils/TestUtilsAssertions.java
diff --git a/core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java b/viewpager/src/androidTest/java/android/support/v4/testutils/TestUtilsMatchers.java
similarity index 100%
rename from core-ui/tests/java/android/support/v4/testutils/TestUtilsMatchers.java
rename to viewpager/src/androidTest/java/android/support/v4/testutils/TestUtilsMatchers.java
diff --git a/viewpager/src/androidTest/java/android/support/v4/view/BaseViewPagerTest.java b/viewpager/src/androidTest/java/android/support/v4/view/BaseViewPagerTest.java
new file mode 100644
index 0000000..7803ea2
--- /dev/null
+++ b/viewpager/src/androidTest/java/android/support/v4/view/BaseViewPagerTest.java
@@ -0,0 +1,1108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.view;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.pressKey;
+import static android.support.test.espresso.action.ViewActions.swipeLeft;
+import static android.support.test.espresso.action.ViewActions.swipeRight;
+import static android.support.test.espresso.assertion.PositionAssertions.isBelow;
+import static android.support.test.espresso.assertion.PositionAssertions.isBottomAlignedWith;
+import static android.support.test.espresso.assertion.PositionAssertions.isLeftAlignedWith;
+import static android.support.test.espresso.assertion.PositionAssertions.isRightAlignedWith;
+import static android.support.test.espresso.assertion.PositionAssertions.isTopAlignedWith;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static android.support.v4.testutils.TestUtilsAssertions.hasDisplayedChildren;
+import static android.support.v4.testutils.TestUtilsMatchers.backgroundColor;
+import static android.support.v4.testutils.TestUtilsMatchers.centerAlignedInParent;
+import static android.support.v4.testutils.TestUtilsMatchers.endAlignedToParent;
+import static android.support.v4.testutils.TestUtilsMatchers.isOfClass;
+import static android.support.v4.testutils.TestUtilsMatchers.startAlignedToParent;
+import static android.support.v4.view.ViewPagerActions.arrowScroll;
+import static android.support.v4.view.ViewPagerActions.scrollLeft;
+import static android.support.v4.view.ViewPagerActions.scrollRight;
+import static android.support.v4.view.ViewPagerActions.scrollToFirst;
+import static android.support.v4.view.ViewPagerActions.scrollToLast;
+import static android.support.v4.view.ViewPagerActions.scrollToPage;
+import static android.support.v4.view.ViewPagerActions.setAdapter;
+import static android.support.v4.view.ViewPagerActions.wrap;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.core.IsNot.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.support.viewpager.test.R;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.EspressoKey;
+import android.support.test.filters.FlakyTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
+import android.support.v4.BaseInstrumentationTestCase;
+import android.support.v4.testutils.TestUtilsMatchers;
+import android.text.TextUtils;
+import android.util.Pair;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for testing <code>ViewPager</code>. Most of the testing logic should be in this
+ * class as it is independent on the specific pager title implementation (interactive or non
+ * interactive).
+ *
+ * Testing logic that does depend on the specific pager title implementation is pushed into the
+ * extending classes in <code>assertStripInteraction()</code> method.
+ */
+public abstract class BaseViewPagerTest<T extends Activity> extends BaseInstrumentationTestCase<T> {
+    private static final int DIRECTION_LEFT = -1;
+    private static final int DIRECTION_RIGHT = 1;
+    protected ViewPager mViewPager;
+
+    protected static class BasePagerAdapter<Q> extends PagerAdapter {
+        protected ArrayList<Pair<String, Q>> mEntries = new ArrayList<>();
+
+        public void add(String title, Q content) {
+            mEntries.add(new Pair<>(title, content));
+        }
+
+        @Override
+        public int getCount() {
+            return mEntries.size();
+        }
+
+        protected void configureInstantiatedItem(View view, int position) {
+            switch (position) {
+                case 0:
+                    view.setId(R.id.page_0);
+                    break;
+                case 1:
+                    view.setId(R.id.page_1);
+                    break;
+                case 2:
+                    view.setId(R.id.page_2);
+                    break;
+                case 3:
+                    view.setId(R.id.page_3);
+                    break;
+                case 4:
+                    view.setId(R.id.page_4);
+                    break;
+                case 5:
+                    view.setId(R.id.page_5);
+                    break;
+                case 6:
+                    view.setId(R.id.page_6);
+                    break;
+                case 7:
+                    view.setId(R.id.page_7);
+                    break;
+                case 8:
+                    view.setId(R.id.page_8);
+                    break;
+                case 9:
+                    view.setId(R.id.page_9);
+                    break;
+            }
+        }
+
+        @Override
+        public void destroyItem(ViewGroup container, int position, Object object) {
+            // The adapter is also responsible for removing the view.
+            container.removeView(((ViewHolder) object).view);
+        }
+
+        @Override
+        public int getItemPosition(Object object) {
+            return ((ViewHolder) object).position;
+        }
+
+        @Override
+        public boolean isViewFromObject(View view, Object object) {
+            return ((ViewHolder) object).view == view;
+        }
+
+        @Override
+        public CharSequence getPageTitle(int position) {
+            return mEntries.get(position).first;
+        }
+
+        protected static class ViewHolder {
+            final View view;
+            final int position;
+
+            public ViewHolder(View view, int position) {
+                this.view = view;
+                this.position = position;
+            }
+        }
+    }
+
+    protected static class ColorPagerAdapter extends BasePagerAdapter<Integer> {
+        @Override
+        public Object instantiateItem(ViewGroup container, int position) {
+            final View view = new View(container.getContext());
+            view.setBackgroundColor(mEntries.get(position).second);
+            configureInstantiatedItem(view, position);
+
+            // Unlike ListView adapters, the ViewPager adapter is responsible
+            // for adding the view to the container.
+            container.addView(view);
+
+            return new ViewHolder(view, position);
+        }
+    }
+
+    protected static class TextPagerAdapter extends BasePagerAdapter<String> {
+        @Override
+        public Object instantiateItem(ViewGroup container, int position) {
+            final TextView view = new TextView(container.getContext());
+            view.setText(mEntries.get(position).second);
+            configureInstantiatedItem(view, position);
+
+            // Unlike ListView adapters, the ViewPager adapter is responsible
+            // for adding the view to the container.
+            container.addView(view);
+
+            return new ViewHolder(view, position);
+        }
+    }
+
+    protected static class ButtonPagerAdapter extends BasePagerAdapter<Integer> {
+        private ArrayList<Button[]> mButtons = new ArrayList<>();
+
+        @Override
+        public void add(String title, Integer content) {
+            super.add(title, content);
+            mButtons.add(new Button[3]);
+        }
+
+        @Override
+        public Object instantiateItem(ViewGroup container, int position) {
+            final LinearLayout view = new LinearLayout(container.getContext());
+            view.setBackgroundColor(mEntries.get(position).second);
+            view.setOrientation(LinearLayout.HORIZONTAL);
+            configureInstantiatedItem(view, position);
+
+            for (int i = 0; i < 3; ++i) {
+                Button but = new Button(container.getContext());
+                but.setText("" + i);
+                but.setFocusableInTouchMode(true);
+                view.addView(but, ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT);
+                mButtons.get(position)[i] = but;
+            }
+
+            // Unlike ListView adapters, the ViewPager adapter is responsible
+            // for adding the view to the container.
+            container.addView(view);
+
+            return new ViewHolder(view, position);
+        }
+
+        public View getButton(int page, int idx) {
+            return mButtons.get(page)[idx];
+        }
+    }
+
+    public BaseViewPagerTest(Class<T> activityClass) {
+        super(activityClass);
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        final T activity = mActivityTestRule.getActivity();
+        mViewPager = (ViewPager) activity.findViewById(R.id.pager);
+
+        ColorPagerAdapter adapter = new ColorPagerAdapter();
+        adapter.add("Red", Color.RED);
+        adapter.add("Green", Color.GREEN);
+        adapter.add("Blue", Color.BLUE);
+        onView(withId(R.id.pager)).perform(setAdapter(adapter), scrollToPage(0, false));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        onView(withId(R.id.pager)).perform(setAdapter(null));
+    }
+
+    private void verifyPageSelections(boolean smoothScroll) {
+        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
+
+        ViewPager.OnPageChangeListener mockPageChangeListener =
+                mock(ViewPager.OnPageChangeListener.class);
+        mViewPager.addOnPageChangeListener(mockPageChangeListener);
+
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right", 1, mViewPager.getCurrentItem());
+        verify(mockPageChangeListener, times(1)).onPageSelected(1);
+
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right", 2, mViewPager.getCurrentItem());
+        verify(mockPageChangeListener, times(1)).onPageSelected(2);
+
+        // Try "scrolling" beyond the last page and test that we're still on the last page.
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right beyond last page", 2, mViewPager.getCurrentItem());
+        // We're still on this page, so we shouldn't have been called again with index 2
+        verify(mockPageChangeListener, times(1)).onPageSelected(2);
+
+        onView(withId(R.id.pager)).perform(scrollLeft(smoothScroll));
+        assertEquals("Scroll left", 1, mViewPager.getCurrentItem());
+        // Verify that this is the second time we're called on index 1
+        verify(mockPageChangeListener, times(2)).onPageSelected(1);
+
+        onView(withId(R.id.pager)).perform(scrollLeft(smoothScroll));
+        assertEquals("Scroll left", 0, mViewPager.getCurrentItem());
+        // Verify that this is the first time we're called on index 0
+        verify(mockPageChangeListener, times(1)).onPageSelected(0);
+
+        // Try "scrolling" beyond the first page and test that we're still on the first page.
+        onView(withId(R.id.pager)).perform(scrollLeft(smoothScroll));
+        assertEquals("Scroll left beyond first page", 0, mViewPager.getCurrentItem());
+        // We're still on this page, so we shouldn't have been called again with index 0
+        verify(mockPageChangeListener, times(1)).onPageSelected(0);
+
+        // Unregister our listener
+        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
+
+        // Go from index 0 to index 2
+        onView(withId(R.id.pager)).perform(scrollToPage(2, smoothScroll));
+        assertEquals("Scroll to last page", 2, mViewPager.getCurrentItem());
+        // Our listener is not registered anymore, so we shouldn't have been called with index 2
+        verify(mockPageChangeListener, times(1)).onPageSelected(2);
+
+        // And back to 0
+        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
+        assertEquals("Scroll to first page", 0, mViewPager.getCurrentItem());
+        // Our listener is not registered anymore, so we shouldn't have been called with index 0
+        verify(mockPageChangeListener, times(1)).onPageSelected(0);
+
+        // Verify the overall sequence of calls to onPageSelected of our listener
+        ArgumentCaptor<Integer> pageSelectedCaptor = ArgumentCaptor.forClass(int.class);
+        verify(mockPageChangeListener, times(4)).onPageSelected(pageSelectedCaptor.capture());
+        assertThat(pageSelectedCaptor.getAllValues(), TestUtilsMatchers.matches(1, 2, 1, 0));
+    }
+
+    @Test
+    @MediumTest
+    public void testPageSelectionsImmediate() {
+        verifyPageSelections(false);
+    }
+
+    @Test
+    @LargeTest
+    public void testPageSelectionsSmooth() {
+        verifyPageSelections(true);
+    }
+
+    private void verifyPageChangeViewActions(ViewAction next, ViewAction previous) {
+        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
+        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+
+        ViewPager.OnPageChangeListener mockPageChangeListener =
+                mock(ViewPager.OnPageChangeListener.class);
+        mViewPager.addOnPageChangeListener(mockPageChangeListener);
+
+        onView(withId(R.id.pager)).perform(next);
+        assertEquals("Move to next page", 1, mViewPager.getCurrentItem());
+        verify(mockPageChangeListener, times(1)).onPageSelected(1);
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+
+        onView(withId(R.id.pager)).perform(next);
+        assertEquals("Move to next page", 2, mViewPager.getCurrentItem());
+        verify(mockPageChangeListener, times(1)).onPageSelected(2);
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
+        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+
+        // Try swiping beyond the last page and test that we're still on the last page.
+        onView(withId(R.id.pager)).perform(next);
+        assertEquals("Attempt to move to next page beyond last page", 2,
+                mViewPager.getCurrentItem());
+        // We're still on this page, so we shouldn't have been called again with index 2
+        verify(mockPageChangeListener, times(1)).onPageSelected(2);
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
+        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+
+        onView(withId(R.id.pager)).perform(previous);
+        assertEquals("Move to previous page", 1, mViewPager.getCurrentItem());
+        // Verify that this is the second time we're called on index 1
+        verify(mockPageChangeListener, times(2)).onPageSelected(1);
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+
+        onView(withId(R.id.pager)).perform(previous);
+        assertEquals("Move to previous page", 0, mViewPager.getCurrentItem());
+        // Verify that this is the first time we're called on index 0
+        verify(mockPageChangeListener, times(1)).onPageSelected(0);
+        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+
+        // Try swiping beyond the first page and test that we're still on the first page.
+        onView(withId(R.id.pager)).perform(previous);
+        assertEquals("Attempt to move to previous page beyond first page", 0,
+                mViewPager.getCurrentItem());
+        // We're still on this page, so we shouldn't have been called again with index 0
+        verify(mockPageChangeListener, times(1)).onPageSelected(0);
+        assertFalse(mViewPager.canScrollHorizontally(DIRECTION_LEFT));
+        assertTrue(mViewPager.canScrollHorizontally(DIRECTION_RIGHT));
+
+        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
+
+        // Verify the overall sequence of calls to onPageSelected of our listener
+        ArgumentCaptor<Integer> pageSelectedCaptor = ArgumentCaptor.forClass(int.class);
+        verify(mockPageChangeListener, times(4)).onPageSelected(pageSelectedCaptor.capture());
+        assertThat(pageSelectedCaptor.getAllValues(), TestUtilsMatchers.matches(1, 2, 1, 0));
+    }
+
+    @Test
+    @LargeTest
+    public void testPageSwipes() {
+        verifyPageChangeViewActions(wrap(swipeLeft()), wrap(swipeRight()));
+    }
+
+    @Test
+    @LargeTest
+    public void testArrowPageChanges() {
+        verifyPageChangeViewActions(arrowScroll(View.FOCUS_RIGHT), arrowScroll(View.FOCUS_LEFT));
+    }
+
+    @Test
+    @LargeTest
+    public void testPageSwipesComposite() {
+        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
+
+        onView(withId(R.id.pager)).perform(wrap(swipeLeft()), wrap(swipeLeft()));
+        assertEquals("Swipe twice left", 2, mViewPager.getCurrentItem());
+
+        onView(withId(R.id.pager)).perform(wrap(swipeLeft()), wrap(swipeRight()));
+        assertEquals("Swipe left beyond last page and then right", 1, mViewPager.getCurrentItem());
+
+        onView(withId(R.id.pager)).perform(wrap(swipeRight()), wrap(swipeRight()));
+        assertEquals("Swipe right and then right beyond first page", 0,
+                mViewPager.getCurrentItem());
+
+        onView(withId(R.id.pager)).perform(wrap(swipeRight()), wrap(swipeLeft()));
+        assertEquals("Swipe right beyond first page and then left", 1, mViewPager.getCurrentItem());
+    }
+
+    private void verifyPageContent(boolean smoothScroll) {
+        assertEquals("Initial state", 0, mViewPager.getCurrentItem());
+
+        // Verify the displayed content to match the initial adapter - with 3 pages and each
+        // one rendered as a View.
+
+        // Page #0 should be displayed, page #1 should not be displayed and page #2 should not exist
+        // yet as it's outside of the offscreen window limit.
+        onView(withId(R.id.page_0)).check(matches(allOf(
+                isOfClass(View.class),
+                isDisplayed(),
+                backgroundColor(Color.RED))));
+        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_2)).check(doesNotExist());
+
+        // Scroll one page to select page #1
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right", 1, mViewPager.getCurrentItem());
+        // Pages #0 / #2 should not be displayed, page #1 should be displayed.
+        onView(withId(R.id.page_0)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_1)).check(matches(allOf(
+                isOfClass(View.class),
+                isDisplayed(),
+                backgroundColor(Color.GREEN))));
+        onView(withId(R.id.page_2)).check(matches(not(isDisplayed())));
+
+        // Scroll one more page to select page #2
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right again", 2, mViewPager.getCurrentItem());
+        // Page #0 should not exist as it's bumped to the outside of the offscreen window limit,
+        // page #1 should not be displayed, page #2 should be displayed.
+        onView(withId(R.id.page_0)).check(doesNotExist());
+        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_2)).check(matches(allOf(
+                isOfClass(View.class),
+                isDisplayed(),
+                backgroundColor(Color.BLUE))));
+    }
+
+    @Test
+    @MediumTest
+    public void testPageContentImmediate() {
+        verifyPageContent(false);
+    }
+
+    @Test
+    @LargeTest
+    public void testPageContentSmooth() {
+        verifyPageContent(true);
+    }
+
+    private void verifyAdapterChange(boolean smoothScroll) {
+        // Verify that we have the expected initial adapter
+        PagerAdapter initialAdapter = mViewPager.getAdapter();
+        assertEquals("Initial adapter class", ColorPagerAdapter.class, initialAdapter.getClass());
+        assertEquals("Initial adapter page count", 3, initialAdapter.getCount());
+
+        // Create a new adapter
+        TextPagerAdapter newAdapter = new TextPagerAdapter();
+        newAdapter.add("Title 0", "Body 0");
+        newAdapter.add("Title 1", "Body 1");
+        newAdapter.add("Title 2", "Body 2");
+        newAdapter.add("Title 3", "Body 3");
+        onView(withId(R.id.pager)).perform(setAdapter(newAdapter), scrollToPage(0, smoothScroll));
+
+        // Verify the displayed content to match the newly set adapter - with 4 pages and each
+        // one rendered as a TextView.
+
+        // Page #0 should be displayed, page #1 should not be displayed and pages #2 / #3 should not
+        // exist yet as they're outside of the offscreen window limit.
+        onView(withId(R.id.page_0)).check(matches(allOf(
+                isOfClass(TextView.class),
+                isDisplayed(),
+                withText("Body 0"))));
+        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_2)).check(doesNotExist());
+        onView(withId(R.id.page_3)).check(doesNotExist());
+
+        // Scroll one page to select page #1
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right", 1, mViewPager.getCurrentItem());
+        // Pages #0 / #2 should not be displayed, page #1 should be displayed, page #3 is still
+        // outside the offscreen limit.
+        onView(withId(R.id.page_0)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_1)).check(matches(allOf(
+                isOfClass(TextView.class),
+                isDisplayed(),
+                withText("Body 1"))));
+        onView(withId(R.id.page_2)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_3)).check(doesNotExist());
+
+        // Scroll one more page to select page #2
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right again", 2, mViewPager.getCurrentItem());
+        // Page #0 should not exist as it's bumped to the outside of the offscreen window limit,
+        // pages #1 / #3 should not be displayed, page #2 should be displayed.
+        onView(withId(R.id.page_0)).check(doesNotExist());
+        onView(withId(R.id.page_1)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_2)).check(matches(allOf(
+                isOfClass(TextView.class),
+                isDisplayed(),
+                withText("Body 2"))));
+        onView(withId(R.id.page_3)).check(matches(not(isDisplayed())));
+
+        // Scroll one more page to select page #2
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        assertEquals("Scroll right one more time", 3, mViewPager.getCurrentItem());
+        // Pages #0 / #1 should not exist as they're bumped to the outside of the offscreen window
+        // limit, page #2 should not be displayed, page #3 should be displayed.
+        onView(withId(R.id.page_0)).check(doesNotExist());
+        onView(withId(R.id.page_1)).check(doesNotExist());
+        onView(withId(R.id.page_2)).check(matches(not(isDisplayed())));
+        onView(withId(R.id.page_3)).check(matches(allOf(
+                isOfClass(TextView.class),
+                isDisplayed(),
+                withText("Body 3"))));
+    }
+
+    @Test
+    @MediumTest
+    public void testAdapterChangeImmediate() {
+        verifyAdapterChange(false);
+    }
+
+    @Test
+    @LargeTest
+    public void testAdapterChangeSmooth() {
+        verifyAdapterChange(true);
+    }
+
+    private void verifyTitleStripLayout(String expectedStartTitle, String expectedSelectedTitle,
+            String expectedEndTitle, int selectedPageId) {
+        // Check that the title strip spans the whole width of the pager and is aligned to
+        // its top
+        onView(withId(R.id.titles)).check(isLeftAlignedWith(withId(R.id.pager)));
+        onView(withId(R.id.titles)).check(isRightAlignedWith(withId(R.id.pager)));
+        onView(withId(R.id.titles)).check(isTopAlignedWith(withId(R.id.pager)));
+
+        // Check that the currently selected page spans the whole width of the pager and is below
+        // the title strip
+        onView(withId(selectedPageId)).check(isLeftAlignedWith(withId(R.id.pager)));
+        onView(withId(selectedPageId)).check(isRightAlignedWith(withId(R.id.pager)));
+        onView(withId(selectedPageId)).check(isBelow(withId(R.id.titles)));
+        onView(withId(selectedPageId)).check(isBottomAlignedWith(withId(R.id.pager)));
+
+        boolean hasStartTitle = !TextUtils.isEmpty(expectedStartTitle);
+        boolean hasEndTitle = !TextUtils.isEmpty(expectedEndTitle);
+
+        // Check that the title strip shows the expected number of children (tab titles)
+        int nonNullTitles = (hasStartTitle ? 1 : 0) + 1 + (hasEndTitle ? 1 : 0);
+        onView(withId(R.id.titles)).check(hasDisplayedChildren(nonNullTitles));
+
+        if (hasStartTitle) {
+            // Check that the title for the start page is displayed at the start edge of its parent
+            // (title strip)
+            onView(withId(R.id.titles)).check(matches(hasDescendant(
+                    allOf(withText(expectedStartTitle), isDisplayed(), startAlignedToParent()))));
+        }
+        // Check that the title for the selected page is displayed centered in its parent
+        // (title strip)
+        onView(withId(R.id.titles)).check(matches(hasDescendant(
+                allOf(withText(expectedSelectedTitle), isDisplayed(), centerAlignedInParent()))));
+        if (hasEndTitle) {
+            // Check that the title for the end page is displayed at the end edge of its parent
+            // (title strip)
+            onView(withId(R.id.titles)).check(matches(hasDescendant(
+                    allOf(withText(expectedEndTitle), isDisplayed(), endAlignedToParent()))));
+        }
+    }
+
+    private void verifyPagerStrip(boolean smoothScroll) {
+        // Set an adapter with 5 pages
+        final ColorPagerAdapter adapter = new ColorPagerAdapter();
+        adapter.add("Red", Color.RED);
+        adapter.add("Green", Color.GREEN);
+        adapter.add("Blue", Color.BLUE);
+        adapter.add("Yellow", Color.YELLOW);
+        adapter.add("Magenta", Color.MAGENTA);
+        onView(withId(R.id.pager)).perform(setAdapter(adapter),
+                scrollToPage(0, smoothScroll));
+
+        // Check that the pager has a title strip
+        onView(withId(R.id.pager)).check(matches(hasDescendant(withId(R.id.titles))));
+        // Check that the title strip is displayed and is of the expected class
+        onView(withId(R.id.titles)).check(matches(allOf(
+                isDisplayed(), isOfClass(getStripClass()))));
+
+        // The following block tests the overall layout of tab strip and main pager content
+        // (vertical stacking), the content of the tab strip (showing texts for the selected
+        // tab and the ones on its left / right) as well as the alignment of the content in the
+        // tab strip (selected in center, others on left and right).
+
+        // Check the content and alignment of title strip for selected page #0
+        verifyTitleStripLayout(null, "Red", "Green", R.id.page_0);
+
+        // Scroll one page to select page #1 and check layout / content of title strip
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        verifyTitleStripLayout("Red", "Green", "Blue", R.id.page_1);
+
+        // Scroll one page to select page #2 and check layout / content of title strip
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        verifyTitleStripLayout("Green", "Blue", "Yellow", R.id.page_2);
+
+        // Scroll one page to select page #3 and check layout / content of title strip
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        verifyTitleStripLayout("Blue", "Yellow", "Magenta", R.id.page_3);
+
+        // Scroll one page to select page #4 and check layout / content of title strip
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+        verifyTitleStripLayout("Yellow", "Magenta", null, R.id.page_4);
+
+        // Scroll back to page #0
+        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
+
+        assertStripInteraction(smoothScroll);
+    }
+
+    @Test
+    @LargeTest
+    public void testPagerStripImmediate() {
+        verifyPagerStrip(false);
+    }
+
+    @Test
+    @LargeTest
+    public void testPagerStripSmooth() {
+        verifyPagerStrip(true);
+    }
+
+    /**
+     * Returns the class of the pager strip.
+     */
+    protected abstract Class getStripClass();
+
+    /**
+     * Checks assertions that are specific to the pager strip implementation (interactive or
+     * non interactive).
+     */
+    protected abstract void assertStripInteraction(boolean smoothScroll);
+
+    /**
+     * Helper method that performs the specified action on the <code>ViewPager</code> and then
+     * checks the sequence of calls to the page change listener based on the specified expected
+     * scroll state changes.
+     *
+     * If that expected list is empty, this method verifies that there were no calls to
+     * onPageScrollStateChanged when the action was performed. Otherwise it verifies that the actual
+     * sequence of calls to onPageScrollStateChanged matches the expected (specified) one.
+     */
+    private void verifyScrollStateChange(ViewAction viewAction, int... expectedScrollStateChanges) {
+        ViewPager.OnPageChangeListener mockPageChangeListener =
+                mock(ViewPager.OnPageChangeListener.class);
+        mViewPager.addOnPageChangeListener(mockPageChangeListener);
+
+        // Perform our action
+        onView(withId(R.id.pager)).perform(viewAction);
+
+        int expectedScrollStateChangeCount = (expectedScrollStateChanges != null) ?
+                expectedScrollStateChanges.length : 0;
+
+        if (expectedScrollStateChangeCount == 0) {
+            verify(mockPageChangeListener, never()).onPageScrollStateChanged(anyInt());
+        } else {
+            ArgumentCaptor<Integer> pageScrollStateCaptor = ArgumentCaptor.forClass(int.class);
+            verify(mockPageChangeListener, times(expectedScrollStateChangeCount)).
+                    onPageScrollStateChanged(pageScrollStateCaptor.capture());
+            assertThat(pageScrollStateCaptor.getAllValues(),
+                    TestUtilsMatchers.matches(expectedScrollStateChanges));
+        }
+
+        // Remove our mock listener to get back to clean state for the next test
+        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
+    }
+
+    @Test
+    @MediumTest
+    public void testPageScrollStateChangedImmediate() {
+        // Note that all the actions tested in this method are immediate (no scrolling) and
+        // as such we test that we do not get any calls to onPageScrollStateChanged in any of them
+
+        // Select one page to the right
+        verifyScrollStateChange(scrollRight(false));
+        // Select one more page to the right
+        verifyScrollStateChange(scrollRight(false));
+        // Select one page to the left
+        verifyScrollStateChange(scrollLeft(false));
+        // Select one more page to the left
+        verifyScrollStateChange(scrollLeft(false));
+        // Select last page
+        verifyScrollStateChange(scrollToLast(false));
+        // Select first page
+        verifyScrollStateChange(scrollToFirst(false));
+    }
+
+    @Test
+    @LargeTest
+    public void testPageScrollStateChangedSmooth() {
+        // Note that all the actions tested in this method use smooth scrolling and as such we test
+        // that we get the matching calls to onPageScrollStateChanged
+        final int[] expectedScrollStateChanges = new int[] {
+                ViewPager.SCROLL_STATE_SETTLING, ViewPager.SCROLL_STATE_IDLE
+        };
+
+        // Select one page to the right
+        verifyScrollStateChange(scrollRight(true), expectedScrollStateChanges);
+        // Select one more page to the right
+        verifyScrollStateChange(scrollRight(true), expectedScrollStateChanges);
+        // Select one page to the left
+        verifyScrollStateChange(scrollLeft(true), expectedScrollStateChanges);
+        // Select one more page to the left
+        verifyScrollStateChange(scrollLeft(true), expectedScrollStateChanges);
+        // Select last page
+        verifyScrollStateChange(scrollToLast(true), expectedScrollStateChanges);
+        // Select first page
+        verifyScrollStateChange(scrollToFirst(true), expectedScrollStateChanges);
+    }
+
+    @Test
+    @LargeTest
+    public void testPageScrollStateChangedSwipe() {
+        // Note that all the actions tested in this method use swiping and as such we test
+        // that we get the matching calls to onPageScrollStateChanged
+        final int[] expectedScrollStateChanges = new int[] { ViewPager.SCROLL_STATE_DRAGGING,
+                ViewPager.SCROLL_STATE_SETTLING, ViewPager.SCROLL_STATE_IDLE };
+
+        // Swipe one page to the left
+        verifyScrollStateChange(wrap(swipeLeft()), expectedScrollStateChanges);
+        assertEquals("Swipe left", 1, mViewPager.getCurrentItem());
+
+        // Swipe one more page to the left
+        verifyScrollStateChange(wrap(swipeLeft()), expectedScrollStateChanges);
+        assertEquals("Swipe left", 2, mViewPager.getCurrentItem());
+
+        // Swipe one page to the right
+        verifyScrollStateChange(wrap(swipeRight()), expectedScrollStateChanges);
+        assertEquals("Swipe right", 1, mViewPager.getCurrentItem());
+
+        // Swipe one more page to the right
+        verifyScrollStateChange(wrap(swipeRight()), expectedScrollStateChanges);
+        assertEquals("Swipe right", 0, mViewPager.getCurrentItem());
+    }
+
+    /**
+     * Helper method to verify the internal consistency of values passed to
+     * {@link ViewPager.OnPageChangeListener#onPageScrolled} callback when we go from a page with
+     * lower index to a page with higher index.
+     *
+     * @param startPageIndex Index of the starting page.
+     * @param endPageIndex Index of the ending page.
+     * @param pageWidth Page width in pixels.
+     * @param positions List of "position" values passed to all
+     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
+     * @param positionOffsets List of "positionOffset" values passed to all
+     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
+     * @param positionOffsetPixels List of "positionOffsetPixel" values passed to all
+     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
+     */
+    private void verifyScrollCallbacksToHigherPage(int startPageIndex, int endPageIndex,
+            int pageWidth, List<Integer> positions, List<Float> positionOffsets,
+            List<Integer> positionOffsetPixels) {
+        int callbackCount = positions.size();
+
+        // The last entry in all three lists must match the index of the end page
+        Assert.assertEquals("Position at last index",
+                endPageIndex, (int) positions.get(callbackCount - 1));
+        Assert.assertEquals("Position offset at last index",
+                0.0f, positionOffsets.get(callbackCount - 1), 0.0f);
+        Assert.assertEquals("Position offset pixel at last index",
+                0, (int) positionOffsetPixels.get(callbackCount - 1));
+
+        // If this was our only callback, return. This can happen on immediate page change
+        // or on very slow devices.
+        if (callbackCount == 1) {
+            return;
+        }
+
+        // If we have additional callbacks, verify that the values provided to our callback reflect
+        // a valid sequence of events going from startPageIndex to endPageIndex.
+        for (int i = 0; i < callbackCount - 1; i++) {
+            // Page position must be between start page and end page
+            int pagePositionCurr = positions.get(i);
+            if ((pagePositionCurr < startPageIndex) || (pagePositionCurr > endPageIndex)) {
+                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
+                        ", but should be between " + startPageIndex + " and " + endPageIndex);
+            }
+
+            // Page position sequence cannot be decreasing
+            int pagePositionNext = positions.get(i + 1);
+            if (pagePositionCurr > pagePositionNext) {
+                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
+                        " and then decreases to " + pagePositionNext + " at #" + (i + 1));
+            }
+
+            // Position offset must be in [0..1) range (inclusive / exclusive)
+            float positionOffsetCurr = positionOffsets.get(i);
+            if ((positionOffsetCurr < 0.0f) || (positionOffsetCurr >= 1.0f)) {
+                Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
+                        ", but should be in [0..1) range");
+            }
+
+            // Position pixel offset must be in [0..pageWidth) range (inclusive / exclusive)
+            int positionOffsetPixelCurr = positionOffsetPixels.get(i);
+            if ((positionOffsetPixelCurr < 0.0f) || (positionOffsetPixelCurr >= pageWidth)) {
+                Assert.fail("Position pixel offset at #" + i + " is " + positionOffsetCurr +
+                        ", but should be in [0.." + pageWidth + ") range");
+            }
+
+            // Position pixel offset must match the position offset and page width within
+            // a one-pixel tolerance range
+            Assert.assertEquals("Position pixel offset at #" + i + " is " +
+                    positionOffsetPixelCurr + ", but doesn't match position offset which is" +
+                    positionOffsetCurr + " and page width which is " + pageWidth,
+                    positionOffsetPixelCurr, positionOffsetCurr * pageWidth, 1.0f);
+
+            // If we stay on the same page between this index and the next one, both position
+            // offset and position pixel offset must increase
+            if (pagePositionNext == pagePositionCurr) {
+                float positionOffsetNext = positionOffsets.get(i + 1);
+                // Note that since position offset sequence is float, we are checking for strict
+                // increasing
+                if (positionOffsetNext <= positionOffsetCurr) {
+                    Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
+                            " and at #" + (i + 1) + " is " + positionOffsetNext +
+                            ". Since both are for page " + pagePositionCurr +
+                            ", they cannot decrease");
+                }
+
+                int positionOffsetPixelNext = positionOffsetPixels.get(i + 1);
+                // Note that since position offset pixel sequence is the mapping of position offset
+                // into screen pixels, we can get two (or more) callbacks with strictly increasing
+                // position offsets that are converted into the same pixel value. This is why here
+                // we are checking for non-strict increasing
+                if (positionOffsetPixelNext < positionOffsetPixelCurr) {
+                    Assert.fail("Position offset pixel at #" + i + " is " +
+                            positionOffsetPixelCurr + " and at #" + (i + 1) + " is " +
+                            positionOffsetPixelNext + ". Since both are for page " +
+                            pagePositionCurr + ", they cannot decrease");
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper method to verify the internal consistency of values passed to
+     * {@link ViewPager.OnPageChangeListener#onPageScrolled} callback when we go from a page with
+     * higher index to a page with lower index.
+     *
+     * @param startPageIndex Index of the starting page.
+     * @param endPageIndex Index of the ending page.
+     * @param pageWidth Page width in pixels.
+     * @param positions List of "position" values passed to all
+     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
+     * @param positionOffsets List of "positionOffset" values passed to all
+     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
+     * @param positionOffsetPixels List of "positionOffsetPixel" values passed to all
+     *      {@link ViewPager.OnPageChangeListener#onPageScrolled} calls.
+     */
+    private void verifyScrollCallbacksToLowerPage(int startPageIndex, int endPageIndex,
+            int pageWidth, List<Integer> positions, List<Float> positionOffsets,
+            List<Integer> positionOffsetPixels) {
+        int callbackCount = positions.size();
+
+        // The last entry in all three lists must match the index of the end page
+        Assert.assertEquals("Position at last index",
+                endPageIndex, (int) positions.get(callbackCount - 1));
+        Assert.assertEquals("Position offset at last index",
+                0.0f, positionOffsets.get(callbackCount - 1), 0.0f);
+        Assert.assertEquals("Position offset pixel at last index",
+                0, (int) positionOffsetPixels.get(callbackCount - 1));
+
+        // If this was our only callback, return. This can happen on immediate page change
+        // or on very slow devices.
+        if (callbackCount == 1) {
+            return;
+        }
+
+        // If we have additional callbacks, verify that the values provided to our callback reflect
+        // a valid sequence of events going from startPageIndex to endPageIndex.
+        for (int i = 0; i < callbackCount - 1; i++) {
+            // Page position must be between start page and end page
+            int pagePositionCurr = positions.get(i);
+            if ((pagePositionCurr > startPageIndex) || (pagePositionCurr < endPageIndex)) {
+                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
+                        ", but should be between " + endPageIndex + " and " + startPageIndex);
+            }
+
+            // Page position sequence cannot be increasing
+            int pagePositionNext = positions.get(i + 1);
+            if (pagePositionCurr < pagePositionNext) {
+                Assert.fail("Position at #" + i + " is " + pagePositionCurr +
+                        " and then increases to " + pagePositionNext + " at #" + (i + 1));
+            }
+
+            // Position offset must be in [0..1) range (inclusive / exclusive)
+            float positionOffsetCurr = positionOffsets.get(i);
+            if ((positionOffsetCurr < 0.0f) || (positionOffsetCurr >= 1.0f)) {
+                Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
+                        ", but should be in [0..1) range");
+            }
+
+            // Position pixel offset must be in [0..pageWidth) range (inclusive / exclusive)
+            int positionOffsetPixelCurr = positionOffsetPixels.get(i);
+            if ((positionOffsetPixelCurr < 0.0f) || (positionOffsetPixelCurr >= pageWidth)) {
+                Assert.fail("Position pixel offset at #" + i + " is " + positionOffsetCurr +
+                        ", but should be in [0.." + pageWidth + ") range");
+            }
+
+            // Position pixel offset must match the position offset and page width within
+            // a one-pixel tolerance range
+            Assert.assertEquals("Position pixel offset at #" + i + " is " +
+                            positionOffsetPixelCurr + ", but doesn't match position offset which is" +
+                            positionOffsetCurr + " and page width which is " + pageWidth,
+                    positionOffsetPixelCurr, positionOffsetCurr * pageWidth, 1.0f);
+
+            // If we stay on the same page between this index and the next one, both position
+            // offset and position pixel offset must decrease
+            if (pagePositionNext == pagePositionCurr) {
+                float positionOffsetNext = positionOffsets.get(i + 1);
+                // Note that since position offset sequence is float, we are checking for strict
+                // decreasing
+                if (positionOffsetNext >= positionOffsetCurr) {
+                    Assert.fail("Position offset at #" + i + " is " + positionOffsetCurr +
+                            " and at #" + (i + 1) + " is " + positionOffsetNext +
+                            ". Since both are for page " + pagePositionCurr +
+                            ", they cannot increase");
+                }
+
+                int positionOffsetPixelNext = positionOffsetPixels.get(i + 1);
+                // Note that since position offset pixel sequence is the mapping of position offset
+                // into screen pixels, we can get two (or more) callbacks with strictly decreasing
+                // position offsets that are converted into the same pixel value. This is why here
+                // we are checking for non-strict decreasing
+                if (positionOffsetPixelNext > positionOffsetPixelCurr) {
+                    Assert.fail("Position offset pixel at #" + i + " is " +
+                            positionOffsetPixelCurr + " and at #" + (i + 1) + " is " +
+                            positionOffsetPixelNext + ". Since both are for page " +
+                            pagePositionCurr + ", they cannot increase");
+                }
+            }
+        }
+    }
+
+    private void verifyScrollCallbacksToHigherPage(ViewAction viewAction,
+            int expectedEndPageIndex) {
+        final int startPageIndex = mViewPager.getCurrentItem();
+
+        ViewPager.OnPageChangeListener mockPageChangeListener =
+                mock(ViewPager.OnPageChangeListener.class);
+        mViewPager.addOnPageChangeListener(mockPageChangeListener);
+
+        // Perform our action
+        onView(withId(R.id.pager)).perform(viewAction);
+
+        final int endPageIndex = mViewPager.getCurrentItem();
+        Assert.assertEquals("Current item after action", expectedEndPageIndex, endPageIndex);
+
+        ArgumentCaptor<Integer> positionCaptor = ArgumentCaptor.forClass(int.class);
+        ArgumentCaptor<Float> positionOffsetCaptor = ArgumentCaptor.forClass(float.class);
+        ArgumentCaptor<Integer> positionOffsetPixelsCaptor = ArgumentCaptor.forClass(int.class);
+        verify(mockPageChangeListener, atLeastOnce()).onPageScrolled(positionCaptor.capture(),
+                positionOffsetCaptor.capture(), positionOffsetPixelsCaptor.capture());
+
+        verifyScrollCallbacksToHigherPage(startPageIndex, endPageIndex, mViewPager.getWidth(),
+                positionCaptor.getAllValues(), positionOffsetCaptor.getAllValues(),
+                positionOffsetPixelsCaptor.getAllValues());
+
+        // Remove our mock listener to get back to clean state for the next test
+        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
+    }
+
+    private void verifyScrollCallbacksToLowerPage(ViewAction viewAction,
+            int expectedEndPageIndex) {
+        final int startPageIndex = mViewPager.getCurrentItem();
+
+        ViewPager.OnPageChangeListener mockPageChangeListener =
+                mock(ViewPager.OnPageChangeListener.class);
+        mViewPager.addOnPageChangeListener(mockPageChangeListener);
+
+        // Perform our action
+        onView(withId(R.id.pager)).perform(viewAction);
+
+        final int endPageIndex = mViewPager.getCurrentItem();
+        Assert.assertEquals("Current item after action", expectedEndPageIndex, endPageIndex);
+
+        ArgumentCaptor<Integer> positionCaptor = ArgumentCaptor.forClass(int.class);
+        ArgumentCaptor<Float> positionOffsetCaptor = ArgumentCaptor.forClass(float.class);
+        ArgumentCaptor<Integer> positionOffsetPixelsCaptor = ArgumentCaptor.forClass(int.class);
+        verify(mockPageChangeListener, atLeastOnce()).onPageScrolled(positionCaptor.capture(),
+                positionOffsetCaptor.capture(), positionOffsetPixelsCaptor.capture());
+
+        verifyScrollCallbacksToLowerPage(startPageIndex, endPageIndex, mViewPager.getWidth(),
+                positionCaptor.getAllValues(), positionOffsetCaptor.getAllValues(),
+                positionOffsetPixelsCaptor.getAllValues());
+
+        // Remove our mock listener to get back to clean state for the next test
+        mViewPager.removeOnPageChangeListener(mockPageChangeListener);
+    }
+
+    @Test
+    @MediumTest
+    public void testPageScrollPositionChangesImmediate() {
+        // Scroll one page to the right
+        verifyScrollCallbacksToHigherPage(scrollRight(false), 1);
+        // Scroll one more page to the right
+        verifyScrollCallbacksToHigherPage(scrollRight(false), 2);
+        // Scroll one page to the left
+        verifyScrollCallbacksToLowerPage(scrollLeft(false), 1);
+        // Scroll one more page to the left
+        verifyScrollCallbacksToLowerPage(scrollLeft(false), 0);
+
+        // Scroll to the last page
+        verifyScrollCallbacksToHigherPage(scrollToLast(false), 2);
+        // Scroll to the first page
+        verifyScrollCallbacksToLowerPage(scrollToFirst(false), 0);
+    }
+
+    @Test
+    @LargeTest
+    public void testPageScrollPositionChangesSmooth() {
+        // Scroll one page to the right
+        verifyScrollCallbacksToHigherPage(scrollRight(true), 1);
+        // Scroll one more page to the right
+        verifyScrollCallbacksToHigherPage(scrollRight(true), 2);
+        // Scroll one page to the left
+        verifyScrollCallbacksToLowerPage(scrollLeft(true), 1);
+        // Scroll one more page to the left
+        verifyScrollCallbacksToLowerPage(scrollLeft(true), 0);
+
+        // Scroll to the last page
+        verifyScrollCallbacksToHigherPage(scrollToLast(true), 2);
+        // Scroll to the first page
+        verifyScrollCallbacksToLowerPage(scrollToFirst(true), 0);
+    }
+
+    @Test
+    @LargeTest
+    public void testPageScrollPositionChangesSwipe() {
+        // Swipe one page to the left
+        verifyScrollCallbacksToHigherPage(wrap(swipeLeft()), 1);
+        // Swipe one more page to the left
+        verifyScrollCallbacksToHigherPage(wrap(swipeLeft()), 2);
+        // Swipe one page to the right
+        verifyScrollCallbacksToLowerPage(wrap(swipeRight()), 1);
+        // Swipe one more page to the right
+        verifyScrollCallbacksToLowerPage(wrap(swipeRight()), 0);
+    }
+
+    @FlakyTest(bugId = 38260187)
+    @Test
+    @LargeTest
+    public void testKeyboardNavigation() {
+        ButtonPagerAdapter adapter = new ButtonPagerAdapter();
+        adapter.add("Red", Color.RED);
+        adapter.add("Green", Color.GREEN);
+        adapter.add("Blue", Color.BLUE);
+        onView(withId(R.id.pager)).perform(setAdapter(adapter), scrollToPage(0, false));
+        View firstButton = adapter.getButton(0, 0);
+        firstButton.requestFocus();
+        assertTrue(firstButton.isFocused());
+        assertEquals(0, mViewPager.getCurrentItem());
+
+        // Normal arrows should traverse contents first
+        onView(is(firstButton)).perform(pressKey(KeyEvent.KEYCODE_DPAD_RIGHT));
+        assertEquals(0, mViewPager.getCurrentItem());
+        assertTrue(adapter.getButton(0, 1).isFocused());
+
+        // Alt arrows should change page even if there are more focusables in that direction
+        onView(is(adapter.getButton(0, 1))).perform(pressKey(new EspressoKey.Builder()
+                .withAltPressed(true).withKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT).build()));
+        assertEquals(1, mViewPager.getCurrentItem());
+        assertTrue(adapter.getButton(1, 0).isFocused());
+
+        // Normal arrows should change page if there are no more focusables in that direction
+        onView(is(adapter.getButton(1, 0))).perform(pressKey(KeyEvent.KEYCODE_DPAD_LEFT));
+        assertEquals(0, mViewPager.getCurrentItem());
+    }
+}
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerActions.java b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerActions.java
similarity index 100%
rename from core-ui/tests/java/android/support/v4/view/ViewPagerActions.java
rename to viewpager/src/androidTest/java/android/support/v4/view/ViewPagerActions.java
diff --git a/core-ui/tests/java/android/support/v4/view/ViewPagerTest.java b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerTest.java
similarity index 100%
rename from core-ui/tests/java/android/support/v4/view/ViewPagerTest.java
rename to viewpager/src/androidTest/java/android/support/v4/view/ViewPagerTest.java
diff --git a/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTabStripActivity.java b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTabStripActivity.java
new file mode 100644
index 0000000..487a1af
--- /dev/null
+++ b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTabStripActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.viewpager.test.R;
+import android.view.WindowManager;
+
+public class ViewPagerWithTabStripActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        setContentView(R.layout.view_pager_with_tab_strip);
+    }
+}
diff --git a/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTabStripTest.java b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTabStripTest.java
new file mode 100644
index 0000000..b7ca014
--- /dev/null
+++ b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTabStripTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.view;
+
+import android.support.viewpager.test.R;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static android.support.v4.view.ViewPagerActions.clickBetweenTwoTitles;
+import static android.support.v4.view.ViewPagerActions.scrollRight;
+import static android.support.v4.view.ViewPagerActions.scrollToPage;
+import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Provides assertions that depend on the interactive nature of <code>PagerTabStrip</code>.
+ */
+public class ViewPagerWithTabStripTest extends BaseViewPagerTest<ViewPagerWithTabStripActivity> {
+    public ViewPagerWithTabStripTest() {
+        super(ViewPagerWithTabStripActivity.class);
+    }
+
+    @Override
+    protected Class getStripClass() {
+        return PagerTabStrip.class;
+    }
+
+    @Override
+    protected void assertStripInteraction(boolean smoothScroll) {
+        // The following block tests that ViewPager page selection changes on clicking titles of
+        // various tabs as PagerTabStrip is interactive
+
+        // Click the tab title for page #0 and verify that we're still on page #0
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
+        assertEquals("Click tab #0 on tab #0", 0, mViewPager.getCurrentItem());
+
+        // Click the tab title for page #1 and verify that we're on page #1
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
+        assertEquals("Click tab #1 on tab #0", 1, mViewPager.getCurrentItem());
+
+        // Click the tab title for page #0 and verify that we're on page #0
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
+        assertEquals("Click tab #0 on tab #1", 0, mViewPager.getCurrentItem());
+
+        // Go back to page #1
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+
+        // Click the tab title for page #1 and verify that we're still on page #1
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
+        assertEquals("Click tab #1 on tab #1", 1, mViewPager.getCurrentItem());
+
+        // Click the tab title for page #2 and verify that we're on page #2
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Blue"))).perform(click());
+        assertEquals("Click tab #2 on tab #1", 2, mViewPager.getCurrentItem());
+
+        // The following block tests that ViewPager page selection changes on clicking in
+        // between titles of tabs as that functionality is exposed by PagerTabStrip
+
+        // Scroll back to page #0
+        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
+
+        // Click between titles of page #0 and page #1 and verify that we're on page #1
+        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
+        assertEquals("Click in between tabs #0 and #1 on tab #0", 1, mViewPager.getCurrentItem());
+
+        // Click between titles of page #0 and page #1 and verify that we're on page #0
+        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
+        assertEquals("Click in between tabs #0 and #1 on tab #1", 0, mViewPager.getCurrentItem());
+
+        // Go back to page #1
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+
+        // Click between titles of page #1 and page #2 and verify that we're on page #2
+        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Green", "Blue"));
+        assertEquals("Click in between tabs #1 and #2 on tab #1", 2, mViewPager.getCurrentItem());
+    }
+}
diff --git a/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java
new file mode 100644
index 0000000..8aa295f
--- /dev/null
+++ b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTitleStripActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.support.v4.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.viewpager.test.R;
+import android.view.WindowManager;
+
+public class ViewPagerWithTitleStripActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        setContentView(R.layout.view_pager_with_title_strip);
+    }
+}
diff --git a/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTitleStripTest.java b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTitleStripTest.java
new file mode 100644
index 0000000..044d9cd
--- /dev/null
+++ b/viewpager/src/androidTest/java/android/support/v4/view/ViewPagerWithTitleStripTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.support.v4.view;
+
+import android.support.viewpager.test.R;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static android.support.v4.view.ViewPagerActions.clickBetweenTwoTitles;
+import static android.support.v4.view.ViewPagerActions.scrollRight;
+import static android.support.v4.view.ViewPagerActions.scrollToPage;
+import static org.hamcrest.Matchers.allOf;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Provides assertions that depend on the non-interactive nature of <code>PagerTabStrip</code>.
+ */
+public class ViewPagerWithTitleStripTest
+        extends BaseViewPagerTest<ViewPagerWithTitleStripActivity> {
+    public ViewPagerWithTitleStripTest() {
+        super(ViewPagerWithTitleStripActivity.class);
+    }
+
+    @Override
+    protected Class getStripClass() {
+        return PagerTitleStrip.class;
+    }
+
+    @Override
+    protected void assertStripInteraction(boolean smoothScroll) {
+        // The following block tests that nothing happens on clicking titles of various tabs
+        // as PagerTitleStrip is not interactive
+
+        // Click the tab title for page #0 and verify that we're still on page #0
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
+        assertEquals("Click tab #0 on tab #0", 0, mViewPager.getCurrentItem());
+
+        // Click the tab title for page #1 and verify that we're still on page #0
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
+        assertEquals("Click tab #1 on tab #0", 0, mViewPager.getCurrentItem());
+
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+
+        // Click the tab title for page #0 and verify that we're still on page #1
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Red"))).perform(click());
+        assertEquals("Click tab #0 on tab #1", 1, mViewPager.getCurrentItem());
+
+        // Click the tab title for page #1 and verify that we're still on page #1
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Green"))).perform(click());
+        assertEquals("Click tab #1 on tab #1", 1, mViewPager.getCurrentItem());
+
+        // Click the tab title for page #2 and verify that we're still on page #1
+        onView(allOf(isDescendantOfA(withId(R.id.titles)), withText("Blue"))).perform(click());
+        assertEquals("Click tab #2 on tab #1", 1, mViewPager.getCurrentItem());
+
+
+        // The following block tests that nothing happens on clicking in between titles of various
+        // tabs as PagerTitleStrip is not interactive
+
+        // Scroll back to page #0
+        onView(withId(R.id.pager)).perform(scrollToPage(0, smoothScroll));
+
+        // Click between titles of page #0 and page #1 and verify that we're still on page #0
+        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
+        assertEquals("Click in between tabs #0 and #1 on tab #0", 0, mViewPager.getCurrentItem());
+
+        // Go to page #1
+        onView(withId(R.id.pager)).perform(scrollRight(smoothScroll));
+
+        // Click between titles of page #1 and page #2 and verify that we're still on page #1
+        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Green", "Blue"));
+        assertEquals("Click in between tabs #1 and #2 on tab #1", 1, mViewPager.getCurrentItem());
+
+        // Click between titles of page #0 and page #1 and verify that we're still on page #1
+        onView(withId(R.id.titles)).perform(clickBetweenTwoTitles("Red", "Green"));
+        assertEquals("Click in between tabs #0 and #1 on tab #1", 1, mViewPager.getCurrentItem());
+    }
+}
diff --git a/core-ui/tests/res/layout/view_pager_with_tab_strip.xml b/viewpager/src/androidTest/res/layout/view_pager_with_tab_strip.xml
similarity index 100%
rename from core-ui/tests/res/layout/view_pager_with_tab_strip.xml
rename to viewpager/src/androidTest/res/layout/view_pager_with_tab_strip.xml
diff --git a/core-ui/tests/res/layout/view_pager_with_title_strip.xml b/viewpager/src/androidTest/res/layout/view_pager_with_title_strip.xml
similarity index 100%
rename from core-ui/tests/res/layout/view_pager_with_title_strip.xml
rename to viewpager/src/androidTest/res/layout/view_pager_with_title_strip.xml
diff --git a/viewpager/src/androidTest/res/values/ids.xml b/viewpager/src/androidTest/res/values/ids.xml
new file mode 100644
index 0000000..e5fcf63
--- /dev/null
+++ b/viewpager/src/androidTest/res/values/ids.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <item name="page_0" type="id"/>
+    <item name="page_1" type="id"/>
+    <item name="page_2" type="id"/>
+    <item name="page_3" type="id"/>
+    <item name="page_4" type="id"/>
+    <item name="page_5" type="id"/>
+    <item name="page_6" type="id"/>
+    <item name="page_7" type="id"/>
+    <item name="page_8" type="id"/>
+    <item name="page_9" type="id"/>
+</resources>
\ No newline at end of file
diff --git a/core-ui/tests/res/values/styles.xml b/viewpager/src/androidTest/res/values/styles.xml
similarity index 100%
rename from core-ui/tests/res/values/styles.xml
rename to viewpager/src/androidTest/res/values/styles.xml
diff --git a/viewpager/src/main/AndroidManifest.xml b/viewpager/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..feb8a03
--- /dev/null
+++ b/viewpager/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="android.support.viewpager" />
diff --git a/core-ui/src/main/java/android/support/v4/view/PagerAdapter.java b/viewpager/src/main/java/android/support/v4/view/PagerAdapter.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/PagerAdapter.java
rename to viewpager/src/main/java/android/support/v4/view/PagerAdapter.java
diff --git a/core-ui/src/main/java/android/support/v4/view/PagerTabStrip.java b/viewpager/src/main/java/android/support/v4/view/PagerTabStrip.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/PagerTabStrip.java
rename to viewpager/src/main/java/android/support/v4/view/PagerTabStrip.java
diff --git a/core-ui/src/main/java/android/support/v4/view/PagerTitleStrip.java b/viewpager/src/main/java/android/support/v4/view/PagerTitleStrip.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/PagerTitleStrip.java
rename to viewpager/src/main/java/android/support/v4/view/PagerTitleStrip.java
diff --git a/core-ui/src/main/java/android/support/v4/view/ViewPager.java b/viewpager/src/main/java/android/support/v4/view/ViewPager.java
similarity index 100%
rename from core-ui/src/main/java/android/support/v4/view/ViewPager.java
rename to viewpager/src/main/java/android/support/v4/view/ViewPager.java
diff --git a/viewpager2/build.gradle b/viewpager2/build.gradle
index a4eb3ad..7f75d09 100644
--- a/viewpager2/build.gradle
+++ b/viewpager2/build.gradle
@@ -38,7 +38,6 @@
 
 supportLibrary {
     name = "AndroidX Widget ViewPager2"
-    publish = false
     mavenVersion = LibraryVersions.SUPPORT_LIBRARY
     mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
diff --git a/viewpager2/src/main/AndroidManifest.xml b/viewpager2/src/main/AndroidManifest.xml
index 198a6f7..ebddd6c 100644
--- a/viewpager2/src/main/AndroidManifest.xml
+++ b/viewpager2/src/main/AndroidManifest.xml
@@ -14,7 +14,4 @@
      limitations under the License.
 -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="androidx.widget.viewpager2">
-    <uses-sdk android:minSdkVersion="14"/>
-</manifest>
\ No newline at end of file
+<manifest package="androidx.widget.viewpager2"/>
\ No newline at end of file
diff --git a/wear/Android.mk b/wear/Android.mk
deleted file mode 100644
index 9e5bf5b..0000000
--- a/wear/Android.mk
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-# Here is a prebuilt library containing all the wearable stubs necessary for ambient mode
-include $(CLEAR_VARS)
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
-        prebuilt-com.google.android.wearable-stubs:wear_stubs/com.google.android.wearable-stubs.jar
-include $(BUILD_MULTI_PREBUILT)
-
-# Here is the final static library that apps can link against.
-# Applications that use this library must specify
-#
-#   LOCAL_STATIC_ANDROID_LIBRARIES := \
-#       android-support-wear \
-#       android-support-core-ui \
-#       android-support-v7-recyclerview
-#
-# in their makefiles to include the resources and their dependencies in their package
-
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE := android-support-wear
-LOCAL_SDK_VERSION := $(SUPPORT_CURRENT_SDK_VERSION)
-LOCAL_SRC_FILES := $(call all-java-files-under,src/main/java)
-LOCAL_MANIFEST_FILE := src/main/AndroidManifest.xml
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_JAVA_LIBRARIES := \
-    android-support-annotations
-LOCAL_SHARED_ANDROID_LIBRARIES := \
-    android-support-core-ui \
-    android-support-percent \
-    android-support-v7-recyclerview \
-    android-support-v4 \
-    android-support-constraint-layout
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    prebuilt-com.google.android.wearable-stubs
-LOCAL_JAR_EXCLUDE_FILES := none
-LOCAL_JAVA_LANGUAGE_VERSION := 1.7
-LOCAL_AAPT_FLAGS := --add-javadoc-annotation doconly
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
diff --git a/wear/res/layout/ws_action_drawer_title_view.xml b/wear/res/layout/ws_action_drawer_title_view.xml
index 15067dd..565e770 100644
--- a/wear/res/layout/ws_action_drawer_title_view.xml
+++ b/wear/res/layout/ws_action_drawer_title_view.xml
@@ -13,11 +13,29 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<TextView
+<android.support.constraint.ConstraintLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/ws_action_drawer_title"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/ws_action_drawer_item_icon_size"
-    android:layout_gravity="center"
-    android:gravity="center|bottom"
-    style="@style/WsWearableActionDrawerTitleText" />
+    android:layout_height="wrap_content">
+
+    <android.support.constraint.Guideline
+        android:id="@+id/ws_action_drawer_guide_end"
+        app:layout_constraintGuide_percent="@dimen/ws_action_drawer_title_end"
+        style="@style/WsVerticalGuideStyle" />
+
+    <android.support.constraint.Guideline
+        android:id="@+id/ws_action_drawer_guide_start"
+        app:layout_constraintGuide_percent="@dimen/ws_action_drawer_title_start"
+        style="@style/WsVerticalGuideStyle" />
+
+    <TextView
+        android:id="@+id/ws_action_drawer_title"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        app:layout_constraintEnd_toEndOf="@id/ws_action_drawer_guide_end"
+        app:layout_constraintStart_toStartOf="@id/ws_action_drawer_guide_start"
+        style="@style/WsWearableActionDrawerTitleText" />
+
+</android.support.constraint.ConstraintLayout>
diff --git a/wear/res/values/dimens.xml b/wear/res/values/dimens.xml
index 9ae13bb..7cd5d20 100644
--- a/wear/res/values/dimens.xml
+++ b/wear/res/values/dimens.xml
@@ -25,6 +25,8 @@
     <item name="ws_action_drawer_item_last_item_bottom_padding" type="fraction">15%</item>
     <item name="ws_action_drawer_item_left_padding" type="fraction">15%</item>
     <item name="ws_action_drawer_item_right_padding" type="fraction">10%</item>
+    <item name="ws_action_drawer_title_start" format="float" type="dimen">.15</item>
+    <item name="ws_action_drawer_title_end" format="float" type="dimen">.85</item>
     <dimen name="ws_action_drawer_item_top_padding">8dp</dimen>
     <dimen name="ws_action_drawer_item_bottom_padding">8dp</dimen>
     <dimen name="ws_action_drawer_item_icon_right_margin">8dp</dimen>
diff --git a/wear/src/androidTest/NO_DOCS b/wear/src/androidTest/NO_DOCS
deleted file mode 100644
index 092a39c..0000000
--- a/wear/src/androidTest/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeSupportResumeTest.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportResumeTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/ambient/AmbientModeSupportResumeTest.java
rename to wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportResumeTest.java
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeSupportResumeTestActivity.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportResumeTestActivity.java
similarity index 100%
rename from wear/tests/src/android/support/wear/ambient/AmbientModeSupportResumeTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportResumeTestActivity.java
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeSupportTest.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportTest.java
similarity index 100%
rename from wear/tests/src/android/support/wear/ambient/AmbientModeSupportTest.java
rename to wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportTest.java
diff --git a/wear/tests/src/android/support/wear/ambient/AmbientModeSupportTestActivity.java b/wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportTestActivity.java
similarity index 100%
rename from wear/tests/src/android/support/wear/ambient/AmbientModeSupportTestActivity.java
rename to wear/src/androidTest/java/android/support/wear/ambient/AmbientModeSupportTestActivity.java
diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml
index 3849df5..77628b8 100644
--- a/wear/src/main/AndroidManifest.xml
+++ b/wear/src/main/AndroidManifest.xml
@@ -13,6 +13,4 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.support.wear">
-</manifest>
+<manifest package="android.support.wear"/>
diff --git a/wear/src/main/java/android/support/wear/widget/drawer/WearableActionDrawerView.java b/wear/src/main/java/android/support/wear/widget/drawer/WearableActionDrawerView.java
index 99cd4ff..b48962d 100644
--- a/wear/src/main/java/android/support/wear/widget/drawer/WearableActionDrawerView.java
+++ b/wear/src/main/java/android/support/wear/widget/drawer/WearableActionDrawerView.java
@@ -419,6 +419,7 @@
                 holder.iconView.setImageDrawable(icon);
             } else if (viewHolder instanceof TitleViewHolder) {
                 TitleViewHolder holder = (TitleViewHolder) viewHolder;
+                holder.textView.setPadding(0, mFirstItemTopPadding, 0, mBottomPadding);
                 holder.textView.setText(mTitle);
             }
         }
diff --git a/webkit/AndroidManifest.xml b/webkit/AndroidManifest.xml
deleted file mode 100644
index 7d2bbc2..0000000
--- a/webkit/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="androidx.webkit">
-</manifest>
-
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
new file mode 100644
index 0000000..b0d66d6
--- /dev/null
+++ b/webkit/api/current.txt
@@ -0,0 +1,12 @@
+package androidx.webkit {
+
+  public class WebViewCompat {
+    method public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+  }
+
+  public static abstract interface WebViewCompat.VisualStateCallback {
+    method public abstract void onComplete(long);
+  }
+
+}
+
diff --git a/webkit/build.gradle b/webkit/build.gradle
index 9acadf7..7975fc8 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -13,21 +13,39 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-apply plugin: android.support.SupportAndroidLibraryPlugin
+
+import static android.support.dependencies.DependenciesKt.*
+import android.support.LibraryGroups
+import android.support.LibraryVersions
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+}
+
+dependencies {
+    api(project(":support-annotations"))
+    api(project(':support-compat'))
+
+    androidTestImplementation(TEST_RUNNER)
+}
+
+ext {
+    webviewBoundaryInterfacesDir = project(':webview-support-interfaces').projectDir
+}
 
 android {
-    defaultConfig {
-        minSdkVersion 21
-    }
-
     sourceSets {
-        main.manifest.srcFile 'AndroidManifest.xml'
+        // Allow compiling the WebView support library boundary interfaces from this project.
+        main.java.srcDirs += new File(webviewBoundaryInterfacesDir, "src").getAbsolutePath()
     }
 }
 
 supportLibrary {
     name = "WebView Support Library"
-    publish = false
+    publish = true
+    mavenVersion = LibraryVersions.SUPPORT_LIBRARY
+    mavenGroup = LibraryGroups.SUPPORT
     inceptionYear = "2017"
     description = "The WebView Support Library is a static library you can add to your Android application in order to use android.webkit APIs that are not available for older platform versions."
+    minSdkVersion = 21
 }
diff --git a/webkit/src/androidTest/AndroidManifest.xml b/webkit/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..6448148
--- /dev/null
+++ b/webkit/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2017 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="androidx.webkit">
+    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
+</manifest>
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
new file mode 100644
index 0000000..8b38d99
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.os.BuildCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class WebViewCompatTest {
+    WebViewOnUiThread mWebViewOnUiThread;
+
+    private static final long TEST_TIMEOUT = 20000L;
+
+    @Before
+    public void setUp() {
+        mWebViewOnUiThread = new androidx.webkit.WebViewOnUiThread();
+    }
+
+    @MediumTest
+    @Test
+    public void testVisualStateCallbackCalled() throws Exception {
+        // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (!BuildCompat.isAtLeastP()) return;
+
+        final CountDownLatch callbackLatch = new CountDownLatch(1);
+        final long kRequest = 100;
+
+        mWebViewOnUiThread.loadUrl("about:blank");
+
+        mWebViewOnUiThread.postVisualStateCallbackCompat(kRequest,
+                new WebViewCompat.VisualStateCallback() {
+                        public void onComplete(long requestId) {
+                            assertEquals(kRequest, requestId);
+                            callbackLatch.countDown();
+                        }
+                });
+
+        assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @MediumTest
+    @Test
+    public void testCheckThread() {
+        try {
+            WebViewCompat.postVisualStateCallback(mWebViewOnUiThread.getWebViewOnCurrentThread(), 5,
+                    new WebViewCompat.VisualStateCallback() {
+                        @Override
+                        public void onComplete(long requestId) {
+                        }
+                    });
+        } catch (RuntimeException e) {
+            return;
+        }
+        fail("Calling a WebViewCompat method on the wrong thread must cause a run-time exception");
+    }
+}
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
new file mode 100644
index 0000000..6219bd3
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import android.support.test.InstrumentationRegistry;
+import android.webkit.WebView;
+
+public class WebViewOnUiThread {
+    private WebView mWebView;
+
+    public WebViewOnUiThread() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mWebView = new WebView(InstrumentationRegistry.getTargetContext());
+            }
+        });
+    }
+
+    public void loadUrl(final String url) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.loadUrl(url);
+            }
+        });
+    }
+
+    public void postVisualStateCallbackCompat(final long requestId,
+            final WebViewCompat.VisualStateCallback callback) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                WebViewCompat.postVisualStateCallback(mWebView, requestId, callback);
+            }
+        });
+    }
+
+    public WebView getWebViewOnCurrentThread() {
+        return mWebView;
+    }
+}
diff --git a/webkit/src/main/AndroidManifest.xml b/webkit/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d50d0f7
--- /dev/null
+++ b/webkit/src/main/AndroidManifest.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<manifest package="androidx.webkit"/>
diff --git a/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
new file mode 100644
index 0000000..3141918
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import android.os.Build;
+import android.os.Looper;
+import android.support.annotation.NonNull;
+import android.support.v4.os.BuildCompat;
+import android.webkit.WebView;
+
+import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import androidx.webkit.internal.WebViewGlueCommunicator;
+import androidx.webkit.internal.WebViewProviderAdapter;
+import androidx.webkit.internal.WebViewProviderFactoryAdapter;
+
+/**
+ * Compatibility version of {@link android.webkit.WebView}
+ */
+public class WebViewCompat {
+    private WebViewCompat() {} // Don't allow instances of this class to be constructed.
+
+    /**
+     * Callback interface supplied to {@link #postVisualStateCallback} for receiving
+     * notifications about the visual state.
+     */
+    public interface VisualStateCallback {
+        /**
+         * Invoked when the visual state is ready to be drawn in the next {@link WebView#onDraw}.
+         *
+         * @param requestId The identifier passed to {@link #postVisualStateCallback} when this
+         *                  callback was posted.
+         */
+        void onComplete(long requestId);
+    }
+
+    /**
+     * Posts a {@link VisualStateCallback}, which will be called when
+     * the current state of the WebView is ready to be drawn.
+     *
+     * <p>Because updates to the DOM are processed asynchronously, updates to the DOM may not
+     * immediately be reflected visually by subsequent {@link WebView#onDraw} invocations. The
+     * {@link VisualStateCallback} provides a mechanism to notify the caller when the contents
+     * of the DOM at the current time are ready to be drawn the next time the {@link WebView} draws.
+     *
+     * <p>The next draw after the callback completes is guaranteed to reflect all the updates to the
+     * DOM up to the point at which the {@link VisualStateCallback} was posted, but it may
+     * also contain updates applied after the callback was posted.
+     *
+     * <p>The state of the DOM covered by this API includes the following:
+     * <ul>
+     * <li>primitive HTML elements (div, img, span, etc..)</li>
+     * <li>images</li>
+     * <li>CSS animations</li>
+     * <li>WebGL</li>
+     * <li>canvas</li>
+     * </ul>
+     * It does not include the state of:
+     * <ul>
+     * <li>the video tag</li>
+     * </ul>
+     *
+     * <p>To guarantee that the {@link WebView} will successfully render the first frame
+     * after the {@link VisualStateCallback#onComplete} method has been called a set of
+     * conditions must be met:
+     * <ul>
+     * <li>If the {@link WebView}'s visibility is set to {@link android.view.View#VISIBLE VISIBLE}
+     * then * the {@link WebView} must be attached to the view hierarchy.</li>
+     * <li>If the {@link WebView}'s visibility is set to
+     * {@link android.view.View#INVISIBLE INVISIBLE} then the {@link WebView} must be attached to
+     * the view hierarchy and must be made {@link android.view.View#VISIBLE VISIBLE} from the
+     * {@link VisualStateCallback#onComplete} method.</li>
+     * <li>If the {@link WebView}'s visibility is set to {@link android.view.View#GONE GONE} then
+     * the {@link WebView} must be attached to the view hierarchy and its
+     * {@link android.widget.AbsoluteLayout.LayoutParams LayoutParams}'s width and height need to be
+     * set to fixed values and must be made {@link android.view.View#VISIBLE VISIBLE} from the
+     * {@link VisualStateCallback#onComplete} method.</li>
+     * </ul>
+     *
+     * <p>When using this API it is also recommended to enable pre-rasterization if the {@link
+     * WebView} is off screen to avoid flickering. See
+     * {@link android.webkit.WebSettings#setOffscreenPreRaster} for more details and do consider its
+     * caveats.
+     *
+     * @param requestId An id that will be returned in the callback to allow callers to match
+     *                  requests with callbacks.
+     * @param callback  The callback to be invoked.
+     */
+    public static void postVisualStateCallback(@NonNull WebView webview, long requestId,
+            @NonNull final VisualStateCallback callback) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            webview.postVisualStateCallback(requestId,
+                    new android.webkit.WebView.VisualStateCallback() {
+                        @Override
+                        public void onComplete(long l) {
+                            callback.onComplete(l);
+                        }
+                    });
+        } else {
+            // TODO(gsennton): guard with if WebViewApk.hasFeature(POSTVISUALSTATECALLBACK)
+            checkThread(webview);
+            getProvider(webview).insertVisualStateCallback(requestId, callback);
+        }
+    }
+
+    private static WebViewProviderAdapter getProvider(WebView webview) {
+        return new WebViewProviderAdapter(createProvider(webview));
+    }
+
+    private static WebViewProviderFactoryAdapter getFactory() {
+        return WebViewGlueCommunicator.getFactory();
+    }
+
+    private static WebViewProviderBoundaryInterface createProvider(WebView webview) {
+        return getFactory().createWebView(webview);
+    }
+
+    @SuppressWarnings("NewApi")
+    private static void checkThread(WebView webview) {
+        if (BuildCompat.isAtLeastP()) {
+            if (webview.getLooper() != Looper.myLooper()) {
+                throw new RuntimeException("A WebView method was called on thread '"
+                        + Thread.currentThread().getName() + "'. "
+                        + "All WebView methods must be called on the same thread. "
+                        + "(Expected Looper " + webview.getLooper() + " called on "
+                        + Looper.myLooper() + ", FYI main Looper is " + Looper.getMainLooper()
+                        + ")");
+            }
+        } else {
+            try {
+                Method checkThreadMethod = WebView.class.getDeclaredMethod("checkThread");
+                checkThreadMethod.setAccessible(true);
+                // WebView.checkThread() performs some logging and potentially throws an exception
+                // if WebView is used on the wrong thread.
+                checkThreadMethod.invoke(webview);
+            } catch (NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException(e);
+            } catch (InvocationTargetException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/VisualStateCallbackAdapter.java b/webkit/src/main/java/androidx/webkit/internal/VisualStateCallbackAdapter.java
new file mode 100644
index 0000000..c6917d8
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/VisualStateCallbackAdapter.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import org.chromium.support_lib_boundary.VisualStateCallbackBoundaryInterface;
+
+import androidx.webkit.WebViewCompat;
+
+/**
+ * Adapter between WebViewCompat.VisualStateCallback and VisualStateCallbackBoundaryInterface (the
+ * corresponding interface shared with the support library glue in the WebView APK).
+ */
+public class VisualStateCallbackAdapter implements VisualStateCallbackBoundaryInterface {
+    private WebViewCompat.VisualStateCallback mVisualStateCallback;
+
+    public VisualStateCallbackAdapter(WebViewCompat.VisualStateCallback visualStateCallback) {
+        mVisualStateCallback = visualStateCallback;
+    }
+
+    @Override
+    public void onComplete(long requestId) {
+        mVisualStateCallback.onComplete(requestId);
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
new file mode 100644
index 0000000..f97b2d8
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.support.v4.os.BuildCompat;
+import android.webkit.WebView;
+
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Utility class for calling into the WebView APK.
+ */
+public class WebViewGlueCommunicator {
+    private static final String GLUE_FACTORY_PROVIDER_FETCHER_CLASS =
+            "org.chromium.support_lib_glue.SupportLibReflectionUtil";
+    private static final String GLUE_FACTORY_PROVIDER_FETCHER_METHOD =
+            "createWebViewProviderFactory";
+
+    /**
+     * Fetch the one global support library WebViewProviderFactory from the WebView glue layer.
+     */
+    public static WebViewProviderFactoryAdapter getFactory() {
+        return LAZY_FACTORY_HOLDER.INSTANCE;
+    }
+
+    private static class LAZY_FACTORY_HOLDER {
+        static final WebViewProviderFactoryAdapter INSTANCE =
+                new WebViewProviderFactoryAdapter(
+                        WebViewGlueCommunicator.createGlueProviderFactory());
+    }
+
+    private static InvocationHandler fetchGlueProviderFactoryImpl() {
+        try {
+            Class<?> glueFactoryProviderFetcherClass = Class.forName(
+                    GLUE_FACTORY_PROVIDER_FETCHER_CLASS, false, getWebViewClassLoader());
+            Method createProviderFactoryMethod = glueFactoryProviderFetcherClass.getDeclaredMethod(
+                    GLUE_FACTORY_PROVIDER_FETCHER_METHOD);
+            return (InvocationHandler) createProviderFactoryMethod.invoke(null);
+        } catch (IllegalAccessException | InvocationTargetException | ClassNotFoundException
+                | NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static WebViewProviderFactoryBoundaryInterface createGlueProviderFactory() {
+        InvocationHandler invocationHandler = fetchGlueProviderFactoryImpl();
+        return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                WebViewProviderFactoryBoundaryInterface.class, invocationHandler);
+    }
+
+    /**
+     * Load the WebView code from the WebView APK and return the classloader containing that code.
+     */
+    @SuppressWarnings("NewApi")
+    public static ClassLoader getWebViewClassLoader() {
+        if (BuildCompat.isAtLeastP()) {
+            return WebView.getWebViewClassLoader();
+        } else {
+            return getWebViewProviderFactory().getClass().getClassLoader();
+        }
+    }
+
+    private static Object getWebViewProviderFactory() {
+        try {
+            Method getFactoryMethod = WebView.class.getDeclaredMethod("getFactory");
+            getFactoryMethod.setAccessible(true);
+            return getFactoryMethod.invoke(null);
+        } catch (NoSuchMethodException e) {
+            throw new RuntimeException(e);
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
new file mode 100644
index 0000000..249d367
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
+
+import androidx.webkit.WebViewCompat;
+
+/**
+ * Adapter for WebViewProviderBoundaryInterface providing the functionality expected of
+ * WebViewCompat, this adapter is the support library version of
+ * {@link android.webkit.WebViewProvider}.
+ */
+public class WebViewProviderAdapter {
+    WebViewProviderBoundaryInterface mImpl;
+
+    public WebViewProviderAdapter(WebViewProviderBoundaryInterface impl) {
+        mImpl = impl;
+    }
+
+    /**
+     * Adapter method WebViewCompat.insertVisualStateCallback().
+     */
+    public void insertVisualStateCallback(long requestId,
+            WebViewCompat.VisualStateCallback callback) {
+        mImpl.insertVisualStateCallback(requestId,
+                BoundaryInterfaceReflectionUtil.createInvocationHandlerFor(
+                        new VisualStateCallbackAdapter(callback)));
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
new file mode 100644
index 0000000..d961c09
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.webkit.WebView;
+
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
+import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
+
+/**
+ * Adapter for WebViewProviderFactoryBoundaryInterface providing static WebView functionality
+ * similar to that provided by {@link android.webkit.WebViewFactoryProvider}.
+ */
+public class WebViewProviderFactoryAdapter {
+    WebViewProviderFactoryBoundaryInterface mImpl;
+
+    public WebViewProviderFactoryAdapter(WebViewProviderFactoryBoundaryInterface impl) {
+        mImpl = impl;
+    }
+
+    /**
+     * Adapter method for creating a new support library version of
+     * {@link android.webkit.WebViewProvider} - the class used to implement
+     * {@link androidx.webkit.WebViewCompat}.
+     */
+    public WebViewProviderBoundaryInterface createWebView(WebView webview) {
+        return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                WebViewProviderBoundaryInterface.class, mImpl.createWebView(webview));
+    }
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/package-info.java b/webkit/src/main/java/androidx/webkit/internal/package-info.java
new file mode 100644
index 0000000..61a92c9
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+package androidx.webkit.internal;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.support.annotation.RestrictTo;
diff --git a/webkit/tests/NO_DOCS b/webkit/tests/NO_DOCS
deleted file mode 100644
index 4dad694..0000000
--- a/webkit/tests/NO_DOCS
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-Having this file, named NO_DOCS, in a directory will prevent
-Android javadocs from being generated for java files under
-the directory. This is especially useful for test projects.